--- name: "day001" title: "Setting Up the Windows Build" markers: "46": "Course of the Handmade Hero series" "184": "Start the project" "306": "Command line in Windows" "424": "Create a virtual drive" "618": "Meaning of the misc folder" "706": "Create the first code file" "768": "Comment header Emacs put in" "877": "Minimum code you will need" "1185": "Configure everything for development" "2920": "Debug with Visual Studio" "3180": "Windows-specific things you should know" "3544": "Add something to do for the program" "3720": "Import a library" --- name: "day001qa" title: "Setting Up the Windows Build - Q&A" markers: "35": "Could you show how you added the Handmade Hero directory to the path?" "224": "Do all Windows programs written in C/C++ use WinMain? Does The Witness have the same started code?" "288": "What is the difference between Microsoft's compiler and gcc?" "387": "What type of milk are you drinking?" "393": "How do you write a renderer that is hardware accelerated?" "406": "Can we get your .emacs file? Do you always code without line numbers?" "419": "Will there be a sushi bar in Handmade Hero?" "423": "*Question regarding the linker and IDE*" "496": "Is there a reason you didn't use the developer command line shortcuts?" "561": "How much experience do you have audio processing code?" "573": "*Asking whether we'll be setting up things in the Mac OS and Linux environment as well*" "585": "Will it be a 2D or 3D game?" "626": "2-hour streams?" "637": "What style of game are you making? ETA for the game?" "668": "Will the game be Windows-only?" "690": "Will you do extended live streams?" "716": "Can you show the command line parameters that you set in the shortcut?" "805": "What is your favorite Linux distro?" "832": "Will I be able to follow you just using VS 2013 Community Edition?" "904": "Will the game have multiplayer?" "962": "Can you please remove the parentheses in return(0);" "971": "When can we get some details on the actual game?" "991": "Why don't you just compile directly in Visual Studio?" "1046": "How does it feel having more than 700 viewers on the stream?" "1158": "*Question regarding command line and the visual debugger*" "1289": "What GDB frontend do you use on Linux?" "1295": "What did yo uwork on while working on Bink video?" "1440": "Will you look at the chat for viewer answers while you work?" "1447": "*Request to do 5-hour streams*" "1512": "Is there a design document?" "1597": "Are we able to open source our own implementations?" "1643": "Fixed point or floating point For the audio representation in the game?" "1650": "*Comment about the C/C++ specification*" "1681": "Are you staying on Windows for the bulk of the show?" "1771": "Do you have *everything* planned?" "1800": "Why don't you run Windows 8.1?" "1878": "*Comment that mentions the Doom 3 source code*" "1891": "*Comment about getting an intern*" "1920": "*Question regarding Twitch quality settings*" "1947": "Any chance you could stream earlier?" "2005": "Will you have an actual repo for the project?" "2033": "Which better-debugger Linux projects are you looking forward to?" "2057": "Windows 7 doesn't support AVX2." "2082": "*Question regarding repo again (answered in 33:25)*" "2104": "Did you consider doing a Kickstarter for this series?" "2263": "*Remark about Twitch stream quality*" "2275": "*Almond milk powerup confirmed*" "2295": "*Setting up a poll to decide best time to stream on Fridays*" "2320": "What do you think about learning math concepts on Wikipedia?" "2365": "*C++ interfacint with API that deals with a dedicated graphics card*" "2380": "*We are all excited that you're doing this in C*" "2411": "*Another Kickstarter comment*" "2446": "*Remark about having a 3D sequel*" "2516": "Would you consider dropping the framerate/" "2536": "*Wrist glove powerup NOT confirmed*" "2550": "Could you recommend some good books? Tutorials?" "2615": "*Clearing up confusion with C++ structs (related: 52:35)*" "2744": "*How we'll transition to take advantage of hardware acceleration*" "2770": "Can you make constructors in C++ structs?" "2789": "*Yet another Kickstarter comment*" "2852": "Are you planning to have descriptive names for the Youtube archive videos?" "2880": "*30 FPS game confirmed*" "2893": "What's up with the Handmade Hero icon on the Twitch page?" "2904": "*Benefits of learning things from scratch*" "3030": "#milkhit" "3035": "Will you ditch the #include ?" "3044": "How often do you use the debugger?" "3062": "Why do you scope the for-loop the way you do? (Muratori For Syntax)" "3091": "*Micro-transactions are all the rage. Suggestion to use them*" "3140": "Will there be an option to pre-order as a gift for a friend?" "3155": "*Difference between C and C++ structs*" "3192": "*Suggestion on putting a green screen behind Casey*" "3201": "Will sound effects be implemented right away?" "3226": "*Twitch partnership is a possibility (?)*" "3246": "How do you plan to design a good game?" "3410": "Why start from scratch?" "3730": "Set up an official forum?" "3842": "Why not code in just pure C or pure C++?" "3990": "Is there a game dev company you really admire?" "4097": "Where do most of your audience come from?" "4228": "SDL or SFML?" "4254": "*Closing Remarks*" --- name: "day002" title: "Opening a Win32 Window" markers: "200": "WNDCLASS Implementation start" "280": "Struct explanation of why Windows Documentation is the way it is" "578": "Initialization of WNDCLASS" "1317": "CALLBACK explanation and basic implementation" "2201": "Registering the WindowClass" "2330": "CreateWindowEx()" "2650": "Windows Message queue | GetMessage()" "3060": "Drawing something with WM_PAINT" "3420": "Switching between drawing BLACKNESS and WHITENESS" --- name: "day002qa" title: "Opening a Win32 Window - Q&A" markers: "92": "Question about Atoms in Windows API" "137": "Can you go fullscreen?" "160": "Improving the way things are shown on stream" "182": "What's the fastest path for getting a pixel on the screen on Windows?" "285": "Dealing with ANSI strings" "369": "Do you use always the same technique for creating a fullscreen window?" "398": "Is the for-loop just for keeping the window alive?" "506": "Can I preorder the Epilepsy Simulator?" "528": "Do we want the player to resize our window?" "549": "Can you experiment what happens when you take out CS_HREDRAW and CS_VREDRAW?" "631": "Any considerations for 64-bit on tonight's code?" "822": "Using const qualifier" "895": "Compilation issue" "1043": "You're nesting quite a lot of blocks." "1084": "My app doesn't respond to the window's close button" "1215": "for(;;) vs. while(true)" "1349": "Can you explain the Window Handler one more time?" "2027": "Closing remarks" --- name: "day003" title: "Allocating a Back Buffer" markers: "50": "Short overview about a backbuffer" "176": "Windows message callback" "283": "Closing the window (PostQuitMessage function)" "550": "about resource handling" "766": "Back to closing the window" "956": "about global variables" "1020": "Different meanings of static: internal, global_variable, local_persist" "1367": "Backbuffer, windows, GDI and us." "1409": "resizeDIBSection() created" "1566": "GetClientRect()" "1849": "CreateDIBSection() created" "1899": "StretchDIBits()" "2311": "CreateDIBSection() usage and explanation" "2899": "About freeing and creating a new DIBSection" "3222": "Device context and Win32ResizeDIBSection()" "3803": "Q&A" "3817": "Remark on not needing to use CreateDIBSection/CreateCompatibleDC and just allocating the array ourselves" "4007": "Remark on the change to the archiving of Q&A sessions (they are now combined with the main day video)" "4117": "Will you be using sleep()?" "4139": "Could you go back through how you got Visual Studio to cooperate?" "4192": "Are other windowing systems less crazy to work with?" "4340": "Are you going to do a more detailed Intro To C series alongside this one?" "4420": "Can you explain what exactly a void* is? A pointer to nothing?" "4803": "Any new thoughts on IMGUI since you made that video a few years ago?" "4875": "Follow up on the previous remark about StretchDIBits, it can take a custom array as long as it is DWORD aligned" "4993": "When will the source be available?" "5010": "When using emacs, I find it hard to use meta key with F and B to skip words, how do you do it so fast?" "5028": "How come !=0 is true in C, and return values of main and functions is 0 if everything is okay?" "5178": "Remark on functions with multiple return values "Pre ANSI C didn't allow return structs"" "5304": "Any reason you put the type in a line above the function name?" --- name: "day004" title: "Animating the Back Buffer" markers: "30": "Correction about StretchDIBits()/BitBlt()" "320": "Writing our custom BitmapMemory allocator. (Note about aligned/unaligned byte access)" "433": "Basic math to determine the bytes needed for BitmapMemorySize. 'Width * Height * BytesPerPixel'" "477": "Description and usage of VirtualAlloc(), the WIN32 memory allocation function we will be using" "795": "Making sure we free any allocated memory before we resize, using VirtualFree()" "920": "Aside about VirtualProtect(), useful to prevent stale pointers and "use after free" bugs" "1009": "Step through of Win32ResizeDIBSection()" "1065": "Changing Win32UpdateWindow() to use BitmapMemory" "1170": "Adding Bitmap dimensions as global variables (temporarily)" "1200": "Setting Bitmap Width/Height and using them in Win32ResizeDIBSection()" "1220": "Setting Window Width/Height in Win32UpdateWindow()" "1317": "Notes on storing a 2D image inside a 1D "block" of memory. Pitch/Stride." "1470": "Setting biHeight to a negative number to ensure the window framebuffer uses a top-down coordinate system with its origin in the top left corner" "1559": "Note on getting MSVC to give full paths to files in the build output log. (Add -FC to build.bat) Allows emacs to jump between build errors" "1620": "BUGFIX: Win32UpdateWindow() definition change" "1665": "Drawing pixels into the bitmap" "1745": "Adding typedefs for specific type sizes" "1839": "Casting void* to different size types to make pointer arithmetic simpler for bitmap access" "2016": "Pixel component layout in memory on Win32. Flipped to read RGB when viewed in the memory registers." "2290": "Drawing pixel colors based on the X and Y" "2410": "Moving bitmap rendering into RenderWeirdGradient()" "2560": "Adding animation and switching GetMessageA() for PeekMessage() so that Windows doesn't block" "2723": "Making sure we handle WM_QUIT inside our PeekMessage() loop" "2783": "Adding XOffset/YOffset variables to the main loop, ++1 them each time through the loop" "2860": "BUGFIX: Adding our window blitting function (Win32UpdateWindow()) to the main loop, so the bitmap will blit each time through the loop" "3025": "Changing "WindowHandle" to "Window" and "WindowRect" to "ClientRect"" "3116": "FINALLY ANIMATION!" "3265": "Changing DrawWeirdGradient() to use a 32-bit pointer and write each pixel in one call using bitwise operations" "3518": "Verification of lack of memory leaks" "3584": "TOTAL SYSTEM MELTDOWN" "3727": "Q&A" "3730": "Is there a reason you prefer using 0 instead of NULL?" "3798": "Clarification about sized typedefs" "3898": "What would happen if you called malloc() instead of VirtualAlloc()?" "3932": "What's the difference between malloc and new and HeapAlloc()?" "3987": "Do you think you could go as slow as you did previous days in the future?" "4047": "Are we going to use Valgrind in the future?" "4063": "Is the project going to take 2 years?" "4090": "Can you explain why we are using the user32.lib and gdi.lib in the build.bat?" "4122": "Would there be a significant performance increase if we allocated the memory for the bitmap on the stack instead of the heap?" "4227": "Do you know what the PAGE_WRITECOPY Memory Protection flag does?" "4552": "About bytes per pixel and bitmap memory layout. Pitch/Stride. Pitch is byte offset between rows." "4789": "You mentioned xxBBGGRR because of little endian, why was the blue channel set in this case instead of the padding?" "4890": "Could the padding byte be used as an alpha channel here?" "4926": "Why are we having a wait symbol on the window?" "4970": "Could you explain the offset to X and Y?" "5040": "About the global_variables and the static keyword" "5295": "Static doesn't give you zero on initialization?" "5378": "Do you consider overflowing numbers to be a good coding practice?" "5423": "Note about statics and extern global variables being initialized to zero" --- name: "day005" title: "Windows Graphics Review" markers: "69": "Brief overview of the week's work." "133": "Capture card considered unneccesary?" "187": "Value of HREDRAW and VREDRAW" "288": "Helping the compiler optimize by avoiding unnecessary pointers" "390": "Explanation of pointer aliasing" "704": "What difference does it make if I put a declaration inside a loop instead of outside it?" "1110": "Where to get Liberation Mono, the font Casey uses." "1174": "Dealing with global variables more cleanly by bundling them up into structures" "1738": "Making a global backbuffer" "1799": "Explanation of Access Violations" "1996": "Aside about types of errors you find in code" "2232": "GetWindowDimension() created" "2462": "Why keep using Width/Height instead of win32_window_dimension?" "2618": "Changing the backbuffer to be fixed size" "2837": "Full step-through with in-depth analyis of program behavior" "3164": "Deep dive on the size of the stack" "3350": "STACK OVERFLOW ACHIEVED" "3705": "Step-through resumed" "5015": "Q&A" "5046": "Would it be a good or bad idea to get one DeviceContext at the beginning of the program and use that for every iteration of the main loop?" "5166": "Chihuahua on speed confirmed" "5182": "Why do you tell Windows you handle messages you don't really handle?" "5346": "I believe SetStretchBltMode() will allow you to get better quality stretching." "5380": "Can you please explain pointer aliasing again?" "6347": "Owl of Shame Moment: Pointer aliasing explanation fail" "6566": "Proper pointer aliasing explanation" "7042": "I was under the impression that the stack always grows downwards on little endian architectures, is that not true?" "7090": "Can you post interesting e-mails you get to the site?" "7111": "The compiler is allowed to, and actually does, assume that two pointers to different types never alias unless one of the types is char or unsigned char" "7186": "Win32DisplayBufferInWindow() is taking four unused parameters. WM_PAINT is the only part where we pass those, but we never use them. Will that change?" "7262": "Wouldn't it be better to keep comments in the code about the explanations you do?" "7287": "Why have BytesPerPixel as a variable? Do you expect it to have different values?" "7384": "On the uselessness of const" --- name: "day006" title: "Gamepad and Keyboard Input" markers: "51": "Getting input from a gamepad: XInput" "200": "Using XInput in the codebase" "386": "A look at the XInput API more in depth." "460": "Programming using XInput API" "549": "Discussing the controller's state: using XINPUT_STATE struct" "690": "Using XINPUT_GAMEPAD struct" "1017": "Handling unresolved external symbol XInputGetState" "1563": "Discussing access violations" "1612": "Safeguarding against access violations" "1910": "Defining and implementing Win32LoadXinput function" "2242": "Playing with the X and Y offset" "2280": "Casey looking for his gamepad" "2330": "Casey showcases pink controller" "2469": "XINPUT_VIBRATION" "2585": "#milkhit" "2815": "Testingand handling button/key presses" "3310": "(Extra) ANSI String Handling" "3370": "(Extra) Not passing something by value anymore" "3490": "Summary and things to come before beginning Q&A" "3548": "LParam 30 is always up for WM_KEYUP" "3597": "Why uppercase variable names?" "3621": "Can you explain your macro and referencing XInput functions again?" "3795": "What's the size when copying becomes problematic for a struct?" "3867": "About (premature) optimisation" "4107": "How does the linker find the XInput DLL on the users machine? [...] Can we distribute the DLL?" "4372": "Is [the dynamic linker] allowed to link XInput in compile time?" "4442": "Why you chose an if-else cascade for key input instead of switch statement? It's up for grabs." "4513": "How do you know the XInput stub things work without testing it on XP computer without XInput installed?" "4623": "Is it a waste of time to check if GetProcAddress() returns zero?" "4752": "Modify code to use the controller stick" "4934": "Where do the WParam and LParam come from?" "5057": "Why did MS decide to use link and import library instead of true dynamic linking?" "5113": "When are we going to get naysayer88 and cmuratori combination game?" "5179": "On Unix you don't need to link to a .so file at all to use a .so file where as on MS platforms you need a .lib file" "5253": "In the far future will you use DirectX or OpenGL or what?" "5285": "We will be drawing the whole screen every frame." "5327": "Why does Valgrind make it look so scary when you don't free()?" "5388": "It looks like WParam and LParam are 32bit on XP" "5412": "Is it possible to keep your framerate consistent while dragging the window around? Doing repaint on WM_MOVE is slow." --- name: "day007" title: "Initializing DirectSound" markers: "53": "Fix: Windows API return values and stubs" "149": "Fix: XInput on Windows 8" "228": "Fix: Restore Alt-F4 functionality" "561": "Bool datatype idiosyncraries" "775": "Review Alt-F4 fix" "835": "Foreshadowing an XInput performance issue" "1004": "Intro to sound programming for games" "1435": "Initializing DirectSound Overview" "1623": "Load the library" "1920": "Create a DirectSound Object" "2034": "Configuring the DirectSound Object" "2284": "Creating and Configuring the Primary Buffer" "3096": "Creating and Configuring the Secondary Buffer" "3398": "Let's try it" "3646": "Final Thoughts" "3725": "Q&A" "3845": "Fixing WaveFormat order" "3967": "Do you use data-structures like linked-list, binary trees..?" "3994": "Can you explain again why you need two buffers instead of just doing everything in one?" "4163": "Are there any case we'd want more than two [audio] channels?" "4265": "If the framerate would ever drop, can there be audio dropouts?" "4421": "The nBlockAlign and nAverageBytesPerSecond are redundant." "4497": "On Linux will we be doing ALSA or higher level like PulseAudio/Jack?" "4560": "What newer sound API would you recommend instead of old DirectSound?" "4606": "The two second buffer doesn't sound acceptable / not-noticeable if you're playing music." "4647": "Have or do you work in the industry?" "4674": "Have you thought about guest programmers tagging in to teach things like linux or whatever topic is their expertise?" "4715": "VirtualAlloc: MEM_COMMIT to MEM_RESERVE|MEM_COMMIT" "4823": "About game development as a career field" "4977": "Will you show us how to use bone animations or will you use spritesheets?" "5055": "More on our usage of DirectSound (Not a buffer)" "5133": "About game programming optimisation" "5276": "Why don't we use the second buffer to grab the handle instead of creating something just to grab a handle?" "5366": "Isn't this learning how to carve stone with chisel instead of using modern machinery?" --- name: "day008" title: "Writing a Square Wave to DirectSound" markers: "64": "Review of DirectSound init" "136": "Tangent: methods and vtables" "532": "Resume review of DirectSound init" "861": "Writing to the sound buffer" "969": "Discussion of waveforms for testing" "1022": "Locking the buffer" "1099": "Dealing with buffer pointers and locks" "1269": "The Lock() call" "1379": "Filling the buffer regions" "1609": "Generating a test tone" "2128": "Getting the WritePointer and BytesToWrite" "2901": "Refine square wave formula" "3099": "Review the code" "3364": "Start DirectSound playing" "3447": "HOLD YOUR EARS" "3502": "HOLD YOUR EARS" "3562": "Don't forget to Unlock the buffer" "3658": "Final Thoughts" "3737": "Review of mod operation and how we used it" "4230": "Q&A" "4269": "Will future broacasts use this Europe-friendly time?" "4281": "Why not XAudio2?" "4363": "Are we going to factor sound playing to a seperate function?" "4425": "Will we rename GlobalSecondaryBuffer?" "4450": "Challenge: XAudio2 is supported on XP" "4489": "Why keyboard events instead of polling?" "4524": "Will we be able to remap keys?" "4543": "Doesn't the size of the buffer increase latency?" "4613": "Will we write audio filters, like reverb?" "4636": "Will we factor the code into seperate files?" "4686": "It takes about a second to start playing, is that expected?" "4959": "Can you show a sine wave as well?" "4982": "What is acceptable latency?" "5344": "No Poop Sauce" --- name: "day009" title: "Variable-Pitch Sine Wave Output" markers: "74": "Review DirectSound init and square wave" "148": "Story Time: The First Game Jam" "536": "The moral of the story" "686": "How to approach debugging the sound code" "940": "Square vs Sine Wave" "1053": "Generating a Sine Wave" "1076": "Tangent: Intro to Floating Point" "1238": "C Libraries for sin" "1495": "Story Time: Before floating point hardware" "1603": "Tangent: Fixed-point math" "1955": "Tangent: IEEE Floating-point representation" "2535": "Implementing the Sine wave test tone" "2889": "Lets run it" "2941": "Debugging in earnest" "3459": "A different error" "3478": "Refactor for clarity" "3826": "Where did it go?" "3848": "Eureka!" "3922": "Victory" "4192": "Q&A" "4207": "In D this bug couldn't have happened. D always initializes variables." "4416": "How do you know that ByteToLock is far enough ahead of the PlayCursor?" "4540": "Try [compiling with] -W3 or -W4" "4554": "Where do I look for standard C library docs?" "4599": "I think you can now remove the ByteToLock == PlayCursor case." "4678": "Will we use the sin() in the actual game?" "4687": "Is autocomplete/intellisense a bad idea? You don't seem to use it." "4765": "Re-explaining the last bug" "4850": "Is it possible for bits to spill over into neighboring variables? For example, when shifting." "5186": "Will we use the same output buffer to overlay several sounds?" "5193": "Change tone frequency based on input, and the bug will resurface." "5197": "Casey: That's a different bug, lets look at it." "5443": "Fixed" "5457": "Diagramming the frequency change issue" "5718": "Let's map the pitch to the sticks." "5820": "Theramin Simulator 2014 Tech Demo" "5833": "Let's lower the latency" "6169": "If we could live with a slightly less accurate sin, we could approximate it with polynomials." "6308": "Will the art and audio be released into the public domain?" "6380": "Is it a good idea to use fixed point math for games that require deterministic simulation for multiplayer? Or can you use floating point across systems?" "6528": "Sometimes you use 'bool' and sometimes 'bool32'" "6570": "Are you going to use ETW to log context switches for the game?" "6582": "Is this the audio api we will be using to ship the game?" "6601": "Is it safe to call DirectSound without initializing COM?" "6647": "Can we do an episode on emacs?" "6693": "Fix: XInput - missing dependencies" "6825": "Fix: Arithmetic for stick values" "7315": "Sign off" --- name: "day010" title: "QueryPerformanceCounter and RDTSC" markers: "79": "The Intel Architecture Reference Manual" "229": "RDTSC- Read Time-Stamp Counter, measures clock cycles" "460": "QueryPerformanceCounter(), measures wall clock time" "930": "Timing our frames" "1022": "Union types (LARGE_INTEGER)" "1308": "Method of determining time elapsed between frames" "1399": "QueryPerformanceFrequency()" "1592": "Using dimensional analysis to convert between unit types" "1873": "Converting seconds/frame to ms/frame" "1956": "Printing out MSPerFrame" "2290": "Finding Frames Per Second using dimensional analysis (cause we can)" "2744": "The dangers of wsprintf()" "3010": "Using RDTSC to find cycles per frame" "3403": "Use wsprintf() to print our timings as floats" "3558": "A bit more about wsprintf()" "3725": "Final Thoughts" "3872": "Q&A" "3886": "RDTSC returns unsigned int" "3928": "Explanation of how C handles division based on type" "4054": "How compiler optimizations affect the execution time" "4198": "Do the divide in doubles." "4406": "It would be nice to have a roadmap...Would you consider doing a 24 hour stream?" "4470": "Will we be able to use a Playstation 2 controller?" "4493": "Can we expect more Jeff and Casey shows in the future?" "4504": "Is it safe to use 64-bit variables and functions on a 32-bit PC?" "4577": "Even though we are doing low level programming, sometimes we have to pass things to Windows, which makes it difficult to follow exactly what the computer is doing. Will this be the same when we go to other platforms?" "4725": "Do you use a profiler or mostly hand-coded timing calls?" "4737": "Why do you use PascalCase for everything?" "4744": "Is it a violation to set one member of a union and then read from another?" "4755": " Was wondering when we would get around to using RawInput to handle DualShock 4 natively" "4847": " Modern CPUs RDTSC returns nominal clocks not real clocks." "4934": "Why are you avoiding doubles in your code?" "4970": "Are you opposed to ever using high level languages in making games?" "5003": "If you wanted to lock the FPS at a particular number, would you just sleep or do something more complex?" "5095": "Isn't RDTSC affected by variable processor technologies in modern processors like SpeedStep?" "5214": "Have you done Ludum Dare?" "5230": "Can we do a bonus stream on ASM?" "5331": "If you read the latency tables for SSE2 float vs double, you'll see that double isn't that much slower than float..." "5838": "What are your thoughts on Swift?" "5843": "What do you think of Jonathan Blow's programming language?" "5870": "Do you have any discussions with Jonathan Blow on his compiler and what sort of features you would like to see in it?" "5939": "Do you ever write functions like printf() that take variable arguments?" "5947": "Would you consider using a templated type-safe version of printf(), even though you hate templates?" "5968": "MULPD is only half as fast if you do millions of operations..." "6003": "What low level language would you suggest to someone new to programming?" "6013": "Are we using the Win32 API but compiling for 64-bits? Do we need to compile for 32-bits for Windows XP support? It looks like we have int64 and real64 in the cpp" "6050": "In game development, do you follow enterprise design patterns, or do you have some different design patterns?" "6069": "What do you use for collections if you do not use templates?" "6078": "I didn't get the outome of the MULPS/MULPD compare. The latency packing was the same, how does that end up being double time?" "6244": "RE MULPS/MULPD: If you're writing SIMD code then you care, otherwise you don't." "6358": "Comment about compiler auto-vectorization" "6463": "Tom Forsyth's rant on double precision" "6515": "Will we take MSVC all the way to shipping or will we use LLVM even on Windows?" "6603": "What's an intrinsic?" "6923": "Switch back to debug build from optimized" "6963": "Isn't it a pain to work in Windows, especially as a programmer?" "7025": "Didn't we want to start adding warnings?" --- name: "day011" title: "The Basics of Platform API Design" markers: "215": "About platform specific code" "476": "What is left to be done on the platform layer" "683": "Topic of the day revealed!" "693": "Portability and cross platformness" "817": "How people used to make code be cross platform (preprocessor #if #else)" "1128": "About preprocessor #if #else cross platforming" "1432": "Separate platform files (e.g. linux_handmade.cpp) as the entry point" "1901": "Unity builds, building your project as one translation unit" "2048": "Virtualising the OS to the game (architecture style 1)" "2063": "Example implementation for virtualising a window wrapper" "2574": "Reasons why perhaps not to use style 1" "2671": "Game as a service to the OS (architecture style 2)" "2835": "Implementing style 2" "3090": "GameUpdateAndRender() - moving RenderWeirdGradient to game code" "3660": "Q&A" "3683": "Seems 'unsafe' to include the platform independent code after including the platform specific headers" "3802": "Would you always orchestrate how you do threading in the platform layer or does it make sense for the platform layer to also provide a more generic threading job service?" "3912": "You said last stream you didn't really like showing the FPS because you didn't find it useful. Can you explain that?" "4188": "On the scale from genius to totally awesome how can you remember all this?" "4341": "Do we currently have a hidden platform dependancy inside the bitmap memory or is BGRA something that happens on the other platforms too?" "4518": "It seems like your approach to handling platform dependant services is to prefer a many-to-one relationship instead of a one-to-many. [...]" "4673": "How did you setup Visual Studio to have that black theme?" "4702": "During coding is it easy to discipline yourself to make the code as clean and tidy as possible. [...] Do you think this is good in general or could it backfire?" "4940": "Would there be a way to build your platform dependant code in a separate entity in order to allow you to use it in the future?" "4991": "Will you be developing your own implementation of strings? (No)" "5032": "Does the unity build approach work with parallel compilation?" "5164": "Do you feel it is necessary to make a flowchart before coding, or do you go with the flow?" "5238": "Why the #define part for the header file (include guards)" "5349": "Why do you specify void in function definitions when they don't take arguments?" "5406": "Do you have a specific method for solving programming problems or do you just write things and solve them in place?" "5429": "Why are you forward declaring game layer functions in the header when you include the whole documentation?" "5477": "Do you think it is realistic for someone with awful math skills to be an efficient game developer?" --- name: "day012" title: "Platform-independent Sound Output" markers: "57": "Review basics of platform API design" "234": "What the API needs to support" "293": "Starting with moving sound across the API boundary" "630": "How most games deal with time (poorly)" "666": "What we are going to do" "895": "Moving sound generation across the boundary" "1170": "Finding the seams" "1369": "Dealing with sound buffers abstractly" "1550": "Allocating a game sound buffer" "1773": "Tangent: buffer overruns and how the debugger helps" "1869": "Actually using the game-generated sound" "2221": "Cleaning up the old stuff" "2536": "A step back" "2610": "Tangent: memory management & alloca" "2877": "Nevermind, we'll put it on the heap" "3057": "Review" "3234": "The remaining jank" "3447": "Tweak the build.bat" "3527": "Final Thoughts" "3570": "Q&A" "3616": "Will we use alloca to store pointers to game objects that are local to the player?" "3869": "If the DirectSound Lock fails, you'll pass garbage pointers to the game logic." "3931": "When you say 60fps may not be feasible do you mean on non-PC platforms?" "4070": "Are we not worried about clean builds?" "4117": "Allocating every frame was your bug with alloca. You were calling it in a loop." "4346": "Can you explain again why our current sound buffer fill is problematic?" "4543": "Wouldn't updating graphics and sound on the same frame cause audio lag?" "4628": "Since alloca is just a function call, how does the compiler know to free the memory?" "4664": "Will we spilt game sound update out of GameUpdateAndRender so we can use it as a callback or on a different thread?" "4696": "alloca is deprecated, we should use malloca." "4817": "can you provide a log of the chat on the website?" "4843": "malloca allocs on the stack if less than 1kB and malloc's if greater." "4893": "How can you safely predict where the flip happens so you can write sound there?" "5094": "We know that you can't go below 30fps for 'smooth' video. Is there a similar rule of thumb for audio?" "5189": "alloca is deprecated because.... [There are better options.]" "5449": "How do you do 2 voices in 1 buffer?" "5458": "When will the first sprite be displayed in animation?" "5471": "I've heard the brain treats sounds within 10ms as in-sync?" "5499": "When you work with temporary memory are there dangers? How do we protect against them?" "5601": "As a rhythm game player, I can notice audio sync off as little as 10ms..." "5703": "Sign Off" --- name: "day013" title: "Platform-independent User Input" markers: "40": "Overview of the day's goals" "155": "Function Overloading (accidental and intentional)" "449": "Extending GameUpdateAndRender() to take input" "513": "Pulling structs into a header file for readability" "588": "On iterating towards an API and avoiding premature design" "815": "Writing our usage code first" "912": "Diagram of input over time" "1247": "Looking at one common method of parsing game input" "1423": "An less expressive but simpler way" "1709": "But Casey, what about the stick?" "2147": "Writing usage for some game_input structures" "2271": "Adding the structures and filling them out" "2445": "Handmade Hero: Better than cooking shows!" "2534": "Porting our platform layer over to the new API" "2776": "Factoring out button processing into Win32ProcessXInputDigitalButton()" "2927": "Processing all the buttons" "3071": "ArrayCount() used but not implemented yet" "3196": "Swapping NewInput and OldInput, how do we want to do it?" "3276": "Finally defining NewInput and OldInput" "3364": "More explanation about swapping" "3448": "Defining the ArrayCount() macro" "3530": "But Casey, what about the stick?" "3611": "Normalizing our stick values" "3894": "Wrap up and Final Thoughts" "4015": "Q&A" "4025": "When normalizing the thumbstick value, is it worse to just add 32768 then multiply it by 2/65535 then subtract 1? I don't like the necessary if statement personally." "4125": "Nitpick, but is it a bit misleading that the half transition count is zero or one, rather than an actual count?" "4157": "Will we be completely ignoring platform code for most of the rest of the series?" "4188": "Can you describe the struct inside of the union in more detail?" "4417": "Does it give any problems with capturing inputs over time when, due to some circumstances from Windows, the game lags and the frame timebase expands?" "4563": "Your normalizing code has an error, they both divide by positive." "4673": "What happens if there's a name conflict between struct scope and a non-nested struct?" "4715": "Do you plan on abstracting the input more. For example, instead of having a player respond to a button press, have them respond to an action that is bound to a button or stick?" "4801": "Why is GameUpdateAndRender() internal when it's designed to be called from the platform layer?" "4835": "Comment about using re-bindable keys and buttons for left-handed people." "4877": "When will you decide to actually remove all the TODOs in your code?" "4911": "Aside about rebindable keys." "4981": "How is the old controller persisted across frames?" "5039": "Will the Windows callbacks for keyboard inputs require a great deal of extra work for you to implement?" "5118": "What about people who only have left arms?" "5145": "Will we eventually be using a timer to poll the controller input, or just a thread?" "5200": "timeBeginPeriod(1) will tick at 1 millisecond resolution." "5257": "Have you done much physics coding, related to games or otherwise?" "5305": "Would you be fine with people using the platform as a base for making their own games, with attribution?" "5389": "How much will you need to explore other platforms before knowing what the abstraction API will look like?" "5426": "What kinds of numerical methods are used in game physics?" "5486": "Final Wrap Up" --- name: "day014" title: "Platform-independent Game Memory" markers: "58": "Intro to memory management." "247": "We won't be allocating." "317": "'Allocation Festivals'" "335": "Why talk about allocation now?" "455": "What would 'normally' happen" "715": "Problem: dynamic allocation spreads managment across code, makes it opaque" "798": "Problem: allocation is another trip through the platform layer" "903": "What we will do instead" "1045": "Adding memory to the platform abstraction" "1241": "Initializing with the new model" "1277": "Allocating the memory in the platform" "1593": "Yes, Virginia, memory comes zeroed." "1720": "Put it where you want it." "2013": "Debugging: Integral promotion" "2198": "Note that the clear to zero is cheap." "2247": "Memory? Check." "2428": "Intro to assertions" "2673": "Avoiding the runtime cost" "2703": "Build options" "2888": "Build options for memory" "3031": "Combining allocations" "3090": "Debugging" "3307": "Mission accomplished." "3384": "TODO: Pass timing info to game" "3504": "Q&A" "3560": "Reasoning behind Main Memory Pool vs Dynamic Allocation?" "3811": "Why use the void* in game_memory?" "3853": "Elaborate on Permanent vs Transient storage?" "4023": "Will the code be on github [be public]?" "4058": "What do you mean by 'avoiding round trips'?" "4375": "Are you going to keep the sound buffer allocation seperate?" "4394": "Why didn't you use libc's assert macro?" "4423": "You're assert has issues." "4477": "Why did you pick a BaseAddress so high up (2TB)?" "4509": "What is the difference between the memory columns in Task Manager?" "4661": "Tangent: PerfMon" "4839": "Recommended: Channel 9 video: Mark Russinovich Mysteries of Windows Memory Managment." "4864": "Are there any guidelines for choosing a safe BaseAddress?" "4906": "What happens if the user doesn't have enough RAM?" "4960": "Isn't worrying about not having enough memory silly?" "5005": "Why are you using pools instead of static allocation?" "5032": "What mechanism will we use to assign memory out of our pools?" "5057": "Having Q&A after the episode is like code review. Was that your intent?" "5116": "What about i.e. modding support? You can't tell in advance if you've allowed enough memory for someone else's mod." "5194": "Will our 64-bit allocation break on Raspberry Pi?" "5247": "Will the Transient storage be freed, or will you just take off its end until its gone?" "5265": "Is it better to keep track of how much memory is freed instead of total size?" "5286": "Why are you reluctant to have to constants be 64-bit integers?" "5367": "Did you pass different flags to VirtualAlloc for permanent and transient storage?" "5394": "What are the 'other reasons' for specifying a BaseAddress." "5461": "Is it possible the pool will be fragmented?" "5590": "Sign Off" --- name: "day015" title: "Platform-independent Debug File I/O" markers: "86": "Overview of the two classes of game file I/O" "330": "Today's goals (building a minimal set of I/O functions)" "408": "A brief lesson on the sad history of file I/O" "760": "The modern and better way of handling files" "894": "A first pass at the usage code" "1136": "Locking our janky code out of the release build" "1321": "Implementing the I/O functions in the platform layer" "1426": "File handles and CreateFile() breakdown" "1747": "GetFileSize() and GetFileSizeEx()" "2103": "A janky situation with ReadFile()" "2227": "An inline function, SafeTruncateUInt64()" "2595": "Step-through of our read function" "2821": "Making a write based on the read function" "3019": "Using the write function" "3209": "Step-through of the write function" "3400": "Editing the .emacs file" "3507": "Breaking the .emacs file" "3619": "An IMPORTANT note on the safety of file I/O code" "3735": "Q&A" "3774": "Will the game be able to carry on in spite of some big time failure, like a graphics device reset. And does software rendering make that easier to deal with?" "3868": "Would it make sense to call normal GetFileSize() and then assert that the high 32-bit value is zero?" "3960": "Would it be useful for us to write our own allocation function that specifically allocates sections of our already-reserved temporary memory? I am having trouble understanding why we are doing separate allocations." "4074": "Will we implement some kind of cloud storage for the writes?" "4135": "I know you removed it for now, but wouldn't a reserve memory method with an arbitrary size still introduce a failure point since it could fail like VirtualAlloc() and we have simply moved the burden onto ourselves?" "4199": "You can reload your emacs settings without blowing everything up each time with evalbuffer." "4255": "Are there any other benefits to doing one massive allocation, aside from having one failure point. Also does the order of properties in your structs matter when it comes to performance efficiency?" "4560": "Do games really usually write to a second file rather than using some soft of safe write function that won't overwrite it if it somehow fails?" "4651": "Do you miss multiple return values in C?" "4710": "Why don't we just map the file into memory?" "4759": "Will allocating a single amount of memory up front make it more difficult to selectively enable/disable certain features of the game, since there could be many combinations, each requiring different amounts of memory?" "4832": "Why does the order of fake_struct_a and b matter?" "4870": "Why did you do the byte macros, but hesitate on the swap? Is there some hidden complexity on pointer swaps?" "5075": "So structs with unions in them have bad performance issues?" "5111": "You mentioned IOCP (I/O Completion Ports) for async file I/O. Are you planning to use multiple worker threads? I've been doing some multithreaded epoll code on Linux, and it's a very janky API unless you're using one worker thread. There are even a few articles on LWN.net only about how to safely remove a file descriptor with epoll." "5187": "On the swap, why does it have to be a macro. Wouldn't a function do the job and cover the janky complexity with types in the macro?" "5226": "Why don't you define the swap macro to be #define swap(a,b){ type_of(a) temp...?" "5253": "Does ArrayCount macro work with strings?" "5266": "Won Chun: Async file I/O in Linux is nutty." "5293": "(Key Switches)Brown or blue?" "5333": "It (ArrayCount) actually works with string literals." --- name: "day016" title: "VisualStudio Compiler Switches" markers: "152": "Explanation of Warning and the Warning levels" "320": "Fixing warnings, and disabling warnings we don't want" "850": "Other command line switches that Casey normally uses" "1080": "Compiler intrinsics command line switch" "1140": "Disabling Run time type information" "1160": "Disabling exception handling" "1340": "Configuring for a 32bit build" "1860": "Windows XP VM Testing" "2372": "-MT vs -MD and why it matters" "2485": "-Fm Creating a map file and looking at it" "2770": "Why the names are mangled in the .map file produced with the compiler switch of -Fm" "3010": "Start moving keyboard input into the non-platform code" "3772": "Q&A" "3873": "Question: -Oi , Why would anyone not want it active" "3962": "Question: How do we add -Wx -W4 to the commandline switches if developing in VisualStudio" "4027": "Question: Would turning on -Od be a good idea to use in the normal build" "4083": "Question: Does compiler compilation always say finished in green" "4125": "Question: I think you mentioned something about not being a fan of rebindable keys, why no option" "4191": "Question: How much difference would be yielded if we disable the CRT" "4226": "Question: I could not see what you did to not have the key x messages not triggered" "4333": "Question: Would it be better to just pass which key was pressed to the non-platform code instead of in the platform code" "4412": "Question: If you build for say AVX2 but the user has a older processor, what happens" "4443": "Question: Will we move to a unified build system for all target platforms" "4482": "Question: Would not -Oi and -Od be clashing" "4521": "Question: Is there a way to make cl emit a human readable summary" "4532": "Question: Does the map file spit out data about struct memebers as well" "4563": "Question: Does not allowing key rebinding mess up on different keyboard layouts" "4637": "Question: Is the game currently linked to the dll version of the CRT" "4671": "Question: I know you won't be using any libraries, but how would you include unity clib and link to that" "4782": "Question: Is there any advantage to processing things in the main loop other then conceptual grouping" --- name: "day017" title: "Unified Keyboard and Gamepad Input" markers: "139": "Overview of the previous day's work" "311": "An introduction to functional programming" "644": "Methods for making our programs more functional" "701": "Rationale for moving keyboard handling out of Win32MainWindowCallback()" "877": "Finishing the keyboard processing code" "955": "Adding a fifth controller (the keyboard)" "1020": "Adding 32-bit and 64-bit compiler options to the build.bat" "1194": "Ensuring keyboard state persists across frames" "1355": "An Assert() that we didn't do anything stupid" "1430": "Finishing our directional stick code with deadzone processing, no zombies." "1776": "Using the deadzone values from MSDN" "2105": "Iterating across all the controllers in GameUpdateAndRender()" "2183": "Testing new input code" "2254": "Changing game_controller_input to work across both keyboard and gamepad" "2472": "Adapting the keyboard and gamepad code to the new structure" "2695": "Connecting the stick input into a fake directional pad" "2896": "Hooking up the real DPad" "3125": "Adding an IsConnected member to game_controller_input" "3187": "Buffer Overrun encourages some bounds checking" "3404": "Why did we overrun the buffer?" "3566": "Adding some last minute keyboard inputs" "3606": "Final Thoughts" "3748": "Q&A" "3770": "Check the array in the Buttons union, you might want 12 now that you've added start and back" "4134": "Is that some copypasta, or is it really supposed to be all MoveLefts?" "4284": "Could it be good to apply some integration on the keys, so we don't just set the value to binary -1/1?" "4376": "Can you talk about the deadzone being round vs rectangular at hardware USB, HID, and XInput API layers?" "4755": "Maybe it's a round deadzone?" "5020": "I'm 16 days behind, is there a better way to catch up than watching all the days on YouTube?" "5062": "For the build.bat, you can build for Windows XP 64-bit using 5.2 instead of 5.1" "5073": "On the inline method for GetController(), what happens if you pass in -1 for index?" "5150": "Can you do struct buttons_type (name the structure) and still get the benefits..?" "5199": "I don't get using Win32 prefix for function names when compiling for 64-bit." "5254": "I was thinking about processing game input in a separate thread so it is framerate independent, but I heard you could introduce input lag. Is that true?" "5326": "You said a circular deadzone would be good for gameplay, why don't you just make it circular? The deadzone would just be a little bit bigger." "5522": "DirectInput vs XInput, which is better?" "5597": "You deleted the Min/Max macro TODO..." "5643": "So when you use the ZeroController, why not just go *NewKeyboardController = {}?" "5729": "stddef should include offsetof(), you can use that to make your assert a little simpler." "5876": "Final Wrap-Up" --- name: "day018" title: "Enforcing a Video Frame Rate" markers: "100": "Discussion: Why we need to have an enforced video frame rate" "327": "Drawing and explaining the frame computation and displaying timeline" "635": "Explaining Variable Frame Rate Monitors" "1080": "Casey's Game Loop Design Overview" "1215": "The two audio choices we can use" "1523": "Multiple Monitor discussion" "1930": "Start implementing the enforced video frame rate" "2180": "Looping to ensure we are within the targetSecondsPerFrame" "2320": "Debugging: no input" "2441": "Compressing/Refactoring Clocking stats" "2945": "Implementing sleep to not melt our CPU" "3200": "Setting the Windows scheduler granularity with timeBeginPeriod()" "3630": "Q&A" "3668": "Question: If we are locking the frame rate. Would that not mean that someone with a lower end computer, would have a slower game speed to others" "3761": "Question: Even if you could get the refresh rate of the monitor, how do you sync with it on the vertical blink" "3832": "Question: Doesn't the sleep function go in the surrounding IF instead of the WHILE loop" "3947": "Question: Does Win32FillSoundBuffer need to come after the vsync loop" "4014": "Question: Check DWM.GetComposition if AERO is on" "4033": "Question: Could you explain the advantages or disadvantages to handling update and render on different threads" "4166": "Question: How would you adjust your memory management to work on devices with limited memory" "4182": "Question: Won't we miss frame rate due to the sleep" "4378": "Question: Can you fix the physics animation frame rate without fixing the missing frame issue" "4570": "Question: Why are we handling sound and video differently" "4587": "Question: Check if DDraw works on windows 8" "4612": "Question: Wouldn't you want to fill the screen buffer before you hit the flip point, so it can grab the screen at the flip point" "4683": "Question: Isn't DWORD an Interger" "4721": "Question: What do you think about having a fixed physics time unconnected to the drawn frame time" "4800": "Question: Any time you compute a world update should that not just set something that says if we get there early then wait." --- name: "day019" title: "Improving Audio Synchronization" markers: "133": "Intro" "211": "Audio Sync Conversation Begins (Summary)" "259": "#milkhit" "268": "Why audio sync is an issue" "330": "Ways to minimize the issue" "400": "Creating a Debug Diagram for audio sync debug code" "937": "Finishing up audio sync debug code" "1423": "Explaining and debugging debug code" "1800": "Bug in debug code encountered" "1891": "Addressing bug" "2100": "Compiling and running successfully" "2130": "Observing weird gaps in sound" "2155": "Not tracking frame time correctly" "2310": "Addressing the weird gaps" "3000": "Running new code for debug diagram. Sound card read seems unreliable" "3180": "Sound stream has to be continuous. Figuring out how far ahead of the current play cursor we should be writing" "3528": "Discussing possible solutions to improve audio sync" "3755": "Improving audio sync" "4040": "Making a running log" "4120": "Getting a log of our audio to do some important things" "4320": "How much granularity we have" "4580": "Audio latency issue found" "4790": "Closing remarks" "4828": "Q&A" "4873": "Are you setup to use ASI Sound Drivers?" "4925": "Is your audio pointer code calculating independently of the variable-fixed visual frames per second?" "5075": "What sort of problems can high audio latency introduce?" "5238": "Could you use that anonymous union struct trick to access the members of bitmap info header structure more easily?" "5327": "Question about switching Audio APIs" "5502": "Why are we ignoring write cursor?" "5590": "Would splitting related functionality in separate files help?" "5650": "If we use the play cursor as offset, could we not overwrite previously written audio data?" "5977": "Comments about Audio APIs again" "6014": "Would rendering at 60 FPS help with the audio latency?" "6076": "Could you change latency values?" "6093": "Is it possible that OBS is affecting the audio latency?" "6122": "Closing remarks" --- name: "day020" title: "Debugging the Audio Sync" markers: "164": "Fixing an off by one error" "312": "Explanation of off by one errors" "433": "Overview of the state of our audio code" "665": "A breakdown of how time is spent during each frame" "847": "A possible, though not great, solution to audio latency" "982": "Tradeoff between audio lag and input lag" "1071": "Falling back to a little bit stupider" "1318": "Beginning to change the code for the audio output method" "1368": "Finding the minimum expected audio latency" "1651": "Converting to seconds using dimensional analysis" "1894": "Writing sound based on the audio latency" "2054": "Great aside about keeping code fluid and a bit messy in the early stages" "2220": "Determining the position to write the audio to" "2787": "How to deal with the low latency case" "3076": "A puzzling situation" "3180": "The aha moment" "3334": "The approach we will be taking for low latency" "3456": "The higher latency approach" "3674": "Another snag" "4028": "Putting our approach down in words" "4382": "Implementing the two case latency handling" "4714": "Do over due to deleted code" "4808": "Putting in the latency branching code" "5015": "Determining if the sound card is latent" "5162": "Mapping the WriteCursor and the PlayCursor into the same space" "5271": "Overview of the code determining how to write the sound" "5400": "Cleaning up" "5482": "How can we possibly predict how many bytes the game should write?" "5582": "Getting sound output separately with GameGetSoundSamples()" "5805": "More cleaning up" "5863": "Computing SafetyBytes" "5946": "Implementing GameGetSoundSamples() in the game code" "6010": "Testing is surprisingly successful, no bugs? NO WAY!" "6167": "Improving our sound output debug drawing" "6505": "Recording some additional details in our markers" "6996": "An assertion fires and some cleanup" "7113": "First look at the debug drawing output and adding global pause key" "7358": "Taking a good look at the debug drawing output" "7480": "A couple early questions" "7547": "Final Thoughts?" "7602": "Drawing another debug marker" "7853": "Improving our estimate of the PlayCursor position to reduce latency" "8279": "Taking a look at how our estimate lines up" "8353": "Drawing our 480 sample jitter window" "8535": "Q&A" "8578": "Did you try the audio without OBS?" "8655": "Is it inexpensive to query for the play cursor and the write cursor?" "8703": "Audio seems to be the most complex part until now, which will be the next most complicated thing?" "8818": "Audio asserts are a pain when you're debugging other things. Change to log messages." "8866": "If we had a buffer that played from start to finish, would it be a valid syncing method to manually set AudioTimer = VideoTimer?" "8925": "Fully visualize waveforms and remove gradient. Turn entire thing into massive audio visualizer." "8982": "Could you please increase ToneHz to 512, my crappy laptop speakers can't output 256?" "9029": "Will this audio system be able to handle music and sound, or will the game have to mux the audio for us?" "9068": "How will you make sure that you don't have regressions in some parts that are not that easy to spot right away?" "9114": "I'm sorry if I'm being slow, but I still don't truly understand why exactly the audio is jumping. It just seems like we should be able to handle it more simply." "9159": "Why is the pitch of the sound changing after the game has been running a little while?" "9595": "Callback to earlier half of question: (I'm sorry if I'm being slow, but I don't truly understand why the audio is skipping.) The original audio skipped when we moved the latency to be inside of three frames." "9745": "If it's not too much of an issue, can we have line numbers on the side when you are coding so we can get a grip of where you are." "9788": "It's more likely to be the accumulation of a small value onto a larger value that is a numerical problem. Mantissas not lining up." "9843": "Wrap-up" --- name: "day021" title: "Loading Game Code Dynamically" markers: "89": "Intro to the episode" "186": "About implementing and using a scripting languages" "375": "Benefits of loading game code dynamically" "509": "Starting on dynamic code loading" "698": "Separating platform and game code to different translation units" "956": "Getting functions from game dll to the platform executable" "1469": "Getting Functions from platform executable to the game dll" "1860": "Searching compiler flags for building a dll" "2118": "Dll main" "2408": "Exporting functions from a dll" "2847": "Loading and unloading the game dll on the fly" "3017": "Moving local persist variables from the dll to game_state" "3151": "Avoid locking the dll to allow rewriting" "3720": "Episode recap" "3817": "Q&A" "3831": "-LD to build a dll and removing incremental building" "3983": "Question: We have small code right now. How does dynamic linking and compiling to an exe work with huge games that are multiple gigs?" "4059": "Casey spoils tomorrows stream by telling people not to spoil it" "4080": "Short recap on loops" "4228": "Question: Do you recommend playing around with dll files, or are they mainly used in specific cases?" "4265": "Question: Can someone now create a dummy handmade.dll and use it to intercept the GameUpdateAndRender function to get a pointer to game memory and change stuff. Is security something you will cover in a later stream?" "4414": "Question: We've got a tiny application right now so if code takes minutes to compile, how are we going to do what we just did?" "4568": "Question: Would you be able to load the dll yourself using ReadFile() and implement getProcAddress() as well, assuming there's an easy way to make the memory executable like mmap()" "4696": "Question: Is this technique still possible without using passing of the large memory blob between the dll and the exe?" "4860": "Question: Does the dll prevent the compiler from inlining?" "4907": "Question: How are we going to implement dll's on Linux/Mac?" "4982": "Question: Are you ever going to write the platform layers for other platforms on the stream in the far future?" "5042": "Question: Is the process roughly the same for doing the Linux equivalent of sharing libraries?" "5142": "Question: Your #define typedef magic kinda bugs me, in that it hides the arguments/return type away from the implementation. How much of a win is having the signature in one place?" "5214": "Question: How does Windows manage memory in a dll? Is there a dll process page? Where are variables made/the statics stored? How is heap managed when allocated from a dll?" "5834": "Question: Doesn't Windows know [who called it] by the instruction pointers leading up to the VirtualAlloc() call?" --- name: "day022" title: "Instantaneous Live Code Editing" markers: "2": "Recap and set the stage for the day" "142": "Remove DllMain() and successfully recompile" "208": "Demo hot reloading, and determine to reduce the update lag and enable debugging of it" "358": "Visual Studio .pdb unloading" "420": "Try using cl's -Fd flag to output the .pdb to a different location, without success" "632": "Try using cl's -PDB:filename linker flag to output the .pdb to a different location, successfully" "676": "Set the .pdb location using a batch file invocation of %date%" "1019": "Test out hot reloading to find that we create many .pdb files" "1106": "Suppress the output of del by piping it to a file" "1229": "Piping stdout and stderr" "1302": "Pipe both the stdout and stderr output of del to NUL, and disable incremental linking" "1411": "Find that our compilation output is more concise, and that we are hot reloading in the debugger" "1455": "Enable Win32LoadGameCode() to use the ftLastWriteTime to determine when a DLL update is necessary" "1989": "Find that hot reloading continues to work latently" "2014": "Make WinMain() reload the DLL if it was updated, using CompareFileTime()" "2145": "Try hot reloading to find that it is now instantaneous" "2249": "Try setting the Working Directory to the data directory, and find that Win32GetLastWriteTime() fails to find our .dll file" "2389": "Enable WinMain() to locate our .exe file using GetModuleFilenameA()" "2744": "Find that we get the full path" "2760": "Truncate the path to the base filename" "2911": "Step through our path truncation to show it all happen" "2992": "Introduce CatStrings() for WinMain() to construct our .exe file path" "3325": "Implement CatStrings()" "3469": "Step through CatStrings() to find that it does what we want" "3584": "Set up the new Q&A question grabber, and reflect on our hot reloading improvements" "3681": "Q&A" "3705": "Unseen Owl of Shame moment on the chat machine" "3744": "How do you manage to time your coding so perfectly?" "3754": "You mentioned yesterday you had something you wanted to address from a previous day, but never did" "3811": "Will this capability be in the shipping game or will it only be for debugging?" "3855": "Does the reload of the DLL reset the game entirely?" "3861": "Demonstrate seamless hot reloading" "3907": "How much time have you spent planning this game prior to even starting on Day 001?" "4003": "Are you building the game in two sort of sections, one being core C++ section and the other being a platform service section?" "4041": "Since DLLs are not on OSX or Linux how will we handle these in those environments?" "4061": "Did you list your qualifications in a previous stream? If not, what are they?" "4093": "Why don't you use dynamic buffer allocation?" "4149": "You said that you are going to show us how to make a game well. What are your qualifications for saying you are making a good game, code-wise?" "4276": "Could you explain your method of compressed programming somewhere in writing, on the forum, maybe?" "4362": "When FindFirstFile() is called, does Windows actually read anything from disk" "4386": "One way to abuse the fact that the game is in a separate DLL is to open the game part up to modders and modders' tools" "4440": "One common theme in these videos is that you shouldn't clean up OS objects or memory on shutdown, but OS objects will presumably need to be cleaned up on DLL reload, correct?" "4494": "I wish you had a subscriber button, this is awesome. Are we in Q&A time right now?" "4629": "Are we going to see the process of designing the game too, as in the game concept rather than the code?" "4831": "Can you give some examples of some types of code changes to the game DLL that won't work well with hot reloading?" "4959": "Do you have any opinion on lua, such as using it for configuration or more comprehensive scripting?" "5049": "Do you think this method of hot reloading can be useful for developing other types of software besides a game, like e.g. a mobile app or business system?" "5100": "Do you think there is a case for DSLs in some cases, instead of using C for the code, like for AI?" "5179": "One benefit of lua is that you don't have to recompile at all" "5205": "Will the game engine be mostly generic or tailored for this game?" "5248": "Could you talk about Larrabee and Xeon Phi?" "5296": "Do I recommend C over C++?" "5477": "As a beginning programmer, is Unity a good start to develop some basic games?" "5518": "You complain a lot about the Windows API, but clearly other platforms aren't any better. What would your ideal, general-purpose platform look like?" "5536": "Were there any personal projects that you had done prior to graduating high school / college that came in handy when looking for a job? How did you come to work at RAD?" "5623": "Do you think games can make use concurrency and parallelism more than it is now?" "5646": "Where can I find the song used in the YouTube trailer?" "5675": "Can you show how to set keybindings in emacs?" "5747": "What do you think of Blizzard as a game development company?" "5818": "Perhaps this question is better suited for the forums: What guidance can you provide for newbie game developers looking to find artists for their game projects?" "5859": "You mentioned on-stream metaprogramming in C. What does that look like? Been dying to know" "5873": "Metaprogramming in C" "5992": "You mentioned that you don't think you will make much of a profit from becoming a Twitch Partner, but you get 7× more viewers than some of the full-time streamers" "6124": "Sorry if I missed it, but did you fix the expected-bytes-until-flip bug in the audio code?" "6157": "Can you make a lot of money by C programming?" "6271": "Do you use hot reloading in any of your non-game projects?" "6281": "Why do you think so few people learn this stuff?" "6609": "I know some of your friends went to ArenaNet, but I can't stress how much Guild Wars 2 feels awful" "6639": "Call it here" --- name: "day023" title: "Looped Live Code Editing" markers: "165": "Review of the live code editing feature" "253": "Building a demo to show gameplay tuning workflow" "540": "Testing the demo" "680": "Adding jumping" "850": "Necessary improvements to square drawing" "944": "Jump tuning" "1012": "Problems with gameplay tuning and a solution" "1099": "Making a loop editor for code" "1173": "The ease of storing the input stream in memory" "1225": "Writing it out to disk instead" "1309": "Creating a win32_state structure that we can pass around" "1350": "Press L to record" "1481": "Usage code for recording and playback" "1536": "Implementing the record and playback functions" "1694": "Functions to handle the recording output file" "1864": "Functions to handle reading in the recording file" "1942": "Some code to loop the input playback" "2096": "Testing the recording and playback" "2268": "Bug-fixing" "2406": "Input record success, moving on to record game state" "2547": "Implementing recording of game state" "2874": "Testing, and a failure to loop" "2983": "Successful looped editing demonstration" "3290": "Playing around with window types" "3587": "Transparent Window! And Access Violation!" "3716": "Improvements to transparent window." "3827": "Final Thoughts" "3984": "Q&A" "4010": "Does Win32PlayBackInput need to return status in case the file read fails and/or reaches the end, since in those cases the function output data structures will be stale or invalid?" "4116": "Will this break when you make changes to the game_state structure?" "4290": "Why didn't you use a switch for all the VKCode stuff?" "4314": "Since it's mostly zeroes, do you think it'd be worth writing out the game state in a sparse way using a simple RLE or something, or is performance sufficient? Or perhaps that would make performance worse?" "4402": "What's on the schedule for next week?" "4437": "Are you going to show how to create more debug tools like this?" "4501": "Regarding saving game state for recording, won't we run into problems if we port a system that doesn't allow us to specify a base address?" "4568": "Any chance for a high-level overview while cleaning up?" "4605": "Isn't a two gig snapshot of your game memory crazy huge though?" "4757": "I think your sine wave is a tad bit off on land of the jump." "4778": "I'm thinking maybe less about the error and more about what happens at the end of the stream when it loops, doesn't that generate an extra repeated input event played back, or am I missing something?" "4885": "Can you clarify if function pointers are part of that game_state block, maybe elaborate on what could ever cause it to fail or misalign?" "5066": "How can we make the playback work if we have no base address?" "5140": "Wouldn't the address spaces of two game_state's clash?" "5220": "Would a memory-mapped file that doesn't commit to disk be faster to read/write from?" "5278": "I thought you were going to use the memory snapshot as a game save, but you're using it like a save state in an emulator." "5310": "How easy do you think it is to re-arrange an existing codebase so that it supports the instant live code editing feature, and what steps would need to be taken to get there?" "5402": "Will there be a Christmas special?" "5418": "How will replay work once you have start-up logic for the game? How will it be skipped? Will it just work?" "5464": "Clarification of earlier question (How often do you look up code?) How often do you study code on your own?" "5602": "Perhaps ReBaseImage() regarding loading dll at location?" "5631": "Suggestion to add -mix to the linker for fixed dll location." "5714": "How long did it take for you to get to a point where you can concieve of a feature and with little effort know exactly what you need to accomplish to realize that feature?" "5923": "Couldn't you create an offset pointer struct which overloads the unary * operator?" "6043": "Have you got some good explanation on how you architect code, is that in the text you wrote about your work on the Witness?" "6126": "I have to spend a lot of time unlearning what I was taught just to get to features which should be easy, but were made hard by the kind of programming I learned in school. Have you had a similar painful unlearning process?" "6291": "Wrap-up" --- name: "day024" title: "Win32 Platform Layer Cleanup" markers: "65": "Goals for the day" "170": "Fixing a dumb audio bug" "498": "Failing to find a supposed SUCCEEDED related bug" "588": "Concerns about WasDown/IsDown" "745": "Fixing a bug in our gamepad input handling" "877": "Fun? with Krita" "1007": "Back to Paint to illustrate the input bugfix" "1257": "Changing our renderbuffer to have fixed dimensions" "1419": "Improving the build.bat file" "1500": "Changing the write location for our .hmi files" "1657": "Writing some helper functions to create the dll path" "2031": "Step-through" "2172": "Taking our helper functions and using them elsewhere" "2423": "Testing the changes to input recording" "2482": "Input Assert firing and turning off Topmost window" "2565": "Changing Win32GetLastWriteTime() to use GetFileAttributesEx()" "2762": "Using DeviceIoControl to potentially speed up input recording hitch" "3066": "Removing stub functions from handmade.h for easier porting" "3230": "Looking at improvments to our 1GB VirtualAlloc()" "3312": "Whiteboard illustration of virtual memory" "3540": "Looking at real world virtual memory addresses" "3699": "Translation of virtual memory addresses into physical memory by the TLB" "3846": "So what are large pages?" "3926": "Changing VirtualAlloc() to use large pages" "4038": "Putting aside the large page support for later" "4106": "Q&A" "4190": "Can we go over really fast an overview of the game recording code?" "4456": "When you're saving the game_state snapshot, how big is the file?" "4525": "Can you check if the StringLength() needs a win32 prefix, or is this game code?" "4537": "How many lines of code is the finished game estimated to be?" "4562": "Maybe use two randoms in your batch file to get a more unique file name?" "4580": "Any advice on where I could go or what to do to pick up a bit more coding or knowledge experience?" "4625": "What is a good example of well-written game code? Everyone talks about the DOOM source code." "4649": "Assuming you want to record exactly what happens in the game, how would the looping handle random values; Say enemy bullets that are fired at random angles?" "4703": "If we dump memory to disk in a large-scale application, wouldn't that cause more than a 1GB footprint for every state?" "4774": "I don't get the stuff where you declare a variable without initializing it, and then you use the address to it in a function call. Is that a dummy thing, or what is it used for?" "4909": "You can make the recording instantaneous using copy-on-write pages." "4978": "Would the sparse file flags dropped the .hmi file size?" "5009": "I'm still not sure why we're using the Windows API to get memory instead of the standard library. Why are we making Windows calls if we are supposed to be doing everything from scratch?" "5089": "As the game grows, how are you going to partition the game memory between systems to keep the record-and-playback feature working?" "5120": "Would it make sense to temporary lessen the size of game memory we don't use at the moment anyway?" "5154": "Are you happy with the timing FPS results? I found an old article on _rdtsc() for more accurate timing." "5221": "When would the Mac code start? I am following with Windows in a VM and it's really slow." "5266": "Is there any negative effects of making the page size bigger?" "5387": "How do you calculate the size of a struct?" "5498": "Can you add line numbers, so those of us following along have an easier time?" "5630": "I believe some people think that the game_state is saved every time with the input, whereas it is only saved at the beginning of the recording and then modified through input playback." "5661": "Do you think the recording technique will run into problems if we have multiple threads using the game_state?" "5707": "If VirtualAlloc() does not guarantee contiguous memory, could this pose a hindrance to cache optimizations?" "5805": "Where can I get earlier versions of the code? The link only gives me the latest version." "5835": "Wrap-up" --- name: "day025" title: "Finishing the Win32 Prototyping Layer" markers: "107": "Plans for today" "260": "Getting the actual monitor refresh rate with GetDeviceCaps()" "627": "Testing monitor refresh rate getting" "677": "Preparing for future multi-threading" "1022": "Adding mouse debug functionality to our game input" "1418": "Getting the state of the mouse buttons" "1707": "Testing mouse button functionality" "1927": "Making improvements to replay code" "2000": "It's time to get piggy!" "2125": "Allocating memory for our replay buffers" "2281": "Changing Win32BeginRecordingInput to write to memory" "2539": "Swapping out WriteFile() for CopyMemory()" "2762": "Testing our new recording technique to much disappointment" "2940": "Poor man's profiling" "3148": "Stepping through to find the real culprit" "3226": "Removing SetFilePointerEx() for a massive speedup" "3331": "What we were going to do with memory mapped files" "3446": "Let's try it anyway" "3793": "Pulling out input file processing into WinMain()" "4045": "Step-through and removal of an assertion" "4135": "Debugging the memory mapped file failure" "4344": "A peculiar fix" "4398": "Review of the recording code" "4472": "Splitting the file output into two streams for more speedup" "4700": "Testing with some notion of success" "4874": "What's the memory bandwidth of Casey's machine?" "5116": "Looking at multiple sequential records" "5296": "Removing/disabling some debug code for now" "5429": "Final Thoughts" "5507": "Q&A" "5567": "Maybe first copy is causing alloc and zero on fault, maybe a second copy would be fast" "5728": "An interesting part of this project is that you're implementing all the compenents yourself that you'd take as given in an existing game engine. That said, do you intend for these components to be reusable in future projects?" "5792": "Why the pig hat?" "5804": "Why don't you use the Visual Studio profiler and anaylze performance?" "5826": "Remark about 300ms being 10 frames, not 3 frames" "5859": "Does it lag if you save to a smaller file size?" "5939": "Isn't the CPU Memory bandwidth only valid for on-die memory?" "6023": "Is the intent of saving the complete game state to support something like a rewind function that Braid allows?" "6067": "Will you do a string pool?" "6086": "When you say the platform non-specific layer, does that mean game code and renderer and logging sorts of things, or is there a sharper distinction between some of those?" "6135": "A quick test on my PC gave me around 3 GB/s..." "6197": "Is it time to split the source into more files?" "6220": "Would a non-caching write be faster for the memory copy? You know the SSE write instructions that bypass the cache?" "6314": "When are the four .hmi files created?" "6350": "...An AMD A8-6400k (Follow-up to 3GB/s memory bandwidth mention)" "6457": "Are you going to do a moblie port? (Android for example) Would the game loop of a mobile game be any different?" "6531": "How about disk write speed and access time?" "6570": "Why is the CPU even involved in a memory copy like this?" "6661": "What was the reason for choosing GetCursorPos() instead of just responding to the WM_MOUSEMOVE message? Is the message pump not fast enough?" "6685": "Have you ever programmed in Java? For how long?" "6747": "(continuation of Why is the CPU even involved question) Wouldn't the copy speed mostly depend on how quickly memory from one part of the memory gets to the CPU and back? In fact, in my mind it seems like large copies are something that could skip the CPU entirely unless it has something to do with paging." "6872": "Is it worth writing games in Java?" "7023": "Are you in dual-channel write mode on your system?" "7033": "Does the Megabytes have any effect on the performance of the memory?" "7058": "Tom Forsyth comment about modern DMA units not being available to users" "7119": "What do you think of Test Driven Development?" "7167": "Can you explain the bit shifting?" "7464": "You can create a performance heavy application in Java without the garbage collection if you configure it to run as real time instead of virtually" "7593": "Do you consider Visual Basic a programming language?" "7636": "On the memory CPU speed, I see the answer is that the hardware doesn't do this. I guess I'm just envisioning a system where the gigabyte of memory never visits the CPU. I am envisioning a system where the memory can receive an instruction that says locally move a gigabyte over to this location" "7731": "Tom Forsyth comment on using LARGE_INTEGER instead of the bit shifting" "7860": "In your mind, what would be a good way to demonstrate to a potential employer proficiency in the type of engine programming you are teaching?" "7958": "Thanks (And a comment from Casey on the success of the stream)" "8009": "What defines the boundary between a high-level language and a low-level language?" "8200": "When will you start actual game logic?" "8213": "Have you heard of the Rust language?" "8251": "Have you ever dealt with programmer burnout? Or how do you deal with the fact there are days almost no code gets written and on some days massive amounts of code gets written?" "8428": "Any source or book recommendation for understanding the concepts you used better?" "8469": "Have you seen Game Programming Patterns by Robert Nystrom? Are you going to use any design patterns?" "8551": "Do you find it useful to learn many different languages to gain perspective?" "8711": "What do you think about using VCS for one man projects?" "8753": "What's your mindset when looking at a problem that's new? How you approach a new coding problem that you have no pre-defined idea how to solve?" "8793": "Will you write a book after Handmade Hero is done?" "8806": "How long have you been in the industry?" "8819": "I've always been a hobbyist, the more I've learned over the last year, the more I love programming. In your opinion is going back for a four-year CS degree a waste if I want to make things that don't suck?" "8842": "Perhaps the problem with high-level languages is that they are less general, but more domain specific in the first place" "8885": "How does your source code control differ from something like Git or SVN?" --- name: "day026" title: "Introduction to Game Architecture" markers: "0": "First day of Programming the Actual Game" "176": "We'll know how everything happens above the platform layer" "365": "Software Architecture" "410": "...vs. Real Architecture" "580": "Taking the metaphor literally: UML as Blueprint" "660": "The problem with that" "797": "An alternative view: Software Designer as Urban Planner" "915": "The freedom of software: malleable architecture" "1045": "Software Design: How the city works" "1235": "The Art of Defining Boundaries" "1296": "Why you want boundaries" "1541": "Metrics for Architecture" "2052": "Game Architecture" "2095": "What we've done" "2287": "What's to come" "2345": "Principles" "2548": "Input->Update->Render" "2694": "Coupling and the Cache" "2934": "Resources: Load vs Stream" "3358": "Immediate mode vs. Retained mode" "3780": "Is Immediate Mode/Retained Mode like IoC (inversion of control) / Dependency Injection [n.b. No it's not -ed]" "3794": "Is it okay that we're using a fixed time step when users might not make 30fps?" "3860": "Game won't run at a fixed timestep: we'll take in t as a param" "3905": "Are you going to work with Virtual File Systems to store resources?" "3934": "On rendering while updating: What about when the render of something at the top of update() would've changed if we'd known about something that's at the bottom?" "3985": "Update dependencies are a general problem that should be solved by the architect" "4045": "What happens when you need to render in a different order than you update?" "4094": "Explain the variable, demands Naysayer88" "4156": "How do you handle update/render at different frame rates?" "4200": "When you say do update/render together, do you mean do it per entity?" "4235": "Are we planning on networking?" "4260": "How are you going to handle shaders?" "4271": "What language are you using primarily? Where can we view old streams?" "4330": "Would a memory mapped virtual filesystem be a bad move?" "4419": "Will handmade use loading or streaming?" "4432": "Can you go over how streaming fits in to the GUAR?" "4509": "Will combining update and render limit multithreading?" "4607": "Treatise on threading" "4843": "Since the eye can only see at 70fps [citation needed -ed], should we set a max fps?" "4888": "How will we handle vsync?" "4928": "Couldn't you store groups together to win some on a split update / render?" "5005": "Async job system?" "5060": "Whennn willl youuu worrrkkk onnn theee gammmeeee?!?!?!?!?!11!!" "5093": "Will we make a physics engine?" "5117": "Is it okay to post a js/html5 port on my github?" "5214": "Thanks / Next time on... / Holiday Hours" --- name: "day027" title: "Exploration-based Architecture" markers: "0": "Welcome" "142": "Evolution of a Project" "403": "How to drive towards an unknown destination" "576": "The dangers of pre-planning" "747": "The exploration two-step" "982": "Game engine goals" "1021": "LoZ Influence" "1196": "Tile Map - What to modernize, what to keep" "1452": "Goals for Procedural Generation of Levels" "1872": "Rich Combinatoric Interactions" "2084": "There's no plan, folks" "2166": "The coding begins" "2190": "Add something we forgot" "2288": "Clean out old debug visuals/sounds" "2555": "Resolution goals" "2850": "Let's draw a rectangle" "2970": "What to know about bounds for drawing geometry" "3261": "Coding drawRectangle" "3768": "Rounding floats to ints" "3932": "Testing drawRectangle" "4248": "What's that link error when you compile?" "4312": "What things are good to put in a portfolio?" "4335": "Does this work?" "4346": "Thought on making this all completely functional?" "4450": "How do you do compression programming with big teams?" "4560": "Do you think writing structs for things like vectors is good?" "4655": "Are you going to use linear texture layout or something fancy?" "4670": "If C didn't exist what language would you use?" "4730": "Where can we find out info on engine architectures?" "4786": "Particulars on procedural generation? Will dungeons regenerate every time you enter" "4849": "Will the game be generated as you go?" "4918": "What with Jon Blow and Variables?" "4987": "Will you use fixed point?" "5027": "How old were you in the picture on mollyrocket.com?" "5059": "Why are subpixels better than pixels?" "5126": "Will you be growing a beard?" "5138": "Are you going to use linear texture layout or something fancy and swizzly (repeat, but answered this time)?" "5183": "Would the player really notice a 1-2 frame lag of sound in this game?" "5248": "How different would initial rendering be if the game was vector-based?" "5295": "You cut me deep, Casey." "5312": "What's bad about OOP?" "5450": "I'm having trouble understanding the sound stuff, should I worry?" "5513": "Did you work on NWN2?" "5571": "Can the compiler optimize the rect draw based on (lack of) aliasing?" "5670": "Will we be doing Antialiasing?" "5676": "Future old-man baldness strategies?" "5694": "Can you explain the subpixel stuff via video?" "5710": "Are you making a runescape clone?" "5715": "What do you suggest for mobile game dev?" "5730": "Will we be using DX11 for the rendering layer?" "5745": "Pokemans? [no]" "5756": "Disparaging Python?" "5799": "Dinosaurs? [are cool]" "5803": "How can I get a (good) job (like you)?" "5814": "Lazer sharks? [also cool]" "5818": "Mounts? [probably not?]" "5821": "How often do tech limitations matter?" "5882": "Member functions?" "5896": "Owl of shame is navi?" "5911": "How will you use the game memory block?" "5941": "What if MinX and MaxX are both less than 0?" "6005": "In a perfect world... Pokemans? [no]" "6029": "Moral message? Hired a writer?" "6047": "Handy Links / Holiday Hours / Happy Coding" --- name: "day028" title: "Drawing a Tile Map" markers: "54": "Overview of the day" "210": "Floating point color discussion" "1010": "Actually doing the color in floating point" "1420": "Showing some of the possible structs we will want to pull out" "1503": "Starting a basic tile map" "1690": "Looping through the tilemap to draw" "2252": "Getting a player to the screen" "2786": "Basic character movement" "2880": "Debugging slow player movement" "3514": "Q&A" "3540": "Question: Is Sleep() still making us miscalculate the fps" "3675": "Question: dtForFrame is only in one of the inputs" "3787": "Question: Maybe we should sync our frames with vsync due to it dropping our frames" "3830": "Question: On the topic of tilemap size maybe use smaller tiles then use 2 tiles for doors" "3866": "Question: Why not use anything created before like sdl, opengl, and so on (new person question)" "3943": "Question: Fixed-point or floating point" "3982": "Question: Would not anyone expect 4pixels per frame at 60fps be a little jerky" "4048": "Question: Yesterday you discussed explorative programming. How do you compare that with AGILE development style?" "4205": "Question: Was procrastination a problem for you?" "4293": "Question: Could all the print output cause the lag in the input?" "4327": "Question: Use space on top/bottom for UI" "4354": "Question: Can we pack the colors in a struct?" "4361": "Question: Is there a reason to set the tiles to a square other than ease of use?" "4400": "Question: Do you add anything to your almond milk other than soaked almonds and water?" "4404": "Question: From yesterday's stream how can you tell the difference in how to change the direction of your design or is that a fundamentally hard problem" "4577": "Question: Would it be bad to do a rectangle tile, since you get a rectangle by doing an ortho view of it anyway?" "4687": "Question: What debugger do you use on Linux?" "4775": "Question: Why do we see 9 threads on the program exit?" "4983": "Question: Are we locked into a tile size once we get going or can we make that dynamic per level or room in the future?" "5077": "Question: What about selling t-shirts?" "5098": "Question: With your compression based programming do you find yourself writing facades for everything so you and others can interact with the modules" "5175": "Question: Why not use Clang?" --- name: "day029" title: "Basic Tile Map Collision Checking" markers: "150": "Review of what's currently been done" "197": "Clearing the screen to black and offsetting the drawable area" "409": "Player collision with the tilemap" "1043": "Moving player initial position inside the map" "1231": "Clearing only the parts of the screen not drawn on" "1390": "Function for checking if a point is occupied and tile_map struct" "1625": "Accessing tilemap data as 1-dimensional array" "2116": "Adding player width to the collision" "2270": "Making player change the map when walking through a door" "2636": "About storing all tilemaps in one big structure" "3028": "Start on storing and accessing multiple tilemaps and the world struct" "3660": "Short recap on where we are" "3736": "Q&A" "3790": "John Blow points out we haven't initialised the world struct members" "3823": "Question: Why does player sometimes stop a pixel before the wall?" "4476": "Question: Are your variables for tilemaps too similar to each other or am I just easily confused?" "4572": "Question: Is there an advantage on using bool32 instead of using bool 8-bit?" "4627": "Question: Can you go over briefly how to encode the tile data in a single uint32?" "4675": "Question: Why does left and right side collision work but not the top and bottom?" "4843": "Question: Why save TileWidth and Height if those values never change?" "4862": "Question: What are the differences between structs and classes?" "4994": "Question: Do you always put int32 or can you use only int?" "5085": "Question: So int32 is because you want to make the game for 32bit computers?" "5165": "The player moves faster diagonally than it's supposed to. Are you planning on fixing that?" "5230": "Question: I'm not familiar with #define, what is it used for?" "5314": "Question: When you use int32 does it have a different influence on the code than normal ints?" "5405": "Making the platform header C compliant" --- name: "day030" title: "Moving Between Tile Maps" markers: "190": "Recap" "396": "About the process of writing code; Messy first, clean after" "478": "Passing information about tilemap" "647": "Checking if player is moving to a different tilemap" "771": "Finding the next tilemap and querying the point" "2167": "Calculating the position in the new tilemap" "2575": "Storing X and Y positions relative to the tile" "3367": "Moving the player on to the new tilemap" "3649": "Floor instead of truncate" "4248": "Q&A" "4312": "Question: Can you talk about the inline keyword? Do you apply any strategies to make sure the compiler does not ignore the request?" "4393": "Question: Are we using C or C++?" "4487": "Question: How did we start the code for the game?" "4507": "Question: What's so bad about including math.h?" "4554": "Question: Why not substract 1 if input is under 0, instead of using floor()?" "4629": "Question: I thought integers were faster to compute than floats, even if the cpu has a floating-point unit." "4783": "Question: How do you decide when to pack things in a struct?" "5248": "Question: Why would we care about screen coordinates? Isn't that just platform code." "5366": "Question: Are you going to make walls obstruct the player the same way the player currently obstructs the walls?" "5417": "Question: Can you explain the raw_position and canonical_position again?" "5536": "Question: Instead of checking three points on the player, wouldn't it be better to check only the side the player is moving towards?" "5679": "Question: Why not have a single set of coordinates for the player that maps the player to a world position?" "6134": "Question: Are there any consequences of using inline in early development, i.e harder debugging?" "6202": "Question: Wouldn't it be better to call the X and Y variables something more descriptive?" "6352": "Question: The game will happen in whole screens without any scrolling or camera movement?" "6493": "Question: Could you explain how pointers/references are working or what you use them for and why?" "6542": "Question: Was there ever a point in your career where you used these unfortunate structure packing practices?" --- name: "day031" title: "Tilemap Coordinate Systems" markers: "0": "Welcome / Recap" "226": "On Scrolling" "294": "Scrolling for Free" "404": "Preview of Coming Attractions: Math Functions" "673": "Looking at floorf" "787": "SSE2" "1188": "Optimization flags: letting the compiler do it for you" "1459": "Math utility layer" "1647": "Trig/Vector Math Looms" "1728": "Coordinate Systems: Why we want them" "1981": "Screen coordinates vs All Math Ever" "2404": "Defining size in pixels and meters" "2880": "TODO: Packing our tilemap indexes" "3454": "TODO: Resolution-independent tile-relative position" "3568": "Q&A" "3604": "Will we be making a map editor?" "3625": "What were you talking about in terms of fast floor?" "3669": "Do enough people have SSE4? (n.b. steam hardware survey: 77% have SSE4, 99.8% SSE3)" "3837": "Can you not store anything and just regenerate everything from seed?" "4011": "Suggestions for speeding up floor (/fp:fast)" "4269": "Why do you do 'Result = foo(); return Result;'?" "4465": "Is it a good idea to be drilling down into intrinsics this early on?" "4547": "Is tile-relative for the real32 coordinates better than tilepage-relative?" "4710": "Why not just store location in world coordinates and div/mod to get tile info?" "4796": "Could our sparseness let us better use the top 28 bits of the tilepage index?" "5042": "Do you know of the intel intrinsics guide?" "5126": "Why is all our game-specific work so far in handmade.cpp?" "5205": "Are we going to move the origin to the bottom left?" "5234": "Line-drawing suggestion" "5283": "Will you be able to find ARM equivalents to your intel-specific instructions?" "5376": "How are we going to deal with different types of tiles?" "5435": "Week Roadmap / Outro" --- name: "day032" title: "Unified Position Representation" markers: "97": "Recap on what we're set out to do" "375": "About canonical position and using it for the player position" "787": "GetCanonicalPosition() to RecanonicalPosition()" "1922": "Debugging the new code" "2294": "Movement units from pixels to meters per second" "2469": "Recanonicalize edge case debugging after assertion fail" "3004": "Back to changing movement units" "3220": "Casey enjoying the little things" "3461": "Debugging player position" "3822": "Q&A" "3859": "Would this be the time to put on screen text for debug info?" "3915": "What is the variable called 'Gray'?" "3955": "How does the difficulty of conceptualising this type of code compare to say coding the backend to a web application?" "4023": "The window title bar is a nice place to spit out some text!" "4057": "About replay buffers: I don't think we ever use the 0th buffer in the Win32State" "4381": "When do you decide to add visual cues to help with debugging?" "4468": "What are your thoughts on the progress you make daily?" "4565": "Does the code actually handle skipping a tilemap?" "4617": "Can the player go diagonally through two wall tiles joined by corners with the current collision detection code?" "4699": "Why are you so fond of inline?" "4838": "Are you going to have input envelopes for feel like acceleration and fricksion?" "4864": "Can you explain what you meant by canonicalization in some simpler terms?" "5171": "Would this kind of code be good for unit tests/fuzz tests to make sure strange corner cases don't creep around?" "5230": "Are there reasons why programmers of older adventure games chose to move the character around the map and not vice versa?" "5372": "Earlier you said const is ugly? Ugly because of how it looks or for some other reason?" "5509": "What's your preferred 2D coordinate system? Y going up or down?" "5568": "Now that there's no raw_position can we rename canonical_position to position and recanonicalize to fix or rebase?" "5598": "Will we be using the tilemap for path finding or some other way to get smoother movement?" "5631": "Will you release your version control system?" --- name: "day033" title: "Virtualized Tile Maps" markers: "123": "Review of position representation" "155": "Today's agenda" "235": "world_position and changing y-axis" "720": "the problem with floating point for positions" "998": "solution: integers and floats" "1173": "sidebar: scrolling the screen works fine too" "1207": "big idea: tile chunks and sparse storage" "1593": "implementing our new coordinate system" "1856": "tangent: toroidal topology" "2155": "back to implementation of new coordinates" "2238": "extracting chunk coordinates from a world_position" "2645": "implementing tile chunks" "3021": "Setting up test data" "3050": "emacs keyboard macro roulette" "3246": "rendering from chunks using new coordinate system" "3287": "super piggy!" "3525": "debugging commences" "3648": "success" "3680": "greed: simple scrolling" "4059": "success again... finally" "4104": "Q&A" "4146": "Why not compute the chunk mask from the chunk shift?" "4444": "How did you generate the map? (A: he hasn't yet, it was typed in)" "4466": "How will you do a third dimension in the new coordinate system?" "4564": "How will you handle screen boundaries with the new chunk size?" "4626": "Is a chunk a quarter of our test map?" "4658": "How about operator overloading?" "4698": "Shouldn't we be thinking about networking and threading from the start?" "4775": "What does 0xFFFFFFFF represent?" "4842": "I'm surprised by your choice to flip the y-axis. Does it really make the math that much easier?" "4977": "I've never used hex literals, I use UINT32_MAX" "5037": "Why not program at a higher level?" "5169": "Why introduce meters?" "5223": "Will you be checking code complexity, introducing smaller functions?" "5263": "Did you set up a Kickstarter?" "5288": "Wouldn't it be nice if tiles were 1.0m instead of 1.4m?" "5333": "Closing thoughts" --- name: "day034" title: "Tile Map Memory" markers: "0": "Intro" "278": "The more you know" "505": "Time to program" "570": "Adding smooth scrolling" "742": "Scrolling works - next test code from yesterday" "840": "Change position offset to be from the tile center" "1035": "Calculating new tile from center offset (discussion)" "1330": "Implement tile offset from center" "1690": "Player moves faster for testing" "1793": "Make a larger world" "2200": "Start creating a new tile map procedurally" "2610": "Persistent game storage" "2990": "Size type" "3870": "Going for it" "4150": "Fate" "4260": "Summary of the day" "4480": "Q&A" "4565": "Garlandobloom says hi." "4578": "Can you explain the motivation behind controlling the page granularity." "4955": "Is the memory arena for more temporary objects than we're storing in the game state directly?" "5130": "Why not have smooth scrolling?" "5180": "We already have the -Oi compiler flag set." "5372": "Does using the memory arena still allow you to hotload your code?" "5491": "Will we be implementing our own trig functions?" "5520": "Will there be enough memory to store the entire sparse tile map?" "5563": "Why not just allocate a large 1D array?" "5740": "You're using a lot of pointers here. (Rant)" "5973": "Will the memory arena be aligning the assigned memory?" "5992": "Don't forget to disable -O2 again." "6005": "Comment on calling sin/cos for x86" "6057": "Why don't you use lookup tables for sin/cos (Rant)" "6162": "How can you say you don't need to free up memory?" "6208": "Is memory access slower than MOV?" "6285": "Why are tiles used? What is the real benefit of tile mapping?" "6362": "Remark on x87" "6392": "Conclusion" --- name: "day035" title: "Basic Sparse Tilemap Storage" markers: "0": "Intro" "130": "Making some rooms" "210": "Making some doors" "319": "Lots of small rooms and Tile ID values" "525": "Now you can see the limits of the world" "560": "Make rooms only in some places - Random Numbers" "660": "Yangtian Li's Talent" "703": "Back to random map generation" "1638": "Not sparse yet" "2010": "Making doors" "2467": "Going back to display single room" "2653": "Tile map review" "2930": "Adding the ability to go up and down" "3410": "Continue the madness and add some stairs" "3830": "Up and down" "4020": "Q&A" "4062": "Would you use DeMorgan's Laws?" "4218": "Do you have emacs commands with Visual Studio?" "4245": "Have you already decided what PRNG algorithm you're going to use?" "4262": "As you put the tile map in 3D dimensions, could this be related to a voxel octtree algorithm?" "4458": "Is there a reason for the chunk size to be a power of 2?" "4594": "When do you use #define instead of local variables?" "4752": "Why are you using inline in variables?" "4770": "Why not use bit flags for floors and such?" "4814": "Why would you prefer an array of tile chunks?" "5070": "Are you following Robert C. Martin Rules?" "5080": "Are we planning to load/unload tile chunks on demand?" "5140": "How much of this code will be used in the final procedural generation?" "5186": "Are we planning on making the tile map layered?" "5222": "Microphone question." "5235": "Why suffix types with 32 such as bool32?" "5315": "Will we need compression for basic sparse tilemap storage?" "5358": "How computationally expensive is the sparse storage?" "5592": "Should rooms only be created when the player is close to them?" "5941": "Are you worried about memory leaks?" "5971": "Are ternaries bad?" "6002": "Why is not possible to save the full map?" "6025": "Conclusion" --- name: "day036" title: "Loading BMPs" markers: "0": "A recap of previous stream" "125": "New test assets for Handmade Hero project" "286": "Introduction to loading BMP files" "388": "Handle player moving up and down 'stairs' before the BMP loader" "560": "Context-switch cost" "646": "Moving up an down implementation" "885": "Difference between tile map system and tile map positioning system" "954": "Implementation continued" "1033": "Fixing generation code" "1305": "Generation code fixed" "1358": "Implementation complete. Working tile map system" "1507": "Loading BMP files" "1590": "A talk on the game's screen resolution" "2170": "Implementing loader" "2360": "Crash course on how to read file formats" "2638": "Debugging a BMP file in memory" "2940": "Processing the BMP file header" "3043": "Packing a struct to avoid padding" "3233": "Processing the BMP pixels" "3560": "Q&A" "3584": "Perfect pitch would sell that!" "3658": "I missed the part where you handled the endianness of the file, or are bitmaps always the same?" "3716": "Do you prefer #pragma pack or gcc-like annotation?" "3748": "What's your threshold for number of function parameters before putting them into a single structure?" "3797": "Could you please describe how the sparse tilemap storage is done so far?" "4273": "Why not use a function template to read raw bytes into any struct you cook up, one primitive at a time, instead of compiler annotations?" "4499": "How will we handle memory when reading files? Would it be wasteful to read into our memory pool, then only use part of it?" "4601": "Could you explain how to handle platform specific data?" "4796": "Would it be easy to implement a generic sparse array to solve our tilemap problem (possibly overloading)?" "4862": "So we have world chunks and -tiles, didn't we also have screens?" "4905": "Why wouldn't you use a function template in the example mentioned before?" "5231": "Will you write asset exporters/importers to get the assets into an efficient format or will you rely on the asset creators tools?" --- name: "day037" title: "Basic Bitmap Rendering" markers: "19": "We're goin' in" "130": "Recap on where we are" "252": "Debugging image file formats 101, creating structured art" "537": "Viewing the structured art in the debugger" "695": "Changing the art to give better information" "818": "Reverse engineering the byte order" "1015": "Why to know how to do this" "1149": "Shifting the alpha values to align with our pixel format" "1339": "Top-down vs bottom-up and filling the backbuffer" "1754": "Loading the actual test art" "1915": "Return relevant information about the bitmap" "2092": "Loading hero bitmaps" "2707": "Displaying hero bitmaps" "2770": "Debugging busted hero bitmaps" "3788": "Getting more info from the bitmap headers" "4057": "Q&A" "4090": "Stream spots a typo" "4120": "Stream spots another typo" "4149": "Will we stick to using bitmaps for the duration of handmade hero, or delve into the lands of PNG?" "4219": "What's the advantage to defining the bitmap header yourself instead of using Windows's?" "4264": "Are we converting our loaded images to a runtime texture format?" "4300": "Why not use a simple custom format for assets?" "4310": "PNG is lossless" "4357": "Are you going to do different blending modes than alpha blending?" "4450": "Should asset loading code be in the platform specific or independent code?" "4503": "Correction to alpha blending question: sub-pixel rendering" "4772": "When we get alpha blending, will we think about gamma correction?" "4837": "Will we be doing resampling to get bitmaps on screen with arbitrary sizes?" "4856": "Will Handmade Hero have Mordenkainen's faithful watchdog?" "4895": "Cool command line texture is homemade" "4903": "Are bitmaps going to be in an atlas file? *reminder on what kinds of questions to ask*" "5008": "I saw a height * (width - 1), should that have been (height * width) - 1?" "5216": "In tiles code, will the area where it's possible to move be imported in bitmaps too?" "5276": "You can simplify DrawBitmap() by changing MaxX initialisation to MinX+Bitmap->Width, same for height" "5340": "Why not embrace the inverted bitmap format?" --- name: "day038" title: "Basic Linear Bitmap Blending" markers: "0": "Prestream stuff" "558": "Intro and welcome" "652": "Where we left off from last time" "677": "Fixing the hero's color" "976": "Figuring out what the shift values are" "1128": "Bitscanforward" "1673": "Renaming bitscanforward to FindLeastSignificantSetBit" "1776": "The intrinsics thing" "1816": "Finding out what compiler we're on" "1887": "Making a compromise: Allowing the intrinsics file access to the platform layer" "2000": "Determining what compiler is being used" "2480": "Simple version of using the alpha channel" "2720": "Alpha as an opacity value" "2796": "Implementing 0-128 off, 129 onwards on for alpha" "2960": "The dumb, slow way to do alpha blending." "3004": "Krita crashes.." "3047": "Blackboard session explaining alpha blending using the background value" "3061": "'Deriving' the formula for a linear blend" "3482": "The canonical form of a linear blend" "3525": "How the 't' works in the linear blend formula" "3635": "Implementing the floating point version of linear blend" "4015": "Drawing the herohead at the location of the player" "4043": "Q&A" "4086": "Stream spots a typo!" "4117": "Stream suggests to assert the bitmap assertion mode!" "4152": "You do not need #pragma intrinsic if you include " "4253": "Would it be worthwhile to avoid converting to float while doing the alpha blend?" "4366": "Why is the Windows-logo still visible at the top?" "4451": "Are there other ways to alpha blend and should you be taking into account which colors are easier to see?" "4866": "Are we at all concerned with the destinations alpha?" "5128": "Will the final blend favor the source over the destination, or is linear good enough?" "5159": "How would you deal with other picture formats such as png, jpeg, etc." "5213": "Why is the mask so complicated to use?" "5271": "Did you mean the other compiler LLVM or Clang?" "5317": "In the bitscan function what about returning index negative one if not found?" "5344": "Can you go over the linear alpha blend diagram again?" "5676": "Is the large VirtualAlloc() at the beginning similar to Linux mmap()?" "5751": "What bitvalue is 50% brightness?" "5854": "Does the display bitmap operation actually do anything with the alpha channel?" "5878": "The solid curve on Wikipedia's gamma correction is the linear space intensity. Should be what you're looking for." --- name: "day039" title: "Basic Bitmap Rendering Cleanup" markers: "0": "Intro and Welcome" "295": "HeroBitmaps structure" "338": "Loading all hero bitmaps" "483": "Drawing loaded bitmaps in the correct order" "572": "Update hero by facing direction based on movement" "701": "Centering the hero on his rectangle" "860": "Finding the center of alignment" "928": "Drawing the bitmap based on alignment" "1055": "The bitmap-changing macro" "1209": "Changing DrawBitmap() to be based off of top and left alignment" "1409": "Explanation of how to draw hero based on alignment" "1545": "Changing the game such that the camera stays centered" "1630": "Adding the camera's position" "1785": "Computing where the player actually is" "1936": "Tile map difference" "2036": "Accounting for the AbsTile" "2230": "Fixing the movement" "2425": "Moving the camera to the player in Z" "2469": "Keeping the camera locked to the player" "2845": "Fixing left and top clipping" "2895": "Explanation of how to fix clipping" "3100": "Checking the framerate" "3158": "Fixing live code loading" "3569": "Testing if hotloading is still functioning" "3635": "Q&A" "3706": "Can you do that live code with a function call? That could just be a poke. -Geneticspecies" "3725": "Enumerations. Am I correct to say you've not used them in Handmade Hero yet? I'm guessing this is simply because it's too early to know what will eventually require enumerations and not some other reason." "3758": "Why not layer the individual bodyparts into a single bitmap that way you only have to draw one image instead of three?" "3800": "Are you wearing a blue cape like the Handmade Hero today?" "3811": "I just wanted to point out that there is a magnifying tool in windows that came with aero" "3909": "Don't you want to test the hotloading? -Andysz" "3939": "HAHA YOU SWORE! -Garlandobloom" "3967": "Can you add a include to handmade.h?" "4076": "Why does the guy have no feet?" "4097": "How do you know which compiler options, like clr and standard headers, you want to use?" "4246": "Changing the literal value of a variable is a peak and poke technique. Poking a value to a memory address..." "4403": "What will happen if you have an item that is infront in one view but in the back in another? Since it seems you have hard coded the order in which they are drawn, will you reorder them based on the view or on some other technique?" "4490": "Why don't you use the emacs calc?" "4525": "Comment on zoomin being at sysinternals.com" "4594": "When you panned off the min edges can you explain how the head was redrawing over the body?" "4922": "Do you ever write test or does the average game not have unit tests?" "5014": "Does this form of live coding work with adding member variables to structs?" "5064": "How does this test code help with the future architecture since it all gets dumped?" "5165": "I'm not sure if this is true. I'm assuming you're making the guy clip when leaving the screen, but why make it clip if you can just make it follow the yellow box which might clip the guy itself. Again I really.." "5195": "If streaming assets will be required to display all visual information will their be some type of manual limit placed on the procedural generation to ensure that all assets will never be required for a single room?" "5220": "End Q&A and closing statements" --- name: "day040" title: "Cursor Hiding and Fullscreen Support" markers: "3": "Intro and welcome" "130": "What we're going to do today" "210": "Cleaning up tSine" "233": "The reasoning behind internal, local_persist, and global_variable" "576": "Searching for static" "594": "static_check.bat" "880": "Cleaning up the TODO(casey): list" "980": "Tackeling SetCursor" "1065": "Spy++" "1305": "LoadCursor()" "1550": "Setting up dynamically controlled cursor visibility" "2052": "Trying to figure out how to stop the 'loading' cursor" "2273": "Fullscreen support" "3069": "Discussion on his method of going fullscreen in Windows" "3285": "Going over the notes" "3330": "'Hacky' way to fill the entire screen with the game" "3530": "Q&A" "3597": "You said you want your artist to leave an alpha apron around your bitmaps. Why is that?" "3735": "Sour trolli worms or Haribo gummy bears?" "3756": "We've got a fair bit of if statements that clamp values. Would a macro make sense?" "3806": "Why do you size of the variable and not the type for MonitorInfo()?" "3878": "Do you prefer separate files for sprite frame elements or a single sheet of them?" "3986": "My asserts in RecanonicalizeCoord() fire up often. Is it a problem?" "4038": "Is supporting different screen sizes part of the plan? (aspect ratios)" "4106": "Could you explain how transient memory storage works?" "4144": "How would you implement a vector? Would you use macros, metaprogramming or something else" --- name: "day041" title: "Overview of the Types of Math Used in Games" markers: "0": "Intro" "118": "Discussing the reason for a math discussion." "238": "Overview of math in programming" "500": "Arithmetic & Algebra" "607": "Euclidean Geometry" "755": "Trigonometry" "842": "Calculus" "1092": "Complex Numbers" "1198": "Higher-level mathematics in game programming." "1249": "Linear Algebra" "1762": "Partial Differential Equations" "2039": "Ordinary Differential Equations" "2463": "Non-euclidean Geometry" "2884": "Topology" "3080": "Minkowski Algebra" "3234": "Control Theory" "3302": "Interval Arithmetic" "3420": "Graph Theory" "3512": "Operations Research" "3588": "Probability & Statistics" "3610": "Discrete mathematics" "3753": "Q&A" "3791": "Do you even breathe bro?" "3800": "Doesn't toroidal topology also apply to spheres?" "4078": "Laptop battery dies" "4207": "Q&A Resumes" "4236": "Is it important to clarify many of these subjects can be learned when you need them, not needed as a baseline?" "4301": "Most of 3D games is in euclidian geometry" "4345": "What happens in partial differential equations if Scott Meyers is in a gorilla suit.." "4403": "Don't the tiles near the inner part of the torus get smaller compared to outside?" "4559": "How is dealing with complex numbers in four dimensions more useful for doing rotations?" "5079": "Ever do anything with laplace transforms?" "5136": "What type of math is used in AI?" "5165": "Is all of the things shown in math classes useful?" "5221": "Quaternions as you use them in rotations are not euclidian!" "5257": "Can we talk a bit about what out of the master list do we expect to use in this game?" "5325": "Will the next two weeks cover the basic functionalities of the parts that are math heavy?" "5362": "Did you learn most of your math from books or did you take courses?" "5377": "I heard Markov chains are also useful crossing control theory with probability. Will we use these?" --- name: "day042" title: "Basic 2D Vectors" markers: "0": "Intro" "22": "Character movement code." "105": "Recap" "170": "Issues with current character movement code." "265": "What we want to do with the movement code." "293": "What makes a game engaging." "390": "Reason for vector math." "420": "What to start fixing." "455": "Vector math intro." "696": "Sketches" "1146": "A scalar problem for the viewer." "1493": "Correcting player's diagonal motion." "1570": "Transitioning to vectors." "1830": "Vector notation" "1993": "Basic Vector Operations" "2266": "Multiplication in Vector Space" "2610": "Adding vector routines to the code" "2905": "Replacing scalar code with vector code." "3713": "Q&A" "3748": "How do union types work in C++ and what are the drawbacks?" "3882": "About vector conventions" "3907": "In the first version of vector, weren't you just missing an anonymous struct in the union?" "4043": "How do you remember all these commands?" "4127": "Is there a performance reason not to use constructors for v2?" "4216": "When would the fact that objects members are private or public come in to play?" "4324": "You should be able to have compound assignments outside the object." "4442": "If you're using vertical bars for vectors, how would you notate the determinant?" "4523": "Can't you make the whole vector struct an union?" "4590": "Does the altered v2 work now if you comment out the constructor?" "4689": "What libs are you using?" "4697": "Just tested the v2 struct in llvm and it compiles fine." "4720": "If I remember correctly, both gcc and llvm complains about the union struct" "4773": "Do you have any book recommandations for vector math?" "4934": "Will you define vector and scalar addition?" "5115": "Any particular reason to not supporting both vector-scalar and scalar-vector operators?" "5179": "The earlier struct-syntax is C99" "5197": "Does not returning real32 instead of v2 in *= operator trim your y-value?" "5305": "In C++11 you can do (v2){5, 2} as v2{5, 3}" "5383": "Don't you need some graphics library to place stuff not in a console?" "5480": "It's time to upgrade your copyright notice!" "5539": "Do you have use for constants like v2up, v2down etc?" "5630": "Copyright should cover all years in which content was contributed" "5688": "How about adding const references to function parameters to avoid copy by value" "5753": "Doesn't const help the compiler optimize?" --- name: "day043" title: "The Equations of Motion" markers: "62": "Intro to equations of motion." "173": "Recap of yesterday's stream." "308": "Motion in-depth: rigid body dynamics." "555": "Linear dynamics." "833": "Fundamental equation of motion." "1075": "Revisiting vectors." "1430": "How we computed motion." "1535": "Some calculus." "1737": "Computing motion differently." "2191": "How it's currently done in the code." "2230": "How we want to change it for our new equations." "2417": "A talk on delta time." "2566": "Piece-wise functions." "2615": "Implementation." "2953": "A look at the game now. We notice player has no friction." "3082": "Implementing some friction." "3506": "Closing remarks." "3640": "Q&A" "3683": "Why use real physics and not something custom you can handtune?" "4019": "Why not add an opposite directional deceleration when collisions occur?" "4049": "Are you concerned that actual physics will retract from the beauty and elegance of the worlds greatest jump code?" "4086": "What would you need to store if you wanted to rewind time ala Braid?" "4373": "Is the character a bitmap?" "4402": "Are we going to normalise the vector from the input, instead of having a special case for diagonals?" "4441": "Will there be a map function to help determine terrain for friction and collisions?" "4477": "Why v2 instead of vec2 or vector2?" "4513": "Why not break the code into smaller functions?" "4596": "Shouldn't you use a max speed variable?" "4652": "Someone: Friction negative acceleration based on current velocity would feel better" "4686": "Can you derive the 1/2at^2 part of the position equation again?" "5034": "Do you think something like bullet or box2d for player movement is appropriate?" "5138": "When would you use other integration methods?" "5660": "Will we use rigid body even after the hero is bouncy and all that?" "5700": "Correction on question from someone" "5749": "If we had terrain (ice or mud), we could have an easy convincing example" --- name: "day044" title: "Reflecting Vectors" markers: "33": "Importance of vector math" "129": "Recap of last episode" "216": "On the homogeneity of scalar and vector math notation" "345": "Goal for today: bouncing off of walls" "426": "Blackboard diagram of expected bouncing behavior" "467": "Axis-aligned vector reflection" "746": "General-case vector reflection" "902": "The inner/scalar/dot product" "1421": "Applications of the inner product: vector length" "1635": "Applications of the inner product: measurement of vectors on new reference frames" "2062": "Solving general reflection using the inner product" "2424": "Implementing the solution" "2602": "Placeholder code to detect orientation of colliding walls" "2959": "Short comment on loss of energy and coefficient of restitution" "3025": "Challenge to the stream: how do you run along the wall?" "3111": "Answer to the challenge" "3208": "Discussion on sticky behavior" "3493": "Q&A" "3571": "Can you explain again why the hero was sticking against the wall?" "3763": "When do we scale down the hero?" "3791": "Have you considered using sin(0) to sin(90) as a non-linear inertia curve?" "3831": "Will you eventually handle player and monsters in some kind of physics engine?" "3872": "Do you need to code in different collision detection for the enemies?" "3909": "Will you add comments to the source for those who preordered?" "3945": "Do you plan on having non axis-aligned walls in the maps?" "4032": "What do you think about position based dynamics?" "4122": "Are we going to do continuous collision detection?" "4148": "Is the computational cost of functions something you only learn by experience?" "4268": "Will you end up in problems when walking into corners after the sticking fix tomorrow?" "4287": "Will there be a minimum distance to the wall?" "4323": "Will computing a vector where the player will stop just before the wall solve the sticking?" "4393": "Additional explanation to the bounce vector calculation" "4765": "Is there a way to speed up the DrawBitmap code?" "4875": "Suggestion to remove reblitting the background to improve performance" "4928": "Stream notes Casey drew the cos/sin triangle wrong" "5019": "A wish to mention formal keywords to help people look things up" "5093": "Was the Witness collision trick to try maintain the distance traveled?" "5121": "Why does wall bouncing not seem to cause sticking, but sliding does?" "5226": "Stream mentions KhanAcademy for learning math" "5240": "Will the rendering code be able to squash bitmaps?" "5281": "Could you/would you benefit from unrolling the collision loop ... ?" --- name: "day045" title: "Geometric vs. Temporal Movement Search" markers: "0": "Intro" "88": "Recap" "150": "Sticking problem recap" "254": "2 ways to handle problem: search in T, search in P" "560": "Problems with search in T" "676": "Solving the problem The Witness way" "930": "Problems with search in position" "1102": "How to implement search in P in Handmade Hero" "1315": "Why you need a flood fill" "1348": "The problem with players with volume" "1690": "Implementing search in P" "1885": "Breaking apart code" "1960": "Casey on messy code (rant)" "2155": "Simplifying the movement code" "2310": "Problem with unsigned integers on the zero boundary" "2417": "Finding the closest tile for each loop" "2525": "Check for empty tiles" "2695": "Defining the valid player region inside the tile" "2840": "How to perform the search" "3360": "Getting the length of a vector" "3460": "Cleaning up to finish on day 46" "3527": "Q&A" "3601": "Why different versions of GetTileValue()?" "3837": "You start variables uppercase and structs lowercase. Why?" "3887": "When npc's are introduced, will they reuse some of the code shown here?" "3954": "Are you going to implement push/squeeze through doorways?" "4051": "It seems like the possible movement is more like a pizza-slice?" "4116": "How would we, using this system, handle when the player would be killed by collision?" "4207": "Will we have to push boulders out of the way of doors?" "4224": "Will you ever fall for some of the dogmatic traps when coding?" "4391": "Does the search method here give the sense of rounded corners?" "4454": "I don't really understand this. Why not just change the players vector with normals?" "4581": "Are you going to worry about how many objects the collision detection system can handle?" "4692": "For search in p, don't you have a problem with passing through walls?" "4775": "Will the search code work if he hits a small notch that would make him bounce back?" "4875": "Will you implement secrets when none of us are watching?" "4940": "Will the characters have skeletal animations?" "5019": "Will the search in p work with moving objects?" "5120": "A great deal of the problems you've faced seems to be around tradeoffs.." --- name: "day046" title: "Basic Multiplayer Support" markers: "0": "Intro and welcome" "85": "Where we were.." "110": "Addressing a bug that was found by the forums" "270": "Thinking about how to handle input" "384": "Which controller maps to which character?" "544": "How we're going to handle this problem" "636": "Mapping a controller to a character" "696": "Pulling player info into the 'entity' structure to support multiple players" "770": "Modifying game_input to allow for multiple players" "871": "Changing his mind about how to handle this" "1139": "CameraFollowingEntityIndex" "1151": "Making the camera follow a certain player" "1327": "Drawing all of the players" "1478": "Fixing HeroFacingDirection" "1701": "AboluteValue intrinsic" "1771": "Adding an entity to the game" "1883": "Initializing a player" "2020": "Crash!" "2184": "MovePlayer()" "2364": "Moving player width/height into InitializePlayer()" "2535": "Calling the movement code" "2604": "Debugging the movement code" "2828": "Some days, you just have to fire yourself." "2946": "Fixing facing direction, again" "3042": "Retuning movement constants" "3129": "What we're going to do tomorrow" "3180": "BRB, controller!" "3239": "Demo of mult-player support" "3270": "Q&A" "3308": "On split-screen what kind of resolution were you thinking for each?" "3375": "You once said visualizing problems is never a wasted effort. Should we use it for collision detection?" "3412": "Are entities just for players or all game objects?" "3443": "How input be handled when both players trigger an action at the same time?" "3466": "Who is the camera following with multiple players? [code change]" "3644": "When you decided to have multiple players you decided to call them entities. Why?" "3716": "How do you make the characters not run through the trees?" "3830": "Why are we doing physical based movement?" "3877": "Will we be doing any image manipulation with code?" "3887": "Any reason to catch failing to load art assets? [code change]" "4014": "Is the notion of having all entities in a single array something that'll stay for long?" "4042": "Why do you not use an auto-compiler?" "4071": "How would disconnected controllers mid-game gracefully handled?" "4133": "When comparing a float to zero shouldn't we be checking withing a tolerance instead?" "4166": "Will there be diagonal movement sprites to the hero?" "4229": "Since small velocities were brought up, will we account for small inputs i.e. deadzones?" "4321": "About storing entities in an array. If there's massive operations on many of them, can this be exploited?" "4383": "Why didn't we use the bitmap masks directly?" "4522": "Are there any games that you've personally developed that are available to the public?" "4659": "Why do you use the function call macros?" "4713": "Will you wait for Jon to finish his presentation tomorrow?" "4734": "Can you explain what you mean by 'deadzone on the controller'?" "4974": "Do controllers have an outside deadzone?" "5038": "Addition to bitmap loading question: 'You && with a 32bit value and use what you get'" "5191": "Can you ever talk about the code you made that shipped 2000+ times?" "5280": "Will we be using a component system?" "5300": "Any estimation where GUIs will appear?" "5335": "Chat says: there are rotation instructions " "5585": "[code change: Using rotation instructions]" "5985": "Rotate will work but it's microcoded, so don't use them if you want performance" "6016": "Doesn't the rotate mess with the XP compatibility?" "6054": "Pondering about microcode speed" --- name: "day047" title: "Vector Lengths" markers: "0": "Intro" "93": "Recap" "170": "Diagonal move recap" "280": "New analog stick problem" "633": "Changing vector length without changing direction" "840": "Doing it aggressively" "948": "An important note about ratios and squares" "1107": "Why use length=1?" "1210": "Back to the wall sticking problem!" "1296": "Explanation of search in T implementation" "1567": "Equation for search in T" "1777": "Simplest possible case" "1940": "Division by zero" "2157": "The equation to solve for infinite vertical and horizontal walls" "2235": "Fixing equation for finite wall sizes" "2310": "Implementing the new collision code" "2440": "How to find the tiles to check" "2750": "What to do about multiple wall collisions" "3253": "Q&A" "3325": "Why did you change from search in p to search in t?" "3572": "How does it handle the state of two separate players on different floors?" "3618": "Why is the code complexity for p-search so much bigger than t-search?" "3799": "Why not treat the map as a matrix and validate objects and collisions through coordinates?" "3863": "Can you elaborate more on how the coordinate system works with the collision detection?" "4011": "Can this be extended to 3D collision?" "4024": "Could you check the player position and check if it's in the inner side of the wall vectors?" "4242": "What's your point on zero-length vector normalization?" "4374": "How come sometimes players can glitch through walls or corners? Is it art or programming?" "4624": "Do you need to do the math with solid walls and objects or is it basic program arithmetics?" "4722": "Chat adds: I think he means graphically. Walls can be hollow inside." --- name: "day048" title: "Line Segment Intersection Collisions" markers: "0": "Intro" "83": "Recap" "175": "Continuing yesterday's work on collision detection" "416": "Writing the wall intersection detection" "638": "Fixing backward movement" "722": "Fixing divide by zero" "860": "Actually move the player" "1088": "Description of partial wall penetration" "1140": "Adding the remaining wall tests" "1388": "New problem: walking through the top wall due to floating point precision loss" "1527": "Implementing a temporary fix" "1755": "Looking for another bug causing the character to stop early" "1806": "Debugging an assertion failure" "1970": "More collision bugs; time to write a better collision detection system!" "2018": "Observing the problems with the current collision detection system" "2125": "What we want from the new system" "2606": "Q&A" "2633": "Can you change the whiteboard colors?" "2793": "Do you plan on getting into calculus to get better collision detection?" "2825": "Do you think any need to prototype some features in some other language?" "2863": "If we changed the resolution of the game, would it change the size of the objects?" "2905": "Can you do collision detection based on if a bitmap and a pixel has alpha?" "3075": "Is it interesting to have a tutorial on floating-point computations?" "3125": "Why not use the old collision system and use the new one only if it finds a collision?" "3183": "What about the tiles? Will they stay the same if you change resolution?" "3293": "What is dynamic loading? I thought C code has to be compiled." --- name: "day049" title: "Debugging Canonical Coordinates" markers: "0": "Intro" "80": "Recap" "125": "Wraparound problem" "445": "Thinking about the problem" "909": "Changing the collision detection loop" "1545": "Why is X changing?" "1725": "Debugging all the things" "1880": "Fixed! The problem with RecanonicalizePosition" "2010": "Testing the new wraparound solution" "2250": "Fixing camera position" "2330": "Describing the camera position problem" "2560": "Changing topography from toroidal to disc" "2750": "Making the collision detection better using areas instead of points" "2880": "Fixing canonicalization" "3194": "Talking about the future of the tile map" "3410": "Q&A" "3489": "Do you use diagrams a lot in your actual work?" "3506": "What do you recommend for learning c++?" "3525": "Try setting handmade hero start at the midpoint between tiles" "3614": "What are your initial thoughts on DX12?" "3656": "Why is your code over 900 lines?" "3673": "How about using signed values for the top coordinates?" "3700": "Stream went offline" "3718": "Why don't you like private?" "3754": "Is there any background information you can give us new viewers?" "3779": "Do you see any complications broadcasting sound from float space in the next room?" "3923": "What is your preferred scripting language?" "3937": "I'm curious if you have to do with memory misalignment?" "3968": "Any reason you're making it somewhat more complicated than it should?" "4030": "How are you supposed to draw the game in Windows 10 without a HoloLens?" "4085": "Is the system rendering offscreen objects in the background?" "4111": "The struct name abc initialisation looks odd" "4155": "What's the estimated date for the release of Handmade Hero?" "4176": "Have you ever pair programmed?" "4187": "Do you go hard in the pain?" "4215": "Could you remove the old RenderWeirdGradient()?" "4230": "Why is there an issue with wrapping?" "4299": "Where did you get your education at?" "4308": "Does C handle pointers any different than C++?" "4335": "Do you use version control?" "4359": "Why not change the tilewidths and heights to 8x16 to wrap the camera with power of two?" "4435": "Can you explain how you use Minkowski addition in the collision?" "4519": "Are you eventually going to add tile entities?" "4575": "How much focus are you going to give to tile entities?" "4635": "How tall are you?" "4653": "What if you translate a 9x9 tilegrid to the player as origin before doing any world map?" "4688": "What do you use to draw?" "4729": "For wrapping you could just check if the new value is between uint_max and the nearest multiple of 9x17" "4751": "Can you explain what float-space is exactly" "5118": "Will you create a map editor?" "5134": "Seems like you could use bitfields or union to combine the different coordinates?" "5155": "What's the best way to learn how to code?" "5201": "I thought floats and doubles are the same speed in the FPU?" --- name: "day050" title: "Basic Minkowski-based Collision Detection" markers: "0": "Intro" "33": "Recap" "159": "To do today: Gliding/skating and area-based collision detection" "227": "Review of collision detection up to this point" "306": "Area-based collision detection (Minkowski sum/difference)" "415": "Example: A player with size passing through two blocks" "530": "Introduction of Minkowski algebra: algebra with shapes" "741": "Chumped by Krita" "924": "Back to the Minkowski sum: rectangle + circle" "1005": "Similar shapes" "1065": "Dissimilar & complex convex shapes: GJK algorithm" "1258": "Rectangles-only collision detection" "1555": "Taking entity size into account" "2025": "Sticky walls appear" "2165": "Changing the origin point of the player" "2280": "More sticking walls debugging" "2625": "Implementing gliding" "2880": "Correcting velocity during collision" "3370": "Debugging final sticking bug" "3640": "Moving the epsilon to stop directly on the wall" "3800": "Or not…" "3860": "Debugging first loop through the wall collision loop" "4198": "Debugging the second loop through the wall collision loop" "4685": "Moment of enlightenment" "4762": "Q&A" "4865": "Why is the heros head 1.5 meters in diameter?" "4889": "How would you handle concave objects with Minkowski?" "4961": "Why isn't the game split up in smaller, more modular files?" "5091": "Is the alpha channel in the art assets created by the artist?" "5121": "How many years since you started doing games?" "5197": "I usually just hope the framerate stays high enough for the velocity not to get too high" "5337": "Can't you have multiple views of the same file with emacs?" "5366": "Will you be able to use minkowski with rotating and diagonal objects?" "5610": "How long have you been working on this game?" "5637": "Is it possible to make an assert that lets you continue on failure?" "5657": "Are you doing any cyclomatic complexity analysis?" "5683": "How would you represent a large sidescroller 2D world?" "5743": "Is it possible to determine the point of collision?" "5771": "Seems like the inability to represent convex objects is a major for problem for physics" "5835": "I meant determining the point of collision with the general GJK algorithm" "5907": "Are we doing a Raspberry Pi port just for the heck of it?" "5964": "Cyclomatic complexity: a direct measure of the number of linearly independent paths through the code" "5990": "BeagleBone black is better than Raspberry Pi I think" "6061": "Can't you do straight on hardware on the PC?" --- name: "day051" title: "Separating Entities By Update Frequency" markers: "0": "Intro" "120": "Recap" "318": "What we're doing and why" "443": "The state of the world coordinate system today" "546": "The vision of the new entity system" "685": "Ballparking entity limits" "1098": "Scaling to large numbers of entities" "1245": "Low- & high-frequency entities" "1313": "Addressing other entities" "1510": "The initial approach for addressing entities" "1790": "Handling re-offsetting in local coordinate space when the camera moves" "2056": "Interaction between low- & high-frequency entities" "2145": "Updating code to add entities with different frequencies" "2440": "Implementing the inefficient version" "2585": "A note about split-screen camera" "2702": "Updating GetEntity to support different entity frequencies" "2933": "Updating InitializePlayer" "3125": "Updating AddEntity" "3265": "Getting the code compiling again" "3586": "Q&A" "3615": "How about hot/cold/frozen instead of high/low/dormant?" "3670": "Chat reminds: wrap intrinsic rotations [code change]" "3928": "Is it a good idea to update the low entities in a separate thread?" "3992": "In a dynamically based language how would you handle refactoring without the compiler help?" "4091": "I've noticed some game physics break when you increase the fps" "4223": "You're just shifting, not rotating [code change: shift-or rotate]" "4732": "Is there any gameplay reason why we want entities alive even off screen?" "4814": "About shifting negative values [code change]" --- name: "day052" title: "Entity Movement in Camera Space" markers: "0": "Intro" "100": "Recap" "192": "Thinking about removing the tile map and making tiles entities" "327": "Test entities against every other entity (O(n*n))" "377": "Update MovePlayer to perform collisions on active entities" "554": "Relative position between entities" "664": "Thinking about different actions for different types of collisions" "874": "Implementing walking on “stairs”" "1062": "Fixing compiler errors" "1168": "Implementing ChangeEntityResidence" "1320": "Thinking about entity types using a cache to keep high/dormant entity positions consistent" "1500": "An aside on programming technique (rant)" "1580": "Recalculating the position into tile space on entity update" "1766": "Mapping entities into camera space" "1900": "Exploring the code in debugger" "2120": "Changing residence of entities when higher residence is requested" "2370": "Debugging entity collisions" "2525": "Debugging sticky collisions" "2697": "Restoring camera movement" "3058": "Todos for tomorrow" "3203": "Q&A" "3253": "Why can't infrequent entity updates happen in the entity's update logic?" "3417": "Why do you want to use a 3D vector for position when the Z value is always going to be an integer?" "3685": "Does Minkowski collision detection have to be axis-aligned?" "3786": "Didn't you just implement a bare-bones relational database? Do you think that's a good mental model for understanding today's code?" "3957": "I noticed your characters do not collide with each-other. I thought you changed that?" "4028": "How good is this addressing scheme for the cache?" "4082": "When jumping you just need x, y, z coordinates to make it happen? [code changes]" "4583": "Will we switch to some kind of sparse storage for example for the high res entities?" "4614": "How would you handle jumping on a ledge or surface to adopt a new base height?" "4699": "What do you think about physics for character or mob movement in a platformer game, meaning that I press right but it starts to accelerate instead of just move?" "4756": "Now make him jump through the ceiling into the next floor." "4794": "Why is he so huge?" "4827": "Will the floor area of the zones be flat or will it have slopes and 3D zones a.k.a. hills?" "4929": "Can you change the yellow tile beneath his feet quickly and easily to be greyish and round so it looks like a jumping shadow? Completely not required but why not! [code change]" "5181": "If you add walls in the middle of rooms would they be handled as entities for the purpose of collision detection or separately?" "5224": "Too fast!" "5435": "How much has changing the rectangle to a bitmap instead of a rectangle impacted your player-on-player collision calculation?" "5453": "How many zombie DLCs will there be?" "5522": "Shouldn't you be doing this blending in a linear color space?" "5586": "When does the core mechanics of the game come into play? Earlier or later in the dev cycle?" "5719": "Is there an easy way to translate from circle to ellipse collision detection?" "5750": "Do you recommend learning to make a game engine rather than using engines like Unity or Unreal for people new to game development?" "5870": "The rectangle box which you have alpha assigned, is that the same box you would assign hit points to in case the character is injured by enemies or obstacles?" "5945": "How common or practical is pixel by pixel collision check vs overall shapes collision check? Which one is more interesting to you?" "5990": "What are your thoughts on the Allegro library?" "6000": "Stream end" --- name: "day053" title: "Environment Elements as Entities" markers: "0": "Intro" "82": "Recap" "162": "Fixing a crash reading off the end of a buffer" "705": "Making walls into entities" "865": "Pulling out camera movement code" "1076": "Removing entities from the high entity set that are too far away from the camera" "1160": "A note on pointer access" "1280": "A note on rectangle bundling" "1598": "Calculating the bounds of the high entity area" "1781": "Preparing to add entities to the high entity set that are close to the camera" "1989": "Putting wall entities in the tile map" "2048": "Changing InitializePlayer to AddPlayer" "2143": "Adding AddWall function" "2349": "Adding the walls right away instead of waiting for the collision detector" "3013": "Adding entities to the high entity set that are close to the camera" "3309": "Calling SetCamera at the start of the game" "3495": "Out of time! Where we'll start tomorrow" "3559": "Q&A" "3602": "Aren't some of the signs in the MinTileX wrong?" "3672": "What does “internal” modifier which is applied to the SetCamera function? I mean what is the difference between non-static and static function?" "4030": "Why do we consider a wall an entity?" "4107": "Will tile chunk and tile map structures go away and walls will be stored only as entities?" "4124": "We have to do some cool screen shakes and some whip pan transitions between screens." "4134": "Will there be a dormat enemy?" "4161": "Can we have some old man that transforms you into a dog and says “you're the dog now man”?" "4245": "Fixing calculation bug in collision detector [code change]" "4563": "What do you think of message buses and what is your favorite implementation of one?" "4580": "Are you planning on having any game screens that pan the camera?" "4635": "Have you ever played Path of Exile or heard of it? They have this desync problem that they claim is unfixable because they handle stuff server-side. Just wondering if you have heard of that game and its notorious bugs." "4677": "Are you using a stylus in Krita or a mouse?" "4698": "Does forcing a game to a certain refresh rate introduce lag?" "4748": "End" --- name: "day054" title: "Removing the Dormant Entity Concept" markers: "0": "Intro" "77": "Recap" "195": "Rationale for removing dormant entities" "356": "Ideas on decoupling low and high entity arrays" "623": "Creating things only in the low entity list by default" "940": "A note about the memory of the high entity array" "1298": "Thinking about using a free list instead of compacting the array" "1407": "Implementing array compaction" "1606": "Changing GetEntity to GetLowEntity and GetHighEntity" "1745": "Changing AddEntity to AddLowEntity and updating AddWall" "1856": "A note on refactoring/rewriting code" "1902": "Updating AddPlayer and MovePlayer" "2352": "Updating SetCamera changing residence from high to low" "2495": "A moment of clarity; description of trouble iterating over a mutating array" "2765": "Handling controlling entities" "3234": "Debugging crashes" "3350": "Debugging missing walls and positioning problems" "3728": "Q&A" "3792": "Is there an advantage of making the size of the LowEntity and HighEntity arrays a power of two?" "3862": "This is a third-person game right?" "3874": "What process would you have gone through for creating the controls and movement if this were a 2D side-scrolling platformer?" "3928": "Do you feel today will be rewritten during optimization?" "4000": "I don't know if it's been answered before but did you consider large fixed point integers for both entity types like Tom Forsythe seems to prefer instead of the swap between the floating point and the high frequency entities?" "4138": "Wouldn't be easier to keep a list of empty entity slots to add them there instead of always moving and changing one of the pointers?" "4191": "Are you familiar with slot maps for game object storage and do you think you'd use them for this project? We use them for our engine." "4282": "Any thoughts on controls for HH on controllerless touch screen devices like tablets?" "4347": "(follow-up) I think a slot map is just an implementation of handles doubly indirect referenced through a table." "4377": "Will Handmade Hero always be 20 scale feet tall?" "4386": "What are you drinking?" "4396": "(follow-up) What I call a slot map is an array that can have arbitrary empty slots and each slot has a version number for self-validation." "4520": "End" --- name: "day055" title: "Hash-based World Storage" markers: "0": "Intro" "125": "Fix typo in SetCamera" "180": "Recap of world coordinate wrapping problem & sparse world storage design" "617": "Introduction to hash tables" "916": "Hash functions" "1124": "Hash collisions" "1249": "Handling hash collisions: External chaining" "1516": "Handling hash collisions: Internal chaining" "1912": "Replace tile chunk counts with a hash table" "2184": "Creating the hash function" "2610": "Looking up entries in the hash table and creating new entries in the table" "2830": "Reviewing the code that has been written" "3480": "Moving the world origin" "3645": "Debugging missing entities" "4190": "Q&A" "4234": "Why not center the world at 0,0,0 and use signed ints for the tile position? [code change]" "4542": "Is a hash map essentially just a creatively shaped tile chunk? If that's the case could you preempt the hash function by contributing more bits from the Z coordinate as opposed to the X and Y for a towery map for example? Am I thinking about this right?" "4751": "What do you think about, and do you ever do, “free” optimizations in early or late stage development such as […] and instead trying to fail as early as possible? Best case scenario you only did one comparision rather than four." "4952": "What sort of cookie is best for programming?" "4960": "What do you think about splitting the hash map code from the tile code such that you can use hash map for other stuff later on?" "5112": "You're not passing the arena to the hash lookup function." "5146": "Is the world going to be generated on the fly or at game startup?" "5205": "Instead of chunks have you thought about spatial hashing? I'm considering it for my game to allow an open generated world but not confined to grid aligned tiles or fixed size objects." "5241": "What about using an octree for sparse style storage rather than a hash map?" "5433": "Since you are using a memory arena for all allocations how will you handle dynamic amount of objects like enemies, particles, etc.?" "5454": "Shouldn't the safe margin be INT32_MAX minus margin?" "5499": "When will this little guy have feet?" "5510": "Isn't the explanation where one letter points to the next letter until the end of the word?" "5593": "I think you said that a hash table was just one of many ways to store the sparse data. Could you briefly mention one or a couple of the other methods?" "5844": "Does starting at 0 cause a problem with the tile chunks since now we are using that as the uninitialized variable? [code change]" "5934": "Shouldn't Chunk->TileChunkX=0 be Chunk->NextInHash->TileChunkX? [code change]" "5974": "Will you write an analog function to malloc?" "6005": "(follow-up) I see. I guess what I was thinking about was what the full 4Bn x 4Bn map would look like if you passed each index in the hash map the opposite way through the hash function. It seems like it doesn't matter in any case becafuse no matter what it's always going to be better than O(n) and most of the time it's O(1) with a tiny bit of performance cost to throw the coordinates through the function." "6031": "Most of your comments are notes and todos. Do you ever add section title comments to separate long blocks of code?" "6053": "Do you see any value in adding unit tests for certain bits of this functionality?" "6103": "Can you visualize the shape of the map so I can understand why a hash table is better than an array?" "6280": "The randomized map only goes up and to the right at the moment. Is it good enough to catch bugs?" "6307": "Will the renderer be a separate piece of code as like the platform player so that it can be substituted with something like OpenGL?" "6318": "End" --- name: "day056" title: "Switch from Tiles to Entities" markers: "0": "Intro" "104": "Recap" "318": "Scaling low-frequency entity updates" "1005": "Revising the tile map" "1110": "Thinking about changing tile map to store entities instead of tiles" "1368": "Options for how to reference entities in memory" "1766": "Storing entities in tile entity blocks" "2012": "Thinking of a technique to improve low entity access" "2074": "Going in the other direction" "2169": "Removing invalid code" "2284": "Thinking about the size of the tile_map TileChunkHash" "2505": "Renaming tile_map to world" "3355": "Debugging refactoring" "3420": "Recap" "3517": "Q&A" "3539": "Do you still expect the gameplay to be broadly grid-based even without tiles?" "3584": "Could you use reflection to help handle the entities and world chunks?" "3653": "Will everything in the game be an entity even if it does not need collision detection or movement?" "3722": "Don't you think most of the storage concerns stem from having just high and low entities and would be solved by having more granularity there so you have more and smaller arrays of entities with some particular aspect?" "3767": "You mentioned considering having the world chunks store a fixed entity count and then add multiple chunks to the hash table if necessary to store more entities. If you were to go that route, how would you compare one chunk to another? Multiple chunks would have the same X,Y,Z." "3856": "In terms of handling entity compression and decompression, where would you grab/store the state of objects that are coming in and out of the update scope?" "3887": "Why do you call C compiled with a C++ compiler “C++”?" "3923": "Why can't world_position just have a pointer to a world_chunk instead of all those AbsTiles? Then Offset_ is relative to the world_chunk." "4044": "I didn't get to watch the entire stream so I don't know if you considered it, but why don't you have a flag for “about to be deleted” that every entity checks against and nulls pointers. Have it visible for all entities for one frame." "4107": "Do you think the todo puzzler will be handled tomorrow, and do you often sleep on decisions like that?" "4171": "(follow-up) What I was getting to is that we seem to be working towards what's called the Entity Component system where what we call now “high” and “low” are just components alongside anything else we want to add to entities later." "4238": "Seeing that the computer handles 1 million entities without lagging, do we really need to worry about the performance hit coming from one extra pointer dereference?" "4350": "Will entities be able to transfer from one chunk to another?" "4372": "Will we start using the entity system for something other than players/walls soon or will the renderer come first?" "4438": "End" --- name: "day057" title: "Spatially Partitioning Entities" markers: "75": "Recap" "191": "handmade.cpp: Create more rooms" "262": "Debugger: Inspect GameState while traversing the world" "440": "Consider creating a spatial partition" "655": "Blackboard: Spatial partitions" "839": "handmade_world.cpp: Introduce ChangeEntityLocation" "1093": "handmade_world.h: Rename AbsTile to Chunk and add ChunkSideInMeters to world" "1199": "handmade_world.cpp: Continue writing ChangeEntityLocation" "1356": "Discuss making FirstBlock a pointer rather than doing the block copy" "1502": "handmade_world.cpp: Continue writing ChangeEntityLocation" "1916": "Blackboard: Keeping the free space at the head of the list" "1990": "handmade_world.cpp: Continue writing ChangeEntityLocation" "2248": "Blackboard: Moving the final entry into the newly freed space" "2331": "handmade_world.cpp: Continue writing ChangeEntityLocation" "2535": "On spending time thinking about data structures vs memory management" "2598": "handmade_world.h and handmade_world.cpp: Manage the memory" "2811": "handmade_world.cpp: Update InitializeWorld and remove GetChunkPositionFor" "2889": "Update the sense of AreOnSameTile" "2946": "Introduce IsCanonical" "3126": "Continue cleaning up" "3358": "handmade.cpp: Change to using ChunkZ" "3413": "Introduce ChunkPositionFromTilePosition" "3514": "Write ChunkPositionFromTilePosition" "3732": "Unplug and plug the keyboard back in" "3783": "handmade_world.cpp: Finish cleaning up" "3854": "Q&A" "3939": "Q: Can you please go over the lasagne code again that goes through the linked list and moves around the entities? And can you remove the note in RecanonicalizeCoord about toroidal topology?" "4522": "Q: Are you dropping frames? Things are glitchy" "4551": "Q: Do you use Bink for videos?" "4577": "Q: For someone who does a lot of coding, nothing seems to be going your way today, including the stream integrity" "4593": "Q: What is your opinion on things like bunny-hopping or other movement mechanics that are bugs in the code, but contribute to gameplay, e.g. if there was a technique for getting speed in your game, albeit difficult? Would you keep it?" "4633": "Q: What do you think about namespacing functions like Entity_GetLocation instead of GetEntityLocation?" "4670": "Q: About PushStruct, isn't it true that it can actually fail if you are out of preallocated memory? So wouldn't you still have to check if your custom block allocation fails if your world gets too big?" "4744": "Q: Why do you need if(Chunk) after Assert(Chunk)?" "4766": "Q: Can you please explain, when you comment your code, what's the logic of having less comments on very big chunks of code?" "4897": "Q: When you said the code today wasn't that performance critical, I instantly thought about a machine gun - stone thrower battle just across a chunk edge" "4921": "We are done with questions" --- name: "day058" title: "Using the Spatial Partition" markers: "28": "Assets: handmade_hero_test_assets_002.zip is released" "121": "Recap" "208": "handmade.cpp: Pull in entities by chunk, rather than tile" "312": "Blackboard: Pulling entities into the working set" "526": "handmade.cpp: Figure out the CameraBounds situation" "925": "Make a version of MakeEntityHighFrequency to be called at the lower level" "981": "Introduce GetCameraSpaceP" "1061": "Continue writing these versions of MakeEntityHighFrequency" "1218": "Use these functions in SetCamera" "1301": "handmade_math.h: Introduce GetMinCorner, GetMaxCorner and GetCenter" "1372": "Debugger: Step through and see what's happening" "1454": "handmade.cpp: Fix the Assertion in MakeEntityHighFrequency" "1474": "Look at AddWall" "1551": "handmade_world.cpp: Look at Subtract and ChunkPositionFromTilePosition" "1604": "Debugger: Step in to AddWall" "1736": "handmade.cpp: Call ChangeEntityLocation in AddLowEntity and make it pass world_position P" "1829": "Pass the world_position P to AddPlayer and finish implementing the spatial partition" "2093": "Run it and see what's happening" "2159": "Debugger: Step into AddPlayer" "2207": "handmade.cpp: Tweak AddLowEntity" "2282": "Debugger: Continue debugging AddPlayer" "2317": "handmade_world.cpp: Tweak ChangeEntityLocation" "2380": "Debugger: Step through the loop in OffsetAndCheckFrequencyByArea" "2485": "handmade.cpp: Add an assertion in OffsetAndCheckFrequencyByArea" "2557": "Debugger: Step through and hit this assertion" "2614": "handmade.cpp: Introduce ValidateEntityPairs" "2756": "Debugger: The MakeEntityHighFrequency routine in SetCamera is the problem" "2824": "handmade.cpp: Pass the correct Index to this routine" "2885": "Run the game and note that the spatial partition is nominally working" "2928": "handmade.h and handmade.cpp: Test the new assets" "3040": "Run the game and find that the new trees are drawn at the wrong locations" "3064": "handmade.cpp: Stop drawing the textured background" "3171": "Assets: Find the base point for the tree in GIMP" "3217": "handmade.cpp: Set the tree's alignment and do DrawRectangle as well" "3272": "Run the game and observe our new trees in their correct positions" "3464": "Q&A" "3532": "Q: For zooming out, could you somehow modify MetersToPixels to make things smaller as you zoom?" "3579": "Q: What is inline v2?" "3664": "Q: Why use Emacs versus Visual Studio's IDE?" "3756": "Q: Is Emacs better than Vim, or is it just preference?" "3823": "Q: Do you think that how fast code runs is the best metric for good code, or do you value simplicity or extensibility as well?" "3959": "Q: Why are you using Visual Studio here if you use Emacs?" "3994": "Did you ever figure out a fix for Emacs whenever you try to create a new file and the patch changes?" "4023": "Q: What's guiding you to make steps towards completing the game, i.e. a list of requirements for the game?" "4134": "Q: Do you ever get annoyed with reading a high depth of nested for loops?" "4195": "Q: Was watching some ROM hacking earlier and watching the registers and memory update in real time was really cool. Do you think a debugger for C could work as well as that?" "4239": "Q: How much time do you spend outside the stream in thinking about the code and game design? If you coded eight hours a day, would you be able to code consistently with the same pace as during your stream?" "4298": "Q: Can you please put in a proper PRNG before you write world gen algorithms?" "4366": "Q: Do you ever feel the need to use recursive functions?" "4395": "Q: Do you build with build.exe in command prompt or batch file?" "4451": "Q: When you say "renderer", what exactly does that mean? If the drawing you have now isn't rendering, then at what point do we go from drawing to rendering?" "4555": "Q: Have any of your friends voiced disagreement with design decisions you've made in this engine?" "4582": "Q: How do you distinguish between what a lot of people might called "premature optimisation" versus ensuring a good design that allows for high performance? The difference there seems really subtle. I feel that designing for high performance is simply organising the code and writing in such a way that does not unnecessarily slow down the code and prevent future optimisations, while premature optimisation is simply optimising something because you think something will be slow without evidence" "4792": "Q: 4096 random numbers" "4803": "Q: Will we have positionless entities? Would something like the current price of Almond Milk futures be an entity?" "4822": "Q: Will you be making a level / tile map editor for this game, for easier level creation?" "4840": "Q: What is your algorithm for a collision with three and more entities?" "4881": "Blackboard: Moving in 1/30th sec" "4995": "Q: Do you plan to use some form of logging for debugging purposes?" "5028": "Q: When you remove a LowEntity from the Chunk list, you swap another into its place. Won't that mess with references?" "5055": "Even for slow frequency entities?" "5099": "We have come to the end of the questions" --- name: "day059" title: "Adding a Basic Familiar Entity" markers: "149": "Recap and plan for the day ahead" "334": "handmade.h: Add EntityType_Familiar and EntityType_Monster" "381": "handmade.cpp: Introduce AddMonster and update AddLowEntity" "649": "Add a monster" "724": "Run the game and see the monster" "817": "Reiterate the fact that it is the SetCamera call that brings everything into the HighEntity set" "869": "handmade.cpp: Write cases for drawing each EntityType" "1007": "Run the game and see our Monstar for the first time" "1030": "handmade.cpp: Add a familiar" "1096": "Run the game and see our Familiar for the first time" "1180": "handmade.cpp: Consider how to update the HighEntities" "1264": "Introduce UpdateEntity" "1350": "Consider the "jump code" and do some clean up" "1552": "handmade.h: Introduce entity_visible_piece and entity_visible_piece_group" "1672": "Change DrawBitmap calls to PushPiece" "2229": "Consider doing the rendering directly, rather than deferring it" "2286": "Finish implementing PushPiece" "2465": "Run the game and note that we're doing the exact same thing we were doing" "2478": "handmade.cpp: Add Update calls for the entities" "2542": "Compute the ShadowAlpha incorrectly for now" "2572": "Implement these Update calls and give the Familiar some logic" "2949": "Implement EntityFromHighIndex" "3082": "Change MovePlayer to MoveEntity" "3143": "Give the Familiar some movement logic towards the Hero" "3231": "Run the game and tweak the Familiar's logic" "3288": "Moment of realisation: The player's speed is baked into MoveEntity" "3304": "Make the Familiar move at half the speed of the Hero and check it out in-game" "3401": "Q&A" "3489": "Q: Why "Monstar" and not "Monster"?" "3538": "Q: If someone rewrites your code using OOP and it runs faster, what would you do?" "3564": "Q: Why do you want to be able to outrun your familiar? Doesn't having to stop for him to catch up get annoying?" "3644": "Q: Could you make the head bob up and down while following the player?" "3829": "Q: Could you write Pong real fast, so I can see how to start?" "3843": "Q: "Monstar" would be confused with "Mon*", a pointer to a Mon" "3859": "Q: Are we going to eventually use a component-based entity system, instead of using an enum of entity types? If not, why?" "3950": "Q: Would you think about doing some proportional integral derivative control for familiars to follow?" "4010": "Q: I have a bad feeling about that switch on EntityType. Do you think it will probably go away as we get closer to the final architecture?" "4055": "Q: Would collision be an XY-only thing, or would you take into account Z, as in jumping over another entity?" "4129": "Q: I have a feeling your Low entities will be quite big if they have AI and stuff. Won't this be a problem for the huge world? Maybe it would have made sense if you had kept the tile data in chunks so you can deflate some entities just when needed" "4187": "Q: The performance boost off the low / high shuffle: when will we see this come into play?" "4233": "Q: Could we spawn a ton of these floating head things?" "5446": "Q: How will the Z work exactly?" "5495": "Q: Will there be a flock system for all the floating heads following the Hero?" "5503": "Q: What kind of path finding will be implemented for High entities and how will they differ from faraway Low entities? And will Low entity NPCs who are always on the move really far away always resolve? It would be interesting to come across a very live world full of history, dead bodies, etc. due to constant AI acting, but would that be feasible?" "5539": "Q: How easy would it be to chain multiple bobbly heads to follow each other?" "5725": "Q: CameraTileY + OffsetY not OffsetX in AddFamiliar call" "5764": "Q: I was very glad to hear that you deem classes to be basically garbage. I spent too much time with C# trying to learn object inter-jugglery between them" "5779": "Q: About the chaining familiars, could each familiar check if the hero has a familiar already and, if it does, then try to follow the familiar instead?" "5804": "We've come to the end of the questions" --- name: "day060" title: "Adding Hitpoints" markers: "115": "Recap and plan for the day ahead" "226": "Describe the "sumo mandarin" still being eaten" "286": "Fix jump shadow" "433": "Modify shadow alpha on floating head" "643": "Reiterate the fact that PushPiece is in pixel space" "706": "Make the familiar stop a little way from the hero" "821": "Add Hitpoint to hero" "925": "handmade.h: struct hit_point" "962": "Should hitpoints themselves be entities?" "1038": "Draw those hitpoints" "1418": "Blackboard: How to center hitpoints around the guy?" "1770": "Implement the code to draw these hitpoints in the right place" "1845": "Change the Offset in PushPiece into meter" "2331": "Run the game and watch the Familiar bob heavily" "2343": "Reduce the BobSin multiplier" "2376": "Place the hitpoints in their correct positions" "2484": "Blackboard: Explain why hitpoints stick together" "2528": "Flip the y coordinate in PushPiece" "2600": "Unify PushPiece and PushRect" "2763": "Fix jump hitpoints" "2779": "Basic v3 and v4" "3116": "Explain why templates are bad" "3314": "Q&A" "3377": "Q: Isn't making a struct for HP is preprogramming a little?" "3468": "Q: Why not just use HitPointMax = 12 instead of dividing into 3 hearts and 4 segments?" "3504": "Q: I noticed the floating head was always behind the player. Are you going to go for a depth buffer approach or draw back-to-front to handle this?" "4056": "Q: Would it be entirely possible to completely reconstruct the current code by following every episode of the series without preordering the game?" "4088": "Q: Do you think that I, as a totally new person of programming, would be able to follow along with the pace you are working at, doing rapid changes to the code without sometimes telling us why?" "4151": "Q: Is there ever gonna be a moment of reflection at some point in the future where you provide a somewhat high level overview of the engine components we have been encountered so far, what they will provide and why we need them?" "4234": "Q: I think it would be really cool if you implement a smooth scrolling room-based combination" "4279": "Q: Is the translucent thing you were talking about hard to do on 2D UI? Do you write the UI in the same Z-buffer or is it separate?" "4371": "Q: Will you be implementing more memory handling code and, if yes, what kind of things?" "4498": "Q: If you do a bounding box, which is an inset X amount of meters / tiles from the room edge, you could use the collision of the player with the bounding box to start smooth scrolling to the next room, etc." "4536": "Q: How will we be handling resolution variance?" "4601": "Q: What kind of error handling / logging do you have in place now, and how will that possibly change?" "4655": "Q: Why are strings such a problem for so many engines?" "4665": "Q: How hard is it to port a 32-bit game engine to compile a 64-bit output client if the origin game splits executables to surpass the 4-gig cap?" "4710": "Q: Zelda had scrolling when you transition between rooms. Are you going to have something similar?" "4727": "Q: Would you mind giving a brief walkthrough of the memory management going on right now in the code from the game boot and forward?" "4941": "Q: Why is it impossible to resize a raster image and why does everything have to be rasterized for drawing? Why can't textures be vector-based?" "5091": "Q: Couldn't we build handmade.cpp and win32_handmade.cpp in separate threads? Is there a way to pipe the error messages in a sane way using the build.bat approach?" "5157": "Q: SWTOR does it (about 32-bit splits into 2 separate processes question)" "5214": "Q: Binding of Isaac does have scrolling between rooms, albeit a very quick transition" "5257": "Q: What is the drawing app we are using?" "5293": "Internet: Check out the scrolling in The Binding of Isaac" "5394": "We've finish up on the stream" "5399": "Save our giant drawing in Mischief" --- name: "day061" title: "Adding a Simple Attack" markers: "116": "Recap and plan for the day ahead" "367": "handmade.cpp: Pull out the code draws hitpoints" "484": "handmade.cpp: InitHitPoints" "704": "Use sprite "rock03" as the hero's attack region" "815": "Blackboard: Casey demonstrate how to zoom in and out in Mischief and decide to save the handwritten into the handmade hero directory" "875": "Blackboard: Talk about the difficulties we will encounter if we treat sword as an entity" "1316": "Blackboard: "Imagine"" "1846": "Implement the sword" "2311": "Bind "Start button" for jumping and arrow keys for attacks in different directions" "2422": "Make sure that we take our sword and launch it" "2635": "Treat sword as a low entity the whole time. Let the camera system force it into high" "2670": "Consider mapping entities into the high set if ChangeEntityLocation moves it into camera bounds" "2721": "Back to implementing the code to launch the sword" "2817": "Introduce some notion to represent whether world_postion is valid or not" "3096": "Run the game and find out that sword doesn't show up" "3164": "Start debugging" "3575": "Visual Studio is awful at being able to show you variables when they exit the scope" "3758": "Find out that the CameraSpaceP of Sword is completely garbage" "3823": "Make ChangeEntityLocation update the new world_postion properly" "4013": "Run the game to verify whether the bug is fixed or not" "4082": "Q&A" "4125": "What do you mean that Visual Studio is horrible at showing variables, and how are you programming in Emacs and running it in Visual Studio?" "4312": "When doing exploratory / experimental programming, I find it difficult to decide between seeing things through or switching to a different approach. There have been many times where I start off on a path and things are going great, but eventually I stall due to some unforeseen problem. Often, I spend a crazy amount of time thinking about how to solve / get around the problem, even in simple ways. Analysis paralysis if you will. Any suggestions? Literally, just keep on writing code, no matter how dumb it is?" "4808": "Will you handle the case where a sword and a monstar would hit each other but are moving toward each other so fast that they pass through each other without colliding in a single frame?" "4845": "Do you think "cheesing" - like making enemies invincible for 10 frames after being hit - is a game design sin, or just something you'd rather avoid?" "5053": "Why not just use the auto window?" "5118": "Is VC++ still better than open-source alternatives?" "5201": "What would you think about adapting the art style to be easier to implement, either at all or this early on. The trite example being for the sword collision you mentioned early on, what if you were to do something like: okay, the sword is going to teleport along the path instantly in one frame and some red line a bit like anime that would be persistent through a couple frames. Basically potentially fundamentally changing the art style with the purpose of getting things to run better. Are there any examples of something like this occurring that you might have heard of?" "5302": "Are you working on the RAD debugger, or will you try using it for HMH before the debugger is released?" "5334": "You always talk about the ways of programming when you started or when programming was at its prime. How can I, an 18 year old, know what it's like or get the knowledge you have about programming? Are there any books or languages or SOMETHING I can do to learn the old ways of programming? [see Resources]" "5520": "Why did you pick C++ of all things?" "5711": "Would there have been an easier language to program the game in?" "5856": "To be able to surpass C++ as the defacto language to code games in, what would you have to do as a language that would make you better than C++?" "5897": "CAN I HAVE A WITNESS BETA KEY!!!" "5908": "Wrap it up for the day" --- name: "day062" title: "Basic Moving Projectiles" markers: "32": "Announce that we will save blackboard.art into handmade/misc/" "161": "Recap" "250": "handmade.cpp: Make the sword actually be thrown" "362": "Talk about the annoying and ugly entity usage" "485": "Back to implementing sword throwing" "567": "handmade.cpp: UpdateSword" "660": "For now only, turn off collision detection if the entity doesn't collide" "710": "Run the game and find out the sword is slowing down" "733": "Pull out move notions into move_spec and introduce DefaultMoveSpec" "1160": "Run the game and see the slow sword" "1175": "Speed up the sword and make sure the sword can only travel certain distances" "1529": "Run the game and hit the assertion" "1674": "An assumption of why we hit this assertion" "1829": "Use a hacky way to solve this problem" "1906": "Try to handle this problem more sanely" "2156": "Run the game and find a strange bug with the sword's velocity being set to zero" "2180": "Start debugging" "3299": "Realize that the bug is caused by the hacky code Casey just wrote" "3371": "Run the game and do some hookshot things" "3411": "Explain how these hookshot things happen" "3624": "Q&A" "3661": "Owl of SHAME!!!" "3700": "Do you ever use gdb?" "3706": "Do you test more than just using asserts?" "3717": "Why did you create a struct for each vector type, instead of using plain float arrays?" "3864": "Do you think version control would help when you go off on a tangent for the stream? You can roll back hacks like that?" "3885": "Not a question but that hookshot thing actually looked like it would be kinda fun to play with" "3911": "Reminder: Bendable shot which allows you to change direction of the shot once" "3929": "What are your feelings on the vector multiply operator performing a dot product?" "3997": "Do you keep your assertions for release code? If not, at what point do you remove them?" "4020": "Why wouldn't you encapsulate each entity type into its separate classes?" "4101": "Correct, they use hadamard" "4126": "Did you add the quick-calc hotkey?" "4233": "Is XML fair game in this project? It's not a library, but it still might not be handmade enough" "4307": "Don't you feel that Low entities have already too much extraneous stuff in them and it would be time soon to split them, and also things like the sword might not need the low part at all?" "4430": "What will we do at 3PM PST when this game is finished?" "4519": "Are you happy with the current progress?" "4559": "More than memory footprint I was thinking about unwanted side effects, i.e. code that deals with the transfer of properties ends up triggering hard to debug shenanigans with the positioning etc." "4633": "Wrap it up" --- name: "day063" title: "Simulation Regions" markers: "25": "Recap on getting initial usage code down to avoid bad design" "123": "Design constraints for high/low frequency entities" "286": "Float precision problem for large worlds" "501": "Problem of scaling to large entity counts" "606": "Realizing the problem - wrong way to think about low frequency entities" "678": "Realizing the solution - simulation regions" "978": "Handling entities moving outside boundaries of simulation region" "1119": "Starting the code reorganization" "1173": "The sim_region struct" "1270": "How to alter SetCamera" "1316": "Ending simulation by mapping entities in a sim_region into low space" "1458": "Beginning simulation by mapping entities into a sim_region" "1572": "Simplifying entity structs" "1646": "More details on BeginSim" "1751": "Adding an entity to a sim_region" "2063": "Switching from camera space positions to simulation space positions" "2282": "Adjusting the entity structs" "2388": "Memory allocation for sim_regions" "2565": "Storing back to low entities in EndSim" "2745": "Deleting code that is no longer applicable" "2933": "Replacing SetCamera with getting a sim_region in the main loop" "3064": "Moving camera position update from main loop to EndSim" "3108": "Adjusting rendering for simulation regions" "3360": "Wrapping up for today - fixing compiler errors" "3550": "Q&A" "3586": "Recommendation for names - instead of stored entities you could have stasis_entity and stasis_region; for the high frequency, you would keep the sim_region and sim_entity." "3629": "Since we know that an entity's speed is bounded, couldn't we calculate a sim_region with bounds such that no entity can move outside of it during the frame? That way anything that the entity could collide with would be pulled into the sim_region?" "3749": "How many TODOs do you have?" "3876": "How will you handle the disparity in update rate between offscreen and onscreen entities? Does it matter?" "3940": "Will the sim_region away from the player cause large timesteps from the normal?" "3982": "I missed whether this new system is based around discrete rooms or integer mapped coordinates. If it's based on rooms, would it be trivial to think in coords instead?" "4004": "What will happen if your sim_region and player location are at the same place? Will it bug out?" "4091": "Why is the low-high frequency system so important? Isn't creating basic gameplay rules and AI interactions in a small world more in-line with your philosophy of doing the simple thing first?" "4414": "How will we update low frequency regions given the sparse nature of the world?" "4444": "Is there a major advantage to using 'fors' instead of 'whiles'?" "4510": "What will the entities that are not visible on the screen be doing? I can't really think of examples of things that need to be updated if they're far from the player." "4653": "How many low entities does it take to screw in a light bulb?" "4706": "For your sparse storage, why not store the (x,y,z) coords bit-shifted into an aligned integer to use it as a composite key into a dictionary or hash map?" "4801": "Do you approach design in a similar way to your architecture (i.e. exploration-based design, design sort of emerges itself organically, etc.)?" "4824": "Is multi-threading in the scope of topics for the project?" "4880": "If a far away room gets updated and the rooms around it are updated too, don't we have this recursive problem where the around rooms need their neighbor too?" "4949": "How much work would it take to turn the game you are making from a 2D world into a 3D world?" "4987": "To clarify my early design question, I just mean as far as your design decisions for Handmade Hero." --- name: "day064" title: "Mapping Entity Indexes to Pointers" markers: "93": "Recap of where we are with simulation regions" "118": "Reorganizing the entity structs" "305": "Updating code for sim_entity within low_entity" "497": "Setting the entity's StorageIndex" "667": "Moving entity stuff out of handmade.h" "691": "How to reference entities?" "879": "Creating an entity_reference" "960": "Populating an entity_reference in EndSim" "1072": "Loading from an entity_reference in BeginSim" "1320": "Storing an entity mapping in a hash table when adding an entity" "1404": "Functions for the entity mapping hash table" "1444": "Creating the entity mapping hash table" "1623": "Internal chaining for the hash table" "1707": "Implementing GetSimEntityFromIndex" "2265": "Implementing MapStorageIndexToEntity" "2364": "Loading entities recursively" "2654": "Addressing compiler errors" "2714": "Updating camera following code" "2934": "Addressing compiler errors" "3027": "Porting MoveEntity code to work with simulation regions" "3389": "Leaving notes for remainder of simulation region work" "3423": "Q&A" "3533": "Why don't you upload chat logs with videos somehow?" "3668": "There's a bug in your random number table. The numbers are limited to a range." "3735": "Could explain your naming conventions or explanations behind using them? I've never seen a style similar to yours - it seems inverted." "3844": "Do you want the stored entities to move like normal ones or simulate them? Like you mentioned stuff moving around with slower updates off-screen." "3921": "Maybe if you change your Twitch server? [in reference to dropped packets for stream]" "3975": "What is the point of high and low entity? Would it make sense to just have one?" "4033": "Can entities reference each other? Do you need to check for cyclic references?" "4143": "When is a ground-up rewrite warranted? How often do you just burn everything down and start fresh?" "4712": "What are your opinions of Scrum and Agile methods?" --- name: "day065" title: "Finishing the Simulation Region Change" markers: "36": "Recap on where we are with simulation region change" "235": "Creating a separate file for entity behavior code" "380": "Changing DrawHitpoints to operate on sim_entity instead of low_entity" "425": "Separating code for updating player from controller processing code" "1327": "Fixing more compiler errors" "1417": "TODO for renaming sim_entity to entity" "1463": "Fixing more compiler errors" "1503": "Bringing in handmade_entity into the build" "1523": "Fixing UpdateFamiliar" "1683": "Fixing UpdateMonstar and UpdateSword" "1778": "Overview of remaining TODOs for sim region code" "1795": "Using transient storage for a SimArena" "2281": "Fixing remaining compiler errors" "2312": "Addressing TODO for clearing hash table" "2553": "Starting to debug the code" "2837": "Altering GetHashFromStorageIndex code to make inspection easier during debugging" "2898": "Continuing stepping through code" "3129": "Found a bug - forgot to update entity pointer" "3165": "Continuing stepping through code" "3294": "Assertion fired on null pointer in RecanonicalizeCoord" "3320": "Stepping through EndSim to figure out assertion" "3515": "Assertion caused by float precision problem?" "3602": "Adding epsilon to IsCanonical to prevent assertion" "3695": "Debugging camera positioning" "3860": "Adding TODOs since we have to stop for today" "3981": "Q&A" "4033": "Assuming we don't go wandering too much on our own, which week has accumulated enough code base for a basic, simple, fully functional game?" "4144": "Regarding high and low entities, would the following solution work? Using one entity struct, all entities are stored in one array, and frequently update the entity if the entity is within camera bounds, and use low-frequency updating if it's outside the camera bounds?" "4305": "Can you give a high-level overview of how entities work now? I get it in bits and pieces, but this week has lost me." "4799": "I'm not sure I fully caught how short-lived/temporary/transient memory is? Is it only for single frames or longer lived? If for longer-lived memory, how do you make sure you don't wrap around and start overwriting memory still in use? Think some homing attack which takes many many frames to resolve." "4885": "How do you determine how much time each sim region should be updated if they aren't updated each frame?" "4914": "How does the work during this experimental phase fit into the final code? Will we be re-using most of it or will we be starting from scratch?" --- name: "day066" title: "Adding Support for Non-spatial Entities" markers: "126": "Where we left off with simulation regions" "172": "Overview of limitation of simulation region - entities currently must have position" "280": "Adding sim_entity_flags" "515": "Updating code for moving collides member variable into a flag" "849": "Making the sword non-spatial" "1011": "Handling non-spatial entities in MoveEntity" "1139": "Handling non-spatial entities in BeginSim" "1199": "Handling non-spatial entities in EndSim" "1269": "Handling non-spatial entities in AddEntity/LoadEntityReference/GetSimSpaceP" "1521": "Handling non-spatial entity in UpdateSword" "1742": "Improving ChangeEntityLocation" "2105": "Debugging GetWorldChunk assertion - problems with storing invalid positions and non-spatial flag" "2371": "Fixing camera following logic" "2454": "Fixing dZ of player" "2583": "Fixing initial camera position" "2673": "Restoring sword functionality" "2799": "Why is the sword's shadow so dark? - Multiple swords" "3021": "Guarding against having multiple entities in sim_region with same storage index" "3443": "Preventing sword being reset when holding down key" "3522": "Q&A" "3606": "Does the current collision code support walls that are not 90 degrees? Say if the wall is at 45 degrees, would the collision code still work?" "3808": "Why not set a boolean value 'to be removed'? It seems like setting the position to an arbitrary position isn't as explicit as setting a flag to say that the entity should be removed on the next update frame." "3903": "The rearranging of code did [introduce] some errors into the code. Is this normal for daily coding?" "4097": "Do we expect most entities to be colliding? If so, does it make sense to have the flag be 'non-colliding' instead?" "4143": "Then why set null position?" "4172": "Would using a tagged union for entity references fix issues we're having with LoadEntityReference?" "4201": "Do you have the whole big picture game architecture in your head at every point, or do you have to check what you did from time to time?" --- name: "day067" title: "Making Updates Conditional" markers: "90": "Reviewing the 'apron' idea for update regions" "664": "Adding Updatable bool to sim_entity" "758": "Setting Updatable bool in AddEntity" "921": "Checking Updatable bool in simulation update" "986": "Setting different bounds for sim_region (UpdatableBounds and Bounds)" "1308": "Does the sword still work? - No" "1385": "Bug - Not setting positions properly when loading entities from references" "1613": "Fixing updating of Familiar" "1706": "Removing non-spatial flag check for sword" "1796": "How to update MoveEntity for more advanced collision effects?" "2024": "Review of iterative movement" "2112": "How to have collision responses within iterative movement?" "2146": "Discussion of callbacks for handling collisions" "2523": "Alternative #1 to callbacks - how to break up MoveEntity" "2637": "Alternative #2 to callbacks - set acceleration and delay calling MoveEntity" "2783": "Implementing alternative #2" "3072": "Bug fixing - MoveEntity shouldn't be called for non-moving or non-spatial entities" "3207": "The sword shouldn't be moving forever..." "3334": "Q&A" "3402": "How will collision be done with moving backgrounds? Such as mazes and moving tiles? Or that won't be in this game?" "3576": "Why don't we use .c instead of .cpp?" "3603": "When you started with enums, why did you start with (1 << 1) instead of (1 << 0?)" "3626": "How big are the source files getting? Are you feeling overwhelmed by the size yet?" "3715": "What happens when you somehow glitch through a wall? Will the game crash?" "3767": "How many lines have you written so far?" "3792": "In what situation would you prefer callbacks to a huge switch-case block?" "4060": "Do we load and draw everything manually to a DIB section, then blit the final image?" "4095": "After you mentioned the 'do all collisions at one time' thing, it seems like in addition to being greatly easier to implement, it also matches the real-world better, like summing all the forces to get the net direction. Why would anyone every want to do an update function for each object?" "4182": "I [Jonathan Blow] use cloc to count lines. It is pretty decent." "4326": "Besides the bits that are obviously tacked on, would you consider the Windows GUI a good API?" "4420": "I guess I should have asked how big it has to get for you to start feeling overwhelmed." "4469": "How'd you decide on this order to build up the engine? Was it intuition or experience?" "4749": "Speaking of UML and diagrams, do you ever use class schematics for code planning?" "4782": "Don't you need to be able to enumerate every possibility in order to use a switch statement? What if you wanted to make a system that can be extended?" "4893": "Why use switch statements instead of just big if-else blocks?" "4914": "Will the way in which collisions are handled be order-independent?" "4976": "Is it better to debug as you go or towards the end of a programming cycle?" "5105": "Actually you want to pass --no3, otherwise it [cloc] is lying about the number of lines - it is dumb." "5199": "Will the game have multiplayer and/or co-op?" --- name: "day068" title: "Exact Enforcement of Maximum Movement Distances" markers: "28": "Recap of where we are with collisions and interactions" "67": "Bug fix from forums - Typo in MoveEntity for testing entity flag" "224": "Overview for today - max movement distances" "477": "Review of MoveEntity" "562": "Review of tMin usage in MoveEntity" "816": "Starting implementation with a maximum distance" "968": "Discussion about cost of square roots" "1041": "Using a ratio to cap tMin" "1309": "Updating DistanceRemaining" "1361": "TODO for Epsilon for (PlayerDeltaLength > 0) ?" "1417": "Adding DistanceLimit to sim_entity" "1597": "Decrementing DistanceLimit" "1687": "Testing out the changes" "1735": "Discussing collision response and double dispatch" "2575": "Alternative to entity type double dispatch - fundamental quality double dispatch" "2846": "Starting to add entity type double dispatch first for collision handling" "3270": "Why sword-monstar collision won't work quite yet - need to respond to collisions but not stop movement" "3506": "Q&A" "3580": "How long in your opinion does it take to become fluent on Emacs?" "3610": "Could an entity have multiple fundamental quality property things?" "3731": "When are you planning to add depth sorting?" "3753": "Will there be enough entities that some optimization will have to happen? How many do you expect to have on a screen? Hundreds?" "3869": "I'm not sure I quite follow your argument for double-dispatch table versus fundamental qualities. Seems to me like you still need to figure out what to do for each quality, what to do in the presence of others, still leads to quadratic growth." "4254": "Yesterday you were talking about using callbacks for the collision system. Will this new system replace the need for them?" "4290": "Casey, I asked a question and the Twitch app crashed on iPad. Any chance you my questions before it did?" "4340": "Casey, as a casual observer and occasional troll, where is the game now? Seriously, I haven't watched for a while, and how do you find the energy to do this weeknights?" "4594": "I noticed sometimes you try to determine regions for collision boxes. Why not implement basic shapes and use those as debug helpers with some alpha percentage?" "4696": "Do you test for collision every update interval? If your sword overlaps with an entity, could it happen that a moving entity gets missed because both entity and sword move in the same tick above and beyond each other?" "4827": "To me it seems as the sword should be influenced by the speed of the player movement at the time it was dispatched? Am I right?" "5004": "I missed the part on how many entities you are simulating at once and where you store them, but won't the dispatch table approach be negative for cache performance? Could its simulation be deferred?" "5098": "It seems logical to make infinity the default maximum distance an entity can travel, but that could have performance implications. Could you say something about that?" "5174": "Could you also do something like that for AI, where for instance, you can impose simple behaviors on top of each other randomly, to make complex and varied behavior, instead of doing the more common behavior tree approach?" "5192": "If you do the AAA-ness way, can you come back to it later and edit or add more details to it like from 6-to-8, etc., or will that cause problems?" --- name: "day069" title: "Pairwise Collision Rules" markers: "95": "Recap of where we left off with collision responses" "284": "Changing things so that stopping on collision is part of collision handling" "385": "Overview of ignoring certain collisions" "820": "Restructuring collision code for ignoring certain collisions with rules" "1413": "pairwise_collision_rule and collision rule hash table for ShouldCollide" "1887": "Tricky problem - How to remove collision rules?" "2051": "AddCollisionRule function" "2382": "Adding first rule - sword shouldn't collide with entity that throws us" "2515": "Adding collision rule when StopsOnCollision is false" "2617": "Problem - Don't want to keep on adding new collision rules" "2836": "Clearing collision rules for an entity" "3495": "Debugging collision rule code" "3845": "Q&A" "3903": "What stops us from programming a game that directly boots into BIOS (hooks up to hardware as low as possible basically)?" "4031": "Do you ever use function pointers?" "4147": "Should the thrown entity have the player's direction/speed added to its thrown speed/direction so you cannot catch your own throws?" "4234": "Could you explain again why you should order the entities before processing the properties?" "4350": "Isn't there a potential bug in MoveEntity if an entity happens to spend the whole distance limit, which gets set to (0,0), and then gets considered unlimited in the next frame?" "4447": "Can the pointers in the hash function become a memory problem?" "4601": "I have two gameplay requests - A non-euclidean room and a monster that spans multiple rooms vertically. Are those things possible?" "4751": "Are renderers reusable?" --- name: "day070" title: "Exploration To-do List" markers: "29": "Overview of the development process" "243": "Recap of collision rule hash table" "353": "Problem with removing collision rules from hash table" "484": "Simple solution, with trade-off, for quickly finding collision rules for entity in hash table - but not doing quite yet" "1237": "Bug in AddRadiusTo" "1386": "Brainstorming stuff to do" "1754": "TODO: Animation/Rendering" "1833": "TODO: GAME" "1884": "TODO: Rudimentary world gen" "2005": "TODO: AI" "2072": "TODO: Collision detection?" "2114": "TODO: Implement multiple sim regions per frame" "2185": "TODO: Metagame / save game?" "2471": "TODO: AI - Rudimentary monstar behavior example" "2482": "TODO: Z!" "2586": "Reviewing the TODO lists - What's hard and what's easy?" "2662": "TODO: Audio" "2778": "TODO: Metagame - save slots" "2928": "In-game UI hopefully not needed" "2956": "TODO: Debug code" "3033": "TODO: Rudimentary world gen - Map display" "3094": "Will you be carrying multiple items?" "3128": "Sorting the TODO lists" "3402": "Q&A" "3442": "Isn't doing this list thinking too far ahead or thinking too far according to your compression-oriented programming?" "3555": "In the GetHashFromStorageIndex function, you do some bit-twiddling to map hash value into hash index. Is there a reason that you didn't just compute hash index as hash index = hash value MOD array count?" "3799": "Right now the familiar lags behind since it moves slower than the player. There may be many legitimate situations where the player and familiar may be separated. Have you considered implementing a proportional integral derivative controller for its speed?" "3884": "Could you briefly go over the solution for the collision table again?" "3896": "Do we have to do z-sorting? For a game like this, can't we just sort on the y-axis, and do things to simulate climbing stairs (change the velocity as the character moves up something like stairs and what have you)?" "3988": "I heard you talking about animations and see you wrote down a skeletal system. Do you have plans on importing from a pre-made program or making an animation program for the artist to use?" "4077": "For the list - Superfish!" "4135": "Asset loading management is missing from the list." "4180": "What 2D game can you think of that did good z-movement? I personally always liked Prince of Persia when he climbed the steps at the end of the level." "4232": "Have you seen watchpeoplecode.com?" "4280": "What is your opinion on using existing code someone else wrote as a learning tool?" "4378": "Spriter's file format is completely open and documented." "4404": "Do you want to have quests in the game? In this case, how are you planning to define them?" "4448": "I think we dropped the check for Entity == HitEntity in collision code last time, or did I miss something?" "4503": "Will you patent the monstar pathfinding algorithm?" "4562": "For z-axis movement, would it be feasible to resize the sprite to be larger as they move up, and then resize the sprite to be smaller once it reaches the level, while doing some parallax stuff on the wall textures for the second resize?" "4678": "I think Pokemon 3rd gen/1st gen did good stuff with the z-axis." "4715": "Will the monstar encounters be random based (like Final Fantasy, Dragon Warrior) or will they be more static (Zelda style)?" "4750": "Should there be a time limit as well as a distance limit on the sword?" "4809": "Minish Cap handles the z-axis really well." "4816": "How exactly does your question sorting plugin work?" "4833": "I believe Ultima Online did some stuff with z-axis, but I'm not sure if it's good though." "4873": "What's the biggest game project you personally worked on?" "4934": "No remark on handmade animations? Or did I miss that?" "5001": "I've been writing my own platform layer in my own code, and I've found I've been 'poisoned' by your approach. By this, I've been heading down by a path very similar to yours simply through knowledge of a possible solution to it. This leads me to a very narrow way of thinking about problems. Do you run into this as well? How do you break through the wall? It takes me a very long to get solutions that fit my needs when I see someone else's." "5318": "How long do you think a good game should be?" --- name: "day071" title: "Converting to Full 3D Positioning" markers: "15": "Recap" "67": "Casey talk about "The coincidence of how people use their TODO notebook"" "172": "Bug fix: Remove the code we left when we were playing around with familiars" "339": "Decide what to do today: Clean up things by using v3" "361": "Get rid of the struct "world_difference" and fix other places we were using it" "496": "handmade_world.h: Change ChunkSideInMeters to v3" "585": "handmade_math.h: Implement the Hadamard product" "676": "handmade_math.h: Clone v2 operations for v3" "914": "handmade_world.h: Offset_ is v3 now" "960": "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" "1048": "Back to deal with compiler errors" "1417": "The ground plane should not be the negative bottom sides of Tiles because we want to prevent things from accelerating near the Z bound" "1572": "handmade_world.h: Tidy up the function ChunkPositionFromTilePosition" "1754": "handmade_math.h: Use anonymous struct in union to grab part of the elements we are interested in v3" "1914": "handmade_math.h: Make a v3 "constructor" that append a v2 with a real32 value" "1985": "handmade_sim_region.h: Upgrade P/dP in sim_entity to v3" "2027": "Keep on dealing with compile errors" "2137": "handmade_math.h: rectangle3" "2194": "handmade_math.h: AddRadiusTo should take a vector as a parameter" "2274": "handmade_sim_region.h: Upgrade MoveEntity routine to v3" "2600": "Get rid of GetCameraSpaceP" "2615": "Keep on cleaning up" "2840": "Program now can be compiled" "2857": "Run the game and find out there is absolutely nothing except our hero" "2881": "Make sure that rectangle bound set up properly" "2913": "Blackboard: Explain what we want to make sure in more detail" "3417": "The bug might be Casey broke something in terms of how to store things into chunk position" "3493": "Q&A" "3531": "Have you considered using macros that take a name and operator to paste in simple vector functions?" "3602": "What kind of almond milk are you drinking?" "3612": "Do you have any suggestions on how to keep up with your 5 episodes a week, when me and my friend have only started watching your videos from the beginning last week?" "3682": "Why type 1.0f instead of 1.0?" "3748": "Have you considered writing tests?" "3936": "Can you explain what your Z really means? If it's for separating levels, should tall walls be able to poke into the upper Z layer(s)?" "3996": "Reminder: Monster that you fight on two floors at once, going up and down stairs to fight the bottom or the top" "4054": "How do you tab between things so quickly?" "4119": "How good of a computer do I need to smoothly code?" "4219": "I love you... Will you marry me?" "4236": "How smooth is it transitioning a knowledge of Python into C++" "4286": "Have you thought more on how the Z-axis will look when finally implemented?" "4355": "When you work on a game do you work on one project or do they contract you for multiple projects?" "4370": "Do you think about data locality all the time, to reduce cache misses?" "4477": "How long have you been programming?" "4490": "Are you done working for real - made all your money, and this is just for fun / philanthropic reasons?" "4510": "How do you determine what gathers in a chunk with the Z-axis? Do you grab entities from all 6 sides of the chunk?" "4527": "Blackboard: "Axis aligned bounding box"" "4691": "handmade.h: TODO(casey): Minkowski inclusion test for sim region begin / updateable bounds" "4768": "I recently watched Jon Blow's talk on attempting deep work and became curious: Do you do anything similar from a psychological perspective, i.e. go dancing like Jon does or do you have some other relaxing / rewarding activity that helps to spawn creative thought or gain elusive insights into problems you are struggling to solve?" "4868": "Do you think RK4 integration is "overkill" for a 2D game like Handmade Hero?" "5065": "Hi, just tuned in so it might have been mentioned before, but why are you using assertions in non-test code?" "5378": "What about having two regions - one outer and one inner, include entities that move into the inner and exclude entities that move out of the outer - so there's a "margin" that allows some moving without ping-ponging right across a hard in / out line?" "5473": "Call it" --- name: "day072" title: "Proper 3D Inclusion Tests" markers: "48": "Coding from scratch, "just like mommy used to code"" "57": "Recap" "111": "Fix IsInRectangle cut/paste bug" "184": "Fix ChunkPositionFromTilePosition bug" "288": "Debug MapIntoChunkSpace precision problem" "431": ""Just do the code and let it go..."" "547": "Debug jumping over the world problem" "822": "Diagramming jump into the next highest chunk" "995": "Found the problem!" "1181": "Solving the world_position puzzler" "1287": "handmade.h: Comment out world_position P;" "1716": "Actually, the world_position puzzler is unsolvable" "1884": "Next up: Minkowski inclusion test" "1905": "Frinstances" "2010": "Diagramming the problem" "2176": "Related problem: finding colliding entities outside the test area" "2532": "Implementation of the simpler option" "3461": "Q&A" "3581": "We had a bit of a troll problem today. Hang on" "3623": "Pasta was gross" "3637": "What was your grade on APCS?" "3704": "I just joined the stream, so sorry if this has been answered, but what math classes did you take in high school, and what grades did you get?" "3732": "I noticed a bunch of your functions are inlined. Is there a difference between using regular functions and inlined functions?" "3944": "Day 72, how much longer do you think it's going to take?" "4010": "Could you take a look at players collision? They spawn very close to each other" "4042": "Since there's not much in the way of questions, where do you get your Almond Milk from?" "4062": "This is my first time watching your stream, and I would like to learn how to code. This seems like a cool stream to watch, but I don't know your streaming schedule. So basically, what's your streaming schedule?" "4090": "Are there are any good use cases for 4D vectors?" "4112": "Blackboard: 4D Vectors" "4261": "General programming question: Do you tend to order your functions in any sort of order - public / private / static - or even flow-wise - Function A calls Function B? Do you tend to always put one above the other, or do you never think about it?" "4323": "Will you extend your Minkowski collision implementation to deal with rotation / arbitrary convex polygons in the future?" "4514": "Why is Win32 Mouse Handling so annoying - WM_LMOUSEDOWN but no WM_LMOUSEUP if you leave your window, WM_MOUSELEAVE unless you get alt-tabbed away, SetCapture helping if you leave the window, unless alt-tab..." "4567": "Casey, when will the Z-index of the entities occur?" "4581": "Is anyone here old enough to miss the great space coaster?" "4604": "Do you ever foresee the project getting to a stage in which you accept pull and merge requests from other developers to fix bugs, add features or other things? Of course you would first have to start using version control before your hard drive fails" "4649": "I've jumped from, like, episode 12 in the archive to the stream, so forgive me if this has been answered before, but why does the player even need to jump?" "4690": "Create a second player by using the Xbox controller, it will be very close to the one created by a keyboard, so both cannot move" "4778": "What's the most elegant / sexy piece of code in the game so far?" "4902": "What program do you use for your blackboard?" "4917": "If I am not mistaken, in your code you didn't need to use any forward declarations and come up against cyclic dependencies up until now. Is this by chance or did you try in your head not to have them when writing up new functions / structs?" "5019": "Entities drawing back to front" "5039": "Will there be a Handmade Hero Convention annually, after game release?" "5065": "Are you implementing any advanced data structures and would you recommend learning assembly to aid in optimizing C programs? Any tips on practice?" "5169": "Is there such a thing as a 'hardware' cursor as compared to a 'software' mouse cursor?" "5300": "We are out of time" --- name: "day073" title: "Temporarily Overlapping Entities" markers: "57": ""Little tiny baby zipfiles"" "126": "Recap and plan for the day" "249": "handmade.cpp: Load rock02.bmp into the set" "301": "handmade_sim_region.h: Add EntityType_Stairwell to entity_type" "402": "handmade.cpp: Re-enable DoorUp and DoorDown" "464": "Talk about adding an entity for the stairwell" "527": "Introduce AddStair" "803": "Run the game and see our new stairwell" "830": "Consider how to implement the stairwell" "923": "Blackboard: Traversing stairs" "1102": "Blackboard: Inside / Outside" "1311": "handmade_sim_region.cpp: Introduce the concept of the player being within regions of space" "1585": "Blackboard: Specifying the traversable area of the stairwell" "1654": "handmade_sim_region.cpp: Continue writing the inclusion check" "2523": "Blackboard: Checking to see if two rectangles intersect" "2802": "handmade_sim_region.cpp: Write RectanglesIntersect" "2995": "HandleCollision between the Hero and a Stairwell" "3093": "Try passing through the stairwell" "3113": "Debugger: Step into HandleCollision" "3226": "handmade.cpp: Make AddCollisionRule return a boolean which states whether or not the entity was already added" "3346": "handmade_sim_region.cpp: Record the fact that you've added a collision rule if it's new" "3447": "handmade.cpp: Intrdouce RemoveCollisionRule" "3547": "handmade.h: Introduce pairwise_collision_rule_flag" "3629": "TODO(casey): Transient collision rules! Clear based on flag" "3784": "Q&A" "3883": "Q: Why did you decide to code at, like, 4?" "3920": "Q: Glad to see the A-A B-B collision detection code come up. Took me way too long to figure that one out" "4190": "Q: You mentioned yesterday about choosing between two ways to solve the problem of large entities that overlap the sim region but are not in the selected chunks. It looked to me like you could use both solutions. If the entity is larger than the max entity size, still allow it and use the add it twice approach. Would this get you all the advantages of both with neither of the disadvantages?" "4296": "Q: Would it make sense to just put a wall of 1/3rd the length on each side of the stairwell to handle the collision?" "4335": "Q: Is the TODO list in the platform layer a more or less comprehensive list of changes you would do before shipping, or are there some additional things one should note?" "4362": "Q: Yesterday you mentioned that when jumping up to a chunk above, the character would jump over the ground level Z=0 and then come down, however, since the jump code is making the Z position go to 0 from negative, wouldn't the character be pushed up to 0 as soon as it reached the low side of the upper chunk, and won't this cause problems when trying to move the character up the stairs?" "4437": "Q: All of the these algorithms all specify convex shapes. Is there anything usable for concave shapes, or is it usually always the case that it's better to just split up a concave shape into multiple convex shapes?" "4511": "Q: About the TODO list, you mentioned a while back that you want to code some sort of zooming out that would let you see entities outside the sim region" "4530": "Q: An episode on metaprogramming, please?" "4578": "We're out of time" --- name: "day074" title: "Moving Entities Up and Down Stairwells" markers: "91": "Blackboard: Processing entities in pairs" "263": "Blackboard: Using that table to process stairwell overlapping" "417": "Blackboard: Travelling inside the stairwell" "547": "Blackboard: Letting the stairwell take control" "638": "Blackboard: Lava" "838": "handmade_sim_region.cpp: Remove the WasOverlapping check" "912": "Add HandleOverlap to MoveEntity" "1079": "Compile and double check that it's still working" "1093": "Write CanOverlap and HandleOverlap" "1259": "Consider reconceptualising the Ground" "1452": "Continue writing HandleOverlap" "1523": "Learn something new about the codebase" "1529": "handmade.cpp: Draw the Stairwell as a rectangle" "1608": "Take a look at the stairwell and describe what we want to do" "1648": "Blackboard: Handling both ends of the stairwell" "1728": "Blackboard: The concept of mapping for any rectangle" "2079": ""This means nothing"" "2117": "handmade_math.h: Introduce GetBarycentric" "2202": "Introduce SafeRatio functions" "2343": "Use GetBarycentric in HandleOverlap" "2472": "Blackboard: Lerp" "2561": "handmade_math.h: Introduce Lerp" "2585": "handmade_sim_region.cpp: Use Lerp in HandleOverlap" "2636": "Handle the stairwell collision in CanCollide" "2661": "Run the game and try walking through the stairwell" "2690": "Debugger: Step into HandleOverlap" "2738": "handmade_sim_region.cpp: Check for things overlapping themselves" "2775": "handmade.cpp and handmade_sim_region.h: Introduce EntityFlag_Moveable" "2893": "handmade_entity.h: Pluralise the Flag functions" "2946": "Debugger: Step into HandleOverlap" "2985": "We already need the clamp" "3005": "Blackboard: How a guy can overlap the stairwell despite his point not being in it" "3036": "handmade_math.h: Introduce Clamp functions" "3171": "Debugger: Step into HandleOverlap and ensure that our barycentric coordinates are normalised" "3228": "Blackboard: Positioning our stairwell" "3302": "handmade.cpp: Do an offset of that ChunkPositionFromTilePosition, because he can" "3356": "handmade_world.h: Make ChunkPositionFromTilePosition take AdditionalOffset" "3387": "Run the game and look for the stairwell" "3412": "handmade_sim_region.cpp: Gather entities by ChunkZ correctly" "3494": "Run the game and see two levels at the same time" "3539": "Debugger: Step into HandleOverlap and find that we're not hitting the test" "3623": "Debugger: Investigate why the inclusion test fails" "3695": "Blackboard: The perils of not having the concept of Ground" "3792": "handmade.cpp: Make the stairwells bigger for now" "3838": "Run the game and find we're lerping properly" "3878": "handmade_sim_region.cpp: Use our Ground value" "3897": "Run the game and find that we're getting closer" "4000": "handmade_sim_region.cpp: Additionally test the entities' Z planes to determine if they CanCollide" "4027": "Run the game and find that we're sort of getting there" "4120": "Q&A" "4151": "Is the familiar going to be programmed to be able to go through the stairwell or instantly teleported to the floor?" "4204": "When are we going to do priority for which sprite is in front and in the background? (I don't know what that is called)" "4322": "You mentioned that you'll be able to attack from below / above. Will you be able to do that on the stairwell?" "4379": "I've just started to see your videos, but you already talked / programmed about entity systems. Will you use it here?" "4440": "Does the scope of this application include moving environments, so you will need to introduce logic to detect movement of assets?" "4490": "Will the game have color grading for different areas, e.g. the blue & black cloak the hero wears might appear as two other colors in some lighting conditions?" "4560": "What are the piece groups and how are they used / useful for our current use in sprite rendering?" "4635": "Can you please, forgive my French, somehow un *** the net coding for DayZ Standalone and finish what Dean "Rocket" Hall gave up on?" "4697": "Will enemies follow you upstairs or down? If they do, how will the space outside the camera work?" "4724": "How will you handle sprite animation? Are you using a library and have you ever hear of the Spine 2D skeleton animation framework?" "4791": "Who is that guy?" "4897": "I mean with there being different floors will it be different? I am assuming not" "4968": "Can you run this game so some of us see its current state?" "5214": "Okay, so you know how we have the camera space and then there's a space outside that we can't see but entities are still moving? Will we need to edit that code to make it work on "Vertical" floors? It's okay if you don't get it. I may be thinking too far in" "5282": "Would we use a fixed, discrete animation for moving up and down stairs a la Link to the Past, or would the goal be to make movement seamless?" "5344": "How much lines of code do you have at the moment?" "5395": "That is the end" --- name: "day075" title: "Conditional Movement Based on Step Heights" markers: "238": "Blackboard: Handling stairwell traversal" "465": "Blackboard: Collision Detection in Z" "501": "Blackboard: Draw reasonably" "515": "Run the game to show the multiple visible floors" "667": "handmade_sim_region.cpp: Prevent the entities from being accelerated by gravity while on the ground" "741": "handmade_sim_region.h: Introduce EntityFlag_ZSupported" "780": "handmade_sim_region.cpp: Use EntityFlag_ZSupported" "890": "handmade.cpp: Take out the stairwell height padding" "944": "handmade_sim_region.cpp: Add a BreakHere variable in MoveEntity" "965": "Debugger: Step into this point in MoveEntity" "1054": "Debugger: Note that EntityFlag_ZSupported is only being set when we're under the Ground" "1074": "handmade_sim_region.cpp: Change that if statement to include the Ground" "1099": "Debugger: Step into that point in MoveEntity" "1231": "handmade.cpp: Give the stairwell some Z depth" "1291": "Run the game and jump through the layers and find that we do now collide with the stairwell" "1348": "handmade_sim_region.cpp: Specify another criteria to determine when we want to stay pegged to the ground" "1445": "handmade.cpp: Stop the Familiar from following us" "1457": "Walk up and down the stairs" "1539": "handmade.cpp: Make the stairwell a little longer" "1683": "Run the game and demonstrate teleporting to the top of the stairs" "1712": "Blackboard: Consider building the stairwells out of multiple things" "1805": "handmade_sim_region.cpp: Consider doing a speculative collide test on the stairs" "1953": "handmade_sim_region.cpp: Introduce TestWallNormal, TestHitEntity and SpeculativeCollide to do these speculative tests" "2398": "Debugger: Step into SpeculativeCollide and find that we are not hitting the stairwell" "2472": "handmade_sim_region.cpp: Flip the logic of SpeculativeCollide" "2486": "Run the game and find that the stairwell is behaving as expected expect for the fact that we're not gliding along it, and also that we are now not colliding with walls" "2554": "handmade_sim_region.cpp: Tweak the logic of SpeculativeCollide" "2606": "handmade_sim_region.cpp: Stop setting StopsOnCollision = false" "2622": "Run up and down the stairs and note how good it feels" "2728": "handmade.h: Attend to the TODO list" "2813": "handmade_sim_region.cpp: Add DefaultGroundLevel to sim_region" "2876": "handmade_sim_region.cpp: Compute the DefaultGroundLevel based on the information in BeginSim" "2912": "Blackboard: Specifying the ground levels in a given sim region" "3029": "handmade_sim_region.cpp: Rename DefaultGroundLevel to GroundZBase" "3086": "Blackboard: Snapping to the correct ground level" "3227": "handmade.h: TODO(casey) Need to make a solid concept of ground levels so the camera can be freely placed in Z and have multiple ground levels in one sim region" "3273": "Run the game and note that the Familiar and Monstar are erroneously getting snapped up to our Z level" "3319": "handmade.cpp: Tweak entities' positions based on their Z level" "3513": "Q&A" "3558": "I'm guessing the engine will manage arbitrarily high ground levels? Would you really want that? Gameplay such as projecting attacks to a monstar below does sound fun" "3648": "Why not use the X and Y positions as they appear on the screen for detecting sim regions?" "3678": "Should you also check the "stair step" at the top of the top of the stairs? It seems you can exit earlier than at the bottom" "3781": "Could you please do an overview, on blackboard maybe, of the "entities position system" (world, screen, etc.) now that it's "done"? I'm having trouble understanding it (hopefully you'll understand my question)" "3999": "Why is the order of stuff drawn on the screen janky (some trees overlap others, some are proper)?" "4006": "Isn't it easy to draw them in order - each layer draws entities left to right, top to bottom?" "4089": "Is the reason why things in different levels seem shifted up due to the Z-offset when rendering?" "4155": "Will this cause for the wall on the top to be drawn above the screen when the camera is locked instead of following the character?" "4192": "When you are allocating everything with custom memory allocators, do you only use the stack for pointers?" "4225": "Are you not worried that three dimensions might complicate entity A.I. to the point where it impacts performance?" "4281": "Casey, can you check your forum registration process? I never got a confirmation email - registered a couple of days ago" "4343": "When will you switch back to centered camera? It seems to be missing on the TODO list" "4364": "Any particular reason behind making the chunk origin the center of the chunk rather than one of the corners?" "4427": "Sorry for being unclear. Do you store anything else than pointers on the stack?" "4474": "If the camera were far away enough from the player, would the player go into a simpler routine like the rest of the entities?" "4496": "Should the possible collision test use the TestHitEntity instead of the TestEntity or are they the same? Can you briefly go over the flow of the HitEntity changes?" "4890": "You could now cancel out the first HitThis == true and not do other checks" "4986": "We have agreed to go on break for a week" --- name: "day076" title: "Entity Heights and Collision Detection" markers: "154": "Start everything up, make sure it's all still working and plan for the day" "381": "handmade_sim_region.cpp: Consider confining collision detection to the entities' Z neighbourhood" "581": "Blackboard: Extending Minkowsi collision into the third dimension" "709": "handmade_sim_region.cpp: Check Rel.Z against the MinCorner and MaxCorner" "778": "Run the game and find that we're passing through everything" "797": "Debugger: Step in and inspect the MinCorner and MaxCorner" "899": "handmade.cpp: Give the wall and other entities some height" "1018": "Run the game and find that we now stop correctly" "1080": "win32_handmade.cpp: Ensure that we're not passing WS_EX_LAYERED to CreateWindowExA" "1185": "Blackboard: Conceptualising TileSideInMeters" "1449": "Blackboard: Conceptualising WorldChunk" "1707": "handmade_world.cpp: Pass in TileDepthInMeters to InitializeWorld" "1776": "Blackboard: Competing Gathers" "1949": "handmade_world.cpp: Update ChunkPositionFromTilePosition to reflect our new Tile dimensions" "2097": "Postpone this until we have debug visualisations" "2143": "Run the game and double check that it's working properly" "2178": "handmade.cpp: Specify the height of things" "2265": "handmade_math.h: See what RectanglesIntersect does" "2330": "Blackboard: Inclusion tests" "2524": "Blackboard: Checking overlaps" "2628": "handmade_math.h: Change the tests in RectanglesIntersect" "2695": "Run the game and find that we are unexpectedly still working properly" "2735": "Investigate what's happening with the stairs" "2819": "Blackboard: Understanding entity placement" "2935": "handmade_sim_region.cpp: Take a look at where Dim is being used" "2999": "handmade.cpp: Introduce AddGroundedEntity" "3180": "Pass AddGroundedEntity to AddWall" "3248": "Run the game and double check that it worked" "3277": "handmade.cpp: Pass AddGroundedEntity to AddStair, AddPlayer, AddMonstar and AddFamiliar" "3486": "Run the game and see where we're at" "3520": "Debugger: Step into AddGroundedEntity" "3567": "handmade.cpp: Consider fixing the drawing code" "3716": "Q&A" "3782": "Q: That kid you just created is around two foot tall" "3810": "Q: Better data is at halls.md" "3843": "Q: I was wondering, why do you have two windows open and not just one?" "3893": "Q: Over four feet seems right for a seven year old" "3942": "handmade.cpp: Make the Hero 1.2 metres tall" "3992": "Q: What apps are you using for the dev environment?" "4075": "Q: Any recommendations for tracking down heap corruption bugs?" "4568": "Q: If you're not allocating memory as the game goes, are you allocating a bunch at the start? How does that work?" "4633": "Q: What are the Linux equivalents to these functions?" "4673": "Q: How far along are we in developing the game?" "4788": "Q: munmap is another Linux equivalent call" "4802": "Q: Is this in C++?" "4871": "Q: Does C++ compiler generate hidden code like constructors, copy constructors, etc., in the way that you structuring the game?" "4974": "Q: Do you use the STL at all in your code?" "5058": "Call it" --- name: "day077" title: "Entity Ground Points" markers: "120": "Recap the bug from yesterday" "242": "Blackboard: The discrepancy between the Entities' base points and the Ground position" "330": "Look at how these concepts are currently specified" "426": "handmade_sim_region.cpp: Add 0.5*Entity->Dim.Z to Ground" "451": "Run the game and find that we're not quite right" "526": "Debugger: Step into the code where Ground is calculated" "605": "handmade.cpp: Look at the current drawing code" "914": "Introduce EntityBaseP" "1031": "Run the game and find that we seem to have solved the problem" "1091": "handmade.cpp: Add two rectangles to the Stairwell" "1200": "Work on the ZFudge" "1350": "Check out the effects on the Familiar" "1386": "MetersToPixels is getting pre-multiplied by OffsetZ" "1457": "Run the game and see it looking more correct" "1514": "handmade.cpp: Don't bother adding OffsetZ" "1554": "Blackboard: What the ZFudge is doing" "1691": "handmade_sim_region.cpp: Look at SpeculativeCollide" "1733": "Introduce GetEntityGroundPoint" "1818": "Use GetEntityGroundPoint to set EntityBaseP and Ground" "1889": "Blackboard: Computing the Ground displacement" "1961": "Run the game and find we can now go upstairs" "1989": "handmade.cpp: Make stairways extend above the ground" "2076": "Blackboard: Understanding StepHeight" "2218": "handmade_sim_region.h: Add WalkableHeight to sim_entity" "2281": "handmade.cpp: Use that WalkableHeight in SpeculativeCollide" "2317": "Run the game and try the stairs" "2359": "handmade_entity.h: Introduce GetStairGround" "2641": "handmade_sim_region.cpp: Convert HandleOverlap and SpeculativeCollide to use GetStairGround" "2815": "Run the game and find that that fixed our problem" "2848": "handmade_sim_region.cpp: SpeculativeCollide needs to know whether we're coming on to or moving off a stairwell" "3041": "Q&A" "3135": "Q: Do you use Clang on Linux?" "3168": "Q: What is the best way to learn C++ from absolute scratch on my own?" "3236": "Q: Do you know anything about Voxpel programming?" "3275": "Q: What versioning and revision control system do you use?" "3283": "Q: Are you planning on replacing the stairs in your house with ramps?" "3376": "Q: How did you get the right side of your Visual Studio debug view to be split vertically?" "3469": "Q: Why do you use so many magic numbers in your code?" "3488": "Q: What do you think about friend classes?" "3510": "Q: Is this turning into reverse Doom? Almost complete 3D rendered in 2D, instead of 2D rendered in 3D" "3630": "Q: Is the top layer going to fade in if you go up the stairs into a closed room?" "3661": "Q: When do you plan on doing Z-sorting with the sprites?" "3676": "Q: Why do you use so many magic numbers in your code? Why so many #defines?" "3733": "Q: Are you planning to use advanced shader techniques? If so, which ones?" "3760": "Q: Looks like I skipped an episode in which you made a lower level visible from a higher one. Do you remember when did it happen? Is the floor going to remain transparent in the future?" "3823": "Q: My previous question was on topic. Missed it, maybe" "3841": "Q: Correct me if I'm wrong, but it seems early on we started with a bottom-centre position for collision detection on our hero. We moved to a centre position which was offset in both X and Y. Now it seems we use a centre X and Y and are continuing to compute the bottom-centre position. Do you feel this needs to be consolidated in any way?" "3950": "Q: What's with the floating head in the middle of the forest?" "3974": "Q: Could you explain the line ControlledHeroes[ArrayCount(((game_input *)0)->Controllers)]; in handmade.h because it looks like you're casting a null pointer and referencing" "4130": "Q: To workaround the Mischief zoom issue, how about you find the zoom level you want then draw four dots, one in each corner, then when you come back you can align those dots back to the corners" "4150": "You could use C++'s decltype or typeof to find that ArrayCount" "4271": "Could you do it: ArrayCount(game_input::Controllers)?" "4300": "Q: declval is what you want" "4404": "Q: Why do you plan on using OpenGL or DirectX for hardware acceleration? Is that something that you have to have knowledge of actual GPU architecture to be able to implement?" "4487": "Q: What do you think of Khronos Vulkan?" "4578": "Q: What is the best way to build a game when you know how to program but you have no art skills? Hire an artist to do it for you? That is my Achilles' heel, but I want to make a game on my own" "4698": "We have come to the end" --- name: "day078" title: "Multiple Collision Volumes Per Entity" markers: "97": "Blackboard: Position != Collision "Mesh"" "553": "handmade_sim_region.h: Introduce sim_entity_collision_volume" "654": "Blackboard: Two ways of storing this collision volume data" "771": "handmade_sim_region.h: Introduce sim_entity_collision_volume_group" "909": "Compile and be guided by the compile errors in replacing the Dim" "943": "handmade_sim_region.h: Add WalkableDim to sim_entity" "1058": "handmade_entity.h: Use WalkableDim in GetStairGround" "1171": "handmade_math.h: Introduce GetBarycentric for rectangle2" "1218": "handmade_math.h: Introduce Clamp01 for v2" "1263": "handmade_sim_region.h: Add sim_entity_collision_volume TotalVolume to sim_entity_collision_volume_group" "1391": "handmade_sim_region.cpp: Pass sim_entity_collision_volume to EntityOverlapsRectangle" "1551": "handmade_sim_region.h: Specify that the VolumeCount is always expected to be greater than 0 if the entity has any volume" "1641": "handmade_sim_region.cpp: Iterate over the Volumes" "1684": "Blackboard: Collision detection is an o(n^2) problem" "1802": "handmade_sim_region.cpp: Continue writing this loop" "2038": ""Don't ask me why I'm doing this renaming"" "2131": "Casey is out of tea" "2141": "Dream of gourmet tea" "2233": "handmade.h: Add sim_entity_collision_volume_groups to game_state" "2757": "handmade.cpp: Use the WalkableDim to draw the Stairwell" "2816": "handmade.cpp: Implement MakeSimpleGroundedCollision" "3070": "handmade.cpp: Do InitializeWorld earlier" "3095": "Run the game and find that we're not totally busteD" "3147": "handmade.h: Flying things can now go over low walls" "3187": "handmade.cpp: Initialise the WalkableDim in AddStair" "3278": "handmade_math.h: Introduce ToRectangleXY" "3353": "Run the game and see that our stairwell is back" "3378": "handmade_sim_region.cpp: Reenable the stairwell collision" "3443": "Run the game and try jumping over the stairwell" "3504": "handmade.cpp: Implement MakeNullCollision" "3590": "Run the game and note the weird effect of gravity while falling down the stairwell" "3664": "handmade_sim_region.cpp: Set Drag.Z = 0.0f" "3709": "Run the game and fall down the stairwell" "3728": "Q&A" "3758": "Run and jump around" "3816": "Can we get a sneak preview of the fundamental types arena?" "3823": "Blackboard: Fundamental Types Arena" "3903": "Besides the missed keys" "3968": "What did I just watch?" "4130": "Could you sketch what you did today visually? Was it just changing the collision paradigm?" "4135": "Would the ground collision be easier / have less issues if it was a volume instead of a plane?" "4187": "Blackboard: Specifying the ground" "4368": "Since you are handling Z, how complicated is it to have entity stacking, with the current code state?" "4406": "Are you using a memory manager?" "4411": "How are you laying out your levels currently and are you going to make a level editor?" "4460": "Is knowing Big O notation important in the game programming industry?" "4508": "You mentioned further ways of partitioning collisions past breaking it up into regions. What would some of those be?" "4556": "End that for today" --- name: "day079" title: "Defining the Ground" markers: "236": "handmade.h: Check the TODO list" "291": "Blackboard: The Ground" "345": "Blackboard: Quake vs. Unreal" "541": "Blackboard: Quake's "Constructive Solid Geometry" Paradigm" "639": "Blackboard: Unreal's "Constructive Solid Geometry" Paradigm" "741": "Blackboard: The difference between these two models" "865": "Blackboard: Robustness vs. Efficiency" "1015": "Blackboard: Propose not talking about "Ground" or "Floors", but "Rooms"" "1906": "Blackboard: What happens when you step off a ledge?" "2116": "handmade_sim_region.h: Add EntityType_Space entity_type" "2177": "handmade.cpp: Implement the ability to create an EntityType_Space" "2441": "handmade.cpp: Introduce AddSpace" "2824": "handmade.cpp: Rename AddSpace to AddStandardRoom and add EntityFlag_Traversable" "3049": "Blackboard: No overlap between adjacent rooms" "3100": "Run the game and see some giant rectangleS" "3143": "handmade.cpp: Turn off AddStandardRoom" "3195": "handmade.cpp: Correct the sim_entity_flags settings" "3242": "handmade_sim_region.cpp: Check EntityFlag_Collides in CanCollide" "3282": "Run the game and find that we now correctly don't collide with the StandardRooms" "3290": "handmade.cpp: Introduce PushRectOutline" "3397": "Blackboard: Drawing out the PushRectOutline" "3458": "handmade.cpp: Continue writing PushRectOutline" "3553": "Run the game and find that we cannot see the outline" "3566": "handmade.cpp: Increase the thickness of PushRectOutline" "3590": "Run the game and find that we're only drawing one line" "3607": "Debugger: Step into PushRectOutline" "3730": "handmade.cpp: Multiply the Dim by half" "3779": "Run the game and see our correctly drawing outline" "3825": "Q&A" "3907": "What setup do you use for debugging on Linux?" "4021": "Can you upload the videos somewhere else? YouTube is blocked in China. I would like to watch from the beginning" "4064": "When doing the vertical movement, would it be reasonable to take two measurements: one at current position, then one at "final moved" position, and average the movement?" "4107": "Are walls going to be entities, or just byproducts of the subtracting of the room volume?" "4140": "LLDB works better than GDB, if you can deal with the command line interface" "4180": "Should you have been able to jump up to a level above the player now that you have a .9 value for the Space Z volume?" "4224": "Will the entities not at the player's Z level always be at the same alpha transparency or will they be slightly less visible to show that they are on a different Z level?" "4314": "Why should anyone trust you to annotate a game when you have no published success preparing a full-fledged commercial game?" "4368": "If you were a software programmer, how many apps could you have done in the same amount of time you have put into this?" "4431": "Will there be water, and how would it affect movement?" "4486": "Reminder: Water that you can swim in, maybe with currents too?" "4516": "Does the system used for the ground now make it harder to have things like moving platforms the player can stand on?" "4530": "Reminder: Moving platforms the player can stand on" "4555": "Was the use of calculus involved in your programming?" "4602": "For this scheme, will the room geometries need to overlap in order to move between rooms, or can they just abut?" "4644": "Can you illustrate how they do the level editors / world layouts in modern engines now?" "4748": "Are you going to use files to store levels? If so, will they be custom format?" "4773": "Would the combat algorithm in a 2D game differ from a 3D game?" "4805": "How can I work with other programmers when our coding styles clash?" "4866": "Should there be walls around stairwells now, or will we still just use the collision rules from before?" "4889": "Are you going to procedurally build levels, or pre-defined levels?" "4903": "Will wee see stuff like light sources, ray tracing, surface mapping, etc. at some point in this stream?" "4941": "Have we started doing collision detection and handling? If no, how detailed will it have to be?" "4966": "What do you think about storing game data in code?" "5039": "So you will continue complaining about Windows while making money programming with it and Visual Studio?" "5430": "Can you rename the stream to Casey's Little Kindergarten?" "5458": "One day you said you lost hope in Microsoft, and now you say you complain so they can fix it?" "5638": "Was git an example, or do you feel there are problems with it? Curious to hear" "5742": "Call it there" --- name: "day080" title: "Handling Traversables in the Collision Loop" markers: "269": "Blackboard: Augmenting the collision loop to loop over two types of t value" "310": "handmade_sim_region.cpp: Introduce tMax" "358": "handmade_sim_region.cpp: Consider how best to modify this routine" "663": "handmade_sim_region.cpp: Loop over the Walls to get all of the data taken by TestWall" "915": "handmade_sim_region.cpp: Introduce test_wall" "956": "Run the game and make sure it's still working" "974": "handmade_sim_region.cpp: Embed TestWall directly in the collision loop" "1065": "Run the game and test the collision" "1132": "handmade_sim_region.cpp: Test tMax" "1323": "handmade_sim_region.cpp: Massage the routine" "1467": "handmade_sim_region.cpp: Implement the tMin vs. tMax logic" "1587": "handmade_sim_region.cpp: Write the tests for Overlap and EntityFlag_Traversable" "1689": "Encourage us not to be scared of solving complex problems" "1969": "handmade_sim_region.cpp: Improve the overlap test" "2157": "handmade_sim_region.cpp: Introduce EntitiesOverlap for this overlap test" "2322": "handmade_sim_region.cpp: Make EntitiesOverlap take an Epsilon enlargement region" "2406": "handmade_sim_region.cpp: Reenable the EntityFlag_Traversable test and use EntitiesOverlap" "2512": "Run the game and find that we can't get past our tMax" "2547": "handmade_sim_region.cpp: Move tMin, tMax and HitThis inside the loop" "2643": "handmade_sim_region.cpp: Rethink the logic of the collision routine" "2785": "Run the game and find that we're working a little more properly" "2804": "handmade.cpp: Only create walls in the first room in order to test the new world definition" "2827": "Run the game and test the collision detection" "3004": "handmade_sim_region.cpp: Increase the size of the overlap Epsilon" "3115": "Debugger: Step into the collision routine" "3243": "handmade_sim_region.cpp: Initialise tMaxTest to our current tMax" "3274": "Run the game and find that everything seems pretty good, but still a little janky" "3295": "Set the stage for next week" "3333": "Q&A" "3343": "Consult the TODO list" "3494": "Can you explain the LengthOf(array) macro, and the sizeof pointers?" "3979": "Will the space entities be used for the collision optimization you were talking about in an earlier stream? o(n^2) stuff" "4038": "sizeof(game_input::Controllers) works for me with g++" "4089": "I noticed that you tend to mostly skip over questions past the first question mark. Is it because you just parse that way or the rest tends to be not much interesting?" "4143": "For things like the projectiles, are we going to extend their bounding boxes in the Z axis so they will always hit enemies that are below them? Or are we going to handle that in screen space somehow?" "4204": "Do you dislike templates?" "4277": "How will you handle something like an explosion that affects all things in an area? Then it's not 1 entity colliding with another" "4329": "What do you think about the new Vulkan API?" "4395": "Wrap things up" --- name: "day081" title: "Creating Ground with Overlapping Bitmaps" markers: "19": "A regrettable incident..." "367": "Maybe we should try to add some sort of drawing to the ground" "433": "Viewing the art assets in GIMP" "672": "Casey's vision for the art" "910": "Load ground textures" "1052": "Introduce DrawTestGround to composite the textures" "1276": "Viewing the results in-game" "1305": "Randomly splat down a ton of grass textures" "1396": "Looking at RandomNumberTable" "1482": "Figure out the maximum value of RandomNumberTable" "1601": "...and the minimum value" "1691": "Produce a floating point number between 0 - 1 within the range of RandomNumberTable" "1784": "Blackboard: Transforming a number from being between 0 - 1 to between -1 - 1" "2045": "Blackboard: What happens in between two points?" "2246": "Blackboard: Degrees of polynomial" "2729": "Implement the equation f(x)=2x-1 and splat multiple grass textures" "2863": "Account for the centre of the bitmap" "2958": "Set the radius by which to offset the splats" "3065": "Provide a function to make a v2 out of integers" "3197": "Parameterise loaded_bitmap" "3490": "Restart the game" "3510": "Tuft it up" "3576": "Q&A" "3629": "On the fancy autoload dll stuff" "3712": "Q: Is there an art team working on this game?" "3761": "Max random number should be set to fixed number 100000[...] because in episode 35 when you went to random.org you chose to generate random numbers from 0 up to that number" "3831": "Obviously that wasn't a serious comment. But on-topic question: Do you want to mention tangents when designing curves?" "3880": "Would you ever actually use a higher degree polynomial interpolation? Aren't there better ways to make interpolating curves that are more stable?" "4433": "Q: What sort of optimisation would you do on that ground stamping?" "4576": "Q: You aren't treating both ends of the random numbers the same. With the current system you can get 1 but you will never get 0 because you are not considering the min..." "4709": "Q: Do you plan on having things like dirt paths and, if so, would you draw them using splats and stamps?" "4808": "Q: So your ground texture design is essentially MegaTexture?" "4869": "Q: Based on the stream, it appears that you need to know math to do this type of activity. Is that correct?" "4933": "Blackboard: Casey's Plan vs. MegaTexture" "5567": "Q: Why do you think John Carmack is a hack and when are you going to say it to his face?" "5766": "Conclusion" --- name: "day082" title: "Caching Composited Bitmaps" markers: "41": "Let's take a look at where things were" "132": "Toggle off the debug boundaries" "169": "Two things to look at: 1) Speeding up the texture splats and 2) Multiple layers" "256": "How to make the random number generation more systemic" "617": "Introduce random_series which takes a seed" "783": "RandomUnilateral (0 - 1) and RandomBilateral (-1 - 1)" "875": "Blackboard: Brief recap of yesterday's maths class" "918": "Introduce RandomBetween" "998": "Pass RandomChoice to the Stamp picker" "1037": "Make Seed function" "1103": "Implement the rest of the random number generation" "1345": "(Re)introduce Lerp" "1488": "Blackboard: Lerp or Linear blend" "1608": "Stick it in handmade_math.h and use it?" "1673": "Finish propagating RandomChoice" "1877": "Make a RandomBetween for use in integer space" "2025": "Find the Familiar" "2194": "Fix the FamiliarOffset range" "2366": "We've taken care of everything regarding the random number table" "2408": "Next: Try doing a pre-composite" "2469": "Look at how game_offscreen_buffer used to work" "2514": "Condense game_offscreen_buffer and loaded_bitmap down to one thing" "2747": "Set the Pitch and Pixel pointer from the Bitmap" "2917": "A small correction, and viewing the results" "2952": "Change DrawBitmap to take loaded_bitmap *Buffer, and change *Pixels to *Memory in loaded_bitmap" "3002": "Remove BytesPerPixel from game_offscreen_buffer" "3070": "Make everything take the data from loaded_bitmap" "3173": "Implement a GroundBuffer cache" "3360": "Implement MakeEmptyBitmap" "3622": "Set the alpha channel of the composited bitmap" "3885": "Recap today's work" "3974": "Q&A" "4022": "Q: Casey, I missed the earlier part of the feed, but what was the intention of moving the ground plane with the player?" "4057": "Q: Why aren't RandomUnilateral and RandomBilateral not just using the implementation of RandomBetween? Seems like a pretty clear violation of DRY, although I realise you aren't currently intending for this code to be extremely clean right now" "4279": "Someone wants a cloc count" "4331": "Q: Why does the Seed function not have a prefix or suffix Random?" "4434": "Q: Is it okay that RandomChoice doesn't select the random value uniformly? [...]" "4522": "Q: Wouldn't RandomChoice have a slightly uneven distribution if the number of choices didn't evenly divide the maximum random number?" "4639": "Q: When is it okay to pass larger objects like r3's by value instead of by reference?" "4921": "Q: Casey, just curious because the background tiles are static at the moment..." "4948": "Q: Do you see yourself extending RandomNumber to have anything other than a uniform distribution?" "5002": "Q: Is this strictly handled in RAM? Do you have plans to use GPU resources for rendering?" "5046": "Q: I notice in functions you will always use a Result variable even if the calculation is a one-liner, rather than using the expression directly in a return statement. Does this incur an extra copy and are there performance implications?" "5106": "Q: Do you plan to move all the other loaded_bitmap memory to be in a memory_arena as well?" "5137": "Q: I think you've used an aggregate initialiser in one place with random_series being seeded, i.e. you only have one call to RandomSeed but you have at least..." "5213": "Q: Initially, you put BytesPerPixel into the bitmap structure because it can be useful. Then I asked you to remove it because it never changes, and you did that. But ten or so episodes later you added it back because it would be useful. And now you're removing it again. This is funny" "5265": "Q: You fix Random to be uniform by generating a full 32bit random number, do mod next power of 2 choice count, then check if result is less than choice count. If not, repeat the whole process" "5298": "The end of another full-power episode of Handmade Hero, which was dedicated to Abner Coimbre" --- name: "day083" title: "Premultiplied Alpha" markers: "104": "Recap yesterday's work" "260": "Investigate peripheral problem" "361": "Blackboard: Alpha channel in the intermediate buffer" "608": "Blackboard: Considerations for handling alpha" "990": "The allergy of computing" "1028": "Blackboard: Alpha blend our edges" "1385": "Fuss with alpha" "1449": "Call DrawTestGround every frame" "1525": "Play with DrawBitmap" "1607": "Introduce real32 RSA in order to keep SA and DA in the same space" "1763": "Does that produce the result we expect?" "1818": "What GIMP thinks is a reasonable thing to have occur" "1918": "Play with the alpha channel of Stone" "2151": "Blackboard: What's happening with the colours?" "2447": "Blackboard: Pre-multiplied alpha" "3354": "Pre-multiply alpha" "3488": "Grab out each individual channel" "3651": "Do that pre-multiplication" "3858": "Blackboard: Brief recap" "3967": "Blackboard: Do the pre-multiplied alpha examples in algebra" "4299": "Blackboard: Have something in that screen to begin with" "4581": "Blackboard: Group the terms" "4933": "Blackboard: The equation for the pre-multiplied alpha" "5045": "Implement the equation" "5137": "Re-enable DrawTestGround" "5224": "Put CAlpha back in" "5413": "Check the equation" "5557": "Q&A" "5598": "Q: According to [a website], to fix the Wacom driver without restarting, stop and start Wacom Professional Tablet Service" "5700": "Q: Being Happy, Sleepy and Sneezy, you do realise you're just four dwarves short of a whole crew?" "5767": "So if I understand correctly (sorry if my interpretation just confuses anyone), the reason off-screen rendering was incorrect before pre-multiplied alpha was that, after blending, things in the texture - the colours there - were pre-multiplied because they were multiplied when they were put in the texture. If, for some reason, you didn't want to optimise your code, you could also divide the colour channel by the alpha to get it back to un-pre-multiplied. Is this a reasonable understanding of the issue?" "6175": "Q: Can you give a small example of what the decompression step between SimEntity and StoredEntity will look like?" "6204": "Q: Maybe we should set a way for you to see things like that kind of help, if someone finds a good possible solution. No, I don't know how" "6235": "Blackboard: A lot of equationing" "6283": "Wrap up the stream with a brief recap..." "6374": "...a peek into the future..." "6569": "...and closing remarks" --- name: "day084" title: "Scrolling Ground Buffer" markers: "96": "Damage Assessment" "157": "We are trying to figure out how to finish off our world construction" "263": "Think about how to handle the ground" "323": "Look at how we're currently specifying the ground" "409": "Blackboard: Our system for defining the ground" "636": "Blackboard: A potential plan and guiding principals of engine architecture design" "771": "Blackboard: How to store the splat list" "880": "Blackboard: Figuring out the shape of the ground" "1044": "Blackboard: Considering multiple Z-levels / depth" "1520": "Blackboard: Empty space things will carve out regions like that" "1639": "Blackboard: What are the splats for the region?" "1729": "Try to make the ground plane scroll infinitely in all directions" "1779": "Enlarge GroundBuffer, introducing MaximumZScale and GroundOverscan variables" "2125": "Partition the GroundBuffer so that we can scroll it around" "2164": "Blackboard: How the GroundBuffer is currently positioned" "2281": "Locate GroundBufferP relative to CameraP" "2591": "Plan to snap the GroundBuffer towards the camera's direction whenever it runs out of pixel coverage" "2613": "Turn off the trees" "2688": "Turn off Z doors" "2732": "Turn on the trees" "2760": "Make the ground constantly generate itself" "2828": "Blackboard: Tiling considerations" "2918": "Turn DrawTestGround into DrawGroundChunk" "3268": "View the results in-game" "3308": "Q&A" "3358": "Q: Why don't we fill the entire game window instead of having all that black space?" "3509": "Q: Are some of these issues with dealing with display on multiple levels stemming from the lack of a Z-coordinate for the camera to just do a lerp on?" "3663": "Q: If no one's asking related questions, could you ballpark a time-frame when adding a font and text rendering system will become useful or necessary?" "3782": "On learning C++" "3910": "Q: You mentioned offloading ground drawing to a separate thread to prevent hitches. Is it possible to offload the drawing work over multiple frames, and would there be any benefits over either method?" "3990": "Q: How much of a memory footprint is your game using already? Certainly it won't be large, but I'm more meaning how many different containers are there?" "4013": "Q: Procedural generation of 2D graphics: is there some mainstream math for that?" "4058": "Q: What is your programming experience as before Handmade Hero?" "4122": "Q: How many different classes are you having to use already?" "4230": "Q: Is there a simple way to explain pointers and references in C++?" "4590": "Closing remarks" --- name: "day085" title: "Transient Ground Buffers" markers: "78": "Recap of yesterday's repeating ground texture work" "138": "Blackboard: A smarter way to do things" "319": "Blackboard: Why don't we just make an array of tiles...?" "400": "Introduce TransientArena" "518": "Two memory areas: permanent storage and not-necessarily-permanent storage" "580": "Create that TransientArena" "621": "Allocate some space out of the TransientArena for the GroundBuffer" "707": "Make space for the array of empty bitmaps" "753": "Loop through them and allocate empty buffers" "834": "Provide the option to ClearToZero" "916": "Spec out GroundBufferHeight and GroundBufferWidth" "1011": "Put GroundBuffer into a loop" "1071": "How is the Bitmap aligned in the world?" "1137": "Find where the GroundBuffer is relative to the Camera" "1250": "Make sure that we're not drawing a GroundBuffer here if it isn't valid" "1316": "Which of our GroundBuffers actually has been getting used?" "1383": "Blackboard: Least Recently Used" "1631": "Look at what's in the structure" "1730": "Introduce GroundBitmapTemplate exemplar" "1881": "Limitations of the automatic dll-loading" "1946": "Debug GroundBuffers" "2015": "Owl of Shame Moment: There should have been a TODO about making the TransientArena do something real" "2062": "Blackboard: Memory partitioning schemes" "2336": "Introduce some way for us to use the memory in the TransientArena effectively" "2433": "Introduce transient_state" "2472": "Blackboard: What's in our stack?" "2547": "Transient initialization" "2807": "Pass the TransientArena to SimRegion" "2832": "Blackboard: Bungee back to the base line that was just after the GroundBuffer" "2869": "Let the Arenas do pushes and pops" "2889": "Insurance policy" "2915": "Implement the bungee and additional security" "3193": "Step through the code" "3294": "FillGroundChunk" "3480": "View the results in-game" "3551": "Q&A" "3575": "Q: What is the most expired food you have ever eaten?" "3591": "Q: Could you explain what pop and push are, and how they work?" "3689": "Blackboard: Memory is a big line!" "4249": "Q: How will the ground texture chunking handle adjacent rooms with different types of ground?" "4409": "Closing remarks" --- name: "day086" title: "Aligning Ground Buffers to World Chunks" markers: "230": "Recap" "254": "The Proposal: First, just produce tiles that cover things... but they won't be seamless" "358": "Address specifying which ground_buffer we need" "423": "Stop doing the test fill for GroundBuffer" "449": "Iterate over every place the camera can see and request a GroundBuffer" "783": "Blackboard: Offset considerations" "889": "Subtract the offset" "945": "Consider the size of a Chunk" "1123": "Brief interlude: See how big those Chunks are" "1672": "Try to view the results in-game and step through the code" "1779": "Multiply ChunkDimInMeters by MetersToPixels" "1868": "Make DrawRectangleOutline" "2292": "View the results and figure out what's happening with the Chunk location information" "2427": "DrawRectangle does not take a Width and a Height" "2486": "...and the Y needs flipping" "2531": "We're getting there, but the Chunks are drawn too tiny" "2566": "Assess the size of the Chunks" "2588": "Try making a Chunk a quarter the size" "2650": "Set the Chunk size based on the size of a 256*256 block" "2696": "Make MetersToPixels something integral" "2825": "Assess where TileSideInMeters gets set and consider doing without it" "2900": "InitializeWorld without TileSideInMeters and TileDepthInMeters" "2980": "Pass the ChunkDimInMeters directly in" "3091": "Introduce TypicalFloorHeight" "3128": "Set ChunkDimInMeters based on the value of MetersToPixels" "3203": "Derive WorldChunkDimInMeters from GroundBuffer{Width,Height} and TypicalFloorHeight" "3277": "Set Tile{Side,Depth}InMeters" "3339": "Do CameraBounds a little differently" "3365": "Introduce SimBounds based on the CameraBounds" "3455": "View the results in-game" "3543": "Request a particular world_chunk to draw" "3825": "View the results in-game" "3910": "Find out why those chunks aren't getting produced until the Hero walks on them" "4021": "This was working totally perfectly" "4073": "Problem solved" "4121": "Q&A" "4167": "Q: What is Muratori syntax?" "4232": "Q: Will the random ground splats be based on some seed so that the ground buffer can be regenerated the same as it was after it gets evicted?" "4273": "Q: I'm sure it's been asked a bunch, but any tips for what language to start with and how to start?" "4376": "Someone found a Muratori 'for' statement in the wild" "4475": "Q: Why are you not passing World as an address when calling functions?" "4501": "Q: Are you going to implement Z-buffers and texture scaling?" "4568": "Q: Is there any other possibility for a Z-buffer?" "4751": "Couldn't you set the SimBounds expansion from the screen dimensions or CameraBoundsInMeters or something? Hope I'm understanding it correctly" "4830": "Q: Will you be implementing dynamic lighting or any deferred rendering for lots of real lights, etc?" "4965": "Q: Is there anyone you can suggest for a hardcore render guy?" "5020": "Closing remarks" --- name: "day087" title: "Seamless Ground Textures" markers: "108": "Take a look at the state of things, but actually address a typo" "166": "Weird stuff can happen when you're using memory directly" "451": "Get back to what we were doing, i.e. making seamless ground tiles" "567": "Blackboard: How to get seamless tiles in" "792": "Loop over tiles in a 3 * 3 grid" "925": "Make sure that the Center accurately reflects that we're in a different Chunk area" "1011": "Blackboard: Center considerations" "1032": "Change the meaning of Center" "1150": "View the results in-game and review the code" "1197": "Correct the computation" "1232": "See where we're at" "1279": "Take another look at it and see" "1309": "Owl of Shame is peeking at us right now because we forgot to use the new Center" "1351": "We are now seamless across X, but not Y" "1378": "Turn off the tufts and take a look at what we're doing differently with the Y" "1455": "Consider the problem and try flipping the Y and X to see which one is done major" "1504": "What is wrong with our Y-handling?" "1542": "Our edges are probably lining up in the wrong order" "1565": "Check and see if that's the case (in-game)" "1658": "Tuft it back up" "1722": "Give it a little bit of slop" "1765": "Force us into a case where we run out of tiles right away" "1860": "Fill in each EmptyBuffer by reusing old tiles" "1928": "Keep the Chunk that's furthest from the camera" "2101": "Introduce Real32Maximum" "2146": "Find whatever Buffer would be best to replace" "2259": "Compile and review the code" "2408": "Let's see, it looks like 16 GroundBuffers is too few" "2514": "Do the detail splats last" "2630": "What should we do in 15 minutes?" "2689": "Make the code-reloading tell us when the code is reloaded" "2843": "Test the new and improved live code editing" "2907": "Casey is a little concerned that we're drawing too much..." "2940": "Shuffle the code" "2986": "Count how many GroundBuffers fit on the screen" "3016": "Assess our current situation" "3086": "Q&A" "3124": "Are the randomly generated floor tiles being cached yet?" "3140": "Do you think having things in place like static cast to put more checks, e.g. int to pointer, is useful over standard C-style cast which just ignores all type-checking? Wouldn't a static cast have found that bug at the start of the stream?" "3329": "Do you think the clumpiness is actually due to splat distance from the centre of the chunks?" "3440": "Do you know why the trees are wiggling around sometimes?" "3543": "What is causing the lag?" "3672": "Are there still places where the background colour shows through the ground tiles?" "3759": "Is this Chunk code already prepared for adding holes to the ground?" "4021": "Could you make code that ensures a certain frame-rate but uses extra available time to generate the ground textures in the background, maybe generating a low-quality version first to avoid having no texture at all?" "4138": "Recap, a glimpse into the future and closing remarks" --- name: "day088" title: "Push Buffer Rendering" markers: "37": "Investigate possible bug in the collision detector" "182": "Pass TestP to SpeculativeCollide and also base MoverGroundPoint off TestP" "207": "Make a version of GetEntityGroundPoint that takes ForEntityP" "276": "Walk around in-game" "300": "Put the stairs back in and try colliding with them" "359": "Increase GroundBufferCount from 32 to 64" "422": "Think about sorting entities in a render list and scaling bitmaps" "528": "Look at the TODO list" "571": "Create handmade_render_group.h" "593": "Consider sorting and translating the coordinate systems" "653": "Take a look at how the buffering currently works" "682": "Pull out entity_visible_piece and entity_visible_piece_group into handmade_render_group.h" "743": "#include handmade_render_group.h and handmade_render_group.cpp in handmade.cpp" "770": "Expand the notion of the PieceGroup so that it tracks everything" "871": "Move the rendering outside" "935": "Now all the pieces are in one giant buffer, and we have no idea which one goes with which entity" "967": "Introduce render_basis" "1026": "Enable setting the render_basis after moving the entities around" "1216": "Set the DefaultBasis and point to it" "1308": "View the results in-game" "1395": "Move PieceGroup up and give it its own memory" "1480": "Change all of the draw calls to operate off the PieceGroup" "1579": "Check it out in-game" "1599": "The inversion and scaling is all still happening erroneously" "1639": "Look at what the Push functions are doing" "1685": "Try and regularise how the rendering works" "1780": "See how it looks in-game" "1816": "Investigate why the Bitmaps aren't being drawn in the correct places" "2100": "It's drawing the same Bitmap" "2121": "Moment of realisation: Rather than sending the whole loaded_bitmap down, we were using one on the stack" "2192": "Consider ways to pass the correct Bitmaps" "2233": "Send the whole Bitmap to ground_buffer" "2335": "See if that fixes our problem" "2380": "Get rid of that other DrawRectangle call" "2431": "Rename entity_visible_piece_group to render_group" "2477": "Consider how we want to extend the notion of render_group so that you can have multiple things pushed onto this render stack" "2516": "Consider linked list vs packed set" "2563": "Add PushBufferBase, PushBufferSize and MaxPushBufferSize to render_group" "2632": "Introduce AllocateRenderGroup in handmade_render_group.cpp" "2718": "#define PushSize macro" "2740": "Allocate MaxPushBufferSize and store it in PushBufferBase" "2755": "Initialise all of the fields of the render_group" "2776": "Call AllocateRenderGroup and set MaxPushBufferSize to 4MB" "2812": "Make the DefaultBasis get allocated and initialise it" "2841": "Store MetersToPixels rather than GameState and pass it to AllocateRenderGroup" "2886": "Initialise MaxPushBufferSize and PushBufferSize" "2916": "Now we've got a problem: When we do PushPiece we can't get one because we don't know where that piece is anymore" "2924": "Attend to the other issues" "3011": "Straighten out the PushBuffer situation" "3247": "See if it works in-game" "3286": "Blackboard: PieceGroup" "3383": "Blackboard: Compression Oriented Programming" "3417": "Blackboard: render_group" "3499": "Q&A" "3556": "Will things like filters end up in the render_group?" "3655": "How long will the renderer take?" "3749": "Could you give us examples of what some of the simpler things will be in the render_group?" "3767": "Are there any static code analysis tools for C / Visual Studio that will help pick up bugs like unused variables, etc?" "3878": "So are you planning on abstracting away the renderer as a layer, similar to how we separated the platform from the game code, so that the various renderers will be operating on the same data structures?" "3948": "If you were going to write an algorithm to generate Sudoku puzzles, how would it work?" "3963": "Unused variables are a warning on my compiler. Did you turn that warning off? I use an allow local macro when I want it to ignore the variable" "4016": "Would it make sense for the render_group to contain render groups itself?" "4064": "I meant whether you plan for the data describing what needs to be rendered to be in a format such that it's suitable for both software and hardware rendering" "4125": "Will our hero always be taller than the treetops?" "4198": "We've finished early... or have we?" "4219": "Are we keeping the 5PM schedule?" "4326": "Wrap it up with a recap and closing remarks" --- name: "day089" title: "Renderer Push Buffer Entry Types" markers: "94": "Take a look at what happened on Friday" "236": "Blackboard: Rendering" "325": "Blackboard: Reasons for using a PushBuffer" "384": "Blackboard: History of game architecture built around the renderer" "421": "Blackboard: Modern day luxuries and trade-offs" "483": "Blackboard: Output Target" "584": "Blackboard: Balanced approach to optimisation" "665": "Blackboard: PushBuffer benefits" "781": "Blackboard: Considerations for supporting multiple targets" "856": "Blackboard: Our first target: Software 'GPU-esque Rendering'" "1020": "Blackboard: Two ways of looking at a render working: 1) Explicit Surface Rasteriser" "1102": "Blackboard: 2) Implicit Surface Rasteriser" "1179": "Blackboard: Reasons to use the Implicit method" "1196": "Blackboard: Something like how our renderer will look" "1247": "Blackboard: SIMD instruction sets" "1361": "Blackboard: Overview of what we're building" "1502": "Start pulling the Draw functions out" "1525": "Mini-rant on devenv" "1568": "Take a look at where we're at" "1587": "Start playing with the code" "1613": "Vaporise PieceCount" "1626": "Look at adding multiple types of commands in there, starting by renaming entity_visible_piece to render_group_entry" "1689": "Pull RenderGroupToOutput out into handmade_render_group.cpp" "1838": "Compression Oriented Programming" "1941": "Consider operating on groups of entities" "2058": "Setup cases for handling different types of Entry" "2127": "Introduce InvalidDefaultCase" "2165": "Increment BaseAddress depending on the Entry->Type" "2211": "Write those cases" "2273": "Create the corresponding render_entries" "2399": "Describe 'compact discriminated union'" "2543": "Review our new ability" "2637": "Ridiculous Trick: Prepend the type_name with RenderGroupEntryType to make the Identifier, and #define PushRenderElement macro for a type-safe way of correctly setting the type field in one step" "2752": "Pass the Type to PushRenderElement" "2814": "Compile and clean up" "2865": "Check all is still well in-game" "2878": "Create a bitmap type" "2963": "Call the PushPiece function for the bitmap" "2999": "Hit an assertion because the Entry->Bitmap is not filled in" "3010": "Make sure we push a rectangle on when we call the bitmap type" "3070": "Check that all is still okay in-game" "3106": "Compress the code down into something more usable" "3270": "Bake the offsets in to PushRect" "3504": "Pull out the EntityBasis computation" "3598": "Clean up" "3692": "See where we're at" "3698": "Q&A" "3795": "Warning! There may be lots of prestream questions today" "3837": "When you meet a bug in the game and are able to recreate it, will you get a bug line in the programming, or how does it work?" "3876": "Is it worth aligning render_entries?" "3951": "What is Mantle?" "3968": "Any recommendations of some reading about GPUs, rendering, rasterisation, except for a Google search?" "4143": "Why use pointers over references?" "4231": "About Mantle, were you aware AMD dropped development for it and put a lot of that manpower into helping push Vulkan?" "4283": "The PushBuffer is an abstraction layer relying on memory for communication instead of a bunch of functions, if I understand correctly. Is that how you prefer API design in general?" "4383": "We are done here" --- name: "day090" title: "Bases Part I" markers: "105": "Take a look at where we're at" "125": "Make lowercase the accessors for the vectors" "380": "Casey doesn't have enough Emacs-fu to bust that out" "540": "Find out if it worked" "570": "Resume work on RenderGroup structure, implementing Clear" "647": "Make DrawRectangle take A which defaults to 1.0f" "681": "Make the Clear call take its values from render_entry_clear" "717": "Make Clear function" "761": "Change R, G, B, A in render_entry_clear to Color" "774": "Cleanup" "787": "Review progress and glimpse into the future" "819": "Ensure that everything's working in-game" "840": "Turn off the GroundBuffers and the 'conditional expression is constant' warning" "905": "Consider what we haven't moved over into the renderer (Outline calls) and note that FillGroundChunk calls the bitmap routines directly, rather than the renderer" "960": "Put PushRectOutline and DrawRectangleOutline into the renderer as more specific concepts" "1184": "Run, crash and update PushRectOutline" "1233": "View the results in-game and add back in the Space lines" "1297": "Make FillGroundChunk go through the renderer" "1379": "Introduce GroundRenderGroup" "1416": "Let FillGroundChunk use the RenderGroup" "1544": "Put in a Clear to verify that things are actually happening" "1586": "Change DrawBitmap to PushBitmap and make it use that renderer syntax" "1612": "Consider supporting pixel positioning" "1714": "View the splatting in-game" "1732": "Cheese the pixel positioning by replacing MetersToPixels with 1.0f" "1774": "Showcase the live code editing by scaling the placement of the ground elements" "1865": "Blackboard: Introduce the concept of coordinate systems and bases" "1975": "Blackboard: How we measure, using the dot product" "2064": "Blackboard: Axes tend to have two properties: 1) Unit length" "2163": "Blackboard: ...and 2) Orthogonal" "2193": "Blackboard: Linear independence" "2293": "Blackboard: Forget about linear independence" "2352": "Blackboard: Orthogonality" "2568": "Blackboard: Linear independence" "2680": "Blackboard: There's linear algebra afoot here" "2694": "Blackboard: See why these are important properties" "2726": "Blackboard: 3D coordinates" "2834": "Blackboard: Basis vectors" "3011": "Blackboard: Basis changes: 'MetersToPixels' and 'negate y'" "3330": "Blackboard: Pretend we had some third universal basis" "3449": "Blackboard: How does Casey move a point from world space into screen space?" "3677": "Blackboard: Preview what we're going to do" "3788": "Q&A" "3821": "Would you represent the origin of coordinate systems in a universal coordinate system?" "3985": "A few streams ago you said you'd prefer to call functions through a macro and then forgot to explain why" "4026": "Why is the familiar moving left to right, or did I miss something?" "4052": "Why are computer coordinates upside-down?" "4350": "How important is it to know how to make a game engine vs simply using one? And if you were to use DirectX libraries, how much would the code differ?" "4866": "Wrap it up with a brief recap and a glimpse into the future" --- name: "day091" title: "Bases Part II" markers: "54": "Blackboard: Clarify linear independence" "138": "Blackboard: Bases" "376": "Blackboard: What does it mean to say we have an origin?" "466": "Blackboard: Consider describing origins and basis vectors in terms of other origins and basis vectors" "712": "Blackboard: Why do I care about this at all?" "732": "Blackboard: Rotation and scaling" "854": "Blackboard: Example rotation" "909": "Blackboard: Example scaling" "963": "Blackboard: What does that look like in code?" "1188": "Blackboard: This is what we'd like to introduce into our renderer now" "1220": "Blackboard: How do we define the X and the Y axis? (Unit circle)" "1481": "Blackboard: A handy optimisation thanks to being in 2D" "1699": "Blackboard: You can also directly plug and chug this" "1741": "Blackboard: Perp operator" "1869": "Blackboard: All we have to do" "1946": "Go into the code and create one of these rotating doodads" "2178": "Run the game to discover that our code is hosed" "2241": "See what our InvalidDefaultCase says" "2278": "Let it hit the InvalidDefaultCase sooner" "2314": "Take a look at the RenderGroup buffer" "2392": "Step through the code with an eye on PushBufferBase" "2441": "Moment of realisation: render_entry_coordinate_system was missing its Header" "2517": "Put our coordinate_system back in there and run again until it hits the InvalidDefaultCase" "2542": "Put in a case for our coordinate_system" "2632": "Define the coordinate_system to be something that's visible" "2772": "View the results in-game and apply transforms" "2867": "Edit this coordinate system live" "2934": "Insert some points that are encoded in that axis" "3099": "Check it out in-game (...or not)" "3146": "Moment of realisation: It'd be nice if Casey actually used PIndex" "3158": "Try viewing again" "3184": "Step through the code watching the coordinates of the Points" "3207": "Reduce the number of Points and view it in-game" "3259": "Play with those axes" "3326": "Do we have pie?" "3368": "Continue playing" "3447": "Q&A" "3566": "Do you usually worry a lot about naming schemes? You always seem to choose a good enough name and move on" "3588": "Is that the variable?" "3610": "How can you draw so fast? Do you use a draw pad and pen?" "3623": "I only partly followed, but it seemed fairly easy to get the basic rotation up and running. I'm wondering how much more work it will be to start rendering textures by sampling them across the plane" "3681": "Is it possible to do realloc with memory_arena?" "3737": "Are parametrics and polar functions going to be used later on?" "3786": "Will subpixel positioning and anti-aliasing be part of the software renderer in the exploration phase?" "3852": "Make the size proportional as well" "3920": "Go nuts with that" "3955": "Time-dependent colour" "4031": "Needs more dots" "4060": "Call it done for the day, with special mention made of that weird pulsating thing and a glimpse into the future" --- name: "day092" title: "Filling Rotated and Scaled Rectangles" markers: "23": "Recap of people egging Casey on to do some weird sine-cosine-theta stuff" "96": "Blackboard: Introduce effects" "279": "Blackboard: How do we do this rotation and scaling?" "329": "Run the game" "351": "Clip away all this ridiculousness" "392": "Look at the coordinate system" "433": "Blackboard: We need to know which pixels will be included as a result of rotating a rectangle" "515": "Blackboard: How the collision detection system may be applicable to pixel filling" "591": "Blackboard: Ignoring rotation and scaling for now" "754": "Blackboard: Iterating over the pixels" "824": "Look at the DrawRectangle routine" "862": "Write a function, DrawRectangleSlowly, that does DrawRectangle in the least efficient way possible" "1003": "Draw a rectangle that's at the origin of the CoordinateSystem" "1091": "See the results in-game" "1103": "Stop it rotating for the moment" "1121": "Check the scaling of the axes" "1194": "DrawRectangle after the fact in a different Color" "1231": "Note that the rectangle is not properly clipping to its max bounds, and rectify this" "1271": "Moment of realisation: We were adding Entry->Origin twice" "1287": "We're filling correctly but inefficiently" "1318": "Consider restricting the area that DrawRectangleSlowly marches over" "1341": "Blackboard: How does that help us do our rotation and scaling?" "1405": "Blackboard: Can't we just test against four corners of our rectangle?" "1475": "Blackboard: How we could have done that without Casey's help" "1735": "Implement one of these edge tests" "1790": "Make DrawRectangleSlowly take all of the coordinate system information" "1857": "Make DrawRectangleSlowly do the edge tests using the dot product" "1938": "Blackboard: Rephrase these edge tests" "1977": "Turn the test around" "2043": "Notice that, because we're not doing the dot product, the sign doesn't flip" "2073": "Make greater-than be our standard" "2103": "Blackboard: Think of the surface normals pointing outwards" "2120": "Change all of those edge functions to be negative" "2170": "Get the dot product in there" "2203": "Blackboard: What are the vectors of those perpendiculars?" "2249": "Implement those vectors" "2320": "Now we're doing the full test, see how it looks in-game" "2339": "Consider changing the edge tests to use the edges of the rotating coordinate system" "2360": "Blackboard: How to use those edges" "2382": "Get rid of vMin and vMax in readiness to use those edges" "2397": "Blackboard: Our tests" "2435": "Implement those tests" "2531": "Compile and view the results in-game" "2568": "Change the scale over time" "2584": "Blackboard: Optimising these tests" "2652": "Implement optimised exclusion tests" "3020": "Fix a couple of things, but not before filling everywhere in the bounding region" "3058": "Check the code" "3100": "Find our typo and restore our buffer pre-step" "3135": "Re-enable our edge test and consider further work" "3188": "Q&A" "3234": "What are your computer specs?" "3314": "Is it weird that I got really excited once the rotated fill got faster?" "3366": "Would skewing the axes still work?" "3457": "Implement a proper perpendicular" "3578": "Blackboard: How we want the Perp to work" "3626": "Make that Perp work" "3673": "Is downscaling bitmaps correctly slower than upscaling (more colour points to blend)?" "3705": "Blackboard: Downsampling and upsampling bitmaps" "3845": "Blackboard: Mipmaps" "3933": "Eventually, will you implement anti-aliasing into the rendering of the rectangle, or is that too much for the CPU?" "3967": "Blackboard: Texture sampling handles anti-aliasing for the alpha'd bitmaps" "4077": "Check out our hilarious little shape and review our progress" "4177": "Historically, did we ever do anti-aliasing with CPU rendering?" "4312": "Postpone anything more until tomorrow, with a potential plan of action" --- name: "day093" title: "Textured Quadrilaterals" markers: "44": "Recap and push forwards" "166": "Expand the notion of CoordinateSystem to allow passing a Texture" "276": "Review how our Edge equations work" "365": "Blackboard: Working through a problem from first principals" "446": "Blackboard: Texture mapping" "562": "Blackboard: Standard nomenclature" "736": "Blackboard: How do we produce some u and v values that tell us where in the texture we are at any given time?" "906": "Blackboard: Take a look at what's going to happen here" "1058": "Blackboard: Does this equation give us what we want?" "1170": "Blackboard: Looking at the problem from another angle" "1281": "Blackboard: The equation we'd like to implement" "1336": "Implement that equation, starting by distributing the negative in the Edge tests" "1369": "Introduce d" "1396": "Compute u and v" "1499": "Lookup the u and v inside the Texture" "1668": "Compile and see what's happening in-game" "1675": "Assert that X and Y are >=0 and < Texture dimensions" "1700": "Do that lookup of the u and v" "1776": "Check out our texture mapping in-game" "1824": "Add in the Alpha" "1916": "See the alpha composite happening in-game" "1943": "Slow down the fanciness" "1973": "Hit an assertion and postpone clamping U and V until we're doing SIMD" "2022": "Resume slowing down that fanciness" "2064": "Notice the flickering and mention subpixel accuracy" "2126": "Make the Tree bigger and put it in the centre of the screen" "2177": "Move the Tree horizontally and keep its angle constant" "2259": "Observe the nature of rendering without subpixel accuracy" "2336": "Blackboard: The number of pixels and texels isn't dividing out evenly" "2496": "Start tackling these problems" "2517": "Notice that DrawRectangleSlowly is ignoring the floating point accuracy that was passed to it" "2608": "Why do we still look like that, though?" "2638": "Blackboard: Doing a better job of figuring out where we are in the texture map" "2838": "Linearly blend (Lerp) the colours" "2935": "Pretend our Texture is smaller than it actually is" "2979": "Blend these guys together, but not before lofting out the Color values" "3181": "Manufacture a v4 for Lerping between two Lerps and ones for doing scalar multiplications" "3287": "View our properly blurry rendering in-game" "3415": "Switch between the old and new ways, for comparison" "3553": "Q&A, after getting the tree spinning again" "3653": "Will the Wall trees be subpixel accurate now?" "3697": "the top of the tree seems to be cut short" "3830": "Is tree spinning going to be in the DLC?" "3854": "does it rotate with subpixel accuracy?" "3918": "What's the most major / fundamental thing left to do on the renderer?" "3969": "TODO(casey): SSE clamping" "3987": "Q: how would you do smooth subpixel rendering for something like pixel art graphics, that doesn't blur but still moves smoothly" "4019": "Blackboard: Doing smooth subpixel rendering for pixel art graphics" "4329": "couldn't you use the rounding +0.5 and truncate to not sample outside the edges of the texture?" "4411": "why are you still adding 0.5f to tX and tY?" "4428": "Is it any faster if you just test the domain of (u,v) instead of testing edges?" "4557": "Is rendering on the cpu different in comparison to rendering on a gpu codewise?" "4639": "Are there performance benefits for using a quad as primitive over triangles in a software renderer like this?" "4739": "why do the edges of the tree look like they are feathered?" "4794": "Will the different renderers be in the platform layer?" "4819": "I saw a great video on youtube called 'Computer Color is Broken' from minutephysics that talks about how blending colours is usually incorrectly done. Without relying on 3rd party libraries, you have an opportunity to do it correctly." "4941": "Remember when you introduced RenderGroup the other week? Is this subpixel rendering lerp one of the things that will go in the RenderGroup?" "4996": "Call it for today with a recap and a glimpse into the future" --- name: "day094" title: "Converting sRGB to Light-linear Space" markers: "67": "Recap last week's work on the renderer" "98": "Won Chun's request: Correct gamma correction" "248": "Chart: Gamma curve of Casey's monitor" "392": "Blackboard: Gamma" "518": "Blackboard: Why does Won care?" "741": "Blackboard: We'd need to undo or, rather, account for the effects of the monitor's gamma curve" "936": "Blackboard: How do we do it in a software rasteriser?" "967": "Internet: sRGB definition" "1056": "Internet: Gamma correction" "1103": "Internet: Filmic Games: 'Linear-Space Lighting (i.e. Gamma)' by John Hable" "1215": "Blackboard: What the gamma curve is generally expected to be" "1336": "Blackboard: Computing that gamma curve" "1412": "Blackboard: Envisioning the Framebuffer pipeline" "1564": "Blackboard: Caring about bandwidth" "1714": "Internet: 'Uncharted 2: HDR Lighting' slides by John Hable" "1746": "Blackboard: We want to mimic what the monitor is doing" "1805": "Implement this sRGB approximation" "2173": "Create the SRGB255ToLinear1 and Linear1ToSRGB255 functions" "2349": "Compile, take a look in-game and go through that with a more fine toothcomb" "2649": "Set a breakpoint and step through the code" "2870": "Moment of realisation: Linear1ToSRGB255 was multiplying by 255 before square-rooting" "2897": "Enjoy our tree in all its gamma corrected glory" "3061": "Start using the Color value to tint our texture maps" "3103": "Blackboard: Tinting" "3131": "Implement tinting" "3187": "Live tinting" "3337": "Premultiply the alpha properly" "3428": "Blackboard: Premultiplied alpha" "3549": "Q&A" "3577": "What would be the visual artifact of using 2 instead of 2.2 for the gamma?" "3688": "Q: Also need to do additive color tinting for full expressiveness" "3731": "I have a CS background but am 2 months behind on coding this. It is much easier to follow when I'm not trying to type myself. How detrimental would it be to my understanding to watch and just stop coding if I get too far behind? Sometimes when you're moving things around, I have to watch that bit 2-3 times" "3798": "Would it be worth only using gamma correction on texels that have alpha not equal to 0 or 1?" "3837": "Could we do our maths in sRGB space?" "3862": "Blackboard: Lerp in sRGB space" "4109": "Blackboard: This Q&A just turned into an exploration" "4240": "When are you going to start implementing OpenGL for the rendering?" "4260": "Wouldn't be the 10_10_10_2 format (which is also available in hardware) be sufficient to avoid banding?" "4325": "Then what is the point of using 2.2 at all? Why not just use 2 for the gamma?" "4378": "By repeatedly converting between linear and our approximated gamma space when doing each blend, are we compounding our errors?" "4487": "Do all monitors use the same 2.2 curve?" "4583": "Is raising the color value to 2 instead of 2.2 really going to save that much processing power?" "4691": "I got stuck implementing a Bitshift + PRNG in your engine, thanks for showing a code comment about 'Wang Hashing' earlier which was just what I needed" "4726": "Wrap it up for today" --- name: "day095" title: "Gamma-correct Premultiplied Alpha" markers: "80": "Recap yesterday's work" "160": "When do you premultiply the alpha?" "298": "This bilinear blend might want to be in premultiplied alpha" "405": "Inspect the change in appearance of the tree" "524": "See if we're storing the Texels premultiplied (we are)" "564": "We are not doing the most correct thing" "607": "Do not premultiply the alpha at all" "651": "Multiply the alpha just before the blend" "700": "On the output our Color values want to be not premultiplied" "752": "What happens on repeated blends?" "855": "Blackboard: When our values aren't stored premultipled" "1004": "Blackboard: Projecting back to sRGB" "1087": "Project the Color values back to sRGB space before storing them" "1198": "Add struct containing rgb and a" "1260": "Check it out in-game and consider making all our routines gamma-aware" "1363": "Convert DrawRectangle to handle gamma correctly" "1730": "Try and check it out in-game" "1792": "Think about making our software renderer run relatively quickly" "2007": "Take another look at DrawRectangleSlowly and premultiply the Color upfront" "2219": "Do a little bit of cleanup" "2318": "Blackboard: How the Header worked" "2365": "Do two sequential pushes of the Header and Data" "2486": "Step through that and make sure it works" "2572": "Increment the BaseAddress properly and check it out in-game" "2698": "Consider pulling out the Draw functions into a seperate file" "2796": "Internet: MSDN: 'optimize'" "2873": "Try using #pragma optimize" "2997": "Internet: MSDN: 'Optimization Best Practices'" "3052": "Try wrapping everything else in a #pragma optimize off" "3265": "Q&A" "3339": "Why can't you compile OpenGL code to C to make a software renderer?" "3360": "Is it useful to be able to debug with optimizations on? Do you think you might be able to show how to do that at some point?" "3400": "Demonstrate /Zo compiler flag" "3698": "GLSL" "3948": "Should the Load Bitmap function also be optimized after making changes today to do premultiply?" "3983": "How would something like a dynamic array in this memory system work? Something that is persistent across frames, but able to change size. Holes are not possible in the memory arenas right now?" "4084": "Couldn't a compiler translate the OpenGL commands to C commands and wrap them in a loop which iterates over the pixels?" "4234": "Could you explain us how you free all the memory stack when closing the game?" "4256": "I have a hard time understanding why sRGB conversions are required for the alpha channel at all, and why your intitial code wasn't correct. The alpha channel is being used to just represent a proportion of photons from one source and a proportion of photons from another source(s). Wouldn't that be outside of the purview of color curves because it doesn't technically have anything to do with brightness?" "4299": "You seem to be manipulating colors on a low level. How are you pushing pixels? Sorry, I am kinda new" "4347": "Any reason why you write 'Texel.a + Dest.a - Texel.a*Dest.a' instead of just 'InvRSA*Dest.a + Texel.a', which would match the RGB channels?" "4374": "Rearrange these calculations and keep on keeping on condensing" "4554": "Wasn't the alpha channel authored with nonlinear colors?" "4592": "Call it a day" --- name: "day096" title: "Introduction to Lighting" markers: "119": "Consider addressing the problem of speed and optimisation in order to ease debugging" "242": "Two possible directions: Renderer Features..." "311": "...or Lighting Control" "386": "Suggest turning off everything except for the tree" "449": "Review what's going on in handmade_render_group" "498": "Turn off DrawBitmap, change the hideous pink background and switch to compile in debug mode" "603": "Stop the tree rotating" "650": "Blackboard: 'Lighting is the sound of graphics' - Doug Church" "833": "Blackboard: Dynamic lighting" "932": "Blackboard: Lighting is fundamentally a 'directional' effect" "1062": "Blackboard: Wavelengths" "1284": "Blackboard: RGB colour receptors" "1469": "Blackboard: Don't talk to animals with more color wavelength sensors than you" "1511": "Blackboard: We see the aggregate effect of all of the light sources scattering light towards our eye" "1604": "Blackboard: Subsurface scattering" "1692": "Blackboard: What makes surfaces look different?" "1957": "Blackboard: What sorts of surfaces do we tend to actually want?" "2110": "Blackboard: Approximations" "2309": "Blackboard: 'Light probes' or Indirect light sampling" "2662": "Blackboard: What do we do in 2D?" "2782": "Blackboard: Normal maps" "2899": "Blackboard: We don't know what the light field is" "3199": "Q&A" "3258": "So is this why animation studios like Pixar have super computers for the rendering?" "3331": "What about shadows?" "3369": "Blackboard: Shadow maps" "3481": "I was looking for a build design doc to follow if you have one?" "3508": "Do we also plan on having a day/night cycle and dynamic shadows, where they stretch and fade depending on the position of the sun?" "3576": "Light feathering, e.g. in a window or tree" "3601": "Sort of on topic would you consider doing a true 3D lighting and or ray tracing discussion/lessons at some time?" "3624": "How do you account for infinite reflections if there is a mirror that reflects light into a mirror that reflects light back at the first mirror?" "3708": "Blackboard: Volumetric scattering" "3783": "Could you repeat that?" "3792": "Q: Heated debates of why we need to go through the trouble you're going through. #JustUseUnity Many newcomers" "3986": "Is 2D worth going for when it becomes more complex than 3D?" "4162": "Is your 'lighting cube' idea the same thing as cubemaps?" "4244": "How to feather light through a window or tree" "4267": "Blackboard: Translucence" "4456": "Why don't we just have the lighting feigned on the sprites?" "4516": "How about the second framebuffer you mentioned with light sources having precomputed distance falloff, plus graphics objects having another channel similar to alpha that indicates reflectivity? That would be fast and maybe good enough for a 2D game" "4551": "Blackboard: Illumination is constant along a line" "4714": "Due to the complexity of lighting, are system resources a major factor/consideration in shading engines?" "4750": "If you use a 2D lighting buffer, will you need to generate a G-buffer or Z-buffer as well first?" "4787": "What about bleeding effects?" "4795": "Is this going to work with software rendering or will it be too computationally expensive?" "4837": "You mentioned computing values for a single source receiving light from multiple sources. How would we in essence do this computation? I'm assuming it's based off of neighbouring pixel values. I'm having a hard time formulating an approach" "4929": "Wouldn't it (in most cases) be smarter to use an existing graphic / render engine and just focus on coding the game itself / gameplay?" "5103": "What is the ambient occlusion and why my video card get late to run games with ambient occlusion? Like really lose FPS" "5129": "Blackboard: Ambient occlusion" "5507": "Do you prefer cake or muffins?" "5519": "Do you have any plans to implement sprite opacity and, if so, could it be taken into consideration with the light map calculation, i.e. less opaque objects block less light?" "5560": "Are there any books or resources you would recommend on lighting or game engine creation in general?" "5631": "So game design documentation, like a roadmap for the game?" "5667": "Wouldn't a game in pitch darkness have the easiest lighting system to code?" "5719": "Can you go back in time and start this series 15 years ago?" "5752": "If you did choose cake, would it be a cheese or mud cake?" "5765": "What I mean is sort of more like how to make beams of light pass through a rendered object" "5784": "Blackboard: God rays" "6108": "Don't you cast rays from the eye and not the sun to reduce calculations, and then see if the rays cast from the eye hit the sun?" "6206": "Can you use a 3D overlay to pretend, say, a slice of a 3D environment. For example, the platform you are on being z, and then x is across, y up and down. So you can have a light source at x 33, y 50, z 1. So all objects less than x 33 would be shadowed to the right, objects greater than would be shadowed to the left, greater than y 50 would be brighter to the front and less would be shadowed to the back... I don't know if this is making sense, but would it be possible?" "6253": "In early episodes you worked on having multiple z levels. Wouldn't this mean you would need to render walls in 3D, thus introducing some 3D into the rendering and lighting calculations?" "6282": "How often do you stream Game Development?" "6312": "What is your background that led to where you are? Is education important or interest more important?" "6326": "Will this lighting system work for blind people?" "6349": "Do you think we'll be able to do all this in real time or will we have to pre-bake some of the lighting information when generating the map?" "6371": "Couldn't you just make a 3D game and then flatten it with a rolling pin?" "6389": "How often is real time radiosity used in games? Is it easy, and do you guys use it? Why or why not? Any hints?" "6486": "I saw a game that uses normal maps on sprites" "6519": "Isn't lights falloff inverse square? As you move farther from the source each ray is further from its neighbors" "6535": "Blackboard: Inverse square law" "6696": "Would you consider voxelizing the scene like Little Big Planet 2 does?" "6766": "Had to log in so hopefully this isn't too late. Wouldn't there be falloff with a point source when integrating across the surface, since the rays spread out away from the source?" "6873": "Why is it easier to represent light as photons and not particles in 3D programs?" "6908": "Rendering light in environments and events approaching the speed of light. How to do it?" "6924": "PBR lightning? Quick run down on how it works?" "6941": "We have come to the end" --- name: "day097" title: "Adding Normal Maps to the Pipeline" markers: "137": "Recap yesterday and plan for today" "175": "Blackboard: Normal maps" "328": "Blackboard: The importance of Normal" "414": "Blackboard: What we need in order to compute lighting based on this Normal" "507": "Blackboard: Where the Normal map fits into the equation" "731": "Blackboard: Description of the surface" "872": "Blackboard: Description of the light" "1018": "Blackboard: Casey's proposal" "1312": "Blackboard: Blurring based on the surface description" "1528": "Introduce the concept of a NormalMap" "1614": "Blackboard: Normals have to be Normal" "1761": "Introduce Unpack4x8 and unpack the Texels" "1880": "Similarly unpack the Normals" "1936": "Blackboard: We often bake the description of the surface into the Normal map" "1991": "Lerp the Normals" "2035": "Introduce environment_map" "2242": "Set tEnvMap from Normal.Z" "2342": "Blackboard: We might want to switch nearer to 0.25" "2385": "Setup the environment_map lookups" "2656": "Create ScreenSpaceUV" "2770": "Pass that ScreenSpaceUV to SampleEnvironmentMap" "2810": "Check if there is a NormalMap" "2833": "Pre-light the Texel" "2873": "We haven't talked too much about how you compute lighting equations, per se" "2912": "Take SampleEnvironmentMap and return the Normal for now" "3079": "Plumbing" "3214": "Check it out in-game and generate a NormalMap to play with" "3288": "Blackboard: The NormalMap that we're going to create" "3321": "Implement MakeSphereNormalMap" "3498": "Blackboard: Think this through a little more" "3564": "Throw in a Normal.z calculation for now and finish MakeSphereNormalMap" "3763": "Add Normalize to handmade_math.h" "3829": "Compile and see it in-game" "3858": "Q&A" "3902": "Your 2D art already seems to have some shading. Will that just represent ambient lighting when mixed with this dynamic lighting you're trying to do?" "3957": "In MakeSphereNormalMap, should 'Y < Bitmap->Width;' be 'Y < Bitmap->Height;'?" "3975": "How far do you think you can increase the capabilities of an engine like this before you start to suffer from performance constraints due to using only the CPU (vs GPU)?" "4077": "Don't you need to SRBGToLinear1 the normals or use the normals instead of the texel in the lerp?" "4184": "Normal.z = Sqrt(1.0f - Normal.x*Normal.x - Normal.y*Normal.y);" "4325": "Is your lighting lookup a similar technique to MatCaps used in other software?" "4340": "What benefits do you see from using the extra time it takes to create your own engine from scratch? Is it worth it in your opinion?" "4355": "The catch is that it's going to take the Sqrt of a negative number if you're outside the sphere" "4443": "We have come to the end of the questions" --- name: "day098" title: "Normal Map Code Cleanup" markers: "103": "Off we go with a bit of a recap" "231": "Talk about MakeSphereNormalMap and GPU vs CPU renderer" "294": "Make TreeNormal for MakeSphereNormalMap to use" "443": "Get the game running, look at the unpacking of the NormalMap and change the way that it's packed" "545": "Blackboard: Consider the hacky nature of the problem" "698": "Blackboard: The Ground's normals" "843": "Handle front-facing bitmaps for now, starting by introducing UnscaleAndBiasNormal" "981": "Check it out in-game and look back through the code" "1048": "Draw just the Normal and force Texel.a to be 1.0f" "1097": "Step through the NormalMap code" "1154": "Moment of realisation: We were still sampling out of the Texture" "1183": "Continue stepping through the code" "1303": "Moment of realisation: Usually you want to move to the next Pixel when you write one" "1333": "Quickly check the maths" "1372": "Blackboard: Nz should be Pythagorean theorem solved" "1479": "Calculate Nz" "1511": "Set the Normal and look at how the Pixels are packed" "1588": "Step through the code" "1612": "Blackboard: Dealing with the area outside the sphere" "1655": "Introduce RootTerm" "1745": "Check the values of the Normal" "1795": "Take a look at it in-game and find some erroneously negative values" "1900": "Owl of Shame Moment: Yesterday's code was awful" "1934": "View the correct NormalMap" "1968": "Recalculate Texel.rgb such that it is within the valid range of colours" "2063": "Turn off the NormalMap and consider using something more defined than the tree bitmap" "2095": "Temporarily draw TreeNormal as if it was a texture map" "2162": "Set the Pitch correctly and introduce BilinearSample function" "2347": "Check it out in-game and switch to the path in which the NormalMap modulates the texture" "2389": "Light the texture with the NormalMap" "2482": "Take a look at it in-game" "2508": "Tackle the environment_map stuff" "2724": "Blackboard: Picking from the environment map" "2871": "Nullify the Middle sample and make SampleEnvironmentMap produce values we can use" "3333": "Look forward to next week" "3388": "Q&A" "3462": "Recap today's cleaning up" "3501": "When you lerp two normals, you probably won't get a normalised vector. There are a few things you can do about that. Would you briefly comment on your thoughts about this?" "3701": "Q: how are we going to sample lights when calculating the pixel values for each sprite? Will there be a list of all the lights? Or will that be a parameter of some sort?" "3730": "What ever happened to your almond milk?" "3747": "Will Yangtian be making normal maps for the art now too?" "3771": "Will you cover more advanced BRDFs? Or just simple phong-like lighting equations?" "3888": "What if I don't want my game to be just 'normal'? Are there any other kinds of maps I can use to make my game more unique?" "3985": "Q: Some games use a 'bump-map' in addition or instead of a normal map. What is the difference between these and what are the advantages or disadvantages?" "4032": "Blackboard: Bump Map vs Normal Map" "4357": "gasto5 Q; Will the effect end up like a bump map effect?" "4374": "Could we do reflections by using our frame buffer as an environment map when drawing the bitmap?" "4397": "If you imagine the surface as an implicit function f(x,y,z) = 0, it's the gradient of THAT function. Which is the same as the cross product of the two surface tangents." "4484": "We have come to the end of the questions" --- name: "day099" title: "Test Enviroment Maps" markers: "147": "Blackboard: Make some light fields" "467": "Create test environment_maps" "598": "Initialise environment_maps" "711": "Setup the LOD (Level of Detail) picker" "815": "Pass the maps to CoordinateSystem" "867": "Compile and clean up" "938": "Run and get nothing in particular happening" "966": "Draw the EnvMaps" "1376": "Prepare the EnvMaps" "1566": "Check it out in-game" "1602": "Note the bugs and extol the virtues of structured art" "1740": "Look at fixing the sampling of the Bottom map" "1889": "Prioritise straightening out the coordinate systems" "1945": "Fix that sampling of the Bottom map" "2103": "Math is right even when you're wrong" "2116": "Implement a checkerboard pattern for the EnvMaps" "2403": "Implement ToV4" "2455": "Continue with the checkerboard routine" "2632": "View the checkerboard in-game" "2696": "Introduce TestDiffuse and TestNormal" "2845": "Take a look in-game and change the colour of the background" "2888": "Take a look at what we were doing in SampleEnvironmentMap" "2920": "Use the Normal to look up into the environment_map" "2965": "View it in-game" "3035": "Q&A" "3090": "In the MoveEntity function you have two variables that are never used: NewPlayerP and OldPlayerP. Will you delete them for me?" "3148": "Would this scheme let you have a pool of water reflect a starry sky?" "3205": "Blackboard: Reflecting a starry sky in a pool of water" "3375": "if you wanted to see the lighting distort according to the spherical shape of the normal map, would that just be part of fixing the math in the section where you sample from the env map, or is there more to it?" "3412": "What are the benefits to having 3 top-middle-bottom EnvMaps vs just using 1 EnvMap for the whole thing?" "3453": "Blackboard: Preview of how the EnvMaps will work" "3588": "I'm not sure I understand the point of the bottom map. Will the ground be contributing lighting to objects above the ground?" "3684": "Will you need a set of EnvMaps for each 'level' in Z?" "3786": "Any plans for doing over-brightening on the lights? (Or even HDR?)" "3877": "Could you contain all lighting information in a 5 byte bitmap: 0-255 Absorbance/reflectance scale for RGB, Alpha, and scattering? I want to try it but I feel really hesitant because you warned against non-32 bit aligned structs" "3950": "Even just using a 0-2 lighting range gets good results" "3976": "Do you plan on 'camera level' lighting effects such as 'stun grenade' for lack of a better example?" "4015": "If you can do without alpha, could you possibly use RGBE, where the E is the exponent for all channels?" "4111": "Is saturation very hard to overlay?" "4140": "Introduce render_entry_saturation" "4379": "Blackboard: Saturation" "4438": "Calculate the Avg and Delta" "4563": "Check it out in-game and then drive it off an animated parameter" "4686": "Will light get reflected horizontally from walls etc. in this scheme?" "4733": "Yay! Now we can oversaturate" "4748": "Close down" --- name: "day100" title: "Reflection Vectors" markers: "66": "Recap where we left off yesterday" "140": "Blackboard: Surface reflectance" "312": "Blackboard: Straight reflection model and Collision detection" "665": "Look at the code" "745": "Blackboard: Orthographic projection" "931": "Make the Z-axis our EyeVector" "951": "Blackboard: A "premature optimisation"" "1123": "Compute the bounce on the assumption that the eye vector is always [0, 0, 1]" "1278": "Compile and see what happens" "1323": "Blackboard: Fudge factor" "1462": "Blackboard: Sampling from the environment map" "1784": "Assume that the BounceDirection is always going in the direction of the map that it's trying to sample from" "1875": "Negate the BounceDirection for the Bottom map" "1985": "Start setting up SampleDirection" "2045": "Compute the offset from the fudge factor and the coefficient" "2136": "Compute tX and tY and (erroneously) clamp them" "2240": "Figure out what the UV is" "2381": "Check it out in-game and introduce some motion" "2620": "Blackboard: The way that we're encoding things" "2652": "Change that default Normal in MakeSphereNormalMap" "2701": "Take a look in-game" "2750": "Step into the debugger" "2820": "Blackboard: We still need some degree of tilt to the mirror" "2870": "It was really just Casey being kind of blunt" "2873": "Tweak the Normal" "2941": "Check out the reflective sphere in-game" "2996": "Consider investigating what's going wrong with the Top map" "3106": "Q&A" "3170": "You could try creating a normal map with a more predictable reflection, rather than a sphere" "3233": "Is the Y-axis correctly set in the normal map?" "3298": "A pyramid was suggested by a couple of people" "3360": "Blackboard: Pyramid" "3425": "Make a pyramid" "3492": "Blackboard: Figuring out a pyramid" "3545": "Set that pyramid" "3630": "Give it a shot" "3670": "Q: So it would need to be flipped on both directions?" "3686": "Q: I think the lower reflection also needs to flip the Y there because it's the incoming vector, right?" "3726": "you said you might have to make the sky texture larger than the ground so it wouldn't miss it. Could you instead sample from adjacent sky maps (assuming they're not occluded)?" "3781": "The edge attenuation is correct, given that a reflected vector right on the edge will have a smaller Y value than ones reflected from nearer the center" "3875": "Q: Would it be possible to rotate the "incoming" sampling from the environment map so that it looks like the sphere is spinning?" "3917": "Cylinders might be useful" "4106": "Are you using a left-handed coordinate system or a right-handed coordinate system?" "4134": "Would inverted versions of the normal maps be useful? (inverted sphere)" "4157": "That's disturbing" "4175": "TODO(casey): Rotate normals based on X/Y axis!" "4349": "Q: That's a wrap!" --- name: "day101" title: "The Inverse and the Transpose" markers: "46": "Recap our current situation" "105": "Start thinking about how we'll transform Normals" "231": "Blackboard: Rotating Normals (is pretty straightforward)" "301": "Blackboard: Non-uniform scaling gets a little bit hairy" "377": "Blackboard: Pretending we have the edge of a gem" "521": "Blackboard: Vectors are not all the same" "683": "Blackboard: Normals are written differently in linear algebra" "766": "Blackboard: Sometimes you have to go down a math hole" "783": "Blackboard: Constructing the P vectors" "857": "Blackboard: Matrix multiplication" "1458": "Blackboard: Transpose operation" "1579": "Blackboard: Inverse operation" "1824": "Blackboard: Gauss steps in with Gaussian Elimination" "2126": "Blackboard: Solving equations in multiple unknowns" "2193": "Blackboard: We're just entirely in the math hole" "2237": "Blackboard: You can add or multiply any two equations with equal terms for free" "2342": "Blackboard: We can regularise operations on the rows and columns of this matrix" "2389": "Blackboard: Use numbers to clearly demonstrate Gaussian Elimination" "2472": "Blackboard: This is not JZ's term" "2487": "Blackboard: You can then divide the last remaining term by whatever the target is" "2590": "Blackboard: We want to be able to multiply a matrix by something in order to produce that identity matrix" "2678": "Blackboard: The regular solution form for Gaussian Elimination" "3492": "Blackboard: Unfortunately we didn't quite get to the inverse transpose" "3746": "Q&A" "3786": "For inverting 2x2 matrices, a simple cofactor equation is quite efficient" "3806": "All of the steps in elimination can be represented as a matrix. Starting with M and multiply by all those matrices you get the identity. So those matrices multiplied together are the inverse. Multiplying them all by the identity gives you the inverse. Is that the trick you are alluding to?" "4067": "To find the inverse matrix couldn't we just rotate by the negative angle and scale by 1 over the amount that we scaled by originally?" "4652": "I remember doing this by putting the identity besides the original matrix and performing each step to each" "4884": "If you had a matrix such as int[2][2] with the example of abcd as the variables in place, couldn't you just swap a and d and make c and b negative?" "4951": "I understood none of today's episode. Would you recommend that I rewatch it, or do you think all may become clear tomorrow?" "5011": "If you write A and then I next to each other, and apply a bunch of operations, you are computing T3T2T1 A and T3T2T1 I. Because you ended up at the identity, T3T2T1A = I. So T3T2T1 = A^-1. Therefore T3T2T1 I = A^-1" "5206": "Blackboard: Look at all of this maths" "5250": "Blackboard: Setup for Day 102 and sign off" --- name: "day102" title: "Transforming Normals Properly" markers: "31": "Yesterday we had a little bit of a problem" "85": "Blackboard: Imagining the Normals for a house" "231": "Blackboard: Recap how to get the perpendicular of a vector" "320": "Blackboard: Constructing this Normal with rotation and uniform scale" "507": "Blackboard: What happens if we do non-uniform scale?" "810": "Blackboard: How can we work around this incorrect calculation?" "1061": "Open up emacs and take a look at what's currently going on in-game" "1095": "Rotate normals based on X/Y axis" "1204": "Introduce NxAxis and NyAxis" "1314": "Give our v4s the ability to assign just to xy, yz or zw" "1356": "Check it out in-game" "1370": "Moment of realisation: We can't just normalise afterwards without having touched the Z size" "1402": "Compensate for the size changes of X and Y" "1482": "Check it out in-game" "1547": "Blackboard: Explaining NzScale" "1759": "RIP Das Keyboard 4" "1811": "Consider NzScale" "1870": "Resume working on sampling from the maps correctly" "2109": "Document SampleEnvironmentMap a little" "2341": "Pass DistanceFromMapInZ to SampleEnvironmentMap" "2413": "Blackboard: Think about the weird nature of lighting in 2D games" "2514": "Flip DistanceFromMapInZ" "2543": "Ensure we're still where we were in-game and continue to verify SampleEnvironmentMap" "2717": "Blackboard: Figure out which direction Z should be sampling in the map" "2821": "Push BounceDirection.z up to the head end and negate it there" "2865": "View it in-game, try flipping it back and investigate what is happening" "3519": "Leave that as the puzzler and go to the Q&A" "3544": "Draw the sampling vector as RGB=XYZ*0.5+0.5 to visualize it" "4010": "Is the map being clipped on either the top or bottom edge? (Don't know if that makes sense.)" "4043": "Could we calculate a value for the NzScale from the Normal.x and Normal.y so that the Normal.z is unchanged after normalization?" "4313": "Only flip the BounceDirection.z when you use the top map" "4688": "Identify that we're almost puncturing through, or inverting, the map" "4833": "Maybe you can try to write code to show points on the textures from which it is doing sampling?" "4850": "How would the anomaly shift if the sphere were to move up and down instead of left and right?" "4960": "Wondering if it shouldn't maybe be " / fabs(SampleDirection.y)"?" "5164": "Show the sampling on the texture?" "5320": "The stream's over" --- name: "day103" title: "Card-like Normal Map Reflections" markers: "83": "Recap the bug" "189": "Blackboard: Sprite cards and casting directions" "604": "Take a look at the offending notion in handmade_render_group.cpp" "721": "Base DistanceFromMapInZ on HeightOfCard" "829": "Blackboard: Figuring out the height offset for the cast" "996": "Calculate ZDiff" "1121": "Turn DistanceFromMapInZ into a more sane equation" "1236": "Initialise values" "1368": "Position the EnvMaps" "1426": "Take a look in-game" "1489": "Disable the sampling debug visualisations for now and check out the reflections" "1566": "Setup EnvMaps values for testing" "1659": "Set the Origin to the middle for FixedCastY" "1713": "Set ScreenSpaceUV to 0.5f, 0.5f and investigate the warping reflections" "2100": "Alpha out the area around the sphere" "2405": "View our sphere and verify that our BounceDirection is not changing" "2441": "Consider what else may plausibly be changing" "2530": "Blackboard: Coordinate system considerations" "2579": "Set OriginY in order to pass it to ZDiff" "2646": "Turn off the sampling overdraw and darken the sphere" "2699": "Check out our stable sphere and allow it to move around again" "2794": "Q&A" "2828": "The reflection is "inverted" - the edge should be the center and vice versa" "2833": "Q: Reflection I think is backwards, at least vertically" "2873": "How long do you anticipate it will take before we get into more game-designey type topics rather than building up the engine?" "2919": "There are 12 mins left of normal stream time!" "2950": "Investigate the sphere's apparently inverted reflection" "3193": "Blackboard: Accentuating tFarMap's falloff by squaring it" "3327": "My guess is that the normals at the edges are now pointing "straight up" while the normals at the center are pointing "sideways"" "3392": "Q: Move it and then it looks wrong" "3469": "Where are the walls relative to the sphere? If it's above it as in out of the screen, then it's wrong" "3693": "Q: Reflect Casey face" "3709": "It feels like the red and blue should swap places" "3725": "Can you make the checkerboard a bit tighter? I think the problem, if any, will show up better if there are more color transitions" "3797": "Do you only want to support standing cards and lying cards, or also any other angle?" "3859": "I think part of the problem is that it might not be 'sitting' on the floor properly" "4154": "Casey is happy, considering the software renderer" "4252": "Isn't this with optimisations on?" "4317": "This is not threaded yet?" "4348": "Kill it for today and glimpse into the future" "4387": "The green dude is tough" "4527": "What about Fresnel!!!" "4605": "Wrap it up for today" --- name: "day104" title: "Switching to Y-is-up Render Targets" markers: "142": "Z is kind of up in the air" "246": "Recap where we left off last week" "413": "Take a look at handmade_render_group.h" "474": "Toggle off the normal mapping test code" "520": "Toggle on the bitmap rendering" "648": "Toggle off the yellow debug lines" "773": "Define a couple of things in handmade_render_group.h" "1058": "Reach back into our memories to the time we were working on ResizeDIBSection" "1148": "Flip the sign of Buffer->Height" "1219": "Walk through the functions in handmade_render_group.cpp" "1437": "Arrive at GetRenderEntityBasisP and change it to handle X and Y symmetrically" "1522": "Introduce TODO(casey): ZHANDLING" "1570": "Continue walking through the functions and remove any instances of Y negation" "1627": "Take a look at how Align is computed at asset loading time and introduce SetTopDownAlign" "1798": "Blackboard: Flipping the Bitmap alignment" "1875": "Write SetTopDownAlign" "1982": "Pop back over to handmade_render_group.cpp" "2026": "Check it out in-game" "2056": "Load the bitmaps bottom-up" "2178": "Check it out in-game" "2233": "Fix the jump direction" "2360": "Fix the bitmap alignments (for now)" "2509": "We are back to parity" "2586": "Take a look at the GroundBuffer sorting" "2767": "Flip the sign of ChunkOffsetY in FillGroundChunk" "2791": "On the importance of focusing on whatever it is that you're focusing on, and to know when to stop and correct things" "2907": "Casey thinks we're in good shape there" "2947": "Q&A" "3051": "Q: Has this work fixed the normal map issue or will we need to address that specifically?" "3106": "Do you think that making the Y component to be bottom-up will also help make sense of game mechanics like gravity?" "3154": "Will we be implementing a matrix/affine transform in order to handle changes to coordinate systems?" "3181": "Blackboard: Multiplying an incoming vector by a matrix" "3505": "Blackboard: The homogeneous matrix" "3700": "The mods had a lot of work to do today, just so you know" "3725": "Casey, maybe I missed it, but when will the Z ordering be done to visually correct sprites in front and behind the character?" "3761": "It's more correct to call that the "translation part". The entire upper part is affine" "3917": "When you exit the program, Visual Studio says that there are about 8 threads terminated. Is there more than one thread in Handmade Hero right now?" "4035": "Would it be possible to have the renderer set up so the world curves back as you move along the Y-axis?" "4244": "Go ahead and end" --- name: "day105" title: "Cleaning Up the Renderer API" markers: "57": "Go ahead and see where we're at" "235": "Come back here to our code" "372": "Pull functions out into handmade_render_group.h and look at them" "445": "Remove PushPiece in favour of PushBitmap" "770": "Specify that a bitmap's alignment will be directly associated with it" "936": "Massage and pass the alignment where needed" "1333": "Check it out in-game and investigate the Shadow" "1402": "Consider drilling down into PushBitmap a little more" "1483": "Figure out what's going on with our Z-positioning" "1925": "Blackboard: Hacky shadows" "2042": "Decommission EntityZC" "2175": "Continue with the Z code" "2555": "Run it and see that it looks fine" "2574": "Halve the Z-position of EntityType_Space" "2689": "Try to handle our Z in a more sane way" "2822": "Give the familiar some attention and keep going with that" "3123": "Blackboard: How the EntityBasis is conceptualised" "3234": "Only use the EntityBaseP.z for scaling" "3271": "Check it out in-game, scrutinising the jumping" "3397": "Q&A" "3458": "Why are you using AlignX and AlignY, instead of a v2 (in bitmap)?" "3608": "Shouldn't the shadow move somewhat up when he jumps (because of the angled viewport)?" "3651": "Could you make the circle reflect a bitmap like a tree if you wanted?" "3785": "Can you let the orb sample from the ground, or is that some time away?" "3989": "How much zooming will the game support?" "4015": "I keep hearing you say entity, but I take it you don't mean entity in the Entity Component System sense. Is that correct?" "4038": "You were going to add a comment to your ZFudge code to say why XY was used only, not Z to avoid skewing trees, character, etc" "4080": "I think I missed the day, but the bitmap is being texturized using a normal function (into the sphere)?" "4090": "When are we going to scale the hero down?" "4130": "Casey feels like there's a bug with our edges" "4155": "Would you implement a "lamp in a dark room" effect with shadow mapping?" "4242": "Will there be emitters of some kind, like sparks from a fire?" "4264": "How would you implement a lamp in a dark room effect in a 2D game?" "4325": "Is it common in game development to use normal function for texturizing? Is it performant? Or is it much more common to break in texturizing triangles surfaces?" "4447": "Will the entities have projected shadows or just blob shadows like the head has currently?" "4508": ""Un-optimized"? Don't you have -O2 on?" "4580": "Will the shadow be reflected in the normal map?" "4597": "Will the particles effects system interact with the normal maps?" "4650": "Go ahead and close things down for the day, then" --- name: "day106" title: "World Scaling" markers: "163": "Recap our current situation" "300": "Take a look in handmade_render_group.cpp" "358": "Render bitmaps using the DrawRectangleSlowly function" "438": "Call through the slow path?" "524": "Check it out in-game, considering how unoptimised the code is" "710": "Blackboard: Scaling" "923": "Blackboard: Intermediate buffering" "1014": "Blackboard: The stupid way" "1048": "Temporarily set the arrow keys to move the camera up and down" "1338": "Reduce the ZFudge factor" "1394": "See that the positions are being scaled, and go ahead and scale the size" "1545": "Check out the scaling in-game and note a bug with the tree popping" "1623": "Give the ground chunks a ZOffset" "1701": "Blackboard: Preventing leaning" "1736": "Do a Basis push for the GroundBuffer" "1807": "We're close, but things scale counter to each other" "1901": "Turn off the ground chunks and the debug rectangles, for now" "1958": "Take a good look at what's happening in-game" "2082": "Scale around ScreenCenter" "2172": "Moment of realisation: The EntityBasis->Offset.xy is currently incorrect" "2289": "Blackboard: How that Offset currently works" "2322": "Multiply the Offset by the ZFudge" "2375": "Check it out in-game and turn the ground chunks back on" "2487": "Show some problems with alpha fading" "2743": "Blackboard: Render buffers" "2817": "Turn off the ground buffer rendering and turn on multiple world layers" "2880": "Tweak the ZFudge" "2931": "Turn the ground buffers off entirely" "2963": "Consider the weird notion of Y-displacement for Z" "3050": "Set GlobalAlpha to 0 and try turning off that Y-displacement" "3230": "We want Z-slices" "3431": "Q&A" "3460": "Did I see that correctly, that the ground shadow jumps along with the hero?" "3497": "Slightly off topic but, can you quickly go over the concept behind MoveSpec? Why not have every entity have their own velocity/drag, etc. values instead? Just for organization?" "3546": "Is the jump a real mechanic or just for making the system robust?" "3569": "Why don't you pre-compose hero bitmaps into a single bitmap at initialization, so there would not be fussing with pushing pieces?" "3612": "When you are walking up a staircase, will the character suddenly snap back on Y when you transition to the next Z slice?" "3654": "If I'm not mistaken, with your way of Z-scaling it's going to be hard to support large (in Z) structures such as tall walls that should be aligned across different Z levels, no? Imagine a multi story house or so" "3742": "If there are going to be pits/ledges in the game, how are you going to render those?" "3767": "I wonder how the ball would work with the zoom in" "3930": "What games do the "bad" fade-out effect you mentioned?" "3973": "How will the staircase be scaled when you are moving up and down it?" "4033": "insofaras I didn't expect Casey to know of Hatoful Boyfriend" "4038": "Everybody knows Hatoful Boyfriend" "4104": "Have you seen/heard of "Hunie Pop" then?" "4144": "Q: That's a wrap?" "4175": "That is a wrap, Abner" --- name: "day107" title: "Fading Z Layers" markers: "205": "Recap where we left things off" "280": "Explain the necessity for Z-slices" "453": "Take a look at how our SimRegion stuff handles unpacking entities" "547": "Take out the ZOffset and reenable DrawRectangle" "642": "Turn off the camera snapping" "749": "Explain the concept of fixed Z-slices" "880": "Move GlobalAlpha" "992": "On separating update and render for entities" "1071": "Set the GlobalAlpha based on the GroundP" "1213": "Introduce CameraP" "1411": "Set the GlobalAlpha from CameraRelativeGroundP" "1483": "Take a look at the fade in-game" "1520": "Makes this a little more formal" "1582": "Blackboard: Specifying the visibility of levels" "1744": "Introduce Fade location markers" "1934": "Introduce Clamp01MapToRange" "2094": "Check it out in-game and correct the fade direction" "2285": "Allow us to go up another level" "2647": "What has Casey done?" "2699": "That's a bug" "2710": "Investigate what's going on" "2886": "Set the MaxEntityRadius for Z to 0.0f" "2971": "Set the SimBoundsExpansion for Z to 0.0f and then to GameState->TypicalFloorHeight" "3101": "See what that gets us" "3171": "Fix Clamp01MapToRange" "3195": "Check out the fade and get the FadeBottom working" "3381": "Check it all out and stagger the stairwell location" "3442": "Walk down the levels and note some issues to work on" "3589": "Q&A" "3616": "Why were some of the trees upside down?" "3737": "Are the head and body entities off to the side supposed to scale with the main character?" "3979": "What is Z-fighting and is it something that you have to worry about in a game like this?" "4011": "Blackboard: Z-Fighting" "4775": "Stream is over" --- name: "day108" title: "Perspective Projection" markers: "143": "Take a look at where we're at" "316": "Blackboard: Perspective projection" "588": "Blackboard: Capturing light in optics (optional)" "1234": "Blackboard: Crazy stuff we can do for photorealism, and camera hoods (optional)" "1606": "Blackboard: The approximation" "1941": "The ZFudge multiplies, but the equation for perspective projection is not a multiplication" "2023": "Implement the equation" "2704": "Take a look in-game and double-check everything" "2855": "Moment of realisation: Our offset is still happening in pixels" "2939": "Do the perspective computation in pixels and work on the values" "3600": "Blackboard: Do the maths one more time" "3847": "Q&A" "3893": "Is squinting analogous to closing a camera's aperture?" "3942": "Are you intending to multiply by XYZ and not just the XY as the variable says?" "3971": "Wasn't the room height 8 meters? That's about 3 times the height of a normal room, so you have to increase the focal length to compress everything" "4014": "Q: Expect a ton of prestream questions" "4027": "Wasn't the parameter already converted to pixels? If so then I think you are converting meters to pixels twice" "4079": "If you wanted to use this code to make a full 3D game such as a first person shooter, how much would you have to change to give the player an adjustable FOV option?" "4298": "How long do you think this is gonna take?" "4382": "No OpenGL, no audio library, no anything. How's being a masochist coming along?" "4493": "Hello! As a software developer, I understand the performance benefits of C++ are important. However, there are a lot of REPL-based code-at-runtime tools coming out that streamline development on both the web and in games. How do you feel about this departure from traditional software development tools?" "4634": "Do you use iPhone? If it's a yes, I would like to give you a copy of my game for iOS" "4654": "Will this game have cinematic mode?" "4687": "I use an iPhone... for my butt" "4709": "Would the renderer be able to support something like zooming out for one screen that is twice as large as normal?" "4883": "Lots of quick time events, too?" "4894": "Where about is the explanation of the reloading the code while running? It sounds like fun" "5017": "What kind of game is this going to be and what will the point of it be?" "5071": "When the game is finished, do you expect the game to look as good as if you made it in a commercial engine?" "5191": "Can I learn how to be a better programmer from this channel?" "5216": "Are you planning any DLC for this game?" "5268": "Do you use Windows Media Center a lot in your game dev process?" "5311": "Why does he move slower at higher zoom?" "5392": "Will the game be fun?" "5408": "Will you cover things like patching and downloading code from the internet?" "5428": "Are you planning on implementing some kind of shader support?" "5489": "Will this game have a Collector's Edition? I want a plastic dragon in it for $150" "5555": "It's dinner time" --- name: "day109" title: "Resolution-Independent Rendering" markers: "96": "Recap where we're at" "193": "Take a closer look at that perspective projection" "342": "Blackboard: The components of the perspective equation" "501": "Determine the size of our monitor" "732": "Think about MetersToPixels and resolution independence" "847": "Encode our hotspots as being proportional to the size of the bitmaps" "1128": "Get rid of MetersToPixels from the encode call" "1184": "Blackboard: We are going to specify sizes in meters" "1276": "Introduce WidthOverHeight and specify our expected sizes" "1415": "Whenever we do that read... right..." "1472": "Do this without any values in the pipeline" "1962": "Blackboard: Unit cube" "2285": "Finally do that MetersToPixels projection" "2450": "Check it out in-game" "2473": "Debug it" "2521": "Check it out and make PushBitmap start specifying the size that it thinks things should be" "2826": "Take a look at the bitmaps in GIMP" "2860": "Synthetically scale up the HeroBitmaps" "2936": "Check it out and tweak the camera values" "3096": "Clean this stuff up" "3380": "Base MetersToPixels off the ScreenDim.x" "3547": "Demonstrate this resolution-independence" "3874": "Q&A" "3938": "Should the hero/tree sizes not be dictated by the resolution of the art, i.e. to maintain constant pixel density?" "4052": "If you want your game to be full screen, how would you want to handle screens with different aspect ratios?" "4098": "Q: Baby familiars" "4140": "Tiny shadows look funny" "4215": "Q: It could be interesting to have larger trees that span multiple Z-levels. Don't know how well it would work in our style" "4238": "Will the game support scaling to arbitrary resolutions now?" "4326": "Could you explain what the #if #endif stuff is for and when/how you use it?" "4452": "Will the stairs have different artwork for the top and bottom and if so how would you make them seamless? Per step artwork each at their own height?" "4547": "Can we at least get some crappy MS paint programmer art stairs in there instead of yellow blocks?" "4555": "What happened to the cool velocity boost from stairwells?" "4580": "Towards the end when packaging, will you show us compression methods and ways to package all the assets in one file?" "4636": "Is the hero supposed to shrink on the stairs?" "4880": "Double Semicolon!" "4916": "Q: Seems we ran out of questions. Thank you for streaming, it's always a privilege! Pre-stream was painful, though" "4922": "Thank you to the moderators: garlandobloom, abnercoimbre, chronaldragon and drive137" "5038": "Look forward to the future" --- name: "day110" title: "Unprojecting Screen Boundaries" markers: "153": "Take a look at where we left off and where PixelsToMeters still happens" "257": "Make the renderer responsible for telling us what the screen dimensions are" "574": "Blackboard: Field of view in Y" "730": "Put camera parameters in render_group" "1066": "Blackboard: Figuring out RawXY distance based on the ProjectedXY" "1136": "Calculate RawXY" "1310": "Figure out what we would fill in in terms of the ProjectedXY" "1586": "Step in and see what we're getting in terms of the size" "1781": "Check it out in-game" "1824": "Keep on the march of tightening this down" "1916": "Introduce MetersToPixels on the monitor" "2249": "TODO(casey): How do we want to control our ground chunk resolution?" "2283": "Pass DrawBuffer->Width and Height to AllocateRenderGroup and take a look in-game" "2327": "Refresh the FocalLength" "2515": "Massage the code" "2638": "Take a look in-game and introduce a way to verify the computations" "2842": "Draw the ScreenBounds" "2926": "Introduce the concept of a DebugCamera" "3233": "See it in-game" "3320": "Investigate why the entities aren't moving in and out of the SimRegion based on Y" "3411": "Draw the CameraBoundsInMeters, SimBounds and SimRegion->Bounds" "3469": "'Too Many Rects' by Casey Muratori" "3513": "Take a look at it all and start to investigate why entities are not getting pulled in up to the SimRegion->Bounds" "3797": "Q&A" "3836": "Will the 'Too Many Rects' song be on the soundtrack album?" "3850": "Should the MetersToPixels value take the pixel density of the monitor into account?" "3898": "Blackboard: How we're parameterising things at the moment" "4348": "Are you sure the camera should be looking down perpendicular to the levels? Wouldn't the perspective art work out better if you said the camera was at an angle?" "4379": "Can you please toss U, V into v2?" "4425": "Q: We will know exactly how far away they are sitting if they have properly purchased their Handmade Hero branded Microsoft(r) HoloLens" "4464": "Blackboard: Non-joke important thing regarding VR headsets" "4613": "Is 'real32' ambiguous because it could be either floating point or fixed point?" "4665": "Is the non-smooth movement at higher zoom levels due to not being optimized or some sort of issue with sub-pixel smoothness?" "4686": "Would it look different if you scale WidthOfMonitor and FocalLength together, constrained to the same ratio?" "4796": "Could you put a slider for the user to change their distance to the camera at the start of the game, like some games do with gamma?" "4843": "We're about done" --- name: "day111" title: "Resolution-Independent Ground Chunks" markers: "54": "Make sure Ignored are unique names for Miblo" "137": "Pull the debug camera back a little further" "249": "Up our tree count" "272": "Start making the game very slow" "341": "Check out all the trees and forecast today's work" "550": "Look at the ground" "680": "Re-enable this GroundBuffer routine" "746": "Give PushBitmap a scale, take a look and note that the Basis isn't being cleared" "813": "Change the Basis back to the Default" "905": "#if 0 the GroundBuffer routine and add visualisation for the places where GroundChunks are being rendered" "1027": "See those places and note that it's never updating where the GroundChunks are" "1075": "Fix that update and take a walk through the world" "1168": "Figure out why we're not getting anything in the bitmap" "1296": "Get the outlines drawing in the right place" "1418": "Get FillGroundChunk working" "1619": "Give DEBUGLoadBMP the ability to let us ask for the default alignment" "1778": "Continue working on FillGroundChunk" "1875": "See if that produces anything more usable for us" "1991": "Verify that the problem is in the Bitmap" "2027": "Try and step into FillGroundChunk" "2098": "Moment of realisation: Visual Studio is too dumb to set that breakpoint when building in -O2" "2179": "Initialise Buffer->WidthOverHeight" "2262": "Look at that frame rate" "2593": "Only render ground layers that are close to the camera" "2754": "Consider optimising some of the renderer" "2960": "Q&A" "2987": "There are 15 mins left of the stream, since you went over in the prestream" "3022": "No stream tomorrow, right?" "3026": "How are you going to handle the ground chunks on the further layers which disappear while still on-screen? Will you need to expand the visibility range based on layer distance?" "3136": "Some elements in the ground are being repeated now for some reason" "3174": "I'm afraid of using sorting and stuff when making games 'cause I'm afraid that if I get too many items it will slow down. Or shall I not worry about that?" "3249": "I think it'd be cool to see really far down through, for example, floors made of glass / ice" "3304": "Will the memory footprint keep getting bigger? There's so much raw pixel data being stored right now, is this a concern at all, will we be compressing data to save ram? I imagine not, but it still feels like we're using too much memory for just a 2D game. Correct me if and because I'm wrong" "3481": "Are the ground chunks stored in some data structure (e.g. hash map or grid) or are they recalculated each frame (I was wondering, because ground chunk knows its position, but wouldn't that be implicit in its position in the data structure)?" "3519": "There was horizontal repetition of some splats but not all of them" "3556": "Do you think you are roughly 1/5 of the way through completing the game at this point?" "3664": "hen all RAM (even on GPU) is used, when the game is put into background (switching a short time to another application) all the memory has to be swapped in and out, right, even to the GPU? Or what strategy is used to prevent swapping in and out of big memory chunks?" "3745": "Q: Are we rotating and scaling the splats on the ground chunks to get the maximum variability?" "3789": "I noticed the hero's head would clip through the trees (i.e. trees on the top part of the room) on occasion and then it would fix itself. What's causing that?" "3835": "Close this down" --- name: "day112" title: "A Mental Model of CPU Performance" markers: "137": "Blackboard: Optimization" "238": "Blackboard: CPU + GPU instructions" "328": "Blackboard: Math operations done wide (SIMD)" "506": "Blackboard: An example instruction" "610": "Blackboard: Issuing an instruction is expensive" "793": "Blackboard: Optimization considerations" "956": "Blackboard: Memory access costs" "1074": "Blackboard: Cycles" "1325": "Blackboard: You should always know how many cycles you have to work with" "1477": "Blackboard: You won't always have all cycles available for use" "1557": "Blackboard: What is a cycle?" "1898": "Blackboard: Pipeline stages" "2076": "Blackboard: Why pipeline? (Doing the laundry)" "2381": "Blackboard: Latency and Throughput" "2633": "Blackboard: Where latency causes us a problem" "2913": "Blackboard: Cache miss" "3061": "Blackboard: Hyperthreading" "3162": "Blackboard: Optimization, the platform" "3307": "Blackboard: So that is optimization" "3325": "Blackboard: Efficiency" "3570": "Q&A" "3613": "Would you be willing to make more blackboard episodes? This is very informative" "3646": "Are you going to be using anything like VTune for measuring performance?" "3686": "How are instructions written in cache memory?" "3753": "Do we manually issue prefetching or is that something inferred by the CPU by looking at how we access memory?" "3908": "I know this is a long way off, but after Handmade Hero is done, do you plan to continue educational streams?" "3934": "How often do you estimate the actual amount of work prior to implementing a feature vs just implementing it and measuring it?" "4139": "So if memory takes a few hundred cycles if the instructions have to reach out to the hard drive, what impact would that have?" "4274": "Two questions: 1) Are there ever any cases where we have to worry about one of our instructions being decoded into multiple microcode instructions without our knowledge?" "4396": "2) In optimizing, have you set up the code in such a way that you can optimize things function-by-function with this eventuality in mind, or will we have to restructure some of the functions to allow them to be optimized?" "4597": "Would it be inefficient to offload the cache to an SSD over/or with minimal RAM usage or would the latency be too much?" "4652": ""Premature Optimization is the root of all evil." What's your take on that quote?" "4768": "Is there any way to use or avoid hyperthreading to your advantage?" "4784": "What do you tell someone who doesn't like emacs?" "4839": "Does hyperthreading reduce maximum bandwidth because it has to switch between states, or can both states operate at the same time?" "4880": "In your experience what drives the "good enough" optimization and how do the novice guys get a handle on that?" "5040": "Wrap things up" --- name: "day113" title: "Simple Performance Counters" markers: "124": "Blackboard: Basic process of optimization" "362": "Gather statistics" "525": "Revisit __rdtsc" "622": "GAME_UPDATE_AND_RENDER: Add __rdtsc cycle counts" "683": "Introduce debug_cycle_counter in handmade_platform.h" "832": "Support folks on platforms such as Linux and Mac, etc." "1122": "Compile, clean and run" "1184": "FillGroundChunk: Turn off the ground chunks" "1224": "Get a look at those timer values" "1569": "Run the game and see the debug cycle count" "1645": "We are already missing our budget" "1696": "Confirm what we know to be true" "1725": "RenderGroupToOutput: Add a timed block" "1795": "Introduce DebugGlobalMemory to enable us to access this timing stuff even when we shouldn't have access to it" "1930": "Note the difference between the two cycle counts" "2014": "Confirm that DrawRectangleSlowly is the culprit" "2116": "Introduce HitCount to discover if DrawRectangleSlowly is slow because it is slow, or because it's called so often" "2265": "Discover that we're calling the renderer thirteen times and DrawRectangleSlowly 64 times" "2345": "Figure out how many pixels we're filling" "2569": "Interpret the data" "2608": "Bust out some emacs-fu" "2622": "Note that we're not operating on that many more pixels than the total on the screen" "2661": "Blackboard: Overdraw" "2790": "Blackboard: Progress report" "2844": "Turn off the NormalMap" "2938": "Understanding ballpark timings" "3113": "Make an estimate" "3648": "AVX-512 hype" "3675": "Q&A" "3714": "Why no text labels on the counters?" "3730": "I'm sorry if this is something you've gone over before, but can you explain the difference between new and malloc() in C++ and when each is useful?" "3784": "Is your handwriting as bad in real life as it is with a tablet?" "3802": "Can you also cut out instructions by doing more work to save previous computations. Like d - XAxis, followed by d - XAxis - YAxis. Should that just be 2 instructions?" "3830": "Do you think we'll do multithreading in the software renderer?" "3847": "Is it possible to Quad-pump every operation?" "4049": "I meant, put it in wide instruction (SIMD)" "4142": "Would you talk Jeff into doing an optimization stream where you are the TA?" "4201": "That is the end of the stream" --- name: "day114" title: "Preparing a Function for Optimization" markers: "91": "Open things up and recap" "168": "DrawRectangleSlowly: Increase efficiency" "213": "Create DrawRectangleHopefullyQuickly" "274": "DrawRectangleHopefullyQuickly: Skip the preamble" "342": "Remove all unnecessary code" "404": "Look at what's happening" "481": "Make the edge testing code more explicit" "589": "Blackboard: See what's happening with these inner products" "724": "DrawRectangleHopefullyQuickly: Test U and V instead" "792": "Run the game" "813": "Make these U and V computations more efficient" "880": "Run the game and ensure that everything still blits fine" "916": "Continue pruning" "1082": "Flatten the routine" "1195": "Blow out v4 Blended into scalar form" "1278": "Take a close look at the routine and precompute InvTexelA" "1415": "Blow out v4 Dest and Texel into scalar form" "1530": "Flatten BilinearSample and SRGBBilinearBlend" "1682": "Assess our situation" "1735": "Unpack and optimise the Lerps" "2037": "Run the game and annotate the code" "2133": "Flatten SRGB255ToLinear1" "2198": "Flatten Unpack4x8" "2339": "That's everything flattened" "2362": "Note that the code is faster" "2458": "We have a nasty problem with the unpackings" "2641": "Blackboard: What is our "wide" strategy?" "2923": "Set the stage for SIMD" "3045": "Consider solidifying texture boundaries" "3113": "Leave it for today" "3189": "Q&A" "3208": "The way the code is written now you have a very long dependency chain (between instructions). Will you break down the code to remove it?" "3402": "Why did you write float instead of real32 this stream?" "3434": "Why use -O2 instead of -O3 or -Ofast (possibly with -fverbose-asm)?" "3486": "Do you ever use exclusive or operations to avoid pipeline stalls? If not, what do you use?" "3544": "Aren't those square roots pretty expensive?" "3811": "Will you make multiple SIMD backends? (SSE?/AVX/FMA versions)" "3844": "You could loft some of those variables out one more loop" "3898": "How expensive is the float<>int conversion compared to the rest of the workload?" "3940": "Since xAxis and yAxis are usually perpendicular, should we special case for that? In the same vein, should we special-case for axis-aligned?" "4016": "Does the compiler do any automatic SSE optimization (or have option for it?)" "4141": "sqrt_ss vs sqrt_ps vs sqrt_pd?" "4316": "Would SSE allow doing sRGB using exponent 2.2 instead of approximating using one of 2, without a huge performance hit?" "4361": "The main reason why you don't get automatic SIMD is precise exceptions. You probably need to tell the compiler that you don't need them" "4484": "What happens if "/arch:AVX2" switch is enabled?" "4526": "Look at this AVX-512 stuff" "4611": "FMA is fused multiply add" "4728": "Yeah, looks like different caps bits" "4763": "Wrap things up" --- name: "day115" title: "SIMD Basics" markers: "59": "Open us up and see where we're at in terms of performance" "112": "Blackboard: SIMD on x64" "394": "Blackboard: How do we use SIMD?" "496": "Blackboard: CPU vs GPU framebuffers" "850": "Blackboard: "SOA" vs "AOS"" "1102": "Blackboard: How this stuff actually works" "1333": "Blackboard: Strided loading on NEON" "1522": "build.bat: Turn off compiler optimisations" "1546": "Internet: Intel Intrinsics Guide" "1734": "handmade_render_group.cpp: Initialise some __m128 registers and use some SIMD intrinsics to operate on them 4-wide" "1867": "Debugger: Go to disassembly and look at the SIMD registers" "2162": "handmade_render_group.cpp: Set four different values in the registers" "2196": "Debugger: See those different values in the registers and note the order in which they are loaded" "2387": "handmade_render_group.cpp: Turn Square functions into multiplies" "2464": "Fix the loop to work on pixels in batches of 4" "2780": "Run the game and note that we are overwriting our boundary" "2835": "handmade_render_group.cpp: Temporarily clip the buffers" "2899": "Separate the memory loading stuff from the computations" "3058": "Declare the arrays before the loop" "3440": "Debugger: Run and investigate the error" "3498": "handmade_render_group.cpp: Correctly test ShouldFill[I]" "3530": "Run and note that we're (almost) back to where we started" "3582": "handmade_render_group.cpp: Walk through the routine" "3713": "Load in the Pixels from the right place" "3753": "Run, note that we're back to some semblance of good, and glimpse into the future" "3846": "Q&A" "3870": "Would it be faster to unpack pixels using a union of an int32 with a struct of 4 int8's, instead of doing 4 shifts and masks per pixel?" "3915": "Why don't we go: Y<2 and X<2 and go through in blocks, instead of a line?" "4064": "Is it better if we calculate if the pixel should be filled and queue it up and only do the calculations once we hit 4 of them?" "4245": "Casey was using a Das Keyboard 4, but it broke, so he is currently using an unknown keyboard he had lying around" "4290": "Sorry, maybe this is off-topic: Would it be correct to say anyone coding in Java, by default, is not making use of any of the SIMD stuff, or do you think the JIT compiler is smart enough to make use of it in certain circumstances, maybe with some analysis of the bytecode?" "4349": "How often do you optimize for cache misses vs optimizing with SIMD? I got the impression that cache misses are by far the most important things to look out for" "4480": "Please send my best regards to Jeff" "4492": "Schedule-wise, how many more weeks until you are done with optimization of the renderer?" "4501": "Will you be covering Morton order texture swizzling?" "4614": "Possibly a noob Q: Have you ever run into problems with floating point arithmetic, and what are some good approaches to avoiding those problems?" "4897": "starchypancakes [...] Casey said SSE2 was standard, I guess I'll start there" "5046": "Is there a way to track how memory gets stored to cache?" "5281": "Off-topic: Do you know if JAI will have extensions / a method for using SIMD?" "5330": "How much do you need to think about the intrinsic instructions while programming, or does the compiler usually take care of that? Is this the big difference between using GNU and Intel compiler, for example?" "5437": "I think he's essentially asking how proficient compilers are at automatically emitting SIMD instructions" "5634": "Do you have to take the instruction cache into account? Or is it large enough?" "5679": "How does intrinsics and parallel processing work together? Does each CPU have registers to do intrinsics? If so, could we increase X-fold the number of pixel rendering in our code if we computed in parallel?" "5733": "Wrap things up" --- name: "day116" title: "Converting Math Operations to SIMD" markers: "83": "Recap yesterday's work" "166": "build.bat: Switch to -O2" "262": "Think about doing the TestPixel TIMED_BLOCK over a wider range" "320": "handmade_render_group.cpp: Move the timer around the for loops" "350": "Debugger: See that there are two loops that are more or less the same" "386": "handmade_platform.h: Number these DebugCycleCounters" "409": "handmade_render_group.cpp: Rename TestPixel to ProcessPixel and remove TIMED_BLOCK around DrawRectangleSlowly" "455": "Debugger: Look at the DEBUG CYCLE COUNTS" "492": "handmade_render_group.cpp: Introduce END_TIMED_BLOCK_COUNTED" "576": "Debugger: See that the ProcessPixel count is now more accurate [243cy/h]" "634": "handmade_render_group.cpp: Write this in SIMD" "995": "Run and see that it's still producing the correct result" "1007": "build.bat: Switch to -Od" "1047": "Debugger: Inspect TexelAr" "1288": "handmade_render_group.cpp: Continue transforming these Texel computations into SIMD" "1761": "Run and note that we're running just fine [575cy/h]" "1786": "handmade_render_group.cpp: Continue making these wide" "2234": "Compile and see if we made any mistakes [557cy/h]" "2251": "handmade_render_group.cpp: Do the rest of this wide, except for the Clamp" "2439": "Intel Intrinsics Guide: _mm_sqrt_ps" "2471": "handmade_render_group.cpp: Do _mm_sqrt_ps and continue converting to SIMD" "2619": "Run and note that we are blitting correctly [427cy/h]" "2634": "Debugger: Look at what Clamp01 does" "2837": "Intel Intrinsics Guide: _mm_min_ps and _mm_max_ps" "2925": "handmade_render_group.cpp: Do the Clamps wide [179cy/h]" "3002": "Run and note that the game is already running faster" "3047": "Reflect on the straightforwardness of this work" "3114": "Consider what's left to convert to SIMD" "3166": "handmade_render_group.cpp: Do PixelP wide" "3256": "Run and note how fast it's running [124cy/h]" "3378": "Debugger: Investigate what the compiler is doing with those 50 cycles" "3774": "handmade_render_group.cpp: Finish doing the SIMD here" "4052": "Run and note that we're creeping forwards [121cy/h]" "4086": "Recap and glimpse into the future of doing the Loads and Repack in SIMD" "4268": "Q&A" "4292": "How do you cover multiple CPU technologies intrinsic-wise? Preprocessor switches on dedicated intrinsics for each? Also, whom to read on ASM? I'm thinking Mike Abrash?" "4389": "We have come from 385 cycles to 123. Does something like the 80%-20% rule apply? Do you think we will get down to 50 cycles?" "4522": "The way we use mmSquare, does it calculate the argument twice?" "4541": "Debugger: Determine if the compiler is doing common subexpression elimination for these multiplies" "4871": "Deep, concentrated investigation" "5154": "Look at how fast the game's running" "5179": "Where do OpenCL and other GPGPU frameworks fit into optimization? It seems like if something is SIMD-able, it could just be done wider on a GPU. Are there workloads that are better suited to the CPU and SIMD?" "5346": "We have optimizations still on?" "5359": "Why are there optimizing options in the compiler if one will end up typing SIMD functions?" "5461": "Do you know of the _mm_setr_ps intrinsic (and _pd etc) - note the r in setr? It loads the values in reverse order, i.e. in the order that is more intuitive" "5498": "When do you think we will thread the renderer?" "5517": "Possibly misguided question, is there a way to overload operators to use SIMD instructions instead?" "5565": "Is padding and alignment still something you have to concern yourself with? I remember doing SIMD in the mid 2000s, and SIMD was essentially worthless (much of the time) if your data wasn't aligned" "5623": "Addendum: By "concern yourself", I mean, is it something the compiler now handles more autonomously when you "engage" SIMD" "5655": "Will you generate asm for NEON (if you port to arm of course)? GCC seems to be pretty bad at generating correct code with intrinsics (from my experience on Android)" "5703": "How would you know if doing something will speed up the code? Especially when it's a fairly large change to the codebase and when time is limited, I find myself reluctant to perform such optimizations in fear of introducing bugs" "5806": "What do you think you'll next want to convert to SIMD, in case I want to practise over the weekend?" "5932": "Can you compile it -Od and show how SIMD has helped there?" "5972": "Would it be a good exercise (albeit a large one) to study a simple CPU and write some soft for it? Arduino or something ancient? I wanted to learn coding for GBA for a while" "6064": "Let's rephrase: what CPU would you advise to study that would be simple enough yet representative enough of the general stuff you should know about when working with CPUs?" "6172": "How long have you been working on this and when do you think you will finish?" "6209": "re you going to optimize gameplay code as well?" "6225": "Have you heard of the JayStation2 Project from Jaymin Kessler, working with the Raspberry Pi 2 B+?" "6243": "Close things down with a recap of the week's optimisation work" "6483": "Shout out to the mods" --- name: "day117" title: "Packing Pixels for the Framebuffer" markers: "125": "Load up the code and consider optimisation" "249": "handmade_render_group.cpp: Comment out if(ShouldFill[I])" "334": "Blackboard: Interleaving four SIMD values" "867": "Blackboard: Establishing the order we need" "946": "handmade_render_group.cpp: Write the SIMD register names that we want to end up with" "989": "Internet: Intel Intrinsics Guide" "1043": "Blackboard: __mm_unpackhi_epi32 and __mm_unpacklo_epi32" "1144": "Blackboard: Using these operations to generate what we need" "1457": "handmade_render_group.cpp: Name the registers in register order" "1515": "Internet: Double-check the parameter order of the unpack operations" "1582": "handmade_render_group.cpp: Start to populate the registers" "1612": "Internet: Keeping in mind how often you move between __m128 and __m128i" "1719": "handmade_render_group.cpp: Cast the Blended values from float to int" "1787": "Use structured art to enable us to see what's happening" "2087": "Debugger: Watch how our art gets shuffled" "2320": "handmade_render_group.cpp: Produce the rest of the pixel values we need" "2503": "Convert 32-bit floating point values to 8-bit integers" "2647": "// TODO(casey): Set the rounding to something known" "2708": "Blackboard: Using 8-bits of these 32-bit registers" "2852": "handmade_render_group.cpp: Bitwise OR and Shift these values" "3027": "Blackboard: How the shift operations work" "3164": "handmade_render_group.cpp: Implement these shifts" "3306": "Debugger: Take a look at the Out value" "3453": "handmade_render_group.cpp: Break out the values" "3502": "Debugger: Inspect these values" "3515": "handmade_render_group.cpp: Fix the test case" "3572": "Debugger: Inspect our stuff" "3613": "handmade_render_group.cpp: Write Out to Pixel" "3668": "Debugger: Crash and reload" "3703": "Debugger: Note that we are writing unaligned" "3862": "Blackboard: Alignment" "3954": "handmade_render_group.cpp: Issue _mm_storeu_si128 to cause the compiler to use the (unaligned) mov instruction" "4043": "Recap and glimpse into the future" "4110": "Q&A" "4199": "Will the operations be reordered to reduce the number of ops and load / stores?" "4321": "You are calculating Out like or(or(or(r, g), b), a). Would it be better to do it like this: or(or(r, g), or(b, a)), so first two or's are not dependent on each other?" "4497": "handmade_render_group.cpp: Write it the way mmozeiko suggests" "4651": "Do you need to start with 32-bit floats? Is there further optimization that doesn't need the casting?" "4701": "Blackboard: Multiplying floats vs Multiplying integers" "4794": "Same for texture bilinear adds together" "4803": "handmade_render_group.cpp: Implement mmozeiko's suggestion" "4980": "Can you compile /O2 to compare it to last week's performance?" "4996": "Why did you make macros for your SIMD operations (mmSquare, etc.) vs making functions?" "5019": "Are these intrinsics the same on other operating systems or compilers, as long as it's using Intel architecture?" "5080": "Why do you say unaligned store is nasty? As far as I know, for latest Intel CPUs (at least starting from Ivy Bridge) unaligned load / store is not very expensive anymore (<5% difference)" "5185": "Is scalar access to __m128 elements still slow on Intel?" "5238": "The processor window is 192 instructions" "5281": "I don't understand how one optimizes by using the intrinsic or function" "5331": "_mm_cvttps_epi32 always truncates. Would that be better than messing with rounding mode?" "5445": "handmade_render_group.cpp: Switch to _mm_cvttps_epi32" "5570": "Wrap up" --- name: "day118" title: "Wide Unpacking and Masking" markers: "25": "Overview of optimization work" "90": "Recap where we were yesterday" "110": "Current issue: Black bars" "200": "Blackboard: Writing correct values to destination" "335": "It's ok to do all operations for all pixels" "412": "Blackboard: Another option: Combine old/new values" "494": "Blackboard: Build a mask" "540": "Masking out the invalid new values" "650": "Making sure we save the original destination" "698": "Haven't SIMD-ized the load yet, deal with OriginalDest differently" "775": "Problem with WriteMask: Haven't computed it yet!" "840": "Use cheesy set macros to set WriteMask" "856": "Handmade Hero: A Bit Garish edition" "920": "Fixing the 'problem': Mi macro for uint setting" "960": "Another thing: Fabian's rounding mode comment" "1017": "Some work to do with the last for(I) loop" "1174": "The explicit version of unrolling the loop" "1320": "Checking we're still working: under 100 cycles now" "1390": "Doing the destination the same way" "1430": "Just saved more cycles moving things out" "1475": "Fixing the WriteMask nonsense" "1538": "SSE Comparison Operations" "1580": "Blackboard: Comparisons for wide operations" "1783": "Using comparisons to generate WriteMask directly" "1910": "Working WriteMask with wide operations" "1930": "Problem: can't get rid of if entirely..." "1960": "Solution: Clamp U and V" "2020": "Get rid of the if entirely!" "2034": "Handmade Hero: Uniformly Stretchy Edition" "2045": "Fixing the bug: U/V copypasta typo" "2105": "Doing the texel fetch wide as well" "2250": "Not optimizing yet, just translating to SIMD" "2385": "Adjusting the texture fetch to use the wide values" "2430": "Converting the fetch coord by truncating" "2520": "Getting fX and fY by subtraction" "2610": "All correct, under 70 cycles" "2650": "No longer need to initialize the Texel values" "2760": "Everything in SIMD now but texel loads" "2810": "Blackboard: Unpacking the color data" "2910": "Pulling out colors using masks and shifting" "3200": "Blackboard: The matrix of sample reads" "3300": "Packing the sample data into 4-wide registers" "3348": "Some crazy emacs macro kung-fu" "3410": "Doing the Texels the same way as Dest" "3485": "Working texel read, and...almost 50cy/pixel" "3565": "What if there's nothing in the mask?" "3679": "Q&A" "3723": "Could you not just align the X coord to a 4-pixel boundary up front, and thereby use aligned loads and stores?" "3783": "Are you pulling this code over into ground splats soon?" "3915": "Is it me or after this whole SIMD conversion the cycles per pixel are much more consistent?" "3944": "I have kind of missed the past few days, I'm wondering if doing CPU intrinsics exclusively for SSE2 in your game code is bad or are we targetting SSE2? For example, should we wrap everything into platform-specific files so its easier to target other platforms?" "4115": "What does it mean for intrinsics that don't have a specified throughput?" "4131": "Instead of loading the destination first would it be faster to skip that and instead do a masked write e.g. _mm_maskmoveu_si128" "4316": "Would it be a good idea to just use SIMD for all our math operations in all our programs?" "4536": "Example of an intrinsic with no throughput: _mm_cmpgt_ps" "4860": "Agner Fog says the throughput is 1" "4936": "[What is latency vs throughput?]" "4966": "What is the end goal of the optimization, trying to get below a certain threshold, or just to get everything converted?" "5034": "Does size of variables and stuff matter to SIMD, like 32bit vs 64bit?" "5145": "Is the SSE code doing any cache prefetch or hinting stuff yet?" "5232": "Couldn't we use a half-float instead of floats as we don't need that much precision with only 255 discrete values?" "5330": "Is the normal map code going to be converted to SIMD?" "5367": "End of the stream" --- name: "day119" title: "Counting Intrinsics" markers: "10": "Lesson: Das keyboards are horrible" "96": "Recap of last episode and today's agenda" "153": "Prep work for getting pre-optimization vs post-optimization cycle counts" "223": "Add cycle counting to DrawRectangleSlowly" "281": "... 350 vs 50 cycles per pixel!" "317": "How long *should* it take to fill each pixel? Let's count up all the intrinsics and their throughputs..." "430": "... How can we automate this counting process?" "478": "Answer: Override the intrinsics with macros that add to some counter variables" "527": "Oops, there's still some SIMDizing left to do here..." "570": "Use _mm_add_ps to increment PixelPx by 4 instead of scalar adds (2-3 cycles better)" "715": "dx and dy can be baked into PixelPx and PixelPy (2 cycles better)" "788": "Should we loft PixelPx and PixelPy axis multiply/add calculation out of the inner loop?" "839": "Maybe loft just the multiplies but not the add? Hmm..." "860": "... try lofting the multiplications. (1-2 cycles worse)" "950": "Note: Texture fetches can't be done in SIMD" "1012": "Fabian on why _mm_maskmoveu_si128 is so slow. Don't use it! It bypasses the cache." "1095": "Adding a #define for each intrinsic to count operations (_mm_add_ps, _mm_mul_ps, etc)" "1305": "Start setting up the intrinsic #defines to count operations" "1425": "Preprocessor cleverness that handles the fact that intrinsics often take other intrinsics as params" "1654": "Define load/store to nothing" "1719": "Mini-rant about the compiler not doing instruction/intrinsic instrumentation automatically" "1906": "We've got counts!" "1935": "Double check that counts make sense" "2007": "Multiply counts by throughputs to get total latency estimate" "2127": "_mm_castps_si128 latency is difficult to know." "2152": "looking up the processor core type in windows" "2212": "_mm_and_ps and bitwise ops are 1/3 cycle on Nehalem" "2428": "Use a macro to sum up the latency*counts to get a rough throughput total" "2575": "Well, Isn't that fancy: Measured throughput is lower than the theoretical best throughput. Instructions are likely executing on multiple ALUs per cycle" "2740": "How many units are in Nehalem core?" "2897": "... Two?" "2952": "On the limitations of executing multiple instructions per clock" "3085": "We're quite close to the max theoretical throughput." "3139": "Memory latency probably isn't hurting performance" "3167": "Make an #if toggle for the intrinsic measurement code" "3238": "How much is gamma (sqrt) costing us?" "3390": "A troubling visual artifact appears around our hero..." "3467": "Aha! An issue with the linear/SRGB code" "3628": "gamma is costing only 6 cycles" "3665": "This is a reasonably optimized pixel loop" "3692": "Agenda for next session: Optimize outside/around the pixel loop." "3716": "Q&A" "3729": "Is this what you were looking for?" "3796": "Nehalem diagram: Only one FPU?" "3952": "Worth timing the load/stores with no ALU ops to see how much we're memory bound?" "4366": "You counted _mm_and_ps wrong." "4415": "Are you doing pre-multipled alpha? (Yes)" "4418": "Could you run the game with task manager open?" "4577": "Will this game only work for your specific processor?" "4603": " Are you going to update the yellow background textures?" "4652": "The texture fetch should be an L1 cache fetch." "4690": "In an alternate universe where nobody cares for art, do you think optimization would still be a focus for developers?" "4774": "Any idea why my cores get maxed out when running Handmade Hero with the XCB platform layer?" "4833": "Why wasn't there a greater speed increase after removing gamma correction?" "4962": "How will we split up the drawing onto multiple cores?" "4976": "What's the floating head?" "4994": "Question about _mm_ps_sqrt and common subexpression elimination" "5054": "What's that drum-like background noise?" "5077": "Do you see all the questions?" "5107": "Can rdtsc be inaccurate with CPUs that vary their cycle rate?" "5183": "How does the CPU do things ahead of time if things are supposed to be done in order?" "5374": "Do you expect a 16x speedup from multi-threading?" "5399": "How do you select the instruction set for optimizing?" "5575": "Aren't the Unity hardware survey results pretty different than the Steam ones?" "5641": "What are the gains you get by writing your own software renderer vs using SDL, GPUs, etc?" "5724": "Can a processor work through different types of calculations in a single cycle?" "5836": "What kinds of things can be delegated to the GPU?" --- name: "day120" title: "Measuring Port Usage with IACA" markers: "31": "Review of last session: cycle counting code" "80": "Fabian: Instruction counts including throughput numbers is not accurate, does not properly take into account CPU's ability to overlap different ops" "240": "Accurate way is to write tool to simulate the CPU, as Casey did for the XB360" "270": "... or Intel architecture code analyzer (IACA)" "455": "Overview on how to use IACA with the code" "488": "Marking sections with IACA_START and IACA_END" "560": "Modifying build.bat to include the iaca directory" "609": "For linux/unix compatibility, mind your case when including files" "698": "Running the IACA command line" "790": "Reading the IACA results" "928": "Trying to decipher the meanings of the letters in the IACA table" "1018": "IACA can output graphs?" "1032": "IACA reports max throughput of 86.60 cycles" "1076": "There maybe some more room for optimization..." "1110": "IACA is pretty nice!" "1160": "Adding some macros to turn IACA on/off" "1187": "Thanks to Fabian for the suggestion" "1244": "Fabian: bilinear and squaring don't need floating point" "1279": "Move the sRGB->linear conversion after the bilinear" "1405": "Bake normalization into color" "1525": "Works fine (not much improvement)" "1672": "Remove a number of multiply ops by keeping things in 0-255 space (no improvement)" "2207": "Diff IACA output from the run with the removed multiplies and the one prior" "2490": "Getting rid of 43 instructions did not improve throughput reported by IACA" "2566": "Seems to be doing the same number of multiplies either way" "2589": "Compiler was smart enough to do the transformations?" "2707": "What other optimizations could we do?" "2839": "Use _mm_mul_mulhi_epi16 to do the square operations more wide prior to the FP conversion?" "2974": "Blackboard: Mask out A and G, which leaves R and B aligned to the 16-bit SIMD boundaries" "3173": "Blackboard: _mm_mullo_epi16 vs. _mm_mulhi_epi16" "3276": "problem: this will square our alpha as well" "3319": "We'll have to use another instruction to handle alpha" "3420": "Bitshifting / masking to pull the components from their 16-bit lanes" "3519": "Wrong result! It's Q&A, but let's try to debug first..." "3995": "Issue found: Should be masking 16-bit, not 8-bit" "4020": "Better, but still a strange result" "4077": "How to avoid squaring the alpha?" "4158": "Just pull the alpha out prior to the squaring?" "4186": ".. that works fine" "4210": "Now let's convert everything to use the 16-bit squaring" "4259": "... around 6 cycles improvement, but small visual problem with the bilinear" "4297": "Found the issue: We were reading only from SampleA" "4307": "Bilinear looks better, but still oddity with green fringing around the hero" "4336": "Found the issue, looks good, but..." "4362": "... we're actually 8 cycles worse now" "4394": "Why? Let's run it through IACA" "4424": "Throughput bottleneck: Inter-iteration? Good question for Fabian" "4439": "Total number of micro-ops have gotten smaller - 350 vs 306 vs. 283 but throughput is worse" "4556": "Could use the same technique when loading the destination, but probably not a good idea" "4621": "Q&A" "4650": "CP stands for Critical path" "4693": "IACA was showing Port 1 as the bottleneck, so reducing multplies won't help" "4745": "Inter-iteration means that run x of the loop depends on the prior run" "4796": "Try hoisting out the TexturePitch/TextureMemory (several cycles improvement)" "5034": "How do you support AVX? What about register saving through context switches?" "5107": "Replace sqrt with mul/rsqrt?" "5474": "Some comments on port 1 pressure from Fabian" "5659": "How can removing the sqrt help if it's done on the multiply port, not the adder port?" --- name: "day121" title: "Rendering in Tiles (Marathon)" markers: "96": "Reintroducing the Intel Architecture Code Analyzer" "646": "A long time ago, in RAD's source tree" "780": "blowtard, an analytical tool for the Xbox 360's PowerPC Tri-Core Xenon written by Casey" "1324": "How IACA's output differs from Casey's stats in blowtard" "1856": "Looking at how to get our cycle count down" "1941": "Manually unroll the Fetch / Sample loop" "2190": "Group by Sample" "2247": "Use _mm_setr_ps as suggested by Fabian a long time ago" "2534": "Taking a look at the total throughput count" "2598": "Casey needs some more soya [sic] milk" "2657": "Could we do a load once, and grab out the two values that we needed?" "2748": "Explanation of possible texel loading optimisation" "3032": "Figuring out how the compiler is loading the texel data" "3618": "This is fine, then" "3661": "We multiply by TexturePitch and sizeof(uint32) four-wide manually, which is stupid" "3726": "Shift up FetchX_4x by 2, rather than multiply by sizeof(uint32)" "3820": "Premultiply FetchY_4x by TexturePitch_4x" "3847": "Give the compiler the wide stuff so that it can see it as wide" "4281": "_mm_mul_epi32 does not do integer * integer" "4423": "Port pressure (we're back to InterIteration)" "4666": "Hyperthreading" "5242": "Designing how to break up the renderer for multithreading to ease pressure on the caches" "5542": "Divide the frame buffer into chunks that are sized appropriately for the cache" "5995": "The plan for setting up the renderer" "6047": "Implementation of interleaved scanlines, in readiness for hyperthreading" "6396": "The logic of interleaved scanlines" "6757": "Updating compiler directives for folks who use LLVM" "6920": "Implementation of frame buffer divisions, in readiness for multi-core processing" "7530": "Go to Disassembly of DrawRectangleQuickly() in order to diagnose bogus cycle count" "7804": "Frame buffer divisions, continued" "8450": "Introduce GetClampedRectArea" "8532": "Problematic thing: Our convention for rectangles before was that they did not include their final value" "8853": "Fix the cycle counter for DrawRectangleQuickly() again" "8982": "A shortcut didn't work out. (!quote 297 + !quote 298)" "9056": "Loft FillRect above the loop" "9394": "Introduce PixelPxRow in order to keep PixelPx as a wide value rather than having to set it each time" "9590": "Check IACA for performance difference and revert to setting PixelPx each time through the loop" "9808": "Shuffle calculations around to figure out how the performance is affected, for good or ill" "10277": "Thinking about that alignment problem" "10558": "Align MinX and MaxX" "10818": "Microsoft Visual Studio 2013 has stopped working" "10923": "Dancing trees" "10983": "Change our loads and stores to no longer be unaligned" "11045": "Assess performance difference and revert back to the unaligned load and store instructions" "11112": "Make sure that we actually always fill the real clip region and not write outside the clip region" "11230": "Our options for filling the pixels" "11352": "Implementation of alignment to the ending edge" "11808": "Clip the leading edge" "11981": "ClipMask" "12093": "Try setting StartupClipMask by using _mm_srli_si128" "12148": "// TODO(casey): This is stupid." "12370": "Early-out the FillRect tests" "12601": "Start passing ClipRect through to DrawRectangleQuickly" "12935": "Moment of realisation, with introduction of the InvertedInfinityRectangle" "13068": "Temporarily adjust ClipRect in order to avoid a crash" "13164": "Introduce TiledRenderGroupToOutput outside of the timer" "13437": "Update DrawRectangle to take the clipping information" "13638": "Update DrawRectangle{,Quickly} to use the Even / Odd information" "13760": "Break the screen up into pieces and render them separately" "14074": "Stretch your legs, Casey" "14188": "We can finally end the stream" "14227": "Q&A" "14232": "a) your top and right clip is off-by-1!" "14394": "_mm_mullo_epi32 is SSE4 intrinsic" "14697": "Will you revert yesterday changes where you changed bilinear pixel unpacking code from float mul to int mul? It was faster with float mul." "14724": "How many more marathon streams will we have? I thoroughly enjoyed the 4+ hours today." "14747": "You should give a big thanks to Rygorous for sticking around and trying to give you tips knowing full well that you wouldn't see them in chat" "14767": "would it be better to have tile sizes always divisible by 4 horizontally (or even 16 to be cache aligned), then there will be no need to deal with alignment and masking?" "14827": "(clip) one too few pixels. look at the edge of the screen." "14960": "just pretty sure I saw glitchiness/off-by-1-pixel stuff near the edges but it might've been the video encoding" "15068": "(tile size %4) - not masking for textures, but ClipMask variable" "15210": "Q: holy crap. our 1st marathon." "15230": "Time for Casey to go to bed, with closing remarks" --- name: "day122" title: "Introduction to Multithreading" markers: "170": "Blackboard: Multithreading" "215": "Blackboard: CPU state" "308": "Blackboard: How the OS conceptualises this" "415": "Blackboard: Threads" "504": "Blackboard: Fibers" "578": "Blackboard: Why do we care about this?" "730": "Blackboard: "Core"" "856": "Blackboard: "Hyperthread"" "1096": "Blackboard: The OS comes in and switches" "1180": "Blackboard: Logical cores" "1353": "Blackboard: "Out of order" vs "In order"" "1448": "Blackboard: The OS and "interrupts"" "1679": "Blackboard: "Preemption"" "1817": "Blackboard: What we have to do on Handmade Hero" "1931": "Run Handmade Hero and monitor its CPU usage" "2081": "Switch to DrawRectangleSlowly" "2231": "Blackboard: Why not do faster single-threaded processing?" "2447": "Set the stage to create some threads" "2607": "win32_handmade.cpp: Introduce CreateThread" "2969": "Run the code and exit" "3015": "Temporarily create lots of threads" "3046": "Solidify things" "3194": "What happens on exit" "3447": "Hype up building without CRT" "3516": "The compiler doesn't know about threading" "3603": "Q&A" "3627": "What does closing the handle of a thread do for you when you release the handle to the OS? Does it open up resources and increase performance?" "3692": "Doesn't increasing the number of threads to match the hyperthreads count increase cross-core/cross-context switches, thus making it less efficient for small operations?" "3801": "Is there any advantage to creating a separate process to render the graphics in the context of game development?" "3898": "Is it still a while yet before we look at other platform layers than win32?" "3931": "Why just 15 threads? Why not future proof?" "3979": "Will we be querying the system for its CPU count to determine how many threads to use?" "3988": "Do you have control over on which core the thread executes from the program itself (thread affinity)?" "4077": "Do you plan to make path-finding multithreaded?" "4105": "Q: Jonathan Blow had created 10,000 threads on his compiler demo. Some people wondered how in the world that could happen" "4193": "No one will ever need more than 16 threads" "4205": "Nobody will ever need more than 256 colors. Ever. - the GIF committee" "4251": "Not related, but why do you use C over C++? Is it just personal preference?" "4331": "Okay. Can we stay on stream after you end the episode's recording for another try on the story?" "4340": "I'll email you the story, meanwhile, here's two other questions: 1) Which programmers' code would you recommend reading? Let's list Sean Barrett's public github (as well as streams from time to time) to start the list" "4368": "2) When are we covering patching / couple of words on brief basics? I assume it mostly has to deal with asset updates and updates of code that handles them?" "4460": "What was the reason for dismissing the use of fibers early on?" "4498": "Have you made any progress on the licence text for ports to other programming languages?" "4570": "Would it be possible for you to boost the sound of your voice on stream? I've always found that it is barely high enough even with all mixers at maximum volume possible" "4599": "Wrap things up" --- name: "day123" title: "Interlocked Operations" markers: "153": "Blackboard: Thread Synchronization / Communication" "211": "Blackboard: Processes" "248": "Blackboard: Threads" "322": "Blackboard: Problem #1 - Knowing what work to do" "425": "Blackboard: Problem #2 - Sync / When work is done / visible" "675": "Blackboard: Conceptualising how threads work" "754": "Blackboard: Doing a busy-wait loop" "979": "Blackboard: Preventing multiple threads from doing the same work" "1137": "Blackboard: x64 provides special instructions" "1186": "Blackboard: "locked exchange"" "1440": "Blackboard: "interlocked compare exchange"" "1611": "Put on the Pig Hat" "1723": "Blackboard: Being slyfox with the other primitives" "1802": "Blackboard: "reads and writes" in a multithreaded context" "1916": "Blackboard: cache lines" "2374": "Take off the Pig Hat and open the code" "2417": "win32_handmade.cpp: Make four threads that do different work" "2561": "Run Handmade Hero" "2577": "Make the threads look for work to do" "2931": "Run and inspect the debug output" "3017": "Moment of realisation: You need to let ThreadInfo values persist" "3098": "Inspect the output" "3152": "Explain what's happening" "3290": "The writes to EntryCount are not in order" "3424": "The reads are not in order" "3494": "Q&A" "3520": "Is your use of "for (;;)" instead of "while(1)" a stylistic choice or is there a benefit / drawback I'm missing?" "3617": "What's the problem with not being interlocked and seeing the same value, as your "TODO" suggests?" "3759": "Blackboard: Why two threads did the same work" "3929": "Do mutexes that I've seen used for multithreaded code in other places rely on those interlocking instructions, or are they something completely different?" "3983": "What is your opinion on lockless queues?" "4098": "What's the point of an infinite loop to begin with? It ends at some point, doesn't it?" "4126": "What threading libraries do you recommend and why (e.g. boost or pthreads)?" "4177": "What's better: a job scheduler from where each thread can get a job, or separate queues for each thread?" "4245": "Blackboard: "Single producer / Single consumer" vs "Single producer / Multiple consumer"" "4479": "I think that the point of "lockless" is that it doesn't use an operating system-level lock" "4495": "Blackboard: "lock free"" "4606": "Hey Casey, an InterlockedIncrement is a lock-free operation! (The terminology is shitty. The original term is "non-blocking" which is more useful)" "4660": "Is it reasonable to synchronize the receiving of network packets on one synchronized thread?" "4756": "Later in the development cycle, will you go over threading for other operating systems like Mac and Linux?" "4785": "What are the advantages of having a queue of jobs, instead of creating a thread every time you add a job?" "4804": "Blackboard: Overlap vs Performance" "5090": "Recap and glimpse into the future" "5288": "Close things down" --- name: "day124" title: "Memory Barriers and Semaphores" markers: "35": "Recap/Review" "165": "Yesterday's TODOs" "240": "TODO 1: Ordering of writes" "393": "CompletePastWritesBeforeFutureWrites" "622": "Looking up memory fences" "730": "Venturing into Visual Studio's include folder" "800": "Putting in an actual CPU barrier" "872": "Where do we go from here?" "900": "Volatile introduction" "1123": "TODO 2: Interlocked writes" "1210": "Looking up InterlockedIncrement" "1297": "TODO 3: Already taken care of by volatile" "1314": "TODO 4: Ordering of reads" "1404": "Checking our work" "1460": "NB: Don't use all 16 hyperthreads!" "1545": "Job completion" "1720": "Waiting for all the threads to complete" "1850": "Suspending and resuming threads" "2091": "Semaphores" "2248": "WaitForSingleObject for suspending" "2435": "Creating the semaphore" "2664": "Problem: Threads never wake up!" "2810": "Waking up by releasing the semaphore" "3207": "How we'll use the semaphore" "3266": "Testing the semaphore" "3410": "Work for tomorrow" "3433": "Q&A" "3504": "In the visual studio output window you can right click and deselect some of the stuff" "3536": "Why does this have to be so complicated??" "3577": "Why did you put the memory barrier in a macro when it's platform-specific code?" "3607": "After the sleep, some threads still pushed several strings, leaving out some of the other threads" "3656": "Would Sleep(0) in your spin-lock help anything?" "3755": "IMGUI has been trending. Sorry if you get asked this more than you like to." "3787": "When you initially started this project, what were the first 5 things you coded and why?" "3802": "I missed most of tonight, what does the volatile keyword mean?" "3827": "How do you plan to maintain cache line coherency between processors? Can physical CPUs share a cache line?" "3903": "Blackboard: MESI and Cache Coherency" "4455": "Was volatile added in C99?" "4477": "Wait, so transactional memory wants to simplify concurrent programming by allowing a chunk of load/store instructions to execute in atomically. Have you messed with this?" "4505": "Blackboard: Transactional Memory" "4738": "Transactional memory is often advocated as an easier-to-use replacement for locks that avoids any possibility of a deadlock, so I wanted your thoughts." "4864": "Why are we building a generic work distribution when the tiled renderer is designed to cleanly split up the work anyway?" "4965": "Wrapping things up" --- name: "day125" title: "Abstracting the Work Queue" markers: "7": "We are absolute control freaks here, people" "85": "Recap and set the stage for today" "226": "win32_handmade.cpp: Introduce DoWorkerWork" "343": "Let our normal thread do work" "415": "Run and see what the threads are doing" "457": "Follow the compression oriented programming approach" "550": "handmade_render_group.cpp: Figure out a way to do TiledRenderGroupToOutput on multiple threads" "638": "handmade_platform.h: Consider pulling in work_queue_entry" "714": "win32_handmade.cpp: Rewrite PushString as AddWorkQueueEntry" "918": "Note the necessity of _mm_sfence" "973": "Pull work_queue_entry down into the test code" "1038": "Split DoWorkerWork in two" "1234": "Think" "1278": "Put while(EntryCount != EntryCompletionCount) into QueueWorkStillInProgress" "1369": "Rename and finish writing these functions" "1848": "Compile and run and see what the threads are doing" "1874": "Discuss our options" "2071": "Rename GetNextWorkQueueEntry to CompleteAndGetNextWorkQueueEntry and make it take work_queue_entry Completed" "2129": "Rearrange ThreadProc slightly" "2244": "Massage DoWorkerWork" "2271": "Tweak the QueueWorkStillInProgress loop" "2335": "Compile and consider removing one more call" "2412": "Go for it and make the work_queue two separate things" "2662": "Run this again" "2719": "handmade_platform.h: Hoist these functions in" "2761": "Think about this a little bit more" "2831": "handmade_render_group.cpp: Write the usage code first" "3006": "Compile and express hate for const" "3040": "Finish writing TiledRenderGroupToOutput" "3298": "Compile and run and crash" "3322": "Moment of realisation: Gotta increment by the correct value" "3332": "Recap and glimpse into the multithreaded future" "3369": "Q&A" "3455": "Will you start new threads for every queue that you make?" "3569": "Still don't understand the use of volatile and memory barrier" "3593": "Blackboard: Memory and Code Fences" "4066": "Can Entry.IsValid be removed and replaced with a test to see if Entry.Data != NULL?" "4084": "What is your take on Naughty Dog's approach using fibers (+ manual management) and thread affinity to core instead of using classic worker / job approach for multithreaded gameplay?" "4103": "The work queue will take any function to do it multithreaded? Does the function need to be special so that this will work?" "4133": "Please write a lock free queue, even though I don't know what those are and if you used one" "4173": "How many CPU cycles does spawning a thread cost? Or better: what's the minimum amount of cycles to work in 2 threads to gain speed?" "4245": "I don't understand why you call it a queue if it is done potentially simultaneously" "4306": "Wasn't there already a bit of thread-related code in the win32 file?" "4324": "Will you add a cool graph over time that shows what task (e.g. from which subsystem) each thread is working on at each moment?" "4459": "Is false sharing between the entries in the work queue potentially problematic (from a performance standpoint)?" "4474": "Does volatile clear the assembly registers by pushing them into the stack and then restore by popping?" "4496": "Why would you want a compiler fence and not a process fence, and vice versa?" "4541": "Shouldn't _mm_fence() imply a compiler fence? Surely there's no point otherwise..." "4604": "Have you implemented friction?" "4614": "So, thread management is a bit like memory management (in that you want to set it up ahead of time rather than allocating them on-demand)" "4677": "The code to ask how many threads will be done simultaneously by the processor is to be added?" "4715": "Is it possible that a work queue entry spawn another work queue entry?" "4766": "(Not an expert at all, which was part of why I asked the question) False sharing causes the processor to skip the cache when different threads access stuff on the same cache line" "4901": "Actually, I can think of one use case for a compiler fence without a memory fence: writing to CPU special registers like control registers or MSRs" "4954": "Getting back into C/C++ coding after many years. Don't know why you are mixing C-style structs and C++ structs?" "4972": "Close things down" --- name: "day126" title: "Circular FIFO Work Queue" markers: "25": "Owl of Shame: Single producer/Multiple consumer issue" "213": "InterlockedCompareExchange" "260": "Fixing our shame" "379": "Simplifying more with the API change" "540": "Implementing the multithreading API" "762": "Piping the work queue through" "873": "Global defines for AddEntry and CompleteAllWork" "960": "Typedefs for the work queue types" "1110": "Smoothing out the multithreading API" "1450": "Getting compiling again" "1680": "Initializing pointers on game startup" "1717": "Continuing clean-up" "1980": "GetCurrentThreadID for our test code" "2086": "Reviewing/Checking for bugs" "2153": "Problem: Queue never resets" "2160": "Temporary Fix: Reset queue when all work is done" "2344": "Turning the queue into a circular buffer" "2570": "Blackboard: Circular FIFO" "2655": "Implementing the FIFO queue" "3035": "Testing the FIFO queue" "3066": "Debugging the FIFO wrapping" "3350": "Fixing the completion goal code" "3540": "Working multithreaded rendering!" "3743": "Q&A" "3778": "Since the workloads don't complete in order what if one workload takes very long while the other threads wrap around in the queue such that a new workload overwrites the slot with the one that is still running?" "3866": "Now that we're multithreaded, could we compile in debug mode and have the game run at a reasonable framerate?" "4107": "Can we tell how much faster it is now that it's multithreaded?" "4324": "60 FPS test" "4383": "Instead of asserting that the queue doesn't overflow when adding an entry would it be better to just wait for an entry to be read if there's no space to write" "4405": "Would you call this a thread pool?" "4424": "When stepping through multithreaded code all the other threads stop as well, I take it?" "4510": "Can you make the number of threads an in-game configuration option?" "4533": "How long until the renderer is sorted?" "4570": "Is the WeShouldSleep still right after you changed the if condition?" "4675": "Why do you use #if 0 instead of // or /*?" "4749": "Can you show 4k?" "4787": "Q: Is multithreaded code less reliable than singlethreaded code?" "4837": "So is the circular buffer recycling threads after they're done processing a tile? I wasn't clear on why a circular buffer was chosen." "4856": "Power cord bumped, computer shut down" "5060": "(once more) So is the circular buffer recycling threads after they're done processing a tile? I wasn't clear on why a circular buffer was chosen." "5075": "Blackboard: Circular buffers" "5193": "I just saw where you're sleeping threads if there's no work, are you still using semaphores to block and wake up threads or are you sleeping threads?" "5235": "Is the archive going to save this correctly?" "5261": "Would it be easier to implement the queue as a linked list so it has no maximum size? Since we never need to traverse the list it should still be fast." "5336": "In the rolling buffer you check each entry to be filled before writing a new one in and otherwise skip to the next slot?" "5379": "Done for the day." --- name: "day127" title: "Aligning Rendering Memory" markers: "83": "Set the stage for this week" "171": "Demo the problem with the tile size" "244": "Confirm that _mm_sfence is unnecessary" "346": "Blackboard: "Write-Combining Memory"" "823": "Blackboard: Tiles and Alignment" "1262": "Suggest rounding TileWidth and TileHeight to the nearest 4 and aligning the tiles to the 4-byte boundary" "1295": "Think some more, and then unthink it" "1331": "handmade_render_group.cpp: Ensure that we always get aligned tiles" "1407": "Blackboard: Calculating and filling the correct number of 4-pixel units" "1570": "Blackboard: The destination buffer must always allow us to overwrite it by a certain amount" "1789": "Assert that OutputTarget->Memory is aligned to 16-bytes" "1905": "Round TileWidth up to the nearest 4" "1993": "See what numbers we're getting" "2054": "Ensure that FinalTileWidth accounts for the fact that it'll be smaller" "2094": "Remove FinalTileWidth and limit ClipRect.MaxX to the OutputTarget->Width" "2123": "Remove the ClipRect adjustments" "2177": "Run single-threaded for the moment" "2226": "Moment of realisation: We're only clipping to the end, but don't handle clipping at the beginning" "2254": "Blackboard: The clipping problem" "2518": "Align the MinX and MaxX" "2828": "Blackboard: Setting the EndClipMasks" "2904": "Figure out when to use the EndClipMask" "3001": "Compile and see what's happening" "3030": "Reverse the sense of the test and run it again" "3055": "See if we're always aligned" "3076": "Compile in -O2 and turn on multi-threading to ensure everything's still kosher" "3122": "win32_handmade.cpp: Double-check that the platform code is allocating the memory aligned" "3200": "Align Buffer->Pitch to 16-bytes" "3250": "handmade_platform.h: Introduce Align16" "3313": "Everything looks fine at 1920x1080" "3373": "handmade.cpp: Setup the PlatformAddEntry and PlatformCompleteAllWork at the beginning" "3480": "Q&A" "3523": "The bitmap memory size calculation squares BytesPerPixel which allocates more memory than necessary" "3530": "win32_handmade.cpp: Remove the multiplication by BytesPerPixel" "3559": "Can you test if weird resolutions actually are working?" "3633": "handmade_render_group.cpp: Ensure that it goes all the way to the end if this is the last tile" "4026": "handmade.cpp: Hard-set the game's DrawBuffer dimensions to test our support of arbitrary resolutions" "4108": "Will you check for Cache Aliasing? With this much alignment hitting cache aliasing is much easier" "4131": "Cache Associativity aliasing..." "4167": "What about the extra pixel around the edges to deal with bilinear filtering? Will you get rid of that?" "4233": "Compile with that #if 0'd out and glimpse into the future of 4K art" "4310": "Will you keep the rendering of the two lines on separate hyperthreads?" "4413": "So this game is going to be a 4K Zelda 1-style game?" "4483": "Assess our progress and glimpse into the future of tightening up the renderer" "4598": "Shut things down here" --- name: "day128" title: "Push-time Transforms" markers: "73": "Opening things up" "158": "Blackboard: Aligning to cache lines" "601": "Renderer TODOs" "789": "Today's work: loose ends" "969": "Taking a look at coordinate systems" "1027": "Revisiting the basis transform" "1200": "Splitting up the update/render" "1362": "Doing the basis transform on demand" "1773": "Getting rid of the EntityBasis" "2124": "Initializing the transform" "2393": "Translating the calls" "2991": "Finishing up code changes" "3225": "Testing the changes" "3287": "Making render transforms work in debug" "3385": "Musings on the engine so far" "3471": "Q&A" "3545": "Everything works the first time because you think out loud." "3591": "Does the yellow part represent the loaded bitmaps?" "3740": "What does it mean to invalidate cache?" "3750": "Blackboard: Cache invalidation" "4137": "Could you summarize what you did tonight? Found it a little hard to follow along." "4258": "Could you explain what is meant when one says something is done serially?" "4393": "I missed a bit of the stream after you removed scale. Didn't you use that for scaling by Z?" "4466": "What's happening between staircase passing in the bitmaps? Is it simple scaling based on the Z axis?" "4713": "How many FPS is this running at?" "4763": "To make the 3D appearance of the staircase, would you have to make render technique to draw the walls of the staircase to start from the bottom floor and end at the top floor?" "4781": "When do you consider consulting other programmers? Where is the threshold?" "4832": "What happens if you want to apply different transforms or lighting to different parts of a scene?" "4874": "What do you expect will be the boost using OpenGL/D3D for blitting?" "4911": "Is there a concept of local space / model space / camera space / clip space in the renderer that is analgous to the kinds of translations in OpenGL/D3D that you would want?" "4995": "Unrelated to the stream, I found a video where you explain quaternion double cover, but there is no explanation of quaternions. Would you consider doing on in the near future?" "5060": "Finishing it up" --- name: "day129" title: "Adding Orthographic Projection" markers: "63": "Recap and set the stage for today" "112": "handmade.cpp: Turn off the debug lines" "192": "Blackboard: Why ground tiles are no longer seamless now that we're doing perspective transforms" "403": "Blackboard: Doing the displacement with perspective transform" "473": "Take a look at how FillGroundChunk is working" "718": "Propose addressing GroundBuffers in terms of coordinates that mean something in the real world" "791": "Walk through FillGroundChunk" "882": "Consider telling the renderer to use the perspective transform" "1004": "Start by writing an API call to the renderer to enable seamless ground tiles using orthographic transform" "1159": "Provide the ability to switch between perspective and orthographic" "1320": "handmade_render_group.cpp: Write Perspective function" "1431": "Write Orthographic function" "1542": "Consider how to allow Perspective and Orthographic to flow through the pipeline" "1583": "Force them to be rectilinear" "1674": "Clean up and compile before moving on" "1728": "handmade.cpp: Make the orthographic version work" "1771": "handmade_render_group.cpp: Write at orthographic path in entity_basis_p_result" "1939": "handmade_render_group.h: Introduce bool32 Orthographic" "2069": "Take a look in-game" "2089": "handmade_render_group.cpp: Walk through entity_basis_p_result" "2134": "Correct OriginalP to P" "2162": "handmade.cpp: Consider what PushBitmap is doing in FillGroundChunk" "2268": "handmade_render_group.cpp: Ensure that MetersToPixels is being calculated correctly" "2308": "Debugger: Step in and see what's happening in Orthographic" "2502": "Moment of realisation: The Scale cannot be 1.0f" "2562": "Debugger: Step into FillGroundChunk" "2694": "Are we doing PixelsToMeters and MetersToPixels backwards?" "2778": "handmade.cpp: Correct the Pixels / Meters calculation in Orthographic" "2800": "Take a look in-game" "2897": "handmade.cpp: Walk through FillGroundChunk" "2952": "Make it splat in a more concentrated area and turn back on the debug lines" "3028": "Splat about half the space and note that there doesn't appear to be 100 things in that tile" "3043": "Return to splatting the whole tile and tweak the sizes" "3119": "Take a look at the seams" "3170": "Create a checkerboard pattern to accentuate the seams" "3287": "See the seams" "3345": "build.bat: Switch to -O2 and run around the world" "3384": "Q&A" "3438": "When do we make everything hardware accelerated to get the amazing powers of ROTATION?" "3476": "handmade_render_group.cpp: Demo rotation" "3647": "Will we see how to find "expensive" functions that are called between frames? So far we SIMD only the pixel renderer right now, because we know" "3715": "I'm so sorry, Casey-sama" "3780": "Can you briefly go over the rest of what we're going to do to the engine before we start implementing gameplay code?" "3862": "This will all be very game-codey" "3952": "Right now to get more performance out of the render you multithread it to render the screen in chunks. GPUs are parallel by design so how do these two concepts differ?" "3988": "Blackboard: Tiled vs Non-tiled GPUs" "4200": "If there are no better questions, wouldn't the solution to internally link objects in an arbitrary amount of linked lists be performance problematic? Or is there a smart solution I am missing here?" "4243": "I feel like the GroundChunks move faster than the trees on the same plane" "4264": "The gaming industry is too hard to enter. Why do potential programmers waste their time?" "4292": "There's a lot of mug action going on. Are you one of those coffee-blooded programmers?" "4306": "I am about to commence studying a degree in Computer Science. I love gaming, and the concept of creating them is fairly interesting, though I am not entirely mathematically inclined. This being the case, would you suggest I stay away from Game Development and steer toward my original plan of Software Engineering?" "4352": "I have Ruby and JS background and I was wondering if you normally do unit testing / behavioral testing in game development, or is it just too hard because of visual elements?" "4421": "On your site you responded to the question, "Why are you doing this project?" with: "Game programmers need to start creating high-quality teaching materials for their trade." How much progress have you made towards developing the twitch VODs into high-quality teaching materials?" "4464": "Do we know how many ms per frame we have right now for the game logic? So far we push 60 FPS but it's hard-locked and maybe we already have some room for game logic?" "4520": "Will everything be programatically animated or will it be done by an artist? Or both?" "4531": "Do you have a YouTube channel?" "4553": "Can you show a snippet where you implemented a hash table?" "4643": "If Vulkan is out by the time you hardware accelerate the renderer, would it be possible to use Vulkan?" "4662": "Why do you think Microsoft decided to omit the 1080i resolution option for the XBox One? Do you think it was too difficult for them to include?" "4678": "Do you plan on commenting the code before releasing the engine?" "4764": "It's just insane that we can have so many laggy games today when CPUs / GPUs are that fast... Thank you for bringing some light into the reasons for that (bad programming and/or languages)" "4979": "Is unsafe memory key for high-performance optimizations needed for modern-day games? I've heard this is the key reason memory-safe languages like Rust and Haskell won't be able to take over for extremely low-latency applications or drivers, but I don't know enough about the domain" "5141": "Shut things down" --- name: "day130" title: "Seamless Bilinear Tiling" markers: "20": "Recap" "108": "Where we left off" "220": "Isolating the bug" "420": "Checking for chunk abutting" "550": "Formalizing the texture boundaries" "625": "Blackboard: Bilinear filtering for things in tiles" "1052": "Fixing the texture sample" "1098": "Blackboard: Thinking through the sample" "1512": "Biasing the sample location" "1710": "Checking the sample bias" "1885": "Ground chunk aprons" "1999": "Blackboard: confirming the apron math" "2056": "Accounting for the apron" "2250": "Work to do on the ground chunks" "2402": "Putting back the debug camera" "2580": "Filling ground chunks multithreaded" "2582": "Adding a low priority queue" "3120": "Problem: ground chunks need to be aligned" "3245": "Adding the ground chunk work to the queue" "3405": "Abort mission, not enough time" "3444": "Crash due to alignment problems" "3600": "Q&A" "3650": "Good stream today. Sometimes it goes really great" "3681": "The Ground Chunks render differently every time you go upstairs and come back down. Are you planning on fixing that before Z-sorting?" "3728": "Can you address the recurring question: "This stream isn't about making games?" I'm tired of trying to explain what this stream is about" "3925": "How long have you worked on this project?" "3961": "How are you deciding what gets queued or not, and high vs low?" "3980": "How are you going to implement seamless tiles with what Yangtian Li creates?" "4017": "I don't see any object oriented patterns. Are you using object orientation?" "4028": "I assume the Yellow/Cyan/Magenta squares are for debugging. What do they represent?" "4126": "You always say "we", who is "we"?" "4163": "You say "3 work weeks" but do you feel like you could maintain this pace 8 hours a day?" "4251": "It seems like the ground chunks are only getting generated when they would actually be visible, not before. When you get the ground chunk into the low priority queue, will empty ground be visible for 1 or 2 frames while they are being generated?" "4297": "Do you think at the end / near end, someone like Jon Blow would be interested in making a game with the Handmade Hero engine in a similar format to see how the game design phase evolves the engine? I know at Pixar they get new and interesting results with unplanned collaboration between artist and engineer" "4342": "Wrap things up" --- name: "day131" title: "Asynchronous Ground Chunk Composition" markers: "160": "Run the game and identify our slight problem" "262": "Why we couldn't generate the ground chunks on a separate thread" "407": "handmade.h: Allow PushSize_ to take an Alignment" "495": "Introduce AlignmentMask" "613": "Blackboard: Turning a power of 2 into a mask" "783": "Set the AlignmentOffset based on the AlignmentMask" "1007": "Go over PushSize_ one more time" "1077": "Debugger: Step through PushSize_" "1128": "handmade.h: Add ## __VA__ARGS to these Push* definitions" "1258": "handmade.cpp: Pass 16 to this PushSize call and run the game" "1317": "Consider queueing up all of FillGroundChunk" "1396": "Turn off TiledRenderGroupToOutput" "1420": "handmade_render_group.cpp: Switch to the player's camera and walk around" "1452": "On leaving part of what we're doing synchronous" "1548": "Provide a temporary storage area to enable the background task to work without the data getting overwritten" "1631": "handmade.h: Introduce GroundChunkArenas" "1735": "Introduce task_with_memory" "1798": "handmade.cpp: Create a bunch of Tasks which each create a SubArena" "1907": "Look at how FillGroundChunk works" "1948": "handmade.h: Make it implicit in task_with_memory that the memory is temporary" "1988": "handmade.cpp: Implement BeginTaskWithMemory and EndTaskWithMemory" "2050": "Do FillGroundChunk if BeginTaskWithMemory is true" "2161": "Write BeginTaskWithMemory" "2328": "Put TiledRenderGroupToOutput on the background threads" "2413": "handmade_render_group.cpp: Introduce RenderGroupToOutput as a non-tiled version" "2541": "handmade.cpp: Call RenderGroupToOutput" "2667": "handmade_intrinsics.h: #define CompletePreviousWritesBeforeFutureWrites" "2720": "handmade.cpp: Clean up" "2751": "Do AllocateRenderGroup from &Task->Arena" "2815": "Introduce fill_ground_chunk_work" "2871": "Put fill_ground_chunk_work into PLATFORM_WORK_QUEUE_CALLBACK" "2910": "Put fill_ground_chunk_work into FillGroundChunk and fill it out at the end" "2954": "Call PlatformAddEntry" "2994": "handmade.h: Implement GetArenaSizeRemaining" "3098": "Introduce GetAlignmentOffset" "3177": "Calculate that Result in GetArenaSizeRemaining and clean up" "3265": "handmade.cpp: Cast GetArenaSizeRemaining to uint32 in FillGroundChunk" "3372": "handmade.h: Implement SubArena" "3521": "Walk through our new functionality" "3600": "Debugger: Start stepping through the code" "3892": "Debugger: NextInHash is not valid" "3952": "handmade.h: Put the += Size in the correct spot in PushSize_" "3986": "Debugger: Identify that MaxPushBufferSize needs to take PushStruct into account" "4007": "handmade_render_group.cpp: Conditionally set MaxPushBufferSize in AllocateRenderGroup" "4080": "Debugger: Continue stepping through and note that the TempCount is 2" "4118": "handmade.cpp: Set Task->BeingUsed = true in BeginTaskWithMemory" "4132": "Run the game successfully" "4172": "handmade_render_group.cpp: Reenable the debug camera" "4273": "Q&A" "4322": "If one of the task_with_memory, which has several task_with_memory in front of it, calls EndTaskWithMemory first, will the stuff in front of it be screwed up? Or is this case not possible? Because I have a feeling that I don't understand something" "4348": "Blackboard: What goes in the arenas and how they work" "4489": "We already had memory reserved for the GroundBuffers. Why couldn't we just use that memory for the threaded stuff?" "4570": "What are the lines on the screen?" "4618": "win32_handmade.cpp: Set OffsetX and OffsetY to 0 in Win32DisplayBufferInWindow for now" "4769": "So you've basically constructed a task pool for ground chunks to run on another thread. Can you use this mechanism for other types of tasks as well?" "4789": "Why not put the stuff at the top of the transient arena (i.e. ground chunk bitmaps) into the permanent storage?" "4809": "Why does it flash magenta once in a while? Is it because we're drawing without the work being finished?" "4840": "Wrap things up" --- name: "day132" title: "Asset Streaming" markers: "86": "Recap" "115": "Hidden stall: Asset loading" "275": "Considerations for asset loading" "433": "Types of assets" "720": "Moving out assets into a single place" "850": "Breaking up asset types" "940": "Problems: data must be available, direct reference" "1048": "Pulling out static bitmaps with IDs" "1340": "Stopgap for other asset types" "1423": "Extending PushBitmap to take an ID" "1825": "Removing a failure case" "1993": "Allocating space for the bitmaps" "2410": "Deferred asset loading" "2495": "Loading one asset at a time" "2972": "Loading assets on demand" "3022": "Background loading assets" "3262": "Anticipate mr4thdimention's editor 4coder" "3511": "Cleaning up" "3614": "We background-load now" "3661": "Q&A" "3680": "Is it useful when assets can be modified from outside (file on disk overwrite, maybe even in memory) and still work in-game? Is it now supported after an asset is loaded, as I could not see any callback to check if a file is modified, as your glazing speed refactoring was way too fast for me?" "3770": "In load_asset_work, where is the memory for the filenames stored?" "3870": "What are the trade-offs to give him more power forcing render pushes out of the rendering queue order?" "3883": "You said we got asset streaming done in an hour, but do we need to do multiple passes on it? If so, why?" "3964": "Where you check if an asset is already loaded or not, if an asset would take a very long time to load, would it check if it's loaded again to try to load the asset again? Not sure if that makes sense" "4089": "Do you consider terrain an asset too so that it can stream?" "4112": "Why: "if (Task) { work }" versus "if (!Task) return; work"?" "4179": "What are the trade-offs to give him (the rendering queue) more power forcing render pushes out of the rendering queue order when it is multi-threaded so the rendering can be controlled more fine-tuned? You where thinking about that in the stream" "4311": "How much of the DirectX / OpenGL typical pipeline are you pre-emptively designing in to your code now?" "4368": "What do you think about Microsoft's _vectorcall as a calling convention for speed?" "4504": "Is it possible for the OS to lose track of memory that you ask for?" "4559": "Could you elaborate on OpenGL and DirectX death?" "4657": "What would be a good way to expand asset streaming to support increasing level of details? (What I'm thinking of is loading a smaller version of the asset first and then the bigger size resources)" "4764": "I recently started from the beginning of the series (on 13 atm). Do you suggest watching all of the Q&As or just going episode -> episode?" "4838": "How infuriating is it to deal with massive asset pipelines dealing with dozens of pieces of software on a large AAA project?" "4968": "Call it a day" --- name: "day133" title: "Preliminary Asset Structuring" markers: "157": "Recap and set the stage" "319": "Blackboard: "One in, One out"" "466": "Blackboard: Only load once!" "556": "Outline our tasks for the day" "605": "handmade.cpp: Get TopDownAlignY back in" "739": "Run the game to see the correct alignment" "747": "handmade.h: Make things only load once" "845": "handmade.cpp: Check to see if the asset in question is loaded" "974": "handmade_intrinsics.h: Introduce AtomicCompareExchangeUInt32" "1145": "Compile and run" "1181": "FillGroundChunk will render incorrectly if the bitmap to be composited doesn't exist" "1302": "handmade.cpp: Only mark the ground chunk as having been filled once we know it has been" "1339": "handmade_render_group.cpp: Introduce AllBitmapsValid (AllResourcesPresent)" "1430": "Add MissingResourceCount to render_group" "1471": "Problem: With ground chunks being rendered on a separate thread, they could potentially be evicted at the wrong time" "1549": "Possible solutions to this problem" "1689": "handmade_render_group.cpp: Introduce CleanupRenderGroup" "1812": "handmade_render_group.h: Add game_asset_id to render_entry_bitmap" "1887": "handmade_render_group.cpp: Introduce UnlockAsset in CleanupRenderGroup" "1939": "Introduce LockAsset in PushBitmap" "1989": "Assess this locking implementation and undo it" "2226": "handmade.h: Introduce AssetState_Locked in asset_state" "2286": "Add asset_state FinalState to load_asset_work" "2343": "handmade.cpp: Assess what DEBUGLoadBMP is doing and consider what to do next" "2532": "handmade.h: Expand the notion of game_asset_id to be more generic" "2595": "Introduce asset_bitmap_info" "2664": "Introduce asset_tag" "2708": "Talk about creating a table of assets which provides semantic information to the code" "2782": "handmade.cpp: Discuss how this semantic information could be used by the world generation code" "2889": "Assets: Take a look at the art assets" "2946": "handmade.cpp: Introduce PickBest to rank assets according to the given criteria" "3219": "Explain how PickBest could work" "3350": "handmade.h: Introduce asset_group" "3410": "Get it compiling and leave it for now" "3440": "Q&A" "3458": "In PickBest, would you want other types of falloffs when computing the difference?" "3477": "When compiling for 64bit, shouldn't you be using _InterlockedCompareExchange64?" "3509": "In your example of having 32 GB of assets uncompressed and 2 GB of space for them, are there techniques you can use to tell whether you will need more than 2 GB at one time?" "3584": "Can you summarize what you've done from the artist's perspective? Did you add a (light) obligation to the contract between the programmer and the artist?" "3662": "If you can't evict locked resources, what would be the point of streaming them over just loading them up front, and doesn't it put a restraint on the diversity of the environments you can have?" "3762": "Shouldn't you fill Work completely before calling PlatformAddEntry for LoadAssetWork?" "3803": "handmade.cpp: Move PlatformAddEntry after the switch statements in LoadAsset" "3846": "I may have missed this, but do you have the ability to set a hard limit on memory usage yet, e.g. so you know you can support lower memory machines?" "3889": "In a prior episode you implemented bilinear filtering. Are you going to take it a step further and implement mipmapping and trilinear filtering?" "4012": "Will the assets loaded in from a file be stored and evicted in the same way as the ground chunks?" "4038": "Song: 'Are There Questions?' by Casey Muratori" "4070": "Why only .bmp?" "4144": "The eviction stuff you're doing, is it basically garbage collection?" "4240": "Will we be using AMD hair physics?" "4327": "If you turn a bitmap black and white by altering the pixel, then would you have two copies of the bitmap? Would you delete one if you have two?" "4462": "Why do people care so much about garbage collection?" "4469": "Why use a pack-file instead of bmps? What makes it "better"?" "4581": "Earlier someone asked why reimplement virtual memory on top of the OS's virtual memory. Are we doing this just so we can have "more" virtual space?" "4665": "Are the ground chunks going to be pre-composited when using the GPU?" "4682": "Is there a reason why you split the character into three bitmaps?" "4692": "Is the rendering going to be eventually done on the GPU?" "4745": "Are game saves going to be part of that asset pack-file, or their own pack-file?" "4823": "Song: 'Q's & A's' by Casey Muratori" "4839": "Does porting the rendering to be done on the GPU mean you have to write a renderer completely separate to the CPU one, or is most of the groundwork done by having the CPU renderer done?" "4944": "I thought you hated both DRM and cloud-based stuff (based off of Jeff and Casey Show)" "5040": "Go get some ramen" --- name: "day134" title: "Mapping Assets to Bitmaps" markers: "30": "Recap" "110": "Review of PickBest" "354": "Looking at how tags might be set up" "530": "Structuring assets more generally" "1123": "Creation of handmade_asset.h" "1384": "Creation of handmade_asset.cpp, writing AllocateGameAssets" "1538": "Cleaning up compile errors" "1613": "Splitting LoadAsset" "1828": "Resuming compile error cleanup" "1855": "Moving DEBUGLoadBMP to the asset system" "2095": "Converting between assets and bitmaps" "2240": "Setting up stopgap bitmap loading" "2386": "Nuking thread_context and moving out ReadEntireFile ptrs" "2715": "Fixing the bugs that got through compile" "2762": "Loading bitmaps using type info" "3260": "Debugging missing trees" "3305": "There's a Count and a range" "3611": "Q&A" "3646": "You won't be using any formal database for the game, correct? Why?" "3869": "Is there any way I can download these episodes to watch on the go?" "3948": "Why code is C as opposed to Java?" "3973": "ssets include compressed sprite sheets, audio, video and bone rigs?" "4043": "handmade.h: Make it incumbent upon the game to set IsInitialized" "4309": "How on earth do you procedurally generate character movement?" "4403": "Can you run cloc.exe again?" "4459": "Have you ever used Unity3D? If so, would you recommend it?" "4464": "What advice do you have for relatively new programmers who are trying to ditch the OOP mindset and move onto things like Data Oriented Design and Compression Oriented Design?" "4956": "Wrap things up" --- name: "day135" title: "Typed Asset Arrays" markers: "140": "Recap the creation of handmade_asset.cpp" "275": "handmade_asset.cpp: Make the arrayed assets go through the asset system" "331": "Provide a stable way to define AlignX and TopDownAlignY with the bitmaps" "550": "handmade_asset.cpp: Remove superfluous asset types" "617": "Debugger: Read out the alignments for the bitmaps" "650": "handmade_asset.cpp: Replace AlignX and TopDownAlignY with AlignPercentage for each asset type" "728": "Remove this DEBUGLoadBMP call and edit an earlier DEBUGLoadBMP call to take into account these changes to AlignPercentage" "766": "Get rid of TopDownAlign" "807": "Run the game" "830": "Consider our current options for cleaning this up while we still don't have a pack file" "905": "handmade_asset.h: Change the structure of asset_bitmap_info" "1006": "handmade_asset.cpp: Allocate a ton of bitmaps for testing purposes" "1033": "Introduce DEBUGAddBitmapInfo" "1179": "Create assets dynamically in AllocateGameAssets" "1367": "Pull out BeginAssetType, AddBitmapAsset and EndAssetType into functions" "1547": "handmade.h: TODO(casey): Optional "clear" parameter!!!!" "1570": "handmade_asset.cpp: Continue writing these functions" "1785": "Debugger: Step through these functions" "2025": "Run the game" "2039": "handmade_asset.cpp: Get the Grass, Tuft and Stone bitmaps using this new system" "2093": "handmade.cpp: Introduce id-based picking of assets" "2193": "handmade_asset.cpp: Introduce RandomAssetFrom" "2298": "Run the game" "2358": "Debugger: See what the asset tables look like" "2397": "handmade_asset.cpp: Add the first asset in RandomAssetFrom" "2453": "Run the game and note the absence of trees" "2544": "handmade.cpp: Investigate this absence of trees" "2607": "handmade_asset.cpp: Determine whether LoadBitmap is thread-safe" "2677": "Use the asset_bitmap_info table" "2753": "handmade.cpp: Re-enable PushBitmap" "2796": "Debugger: Step through LoadBitmap and RandomAssetFrom" "2899": "Inspect the assets" "2997": "handmade_asset.cpp: Add the Choice rather than the Count in RandomAssetFrom" "3034": "Run the game and wonder why it was failing" "3106": "handmade_asset.cpp: Finish off the asset array set" "3153": "handmade.cpp: Set Stamp from RandomAssetFrom" "3226": "Run and note the absence of ground chunks" "3261": "handmade.cpp: Write the fail case for AllResourcesPresent" "3324": "Debugger: Look through FillGroundChunk" "3371": "handmade.cpp: Setup RenderGroup, Buffer and Task near the top of FillGroundChunk" "3416": "Run the game and recap today's progress" "3485": "Q&A" "3522": "What do you mean when you say to write "usage code first"? Also, is there any special handling of Asset 0? I am unclear on this" "3645": "You used some uint32_t in t here instead of uint32" "3701": "Are you expecting a new batch of art from Yangtian?" "3721": "Are you gonna eventually downgrade the graphics to stir up some controversy and get the game talked about on NeoGAF and Reddit?" "3792": "What are some example changes to the gameplay that would require changes to the tags?" "3833": "What certifications do you have?" "3864": "Do you ever feel sleepy when it's taking you a long time to solve a bug?" "3881": "Are you going to show the asset pipeline tools programming on stream?" "3932": "I missed the pre-stream. Did you talk about APIs like you said you would on twitter?" "3951": "What reason is there to use size_t other than int32 or uint32?" "4020": "Do you plan on implementing HTC Vive and Lighthouse support for whatever reason?" "4052": "If the asset pipeline won't be done on stream, will you still release the source for it?" "4123": "Will you do a separate isolated session on databases (mentioned yesterday)? I would love to hear your thoughts on that" "4152": "Will you talk about APIs now?" "4170": "HTC is handing you $500,000: are you doing Vive support now? Hmm? HMMM??" "4249": "Will you accept Chromatic Aberration as the best post-processing thing ever conceived?" "4371": "Why don't you support DirectInput8 for supporting good old USB controllers, instead of just Xbox360 controllers?" "4416": "If the people in this chat collectively give you $500K, will you implement VR?" "4447": "Rant: APIs, with the assistance of Dependency Walker" "5265": "Seems to me nobody at Microsoft has any idea about why Windows is still even working properly" "5543": "Isn't the huge amount of the dependencies an inevitability of complex software like a modern full OS for productivity desktop?" "5733": "Do you know that your channel runs ads for an eSports gambling site?" "5789": "Wrap it up" --- name: "day136" title: "Tag-based Asset Retrieval" markers: "40": "Recap" "82": "Casey has an itch" "103": "Goals for the asset system" "508": "Looking at the Hero Bitmaps" "649": "Classifying hero parts" "765": "Classifying facing directions" "858": "Requesting assets by tags" "1231": "Using BestMatchAsset for the HeroBitmaps" "1544": "Loading in the hero parts" "1724": "Tagging hero parts by direction" "2113": "Revisiting FacingDirection" "2197": "Blackboard: Supporting different comparison functions" "2515": "Using the actual facing direction angle" "2700": "Debugging broken directions" "2998": "Temporary fix: Shift the domain" "3075": "Tomorrow's task: Correct periodic handling" "3117": "Q&A" "3136": "It's a bit delayed, so bear with us" "3174": "Could all tag matching be periodic and then we just make the period really large when we don't want it to wrap?" "3242": "The hero has separate bitmaps for his sprite. Will this be a recurring thing for other kinds of sprites in the game?" "3285": "From a scale of 1-10 how dumb do you think the Windows API is?" "3345": "For getting the angle you want couldn't you just divide the angle by 45, giving you a number to switch on? You could go a step further and take the modulus of the number of angles you want" "3382": "Tau is clearly the superior constant. Please remove every instance of Pi in the code!" "3535": "What is your opinion on people who use spaces instead of tabs?" "3563": "hy did you use A tangent of the angle for determining the asset?" "3573": "Blackboard: Looking up an art asset" "3889": "How many spaces: 2, 3 or 4?" "3904": "Will you implement asset loading priority? For example, the player should probably load first so that you're not invisible in the beginning" "3931": "Would it be a good idea to switch to using Matrices for Rotation (so further down the line it's easier to implement scale and transform)?" "4000": "Maybe this is something I missed, but are you using cmath's atan2?" "4050": "Call it" --- name: "day137" title: "Matching Periodic Tags" markers: "108": "Demo a bug in the asset system" "185": "Blackboard: Periodic Tag Matching" "441": "Blackboard: "Neighbourhood operator"" "620": "Blackboard: "Neighbourhood distance"" "810": "Blackboard: Changing the sign of a point in the negative range in order to compute the distance of it from a point in the positive range" "923": "Blackboard: Moving a positive number into the negative" "981": "Blackboard: The whole equation for doing this neighbourhood calculation" "1211": "handmade_asset.h: Add HalfTagRange to game_assets" "1268": "handmade_asset.cpp: Set the HalfTagRange for each TagType" "1331": "Use the HalfTagRange in BestMatchAsset" "1406": "handmade_intrinsics.h: Write a real32 version of SignOf" "1417": "handmade_asset.cpp: Continue adding (Half)TagRange to BestMatchAsset" "1522": "Debugger: Step into BestMatchAsset" "1571": "Play the game and check out our new functionality" "1603": "We're kind of done" "1680": "handmade_asset.cpp: Add *FileName[] in order to loop over the bitmaps and set TopDownAlign" "1819": "Debugger: Look at the alignments" "1970": "handmade_asset.cpp: Bake that calculated alignment into the hero bitmaps" "2014": "Run the game and check out the correct alignments" "2042": "Start talking about the asset file format" "2136": "handmade.h: Add two items to the Asset streaming TODOs, and prioritise Audio" "2231": "handmade_asset.cpp: Introduce LoadSound" "2639": "Introduce DEBUGLoadWAV" "2697": "Internet: Bring up the WAVE specifications" "2743": "Blackboard: "IFF" file format" "2925": "handmade_asset.cpp: Introduce WAVE_header" "3032": "Introduce WAVE_fmt" "3158": "Introduce WAVE_chunk" "3183": "#define RIFF_CODE" "3312": "Parse the WAVE_header for its IDs" "3394": "Leave it there and glimpse into the future" "3478": "Q&A" "3510": "For getting the character sprite couldn't you just do the following? int sprite_to_load = (angle + (180 / sprites)) / (360 / sprites) % sprites" "3599": "ChronalDragon and I had a combined question about the audio asset struct. Will it need a SoundLoopable, or LoopStart / LoopEnd (with LoopEnd == -1 meaning a one-shot sound)" "3640": "Plans for implementing other audio formats like MP3?" "3785": "Wait, how exactly is MP3 patented?" "3888": "Yeah, but why would people patent a file extension?" "3932": "FLAC is 50% the size of WAV, so it's useful for lossless compression" "4116": "So is that why RAD doesn't patent any of their stuff?" "4136": "Wind things down" --- name: "day138" title: "Loading WAV Files" markers: "66": "Assets: handmade_hero_test_assets_003.zip is released" "177": "handmade_asset.cpp: Correct a mistype in WAVE_fmt" "267": "handmade.cpp: Do a DEBUGLoadWAV call in GameUpdateAndRender" "320": "Debugger: Step in to DEBUGLoadWAV" "369": "Fall foul of Microsoft Visual Studio" "453": "handmade_asset.cpp: Introduce riff_iterator to use in DEBUGLoadWAV" "628": "handmade_asset.cpp: Add WAVE_ChunkID_data to RIFF_CODE" "719": "handmade_asset.cpp: Continue on writing the usage code for DEBUGLoadWAV" "787": "handmade_asset.cpp: Introduce ParseChunkAt" "834": "handmade_asset.cpp: Introduce NextChunk" "949": "handmade_asset.cpp: Introduce IsValid" "998": "handmade_asset.cpp: Continue on writing DEBUGLoadWAV" "1045": "handmade_asset.cpp: Introduce GetChunkData" "1124": "Debugger: Step in to DEBUGLoadWAV" "1316": "handmade_asset.cpp: Remove Chunk from riff_iterator and ParseChunkAt, and instead use it in NextChunk and GetType" "1361": "Debugger: Continue on stepping through DEBUGLoadWAV" "1408": "Internet: Try and determine whether the RIFF file should end in zeros" "1610": "handmade_asset.cpp: Pad the Chunk->Size if it is odd" "1665": "handmade_asset.cpp: Subtract 4 from the Header->Size" "1721": "Debugger: Step through DEBUGLoadWAV and find that we're correctly iterating over the chunks" "1749": "handmade_asset.cpp: Assert certain data to be valid" "1808": "Internet: Find out what nBlockAlign means" "1877": "handmade_asset.cpp: Assert nBlockAlign to be 2 * nChannels" "1908": "handmade_asset.cpp: Set the ChannelCount and SampleData" "1969": "handmade_asset.cpp: Assert ChannelCount and SampleData to be valid" "2021": "handmade_asset.h: Add ChannelCount to loaded_sound" "2067": "Internet: Try to establish how to determine the sample count minus any rounding" "2099": "handmade_asset.cpp: Compute that SampleCount" "2145": "handmade_asset.cpp: Introduce GetChunkDataSize" "2192": "handmade_asset.cpp: Create arrays for our SampleData" "2277": "Blackboard: Deinterleaving audio channels in place" "2655": "handmade_asset.cpp: Write out the swizzling algorithm for the left channel" "2799": "handmade_asset.cpp: Spam in some test data" "2941": "Debugger: Check out the values in the right channel" "3047": "handmade.cpp and handmade.h: Reenable tSine" "3128": "handmade.h: Introduce loaded_sound TestSound" "3191": "handmade.cpp: Comment out GameOutputSound and use TestSound" "3322": "Run the game and hear that it doesn't sound very good" "3362": "Debugger: Step through the SampleIndex loop" "3408": "handmade.cpp: Make the Sample data be int16" "3447": "Run the game and still hear the clicking" "3470": "Listen to the sound" "3521": "handmade.cpp: Read through the SampleIndex loop" "3577": "Debugger: Step in and inspect the SampleData" "3664": "Internet: Take a look at PCM Data" "3718": "handmade_asset.cpp: Remove the test code" "3749": "Run the game and hear it more correctly" "3762": "build.bat: Switch to -O2" "3789": "win32_handmade.cpp: Set GameUpdateHz to MonitorRefreshHz / 2.0f" "3801": "Run the game and hear it all playing correctly" "3839": "handmade.cpp: Play music_test.wav" "3856": "Q&A" "3885": "You could try uninterleaving the channels in place like this: http://imgur.com/ZcDu4Tb" "3950": "Probably the second-easiest way to deinterleave is multi-pass. Swap R0/L1, R2/L3, L4/L5 etc. Then do the same with two-sample blocks, four-sample blocks, etc. Easiest way is to deinterleave directly into mix/output buffer." "3978": "Why do you need to un-interleave sound? When you play it, you still have to read both left and right values" "3999": "People are asking about the benefits of extern C? What issues does it address?" "4123": "Casey, can you please explain: (Chunk->Size + 1) & -1 ?" "4454": "Why are the samples interleaved and not flat?" "4518": "If you think of your interleaved data as an Nx2 matrix, then transposition can be viewed as interleaving. Here is an in-place way to do it: https://goo.gl/fgPmrg" "4568": "Thank you" "4685": "Why do you want to change the PCM data in place instead of compacting it to just the information you need and allocating extra space?" "4749": "Wrap it up" --- name: "day139" title: "Introduction to Sound Mixing" markers: "19": "Deciding to do an audio mixer" "258": "Blackboard: Sound and Music" "300": ""The world is filled with molecules"" "549": "Blackboard: How we hear" "653": "Blackboard: Frequency" "1139": "Blackboard: Amplitude" "1652": "Blackboard: Doing this process from the software side" "1834": "Blackboard: Mixing sounds by adding them together" "2223": "Blackboard: Optionally increasing the complexity" "2289": "Blackboard: Clipping" "2622": "Blackboard: Modulation and Interpolation" "3014": "Blackboard: Pitch" "3377": "Blackboard: Set the stage for tomorrow" "3478": "Q&A" "3502": "You said panning is just a function of volume, but could it also mix a portion of one source channel into the other output channel (for stereo)?" "3788": "Earlier in the stream you were describing audio in relation to light and you mentioned how sound is volumetric. But isn't light also volumetric?" "4328": "No special sound effects such as reverb?" "4362": "Are you going to do any work with sound analysis or visualization using FFTs? Do have any experience with that kind of stuff?" "4404": "Is their any need for an equalizer for the game's engine? I assume it would be trivial to implement." "4494": "Won't we also want at least a low-pass filter for audio coming from, for example, the other side of a wall?" "4550": "Some older sound cards could do cross-talk cancellation to try to do 3d sound with 2 or 4 speakers instead of with headphones, do you have any experience with this?" "4567": "What is a good way to get sound to bounce off objects more realistically? (i.e., walls, cars, etc.)" "4642": "Call it a day" --- name: "day140" title: "Implemented a Sound Mixer" markers: "86": "Recap and set the stage for the day" "264": "handmade.h: Introduce playing_sound and add a pointer to it in game_state" "475": "handmade.cpp: Setup the PlayingSound loop" "612": "Blackboard: Working in a 32-bit depth mixing buffer" "703": "handmade.cpp: Introduce RealChannel0 and RealChannel1" "776": "handmade_asset.h: Introduce loaded_sound" "802": "handmade.cpp: Call loaded_sound and sum the Samples in our loop" "1112": "handmade.cpp: Loop over the summed sounds, read out of them and write them to the SampleOut buffer" "1341": "handmade.cpp: Introduce SamplesToMix and SamplesRemainingInSound to handle the finite nature of the audio" "1528": "handmade.h: Add playing_sound *FirstFreePlayingSound to game_state" "1551": "handmade.cpp: Use that FirstFreePlayingSound in the PlayingSound loop" "1583": "handmade.cpp: Snap the Next pointer earlier in order to protect against the act of having it freed screw up our iteration" "1680": "handmade.h: Introduce the concept of a MetaArena" "1871": "handmade_asset.h: Add audio assets to asset_type_id" "1930": "handmade_asset.cpp: Extend the asset loading to handle audio" "2067": "handmade_asset.cpp: Introduce AddSoundAsset" "2186": "handmade.cpp: Make the new system emulate what we had at the start of the stream" "2341": "handmade_asset.cpp: Introduce GetFirstSlotID and various Get functions for Bitmaps and Sound" "2731": "Debugger: Step through the asset loading code" "2751": "handmade_asset.cpp: Set the SoundCount to be 256 * Asset_Count" "2771": "Debugger: Inspect GameState->FirstPlayingSound" "2795": "handmade_asset.cpp: Turn it up to full blast" "2824": "Debugger: Step into LoadedSound" "2907": "build.bat: Switch to -O2 and run the game" "3013": "handmade.cpp: Introduce PlaySound" "3220": "Run the game and hear our sound" "3225": "handmade.cpp: Call PlaySound upon triggering the Sword" "3309": "handmade.h: Add random_series GeneralEntropy to game_state" "3396": "Run the game and find that it almost works" "3415": "handmade.cpp: Investigate the bug" "3454": "Blackboard: Linked list" "3494": "handmade.cpp: Correctly construct this linked list" "3688": "Debugger: Step through the playing_sound linked list" "3884": "handmade.cpp: Reset SamplesPlayed to 0 in PlaySound" "3933": "Run the game and hear our sound" "3980": "Q&A" "4053": "s the sound buffer logarithmic or linear (decibel or linear values) and do we (have to) account for that in building the sums for the buffer?" "4084": "Do you already have someone composing the soundtrack?" "4192": "A reminder about the parameter order in InterlockedIncrement and the bug it covers up" "4241": "handmade_asset.cpp: Handle the case when BeginTaskWithMemory in LoadBitmap fails" "4324": "When mixing a mono sound to stereo, volume of each channel should be 50% for center panned" "4412": "Will this audio code allow you to play the same sound simultaneously (i.e. if you start the same sound before it finishes the first time)?" "4433": "The second and third parameters in the compare and swap" "4479": "handmade_intrinsics.h: Swap those parameters in AtomicCompareExchangeUInt32 and then swap them back and instead change the funtions where it's called" "4614": "The audio seems to be frame rate dependent at the moment. Could putting it in a separate thread or using interrupts (if you can), make it not frame rate dependent?" "4715": "Would you mind adding a __sync_val_compare_and_swap(Value, Expected, New) for gcc / clang" "4735": "handmade_intrinsics.h: Add tfnw's suggestion" "4850": "handmade.cpp: Play the music instead of the bloop, to demonstrate playing the same sound simultaneously" "4934": "So why does it work?" "4974": "Blackboard: Separating asset data from instance data" "5075": "Why use a linked list as opposed to another data structure like a vector?" "5152": "But can you take the output of the sound summer mechanism and play that?" "5168": "Go ahead and call it" --- name: "day141" title: "Streaming Large Audio in Chunks" markers: "0": "Welcome and thinly veiled threats" "96": "Recap of last episode and today's agenda" "286": "Brainstorming possible ways of loading large audio in chunks" "550": "Chaining sounds together" "776": "Programming the simple version that skips" "924": "Aside on loading and prefetching" "1153": "Extending asset_sound_info to refer to a particular section of a file" "1405": "Aside on terseness of typedefs for basic types" "2200": "Seamless mixing" "2768": "Pulling sound code out into a separate file" "3114": "Abstracting the audio arena" "3384": "You should apply for a (twitch) sub button" "3421": "What is your favorite genre of music and do you see it influencing the atmosphere of the final game?" "3557": "I think I missed the day you added the music. Where is the track from? Will it be in the final game?" "3608": "What is the reason you use a temporal arena in the mixer instead of a normal arena?" "4030": "We've had some new blood asking about the absence of Java. Could you please help clean the chat by doing another Java rant?" "4279": "Are you now streaming long audio assets from disk?" "4310": "I think we need a fade-out when audio stops, rather than a dead stop, to avoid a loud click" "4424": "Once upon a time the number of hardware channels available on a soundcard was important. Do most games these days don't care because doing things in software is fast enough?" "4752": "Would you ever need any kind of MP3/OGG support in Handmade Hero or is WAV OK for music here?" "4984": "Would a garbage collector help us with managing the sound buffer and chunks?" --- name: "day142" title: "Per-sample Volume Interpolation" markers: "46": "Plan for today" "127": "Dynamic asset streaming and audio mixing didn't take that much code" "217": "Public service announcement: Sometimes, writing your own code is faster than reusing other people's code" "356": "Some differences between audio and video animation and their effects on sound mixing architecture" "595": "We want to change volume over time, while avoiding discontinuities" "773": "Definition of the interface to ChangeVolume" "843": "Two ways of specifying speed of volume change: time it takes to reach target volume vs rate of change" "1280": "Using dimensional analysis to figure out dVolume" "1850": "Changing resolution back to 960x540 to remain in debug mode at a reasonable framerate" "2070": "Avoiding overshooting the target volume" "2668": "Problem of current approach: repeated imprecise floating-point addition may lead to errors" "2725": "Alternative approach: linear interpolation between beginning and end volumes" "2802": "Alternative approach: backsolving to hit the target volume at the end of the loop" "2891": "Testing ChangeVolume interactively" "3188": "Q&A" "3229": "Can you show again how you skipped a failed assertion, by going to disassembly?" "3610": "Would there be any case where you would like to increase volume non-linearly?" "3721": "So far you can just change the volume of individual sounds. Should we be able to change the volume of the master output as well?" "3806": "Will Handmade Hero support spatialization? e.g. sound mostly in left channel if on left side of the screen, sound mostly in right channel if on right side, etc." "3843": "How hard would it be to do a fade-out/fade-in for the music when the window loses focus/gets focus back?" "3909": "So what did you end up doing to dVolume if it wasn't linear interpolation?" "3928": "If you implemented Assert using ?: instead of if, you could use it as part of expressions or other such places where you can't have an if statement" "3975": "Did you already implement audio clipping?" "4054": "(clarification) Managing audio dynamic range. Yes" "4084": "With respect to Assert, I don't know why you would want to put one in an expression, but apparently that's how it's usually implemented... It can't hurt, right?" "4185": "You can't just hard-clip audio, though. If you don't use a compressor/limiter you would have to at least use soft-clipping with tanh or something" "4212": "Will you implement audio file compression?" "4295": "What would an audio compressor do?" "4425": "How much optimization would the mixer require?" "4461": "What is the difference between a limiter and a compressor?" --- name: "day143" title: "Pitch Shifting in the Mixer" markers: "26": "Recap and plan for today" "74": "Discussion on using volume changes and pitch-shifting to generate a rich soundscape with few sound assets" "419": "How to pitch-shift a sound" "554": "Compromises for minor pitch changes" "683": "Deciding on linear interpolation for real-time mixing" "805": "On the importance of linear blending" "1022": "The simple version: choosing the nearest sample" "1089": "Implementing the simple version" "1307": "(intermission) Outputting sound even when the game window loses focus" "1675": "Back to implementing the simple version" "2041": "Debugging the simple version" "2298": "Adding linear blending of samples" "2500": "Comparing sound output with and without linear interpolation between samples" "2574": "Making dSample part of playing_sound" "2695": "Flushing queues before reloading game code" "2807": "Copying strings out of the game code block to avoid crashing after hot code reloading" "2917": "Implementing PushString" "3283": "Q&A" "3328": "How would you pan a sample slightly left or right in volume?" "3787": "Would this pitch shift be animated as well, like you enter a time-dilated area and pitch-shifts in a second or two as you cross a barrier" "3842": "If you wanted to pitch-shift the music without changing the speed couldn't you just do a quick and dirty linear interpolation between the current sample and the next sample?" "3970": "Did you ever cover what would make a good test sound file for this type of mixing work?" "3990": "Do you ever use memcpy from the C standard library?" "4013": "What's the yellow Rectangle?" "4060": "What kind of sound options do you plan to include in the game? Like will the player be able to pause the game and mute the music but keep the sound effects? Or is it going to be a fixed thing like controller settings?" "4171": "Wouldn't you want to use the alternate way of animating the volume for this feature? By setting a rate, not a length of time?" "4217": "With a player running, would you connect speed of the player to pitch or look to add more sounds i.e. more steps in grass?" "4254": "Once you release this source code, this will allow people to build upon/edit to make their own games. Correct?" "4302": "You may have already covered this, but does the OS alone allocate threads to run on each core, so is it impossible to force a single thread to run on its own unique core?" "4484": "Is programming just remembering a whole bunch of commands and putting them into sequence?" "4590": "Is it too complex to add low/high pass filters via code?" "4683": "If a tree falls and the hero is not there to hear it, will it make a sound?" "4752": "Is the next thing you are going to do put the sound code in SIMD?" "4798": "Are you going to use complex numbers? I heard they're useful for sound processing" --- name: "day144" title: "SSE Mixer Pre and Post Loops" markers: "131": "Plan for today: SIMDizing the mixer" "221": "Aligning the temporary buffer" "300": "Making sure the temporary sound buffers are big enough to fit all samples" "329": "Explanation of Align16" "383": "Alignment macro for any power of two: AlignPow2" "677": "Clamping samples to the signed 16-bit integer range" "1089": "(intermission) Two's complement" "2084": "Back to SIMD" "2208": "Rounding the samples" "2257": "Downconverting from 32-bit to 16-bit integers. No clamping necessary!" "2394": "Looking for intrinsics that interleave 16-bit values" "2658": "Interleaving the samples before packing them" "2847": "Making sure we don't write out of bounds" "2940": "Debugging output using structured input" "3170": "Padding the buffer in the platform layer to make sure we always have space for overwrites" "3260": "Casey remembers that the horizontal mouse position was linked to music panning" "3292": "Getting rid of unnecessary clamping operations" "3345": "Using aligned loads and stores" "3444": "Plan for next episode" "3690": "More 2s complement. Full example" "4290": "Q&A" "4297": "Why isn't 2's complement used for floating-point numbers if it makes signed arithmetic easy?" "4595": "Are you not going to profile it too see how much faster it gets?" "4615": "When you implemented streaming in chunks of audio; I believe the code actually loads the entire file (with a platform layer VirtualAlloc) for each chunk. Is this just an artifact of the debug nature of that code?" "4653": "Does the audio make the framerate in debug mode?" "5169": "If 1111 (-1) is supposed to be less than 0000 (0) then how do number comparisons work on the CPU level?" "5559": "Do you have any tips for speeding up compile time when using multiple translation units?" "5575": "It's movsx for signed" --- name: "day145" title: "SSE Mixer Main Loop" markers: "69": "Plan for the day" "182": "Working 8-wide instead of 4-wide" "483": "Making sure the sound buffer always asks for multiples of 8 samples" "740": "Samples seen as chunks of size 8" "990": "Padding the end of the output buffer with zeros as a consequence of working with blocks of samples" "1260": "Pitch-bending forces us to read unaligned" "1535": "Updating the routine to work with blocks of 8 samples" "1999": "Seamlessly transitioning between streaming sounds by padding them with subsequent sounds up to 8 samples past their end" "2518": "Debugging pitch-shifting after the changes" "2782": "SIMDizing the main mixer loop" "3172": "Trouble SIMDizing the loads of the bilinear case" "3413": "Loading samples one by one for the bilinear case, not by blocks of eight samples" "4027": "Take a listen in-game" "4099": "Q&A" "4219": "What's in the 8 bits we've been working on? Is it frequency and volume?" "4245": "Why is there a command override Od with O2 in the build output?" "4292": "Can you skip the 0.0f*dSample and only do 1.0f, 2.0f, 3.0f ?" "4346": "What does -Od do?" "4414": "What is the "handmade_optimized.cpp" all about?" "4486": "I'm guessing that without specifying some sort of optimization flag, there will still be some optimizations done, which you want to explicitly not do?" "4529": "Is this the last stream for audio?" --- name: "day146" title: "Accumulation vs. Explicit Calculation" markers: "160": "Pitch-bending makes aligned reads impossible, so we can support looping sounds, after all" "435": "Working on chunks of 4 samples instead of 8" "1111": "Simplifying OutputPlayingSounds" "1287": "Working on the linear-blended sample load" "1893": "Writing a more robust termination condition" "2009": "Looking for the source of a failed assertion" "2527": "The problem was the accumulation of floating-point error while fetching samples" "2686": "Accurate SamplePosition" "3011": "Blackboard explanation: accumulation vs explicit calculation" "3364": "(Prestream-like) Q&A" "3451": "You're a rad dude" "3475": "What would you recommend as a good tutorial source or area to learn how to code" "3531": "Is your SIMD clear to zero faster than memset?" "4021": "Do you have a public style guide?" "4049": "I'm looking to learn something other than Java so I can have diverse knowledge. Any recommendations on how to go about doing that?" "4169": "At what point did you first feel like you could easily write software independently?" "4202": "Why is the sample index floating point? Is it for the pitch shifting?" "4216": "Why do gaming companies like Riot or Blizzard entertainment use C++ over all the rest of programming languages?" "4723": "League of Legends is written in flash" "4852": "Actually, only the login client is flash. The game itself is C++." "4928": "Also, there is a new version of Binding of Isaac that is non-flash" "4970": "Well I said air, not flash, but I guess I'm wrong either way?" "5003": "What is the difference between arbitrary and random?" "5035": "I don't know if air has the exact same runtime though? I've worked with air/flex and it's definitely the same API, but I don't know about the runtime" "5055": "("What is the difference between arbitrary and random?" followup) in the mathematical sense" "5103": "What would you rather write a game in? Java or C#?" "5141": "Have you ever smoked weed and programmed?" "5170": "The Axiom of Choice is kind of about arbitrariness and is kind of controversial" "5178": "(Question from Casey to Jon Blow) Is emergent design bad?" "5310": "(Jon answers)" "5423": "Why do you say OO is awful?" "5818": "Will HmH support "physics/simulation" and rendering in different threads?" "5837": "You make it sound like those languages have no purpose. They're great for other things than game dev" "5860": ""Arbitrary" is the bottom element of a mathematical lattice. See http://www.azulsystems.com/blog/cliff/2012-02-12-too-much-theory for details" "5875": " What do you do in order to help prevent carpal tunnel syndrome? Does it get real bad? Anything in particular you try and avoid?" "6012": "Do you know of any OpenGL resources you know of that actually explain why they do what they are doing?" "6034": "By what you said, can I conclude that you have not written a Game Design Document?" "6070": "So OO is kind of like when you design a game ahead..." "6223": "Is this project planned to be a game playable for "real" or more like "How I create games"?" "6295": "Since we are talking about OO/Programming Languages I must ask, how do you feel about Perl?" "6320": "Do you feel Minecraft was a success because of the idea rather than the execution for the first time ever?" "6416": "Dynamically-generated maps?" --- name: "day147" title: "Defining the Asset File" markers: "54": "Recap of previous episode" "98": "On managing programming time efficiently" "199": "The mixer interface with the game is not final, but we already know what it needs from the asset system" "309": "Plan for the day: definition of the asset system" "437": "Two aspects of the asset system: file management and memory management" "601": "Focusing on the asset files" "672": "Types and Tags decouple the game code from the asset table" "939": "Review of the asset system code" "1095": "Asset types reference a contiguous range of actual assets in a separate table" "1230": "Generalizing the asset system to allow for multiple ranges of the same asset type in different asset files" "1739": "Making a program that writes a dummy asset file" "1906": "One example of when to use libraries" "2908": "Simplifying the asset structures by getting rid of SlotID" "3976": "Q&A" "3999": "How many lines of code is the project so far?" "4064": "You mention LZ compression of assets. Will we write the compression algorithm?" "4101": "Are we using bitmaps for any other reason than how easily they can be processed?" "4151": "What does "union" do when used in the struct?" "4369": "Did I see an off-by-one error on assigning bitmap_id? bitmap_id Result = {...->variable++} Is that increment correct?" "4428": "Off-topic Q&A" "4434": "Opinions on specialized game development universities, like DigiPen?" "4453": "Any thoughts about Unreal Engine 4?" "4460": "How did you start learning C/C++? School or self-taught?" "4473": "Have you considered having a keyboard-cam, so we can see your lightning fingers?" "4487": "Did you program during the weeks missed?" --- name: "day148" title: "Writing the Asset File Header" markers: "38": "Recap and plan for the day" "147": "Bug determining when sounds finish playing" "628": "Rearchitecting the mixing loop to avoid this sort of bug. Removing a secondary variable to avoid having to keep it in sync" "736": "On the importance of assertions" "821": "Write assertions to catch the kind of errors that you tend to make" "936": "Back to the test asset builder" "1261": "Trick to avoid modifying lots of code to reflect the change of a variable from object to pointer" "1563": "Data that we want to include in the asset file" "1672": "Pragma-packing the file format structures" "1725": "The hha header and its magic value" "2024": "Overview of the structure of the asset file" "2320": "Using offsets and counts to access asset content" "2680": "Writing the header from the test asset builder" "2766": "Two ways of computing the offsets of tags, asset types, and assets" "3056": "Streaming files mini-rant (extended in the first question of the Q&A)" "3171": "Writing out the arrays" "3522": "Stepping through the code" "3965": "Hex editing the resulting file" "4055": "Q&A" "4082": "Why is a position for a stream a bad idea?" "4620": "Are you concerned that "trusting" the file format could have security concerns, e.g. someone could say they've made some modded assets, and give out a specially crafted .hha file that runs arbitrary code?" "4869": "What is the main difference between using asserts in your code and writing separate test functions/programs that check your results, and when do you choose one over the other?" "5022": "Will multiple threads pose any problems to reading the assets file?" "5051": "If C++ had introspection, would this be a a place where you would use it? e.g. to introspect the types you want to include in the asset pack" "5176": "Are there any specific times your streams start and end?" "5237": "Why not just read the entire file in as a string and parse it as you please, then do the same for writing" "5443": "Another option is to memory-map the file and then do as you will. Although that may not work on older consoles" "5599": "Do the mollyrocket artists ever interact with the asset packer or is it automated somehow. E.g. if they immediately want to preview how their artwork looks in game" "5636": "I was taught to use exceptions because it does not convolute the code with error checking code" "5725": "(clarification to question at 1:30:43) When I said "memory-mapped file", I meant it as an alternative to fread(), not as an alternative to streamed loading. Using fread() actually copies all data twice: buffer cache into FILE* buffer, then buffer into final destination. Copying from a memory-mapped file means only one copy" --- name: "day149" title: "Writing Assets to the Asset File" markers: "12": "Recap and plan for the day" "180": "A file is a permanently stored version of memory" "260": "Two ways of storing the asset array and the assets:" "299": "1) Going back and forth after writing each asset" "369": "2) Writing all the assets, going back and writing the whole asset array" "453": "C Run-Time library function: fseek" "587": "The CRT's fseek does not support 64-bit offsets" "1155": "Moving the BMP code into the test asset builder" "1387": "Including the math header file, after all" "1434": "Moving the sound code into the test asset builder" "1835": "The CRT's ftell does not support 64-bit offsets" "2094": "Guarding against multiple bitmap pitches" "2233": "Loading asset data into freeable memory" "2370": "C Run-Time library version of ReadEntireFile" "2475": "Figuring out the size of a file using fseek" "2565": "Skipping the first, intentionally blank, asset" "2594": "Debugging ReadEntireFile" "2899": "Switching to loading all assets from the pack file" "3035": "Approaching expansive code changes. One step at a time" "3240": "Referencing the asset file loaded into memory" "3416": "Straight casting of the header file as an hha header struct, and checking the magic value and version" "3559": "Stepping through the code" "3617": "Q&A" "3656": "How long has this been going for?" "3680": "What does flat-loaded mean?" "3829": "What is the benefit of keeping all assets in one file as opposed to making different asset files dedicated to each type of asset? (answered at 1:05:42)" "3886": "Should there be error asserts if there are no assets that match a query?" "3920": "Will you ever make games to make profit off?" "3942": "The latter (about the assets)" "3948": "Our single-file HHA file format" "4042": "Why split our HHA file?" "4172": "Off-topic Q&A" "4183": "Where did you learn to code?" "4195": "How long have you been coding?" "4199": "Is this what you do full-time? Or do you work for a company?" "4233": "Will the game be multi-player or single-player? And will you be able to code your character, kind of like CodeSpells, like the name "handmade hero" would suggest?" "4306": "Why is your bio webpage not viewable without javascript?" "4383": "What is a bit map?" "4549": "Have you been doing this all your life?" "4552": "What is the Windows 10 release date?" "4559": "What is your day job? And do you enjoy it?" "4573": "What is Overlapped IO?" "4593": "In that case (referring to question at 1:03:49), why do other developers break up their assets in separate files?" "4647": "Would having separate files assist with modding or patching?" "4696": "Is Mike Acton's Data Oriented Design any different than Compression Oriented Programming?" "4806": "One reason to split files is to get around the FAT32 4GB limit. Another reason might be if your pipeline allows audio devs to update their pack file for the game w/o needing or messing with other parts of the game (models, textures)" "4860": "Where can we read about the actual plan for the game? (gameplay)" "4866": "Are you using any C++ plugins for Emacs?" "4879": "Won't the game have to wait until all the assets have been decompressed before the game can start?" "4927": "Why are you using Windows instead of Linux?" "5458": "Can you say something on stream to get reddit angry; they're already complaining about your OOP statement" "5483": "But you can code on Linux for Windows very easily, right?" "5561": "We are about done for the day" --- name: "day150" title: "Loading Assets from the Asset File" markers: "27": "Recap and plan for the day" "131": "Loading the asset array" "380": "(intermission) Simplifying asset-related structs" "684": "Back to loading the asset array" "713": "Storing the base of the file" "736": "Loading the asset type array" "882": "Removing the call to DEBUGLoadBMP" "1156": "Removing the call to DEBUGLoadWAV" "1355": "Testing the changes" "1406": "Let's load only what we need, not the entire asset file" "1450": "Flat-loading the asset tags and the assets" "1667": "AssetTypes are not flat-loadable" "1722": "Defining the file API" "1774": "Recipe for a good API: write the usage code first" "1920": "The platform layer takes care of knowing the location of the asset files" "2333": "Allowing all operations on files and checking for errors just once" "2462": "Merging the contents of asset files" "2671": "Another opportunity for centralized error handling" "2858": "Informing the OS that we are finished using the list of hha files so that it can free any associated resource" "2951": "Organizing our assets by asset type by looping multiple times over all files" "2991": "Do this in a super janky way" "3330": "Including a TagBase in the asset_file struct to rebase its tags" "3622": "Q&A" "3691": "What's your general rule for making a variable a pointer versus not?" "4284": "I don't completely understand your aversion to using the C standard library... is this just a hmh thing for teaching? Or do you just never use the standard library?" "4541": "How and where will user save data be stored?" "4611": "Off-topic Q&A" "4615": "What keyboard are you using?" "4625": "How long have you been developing games?" "4637": "Why brown switches over blue?" "4663": "What did you had on your arms?" "4674": "Do you like dogs or cats?" "4691": "How far do you think you are in terms of stream days from implementing game logic in terms of play vs platform?" "4727": "I just got two Rpi2s, what do you think about the Rpi2 in general?" "4735": "What do you think about Intel INDE?" "4808": "End of the off-topic Q&A" "4835": "On the joy of building your engine from the ground up" --- name: "day151" title: "New Platform File API" markers: "47": "Recap and plan for the day" "244": "Review of day 150's code" "556": "Loading the asset arrays" "588": "Overview of the tag index rebasing mechanism" "704": "Setting the file's TagBase" "916": "Rebasing the asset array" "1100": "Reading in the hha_asset data" "1205": "Defining the file functions in the platform layer" "1357": "Defining the platform_file_handle and the platform_file_group structs" "1512": "File-related platform-specific functions" "1607": "Defining PlatformNoFileErrors as a macro" "1829": "Placing the new callbacks inside game_memory" "1906": "Platform API globally available to the game" "2205": "Prerequisite wiring to start implementing the win32 version of the new file functions" "2512": "It's no longer necessary for the threaded worker to deal with the asset metadata" "2590": "The work orders for bitmaps and sounds are reduced now to loading a chunk of data, so they can be merged into a single work order type" "2688": "Swapping to the new work order type with the _old_ version of the file loading routines to minimize the amount of debugging" "3105": "Reserving space for bitmaps" "3178": "Filling out the work order struct" "3612": "The win32 file routines are still not finished but our time is up, so let's leave the code in a running state" "3695": "Q&A" "3712": "With this system, is it possible to add an updated version of an asset in a new .hha file without modifying the original? How would the IDs work in this case?" "4012": "What will get rid of the initial flicker of the character at startup?" "4085": "As a programmer implementing a game with fairly simple graphics, any suggestions on finding somebody to commission art assets from or similar if you don't happen to know a good digital artist?" "4132": "End of Q&A" "4142": "Review of tasks left to finish the asset system" "4283": "Review of upcoming tasks" --- name: "day152" title: "New Win32 File API Implementation" markers: "27": "Recap" "70": "Plan for today" "143": "Asset metadata is already loaded, so LoadBitmap and LoadSound reduce to just fetching the data" "238": "Getting rid of LoadSound" "382": "(intermission) Forcing order of reads between checking if an asset is loaded and accessing it" "477": "(intermission) Implementing CompletePreviousReadsBeforeFutureReads" "595": "Back to removing LoadSound" "814": "Copying the contents of assets into the right place in memory" "861": "General-purpose memory copy function" "981": "Setting the channel sample pointers" "1077": "Testing the changes. There's some strange clicking bug going on, probably not related to today's changes. We'll do the debugging later" "1181": "Asset background loader with tag matching in 430 lines of code!" "1378": "Avoiding loading the entire asset file into memory" "1404": "Assets need to be rebased and pointed to the appropriate file through a file index" "1516": "Finding a good place in the code for the asset struct" "1654": "Filling in the asset struct" "2016": "The asset struct is just an hha_asset augmented with a file index" "2109": "Don't design architecture up-front" "2210": "Implementing GetFileHandleFor" "2348": "File I/O code is simple. Assuming we don't get it wrong, we'll save time by writing it now and testing it together with the code we just wrote. The alternative would involve writing some extra test code" "2496": "Implementing the platform functions" "2603": "We don't close files, so there's no need for a Win32CloseFile function" "2645": "Win32OpenFile" "2953": "Win32ReadDataFromFile" "3021": "Overlapped I/O" "3225": "Windows can't do reads bigger than 4GB. We don't plan on reading assets of that size, but let's assert against that situation, just in case" "3323": "Win32FileError" "3407": "Ignoring file operations on bad handles" "3488": "Testing today's code" "3549": "Quick step-through" "3600": "We hadn't read the header yet!" "3734": "Visual Studio fails to show size information on symbols outside the current running executable" "3900": "The null asset triggers an assertion. We ignore it for the moment" "3946": "It (mostly) works!" "3985": "Q&A" "4045": "What do you use when you need something more dynamic than arenas? Default to VirtualAlloc/malloc? Something completely different?" "4173": "How "handmade" are you going to go on the Linux version?" "4250": "Kind of off-topic do you usually have that much luck not getting bugs?" "4382": "Do you usually design an API by just implementing it, or do you try to define the interface first?" "4549": "What is "usage code"? Basically everything down the line that awaits to be fed data?" "5242": "Do you feel that a lot of the common programs today have "bloated" code (much unnecessary code or something along those lines), and/or that coders need to learn to simplify/barebone their code?" "5262": "Doesn't anticipating the usage of the API require decades of work?" "5594": "So basically when you're about to make shoes for a monster, you don't assume how many legs or toes it has, let it stomp around and then use the footprints to make the shoes" "5624": "Suggestion: call this "Snuffy-oriented programming"" --- name: "day153" title: "Merging Multiple Asset Files" markers: "25": "Recap" "107": "Plan for today" "202": "Guessing the origin of last stream's bug" "327": "Examining the test asset builder" "447": "AssetCount is off by 1 and null asset is not loaded" "519": "Correcting the asset count" "596": "Building the null asset" "668": "We're good to go" "687": "Testing asset merging" "729": "Taking the null tag into account" "1045": "Splitting the test asset file to test the merging procedure" "1368": "Loading just one of the files" "1513": "AssetTagCount was not initialized (although that is not the source of the error)" "1545": "Avoiding uninitialized variable bugs" "1721": "The actual bug: not clearing the asset types array in the test asset builder" "1882": "Testing the merging code. There's still a bug" "2072": "Remapping the next id to play to take into account multiple asset files" "2552": "Deciding against remapping the next id to play in favor of explicit looping and chaining of sounds" "2892": "Implementing GetNextSoundInChain" "3110": "Q&A" "3165": "Can we do advanced and then looped sounds?" "3294": "If you're doing the id.value += 1, won't you eventually loop off the last sound asset?" "3375": "Can I watch when you first started writing this game?" "3386": "(intermission) Examining an assertion raised when SamplesPlayed exceeds SamplesCount in pitch-shifted sounds" "3636": "What is the next thing you have planned after assets?" "3720": "How do you determine whether to fix a bug or keep moving forward?" "3850": "If I decide to go for a PhD or something in the future, will you give me the blessing to write about Compression-Oriented Programming?" --- name: "day154" title: "Finding Assets Files with Win32" markers: "23": "Recap and plan for today" "159": "Review of related code" "243": "Getting rid of hardcoded file names" "322": "Listing file names on Windows (FindFirstFile)" "535": "The lpFileName parameter can include wildcards" "654": "Listing the rest of the files (FindNextFile)" "741": "Guarding against invalid handle values" "828": "Invoking FindClose on the file handle returned by FindFirstFile" "910": "Structuring the file loop to be more uniform" "990": "(aside) Textbook horrible API design" "1169": "Problem: we don't know how many files there are until we have looped over them" "1233": "Revising the file API. There's no need for random access of files. Sequential access is enough and is cleaner to implement" "1288": "Preiterating the files" "1351": "Allocating space for the win32 opaque data segment of the platform_file_group struct" "1412": "Discussion on extensible platform non-specific types. This type of "space saving for dynamic unions" can be implemented using C++ inheritance, but we will encounter other types that can't" "1591": "Freeing the platform_file_group" "1867": "Second iteration to load the files, now that we know how many of them there are" "2226": "Jumping to the definitions of windows system calls using Visual Studio" "2292": "Choosing the ANSI versions of system calls and structures" "2454": "Getting the file names" "2468": "Testing the code so far" "2668": "Parameterizing the file extension" "2765": "Write your own string system if you work with strings frequently" "2917": "Possible extensions to the file API" "3007": "Q&A" "3075": "Does the save file need to use this system now?" "3149": "How do you feel now that you finished this?" "3207": "Socapex insists that the STL *is* the language and that you therefore should use "strings" from it" "3392": "Could you elaborate on the union style inheritance you mentioned? In the same vein, will entities end up being unions?" "3566": "What about updating the asset file with more files? How do you manage a ton assets as in knowing what is where?" "3609": "Will the ASCII version of FindFirstFile work even if the full file path has unicode in it?" "3680": "Will pre-rendered fonts be included into the HHA file?" "3686": "Is this the new Call of Duty?" "3766": "Does the requirement to call FileClose() make more sense when you consider that FindFirstChangeNotification/FindNextChangeNotification/RefreshDirectory are part of the same API?" "3902": "How are you doing the audio?" "3950": "You wrote code for "Lineage Forever"? Any comment on writing it on the game/any other Lineage games? Lineage 1 pretty much sparked my entire career as a computer scientist/programmer" "4122": "What's after the asset file loading?" "4138": "Why do you use #defines for things like PLATFORM_GET_ALL_FILE_OF_TYPE_BEGIN instead of just normal function call?" "4203": "I have not followed the latest episodes due to I actually watching it from the beginning. But is there any like crypting in savefiles regarding cheating, etc?" "4292": "Are there any books on game programming or general programming that you would recommend?" "4433": "What do you think about "Game Engine Architecture" by J. Gregory ? The books looks solid" "4450": "(Referring back to Q at 00:59:26) I meant the artist is making files how do you track what you added and what you didn't. What assets have changed. and need updated kind of thing?" "4542": "Is the graphics double-buffered?" "4625": "When are you going to stream your hands coding? Would be neat. You talked about doing it some time" "4657": "(Referring back to Q at 01:10:03) Well just because people would know how to beat the encryption, doesn't mean it would be a bad thing to teach in this series" "4732": "Have you read "The Tao of Programming?"" "4739": "Does it tear with Aero disabled?" --- name: "day155" title: "Introduction to Particle Systems" markers: "24": "Recap" "49": "Three possible subjects for today's stream" "283": "Let's do particle systems!" "385": "Introduction to particle systems (blackboard)" "567": "Particle systems are used to represent objects with no specific shape" "715": "Emitters and particle behavior" "835": "On the shape of particles" "879": "Overview of simple particle system implementation" "1019": "The particle struct" "1160": "Writing the particle system test loop" "1210": "Rendering and then simulating VS simulating and then rendering" "1332": "Rendering particles" "1504": "Simulating particles" "1562": "Particle placement" "1739": "Inspecting the simulation and drawing of the particle system" "1768": "Drawing particles using the shadow asset" "1976": "The hero is now the emitter" "2338": "Changing colors" "2634": "Introducing randomness into the velocities of particles" "2660": "Using a new random series just for effects" "2825": "Tweaking the velocities" "2963": "Fun selecting different sprites" "3012": "Color randomization" "3233": "A more explicit way of ramping colors up and down" "3659": "Q&A" "3694": "For a while I have felt that interpolating particles in RGB leads to results that are dull and muddy. I have been wanting to try YCrCb or maybe even LAB sometime. I guess you can compensate via splines through RGB but I think you'd be doing a lot of tweaky work all the time to get better results (even though YCrCb is just a linear transformation, I think there's a substantial amount of skew.)" "3789": "Will particle pre-warming be supported?" "3863": "When you were messing with the z direction, it seems kind of like a puddle on the ground" "3875": "Ever messed with using some kind of a stateless system of doing this? Like one function parameterized by another function?" "3905": "Is rain a particle system?" "3913": "I wonder if head particles like this could be used in the game... for example as an effect of magic related to disguises. Like, when you dissolve the disguise of the Superfish" "3932": "Witness is RGB and probably too late to change, but we don't rely on wowee particles much" "3989": "Z still points towards the screen" "4022": "Does anyone ever use layers? Or just Z-sorting?" "4038": "At what time does Handmade Hero stream? I saw this on the front page and it seems interesting" "4077": "Maybe for the Galaga game I will switch to HSV..." "4110": "Will these videos help someone learn C and C++ who has absolutely no experience?" "4236": "Have you, or will you explain how shaders work?" "4264": "Will these particles be able to react to things like impacts?" "4304": "How many particles at the moment?" "4318": "How many particles till we see a noticeable slowdown?" "4440": "Are you using Emacs outside of Visual Studio or inside of it?" "4450": "When do you plan on implementing a way to adjust the position of the individual particles when the entities move?" "4502": "What made you pick C++ over C#?" "4555": "What parameters will you tweak with curves? Scale, position, color, rotation, external forces, etc. Will the curves depend on time only?" "4636": "How many times have you said "right" in this broadcast?" "4670": "Is your .emacs config open source?" "4685": "Can you explain what procedural level generation is? Are there other types of generation, and if so what are the differences?" "4734": "What do you think about using Unity as a platform layer and using all your own logic?" "4797": "Why do you pronounce "nightmare" as "night mirror"?" "4807": "Do you have someone making the game assets for you or are they self made?" "4817": "Will you be making development tools for Handmade hero, like a map editor?" "4833": "(Referring to Q at 1:17:50) I mean is your config *public domain*? Can I give it to someone who'd like to get started with Emacs? I myself preordered ages ago, best 15$ expenditure of my life. NO CONTEST. <3" "4856": "(Referring to Q at 1:18:54) You can use DLLs. I have done this!! Much using rust, fyi" "4915": "You went from two-k on my name to zero-k. A single one would be appreciated ;D" "4952": "I mean the particular flow or direction is now from bottom up. Feels like its not hard to do left to right for example" "5042": "I think it's like GNOOKLES, but with a K sound instead of G" --- name: "day156" title: "Lagrangian vs. Eulerian Simulation" markers: "14": "Recap" "82": "Plan for today" "168": "Adding acceleration and taking it into account to compute new positions" "387": "Bouncing particles off the ground" "596": "Modeling loss of energy" "840": "We want our fountain to be more fountain-like" "1194": "Writing special-purpose code to achieve the desired behavior" "1770": "Considering the interactions among particles instead of simulating particles in isolation" "1841": "Two raw categories of physics simulations: Eulerian and Lagrangian methods" "1885": "Lagrangian: Simulation of the motion of particles through space" "1969": "Eulerian: Simulation of density and mean velocity of particles at specific locations in space" "2161": "Lagrangian methods are bad at handling density" "2200": "Eulerian methods don't keep track of the properties of individual particles" "2266": "We'll resort to a mixed Eulerian-Lagrangian method" "2325": "We could use the density gradient from an Eulerian representation to compute the horizontal push of particles in the Lagrangian representation" "2577": "Let's implement it" "3057": "Drawing the density field" "3603": "Dispersing particles taking into account cell density" "3805": "Discussion of possible improvements to the simulation" "3840": "Taking advantage of the density gradient to achieve better results" "4080": "We still don't use the mean velocity of particles inside each cell" "4133": "Q&A" "4158": "I suppose adding some friction to dP.x might help" "4241": "Try reducing the size of the individual cells" "4403": "The back of the head would make a better particle than the side of the head" "4584": "If you're going to alter the GridScale, you probably need to scale Dc by it too." "4622": "Did you ever add a way to tell the music to shut off or did you just disabled it?" "4642": "What would happen if the particles were spawned between two cells? Would that cause an effect where everything would just not bounce off each other anymore?" "4674": "On API design: You recently emphasized "Write the usage code first" and then the implementation later. While compression oriented programming is about writing code first and then compressing it, pulling code into functions where necessary, allowing the API to evolve out of that process. They seem like two contradictory methods. Are they? How do you decide when you're using one or the other?" "4978": "Would it be possible to split the fluid computation across two frames. Like use the first frame to accumulate velocity and momentum changes and the second one to resolve them?" "5022": "Does the size of the grid relative to each particle matter much?" "5070": "(Referring to Q at 01:17:22) Say you're deciding whether to bounce the particles off based on the density now, then if the particles were spawned between 2 cells, wouldn't the density be halved and not bounce off anymore?" "5182": "Would simulated annealing work for this issue?" "5196": "Doesn't writing usage code first imply simplicity in API calls? Doesn't this box you in when trying to create persistent things on the stack? All complex initializations for persistent objects have to be done somewhere. If done on the stack, how do you persist complex data structs without using static?" "5266": "Current simulation is in pixel space?" "5276": "Are pre-rendered effects viable?" --- name: "day157" title: "Introduction to General Purpose Allocation" markers: "18": "Plan for today" "88": "Our asset memory management problem can't be solved by a garbage collector" "156": "Asset memory management (blackboard)" "220": "A good way to think about memory management" "604": "The amount of memory we need is larger than the amount of memory we have. We have a Virtual Memory problem." "901": "Stacks and GC can't help us in this situation" "992": "Memory fragmentation" "1160": "In a world were all the assets were the same size..." "1280": "In our case assets are not the same size, but we could find ways around that" "1415": "We could have a big sprite sheet and page the chunks in when they were needed (similar to Megatexture)" "1674": "Another option: A variable allocator. It could defragment memory or merge contiguous freed spaces. We're choosing this one for educational reasons" "1896": "Overview of the variable allocator" "2058": "Running out of memory on purpose" "2234": "Restructuring loaded_bitmap and loaded_sound to move asset data inside asset_slots" "2981": "Moving asset data inside asset_slots" "3174": "Determining ahead of time when we're going to hit our memory limit" "3240": "We can't free assets to make room for new ones from inside a call to LoadBitmap" "3335": "We can mark bitmaps as freed between frames. Two options: a) deferring LoadBitmap calls till the end of the frame and b) keeping some amount of free space to make loading always possible" "3464": "Q&A" "3477": "It's official: Assets are now handles" "3517": "Would there be a benefit to using a 2-level cache for storing compressed and uncompressed assets?" "3575": "Is there any performance reason to not use malloc and free?" "3652": "Are there technical terms for the memory emptiness assurance algorithm?" "3677": "Can you talk a bit about what new / delete actually does and when to use them?" "4353": "Could you briefly comment on how viable it would be to recast the problem as one of asset packing? Split sounds into fixed-sized chunks and dice bitmaps into fixed-size tiles, so that all of the tiles are of a reasonable size. Group related assets together so they are loaded together. That sort of thing" "4456": "Is there a real "philosophy" difference between using smart pointers and garbage collection? Or are smart pointers just a way to implement garbage collection?" "4772": "What about RAII?" "5382": "How about vibration effect assets?" "5390": "What is the difference between a megatexture and a texture atlas?" "5433": "Do you object to use of explicit vtables, like you would have to use in C?" "5475": "Would thinking about asset allocation in terms of the maximum amount of pixels that can be displayed on screen at one time be worth it (for instance with your 16MB safety buffer). So you tailor the asset loading to load assets at a resolution proportional to the distance to the camera and operate under the assumption that only a fixed number of things can "physically" occupy the high-res space and so on for medium, low, etc." "5553": "(Referring to Q at 01:12:33) The thing I didn't see was grouping small related assets together so they fit in one allocation unit." "5584": "Is this still the same blackboard file from day 1? Is there a fully zoomed out view and how much RAM is that program consuming now with all your current doodles?" --- name: "day158" title: "Tracking Asset Usage" markers: "18": "Recap and plan for today" "72": "Using the OS's virtual memory system to solve our memory management problem" "267": "Tracking memory load" "291": "Using an allocation scheme that gets the memory from the OS and returns it on eviction" "499": "Implementing platform_allocate_memory" "626": "These changes break the looped live code editing feature" "777": "Two approaches: a) deferring LoadBitmap calls till the end of the frame and b) keeping some amount of free space to make loading always possible" "820": "Tracking amount of memory used in the asset system (AcquireAssetMemory)" "916": "RealeaseAssetMemory requires us to provide the size of asset to free" "1096": "Using the platform calls instead of the memory arenas" "1157": "Tracking memory usage and freeing memory at the end of the frame (EvictAssetsAsNecessary)" "1300": "Evicting the least recently used asset" "1398": "EvictAsset" "1604": "Distinguishing between bitmaps and sound inside AssetState" "1775": "Computing the amount of memory taken by an asset" "2111": "Getting rid of duplicated calculations" "2501": "Figuring out the location of the chunk of memory to free" "2752": "Doubly linked list to keep track of least recently used asset" "3129": "Doubly linked list theory (blackboard)" "3235": "AddAssetHeaderToList" "3381": "Semantic setup of pointers" "3433": "RemoveAssetHeaderFromList" "3738": "Initial sentinel setup" "3873": "We should avoid evicting locked assets" "4052": "Types of doubly linked lists and overview of their implementation" "4200": "Q&A" "4205": "What function owns the pointer to the head of linked list?" "4216": "Isn't a linked list what you're always told not to do if you're care about the cache at all?" "4305": "Could the platform_allocate_memory function allocate a few bytes more than requested and store the size there to avoid it having to be passed to the free function?" "4327": "Having a list header at the end of each asset struct, wouldn't that invalidate the cache a lot, when processing the list, since asset structs are potentially large?" "4394": "In RemoveAssetHeaderFromList, would it make sense to zero out the prev and next pointers of the header that is being removed, or is it just unnecessary cleanup? Are there pros and cons to this?" "4436": "Will there be a fountain of heads somewhere in the actual game, possibly as a Halloween item?" "4443": "Is Twitch your full-time job?" "4447": "How will you re-enable the live code reloading after this is done?" "4513": "Can you briefly go over inlined functions?" "4580": "Which classic data structure do you enjoy implementing the most?" "4628": "Does/will this system support hotloading of assets?" "4718": "Does it make sense to write your own non-block dynamic allocator instead of using the memory system of the OS?" --- name: "day159" title: "Cleaning Up the Loaded Asset Infrastructure" markers: "22": "Recap and plan for today" "122": "Preventing eviction of locked assets (those used in background tasks)" "246": "We never lock any asset; let's lock some" "421": "Not locking sounds" "475": "The render group knows whether an asset should be locked or not" "501": "Safeguarding against caller mistakes" "761": "Preventing the eviction of assets before they are completely loaded" "954": "Testing the changes" "986": "Moving the most recently used asset to the front of the linked list" "1324": "Getting the header from the slot is tricky" "1769": "MoveHeaderToFront should only affect loaded bitmaps" "1814": "Deciding to clean up the loaded asset code" "1830": ""Locked" as a flag, independent of asset loading stage" "2208": "Checking the commit size of the game on the Windows task manager. Casey's head gets in the way; see Q at 01:01:43" "2346": "Simplifying the loaded asset infrastructure" "2429": "Merging asset slot and asset" "2664": "Condensing everything necessary to work with an asset into the asset header" "3169": "Storing the size of the loaded asset instead of its type" "3241": "Some debugging" "3519": "Removing GetSizeOfAsset" "3655": "Q&A" "3703": "Your head was over the window when you were looking at the commit size" "3779": "The linked-list way of computing least-used asset seems like a simple and neat trick. What are its drawbacks?" "3958": "Garlandobloom may be too drunk today" "3971": "Can you explain the code in which you changed the asset loading so that it stops blinking (the bitmaps and sounds)?" "4433": "Will there be a concern of cache misses while manipulating the doubly linked lists every frame?" "4516": "You've got a TODO about the size of the audio asset struct. How important do you think it is to keep structs compact? -- (Casey undoes the size shrinking of LoadedBitmap, since now it's included in the asset header and not in the asset slot (blackboard))" "4820": "Do you have a hard drive to check this system on it?" "4838": "Is there a problem setting the asset header to null after unlocking it? I thought there was some background loading of some stuff" "4879": "Is the heap and the stack just different sections of RAM, managed by the OS? Also, if so, do different programs ever share stack space? Would you please shed some light on this or point me to some video of yours that I missed?" "4945": "I'm confused as to what the memory layout will be after using the doubly linked list for a while? The memory will fragment eventually as of now, no?" "5012": "Couldn't we use just use a 'IsLocked' bool, inside 'Asset->Header' struct?" "5030": "Won't this method of swapping the assets cause memory fragmentation?" "5267": "So something like this can't happen? Asset evict function is called, release happens, unlock happens, thread context switches to loader, something gets loaded into that slot with some header, thread context switches back, header is cleared to 0" "5437": "Is it possible that, due to the kernel caching disk accesses, we're paying more than once for each asset? Like, after we evict an asset, is another copy of it likely to be cached in physical memory because of the OS's caching of the pack file?" --- name: "day160" title: "Basic General Purpose Allocation" markers: "13": "Recap and plan for the day" "114": "Plan for today: Writing our own general-purpose memory allocator" "252": "Ode to stack memory allocation" "333": "The asset system needs a more sophisticated memory allocator" "405": "Closer look at asset eviction and memory fragmentation (blackboard)" "641": "Overview of our approach" "781": "Thinking of our available memory in terms of free fragments" "865": "Merging contiguous free blocks" "972": "We won't be performing small allocations" "1010": "Every block will keep information of neighboring blocks" "1123": "A possible way of implementing the allocation operation" "1452": "We can call EvictAssetsAsNecessary from inside AcquireAssetMemory!" "1724": "Modifying AcquireAssetMemory to work with our own memory" "2168": "Evicting assets to make room for a new one" "2239": "Keeping track of the location of our assets" "2446": "Doubly linked list of memory blocks" "3012": "FindBlockForSize" "3146": "Conditionally splitting the memory block used to store an asset as a function of its remaining capacity" "3395": "Recovering memory blocks inside ReleaseAssetMemory" "3495": "Q&A" "3580": "Given that this is an optimization problem, it seems like we'll want to have a system for profiling asset use and eviction (and check its output periodically as the game and assets grow over the next year or so). Should this be on the agenda in the near term?" "3673": "I'm not clear on what happens in the else when we fail to find a block, could you go over it?" "3823": "Why do we need to check the remaining size > threshold ? Why not just use the remaining size if it satisfies the request size?" "3966": "How come this memory management system is strictly limited to game assets and not other things as well?" "4001": "What will the GUI handle? (Answered at 01:11:18)" "4012": "If this were a commercial project, would it make sense to use malloc instead here, or write your own anyway for managing assets?" "4170": "Any possibility of using Markov Chains for the game or game engine?" "4187": "It's looking like Vulkan, if it gets released in a timely manner, is going to be a good choice for hardware rendering. I just read that you have control over all memory to avoid any unknown allocations "Explicit memory management in Vulkan allows applications to use custom allocation strategies. For example to allocate all memory up-front and avoid any allocations during rendering"" "4268": "Have you thought about having a "prefab" asset that people could use to make more complex assets, like a whole house with functional doors?" "4279": "(Referring to Q at 01:06:41) The GUI mentioned in the TODO list" "4308": "You keep saying "split the block in half" What do you mean? 'Size = Size/2'?" "4416": "(Referring to Q at 01:09:47) This is where I read it from: http://blog.imgtec.com/powervr/trying-out-the-new-vulkan-graphics-api-on-powervr-gpus" "4507": "Will the debug GUI have a cool console like Quake/Unreal?" --- name: "day161" title: "Finishing the General Purpose Allocator" markers: "21": "Recap and plan for today" "106": "We will need to debug the changes from the past episode" "221": "Simplifying some of yesterday's code" "454": "Finishing the merging of the freed blocks" "614": "Implementing MergeIfPossible" "961": "Modifying AcquireAssetMemory to check if the asset we are loading fits inside the newly freed space" "1007": "We're good!" "1156": "Potential problem of this general-purpose allocator: The linked list could be too long to walk on each allocation" "1533": "Fixing an error in OpenNextFile: If the platform layer failed to allocate the file handle, that function would fail to report the error" "2148": "Working with asset files containing Unicode characters" "2281": "On the importance of not exposing the concept of filenames to the game code" "2426": "Making the code work properly with Unicode file names" "2548": "wchar_t" "2861": "Isolating the game code from the concept of file extensions" "3184": "Q&A" "3206": "First rays of Moscow sun bid you Good Evening, Casey. I humbly request to be granted two off-topic questions (maybe near the end?)" "3235": "I asked a similar question yesterday, but I guess it wasn't clear. Have you thought about how the asset system could work with 3rd party mods? Say someone wants to make a mod that adds new graphics, sounds and/or game logic. How hard would it be to implement a mod loader, Steam Workshop support, etc?" "3323": "Should there be a way to say if one of the hero assets are loaded then they all should be loaded and not evicted?" "3390": "Might be off topic, but why exactly do you have typedef'ed functions in the code?" "3458": "Did you see this Nostalgia Critic Wicker Man (Cage in a bear suit) review? www.youtube.com/watch?v=vj_CRnwJTk8" "3474": "Can we get a visual display of the loaded / unloaded chunks of asset memory when we do the debug stuff?" "3490": "I would like to hear what your definition of enumeration is, if you will" "3524": "Good evening Casey. Does Windows 10 change the coding (if you know)?" "3572": "On MergeIfPossible, when you pass the checks and do the merge, you add the size of the header plus the size, but on the line before that you check that the (size + header) matches, but the size should already include the header. Can you explain why that is?" "3796": "What's the cause of the depth error you get on rendering?" "3826": "You know I'm the biggest fan of the series, but I suspect for complete newbies the current way you construct the game makes little sense. Consider this: you know how to make a game, so you methodically cross over a check-list of components you know by heart (mostly). What would probably be easier and more graphic for larvas to grasp is to make a little functional game(title screen, game loop, game over, start over, etc) and THEN iterate upon it. It's more visual and having a little game that evolves every day little by little keeps the maker motivated, as opposed to a pro that knows what the game should look like in the end" "4054": "Did you ever play Freelancer?" "4081": "Have you seen Kung Pow?" "4113": "Which version of Visual Studio are you using at work?" "4140": "Will that point in time see a new intro trailer with an old motherboard being pulled from the attic, engine booting up and Handmade Hero announcing the completion of the engine, perhaps with a nice sine scroller and particle effects?" "4166": "Is font rendering around the corner?" "4191": "How do you render without instantiating a brush object?" "4260": "Will you be going the easy way and using Bitmap fonts, or will you be implementing TTF?" "4328": "Do you know anyone by the name of Andre Lamothe?" "4359": "Are you going to implement distance field font?" "4511": "Is it worthwhile to try to make a game only using pure functions, i.e. no side effects" "4633": "Will you cover non-mono-spaced fonts and font kerning?" "4733": "(Referring to Q at 01:15:11) Functional game: The state is an argument and a new state is returned" "4905": "How much of the code you have written so far can be ported to 3D easily?" "4949": "(Referring to Q at 01:18:53) At least in Haskell, the "pure functional" part is hidden away from the IO stuff via a mathematical concept called "Monads"" "5037": "What do you think of a graphics system that intentionally simulates Mode 7?" --- name: "day162" title: "Introduction to Fonts" markers: "62": "Recap and overview of upcoming debug work" "143": "Plan for today" "246": "Test-driven vs visualization-driven game development" "378": "Fonts from the ground up. What are font files?" "650": "Fonts describe a mapping from character set encoding to outline shapes" "742": "ASCII/ANSI encoding" "895": "Unicode" "969": "Pros and cons of Unicode" "1163": "Unicode codepoints" "1261": "Basic typography (baseline, maximum ascenders and descenders, line height)" "1411": "Kerning" "1430": "Monospace fonts" "1546": "Proportional fonts" "1737": "Kerning information" "1945": "Hinting" "2132": "Ways of using fonts inside Handmade Hero:" "2175": "1) Load TTF and tesselate the glyphs into an outline made of triangles" "2277": "2) Load TTF and perform implicit rasterization" "2492": "3) Use prerasterized fonts" "2627": "Approaching prerasterized fonts" "2821": "Plan for the next episode" "2967": "Q&A" "2993": "Aren't there licensing concerns with fonts?" "3200": "Will you support Unicode in Handmade Hero?" "3210": "Could we not pre-rasterise our fonts whenever the resolution is changed / at run time basically?" "3245": "Will you be writing something using the font before you code the actual font reading etc?" "3270": "Q: Will classic bitmap fonts remain relevant in the coming years or will we just start flat out with vector fonts forever more?" "3304": "Are you doing quantum mechanics?" "3310": "Did you ever try making a font yourself?" "3321": "Will you have unique fonts made for the game?" "3332": "If you had multiple font families and were pre-rasterizing them, can you stuff them into one file?" "3349": "Can I come live with you and you tutor me?" "3357": "How are combining Unicode characters that some languages have handled?" "3371": "Blackboard: Combining glyphs" "3490": "I became a much happier person once I started rasterizing fonts on the fly all the time. So much better" "3516": "A bit off-topic, what makes code "publishable"? You said you wouldn't publish the current win32 platform layer. Exactly why not?" "3594": "Will you be writing your own pre-rasterizer from scratch, or using a 3rd party tool?" "3607": "In which episode will you implement Unicode skin tone emoji modifiers?" "3652": "How much time do you spend preparing for each stream?" "3657": "If you were to have a loot history or story line history - you mentioned 40px - if you wanted to allow users to adjust this UI, would you still do pre-rasterized? At what point would be the threshold for including a proper non-rasterized version?" "3708": "The Eulerian method you used for the particle system moves stuff from high density to low density cells, right? Could the Eulerian method be used the other way, e.g. to make something that has gravity and pulls low density stuff towards itself? Also, I wondered if Eulerian simulation could be used for AI systems: maybe having different characters being attracted to or "repelled" by crowds." "3925": "Isn't abuse of text in a game a bad game design idea?" "3955": "Will you use correct typography terminology for the code or will you be carefree about it?" "3981": "By adding more and more layers of complexity to the engine, do you start to measure and optimize those parts just when FPS is low enough, or when do you usually start with optimization?" "4124": "What do you think is the hardest challenge for you in programming, these days?" "4457": "The worst part is, you say stuff about these tools being terrible and NOBODY SEEMS TO UNDERSTAND THEY ARE TERRIBLE. Everyone is like, "what do you mean???"" "4570": "Have you considered signed distance fields for text rendering?" "4640": "But don't you think you're not being completely fair to the other crowd, who are not going to lower level? For example, I love and care about lower level stuff, but to pay my bills I have to be able to output an application within 10th of the time it would take me if I did everything at lower level. I have no choice but to rely on WPF and C#" "4745": "It's not enough to see a good tool once to understand that modern tools are bad. I feel like you also need to be a pretty good programmer, which is far from where most of us are now. If you are a mediocre programmer, you won't feel it. Do you agree?" "4868": "Would you take a job in the mafia if they gave you a perfect version of Emacs and Visual Studio?" "4892": "Close it down" --- name: "day163" title: "Asset Processing with STB TrueType" markers: "2": "We can use libraries inside the asset processor" "50": "Two ways of generating the font bitmaps: Resorting to windows or using a library" "92": "Deciding to resort to an stb library" "218": "The stb libraries" "308": "The stb_truetype library" "337": "Structure of the stb libraries" "537": "Using the library" "579": "Library integration in two lines" "728": "Documentation of stb libraries" "831": "Rasterizing one letter" "991": "Pass the entire thing to Sean" "1107": "Using GetCodepointBitmap" "1167": "Font scaling; points and pixels" "1297": "Recording the size of returned bitmap and the X and Y displacement offsets" "1421": "Freeing the memory allocated by stb_truetype" "1470": "Appreciating work well done" "1543": "Using the character bitmap as a loaded_bitmap" "1849": "Displaying the bitmap" "1886": "Testing it" "1920": "Checking MakeNothingsTest" "2118": "Debugging the drawing code" "2170": "MakeEmptyBitmap was out of date and missing some initialization code" "2220": "Testing it again" "2318": "Flipping the letter bitmap upside-down" "2398": "Moving this code to the asset builder" "2529": "Merge handmade_asset_type_id.h into handmade_file_formats.h" "2583": "Adding one bitmap per letter to the asset file" "2802": "Reload the entire font file and make Sean parse it" "2983": "Good job, Handmade Hero" "3074": "Adapting the font rasterizer test code to the asset system" "3200": "Adapting the asset system to the new asset type" "3457": "AddCharacterAsset" "3562": "Thank the compiler" "3598": "Go ahead and run our generator" "3618": "Try and debug the program in Visual Studio" "3649": "Let's try that again" "3678": "This machine is very old" "3757": "Try to change the heads to be fonts" "3783": "Filtering which letters spew out of the fountain" "4049": "Library success!" "4136": "Q&A" "4156": "The 'A' is the best match for the null terminator" "4193": "Until tonight, I thought there was a use case for CMake (which is that, if the user compiles the program, it finds libraries so that you don't need to know where they're installed). But now... it seems the STB way is the only reasonable default. I think I'm done with CMake for the foreseeable future" "4292": "External libraries, malloc/free, what's next, a java virtual machine?" "4331": "You have used a library, and there are riots raging in the streets. I see shadows of pitchforks, cast by torch lights of the rabid crowd. Run, Casey, I'll do my best to slow them down. *tips his hat with a last farewell gaze*" "4366": "How would you write debug info now?" "4379": "Also, if you make the Hero spew out letters of my nickname at random (at least 'til the end of Q&A (and we already established that I'm the mascot of the community (le lovable goof))), holy hell will I be happy" "4400": "I noticed "mollyrocket" in one of the comments of the STB file... Did you make contributions?" "4423": "It looks like this episode was brought to us by the letter N" "4479": "Rephrase: how would you output sentences to see debug strings like fps or error codes?" "4496": "Is the debug text going to be spewing forth out of the handmade hero's head?" "4508": "I'm curious: what do you look at when hiring an artist (I have no idea how you apply for that)? After watching a few episodes of Double Fine Adventure I'm in awe at how good artists at Double Fine seem to be and what kind of *richnesses* you have to have to be one of those. You also seem to practise more intelligent and humane approaches to hiring" "4609": "It's almost 1am, please tell me this won't be a normal thing" "4689": "Can you input a tilde sign in emacs with your config, because I can't?" "4709": "I don't look for a practical advice, just interested how you do it now. Often my friends tell me "I can't give you an objective answer/data" "screw it, I want YOUR opinion!"" "4779": "ONE MORE! Ever thought of special episodes with guests/bonus episodes done on specific topics by someone else (being a rad debugger with Jeff or being a splendor deitial programmer with Fabian)?" "4830": "Is formatting coming tomorrow?" "4862": "I've heard you mention a "new language" someone is developing. Could you mention the name/creator? I Usually listen to Handmade Hero in my car on my way to work so I can't write it down if I hear it" "4916": "Go to bed" "5135": "See you on the internet, Casey" --- name: "day164" title: "Asset Processing with Windows Fonts" markers: "2": "Recap and plan for today" "103": "Reasons for and against using libraries in the asset processor" "259": "Windows calls to draw fonts" "371": "GetPixel: Simplest way of getting the rendered font, pixel by pixel" "426": "CreateCompatibleDC and CreateCompatibleBitmap" "526": "Defining an alternative code path inside LoadGlyphBitmap to render fonts via Windows calls" "591": "TextOut: Drawing text to an HDC" "681": "Creating the device context" "740": "CreateCompatibleBitmap" "840": "We are not using the right font yet" "863": "This is a zygote of a thing" "914": "Finding out space taken by the text" "958": "GetTextMetrics" "1008": "GetTextExtentPoint32" "1098": "Clearing the background prior to writing the glyph: Patblt" "1222": "SetTextColor" "1288": "Try doing some extraction" "1308": "GetPixel: Extraction of the glyph" "1430": "Recap of previous steps" "1524": "Test out this alternative font implementation" "1557": "Debugging it" "1610": "No need to debug; Casey remembers the cause of the problem" "1656": "SetBkmode: Setting the background filling behavior" "1709": "Selecting a background brush instead of calling PatBlt" "1758": "'Doopity Doo' by Casey Muratori" "1795": "SetDCBrushColor" "1828": "Let's test it" "1895": "Setting the background color with SetBkColor" "1933": "Success!" "1970": "CreateFont: Picking the font" "2071": "AddFontResourceEx: Making the font visible to windows" "2246": "We need to specify the font name" "2692": "We also need to mark the font as active" "2744": "Testing the renderer with a more recognizable font" "2814": "Back to STB font rendering for a minute" "2872": "Resorting to solid alpha to inspect the bounding boxes" "3174": "Scanning the bitmap to get the bounding box of the glyph manually" "3461": "Adding a one-pixel empty border" "3580": "Q&A" "3619": "Can the fonts have outlines?" "3643": "What did you mean by "backing bitmap"?" "3796": "I love how stb_truetype is easier and arguably better than the windows api version" "3804": "Vote on the strawpoll!" "3883": "Does windows font have subscript and superscript support and therefore so much overbounding? Also, is the anti-alias only stored in the alpha value by windows? After seeing a pro like you struggle with this API I understand the burden you go through with it, having seen STB yesterday" "3970": "To clarify, do we have the ability to create font bitmaps with outlines on the characters that could maybe be colored separately?" "4042": "Which one is worse: GDI or DirectInput8?" "4054": "Is today a good example of why sometimes using a library is okay?" "4211": "Would DirectWrite (or ClearType) help out with the anti-aliasing?" "4225": "Ignore this if you're already doing this, but why not ship the mono bitmap as part of the asset file instead of the much larger RGBA bitmap?" "4316": "Q: People are liking the idea of handmade.dev" "4355": "How often do you regret using a API/lib and back-up writing your own implementation? When you are fast-paced as you maybe this sometimes is better when your knowledge of the problem is sufficient" "4469": "What GUI toolkit do you recommend?" "4512": "Would CLEARTYPE_QUALITY instead of ANTIALIASED_QUALITY make a difference?" "4530": "Blackboard: LCD pixel elements" "4632": "That's all she wrote" --- name: "day165" title: "Fixing an Asset System Thread Bug" markers: "50": "Two possible plans for today:" "61": "a) Construction of sentences and paragraphs" "129": "b) Fixing a bug. Let's fix the bug" "223": "Explanation of the bug" "358": "How does the bug happen and how should we fix it?" "473": "One approach: Marking assets as used or not used" "509": "Cons of asset locking" "574": "Blackboard brainstorming" "604": "In-flight asset protection" "673": "Usage patterns of assets" "801": "Keeping an asset usage count and its associated problems" "965": "Introducing render_group generation IDs" "1202": "Cons of this approach: Possible wrapping of the IDs" "1304": "Maybe the wrapping is not a problem, after all" "1394": "Some other complications of this approach" "1634": "Feasibility of using generation IDs given the current state of our asset system code" "1845": "Generation IDs make MoveHeaderToFront superfluous" "1920": "Doubly-linked lists and threading don't play well" "2158": "Blackboard explanation of some problems we will encounter" "2249": "One possible solution: Queuing our MoveHeaderToFronts so that only one thread performs them" "2342": "Another solution: Lock-free heap data structure" "2399": "Yet another idea... that also poses some problems" "2568": "We could also sort the generation ID-asset pairs separately" "2780": "How about a multithreaded heap?" "2902": "Coding the "generation IDs" approach" "3328": "Updating the GenerationID" "3444": "Compressing GetBitmap and GetSound together" "3710": "Leaving the code in a working state (although we are still not finished)" "3837": "Q&A" "3892": "Hey Casey, can you do a 2-min recap of everything done today?" "4069": "How often do you actually implement something from a paper?" "4125": "What would be the worst case scenario if you had multiple threads trying to remove an asset? Couldn't you just wait till no thread was trying to remove the asset?" "4154": "One way to avoid the lock is to split the LRU list into two parts. Keep the most recent 25% of it in one partition and the least recent 75% in another. Only move an asset to the head of the list if it's in the least recent part" "4194": "So IIUC, our problem is that "least recently used", in this context, means "least-recently-stopped-being-used-in-all-threads", and we can't really know that for certain without having some form of inter-thread communication.... Is that correct?" "4243": "Meathead protein-powder action" "4398": "You don't take the lock on hot assets most of the time" "4454": "I haven't seen you drink any milk this stream, is that why you are tired?!" "4496": "You can avoid the genid gap checking list by keeping min/max/cnt rendergroup "done" ids, and freeing all assets 0? Or will we now need to include the ASCII control chars to make CodePointCount work?" "4002": "Will you have stream later: On various meta programming tricks? Some useful & nifty tips and tricks for developers?" "4052": "Which Chinese dialect are you thinking of supporting?" "4115": "How big do you think the game will be in the end?" "4131": "How about right-to-left languages?" "4201": "We ended the questions right as the stream ended" --- name: "day171" title: "Adding Font Metadata to the Asset Builder" markers: "25": "Recap and plan for today" "294": "We want the ability to load multiple fonts" "380": "TODO(casey): Are there larger numbers than 4096...?" "426": "Using more explicit asset structs in the asset packer" "743": "Moving the font loading code to a separate function" "1040": "Freeing the memory taken by the fonts" "1105": "We need at least a font for the game and another one for debug purposes" "1141": "Our STB code path is broken for the moment" "1170": "Making fonts available as usable assets" "1216": "AddFontAsset" "1285": "Pulling together duplicated code into AddAsset" "1659": "Hardcoding the codepoint count until we know the range of characters we want to load" "1821": "Initializing the global font device context at startup" "2194": "Building the font tables" "2338": "Writing the asset font information into the asset file" "2501": "Faking the horizontal advance using the width of the current character" "2722": "Loading the font data from the asset file" "2745": "The codepoint loading gets tricky when using more than one asset file..." "3048": "...but we can do the codepoint rebasing per file!" "3455": "Q&A" "3485": "Give us a sec" "3505": "I tried to explain to someone that a color is just a uint32 and I am not sure I got it across" "3541": "Blackboard: "Color" -> Ambiguous term!" "3826": "You added Textmetrics into the struct and then decided to alloc it - why? And whats the benefit?" "3902": "About the language having different fonts. Would this apply to added packages by other people?" "3960": "I'm talking about in terms of how the GPU cares about the color of a pixel, as opposed to a struct with float r,g,b,a. Which is not really necessary for a buffer thing" "3982": "Blackboard: GPU ~ CPU" "4447": "Do any systems ever represent light as an actual frequency and change that value based on interaction with the simulated environment?" "4588": "If you take in user input at some point will you worry about blocking Unicode control characters?" "4604": "So you care about the stack memory. When would you start to really measure it, or is some gut feeling enough? I would never had that idea before not getting an actual error" "4635": "What is HDR?" "4731": "Do you think there will be a time when CPU and main bandwidth is fast enough to replace GPUs entirely, going back to the days of software renderers?" "4752": "Wind things down for dinner" --- name: "day172" title: "Extracting Kerning Tables from Windows" markers: "48": "Recap and plan for today" "163": "There's a bug that prevents the fonts from loading" "217": "Writing fonts in a separate asset file" "370": "Stepping through the asset packer" "773": "We were not setting the horizontal advance correctly. For the moment, we'll just hardcode it to be the width of the current character" "995": "We were using the incorrect AssetType for our font glyphs" "1130": "Testing and still not loading" "1141": "Stepping through the asset loading code" "1276": "Take it back" "1305": "On getting older" "1336": "Debugging LoadFont" "1363": "We were not calling LoadFont yet!" "1419": "Implementing PushFont" "1620": "The fonts are back!" "1697": "Let's look for the correct kerning pair values" "1786": "Reviewing the GetKerningPairs docs" "1870": "Figuring out the number of kerning pairs" "1929": "Getting the kerning pairs" "2000": "Structure of tagKERNINGPAIRs" "2163": "What is the default advance?" "2478": "Question the ABCs" "2493": "Checking the system header files to see which functions and struct offer wide-character alternatives" "2603": "Debugging the LoadFont crash" "2730": "GetCharABCWidthsW expects a range, not a count" "2760": "Our fonts look nicer now" "2826": "Using the ABC's A information to modify the alignment of our glyphs" "2893": "(Blackboard) Diagram of the alignment point calculation" "2972": "Our fonts look even better" "3073": "The fonts still look bad, but it's Windows' fault" "3148": "See how Segoe Condensed looks" "3186": "Windows fonts make a fontographer cry" "3267": "We still have to see how our glyph bounding box detection interacts with the system's kerning information" "3421": "The alignment based on the bounding boxes was already correct and we didn't need the ABCs" "3630": "Modifying the TextOutW call in the asset packer to allow Windows to paint glyphs to the left of the specified drawing point in the font Device Context" "3794": "Q&A" "3817": "Could you use another text sample like "AVA WA Ta"" "3862": "Learn something new about Arial and Helvetica" "3982": "How do you know so much about fonts?" "4046": "Do you typically license fonts for use in games? Or does the loophole about rendering them to bitmaps mean you can just use whatever you want?" "4068": "Recommend Google Fonts" "4226": "Is fonts a topic you enjoy? An author once wrote: "If music is the subjective application of physics, then font rasterisation is almost certainly the subjective application of computer science." Do you agree?" "4270": "Probably doesn't make sense to look at kerning for lowercase to Uppercase. I doubt many fonts bother with those cases" "4325": "Would Times New Roman be any better?" "4330": "What are some examples of font / typesetting systems that can do kerning well? Is Knuth's TeX the only game in town?" "4454": "Hmm... good point. More game designers should have a guy / gal who knows about fonts, because I see lots of games where it's hard to read quest text / chat text" "4518": "Regarding the abstract text, I agree! Which is why I asked. Given your experience, maybe you could've read more into that than I could" "4551": "The down-left corner of the "A" is cut, but you search bounds by the pixels, so why did this happen?" "4593": "Have you played Facade and / or met the designers?" "4689": "Clear everything to black instead of white" "4854": "You said Molly Rocket's upcoming game has crazy font functions - can you say one example what about fonts can be crazy? Just wondering" "4872": "What's behind the curtain?" "4884": "Facade was kinda interesting. One time I typoed the first thing I said to the guy when he opened the door and he just scowled, shut the door in my face and then the game faded to black and ended" "4906": "Check our edges" "4943": "Close things down here" --- name: "day173" title: "Precise Font Alignment" markers: "14": "Recap and plan for today" "106": "Review of last episode" "135": "The first line should start one line down from the top of the screen" "287": "We want to be able to access the LineAdvance information without having to load the font" "338": "The placement is not correct yet" "435": "The zero Y is at the center of the screen, not the edge" "459": "Testing multiple sizes inside a word" "534": "We don't have the necessary information to do kerning between characters of different sizes" "566": "(Blackboard) Explanation of the problem" "744": "Our Kerning tables don't specify the initial horizontal offset in the absence of a preceding glyph" "830": "Special-casing the kerning for the null glyph in the asset packer" "902": "Fix the variable shadowing" "913": "Still not lining up with the left edge and upper edges" "951": "Lining up with the top edge by looking at the ascenders and descenders of the font" "1311": "The characters still don't line up with the top edge, but it's because the font includes glyphs taller than the ones we are displaying" "1426": "Aligning the text with the left edge. Baking the leading space into the kerning" "1555": "Processing the characters before the fonts to have access to the necessary information" "1838": "Compare kerning" "1923": "The ABC's A was already included in the horizontal advance" "1985": "The kerning is still not quite right" "2025": "Using our own measurement of the width of the character instead of the ABC's B" "2146": "Debugging some more" "2449": "Checking the documentation of the ABCs" "2622": "(Blackboard) Thinking some more about the problem" "2704": "In order to be able to flush-align all characters to the left, the prestep of the current character should be applied to the next character!" "2865": "Subtracting our kerning adjustment from the previous character" "2985": "No kerning for characters following the null codepoint" "3057": "Is it even possible to match Windows' kerning exactly?" "3090": "We'll have to compress the font ranges to support kerning for other languages" "3351": "Q&A" "3421": "The more I see the kerning in Notepad, compared to yours, the more awful it looks to me" "3444": "I realise that this is uncharted territory, but it seems to me that font rendering is taking more time than the rest of the renderer. Is that normal?" "3629": "Isn't Japanese evenly spaced?" "3652": "Migraine :(. Glad to at least catch the Q&A" "3669": "I was testing kerning in Notepad, Word, Wordpad... No kerning there? Where do you have seen kerning in Windows?" "3686": "Don't forget the boilerplate" "3692": "John Carmack programmed low level graphics and got a Ferrari. Font rendering guy never got anything. When are we going to go back to programming cool superstar things?" "3764": "I'm in my second year at uni for programming, and I still have problems getting my head around single things. My question is how long did it take you to have a good understanding of programming in general?" "3791": "Fair enough. Maybe it just seems like progress is slower for some definition of "progress"" "3822": "I'm confused why the font rendering relies so much on windows. Isn't all this stuff stored in the font files, or is that harder without Windows text metrics and such? Or, to put it another way, how would what we did today be different if we were using stb_truetype?" "3858": "On the MSDN entry "Uniscribe Glossary" ABC Values is better explained how Windows understands it" "4020": "Ignore the documentation and just do GetCharWidth32" "4093": "See how that kerning looks" "4210": "Do you use the graphics card at all when rendering?" "4226": "I'm sure this has been answered so feel free to ignore if true. What are the features of C++ that you use that keep you from using just plain old C?" "4252": "When you say Windows uses kerning, why is every letter never overlapping in the space of the followed letter? In your code I see the letters overlapping. Did I understand kerning wrong?" "4296": "O-oh yeah, well, John Carmack also got to make Rocketships, so he wins" "4323": "Are you saying Adobe has better programmers than Id?" "4381": "Why didn't we use bitmap fonts and used TTF? Bitmap fonts are cross platform, are they not?" "4416": "When I render on a GPU, is there a way without copying the render result back to RAM?" "4444": "Japanese isn't evenly spaced. Some characters like 「 and 」 rely on kerning" "4497": "How do you render to the GPU?" "4527": "Favorite font for reading?" "4544": "To display the result" "4594": "I almost got a headache when you said alignment is not the same as kerning, please expound" "4611": "Blackboard: Spacing vs. Kerning" "4814": "Would you rather have a CPU with more cores than a GPU, or enough clock cycles to outperform the GPU with software rendering?" "4832": "You can look here, 3. Tsumegumi for Japanese kerning" "4943": "When thinking Adobe has a market value of over 40billion, why no great programmer wants to do a better Photoshop?" "5080": "There are actually a lot of people competing with Photoshop, and you are using one of those products on stream right now..." "5161": "Wind it down" --- name: "day174" title: "Adding Sparse Unicode Support" markers: "15": "Recap and plan for the day" "108": "Spaces are not displayed" "170": "Adding the kerning value for space to the kerning table" "245": "But wait... that kerning value was already there" "291": "Explanation of Casey's previous assumption of what caused the bug" "354": "Debugging the asset packer" "386": "It seems that the asset packer does not process the space codepoint" "465": "The asset packer ignores the space glyph because it has no visible pixels" "497": "Spaces are back but we have lost the small letters" "498": "Run Handmade Hero, although..." "530": "Fixing a bug introduced while fixing the problem of the visibility of the space glyphs" "578": "Checking the width of rendered spaces" "617": "Choosing a target foreign string to test the rendering of non-ASCII characters" "681": "Checking that Arial has all the necessary codepoints" "731": "Finding the codepoints associated to the test string" "892": "A table that encompassed the complete range of characters necessary to represent both ASCII and our target kanji would be massive" "970": "We need a way of condensing the ranges of available characters" "1003": "(Blackboard) Layout of the 1-D symbol lookup table" "1091": "Easiest but slow solution: store the codepoints themselves for each row of the table" "1162": "What about preprocessing every string to store the indices to the glyph tables instead of the characters?" "1322": "Or we can simply store one big table that maps each character to its associated glyph index" "1383": "Any objections?" "1407": "Storing pairs of codepoints and bitmap_ids instead of just bitmap_ids" "1480": "The new codepoint table will be decompressed at runtime and used as a direct lookup table" "1531": "Let's implement that" "1850": "Adding the kanji owl characters by hand to the asset file" "1880": "Do AddCharacterAsset for the Kanji Owl straight after adding the other font Assets" "1934": "Modifying the code that uses plain characters to use glyph indices instead" "1962": "Setting a maximum glyph count" "2227": "Fonts are done" "2282": "Using a huge table at asset pack time to map every Unicode codepoint to our glyphs" "2605": "Freeing memory associated to the loaded_font variables" "2639": "Propagating the last changes through the code" "2691": "We can't refer to the kerning of a pair of glyphs until we have mapped both glyphs" "2958": "Modifying the HorizontalAdvance table as the last step before writing the font to the asset file" "3121": "(Blackboard) Writing only the part of the HorizontalAdvance table that we'll use" "3184": "Starting to implement the partial storage of the HorizontalAdvance table" "3372": "On freeing things" "3381": "Leaving the code in a compiling state before the end of the stream" "3547": "Q&A" "3566": "I noticed that you rarely comment your code. Your comments mostly consist of TODO comments. What are your thoughts on commenting your code, considering a lot of it is pretty complicated, unless of course you don't see it as such? Or do you think that since you write good code, it doesn't require comments to be readable?" "3719": "Why was your first calculation of the GlyphTable index size too big (64k) and reduced to 2k, and still later went full-on 64k again? What changed the size?" "3774": "Would it be a good practice to comment after writing all your code for others?" "3957": "Since the questions are slow today, when do you think you will write a proper RNG?" "3973": "Or a real hash function?" "4026": "My comment-writing rule for a while has been: "code should clearly tell you what is being done; comments, if you need them, should only tell you why"" "4075": "How long have you been coding (years)?" "4083": "When will you implement the chocolate wine fountain?" "4119": "Call it" --- name: "day175" title: "Finishing Sparse Unicode Support" markers: "23": "Recap and plan for today" "70": "Reviewing the the current status of the test asset builder" "295": "On type-safe memory allocations" "433": "Reserving space for the null glyph" "639": "Happy Birthday, Windows" "798": "Running the asset builder" "830": "Reviewing the asset loading code" "870": "We don't address Unicode codepoints directly anymore" "916": "Unpacking the dense glyph table" "978": "Using an unnecessarily big Unicode mapping table for the moment" "1193": "Storing the highest used codepoint in the asset file" "1345": "Hunt for ONE_PAST_MAX_FONT_CODEPOINT" "1383": "Genius day at Handmade Hero" "1406": "Casey's mommy says he's very good at programming" "1479": "We normally wouldn't be doing finicky suballocations by hand" "1580": "Adding extra finalization code after font loading" "1690": "Building the Unicode mapping table" "1970": "Implementing ZeroArray helper function" "2050": "Guarding against overflows by double casting" "2127": "Substituting codepoints with glyphs" "2245": "Implementing the glyph lookup routine" "2306": "Debugging today's and yesterday's changes" "2334": "No fonts visible. Let's inspect the font loading code" "2373": "OnePastHighestCodepoint was set but not saved to the asset file" "2558": "Another small error in font loading code" "2600": "Our font is back!" "2608": "Displaying the handmade owl unicode codepoints" "2648": "We egged Casey on" "3070": "The kanji codepoints are there but not kerned properly" "3140": "Q&A" "3219": "So, are we done with fonts now? Moving on to other parts of the debug?" "3272": "So what will we be moving onto next week?" "3313": "Any chance you could use a different font for the editor? Hard to tell difference between 0s and 8s" "3334": "It's possible that that's how it is supposed to be kerned" "3417": "Maybe it's just twitch, but the letters in Red look a bit off on the edges" "3578": "Might be a basic question but why do we need our own font rendering? Doesn't Windows have its own font rendering functions we could call?" "3674": "I saw you were wearing something around your forearms. Is that to treat Tendinitis? I heard about this condition from typing too much" "3687": "People don't understand why a font rendering system can be complex because they think in terms of pixels. Any comments on this (only if there are no other questions)?" "3719": "Can you check if your numbers are monospaced? For example, 111111 should be the same width as 999999" "3797": "What happened to ZoomIt?" "3861": "Not a question but I think ZoomIt is just on the desktop" "3948": "The ones and nines don't line up the same way in game and in notepad" "4017": "How do you have the background black in Mischief? I found it a bit tricky to change the background color for some reason, surprisingly!" "4037": "How do you prefer to traverse trees, loops or recursion? Why?" "4066": "If you want to start your own game project, do you start from scratch, use Frameworks / API / SDKs (SFML, SDL, etc.) or use an engine (custom made by you, or one that already exists)?" "4121": "They don't line up relative to each other though" "4165": "Any plans to add scripting or modding hooks?" "4193": "Off-topic: How do you grep with your Emacs config?" "4241": "Sure. Some (reasonably) think of the screen as a grid of pixels and that font rendering is directly plastering that font on the screen. So nvm, they just haven't understood beyond bitmap fonts" "4306": "What font do you use in Emacs?" "4339": "Why did you use GlyphIndexFromCodePoint instead of an array of (mostly null) pointers to achieve sparseness?" "4398": "How valuable do you think non-mono-spaced fonts would be in, say, an editor?" "4450": "Could you recommend a website or YouTuber that could teach me coding? I really want to learn" "4605": "I like to limit the scope of my functions to be defined only where they're used. How do you workaround the fact that C doesn't have locally defined functions? Do you use functors?" "4668": "Vertical cursor navigation is easier to follow in a mono font" "4685": "Tried to use grep in Emacs: the program crashed" "4706": "How do you handle introspection / metadata to build your editor inspection tools?" "4745": "Wind it down" --- name: "day176" title: "Introduction to Debug Infrastructure" markers: "67": "Plan for today" "154": "Test-driven development doesn't help solving the harder problems of game programming" "299": "Purpose of debug services" "393": "1) Coaxing bugs to the surface" "480": "2) Locating bugs that are clearly present but difficult to pinpoint" "718": "We'll focus on versatile debug services aimed at solving difficult bugs" "801": "Logs. Example of debugging framerate problems" "949": "We could start by recording our debug timers on each frame" "995": "Simplifying the usage of our debug timers" "1058": "We could combine the log and the looped live code editing replay system" "1201": "Limitations of this approach - Is not particularly good for multithreading problems" "1283": "Necessary components: counter log, replay system, log of memory consumption and diagramming" "1336": "Diagramming" "1557": "We want all the debugging subsystems going through the same log" "1634": "We want to avoid having to change the code in order to debug it..." "1751": "...and also avoid having to remove debug calls once we're done" "1904": "Review of desired features for our debug system" "1976": "Will we need tuning/fiddling support?" "2200": "Let's start building the debug system" "2285": "The old debug cycle counters were lousy on purpose" "2580": "Improving the interface of the cycle counters" "2607": "Abusing constructor/destructor pairs to achieve that better interface" "3289": "We shouldn't need to store values anywhere to make paired calls at the beginning and end of a frame" "3431": ""I just kind of ruined The Variable"" "3663": "Review of the inner workings of the new cycle counter interface" "3735": "Testing that the code still runs after today's changes" "3757": "Q&A" "3802": "Is there a way to determine how much overhead the debug takes when it is enabled? (Or is there such a thing as debug levels?)" "3888": "Why not use a simple template? That would remove storing the ID, e.g. template struct timed_block {};" "3950": "Would you agree that there is a similarity between test driven development and "writing the usage code first"?" "3992": "Would you consider functional programming for game development?" "4081": "How does the StartCycleCount get stored in the struct when you don't explicitly set StartCycleCount = StartCycleCountInit or something what you did with the ID?" "4135": "Do you get Heisenbugs, where the bug happens only when there's not any debug code running?" "4218": "So the destructor gets called right when it goes out of scope?" "4448": "Community fight" "4465": "Close this down and wrap up another episode of Handmade Hero" --- name: "day177" title: "Automatic Performance Counters" markers: "11": "Plan for today" "100": "Recap of work done in the previous episode" "221": "TIMED_BLOCK should be easier to use" "309": "Timing a block should be an inexpensive operation" "423": "Don't be afraid of major changes" "467": "Getting rid of the debug counter IDs" "505": "Preprocessor directives" "667": "The __COUNTER__ preprocessor directive" "707": "Consider MSVC's gender" "768": "Preprocessor directives are frequently used in debug code" "802": "Getting rid of the argument to TIMED_BLOCK" "876": "Avoiding predefined values while still describing the location of the TIMED_BLOCK call" "1009": "Mapping filenames and line numbers to IDs" "1044": "We could use some sort of mapping strategy, but that's too complex for a debug log system" "1154": "An alternative method: Avoid looking for filenames and line numbers until we need to print them" "1247": "Depending on the amount of information we log, this method could tax our write bandwidth" "1426": "We'll try first the alternative method" "1488": "Have a thought" "1491": "We could resort to __COUNTER__ because of our single compilation unit build!" "1547": ""Are you thinking what I'm thinking?"" "1590": "Quick test of the __COUNTER__ approach" "1765": "__COUNTER__ passes the test!" "1796": "Dealing with two translation units. We will keep one array of debug records for each of them" "1904": "We could define the DEBUG_PREFIX preprocessor symbol to access the proper array" "2002": "Forward-declaring the debug record arrays" "2096": "Accessing debug records" "2166": "Using the DebugRecordArray preprocessor symbol instead of DEBUG_PREFIX" "2280": "Defining the fields of the debug record array" "2313": "Implementing the timed_block constructor and destructor" "2432": "Using the new TIMED_BLOCK syntax" "2568": "Adding HitCount as an extra parameter to TIMED_BLOCK" "2696": "handmade_debug.h: Fuss with the vagaries of C++ preprocessor nonsense" "2700": "Expanding __LINE__ in the presence of the paste operator" "2908": "Modifying OverlayCycleCounters to work with the debug record arrays" "3041": "Testing today's changes" "3060": "Identifying our debug counters using the file names stored in the debug arrays" "3100": "It works!" "3129": "What we have accomplished today" "3188": "Q&A" "3256": "There's an alternative way to start / end the counter instead of using constructor / destructor pair, and you don't have to store the data in the struct. Maybe not as convenient but it's worth mentioning. I use it quite often when I have to 'begin X' -- write code -- 'end X'. It's basically a hacked / tweaked version of C#'s 'using' statement. I think you'll find it interesting" "3313": "Write out elxenoaizd's suggestion" "3393": "I feel like I missed something: why does the array name need to be different between builds?" "3440": "How do you move your typing cursor around so fast? Is that an IDE-specific macro?" "3487": "Could you expand on how you would have done the char *Filename / *FunctionName with uints instead?" "3554": "This is awesome. You have a few minutes left: could you output the results or show them in the debugger?" "3574": "handmade.cpp: Print out the debug cycle counts" "3874": "Do you recommend taking game-programming as a major or programming in general?" "3888": "What other useful preproc values could we use other than __FILE__, __FUNCTION__ and __LINE__?" "3947": "I'm not sure I fully understand Unity builds. So Unity build is when we compile everything to a single file? I don't think that's the case because we do have multiple source files in HMH..." "4036": "Where did the whole weird IInterface CClass style of programming I see everywhere come from?" "4063": "Why do you have both u32 and uint32 typedefs? What's the difference?" "4098": "If exceptions are bad, then what is a good way to handle errors? Just return error codes? A global error value like in errno or GetLastError()? What do you think of the idea of having a central error handling function that we call and pass it the error id and it acts accordingly (switch statement maybe)?" "4239": "Why use Record->FileName instead of Record->FunctionName?" "4247": "I am kind of new to the stream. Is there a reason you hate C++ so much?" "4334": "Will this game compile with gcc or only with the Visual Studio compiler?" "4384": "General Programming Question: Do you see the use of public variables being accessed outside the class bad practice, versus using a "getter / accessor" function?" "4443": "handmade.cpp: Demo bad programming practice" "4592": "How would you handle parsing errors / exceptions in a recursive decent parser?" "4608": "Internet says __COUNTER__ started on VC++" "4673": "Spin it down" --- name: "day178" title: "Thread-safe Performance Counters" markers: "16": "Recap and plan for today" "147": "Packing a tiny monospaced font into the asset file" "245": "Supporting font selection" "414": "Adding the debug font" "549": "Testing the packing of multiple fonts" "608": "The AssetCount is wrong. Let's debug that" "710": "We're missing one entire character set" "885": "Are TypeIDs not initialized?" "922": "Let's see if it's the asset processor's fault" "1056": "The way the code is structured, we can't BeginAssetType twice for the same AssetType..." "1093": "... but we can group all the font packing calls inside WriteFonts to sidestep that issue" "1156": "Tagging the fonts" "1325": "Testing the new font packing" "1360": "Picking a different font" "1435": "It works!" "1473": "Specifying the size of the font" "1650": "Adding some extra TIMED_BLOCK calls" "1919": "There are still two problems that we need to solve:" "1922": "1) The timing of anything that encloses the render process is wrong" "1960": "2) The access to the timers is not thread-safe" "2100": "The first problem can be solved by displaying the counters with one frame of delay..." "2180": "... but we'll first solve the threading problem" "2202": "(Blackboard) Thread-safe performance counters" "2215": "Review of implementation of performance counters. Using Record->CycleCount as temporary storage is problematic, because it should contain the end result" "2360": "Using a separate value to keep track of the StartCycles" "2415": "The concurrent access to HitCount and CycleCount is also a problem" "2548": "Implementing AtomicAddU32" "2655": "Consulting the _InterlockedExchangeAdd docs" "2756": "The result does not look correct yet" "2780": "Resetting the counters atomically" "2864": "Correcting the _snprintf_s format specifiers of the time counters" "2890": "Updating CycleCount and HitCount atomically together by merging them into a single U64" "3152": "Making the reading and resetting of the counters also atomic using an unconditional atomic exchange" "3236": "It seems to be working" "3245": "We are now thread-safe" "3320": "Reporting both DebugRecordsMain and DebugRecordsOptimized" "3528": "Reporting also the line number of TIMED_BLOCKs" "3585": "Adding some more TIMED_BLOCKs" "3630": "The path of least resistance should be the right path, so that doing the right thing is never drudge work" "3670": "Q&A" "3696": "This was, again, pretty awesome! Thank you" "3704": "Wouldn't a union be helpful for that HitCount_CycleCount? It just seems unnecessary having to remember their offsets and / or lengths" "3734": "Yesterday I asked about preprocessor constants other than __FILE__, __LINE__ etc. I did some searching and found out about __TIME__ and __DATE__. Maybe it's useful for us to include a date-time stamp in some of our logs?" "3770": "Can you align the text into columns with %32s in the sprintf or something?" "3789": "handmade.cpp: Align the text into columns" "3865": "You mentioned yesterday that destructors are called when the scope of the object ends. I just wanted to note it seems that if you use it to exit a function instead of 'return' then the destructors won't get called!" "3898": "Will you marry me?" "3927": "Won't rtdsc give wrong results if your thread is pre-empted and scheduled onto a different CPU between the constructor and destructor calls?" "4098": "Are you working on any games other than Handmade Hero?" "4117": "General Programming Question: Do you have any general advice for optimizing code performance, e.g. multithreading, algorithm complexity analysis, etc.)?" "4140": "Sorry I made a typo in the previous question: You mentioned yesterday that destructors are called when the scope of the object ends. I just wanted to note it seems that if you use "exit" to exit a function instead of 'return' then the destructors won't get called!" "4184": "The values are pretty hard to read when they're changing literally every frame. Wouldn't it be better to average them?" "4211": "Have you considered keeping the timers in thread-local storage instead of using atomics every time you write to them?" "4331": "Are lock-free data structures worth the time they take to write?" "4355": "Do you think it would be worthwhile to make the time records hierarchical (like a call tree), and how would you go about it?" "4483": "Can you explain the difference between mutexes and interlocks?" "4517": "Blackboard: Interlocks and Mutexes" "4843": "Wait, about the values, can you draw a graph out of them?" "4855": "NOOO! Save the Cherry MX Blues" "4863": "Will you be able to fix the click bug at the end of sounds with the debug system?" "4896": "Can you still time a smaller section inside the code or does it just work for whole functions now?" "4941": "I noticed you prefer to keep things on the stack and return by value. 0) This helps with locality of reference and is more cache friendly, am I right? 1) Is the stack size something to be concerned about? 2) When returning by value, is the time taken to copy the object and return it something to be worried about? Maybe when the struct is large? In that case, do you prefer to return a pointer to the object?" "4986": "How do threads wait on lock-free structures? Do they?" "5300": "What's wrong with pointers to inline functions?" "5339": "Why you skips my questions?" "5349": "Did you get a degree in CS? What's your background on programming?" "5382": "Wind it down" --- name: "day179" title: "Tracking Debug Information Over Time" markers: "43": "Rant: Dedicate this episode to an awful company" "341": "Boot this up on maybe the last version of Windows which works in terms of rendering fonts" "390": "Apologise to those following along at home on Windows 8" "427": "Our debug timer system is still missing some important functionality:" "446": "1) The timings are hard to visualize" "513": "2) It lacks the ability to point out which code is responsible for missed frames or other performance issues" "632": "We want to keep a longer history of the values of our performance counters" "742": "We are interested in keeping track of events that happen in the platform-specific layer, so some part of the debug system will have to live there" "849": "The platform layer will announce the end of each frame to the debug system" "1054": "The platform layer will also inform the debug system of several other events" "2121": "Writing the plumbing around DEBUGGameFrameEnd" "2220": "Allocating debug memory on the platform layer" "2307": "Improvising the set of structs that will keep track of the values of our counters" "2460": "Modifying OverlayCycleCounters to use the debug memory" "2614": "Making DEBUGGameFrameEnd update the debug records" "2810": "Allocating some memory for the debug storage" "2901": "The debug information is now piped through the new system" "2918": "Recording the snapshots into a rolling buffer" "3027": "Recording the minimum, maximum and average values of timers" "3343": "Using double precision for the values of timers" "3483": "Printing out the statistics" "3529": "The output looks incorrect because we're not using the appropriate type specifier for the timers in _snprintf_s" "3583": "(Blackboard) Deriving the correct expression for the average cycles/hit. (Although it should be hits/cycle; see Q at 1:07:29)" "3944": "Q&A" "3975": "Song: 'Questions For Me' by Casey Muratori" "3985": "Is a C compiler faster in compiling C code than a C++ compiler compiling C-like C++?" "4043": "Shouldn't it be CycleOverHit?" "4049": "handmade.cpp: Change HitOverCycle to CycleOverHit" "4063": "Is there a standard / portable way in C to get a FILE* to a block / region in memory? In Linux there's fmemopen but I can't seem to find an equivalent in Windows. Internet seems to suggest MapViewOfFile but I don't think that is it, I don't want a memory mapped file, just FILE* to a memory region. Does such a thing exist or am I looking at this the wrong way?" "4156": "Are there inherent problems with using composition for writing game engines like there are problems with OOP?" "4178": "Why is the preprocessor able to convert a parameter to a string via the # symbol, but not the other way around, i.e. string stripping, taking the inner value of the string and pasting it? My guess is that it's because this would not make it possible for the macro to be determined at compile time since we can pass it arbitrary strings?" "4264": "Unless I missed it, shouldn't it be CycleOverHit rather than HitOverCycle?" "4274": "Averages of averages need to be weighted by the population size. This is a common mistake that you even see in scientific papers that try to combine the results of other scientific papers" "4327": "Turbo C's successor is C++ Builder from Embarcadero" "4349": "Metaprogramming question: Let's say I want to have a generic dynamic list (resizable array) in my game library. Void-pointers and macros are two ways of approaching this; another is generating the code for the unique list types I want. Is this what you mean when you say "I write C programs that spit out C programs"? If so, can we do this generation at compile-time (like we can do in jai) or are we forced to write and run an executable that does the generation for us?" "4409": "With respect to composition: I have a Player struct that has various other structs to represent what the player is composed of. One could be the Object struct which is added to any entity in the game that I want to behave like an object. Then I create functions that run on objects such as objectMove(Object *obj) so that anything that I want to move in the game would simply have an Object struct within it" "4469": "When writing game engines, how much should a programmer know about how the compiler works, and what is a good way to learn what is going on under the hood?" "4549": "Hey! I am looking to pick up programming, I have some basic knowledge but really would like to know where to get started and any suggested languages you might think are a good place to start" "4594": "How much more engine work are we going to do before diving into gameplay stuff?" "4695": "Can you run around in the game a little bit? The last time I watched was a month or two ago and I'd love to see how it's progressed" "4781": "Your thoughts on using a scripting language with the game engine?" "4804": "For the performance counters, could you perhaps color-code them according to how far outside of an ideal or expected range they are? Similarly is there a way to (roughly) estimate the ideal cycle count of a function?" "4846": "I have an interview tomorrow and I'm going to have to whiteboard. How to not be nervous?" "5154": "That's about it for today" --- name: "day180" title: "Adding Debug Graphs" markers: "11": "We will replace the C standard library functions at some point" "165": "Recap" "246": "Let's display the debug information in a more useful way" "290": "Moving the debug code into handmade_debug.cpp" "485": "Graphing the values of timers" "524": "Displaying also the counters that have not been updated in the last frame" "613": "We will pick the maximum value of a timer over a period of time and use it to scale its plot" "754": "Drawing a rectangle for each counter" "872": "Plotting the rectangles next to the text, aligned to its baseline" "956": "Using the ascender height of the text as the chart height" "984": "The debug display code needs simpler access to font information" "1058": "Using the relative value of the timer with respect to its maximum value to modulate the color of the rectangle" "1209": "Testing the code so far. Our heartbeat graph doesn't line up with the text" "1256": "Centering the timer plots with respect to the text" "1306": "The automatic change of scale of the timer plots is not perfect, but there's no immediate way to solve it" "1434": "Adjusting the plot sizes" "1551": "Some of the performance counters are never hit and they show as "null". We won't be drawing those" "1678": "We will save the platform layer debug_frame_end_info timings also as snapshots and we will display them as a stacked graph" "1770": "Moving the DEBUGGameFrameEnd function to handmade_debug.cpp" "1948": "Capturing debug_frame_end_info snapshots" "2035": "The order of the debug_frame_end_info fields is specific to the platform layer and it shouldn't be" "2097": "Transforming the individual debug_frame_end_info counters into an array of self-describing debug_frame_timestamps" "2221": "Now we can iterate over all platform timestamps and plot them as a set of stacked bars" "2330": "Using the inverse of our framerate (33 ms) as chart height" "2752": "Implementing RecordTimeStamp" "3030": "Testing the stacked bar chart. It's not positioned correctly" "3160": "The plot seems to be overshooting 33 ms. Let's draw a reference line to check that" "3256": "Yes, we're missing the target framerate" "3293": "Color-coding the stacked rectangles to tell them apart more easily" "3430": "Testing the color-coded rectangles. The plot doesn't look right" "3473": "We never bothered to stack the rectangles!" "3509": "It works now and the majority of the time is spent inside the GameUpdateAndRender function" "3592": "Q&A" "3701": "Doesn't the multi-core rendering screw up your timing?" "3757": "Can you briefly explain how it tracks how long it takes the frame to work and the render engine to work if rendering the debug is part of that work? Also a suggestion, use a key to toggle the debug display to see the game" "3952": "Did you get 4coder set up?" "3977": "Do you ever think it's amazing how 100s of designers can screw up a project by trying to be complex when indie designers can make a better game in a few months?" "4178": "You mentioned that the way you draw rects is not optimized. What do you want to change?" "4244": "Because you're using rendering on multiple threads, is it saying that you're spending more cycles in DrawRectangle / DrawRectangleQuickly than GameUpdateAndRender?" "4346": "Why are you echoing to lock.tmp in your bat file?" "4453": "So after "lib freedom week" we could reasonably easily boot HH off something like baremetalOS and go all "look 'ma no OS" (minus sound I guess)?" "4500": "Will HH be optimized for GPUs or are you sticking to CPU render? Will that be an arduous task or pretty straight forward?" "4532": "If I have a simple app concept that I can't code myself because I'm a scrub, is there any good way to get somebody to make an app for me that is somewhat simplistic and we split profits or even I just get 10%? I don't care about the profits I just want to help develop the app" "4572": "Why are you not using visual studio to write your code? It seems to be a windows machine you are working on" "4611": "Close outta here" "4645": "Announcement: GitHub private repository now available for those who preorder the source" --- name: "day181" title: "Log-based Performance Counters" markers: "11": "Recap and plan for today" "130": "Our performance counters are inexpensive, convenient and thread-safe" "219": "They report the amount of time an operation takes, but not _when_ it happens" "258": "In order to improve our profile view, we need to collect more data" "362": "The action of collecting the data should be cheap. Any real work should be deferred till the end of the frame" "456": "A log-based system could fit our requirements" "498": "Is the amount of logged events going to be too large?" "627": "Let's give the log-based approach a try" "655": "Can we call rdtscp?" "735": "We seem to be in luck" "830": "rdtsc tells us about elapsed processor time" "891": "rdtscp should also report which processor/core is running our code" "1140": "Trying to see if rdtscp returns the core identity" "1220": "We don't have a way of disambiguating threads at the moment" "1258": ""It's kinda nice to get stuff for free"" "1273": "We'll use a lighter version of debug_record to record debug entries" "1402": "Disambiguating threads, cores, debug_records and debug_record_arrays inside debug_event" "1459": "We only need a single big DebugEventArray" "1526": "Keeping track of the position inside the debug event array" "1555": "Double-buffering the debug event arrays" "1632": "Filling in the debug event records" "1702": "The array index will be determined by a preprocessor symbol defined inside build.bat" "1789": "Defining AtomicAddU32" "1954": "Telling apart the beginning and end of a timed block using entry types" "2026": "Pulling together duplicated event recording code into the RecordDebugEvent macro" "2250": "What is the 32-bit interlocked add-exchange instruction? It's _InterlockedExchangeAdd" "2438": "We can't do a synchronous exchange of pointers and clear the event index at the same time..." "2528": "... unless we pack the position and the event index together into a single 64-bit variable" "2741": "Exchanging debug event arrays at the end of the frame" "2790": "Transforming the macros into inline functions temporarily for easy stepping" "2860": "Our debug array is not large enough for the amount of entries we're recording" "2944": "Bump that number temporarily just to see if that really is happening for reals" "2970": "The information we log will allow more in-depth profiling operations" "3005": "Recap on the bundling together of array and event indices" "3049": "Switching event array indices correctly" "3209": "CollateRecords() can reproduce the behavior of our old non-log-based event system" "3432": "We have two event arrays (one for each compilation unit) and that makes the code uglier than it would be if we had better tools" "3505": "Linearizing the access to the debug_record arrays" "3741": "Fixing compilation errors" "3839": "Accessing the filenames, function names and line numbers of debug_records" "4010": "The log-based system seems to be working" "4057": "Q&A" "4084": "You mentioned that you use a known base address for your memory management. Could you talk a bit more about that? Does that mean I can now find things by just offsetting from that address, and does it mean that if I fwrite this whole block I'll essentially be fwriting the whole game?" "4142": "You can specify which functions to optimize by enabling optimization on the command line and surrounding code you don't want optimized with #pragma optimize("", off) ..... #pragma optimize("", on)" "4191": "Do you ever find use size_t or do you just use u32, u64, etc?" "4220": "Do you keep track of struct padding when you add / remove fields, or is it something you don't think about too much, so order of fields doesn't matter much?" "4256": "Also, what's the point of the core number in the debug info? It seems the thread ID is the important part" "4314": "Look forward to tomorrow" "4355": "How will we avoid collecting or displaying stats on debug-rendering code?" "4373": "Are profilers as bad as debuggers?" "4378": "What do you think about checked exceptions?" "4409": "Thanks and a few words on preordering the source and using the GitHub repositories" --- name: "day182" title: "Fast Thread ID Retrieval" markers: "36": "Recap and plan for today" "172": "On the benefits of having a nice inline profiling system" "310": "The profiling system is only slow in the collation phase, and that is acceptable" "405": "Limitations of the current implementation of the profiling system:" "468": "1) It is possible for the profiler to read bogus data under extremely improbable conditions" "640": "2) The debug records are not stamped with core and thread indices" "660": "The core indices are not that important..." "699": "... thread indices, on the other hand, are crucial" "813": "Two options to disambiguate between threads:" "817": "1) Getting a thread index" "872": "2) Generating unique IDs with an atomic operation to pair our begin and end timed blocks" "936": "Can we find out the thread index with a simple function call?" "984": "How does GetCurrentThreadId work?" "1098": "It looks like GetCurrentThreadId only issues a couple of instructions to get the thread ID back" "1167": "Thread local storage" "1259": "Segmented addressing" "1427": "Is there some intrinsic that allows us to replicate GetCurrentThreadId's behavior?" "1605": "Yes, _readgsqword" "1660": "Replicating the behaviour of GetCurrentThreadId" "1668": "Debugger: Step in there after the jump" "1791": "Testing our version" "1843": "It works!" "1883": "Recording the thread ID inside RecordDebugEvent" "1940": "Abstracting GetThreadId on the platform layer" "2155": "Unifying the timer counters of platform and game layers" "2218": "Exposing the debug system to the platform layer" "2428": "How do we find the locations of the debug structures?" "2495": "We could store them on the platform layer side..." "2529": "...or we could leave the debug arrays on the DLL side and use DLL binding to patch their addresses" "2574": "DLL binding with _declspec(ddlimport)" "2666": "Consolidating the debug structs into a single struct (debug_table)" "2920": "Using the TRANSLATION_UNIT_INDEX preprocessor symbol instead of RecordArrayIndexConstant" "2951": "Accessing only the debug_table from inside the debug-related routines" "3465": "Moving the necessary intrinsics to the platform layer" "3526": "Testing. There's a bug" "3642": "Getting rid of GlobalDebugEventArray" "3670": "And... we're back!" "3710": "Q&A" "3758": "What do you think is an effective way to get better at assembly? Go over a book / tutorial? Read the code disassembly in VS? Mike Acton can look at a piece of code for a couple of seconds and estimate how many cycles it takes and what the assembly code for it is. I'd like to reach that level one day" "3897": "We're actually a pre-recorded laugh track" "3908": "How would you deal with switching between multiple APIs in a single application (like software / hardware renderer)? Would it be structured similar to the platform layer?" "4295": "Why don't compilers expose API that gives us information about our code (access to the AST, etc.)? Because when we write a top-down parser we're essentially writing something that the compiler already has" "4475": "Are you still using the software renderer or did you move over to DirectX or OpenGL?" "4480": "At what point does a person become a good programmer? When do you think you became a good programmer?" "4546": "How do you handle programmer burnout / depression? Those days when you're just not in the mood to do anything, not productive, you're demotivated, you can barely do any coding, you'd rather do 'anything' else other than what you should be doing" "4659": "Do you really prefer to save two unconditional jumps (so the CPU pipeline won't be flushed at any chance) instead of Compiler & Platform Independence (referring to the GetThreadId part)?" "4728": "Why are you making an engine instead of a game?" "4887": "Do you think implementing a regex matcher is worth it / useful for meta programming?" "4901": "You seem to be pretty unhappy with the quality of modern software. Do you think programmers were better in the past? Is the software you produce always flawless and bugless? Asking seriously, just trying to understand your point more clearly. Thanks" "5241": "Wrap it up" --- name: "day183" title: "Platform Layer Debug Events" markers: "8": "Recap and plan for today" "116": "Removing the obsolete debug_frame_end_info" "135": "In place of that, we could have an array of counters for the platform layer translation unit" "185": "But we can also write directly to the GlobalDebugTable" "314": "Introducing manual_timed_block to have more flexibility recording events" "508": "Implementing BEGIN_BLOCK and END_BLOCK" "542": "Naming blocks so that we can pair BEGIN_ and END_BLOCKs" "590": "We want to avoid creating scopes for the only purpose of timing what's inside" "613": "Let's write the usage code first" "810": "Naming also the END_BLOCKs" "903": "Implementing the named BEGIN_BLOCK" "1114": "Implementing the named END_BLOCK" "1187": "Renaming TIMED_BLOCK as TIMED_FUNCTION" "1257": "Making the code compile after all the changes to the debug system" "1378": "Reintroducing TIMED_BLOCK and consolidating it with TIMED_FUNCTION" "1560": "There's a compilation problem related to BEGIN_BLOCK" "1652": "Debugging the macro by commenting parts of it out" "1686": "The problem was one of conflicting names" "1736": "Grabbing the GlobalDebugTable at DLL-load time" "1813": "Changing the type of the global debug table to be a pointer" "1928": "Introducing a placeholder GlobalDebugTable in the platform layer" "1980": "The program crashes" "2095": "We did not initialize the counter inside the timed_block constructor" "2106": "Testing the last changes. The platform layer writes now to a separate debug memory" "2131": "Hooking up the debug table from the game code after loading the game DLL" "2215": "The debug array could also live in the platform layer side, but that option would have its own problems" "2337": "The sharing of the debug_table could be better" "2410": "The platform counters still don't show up in the visualization" "2459": "We were not printing the platform layer records yet!" "2504": "Adding the RecordCount per translation unit to the debug table" "2762": "Figuring out the platform layer record count" "2862": "Testing again" "2917": "The Win32Loop closes after DEBUGFrameEnd is invoked, so its value is incorrect" "3025": "We want to have a way of establishing frame boundaries" "3080": "Introducing FRAME_MARKER" "3133": "New debug_event_type: DebugEvent_FrameMarker" "3254": "Testing it" "3310": "(Blackboard) Structure and plans for the debug log. We want to keep a history longer than one frame" "3422": "We need to allocate more memory. Maybe it should come from the platform layer" "3490": "Is the amount of data we want to keep in the static section going to be a problem?" "3573": "Instead of two ping-pong arrays, we have now sixty-four" "3630": "Now we can look across frames and we don't need the snapshots anymore" "3680": "Not as good as a circular buffer but it will do" "3763": "Q&A" "3791": "Are you going to start the hardware renderer before starting on game logic? Or are you going to wait until software doesn't cut it? Or are you waiting for Vulkan?" "3849": "Do you just use the blue line selector and green cursor to make it easier to follow on stream, or is that how you normally like it? I feel like it would get fatiguing on the eyes" "3874": "When do you think it is a good idea to use somebody else's library / system instead of implementing our own? (e.g. Do you use anything from the C standard library?)" "4028": "Missed the first half of the stream, are you saving the past 60 frames into a buffer?" "4060": "If a miracle happens and C++ starts doing things right and addresses the issues in the implementations of most of their features, would you use their features like templates etc., or stick to metaprogramming etc.?" "4082": "In the debug display, are we going to see something like Brendan Gregg's flame graphs (where function call depth is represented on the Y axis)?" "4107": "I think a lot of people would like to see how to write a hardware renderer, myself included" "4233": "Getting good at writing game engines: make lots of them or work on a few larger ones and continue improving them?" "4327": "Close it down" --- name: "day184" title: "Collating Debug Events" markers: "19": ""We have all the code"" "25": "Recap and plan for today" "185": "(Blackboard) Problems related to performance counter visualization" "212": "There's one straightforward approach to performance counter visualization that we could implement..." "256": "...but it poses some problems" "311": "We could sidestep the issue by building two separate views: one hierarchical, the other one a ranking of routines sorted by total decreasing execution time" "520": "Implementing DEBUGOverlay by writing the usage code first" "555": "Thinking aloud about the task" "826": "(Blackboard) We'll support the display of multithreaded routines by segmenting the bar charts into lanes" "1425": "Figuring out the structures that will allow us to draw the charts" "1654": "Testing the new code" "1670": "Filling out the collation structures" "1719": "We'll use an arena to collate the debug events and records..." "1888": "...which means we'll be recollating all the data every frame" "2094": "Testing that we are still running. The memory we'll use for collation should be in place now" "2101": "Collating the debug information" "2393": "(Blackboard) Which event arrays are we going to process?" "2456": "“Sometimes programming just doesn't make sense.”" "2467": "Make CollateDebugRecords() loop over the debug event arrays from oldest to newest" "2631": "Processing the debug event arrays" "2685": "Multithreading and the possible lack of strict rdtsc serialization could interfere with the ordering of the events" "2716": "We'll draw a new set of bars after each frame marker" "2965": "We'll ignore all events preceding the first frame marker we encounter" "3020": "Figuring out the relative clock of events inside a frame" "3138": ""I liked how that completed to nothings"" "3356": "Q&A" "3417": "You could have made your loop this way: for(u32 EventArrayIndex = InvalidEventArrayIndex + 1; EventArrayIndex != InvalidEventArrayIndex; EventArrayIndex = (EventArrayIndex + 1) % MAX_DEBUG_FRAME_COUNT) { ... }; Or did you want to save the modulo?" "3519": "Might not have a ton of on-topic questions. Chat was a bit... distracted" "3525": "What would be the most important things you'd look at when hiring a programmer? What type of questions would you ask? Does he have to have, like, 20+ years of experience?" "3654": "Do you think you do not need to ever worry about modulus or divides anymore?" "3742": "Which Linux debugger is closest to not sucking and what is it missing?" "3774": "On a scale of 1 to Visual Studio, why is Emacs a 1 and when will you join the visual studio master race?" "3850": "Sorry if this has been asked before, but what keyboard are you using?" "3899": "How did you get into Game Development?" "3968": "My girlfriend wanted to let you know that she has the same water bottle as you!" "4043": "What decision process do you use to choose the color of sweater to wear on a particular day?" "4068": "Will you please sign the contract with twitch so we can get good Casey emotes in chat?" "4081": "Have you seen the Poker keyboard series? It's very interesting in that it has all the keys in the center of the keyboard, you never have to leave the center row" "4093": "We'll keep you updated!" "4096": "Still using the 3 bin system for clothes?" "4100": "Does it ever happen to you when you sleep on a problem and then when you wake up the solution would just click in your head?" "4237": "Does it have to be at night, or just when you're sleeping?" "4267": "What time do you usually go to sleep?" "4273": "Could you please expand on what you meant by "in the future there won't be dedicated hardware for graphics"? You mean it'll be more CPU cores and ray tracing instead?" "4354": "Would you think in the next 5-10 years they'll move us from 64-bit to 128 bit?" "4373": "Wind it on down" --- name: "day185" title: "Finishing Basic Debug Collation" markers: "8": "Recap and plan for today" "82": "We left the code in a non-working state" "157": "Review of code from the previous day" "210": "Pushing debug frames into the collation memory arena" "280": "By using MAX_DEBUG_FRAME_COUNT as the size of our event arrays, we assume that only one frame end event will be issued per frame. Let's get rid of that restriction" "353": "Allocating debug_frames" "390": "Allocating debug_frame_regions" "475": "Testing. We are running out of debugging memory" "540": "What is the cause of that error? Are we processing too many frames?" "595": "We were treating the whole event array as if it was populated with real events!" "621": "The game runs now" "644": "(Blackboard) Problems we will face while pairing begin and end events" "922": "We will identify the events with a combination of their thread and counter ids. We will pair them using a stack" "1078": "Forbidding overlapping begin/end paired blocks" "1200": "Allocating storage for the stack to pair the debug blocks" "1378": "Using debug_thread to segregate debug blocks according to the threads that originated them" "1653": "Processing DebugEvent_BeginBlocks" "1774": "Setting the values of debug_blocks" "1842": "In DebugEvent_EndBlock we'll find the matching block, if there is one, and pull it out" "2019": "Finding the frame index associated to the BeginBlock that matches our EndBlock" "2180": "Drawing a debug region once we find an EndBlock" "2261": "Yawn" "2268": "On the perils of overeating" "2283": "We will normalize the size of the bar charts with respect to the beginning and ending clock values of the frame" "2503": "We will only draw top-level blocks, for the moment" "2652": "Removing matching blocks from the stack" "2731": "Implementing GetDebugThread" "2835": "Implementing AddRegion" "2990": "Scaling the bars using the frame's clock range" "3030": "Testing. The game seems to loop forever and hang" "3073": "The bug was that we were not initializing the thread id" "3120": "Still not running correctly" "3215": "After increasing the amount of top-level regions per frame, the program works but runs really slowly and does not show the debug bars" "3243": "Stepping through the code" "3271": "Keeping the largest FrameBarScale to scale our debug bars" "3454": "The scale for drawing seems wrong" "3546": "Let's hardcode the FrameBarScale for the moment for debugging purposes" "3622": "The debug visualization is still not showing properly" "3812": "We were not multiplying the scaling factor by the chart height" "3874": "Q&A" "3938": "Is there still going to be a debug visualization of the asset memory chunks?" "3961": "Can you make a mini episode about project management, outsourcing, freelance hiring, etc.? Programming is great but making a game takes more. If not, can you point to good resources on the topic?" "3980": "Do you use the same memory model as in HMH when writing utilities or meta programs, or do you just malloc and it wouldn't matter because the thing runs once, does its thing and closes?" "4112": "What are the pros / cons of viewing debugging information real time vs logging them and viewing them after the fact?" "4341": "Off-topic. People want you to actually drink chocolate wine some time. Are you up for it?" "4369": "Are you going to IndieCade in Culver City? Would you recommend it?" "4383": "Thank you very much for mentioning cmirror. It addresses a lot of my issues directly and is much more human readable. What was the GetToken written for? For config files? Doesn't seem like for C code" "4424": "How will you debug the OpenGL / Direct3D stuff when you will ship?" "4573": "Did I misunderstand mollyrocket.com update, or should there be a comic there today having something to do with your project?" "4670": "Wrap up here" --- name: "day186" title: "Starting to Debug Event Recording" markers: "8": "Recap and plan for today" "79": "We'll be debugging our event record visualization" "145": "Quick review of the code relevant to the task" "209": "Are we building the debug frames properly?" "242": "Checking that the frame count is correct" "332": "There are too few regions inside a frame" "378": "Stepping through the code looking for the cause of that error" "855": "There seems to be a problem with the BEGIN_ and END_BLOCK pairing" "1015": "Stopping when we hit the END_BLOCK event of the GameUpdate counter" "1066": "Implementing StringsAreEqual" "1312": "The opening and closing GameUpdate events don't match at all" "1404": "The hierarchy of nested events seems too deep" "1533": "Is END_BLOCK_ not working properly?" "1628": "Examining DrawRectangle" "1787": "DrawRectangle is called from multiple threads" "1897": "Could the code that deals with multiple threads be wrong?" "1923": "Stepping through the code at DrawRectangle events" "2000": "Drawing rectangles inside the debug code could be the cause of the bug" "2105": "What does the global debug table look like when we're timing DrawRectangle?" "2445": "Some more stepping through the code" "2560": "Examining event writting inside TIMED_FUNCTION" "2598": "There are too many end blocks for the same ThreadId" "2640": "Is GetThreadId wrong?" "2729": "Testing GetThreadId at thread creation time. It checks out" "2977": "Substituting TIMED_FUNCTION with paired BEGIN_ and END_BLOCKs to avoid constructor/destructor pairs" "3186": "We're out of hypotheses. Let's freeze some threads to run them in order" "3375": "The problem seems to disappear when we run the threads in order. But why?" "3550": "Verifying that GetThreadId returns a u16" "3600": "Perplexing bug" "3690": "Checking that EventArrayIndex is aligned to 8-byte boundaries" "3975": "Outsourcing the problem to the stream" "4013": "We could debug the problem in isolation, on a simpler version of the code" "4057": "Q&A" "4084": "Try running without timing DrawRectangle" "4244": "The MSDN documentation for __readgsqword states "These intrinsics are only available in kernel mode, and the routines are only available as intrinsics". If this is the case, how were you able to use __readgsqword to read out the thread ID? (I'm not really sure what the difference between kernel mode and user mode is)" "4330": "You said that it seems to work normally for a little while, then stops working when it's under stress. Maybe let the threads run wild for a little while, then freeze them? Or is this not possible with the debugger?" "4568": "Is it possible that the ArrayIndex part somehow got swapped out during begin / end records?" "4584": "Did you create your colors to be easy on the eyes? If not, how did they come to be?" "4601": "Didn't you remove the EndBlock call?" "4803": "handmade_render_group.cpp: Make DoTiledRenderWork a TIMED_FUNCTION" "4870": "handmade_render_group.cpp: Make IGNORED_TIMED_FUNCTION by a TIMED_FUNCTION again" "4970": "If the debug code is slower than the actual runtime of the game, how can we rely on the debug systems to give us accurate timing of how long things are taking in the game since they naturally take more time in debug mode?" "5119": "handmade_debug.cpp: Render debug information for fewer frames" "5342": "If I remember correctly from the other day, you discard events if buffers are full. Are you sure all buffers are big enough?" "5390": "build.bat: Switch to -O2" "5469": "Could it be threads running across a frame boundary?" "5581": "Leave it in a state where it is broken" --- name: "day187" title: "Fixing an Event Recording Bug" markers: "8": "On the headwind of live streaming" "53": "It would seem that the viewers of Handmade Hero solved the bug from the last stream" "181": "Description of the effects of the bug" "270": "Even with lots experience, difficult bugs will still happen" "348": "This bug was not so complicated, but its source laid outside what we considered to be the set of probable causes" "487": "The bug is probably related to incorrect translation unit indices" "602": "RecordDebugEvent may generate an incorrect translation unit index if it's not inlined by the compiler" "722": "Checking that theory" "841": "Is one of the timing functions in handmade_optimized not working properly?" "870": "Disabling optimizations" "912": "The bug does not reproduce in debug mode" "956": "Stepping though the optimized code" "1080": "RecordDebugEvent is not inlined" "1135": "Yes. Wrong translation unit. The forum nailed it" "1171": "Making RecordDebugEvent a macro fixes the issue, but..." "1218": "Owl of Success Moment" "1264": "... we should get rid of the code related to translation unit indices anyways; it introduces too much complexity and opens the door to subtle bugs" "1362": "We won't remove the translation unit indexing yet" "1458": "Back to visualization. Let's avoid producing regions that would be invisible in our debug plots" "1574": "Introducing options to compile away the profiling code" "1765": "According to the debug display, we should be running at a higher framerate" "1892": "Validating rdtsc measurements against wall clock time" "2010": "Recording the wall clock during FRAME_MARKER invocations" "2419": "Our display does not agree with the framerate because we are not taking into consideration the time it takes to collate debug records" "2483": "Selectively setting SecondsElapsed instead of ThreadId and core index" "2841": "HAL: "I'm sorry, Dave, I can't... I can't save the file"" "2900": "Testing today's additions. It's odd that the time we spend inside FrameWait and FrameDisplay went up" "3000": "Adding DebugCollation counters" "3030": "DebugCollation takes a lot time" "3069": "Using the wall clock times to print the time it takes to draw a frame" "3240": "We're at 250 ms/frame" "3274": "Without drawing the debug rectangles, it goes down to 91 ms/frame" "3345": "Disabling debug event recording, we get back to our original performance" "3554": "Our collation of the debug records is very expensive" "3636": "Q&A" "3665": "What's your favourite bug of all time?" "3708": "Often when I'm debugging, I have to stop myself from changing stuff at random because of mental laziness, hoping for "an even number of sign errors". Do you ever have that urge? If so, has it diminished as you have become more experienced?" "3919": "Doesn't it go against your philosophy of "write the code as you need it" to make a debugger like this before the game needs much debugging?" "4041": "Is there any way to keep familiar with old code or is working with it frequently the only way?" "4249": "Mok actually found the bug and AndreasK actually figured why it is causing what was happening by looking at the assembly. The compiler decided to not inline the call in the constructor and inline it in the destructor so the start marker is wrong and the end marker is right" "4341": "It looked like that FRAME_MARKER was going past this TODO: "// TODO(casey): Move this to a global variable so that there can be timers below this one?"" "4394": "win32_handmade.cpp: Move that TODO down and check if GlobalDebugTable exists" "4447": "Do you really care about compilation units or just threads? Hash the thread IDs" "4486": "Do you write code for this project off stream, for fun or speed?" "4524": "If I don't have a credit card, is there another way to buy it?" "4569": "You brought up your devlog: do you think that writing a devlog is good for the writer, the readers, or both?" "4585": "It sounds like the debugger is not only a tool to find out what is going wrong, but to detect when things are going to go wrong. Is that a fair assumption? I never thought of a debugger as something that keeps me "situationally aware". That sounds like a great idea" "4666": "We have come to the end of the stream" --- name: "day188" title: "Adding Hover to the Debug Graphs" markers: "15": "Recap and plan for today" "82": "The game runs slow because every frame we're collating all events for the past 64 debug frames" "130": "Decreasing the amount of debug frames we process from 64 to 8" "241": "We want to extract more information from the debug display" "380": "We want the debug display to show us information associated to any bar when we hover over it" "405": "Passing the game input to the debug system so that it can access the mouse position" "467": "Checking if the mouse position falls inside any given rectangle" "605": "The information to display will come from a debug_record associated to the debug_frame_region" "705": "Adding a debug record and a cycle count to debug_frame_region" "803": "Building a rectangle to test if the mouse pointer falls inside" "990": "Implementing a version of PushRect that takes a rectangle as its argument" "1064": "Testing. It runs but hovering doesn't work yet" "1106": "The mouse position is relative to Window' coordinate space, not to our rendering space" "1235": "Transforming mouse coordinates to the game space" "1350": "Hover works now" "1380": "Changing the position of the debug text on the screen" "1501": "Our ms/frame display shows 0 ms because we're computing it using the information from an unclosed frame" "1627": "We don't want the game layer to depend on Windows' representation of mouse position. The platform layer should transform it into the game's coordinate system" "1710": "Transforming the mouse position inside win32_handmade.cpp" "1830": "(Blackboard) If we want the leftmost and rightmost columns of our backbuffer to have the same absolute X, the (0,0) coordinate will fall on a pixel boundary" "2321": "Pausing collation" "2433": "Defining enumerands for mouse buttons" "2586": "Implementing WasPressed using the recorded HalfTransitionCount" "2706": "Testing. It does not work" "2721": "Cry about it" "2818": "We're not clearing the mouse state!" "2925": "Clearing the half-transition count at the start of each frame" "3036": "See if we can write something that's not total garbage" "3137": "Testing. It works" "3187": "Q&A" "3211": "Put the Pig Hat on the Owl" "3225": "You had four Owl of Shame moments" "3236": "Mouse code bugged for over 150 days, bring on the Owl" "3269": "Will almond milk make me smarter?" "3283": "And on behalf of all the people here, we love you and you are awesome" "3326": "I'm new here. Why constrain yourself to 1-hour segments? Isn't ramp-up time every day hard?" "3389": "How would you go about optimizing the debug rendering? It looks as though there is a lot of unnecessary work with EntityBasis calculation, etc." "3462": "build.bat: -O2 some of that up" "3537": "You've trained everyone to listen for whether you pronounce the letter "t", or its allophone, the glottal stop, when you say the word "buttons"" "3563": "Shoot, wasn't paying attention and I used the mouse code in another program. What was broken about it?" "3582": "At some point, would it make sense to pause and re-display the frame that is currently moused-over?" "3628": "By the way, I'm from iraq, and it's 4am right now. Can you some time do early stream? I don't mind not sleeping until 4am, but in 2-3 weeks university starts and it would be awesome if you bring back early hours" "3659": "I think you only render "top level" debug timed functions etc. Are you planning on "drilling down?"" "3672": "What is the other long bar? Some kind of frame wait? Should it be that long?" "3682": "Are you an indie developer and / or is this your professional job? If not, what is your day job?" "3707": "I forget if the white line is 33ms or 16ms. Could you add a green line for 60Hz, orange for 30, and red for 10, or something?" "3729": "I noticed in task manager that all of my Steam games are 32-bit processes. Is there a really good reason to compile games in 32-bits rather than 64?" "3800": "The debug display is for processing time. Are you going to do any visuals for memory usage?" "3844": "Would you be willing to do a 1-2 hour prestream?" "3860": "Wind it down" --- name: "day189" title: "Incremental Debug Frame Processing" markers: "10": "Recap and plan for today" "113": "Current features of the debug display" "169": "We want to be able to expand the top-level debug bars" "197": "Should the debug bars be horizontal?" "244": "Turning the chart sideways" "552": "Fixing the height of the bars" "600": "The debug rectangles don't fit in the screen even running an optimized build" "661": "Reviewing FrameRateWait" "786": "Turning FrameRateWait off" "819": "DebugCollation is very expensive" "924": "Processing frames incrementally to reduce collation time" "1005": "We want to avoid restarting the collation on each new frame" "1092": "We will restart the collation when we run out of frame storage" "1110": "Implementing RestartCollation" "1165": "Testing. It works" "1178": "Collating events in sweeps" "1212": "Restarting at the last event array index we used" "1322": "Storing the collation array index inside debug_state" "1368": "Testing that the game still runs" "1380": "Restarting collation when we run out of frames" "1484": "Adding CollationFrame to the debug_state" "1538": "Testing. It still takes a lot of time to run the event collation. Where is it spent?" "1659": "Are we hitting the debug event limit and restarting every frame?" "1696": "Testing. Collation still takes a lot of time" "1758": "Optimization makes it tolerable" "1800": "Why does right-clicking turn the debug display off?" "1906": "It happens both in optimized and non-optimized mode..." "1930": "Let's step through the code to debug this issue" "1997": "Why is DebugState not initialized?" "2055": "We never DebugState->initialized to true!" "2090": "And that solves the collation slowness problem" "2163": "Let's expand the timing bars" "2227": "Right now, we are throwing away all timing blocks under the top level" "2254": "Instead of showing the descendants of the top-level block, we will show the timing blocks whose source is a particular debug_record" "2445": "Implementing GetRecordFrom" "2487": "ScopeToRecord will allow us to move down the hierarchy of debug records" "2558": "When the left mouse button is pressed over a debug block, we'll set ScopeToRecord" "2600": "Testing it. It does nothing" "2680": "We need to recollate the events when we select a time block" "2780": "Implementing RefreshCollation" "2794": "Testing. It crashes" "2816": "Performing the collation refresh at the end of DEBUGOverlay" "2950": "Testing. It works now but sometimes we still hit the maximum limit of regions per frame" "3080": "Implementing TextOutAt, a DEBUGTextLine with explicit positioning" "3252": "Moving the time block debug information next to the mouse pointer" "3396": "Q&A" "3420": "Are the events keeping the same colors across frames? The long one looks like it keeps changing" "3452": "handmade_debug.cpp: Make the colors persist across frames" "3604": "handmade_debug.h: Add ColorIndex to debug_frame_region" "3708": "Does the 0.5 pixel error in yesterday's stream matter a lot? I mean, it seemed a pretty easy thing to overlook. Would it make some calculations erroneous?" "3761": "Why are there blank gaps on some of the bars? And why are the collated frames not flush with the other lines?" "3793": "Is there a reason why we have many different starting points for coordinate systems (center vs top-left vs top-right corners; windows vs Direct3D vs OpenGL)? Wouldn't our lives be easier if there was a standard for them?" "3849": "With handling sorting here, will we finally handle sorting of the other sprites in the game? Or will we just push that off further?" "3866": "Why do we have both bool32 and int32?" "3881": "Pretty cool! It does seem like a lot of calls take very different amounts of time even though they're probably not doing anything different. Is that due to other active processes? Is it usually worthwhile to try to get more consistent timings?" "3905": "How 'valuable' do you think C++ operator overloading actually is? I'm thinking of fully moving to just pure C. Do you think it would be inconvenient / a hassle to program without them? (Vector operations, etc.)" "3940": "Will you show us how to do hit detection for obscure shapes that may or may not exist in the debug UI?" "3967": "Have you seen the UE4 GDC Trailer and what are your opinions on it? I understand we are all indies, but just in general, from a player standpoint" "3994": "The longer bars (which I assumed was when the collation was happening) are farther left on the screen, than the shorter bars" "4030": "By obscure shapes, I mean a slice in a pie-chart" "4150": "Yes" "4264": "Yes the graphics. Check it out whenever" "4367": "[re functions taking different amounts of time] I mean, if we don't send any input and essentially the same image keeps getting rendered repeatedly, we still see a lot of fluctuation in the amount of time being consumed per frame. We have a lot of chop where I would have expected relatively calm waters (unless we're losing time to other processes on the machine)" "4512": "Curious what point represents the amount of time it takes the operating system to set up the parallelism, if parallelism is the right word" "4586": "Do you know why one of the worker threads started after the others?" "4636": "Every once in a while it seems like a frame gets missed; I've noticed that happens in things I do as well. Is there a way to get around that reliably?" "4716": "What do you think of the theory that says we already know everything, all the knowledge there is, but we just don't remember it? So when we study, etc. we start remembering things..." "4817": "Announce an announcement and sign off" --- name: "day190" title: "Cleaning Up Debug Globals" markers: "14": "The only reason we are writing a user interface is to support our debug system" "68": "Since we are the only users of the UI, we don't care if it's not intuitive, as long as it provides efficient interaction at a low implementation cost" "188": "Recap" "202": "Our approach to UI code" "285": "Initial plan for today: Turning off the profiling visualization" "429": "The debug UI can be a nice complement live code editing" "559": "Change of plans: We'll get rid of the global debug variables" "630": "Moving global variables inside the debug state" "650": "Making sure all routines have access to the debug state" "742": "It will be better to access the debug state through the DebugGlobalMemory. Implementing DEBUGGetState" "1035": "Testing. We got rid of those global variables" "1099": "The memory for the DEBUGRenderGroup comes from the transient arena. It should come from the debug arena" "1145": "Performing the DEBUGRenderGroup allocation inside DEBUGReset" "1206": "Access to the debug state should imply its initialization" "1340": "CollationArena will be a subarena of DebugArena" "1430": "Initializing the debug RenderGroup" "1472": "DEBUGReset will call BeginRender" "1542": "DEBUGOverlay will call EndRender" "1610": "The debug system shouldn't rely on the asset system; debug assets should be baked into the binary" "1965": "If we want the debug system to have access to the asset system, we need to make sure that the asset system is initialized first" "2038": "Implementing DEBUGStart and DEBUGEnd" "2349": "Testing. Live code editing and debug services work together now" "2410": "Resizing the profile view by changing its orthographic projection" "2683": "The mouse pointer position should also be transformed" "2727": "Controlling the placement of the profile rectangle" "2997": "Adjusting lane heights" "3217": "Displaying the profile rectangle so that we can debug the code that scales and positions it" "3401": "Fixing lane heights" "3660": "Q&A" "3700": "I appreciate that there are more robust ways of implementing such things, but would it be practical to use the debug data to drive some of the game's visual effects, e.g. fire or, more likely, some otherworldly magical entity or the display on an in-game computer? Maybe it could be a sort of Easter Egg for those of us who know how the game's made" "3765": "There are magenta spikes in the debug graph that happens so fast we don't have time to click on them. How do we plan to catch those? Having the ability to step-over frame-by-frame would be useful, methinks. Another idea is to have the debug text left off at the last rect position we hovered at" "3878": "Wrap it up" --- name: "day191" title: "Implementing a Radial Menu" markers: "7": "Recap and plan for today" "91": "Try something epically ridiculous" "182": "We want to be able to turn on and off parts of the debug interface" "270": "At the moment, the live looped code editing overrides our input, so it precludes interaction with the debug UI" "317": "Using the right mouse button as a "clutch"" "392": "Turning on and off the profiler" "463": "Start writing code at the place you know how to code" "589": "Drawing a radial menu" "648": "Let's pretend we have some menu items" "735": "Drawing the menu items" "820": "(Blackboard) Positioning text strings around a circle" "979": "Implementing Arm2" "1095": "Testing it. Looks OK, but are the labels centered?" "1110": "Marking the center of the circle" "1232": "Centering the text" "1320": "The code required to measure the dimension of labels has much in common with the code that draws them. Let's make sure the implementation of those operations does not fall out of sync" "1497": "Pulling the bitmap size computation out of PushBitmap to make it callable from other functions" "1729": "Defining debug_text_op" "1783": "PushBitmap will ignore non-loaded bitmaps" "1931": "Pre-pushing the debug font at DEBUGStart" "2100": "Fixing some compilation errors" "2170": "Computing the dimensions of a text string by computing the union of the rectangles of each of its glyphs" "2340": "Implementing the rectangle2 version of the inverted infinity rectangle" "2546": "Testing our new code. Implementing DEBUGGetTextSize" "2619": "Drawing the boundaries of the text labels to check their placement" "2730": "The placement of the labels is exact" "2740": "Some thoughts on the "operation" code transformation" "2821": "Centering the labels" "2897": "Finding out the menu index closest to the mouse pointer to change its color" "3194": "Activating menu items" "3217": "Do something like this" "3390": "Testing it" "3519": "Placing the radial menu relative to the mouse position at the time it was invoked" "3593": "Coming attractions" "3637": "Q&A" "3664": "I think you added v3.xy for v3-to-v2 conversion" "3706": "Even if the menus in the circle get cluttered, we could make it so that each button in the circle lead us to another circle / layer / subset of buttons" "3737": "Can you explain a bit more on that closure stuff and how to do it in C? I didn't quite understand it" "4077": "Why did you use radial menu over list or another format?" "4104": "It would be cool if the menu items are aligned with the circle borders, that way there's less chance of the text colliding" "4118": "You mentioned C doesn't officially support closures. Did you ever make an attempt to hack it, maybe via 'functors' or something like that?" "4140": "Have you ever considered a debug output for the stream where we can see your keystrokes?" "4163": "Anticipate mr4thdimention's editor 4coder" "4182": "Oftentimes when using somebody else's API / engine you end up having to 'fight' with it to have it do what you want from it. Do you think that is a sign that one should leave that API and try another / write his own instead of 'fighting' all the time?" "4518": "Are you ready for the world to end tomorrow as predicted by crazy Christians?" "4533": "Since draw rectangle quickly is in its own translation unit, are you going to write that code in straight ASM instead of C / intrinsics?" "4550": "Wait, isn't 4coder already better than Emacs?" "4570": "Can you go into detail on I/O Completion Ports since you brought them up?" "4585": "Wind it down" --- name: "day192" title: "Implementing Self-Recompilation" markers: "7": "Recap" "53": "Plan for today" "152": "Features and limitations of our current radial menu" "241": "We will build our UI around the debug features we already have" "350": "Let's find a way of turning debug features on and off easily from the debug interface" "391": "Quick review of the debug camera" "440": "There's a conflict between the reloading system and the debug event array collation" "513": "Maybe we should flush all events after a reload" "612": "Flushing the array event buffer" "735": "The DLL reloading already cleared that buffer. We only need to restart the collation process" "840": "Moving the ExecutableReloaded flag from the game input to the game memory" "899": "Testing it" "939": "The current way of switching between regular and debug cameras is inconvenient" "997": "We would prefer to automate the process of changing the code and recompiling it" "1082": "We will collect all switches inside the globally accessible handmade_config.h" "1203": "Be banana-cakes" "1221": "Assigning a type to config switches" "1256": "Rewriting the config file from inside the game code" "1321": "Implementing WriteHandmadeConfig" "1411": "We resort again to _snprintf_s to minimize the amount of CRT functions we will have to replace later" "1642": "Rewriting the config file after every debug UI action" "1697": "We want the game to recompile itself" "1715": "The platform layer will allow us to execute build.bat via DEBUGExecuteSystemCommand" "1945": "The OS function we are looking for is CreateProcess" "2310": "Testing it. It does not work" "2326": "CreateProcess returned false" "2369": "Using GetLastError to find out why" "2431": "Providing an explicit path to cmd.exe" "2492": "It works now" "2502": "Toggling the value of DEBUGUI_UseDebugCamera in the config file" "2559": "Introducing the Uber-Debug-UI!" "2588": "Getting rid of the compilation window pop-up" "2660": "Hiding the window using the wShowWindow flag inside the startup info parameter" "2800": "It works!" "2810": "Getting information about the state of the the compilation process" "3000": "We will use WaitForSingleObject to find that information" "3174": "Querying the platform layer about the state of the compilation process" "3348": ""We don't care big it is"" "3372": "Implementing DEBUGGetProcessState" "3511": "Using GetExitCodeProcess to confirm the completion of the compilation" "3725": "Signalling the ongoing recompilation graphically" "3801": "Find that platform_api doesn't have DEBUGGetProcessState" "3818": "Apologise for the slang" "3889": "Q&A" "3931": "Why be able to compile from the game if we can do it from the editor? Is it just to be cool?" "3990": "Compile in mr4th's editor and do all of the game development work from in-game?" "4011": "I like how it's "STARTUPINFO", but "PROCESS_INFORMATION". Inconsistency even in a single small part of the WinAPI... Do such things annoy you in a "professional" API?" "4053": "Why are we writing to a code file instead of just passing -D to the build line? Seems like it would be a little easier, although I have to admit you made that look pretty easy" "4104": "Why not use system() instead of CreateProcess()?" "4183": "Do you plan on reading the original config file and then rewrite with modified values?" "4192": "Why not just set a boolean variable instead of recompiling a #define?" "4238": "Will there be a dev console?" "4250": "Also, system() runs a program through CMD.EXE, which is yet another dependency" "4317": "The chat recommended CREATE_NO_WINDOW as a process creation flag. You could probably use that instead of the minimized window" "4358": "What is in the bat file that is run?" "4368": "Why does it zoom out?" "4382": "Are you using sublime?" "4387": "Can you add a radial menu for debug camera, instead of piggybacking off toggle graph? It's bugging me" "4399": "Shut down" --- name: "day193" title: "Run-time Setting of Compile-time Variables" markers: "8": "Recap" "41": "Plan for today" "103": "Review of last episode" "123": "We will be extending the debug system so that we can compile in and out debug features more easily" "201": "Optional compilation of ground chunk outlines" "287": "Optional compilation of the particle fountain" "307": "Why doesn't the particle system work?" "410": "The fountain depends on outdated font code" "420": "handmade.cpp: Go back to the head fountain" "452": "The game overwrote our changes to the handmade config file. Let's prevent that from happening again" "509": "Optional compilation of the particle grid" "528": "Optional compilation of room outlines" "568": "Fixing an outdated call to DrawRectangle" "748": "Optional compilation of ground chunk checkerboard patterns" "818": "Optional compilation of ground chunk reset on DLL reload" "940": "Optional compilation of weird renderer buffer sizes" "1094": "Finding out the correct findstr syntax to list all "#if 0" occurrences" "1240": "Optional compilation of the behavior that makes the familiar follow the hero" "1289": "Optional compilation of bilinear lighting sampling" "1329": "Optional compilation of the room-based camera movement" "1350": "The room-based camera is broken. Let's fix it" "1690": "It's working now" "1748": "We have enough items for the moment" "1795": "We want to know the values of our compilation switches to write them out to handmade_config.h" "1857": "The debug_variable struct will keep the names of the switches, their values and their types" "1911": "Defining them using the DEBUG_VARIABLE_LISTING macro" "2012": "Writing the variables to the config file" "2160": "What parameters does _snprintf_s require?" "2400": "Stepping though the code that builds the contents of the config file" "2445": "Writing the file worked" "2459": "Printing the variable list instead of the old menu items" "2512": "Toggling debug variables" "2588": "Testing. It works" "2622": "The run-time exclusion of pieces of debug code has some nice properties..." "2710": "...the only small catch is it still takes too many steps to add a new switch" "2774": "We would like the listing to upgrade itself automatically after a new variable is added, but parsing the code just for that may be going overboard" "2825": "Let's keep the variable listings in a separate file" "2911": "Our radial menu should allow us to _not_ select something once it's active" "3000": "Coloring menu items depending on their value" "3068": "Testing. The menu should not select an action when we remain at its center" "3126": "The compilation process is a bit slow, but we can skip the compilation of the asset builder" "3203": "Q&A" "3285": "I don't understand why a single if-statement would be expensive if we do it at runtime. Can you give an example?" "4074": "Why are we adding // b32 comment in the config file?" "4110": "Can you toggle the debug options while looping?" "4181": "Separate out the mouse handling from the recorded input" "4291": "Prepare to try operating the debug UI while looping" "4305": "Increase the debug menu radius in DrawDebugMainMenu()" "4333": "Try out the debug UI while looping" "4386": "You should add an optimization switch to the UI at some point" "4442": "Wouldn't -O2 optimize those dead branches out?" "4481": "Could you have an option to either recompile or simply toggle an "if"? It seems like most of the time you would use the regular "if" so the change is instantaneous, but in extreme cases you could easily just do the recompile option" "4585": "We are overtime" --- name: "day194" title: "Organizing Debug Variables into a Hierarchy" markers: "9": "Announcement: HandmadeCon 2015" "820": "Set the stage for the day" "924": "Recap where we left off" "1011": "Request some features" "1151": "Coin a phrase" "1277": "Take a look at the current debug code" "1517": "handmade_debug_variables.h: Introduce DEBUGCreateVariables" "1632": "handmade_debug_variables.h: Implement the ability to create groups of variables" "2073": "handmade_debug.h: Introduce debug_variable_group and debug_group" "2330": "handmade_debug_variables.h: Write DEBUGBeginVariableGroup and DEBUGAddVariable" "2736": "handmade_debug_variables.h: Write DEBUGEndVariableGroup" "2769": "handmade_debug_variables.h: Create debug_variable_definition_context" "2875": "handmade_debug.cpp: Call DEBUGCreateVariables" "3035": "handmade_debug.h: Add debug_variable *RootGroup to debug_state" "3103": "handmade_debug.cpp: Introduce WriteHandmadeConfig" "3465": "handmade_debug.cpp: Clean up compile errors" "3504": "handmade_debug.cpp: Call WriteHandmadeConfig" "3529": "Debugger: Step into WriteHandmadeConfig" "3619": "handmade_config.h: Look at the file we wrote out" "3651": "handmade_debug.cpp: Reinsert DEBUGUI_ at the front of the debug variables" "3681": "Debugger: Continue stepping through" "3702": "handmade_debug.cpp: Recap what we've done" "3777": "Q&A" "3813": "Can we make it an option to toggle between optimized and debug builds from the debug menu?" "3919": "Can you run the tool to see how many lines of code we have?" "3939": "Wouldn't it be prettier visually in our config files to be indented according to their group depth, that way we know which variables belong to which group? (i.e. variables in the root group don't have any indentation, group depth 1 will have a single level of indentation etc.)" "4180": "Linux / OS X Support [see Resources]" "4223": "Do you have any add-ons that you are using with emacs? Is it something like spacemacs?" "4235": "Off topic question: Are you using your razer on stream?" "4267": "Not running the game today?" "4276": "Was the intro talk about HandmadeCon included as part of the main hour of the stream?" "4284": "Switching between debug and optimized mode would not need a restart of the whole game?" "4312": "Can we sometimes see you play a game on twitch, like Jon does? Just a chill out stream. Would love to hear your opinion on many different games" "4340": "What about a Handmade Certification for games? A badge of honour, could be placed in a splash screen or in the credits. Products use certifications, e.g. Australian Made. Could be organised at the conference" "4412": "Thanks to you, I was able to implement dynamic code reloading for my project too! Saving me a ton of time" "4426": "Why Do I Have No Straem. I payed the micropayment" "4468": "handmade_platform.h: Implement the suggestions from the forums to enable SDL Handmade to run on Linux and OS X" "4883": "Does the idea for having your compile_switch / variable_switch speed cake involve compiling code out with "if(0)"?" "4905": "Why dont you use lua are you dumb" "4967": "How do you handle multithreading?" "4982": "Q: You inspired me to forget about my years of commercial experience writing RMGUIs and go and implement an IMGUI for my game engine. I love coding again!" "4996": "elxenoaizd: Someone asked a Q: about PushStruct on that day, so I'm guessing Casey MIGHT have introduced it then" "5003": "Q: Damn?" "5007": "How long have you been making games?" "5027": "Check unmatched parenthesis in #elif in ThreadID extraction" "5047": "What?" "5052": "Does streaming your development motivate you to do more / or more consistently?" "5076": "Did you use _snprintf or sprintf? The define is saying "change snprintf to _snprintf"" "5118": "Do you use any type of documentation or design for this project? What types of documents have you produced / planning to produce for this project?" "5162": "Wrap it up" --- name: "day195" title: "Implementing an Interactive Tree View" markers: "68": "Recap and set the stage for the day" "102": "handmade_debug.cpp: Consider cutting and pasting WriteHandmadeConfig" "208": "handmade_debug.cpp: Cut and paste it into DrawDebugMainMenu" "419": "handmade_debug.cpp: Initialise the menu" "542": "handmade_debug.cpp: Set the TextP and advance AtY" "650": "Run the game and see how it looks" "659": "handmade_debug.cpp: Indent the text based on the depth" "709": "Run the game and see our hierarchical printout" "725": "handmade_debug.cpp: Implement the ability to interact with the menu" "998": ""A Variable can be anything that it wants to be"" "1148": "Run the game and see our progress" "1161": ""That's a mistake"" "1174": "handmade_debug.cpp: Fix the test" "1241": "Run the game and demo a bug" "1274": "handmade.h: Introduce PushCopy" "1431": "handmade_debug_variables.h: Use PushCopy to copy Name to the stack" "1475": "handmade_platform.h: Move StringLength from win32_handmade.cpp" "1521": "Run the game and see that our strings do persist, but that we have a bug" "1614": ""There must be a bug"" "1628": "handmade_debug.cpp: Add an InvalidDefaultCase and clean up garbage in handmade_config.h" "1679": "handmade_debug_variables.h: Copy the null terminator onto the end of the Name string" "1753": "Run the game and find that everything's working nicely" "1774": "handmade_debug.cpp: Implement the ability to expand / collapse the tree" "1878": "Run the game and try out the newly compressed tree menu" "1900": "Consider adding more features" "1950": "handmade_debug.h: Add some more debug_variable_types" "2003": "handmade_debug.cpp: Use those variables in WriteHandmadeConfig" "2162": "handmade_debug_variables.h: Create some debug variables using those types" "2295": "Run the game and see our new debug_variable_type in action" "2321": "handmade_debug_variables.h: Consider implementing the ability to tweak values in the UI" "2390": "handmade_debug.cpp: Introduce DEBUGVariableToText to stick the prefix and suffix onto the variables" "2833": "handmade_debug.h: Introduce debug_variable_to_text_flag" "2864": "handmade_debug.cpp: Use DEBUGVariableToText" "3148": "Run the game and see that everything seems to be working, except for the handmade_config.h printout" "3179": "handmade_debug.cpp: Correct the carriage return and stop printing out groups in WriteHandmadeConfig" "3347": "handmade_debug.cpp: Introduce DEBUGVariableToText_PrettyBools" "3413": "Run the game and find that we're getting a little closer" "3445": "handmade_debug.cpp: Correct typos" "3531": "handmade_debug.cpp: Print out // before the groups" "3605": "Run the game and see that it all looks pretty good" "3646": "handmade_debug.cpp: Create a bunch more debug variable types" "3856": "Run the game, assess our progress and glimpse into the future" "3936": "Q&A" "3963": "That was pretty bools, man!" "3968": "Casey, we hear cutlery. Maybe skip Q&A and eat?" "3988": "Why aren't the + and - signs not shown for the group labels?" "4041": "Instead of manually typing values of power of 2 for our debug text enums can't we just use 1 << 1, 1 << 2, etc.?" "4059": "So is THIS what you meant by IMGUI?" "4087": "Colored text option for V4's representing colors?" "4095": "Will you be adding string type debug variables, maybe for things like save folder location, keybindings etc.?" "4115": "Why can't we use LLVM in windows? That way we use the same compiler for our major platforms" "4153": "printf comes from a library, we must implement string formatting so the stream isn't based on a lie" "4311": "If you had to implement an encryption system, would you use a library or write it from scratch yourself?" "4321": "(Off topic) How long after getting his / her number should you text / call them?" "4330": "Are you planning on doing user text input (i.e. spawn entity with x amount of health)?" "4335": "You missed my question twice in the prestream. Looks like it's not appearing. Is there a max question length that you filter out?" "4348": "You can debug LLVM things using the Visual Studio UI" "4365": "Would it be possible to compile all possible combinations of debug vars as separate binaries but then only use the one that matches the chosen debug vars, for faster switching? Is this a stupid question?" "4602": "What is the end goal for the Debug GUI? Like, at what point will we say this is done?" "4622": "In case the debug variables header is messed up, can we check easily if a debug variable is not defined and set some default value?" "4640": "How would you implement your own string without having them being null terminated? Bundle the char* with a count variable?" "4658": "Handmade Certification" "4773": "Wrap it up" --- name: "day196" title: "Introduction to UI Interactions" markers: "187": "Recap and set the stage for the day" "281": "Blackboard: UI Input Processing" "567": "handmade_debug.cpp: Explain how the code is structured for IMGUI" "755": "handmade_debug.h: Introduce *Hot, *InteractingWith and *NextHot debug_variables" "931": "handmade_debug.cpp: Introduce DEBUGInteract and build it up using those variables" "1324": "Run the game and see what happens" "1348": "handmade_debug.cpp: Determine whether the variable we're interacting with is Hot" "1466": "handmade_debug.cpp: Introduce DEBUGBeginInteract and DEBUGEndInteract" "1779": "handmade_debug.cpp: Implement the ability to modify the debug variables" "1960": "Run the game and see our current progress" "1974": "handmade_debug.cpp: Reimplement the ability to expand / collapse the tree menu" "2078": "Run the game and note an interesting situation regarding the interaction" "2180": "handmade_debug.h: Introduce debug_interaction" "2281": "handmade_debug.cpp: Test the interaction state in order to determine which type of interaction to perform" "2461": "Don't be premature" "2503": "handmade_debug.cpp: Perform different interactions depending on the DebugVariableType" "2720": "Run the game and check out our new ability" "2742": "handmade_debug.cpp: Check that we have a variable and rerun the game" "2773": "handmade_debug.h: Add NOP to debug_interaction" "2851": "Run the game and try out this new NOP interaction type" "2876": "handmade_debug.h: Introduce debug_variable_hierarchy" "3095": "handmade_debug.cpp: Setup the hierarchy" "3265": "Debugger: Step in to DEBUGDrawMainMenu to find where everybody went" "3333": "handmade_debug.cpp: Flip the order of the values passed to DebugState->Hierarchy.UIP" "3352": "Run the game and find that it's all working" "3391": "Q&A" "3426": "Once you finish making the game, you you do a live playthrough?" "3537": "We're getting close to 200 episodes; how long do you think until you start on the game proper?" "3758": "Does this mean a proper RNG is around the corner?" "3897": "Did you already cover the Minkowski difference on stream?" "3966": "Could you explain the difference between how IMGUI is often implemented, and how you think it should work again? It went a bit fast for me" "4073": "Would you ever consider doing a 24-hour stream that was create X app or game from start to finish in one stream?" "4150": "Close" --- name: "day197" title: "Integrating Multiple Debug Views" markers: "9": "No plan for today. We will pull together the debug UI code but we still don't know how" "105": "Current state of the debug UI" "141": "We want to bring the debug system to closure, to modify it so that it's convenient to use in the future" "204": ""Oh games, they're so wacky and weird"" "209": "We will try to unify the debug UI and the profile view" "240": "We could integrate the profile display as an element of the debug variable hierarchy" "281": "Introducing a new debug_variable_type enumerand for the profile system" "322": "Reviewing the structure of the profile display code to think on how to integrate it" "472": "Rethinking the profile enumerands" "543": "Adding the profile display to the hierarchy by making the debug_variable_definition_context explicit" "756": "We won't be turning these new variables into text" "801": "Filtering out profile counter variables so that they're not written to the handmade config header file" "874": "We need to generalize the rendering of UI elements to take into account the profile display" "1030": "Inserting the profile display into the hierarchy" "1066": "Defining the bounds of the profile display" "1199": "Drawing the profile display into those bounds" "1366": ""Meh nnn hh meh"" "1452": "AtY will now denote the upper-left corner of an element, not the baseline of the text" "1564": "Debugging the placement of the UI items" "2075": "Their positioning is still a bit faulty" "2095": "Collapsing the profile view" "2174": "Finishing the text positioning" "2242": "The text strings line up properly now" "2314": "Including a second profile display to list show counters by function" "2384": "We want to be able to resize the profile views" "2545": "We'll introduce a small handle so that the user can resize them" "2735": "There are several ways to treat the resize handler. We will let the caller suggest the interaction that should be performed" "2968": "If the click happens inside the resize rectangle, we set the HotInteraction to resize the profile view" "3105": "Highlighting the resize control when hovered upon" "3165": "Interacting with the resize control" "3240": "Debugging the new code" "3361": "It's working!" "3384": "Normally we would set the size of the display by measuring the distance from the point where the down-click happened to the current position, but this is internal debug code" "3473": "Introducing a root group" "3525": "Q&A" "3559": "Do you think this way of structuring UI code could be used to build a full application, or is it just useful for debug UIs? What extra things do you think you'd need to add to make it useful for a full app UI?" "3730": "Were you nervous the first time you streamed Handmade Hero?" "3838": "What do you think about GCC and its dbg?" "3891": "Did you ever get your IRC fixed to show names again?" "3907": "Have you considered working at Valve? What is your opinion of them and their structure?" "4085": "What will the game look like in 25 episodes?" "4194": "Will you be using profiling tools (like gperf) to find hot spots in the code, or rely on your own debug system only?" "4331": "Have you met Michael Abrash or Carmack in person?" "4418": "Are you going to see The Martian?" "4451": "You talked about projects you'd like to program. We are seeing a bunch of space games now after being without decent ones for a while. Are you interested in space games at all?" "4577": "Kerbal Space Program?" "4609": "When is the next Casey drink+game night?" "4646": "Star Citizen is crashing and burning" "4776": "How did you end up working on The Witness, and what is it like to get jobs as a 'freelancer'?" "4830": "If Star Citizen _does_ end up delivering, do you think it has the potential to change the current publisher AAA model or do you think it will be a one-shot regardless of its success?" "4902": "Start to wind it down" "5002": "Wait, is there a limit?" "5087": "Finish winding it down" --- name: "day198" title: "Run-time Editing of Debug Hierarchies" markers: "138": "Recap and set the stage for the day" "271": "handmade_debug.h: Introduce debug_variable_reference" "484": "handmade_debug_variables.h: Introduce DEBUGAddUnreferencedVariable" "583": "handmade_debug.h: Add debug_variable *Var to debug_variable_reference" "591": "handmade_debug_variables.h: Introduce DEBUGAddVariableReference" "735": "handmade_debug_variables.h: Clean up compile errors" "851": "handmade_debug.cpp: Propagate Ref out" "976": "Compile and see that it still works" "995": "handmade_debug_variables.h: Try adding a UseDebugCamRef into two different groups" "1086": "Run the game and see UseDebugCam in two groups" "1131": "handmade_debug.cpp: Implement the ability to have more than one debug_variable_hierarchy" "1466": "handmade_debug.cpp: Introduce AddHierarchy" "1652": "handmade_debug.cpp: Write the Hierarchy doubly-linked list" "1782": "Debugger: Step in to AddHierarchy" "1875": "handmade_debug.cpp: Call AddHierarchy in the correct place" "1947": "Run the game and find things in better shape" "1978": "handmade_debug.cpp: Implement the ability to tear items off the menu" "2339": "handmade_debug.cpp: Implement DebugInteraction_TearValue" "2474": "handmade_debug.variables.h: Introduce DEBUGAddRootGroup" "2708": "handmade_debug.cpp: Call DEBUGAddRootGroup" "2832": "handmade_debug_variables.h: Make DEBUGAddVariableReference take debug_variable *Group" "3011": "handmade_debug.cpp: Call DEBUGAddVariableReference" "3064": "handmade_debug_variables.h: Make DEBUGAddRootGroup add a debug_variable_reference" "3120": "handmade_debug_variables.h: Introduce a new DEBUGAddRootGroup and rename the original to DEBUGAddRootGroupInternal" "3287": "Run the game and test out our new tearing ability" "3345": "handmade_debug.cpp and handmade_debug.h: Introduce DebugInteraction_MoveHierarchy" "3445": "handmade_debug.cpp: Draw a MoveBox for each Hierarchy" "3521": "handmade_debug.cpp: Implement the ability to move that Hierarchy" "3571": "handmade_debug.h: Add debug_hierarchy *NextHotHierarchy to debug_state" "3734": "Debugger: Step in to DraggingHierarchy" "3778": "handmade_debug.cpp: Clear NextHotHierarchy" "3794": "handmade_debug.cpp: Introduce DEBUGTextLine to display when we are interacting" "3862": "handmade_debug.cpp: Make the check be on HotInteraction" "3925": "Run the game and try that again" "3955": "handmade_debug.cpp: Move Assert(Var)" "3982": "Run the game and check out our tearing and moving abilities" "4020": "Q&A" "4067": "No questions" "4084": "You mentioned that encapsulation is good but not in the OOP way. Could you elaborate then in which way you mean?" "4149": "Are the menu items spaced evenly vertically? Looks a bit odd to me" "4165": "handmade_debug.cpp: Use LineAdvance to space the lines" "4609": "Why is there so much lag / latency when dragging the hierarchies around? Or is that just Twitch streaming artifacts?" "4688": "Are the different tear-offs intended to have identical hierarchies or is the intention that you drill down into different things without all the tear-offs being affected?" "4752": "I noticed you use the internal keyword. I haven't seen it before. What is its purpose?" "4763": "I apologize since I came in late, but out of curiosity, what was the tolerance (in pixels) you used for dragging out a subsection?" "4778": "You mentioned that for linked lists at work you use metaprogramming. What did you mean?" "4791": "I missed 90% of the stream, so I missed a ton. I just want to ask what are some tips for people who want to get into designing games? Dos and Don'ts and simple things that are worthwhile" "4802": "Does anyone know if there is plans in the future to add other platform support to this project?" "4823": "Have you ever written anything for the PS1? (I think Jeff mentioned he used to do some stuff in a J&C episode?)" "4827": "Have you ever played any of the Space Quest games? The music for the video on the Handmade Hero site reminds me of it a lot" "4847": "Do you plan doing something with the character spacing in the text renderer?" "4862": "Is 'sentinel' a design pattern that will help with making the torn instances of the UI independent, or is that terminology that you've gained in years of tool development? Now that I understand what you meant by 'tearing' the interface, it seems really useful for isolating instances of hierarchies" "4891": "Not a huge deal, but the labels no longer show if clicking them will expand or minimize them. Also at a glance it is not clear what is a category and what is a var" "4908": "Which game console had the worst SDK?" "4936": "Wrap it up" --- name: "day199" title: "Reusing Debug Interactions" markers: "109": "Recap and find that we must have broken something" "161": "Debugger: Step through DEBUGInteract" "246": "handmade_debug.cpp: Identify the problem and set DebugState->InteractingWith in a different place" "344": "Run the game and find that we're fine" "382": "handmade_debug.h: Introduce a new debug_interaction and rename the old one to debug_interaction_type" "505": "handmade_debug.h: Simplify debug_state" "572": "handmade_debug.cpp: Make DEBUGDrawMainMenu work with this new structure" "736": "handmade_debug.cpp: Introduce InteractionsAreEqual" "793": "handmade_debug.cpp: Continue working on DEBUGDrawMainMenu" "894": "handmade_debug.cpp: Introduce InteractionIsHot" "935": "handmade_debug.cpp: Continue cleaning up DEBUGDrawMainMenu" "1053": "handmade_debug.cpp: Make DEBUGBeginInteract work with the new structure" "1275": "handmade_debug.cpp: Make DEBUGEndInteract work with the new structure" "1392": "handmade_debug.cpp: Make DEBUGInteract work with the new structure" "1535": "handmade_debug.cpp: Make DEBUGEnd work with the new structure" "1549": "Run the game and hit an assertion" "1576": "handmade_debug.cpp: Set these variables in DEBUGBeginInteract" "1724": "Run the game and find that things are better" "1763": "handmade_debug.h Add v2 *P to debug_interaction" "1796": "handmade_debug.cpp: Use that *P in DebugInteraction_Resize and DebugInteraction_Move" "1862": "handmade_debug.h: Add DebugInteraction_Resize and DebugInteraction_Move to debug_interaction_type" "1878": "handmade_debug.cpp: Continue adding that P" "1942": "Run the game and try interacting with the menu" "1982": "handmade_debug.cpp: Give DebugInteraction_TearValue an interaction" "2047": "Run the game and test this generic moving" "2085": "handmade_debug.h: Extend this notion of generic movement to another debug_variable_type" "2131": "handmade_debug.h: Introduce debug_bitmap_display" "2188": "handmade_debug.cpp: Implement DebugVariableType_BitmapDisplay" "2380": "handmade_debug_variables.h: Introduce a DEBUGAddVariable for bitmap_id" "2662": "Run the game and hit the InvalidDefaultCase" "2708": "Add DebugVariableType_BitmapDisplay to DEBUGShouldBeWritten" "2729": "Run the game and try out the resize interaction" "2755": "Consider how best to resize bitmaps directly without using the alignment offset" "2895": "handmade_render_group.cpp: Implement the ability to turn the alignment off" "3057": "Run the game and find it's correctly resizing" "3081": "handmade_debug.cpp: Draw the Bounds of the guy" "3113": "Run the game and consider the aspect ratio" "3183": "handmade_debug.cpp: Implement the same resizing for the bitmap as for the font" "3353": "Run the game and find that the resizing works much better" "3544": "Q&A" "3657": "Maybe I'm misunderstanding, but is it desired behavior for the "tear" feature to tear all groups below it even if they are on the same level in the hierarchy? I would think you would only want to tear the current group and subgroups, not other groups on the same level. For example, you wouldn't want the "profile" group to get torn when you tear the "particles" group" "3736": "If I bought a ticket for the Con that I can't use, can I donate it to someone?" "3754": "Can the new bitmap display be torn off as well?" "3782": "handmade_debug.cpp: Allow the bitmap to have an ItemInteraction" "3939": "Is it worth doing so much UI work if the game will not feature much UI?" "4032": "Can you add variables to change the match vectors?" "4114": "Will there be a menu system like pressing start in Zelda to change items? Nothing fancy, but just something to get us started on how to do it" "4196": "Assume that we have Q:'d out" --- name: "day200" title: "Debug Element Layout" markers: "110": "Recap and set the stage for the day" "317": "handmade.debug.cpp: Look at how we're currently drawing things" "437": "handmade_debug.cpp: Introduce layout struct to contain local variables" "602": "handmade_debug.cpp: Introduce Advance" "921": "Run the game and find that it's the same as it was" "930": "handmade_debug.cpp: Introduce PlaceRectangle" "1121": "Run the game and find that it just works" "1131": "handmade_debug.cpp: Use PlaceRectangle to compute the layout of elements for us" "1223": "Run the game and show the elements using the same layout routine" "1250": "handmade_debug.cpp: Consider the difficulty of pulling out the SizeP computation" "1445": "handmade_debug.cpp: Simplify and loft out computations from DEBUGDrawMainMenu" "2030": "handmade_debug.cpp: Introduce BeginElementRectangle, MakeElementSizable, DefaultInteraction and EndElement" "3243": "Run the game and spot a mistake" "3260": "handmade_debug.cpp: Only push the rects if the Element has a Size and stop making Text elements Sizeable" "3305": "handmade_debug.cpp: Add the DefaultInteraction" "3363": "Run the game and see that everything seems to be working pretty well" "3465": "Q&A" "3630": "Why don't you connect to chat with your desktop?" "3767": "Set the stage for the evening and wind it down" --- name: "day201" title: "Isolating the Debug Code" markers: "107": "Recap and hit a first-chance exception" "158": "Investigate this exception" "362": "win32_handmade.cpp: Move DebugCollation above FramerateWait and pass NewInput and &Buffer to DEBUGFrameEnd" "450": "handmade.cpp: Remove DEBUGStart and DEBUGEnd" "474": "handmade_debug.cpp: Call DEBUGStart and DEBUGEnd in DEBUGGameFrameEnd" "666": "handmade.cpp: Introduce DEBUGGetGameAssets to enable the debug system to get the TranState->Assets out" "757": "handmade_platform.h: Give DEBUG_GAME_FRAME_END the same call structure as GAME_UPDATE_AND_RENDER" "803": "handmade_debug.cpp: Create a DrawBuffer for the debug system" "900": "Debugger: Step into DEBUGGetState" "932": "handmade_debug.cpp: Paste DEBUGGetState into DEBUGGameFrameEnd" "1010": "Run the game and find that we're in better shape" "1111": "handmade.debug.h: Consider getting rid of this header file entirely" "1192": "handmade.cpp: Add conditional on HANDMADE_INTERNAL to enable us to toggle the debug system" "1272": "build.bat: Turn off HANDMADE_INTERNAL" "1287": "handmade_platform.h and win32_handmade.cpp: Add conditionals on HANDMADE_INTERNAL" "1367": "handmade_platform: Remove HANDMADE_PROFILE in favour of HANDMADE_INTERNAL" "1505": "Run the game successfully" "1517": "build.bat: Toggle HANDMADE_INTERNAL and still run successfully" "1606": "Think about how to proceed" "1740": "handmade_debug.h: Move the contents of debug_variable_group into debug_variable_reference" "1852": "handmade_debug.h: Consider splitting the variables up" "1983": "handmade_debug.h: Rename debug_variable_ structs to debug_tree and debug_tree_entry" "2033": "handmade_debug.h: Introduce debug_tree_entry_group" "2081": "handmade_debug.h: Rewrite debug_tree" "2204": "handmade_debug.h: Introduce debug_tree_entry_window" "2278": "handmade_debug.h: Introduce debug_tree_entry_type" "2325": "Recap these changes" "2392": "handmade_debug.h and handmade_debug_variables.h: Clean up the compile errors" "2511": "Consider using a caching-centric system" "2681": "handmade_debug.h and handmade_debug_variables.h: Start to implement a caching-centric system" "3857": "Pause this temporarily and turn off HANDMADE_INTERNAL" "3897": "Q&A" "3925": "Now that the amount of debug code is getting larger, will you create a debug debug system to debug the debug code?" "3964": "Is this the link you were looking for earlier for MartinCohen?" "4027": "What do you think about the use of pre-fetch cache instructions? Are they a viable option for general purpose programming to get maximum performance?" "4108": "After the two year period, will we be able to mod the game?" "4117": "Does the architecture of your target system have a big effect on how you design your debug system?" "4191": "Would be it an idea to pass build.bat a parameter which you would use to switch optimisation on and off on the different build units? Like IF %1 == opt, do this, otherwise do that" "4229": "What do you think about "No Man's Sky"? I can't even think about how it works now. Will I get some idea after learning from you?" "4288": "I mean, after you release the source code. Will we be able to create our own bosses, worlds, etc.?" "4308": "Will you be returning to game specific coding soon?" "4421": "Could something like a Raspberry Pi or other ARM desktop PC run Handmade Hero well enough, and is that the kind of system where you would want to do the debugging on a separate machine?" "4487": "I meant for usage inside the game, so you could switch optimisation on and off from the debug menu" "4526": "Do you think it would be totz baller to make a GUI visual language for game scripting like what Unreal has?" "4574": "Blackboard: Visual Scripting" "4715": "Couldn't you collate just the last frame every frame instead of doing all of them in chunks?" "4822": "Close this down" --- name: "day202" title: "Multiply Appearing Debug Values" markers: "28": "Debugger: Enabling "Go To Definition / Declaration" feature" "190": "Internet: Building Browse Information Files: Overview" "240": "build.bat: Add -FR flag" "438": "Debugger: Show a dummy win32 project with this browse info enabled" "475": "build.bat: Remove -FR flag and delete the *.bsc and *.sbr files" "493": "Recap our current status" "539": ""Patience is a virtue"" "732": "Set the stage for the day" "835": "handmade_debug.h: Introduce debug_variable_link" "910": "handmade_debug_variables.h: Introduce DEBUGAddVariableToGroup" "1038": "handmade.h: #define DLIST_INSERT" "1120": "handmade_debug_variables.h and handmade_debug.cpp: Use this DLIST_INSERT macro" "1199": "handmade_debug_variables.h: Continue cleaning up" "1257": "handmade.h: #define DLIST_INIT" "1325": "handmade_debug.h: Consider whether we want to store parent pointers for variables" "1405": "handmade_debug_variables.h: Introduce debug_variable_group_builder to enable DEBUGEndVariableGroup to pass the parent VarGroup back" "1507": "handmade_debug_variables.h: Add a GroupDepth and *GroupStack array to debug_variable_definition_context to show another way to solve this problem" "1753": "handmade_debug.cpp: Initialise that GroupStack in debug_variable_definition_context" "1867": "handmade_debug_variables.h: Continue on cleaning up compile errors" "1985": "Blackboard: Traversing trees using pointers and then stacks" "2288": "handmade_debug.cpp: Add *Stack to WriteHandmadeConfig" "2511": "Blackboard: The natural order of the stack" "2740": "handmade_debug.cpp: Introduce debug_variable_iterator to augment the stack" "3159": "handmade_debug.cpp: Continue cleaning up compile errors" "3255": "handmade_debug.cpp: Unwind the stack iteration loop" "3385": "handmade_debug.cpp: Use our stack implementation in DEBUGDrawMainMenu" "3445": "handmade_debug.cpp: Continue cleaning up compile errors" "3646": "handmade_debug.cpp: Introduce a dummy GetDebugViewFor" "3678": "Correctly spell "variable"" "3687": "handmade_debug.cpp: Finish cleaning up compile errors" "3829": ""That's the end of that"" "3891": "Q&A" "3919": "Does it work?" "4052": "Earlier in the stream you said that you once spent 10 weeks on a problem. What was that problem?" "4143": "Have you considered using intrusive linked lists like those in the Linux kernel that use offsetof()" "4203": "How portable will the game engine be? Could it be used to make other games?" "4242": "Curve Solver?" "4265": "Will we ever see the memory chunk debug visualization?" "4352": "What flavour of Linux on your laptop today, and what will it be on Monday" "4382": "By the way, I think the Linux kernel implementation can have something in multiple lists at once" "4404": "Blackboard: Linked lists" "4475": "Can you give me a quick rundown again of how you're substituting the stack for instances of the debug view?" "4501": "So what do you use as a "formatting language" usually?" "4555": "Is this how you do UI in your other programs?" "4604": "Call it done" --- name: "day203" title: "Debug UI State Caching" markers: "59": "Recap our current situation" "139": "Blackboard: Breadth-first vs depth-first tree traversal" "526": "Debugger: Step into DEBUGDrawMainMenu and hunt for the hierarchy" "805": "handmade_debug_variables.h: Make DEBUGAddVariable call the correct Context" "818": "handmade_config.h: Manually rewrite the config" "882": "Debugger: Step through and hit a first-chance exception" "920": "Debugger: Inspect the DebugState->RootGroup" "993": "handmade_debug_variables.h: Set Link->Var in DEBUGAddVariableToGroup" "1009": "Run the game and find it's looking a little bit better" "1039": "handmade_config.h: Ensure that the write-out worked correctly" "1063": "handmade_debug.cpp: Test for View->Collapsible.ExpandedAlways to be true" "1157": "Run the game and find that everything is collapsed" "1177": "handmade_debug.h and handmade_debug.cpp: Add debug_view Dummy to debug_state and make GetDebugViewFor return it" "1210": "Run the game and see the debug menu expand briefly" "1228": "handmade_debug.cpp: Finish implementing GetDebugViewFor" "1469": "Run the game and see that it's almost working fine" "1485": "handmade_debug.h: Consider storing the debug_view in debug_variable_link" "1615": "handmade_debug.h: Introduce debug_id" "1671": "handmade_debug.cpp: Pass ViewID to GetDebugViewFor" "1701": "handmade_debug.cpp: Introduce DebugIDFromLink" "1755": "handmade_debug.h: Add debug_id ID and debug_variable *Var to debug_interaction" "1812": "handmade_debug.cpp: Revert the code in DEBUGEndInteract and DEBUGInteract" "1867": "handmade_debug.cpp: Introduce VarLinkInteraction in order to compress these routines" "2028": "handmade_debug.h: Add debug_view *ViewHash to debug_state" "2140": "handmade_debug.cpp: Implement a hash function in GetDebugViewFor" "2433": "handmade_debug.cpp: Introduce DebugIDsAreEqual" "2485": "Run the game and see that our stuff works, except for indentation" "2549": "handmade_debug.cpp: Set the Layout.Depth in order to fix the indentation" "2628": "Run the game and see that the indentation is working pretty well" "2682": "handmade_debug_variables.h: Investigate why the Real32 isn't working correctly" "2768": "handmade_config.h: Try manually adding .0f to DebugCameraDistance" "2795": "Run the game and find that DebugCameraDistance is working" "2827": "handmade_debug.cpp: Reimplement tear-offs" "3027": "handmade_debug_variables.h: Introduce DEBUGAddVariableToDefaultGroup" "3090": "Run the game and find that the tear-off behaves as it did before" "3138": "handmade_debug.cpp: Grab the correct group in DEBUGDrawMainMenu" "3218": "Run the game and tear off specific values" "3258": "handmade_debug.h: Make DebugIDFromLink and VarLinkInteraction take the Tree" "3335": "Run the game and see that the state is isolated" "3398": "Recap today's work" "3470": "Q&A" "3494": "Pure design question. In GetDebugViewFor() your method is named such that it's a query but it appears to be a command in some cases (in that it changes the state of the system). I've heard that you typically want to avoid this. Do you agree? Is there a reason you did this?" "3593": "Do you think learning all the algorithms and data structures is a must, or is it OK to learn them when the need for one of them rises? Or is it one of those things that you have to learn beforehand in order to know if you need them or not?" "3721": "4bugger... No libraries. You need a new game maker?" "3736": "Q: Binary search tree is a subset of BTree, I think" "3787": "About your memory allocation (way back when): Shouldn't the amount of memory you allocate depend on the size of the world chosen by the user? As it is, it is fixed at compile time (if I understand correctly)" "3929": "I would like to be a tools programmer / game tech writer like you, but I'm still learning things so I'm not fully qualified to work as one. I'm thinking of working in a simple game company where the qualifications aren't so hardcore (maybe they use Unity or whatever), and at the same time do my private low-level self-learning. Good idea? Yes / No" "4115": "What are your plans for streaming once you complete this game?" "4126": "You've discussed using Blender. Are you a 3D modeller of some sort? More specifically, what operations do you do with that software package?" "4209": "I'd like to see a Blender pre-stream demo" "4230": "Would you consider doing a short off-hours stream to show people how you do things (like metaprogramming) that you won't get to touch on in Handmade Hero?" "4268": "Hey, love catching the stream when I can. What language do you recommend as a beginner programmer looking to get into game development?" "4491": "Stream is over" --- name: "day204" title: "Unprojecting the Mouse Cursor" markers: "8": "Announcement: Miblo's Patreon" "184": "Recap and set the stage for the day" "256": "Run the game and see where we're at" "341": "Consider moving away from explicitly constructing the debug hierarchy" "531": "On writing the usage code and then unifying the systems" "614": "handmade_sim_region.cpp: Look at how the entities are currently handled" "669": "Implement the ability to click on an entity in order to inspect it" "791": "Run the game and illustrate what we'd like to do" "948": "handmade.cpp: Introduce DEBUGUI_DrawEntityOutlines" "1085": "Run the game and see the new outlines" "1114": "handmade_render_group.cpp: Make PushRectOutline additionally take a Thickness" "1146": "Run the game and see the thinner magenta outlines" "1199": "Consider the problem of the perspective transform" "1309": "handmade_render_group.cpp: Look at Unproject" "1399": "Blackboard: Why we need the distance from the camera" "1526": "Blackboard: Conceptualising this entity picking" "1628": "handmade.cpp: Unproject the MouseP" "1766": "handmade.cpp: Test the LocalMouseP against the 2D entity Volume->Dim" "1965": "handmade.cpp: Do a PushRect of the mouse's location" "2020": "handmade.cpp: Do an Orthographic call to draw the MouseP" "2187": "handmade_render_group.cpp: Add OffsetP and Scale to Orthographic" "2256": "Run the game and see the mouse" "2292": "Debugger: Step into GameUpdateAndRender and inspect the MouseP" "2349": "handmade.cpp: Try and draw the LocalMouseP" "2437": "Run the game and don't see the LocalMouseP" "2462": "handmade.render_group.cpp: Investigate why we're not seeing the LocalMouseP" "2624": "handmade.cpp: Multiply the mouse's Transform by PixelsToMeters" "2742": "Run the game and see that the rects aren't correctly positioned [tl;dw: see 1:39:32]" "2779": "handmade.cpp: Investigate why rects aren't correctly positioned" "2897": "handmade.cpp: Pass the entity's Transform to the Unproject call" "2947": "Run the game and see that we're getting a little closer" "3067": "handmade.cpp: Pick one entity to consider" "3088": "Run the game and see that the mouse's rectangle is incorrectly placed and scaled" "3136": "handmade.cpp: Try doing Unproject without the subtract" "3172": "Run the game and see that it's surprisingly in the right place" "3263": "handmade.cpp: Consider the possibility that Unproject may be fundamentally busted" "3287": "handmade.cpp: Add OffsetP.z to LocalZ" "3309": "Run the game and suggest that that's more correct" "3419": "handmade_render_group.cpp: Study our routines" "3735": "handmade.cpp: Try putting that subtract back in to the Unproject" "3928": "Run the game and try to determine how far off we are" "3960": "handmade.cpp: Try hardcoding values" "4052": "Run the game and don't see a MouseP rectangle" "4100": "handmade.cpp: Pass WorldMouseP to PushRect" "4137": "Run the game and see that it's okay, but not great" "4157": "handmade.cpp: Set LocalZ to 1.0f" "4281": "handmade.cpp: Add RenderGroup->Transform.DistanceAboveTarget to PushRect" "4457": "handmade_render_group.cpp: Introduce CompleteUnproject" "4947": "Run the game and conclude that we'll want to clean up what's happening in the projection" "5029": "Q&A" "5058": "The lag is real" "5084": "How will the focal length factor in? Will you have FOV stuff?" "5163": "Elvin?" "5180": "Semi related: What do you think about using different types for Points and Vectors?" "5212": "Does the screen center need to be involved? It was used in CompleteUnproject" "5230": "Is part of the problem that the code isn't normalizing the motion between the mouse and the entity relative to the screen dimensions in world coordinates at the different levels?" "5283": "handmade.cpp: Try doing the MetersToPixels after the fact" "5323": "handmade_render_group.cpp: Check that there weren't any other transforms happening to PushRect" "5377": "Mm. We seem to have run out of questions" "5380": "What is the problem with this Unproject?" "5421": "handmade_render_group.cpp: Investigate the problem" "5546": "Meta-point: On the potential features of a development tool that would help with these types of problems" "5771": "Debugger: Inspect a bunch of values and copy them to a scratch buffer" "5972": "Owl of Shame Moment: We took out Z movement relative to the basis P" "6048": "handmade.cpp: Correctly set Transform.OffsetP" "6071": "Run the game and find it in the right place" "6257": "On getting bitten by a feature" "6279": "Lament this 2.5D nonsense" "6315": "Glimpse into the future and wrap it up" --- name: "day205" title: "Picking Entities with the Mouse" markers: "91": "Recap and set the stage for the day" "198": "handmade.cpp: Outline all of the entities" "285": "Consider making the renderer work more logically" "424": "handmade_render_group.cpp: Deprecate Unproject" "545": "handmade_render_group.cpp: Work CompleteUnproject into a new 3-dimentional Unproject function" "846": "win32_handmade.cpp: Unify our output and input coordinate systems" "1014": "handmade_render_group.cpp: Finish writing Unproject" "1061": "handmade_math.h: Introduce operator-= for vectors" "1099": "handmade.cpp: Call the new Unproject" "1130": "Debugger: Step in and inspect MouseP and PixelsXY" "1203": "handmade_render_group.cpp: Divide by MetersToPixels" "1216": "Debugger: Step back in to Unproject" "1469": "handmade_render_group.cpp: Look at the DistanceToPZ calculation in GetRenderEntityBasisP" "1522": "Blackboard: How DistanceToPZ is specified" "1674": "handmade_render_group.cpp: Rename ZMeters to ZMetersFromTargetPlane" "1709": "handmade.cpp: Set LocalZ = 3.0f" "1723": "Run the game and set that it now works" "1770": "handmade.cpp: Test to see if the MouseP is on the plane of the Entity" "1917": "Run the game and note that the scale is a little bit off" "1938": "handmade.cpp: Respecify Unproject to not take ZMetersFromTargetPlane" "2252": "Run the game and see that we're correctly doing that inversion" "2297": "Run the game and test how these outlines work" "2356": ""I guess the Wacom tablet decided to take its own life"" "2368": "handmade.h: TODO(casey): Real projections with solid concept of project/unproject" "2411": "handmade.cpp: Only push the outline when the mouse is over the entity" "2444": "handmade.cpp: Manually provide the ability to introspect the HOT_ELEMENT" "2792": "handmade_platform.h: #define all of these new DEBUG macros" "2854": "Run the game and see that we're still highlighting but that the debug menu no longer works" "2935": "handmade_debug.cpp: Unproject the MouseP" "2996": "handmade_render_group.cpp: Compute UnprojectXY" "3073": "Run the game and see that we have our picking back" "3111": "Q&A" "3195": "I'm a little unclear about what pressure is keeping you from doing the Z math exactly like you would in 3D" "3208": "Blackboard: Conceptualising Z" "3585": "Where are you going to draw the labels for entity properties?" "3605": "Did you decide which 'awesome thing' to do for tomorrow's stream?" "3625": "What do you define as a good game design?" "3634": "Curious if your decision to design your own game engine has more to do with you furthering your own skill level, or do you have reason to not trust the middleware solutions you have seen in the past?" "3882": "Did you play Warcraft III at all or any of the mods? I need some help replicating some of the movement mechanics from one of the games and nobody understands me when I describe it. Willing to pay PayPal to whoever can code it. I'm betting it's honestly somewhat simple" "3941": "Would it work to render it in full 3D and rotate all the sprites by 45 degrees (or whatever angle the camera is taking)?" "4071": "I understand the art is drawn in the 3/4 view. Is the camera at an angle or top down?" "4234": "The 3DS Zelda games do the 3D-at-an-angle for 2D" "4293": "So I'm making a full 3D RTS that uses a mouse with a joystick built in so you can adjust where you are looking with the joystick and still use the mouse as a mouse for unit selection. Do you think that is an untenable idea for a product? If you had to buy a new mouse for one game, would you be like "nooo"?" "4332": "Did you ever end up playing The Mother series? Still on your TODO?" "4349": "I kind of jumped over 100 episodes so I don't understand what the issue was with the debug selector. Was the issue with the hitbox depth only or also the position?" "4442": "Look forward to tomorrow's Devstreamathon and consider supporting Hitbox" "4513": "https://restream.io/" "4539": "Why did Jon get banned?" "4629": "Wrap it up" "4723": "Announcement: The speaker list for HandmadeCon 2015 will be announced on Monday" --- name: "day206" title: "Implementing Introspection" markers: "32": "Recap and set the stage for the day" "225": "simple_preprocessor.cpp: Introspection" "385": "simple_preprocessor.cpp: Name this function ReadEntireFileIntoMemoryAndNullTerminate" "436": "simple_preprocessor.cpp: Call this function to run on handmade_sim_region.h and build it up" "540": "build.bat: Add simple_preprocessor.cpp" "585": "Debugger: Step into simple_preprocessor.cpp and ensure that it works as expected" "651": "simple_preprocessor.cpp: Null terminate the file" "679": "handmade.h: #define introspect" "751": "handmade_sim_region.h: Use this introspect macro" "762": "Brown butter" "796": "Describe tokens" "898": "simple_preprocessor.cpp: Introduce token structures" "1001": "simple_preprocessor.cpp: Loop over the Tokens and print them out" "1218": "simple_preprocessor.cpp: Introduce struct tokenizer" "1280": "simple_preprocessor.cpp: Introduce EatAllWhitespace" "1389": "Get a little brained" "1686": "simple_preprocessor.cpp: Provide a way to parse identifiers" "1760": "simple_preprocessor.cpp: Move GetToken's functionality to the correct place and write EatAllWhitespace" "1873": "simple_preprocessor.cpp: Provide the ability to parse C-style comments and introduce IsEndOfLine" "2076": "simple_preprocessor.cpp: Introduce IsAlpha and IsNumeric" "2157": "simple_preprocessor.cpp: Handle unknown tokens" "2220": "simple_preprocessor.cpp: Skip the closing quote" "2327": "simple_preprocessor.cpp: Implement ParseIdentifier" "2409": "Debugger: Step into simple_preprocessor.cpp and inspect the Tokenizer" "2467": "simple_preprocessor.cpp: Handle skipping over the first character" "2553": "Debugger: Step back in and inspect the Token" "2610": "Run the preprocessor and look at its output" "2649": "simple_preprocessor.cpp: Introduce ParseIntrospectable" "2729": "simple_preprocessor.cpp: Introduce TokenEquals" "2888": "Debugger: Step in to TokenEquals" "2931": "simple_preprocessor.cpp: Check for the string "intr"" "2977": "Debugger: Step through the loop inspecting At and Index" "3051": "simple_preprocessor.cpp: Implement ParseIntrospectable" "3191": "simple_preprocessor.cpp: Introduce ParseIntrospectionParams" "3234": "simple_preprocessor.cpp: Introduce ParseStruct" "3317": "simple_preprocessor.cpp: Introduce ParseMember" "3364": "simple_preprocessor.cpp: Introduce RequireToken" "3419": "simple_preprocessor.cpp: Provide the ability to print out the DEBUG_VALUE" "3643": "Run the preprocessor and see what happens" "3715": "Q&A" "3772": "It seems like you are doing recursive descent parsing. Is that how you would describe it?" "3815": "Blackboard: Recursive Descent Parser" "3904": "simple_preprocessor.cpp: Introduce a more recursive example of ParseMember" "4157": "Can you please satisfy my C standard anal retention by accepting 'v' and 'f' as whitespace?" "4210": "Have you an opinion on OpenCLC? Would that be out of bounds for Handmade Hero?" "4231": "How would you handle errors if you were deep in the recursion? Is checking return values everywhere the best way?" "4278": "I showed up late. Can you explain what introspection is?" "4582": "Do you if Jon does "metaprogramming" for his language?" "4632": "Regarding errors again, would this be a place where exceptions would actually be useful?" "4680": "Now that we have the preprocessor, do you plan to make more use of it going forward in Handmade Hero?" "4698": "Who is Jon and what language are you talking about?" "4719": "I'm writing a parser that looks pretty similar to this, but it runs on multi-GB files which takes a while. Any common approaches to use SIMD/multithreading to speed up text parsing? Seems more difficult since the characters aren't "independent" in the way pixels are" "4818": "This stream makes me feel like an extremely inferior and incompetent programmer. Do you approve of this?" "4978": "How does metaprogramming change your workflow? Can you talk about incorporating generated code with the "regular" C files?" "5152": "Wrap up" --- name: "day207" title: "Using Introspection Data" markers: "106": "Recap and set the stage for the day" "246": "simple_preprocessor.cpp: On understanding the contents of structs" "451": "simple_preprocessor.cpp: Make ParseMember take StructTypeToken" "551": "Run the preprocessor and see this new information" "595": "build.bat: Pipe the output of the preprocessor to handmade_generated.h at compile time" "673": "Describe ths metaprogramming workflow" "700": "handmade.h: #include handmade_meta.h" "720": "handmade_meta.h: Introduce member_definition and meta_type" "828": "handmade_meta.cpp: #include handmade_generated.h and #include this file in handmade.cpp" "878": "handmade_generated.h: Mention the fact that once this is generated, we always have it" "919": "handmade_debug.cpp: Set some values and print them out using DEBUGTextLine" "1338": "Debugger: Run the game and see these debug values" "1395": "handmade_debug.cpp: Introduce DEBUGDumpStruct" "1498": "handmade_sim_region.h: Make sim_region introspected" "1546": "handmade_meta.h: Add the types in sim_region to meta_type" "1584": "handmade_debug.cpp: Set these values of sim_region and print them out" "1645": "Run the game and see the sim_region printing out" "1667": "handmade_generated.h: Note that new types have to keep being redefined in handmade_meta.h" "1708": "handmade_math.h: introspect rectangle2 and rectangle3" "1750": "simple_preprocessor.cpp: Process handmade_math.h" "1811": "Run the preprocessor and see that these rectangles are now defined" "1845": "handmade_debug.cpp: Show what we otherwise would have to do to define a new type" "1915": "Run the game and view those rectangles" "1928": "handmade_debug.cpp: Use the meta generator to define rectangle3 for us, and manually define MetaType_v3" "2147": "Run the game and see our debug output" "2158": "handmade_debug.cpp: Discuss ways to get this code generated for us" "2268": "simple_preprocessor.cpp: Introduce meta_struct to enable us to keep track of structs seen" "2511": "simple_preprocessor.cpp: Printout #define META_HANDLE_TYPE_DUMP and loop over the Meta structs" "2711": "simple_preprocessor.cpp: Take a look at how this injection works" "2761": "Run the game and see all of this new stuff being printed out" "2774": "handmade_debug.cpp: Add the concept of an indent level" "2930": ""There's nothing worse than a whiny C compiler"" "3089": "Run the game and see our newly indented output" "3112": "simple_preprocessor.cpp: Print a line to tell us what the member was" "3158": "Run the game and look over our generated debug information" "3200": "handmade_world.h: introspect world_position" "3287": "simple_preprocessor.cpp: Process handmade_world.h" "3302": "Run the game and see the entity printout" "3384": "handmade_sim_region.h: introspect everything" "3459": "Run the game and notice that pointers aren't handled correctly" "3516": "handmade_meta.h: Introduce member_definition_flag" "3554": "simple_preprocessor.cpp: Recognise pointers" "3586": "handmade_debug.cpp: Dereference a pointer and skip printing it if it's null" "3643": "Run the game and see it starting to make more sense" "3655": "handmade_debug.cpp: Set TestCollisionVolumeGroup parameters" "3781": "Run the game and see this information" "3793": "handmade_debug.cpp: Set another lot of values, but note that the generator does not know how to handle them" "3827": "handmade_sim_region.h and handmade.h: Introduce counted_pointer" "3883": "simple_preprocessor.cpp: Note that the parser must be aware of how to handle these counted pointers" "3920": "On building on our knowledge to progress from basic introspection to metaprogramming" "3984": "Q&A" "4042": "So when you say you've built up multiple layers of metaprogramming, do you mean your metaprograms output things like what we wrote today?" "4079": "Isn't offsetof fairly safe to rely on with remotely recent compilers?" "4106": "handmade.cpp: Try using offsetof" "4225": "Someone said that the string function you were looking for was called strdup" "4243": "In the episode of the Jeff and Casey Show "The Wolf Doesn't Want to Come Anymore" you mentioned that you use metaprogramming techniques to make up for modern language shortcomings. Curious what functionality you have used metaprogramming to achieve that you would have found prohibitive in modern languages? Can you suggest any specific usages to pursue for either program robustness, optimization, etc.?" "4345": "To rephrase, are your "multiply layered" metaprograms outputting further metaprograms? Or is it a single layer that has enough complexity to be considered more than a single pass? (Not sure how to phrase, I was mostly trying to prompt further discussion of what you've mentioned previously)" "4444": "Odd... offsetof is defined in MSVC's , and is specified in C '89 as belonging to that header... Did I miss something?" "4512": "Debugger: Use the test project to Go to Definition of offsetof" "4629": "Based on what Jonathan Blow has so far, do you think JAI will have the metaprogramming capabilities that you'd want? If not, what do you think it is missing?" "4703": "You said in a previous stream that you don't really program in C anymore, you basically program in "Caseylang". Does that refer to your metaprogramming tools or is there more to it than that?" "4718": "You're not using header files for OpenGL / Direct3D?" "4728": "Have you worked with any functional languages? Haskell or maybe Scala?" "4765": "Maybe a bit off topic but going along with the Master Spy thing, have you ever done a stealth game and, if so, what particular programming challenges do stealth mechanics bring that you don't usually have to deal with?" "4854": "Is the syntax of Casey-Lang still very close to C?" "4869": "Your metaprogramming tools sound very useful, will you ever open source them, maybe in your will if nothing else?" "4928": "Will you write your own installer for Handmade Hero? Or just zip it and be done with it?" "5004": "How about writing a Casey-Approved GUI debugger for Jai?" "5055": "I'm looking forward to additional visualizers in the debug view (e.g. a small grid view with a dot or line from (0,0) to represent a v2 along with the decimal digits). Do you think that would be worthwhile?" "5128": "Do you ever metaprogram the sims stuff and the job queue?" "5251": "Is there any feature you would add to Jai?" "5458": "Close it down" "5594": "Announcement: F2P discussion between Casey and Shawn McGrath on Thursday" --- name: "day208" title: "Adding Data Blocks to the Debug Log" markers: "97": "Run the game and recap our situation" "125": "handmade_debug.cpp: Get rid of the TestEntity stuff" "175": "handmade.cpp: Consider how we'd like to leverage metaprogramming" "666": "handmade_platform.h: Give DebugEvent the ability to output values" "974": "Run the game and see that the debug system does still work" "994": "handmade_platform.h: Compress the data" "1024": "handmade_sim_region.h: Consider manually defining the DEBUG_VALUEs to write to the debug stream" "1176": "handmade_platform.h: Conditionally #define the DEBUG macros differently" "1444": "handmade_platform.h: Introduce variations of DEBUGValueSetEventData" "1506": ""Not every infinity has to be huge"" "1765": "handmade_math.h: Move in the DEBUGValueSetEventData functions" "1791": "handmade_meta.h: Fix the definitions" "1907": "Debugger: Find that we are recording these debug values" "1944": "handmade_debug.cpp: Reassemble the debug variables back into a structured piece of data" "2307": "handmade_debug.cpp: Introduce DebugEvent_OpenDataBlock and DebugEvent_CloseDataBlock" "2492": "handmade_debug.h: Add them to debug_thread" "2602": "handmade_platform.h: Add them to debug_event_type" "2666": "handmade_platform.h: #define DEBUG_BEGIN_DATA_BLOCK" "2836": "handmade.cpp: Use StorageIndex for DEBUG_BEGIN_DATA_BLOCK" "3074": "handmade_platform.h: Add VecPtr to debug_event" "3149": "handmade_debug.cpp: Introduce AllocateOpenDebugBlock" "3290": "handmade_debug.cpp: Introduce DeallocateOpenDebugBlock" "3360": "Run the game and see that there's no change" "3380": "Q&A" "3418": "Great stream today! Could you explain how this code works? It's fast inverse square root, but I still have no clue how it works" "4067": "What would be a good project for a beginner game programmer?" "4123": "I just read that Natural Selection 2 (for which Unknown Worlds made their own game engine) say they no longer support Windows XP. Does Handmade Hero run on XP, and why wouldn't it?" "4345": "Have you used the Steam Controller? What do you think about it?" "4444": "Thanks, here was the blurb out NS2. Looks like a Visual Studio issue. (What else is new?)" "4485": "Numerical Methods that Work: this is the book you're recommending right?" "4552": "Q: Everything that runs on Windows P runs on Windows NP" "4587": "Any tips on reading books? I find it really hard to read them. I do enjoy their table of contents, gets me excited, but when I read on it gets quite boring" "4816": "Have you read "Linear Algebra Done Right?" by Sheldon Axler? I always recommend it to people who ask me about linear algebra" "4923": "On that note, how do you deal with some of the generally poor social skills in programming / math fields? Noticing this more and more lately, unfortunately" "5118": "Safely call it a day" "5195": "Announcement: F2P discussion between Casey and Shawn McGrath on Thursday" "5243": "Announcement: The speaker list for HandmadeCon 2015 will be announced next Monday" --- name: "day209" title: "Displaying Buffered Debug Data" markers: "53": "Adjust the chair" "106": "Recap where we left off" "217": "handmade_debug.cpp: Implement the various DebugEvents" "620": "handmade_debug.cpp: Introduce EventsMatch" "702": "handmade_platform.h: Massage debug_event" "800": "handmade_platform.h: Replace RecordDebugEventCommon with RecordDebugEvent" "845": "handmade_debug.cpp: Massage these DebugEvents" "880": "handmade_debug.cpp: Make DeallocateOpenDebugBlock take **FirstOpenBlock" "1069": "handmade_debug.cpp: Fix compile errors" "1145": "Run the game and see the same results" "1165": "handmade_debug_variables.h: Generate DEBUGAddVariables dynamically" "1624": "handmade_debug.cpp: Implement the variable adding stuff" "1785": "handmade_debug.cpp: Make DEBUGBeginVariableGroup take the DebugState" "1863": "handmade_debug.cpp: Rename DEBUGAddVariable to CollateCreateVariable and DEBUGBeginVariableGroup to CollateCreateVariableGroup" "1926": "handmade_debug.cpp: Introduce CollateAddVariableGroup" "1982": "handmade_debug.cpp: Bring DEBUGAddRootGroup into play" "2055": "handmade_debug.cpp: Massage DebugEvent_OpenDataBlock" "2250": ""Everyone is happy and smiling" (quote 280)" "2276": "handmade_debug.cpp: Introduce CollateCreateGroupedVariable" "2387": "Debugger: See what's getting passed to the DebugBlock" "2515": "handmade_debug.cpp: Correct typo" "2540": "Run the game and see that we're working" "2564": "handmade_debug.cpp: Provide a way to view the RootGroup per frame" "2655": "handmade_debug.cpp: Make DEBUGDrawMainMenu display everything expanded by default" "2721": "handmade_debug.cpp: Set debug_variable *Group = Tree->Group and conditionally override the Group" "2895": "Run the game and see what it's printing" "2935": "handmade_debug.cpp: Investigate why we're printing out so many RootGroups" "3090": "Debugger: Step into FirstOpenDataBlock to determine that our Events aren't matching and why" "3204": "handmade_platform.h: Consider removing the concept of EventsMatch" "3376": "Debugger: Run and find that we hit a first-chance exception when we wrap" "3412": "Debugger: Inspect the RootGroup" "3524": "Debugger: Step through RestartCollation" "3598": "handmade_debug.cpp: Test for HackyGroup" "3658": "handmade_debug.cpp: Provide the ability in CollateDebugRecords to break at frame 31" "3714": "Debugger: Step into CollateDebugRecords and inspect the data" "3831": "handmade_platform.h: Determine that we wrap the array when we hit frame 32" "3935": "handmade_debug.cpp: Make RestartCollation happen one frame earlier" "3966": "Run the game and see that the entity picker is working" "4004": "Q&A" "4109": "We've been on the debug code for quite a while. How much longer do you think it will take before we're finished?" "4293": "Do you ever use data breakpoints? I find them helpful when some value is changing somewhere but you're not sure where" "4399": "Does the design of this debug system differ significantly from the debug systems you've worked on for other games?" "4423": "(Not SUPER on topic, feel free to skip): How do you treat GL handles in your own code? Are they handled by the asset system or by something else?" "4470": "Call it" "4482": "Announcement: F2P discussion between Casey and Shawn McGrath after tomorrow's stream" --- name: "day210" title: "Consolidating Debug Data Storage" markers: "170": "Recap and set the stage for the day" "276": "handmade_platform.h and handmade_debug.h: Point out the repeated code that could be compressed out" "540": "handmade_debug.h: Make debug_variable contain debug_event Event" "641": "handmade_platform.h: Move the data from debug_variable to debug_event" "659": "handmade_platform.h: Make vectors and rectangles accessible as base types" "742": "handmade_platform.h: Port the DEBUGValueSetEventData functions to use our new base types" "794": "Anticipate mr4thdimention's editor 4coder" "859": "Compile and fix compile errors" "965": "Run the game and see that we're still passing the right values" "975": "Anecdote: Some of the most productive work you will ever do will be with the delete key" "1003": "handmade_debug.h: Consider deleting some code" "1058": "handmade_debug_variables.h: #if 0 as much of this code as possible" "1114": "Make this stuff not happen" "1134": "handmade_debug.cpp: Look at a secondary value when we see a DebugVariableType_Event" "1178": "handmade_debug.cpp: Use the debug_event_types from handmade_platform.h" "1357": "handmade_platform.h: TODO(casey): Have the meta-parser ignore its own #define" "1396": "handmade_debug.cpp: Make DEBUGBeginInteract and DEBUGEndInteract use the other information" "1610": "handmade_debug.cpp: Capture any DebugEvent as a data block" "1673": "Run the game and find that the Tree was never initialised" "1708": "handmade_debug.cpp: Check that the Group exists" "1736": "Run the game and see that it's all well and good" "1756": "handmade_platform.h: Recap the changes" "1786": "handmade_platform.h: Introduce DebugEvent_FirstUIType to contain the DebugVariableType_ data" "1909": "handmade_platform.h: Rename DebugEvent and DebugEventType to DebugType" "1986": "handmade_debug.h: Change debug_variable_type to debug_type" "2032": "handmade_debug.cpp: Rename plenty to DebugType" "2131": "Run the game and see that everything is still working as expected" "2168": "handmade_debug.h: Remove debug_profile_settings" "2229": "handmade_platform.h: Add BitmapID and SoundID to debug_event" "2280": "handmade_debug.h: Remove debug_bitmap_display" "2287": "handmade_platform.h: Add the type definitions for bitmap_id and sound_id" "2358": "handmade_platform.h and handmade_debug.cpp: Propagate BitmapID" "2455": "handmade.cpp: Output a bitmap to our debug system" "2538": "Run the game and see that we are outputting a bitmap" "2579": "handmade_debug.h: Note that the debug_variable is disappearing" "2673": "handmade_debug.h: Consider the possibility of debug_variable_link storing the VarGroup" "2806": "handmade_debug.h: Add *Children to debug_variable_link" "2908": "handmade_debug.h: Remove VarGroup from debug_variable and rename *Children to *ChildSentinel" "3076": "handmade_debug.h: Introduce debug_variable_group to contain the Sentinel" "3238": "handmade_debug.cpp: Propagate these new structs" "3558": "Debugger: Inspect Iter->Link" "3618": "handmade_debug.cpp: Read through the routine" "3695": "handmade_debug.cpp: Set the Link->Children" "3721": "Run the game and note that we're getting a little bit closer" "3760": "Q&A" "3802": "It's expected. I've got more to do?" "3846": "Why call it Sentinel instead of Head even though it is a sentinel?" "3881": "What's your favourite data structure?" "4017": "Handmade, I'm not sure if you specified this in a previous broadcast, but do you plan to implement side scrolling or any kind of platforming alongside the top-down view?" "4074": "Llvm is getting too deep?" "4100": "Legend of Zelda has some faux-sidescrolling rooms" "4123": "What has been your favourite thing so far writing this engine?" "4148": "I had an idea that's probably stupid. But I was wondering if a Vector that, when deleting an element, just left an empty spot that's skipped over when iterating, would still be cache friendly - and still efficient when deleting and inserting. This is slightly over my head though" "4287": "How about your favourite equation?" "4323": "Blackboard: Linear blend" "4346": "Do you use DirectX?" "4376": "What do you think of clang C1 for Visual Studio?" "4443": "If you were doing these compressions (the ones you did today) at work, how different would your process be?" "4551": "Microsoft is making clang for parsing -> intermediate a first class fully supported citizen for visual studio starting in November. Intermediate to machine is still Microsoft (C2)" "4633": "How long do you think it will take before someone makes a Linux debugger that can rival Visual Studios?" "4674": "What do you think of programming competitions? Have you participated in any?" "4688": "What role do you think software security has in modern gaming? Is it not worth wasting CPU cycles to guard against different exploits? How good of a job is the game industry doing in implementing it and should they be doing more or less?" "5015": "Close down the Q&A and get the chat link setup for Mr McGrath" --- name: "day211" title: "Removing Records and Translation Units from the Debug Code" markers: "65": "Recap where we left last time and set the stage for the day" "174": "handmade_debug_interface.h: Throw all of the debug annotation code into this new header file" "241": "handmade_debug.h: Remove debug_variable entirely and give its functionality to debug_event" "375": "handmade_debug.cpp: Rename DEBUGVariableToText to DEBUGEventToText" "390": "handmade_debug.cpp: Introduce GetName" "482": "handmade_debug.cpp: Replace Var->Event. with Event->" "490": ""Everyone's happy and fine and dancing around..."" "734": "handmade_debug_interface.h: Consider extending the concept of debug_event to support an additional Name and stop storing DebugRecordIndex" "910": "handmade_debug.cpp: Comment out Var->Name in CollateCreateVariable and ZeroStruct *Var" "945": "handmade_debug.cpp: Continue moving debug_variable functionality to debug_event" "1005": "Debugger: Notice that we don't currently support some of the DebugTypes" "1086": "handmade_debug.cpp: Assert that the Type != EndBlock" "1127": "handmade_debug_interface.h: Remove DebugType_FirstUIType from debug_type" "1159": "Run the game and see that it's all good" "1168": "handmade_debug_interface.h: Replace DebugRecordIndex with *Name and remove TranslationUnit from debug_event" "1343": "Pig Hat Time" "1351": "handmade_debug_interface.h: Stuff *FileName, *BlockName and LineNumber into debug_event and remove the concept of debug_record" "1705": ""Sometimes you're dumb"" "1734": "handmade_debug.cpp: Change Source to Event" "1840": "handmade_debug.h and .cpp: Change ScopeToRecord to be a char and change how it is used in DebugType_EndBlock" "1978": "handmade_debug.cpp: Remove GetRecordFrom" "2006": "handmade_debug.h: Add *Event to debug_frame_region" "2067": "handmade_debug.cpp: Set ColorIndex to OpeningEvent->BlockName" "2115": "handmade_debug.cpp: Rename Source to Event" "2126": "handmade_debug.cpp: Change HotRecord to HotEvent" "2170": "handmade_debug.cpp: Remove the check on GlobalDebugTable" "2185": "Run the game and see that we're getting a lot closer" "2220": "build.bat: Remove TRANSLATION_UNIT_INDEX" "2242": "Run the game and check that it's still okay" "2245": "handmade_debug_interface.h: Remove debug_record and put GetController back into handmade_platform.h" "2288": "handmade_debug_interface.h: Move ThreadID and CoreIndex from threadid_coreindex to debug_event" "2347": "Run the game and see that all is working nicely" "2359": "handmade_debug_interface.h: Remove #define MAX_DEBUG_TRANSLATION_UNITS" "2390": "handmade_optimized.cpp: Remove DebugRecords_Optimized_Count" "2408": "handmade_debug.cpp: Remove DebugRecords nonsense" "2434": "handmade_debug_interface.h: Consider packing debug_event a little more" "2538": "handmade_debug.cpp: Add Var->BlockName back in to CollateCreateVariable" "2562": "Run the game and see "Hot Entity" again" "2583": "handmade_debug.cpp: Remove debug_event *Var" "2646": "handmade_debug.cpp: Do CollateAddVariableGroup rather than CollateCreateGroupedVariable" "2710": "handmade_debug.h: Remove DebugType_VarGroup from debug_type and call it OpenDataBlock everywhere" "2755": "Debugger: Investigate why BeginBlock is happening" "2922": "handmade_debug.cpp: Remove CollateCreateGroupedVariable" "2928": "handmade_debug.cpp: Assert that Link->Event->Type != DebugType_BeginBlock in CollateAddVariableToGroup" "2954": "Debugger: Inspect Stack and Depth" "3034": "handmade_debug.cpp: Try doing RestartCollation on every frame" "3122": "Run the game and find that it was an overwriting problem" "3170": "Q&A" "3239": "Will you get back to game related coding next week?" "3274": "Do you ever wear the piggie hat at work?" "3297": "What would be the thing that would impress you on a programmer's resume?" "3332": "Bit off-topic, but when will you do the ODE stuff?" "3368": "Blackboard: Ordinary Differential Equation" "3562": "I think he meant e^kt" "3696": "I see a lot of branching in your code. Aren't you trashing the caches and the branch predictor?" "3916": "Been soaking up so much of this stream as I catch up. I realized that I'm writing the usage code first nowadays. It's really streamlined my implementation brain. Just wanted to say thanks. Debate was great too" "3935": "Been learning about x86 assembly in one of my CS classes. Is there any way to force the compiler to use a register for a certain variable instead of a place on the stack?" "4019": "Just asking, but is it worthwhile to put so much effort on the debug system at this stage? There's a lot of things you're doing right now that I'm not sure how it will help in the future (maybe just because I have never programmed games before), but if I as a newbie game programmer were to work on this, do you suggest going as far as you're going right now or proceed on the gaming part to see what I need first before doing it?" "4117": "Well if you would just replace the branches with polymorphism..." "4129": "What's more impressive: previous projects + practical experience vs college degree?" "4180": "Compilers generally ignore the 'register' keyword" "4254": "Ever thinking about running Handmade Hero through cachegrind?" "4385": "Wind it down" --- name: "day212" title: "Integrating Debug UI into Game Code" markers: "70": ""We will be in sync..."" "94": "Recap and set the stage for the day" "196": "Run the game and show that the picking system is kind of random and janky" "358": "handmade.cpp: Look at the current picking system and consider what we'd like to do" "554": "handmade.cpp: Decouple the hit testing and the output" "821": "handmade.cpp: Use debug_id in order to unify the system" "974": "On the uses of pointers as a location in memory and a name" "1224": "handmade.cpp: Make DEBUG_HIT take LocalMouseP.z" "1414": "handmade_debug_interface.h: #define the necessary values and implement them" "1771": "handmade.cpp: Introduce DEBUG_REQUESTED" "1850": "handmade_debug_interface.h: Give debug_event the concept of a DebugID" "1911": "handmade_debug.cpp: Introduce DEBUG_HIT, DEBUG_HIGHLIGHTED and DEBUG_REQUESTED" "1992": "handmade_debug.cpp: Check for the existence of Memory in DEBUGGetState" "2126": "Run the game and hit an assertion" "2254": "handmade_debug.cpp: Replace the Assert in DEBUGGetState with a check for DebugState" "2290": "Run the game and find that the debug system highlights everyone" "2309": "handmade_debug.h: Add DebugInteraction_Select to debug_interaction_type" "2385": "handmade_debug.cpp: Introduce DebugIDInteraction based on VarLinkInteraction which takes the Type and ID" "2507": "handmade_debug.h: Add debug_id SelectedID to debug_state" "2523": "handmade_debug.cpp: Write DEBUG_HIGHLIGHTED and DEBUG_REQUESTED" "2580": "handmade_debug.cpp: Introduce IsSelected" "2696": "Run the game see that it doesn't look very exciting" "2709": "handmade_debug.cpp: Clear the NextHotInteraction when we end" "2747": "Run the game and see that we're in much better shape" "2834": "Q&A" "2860": "You technically have 15 more minutes since we started late" "2905": "Use the 10 remaining minutes to nefarious ends" "2917": "handmade_debug_interface.h: Make DEBUG_HIGHLIGHTED take *Color" "2927": "On compiling something out and using ... as the parameters" "2957": "handmade_debug.cpp: Highlight entities in different colours" "3093": "Run the game and see that the picked entity persists" "3128": "handmade_debug.cpp: Make DEBUG_REQUESTED work on both the selected and hovered entities" "3180": "handmade_debug.h: Add SelectedIDCount to debug_state" "3212": "handmade_debug.cpp: Make IsSelected loop over all of the SelectedIDCounts" "3251": "handmade_debug.cpp: Introduce ClearSelection and AddToSelection" "3359": "handmade_debug.cpp: Make DebugInteraction_Select handle multiple selections" "3460": "Run the game and select as many things as we want" "3500": "Q&A Take #2" "3545": "<3. *handmade?" "3564": "You can emulate expression blocks with lambdas if you don't mind the craziness of C++11" "3584": "insobot checks for your !qa thing I believe, yeah" "3605": "Would you think it's better to start at a junior position at a company and then working my way up? Or try to apply for a higher position immediately?" "3623": "About universal IDs, what if some things want to be identified in the same system, but don't have fixed storage location or conflicts in some other way with the universal uniqueness?" "3710": "Do you know yet if the HandMadeCon talks are going to be streamed and / or recorded?" "3739": "Bots on bots... Damn, imagine all the off-by-one errors" "3747": "Yeah, but wouldn't bots teaching bots how to program be the beginning of the singularity?" "3756": "You have recommended The C Programming Language book after watching your introductory series. Are there any other books you would suggest such as proper programming practices or reference books?" "3785": "You mentioned that the pointer could be used as a key and the thing it's pointing to is the value. So do you mean something like this: PairOf X*, X?" "3805": "What else are you working on outside this project?" "3840": "If you're just starting to watch these videos and you don't have time to watch them all, which ones are most important?" "3909": "How do you pick apart code of other programs / websites, etc.? Sorry for the newbish spam, I just want to get started in the morning" "3993": "Trying to work with others and reading their code, do you try to understand everything they wrote or just understand enough to solve your problems?" "4080": "Is there a programming pattern you see all the time that you can't stand or hate?" "4182": "How do you deal with programming colleagues that use OOP, getters / setters, etc.? Do you try to give them advice or stay away from them if possible?" "4206": "I only know C++ really, but what's the alternative to getters / setters?" "4220": "Story: C++ getters / setters" "4510": "What about a getter than does some calculation on private variables? Like a getDay function on a class that stores an integer representation of time / date?" "4525": "Jon should do that for JAI" "4537": "C# does what you describe" "4572": "The getters and setters are less performant too, right?" "4581": "I know you mostly work on code in smaller groups of people, although what is it like to program in teams and how does the work get split?" "4630": "What about the downside that you don't know whether a value you're accessing does a function call or not?" "4675": "Wrap this up" "4706": "Announcement: The speaker list for HandmadeCon 2015 is up" --- name: "day213" title: "Turning Debug Switches into Events" markers: "91": "Recap and set the stage for the day" "178": "Select a bunch of entities and see our frame rate getting tanked" "235": "handmade_platform.h and win32_handmade.cpp: Implement modifier keys" "374": "Debugger: Go to Definition for VK_BROWSER_BACK" "491": "handmade_debug.cpp: Check to see that Shift is down in order to determine when to add to the selection" "533": "Run the game and try multi-selecting" "644": "Consider consolidating data from various sources" "730": "handmade_config.h: #if 0 everything and investigate how to handle erroneous settings" "860": "handmade_render_group.cpp: Introduce the concept of a DEBUG_IF to create the debug variables" "1152": "handmade_debug_interface.h: #define DEBUG_IF" "1500": "handmade_render_group.cpp: Use DEBUG_IF" "1706": "handmade_debug_interface.h: #define DEBUG_r32" "1829": "Anticipate Jonathan Blow's language JAI" "1911": "handmade_debug_interface.h: Rename variables to facilitate macros" "2789": "handmade_debug_interface.h: Add DebugType_Unknown" "2830": "handmade_debug.cpp: Continue cleaning up compile errors" "2904": "Anticipate mr4thdimention's editor 4coder" "3000": "handmade_debug_variables.h: Delete the file" "3053": "handmade_debug_interface.h: Implement the ability to compile out the entire debug system" "3809": "handmade_config.h: Manually rebuild the file" "3903": "Run the game and see that everything is working properly" "3929": "Q&A" "3943": "hmh_bot Clojure is a bad language" "3958": "Why use getkeystate() instead of WM_KEYDOWN / WM_KEYUP?" "4071": "I don't have much experience in it, but you mentioned the RTTI in C++ is not as good. Could you explain a bit why?" "4194": "I don't quite get why you need to nest the macros for DEBUG_IFs. Can you explain it?" "4598": "You mind going over your debug UI plan for those who don't know what the current plan is?" "4651": "Isn't metaprogramming a security hole?" "4660": "I've been reading about the cost of virtual functions. Normal non-virtual functions costs a 'call' command, but with virtual we need two fetches and a call. Is that very costly in performance critical areas? Is that the reason to avoid virtuals? For me, I don't like the fact that they introduce hidden costs, makes it harder to reason about your code" "4814": "I can't figure out for the life of me a way to draw an empty, non-filled Rectangle via the Win32 API. I tried SelectObject(DC, GetStockObject(NULL_BRUSH)) and then Rectangle(...) but it never draws anything" "4844": "win32_handmade.cpp: Demo MoveToEx and LineTo" "5067": "What are your thoughts on twitch starting to affect game design?" "5258": "Could you list the important features a good graphical debugger should have?" "5323": "Are you one of those that thinks that previously DirectX was better than OpenGL, but now is the opposite?" "5335": "Do you know how far has metaprogramming come along in other fields? I can imagine researchers using genetic algorithms to self enhance code" "5351": "Spin things down" --- name: "day214" title: "Collating Permanent Debug Values" markers: "85": "Recap and set the stage for the day" "125": "handmade_debug_interface.h: Turn on DEBUG_IF and resume implementing it" "253": "handmade_debug.cpp: Introduce DEBUGInitializeValue" "294": "Consider how to hook this into the system" "553": "handmade_debug.cpp: Make varieties of DEBUGInitializeValue for the various types" "767": "handmade_debug_interface.cpp: Try using the sequence operator to set DebugValue##Path" "1048": "On using the sequence operator to initialise a static" "1111": "handmade_debug_interface.cpp: Use the sequence operator to set DebugValue##Variable" "1191": "handmade_debug.cpp: Write DEBUGInitializeValue" "1307": "handmade_debug.cpp: Consider adding CollateAddVariableToGroup, AcquireMutex and ReleaseMutex to DEBUGInitializeValue to enable us to manipulate these types indirectly" "1527": ""A better way"" "1538": "handmade_debug_interface.h: Write a new, thread-safe DEBUGInitializeValue" "1850": "handmade_debug.cpp: Implement the ability to output all the variables in a list" "1902": "handmade_debug.cpp: Introduce GetGroupForName" "1927": "handmade_debug.cpp: "Double up on the fanciness"" "2013": "Blackboard: How handmade_config.h enables us to preload values on execution" "2115": "handmade_debug.cpp: Undo and introduce GetGroupForHierarchicalName" "2169": "handmade_debug.cpp: Add *ValuesGroup to debug_state" "2272": "handmade_debug.cpp: Make CollateAddVariableToGroup test if Permanent" "2326": "handmade_debug.cpp: Write GetGroupForHierarchicalName" "2489": "handmade_debug.cpp: Initialise DebugState->ValuesGroup" "2527": "Run the game and see that it picks up all the debug variables" "2542": "handmade_debug.cpp: Set *HackyGroup differently in DEBUGDrawMainMenu" "2568": "Run the game and see that we're sort of working" "2613": "handmade_debug.cpp and handmade_debug_interface.h: Investigate why we're adding the same variable multiple times" "2731": "Debugger: Break into DEBUGInitializeValue and inspect Event" "2882": "handmade_debug.cpp: Test if Event->Type == DebugType_MarkDebugValue at the start of the routine" "2992": "Run the game and see all of the variables" "3067": "win32_handmade.cpp: Reduce the number of threads used" "3130": "Run the game and see that we are still outputting too many copies of the variables" "3142": "win32_handmade.cpp: Revert the number of threads used" "3175": "Debugger: Break into DEBUG_IF and Go to Disassembly" "3321": "handmade_debug.cpp: Find that RestartCollation keeps rereading the events and adding them" "3537": "Q&A" "3563": "Variable initiation hack in DEBUG_IF macro makes my internal code quality kitten sad. Would it be possible to move that initiation to struct ""method""?" "3595": "Persisting the DEBUGValue between live code loading is great, I didn't understand what you were doing but then I got it with the demo, really cool. I had conflated the value of a variable with the value of debug of the variable. Small addition for a huge benefit" "3740": "Are you sad that you didn't fix Collation? If no more questions come in it would be neat to see it now, so you're not sad" "3769": "Will you have time tomorrow to look at 4coder? I am trying to decide whether to prioritize getting the new demo out tomorrow morning" "3873": "Gotcha, I do have parameterized commands that I'd love to hear a response on" "3910": "Why are you awesome? Which dojo did you train to become a code warrior?" "3942": "desuused elaborated with a Cmuratori prefix" "3979": "I quote "instead of writing debug_event Name = initiator((AnotherVar = something, something)); make a struct constructor debug_event (&AnotherVar, something) that initiates the value"" "4075": "So that you don't do assignment in the function call in the macro, which makes me really saaaad" "4225": "Are you playing any games? If so, what?" "4266": "So elvin = elxenoaizd?" "4298": "How did you keep up that awesome beat just now?" "4311": "What type of games do you prefer?" "4359": "Not elven but elzen" "4388": "Wind it down" --- name: "day215" title: "Cleaning Up Debug Event Collation" markers: "60": "Recap and set the stage for the day" "309": "Blackboard: The inconsistency between an event buffer and a frame" "585": "handmade_debug_interface.h: Start to make Events be a temporary buffer by reducing the MAX_DEBUG_EVENT_ARRAY_COUNT" "622": "Run the game, bump up the MAX_DEBUG_EVENT_ARRAY_COUNT and play with the camera" "686": "handmade_debug_interface.h: Remove MAX_DEBUG_EVENT_ARRAY_COUNT and MAX_DEBUG_EVENT_COUNT and bake their values straight into Events" "878": "handmade_debug.h: Start porting the rest of the code to use copy out" "1108": "handmade_debug.h: Reorganise debug_state" "1299": "handmade_debug.cpp: Massage DrawProfileIn" "1505": "handmade_debug.cpp: Replace the concept of CollateArena in GetDebugThread with allocatable values" "1648": "handmade.h: #define FREELIST_ALLOC" "1783": "handmade_debug.cpp: Use FREELIST_ALLOC in GetDebugThread" "1834": "Internet: decltype" "1871": "handmade.h: Fight with decltype" "2079": "handmade.h: Make FREELIST_ALLOC work" "2103": "handmade_debug.cpp: Introduce NewFrame to initialise the collation" "2568": "handmade_debug.cpp: Implement collation" "2753": "handmade_debug.cpp: Provide the ability to get new frames" "2900": "handmade_debug.cpp: Work through compile errors" "3420": "handmade_debug.cpp: Introduce FreeFrame" "3471": "handmade.h: Attempt to silence the "assignment within conditional expression" warning" "3545": "handmade_debug.cpp: Fix some copy pasta" "3603": "Run the game and run out of memory" "3620": "handmade_debug.cpp: Implement FreeFrame" "4088": "handmade_debug.cpp: Introduce FreeVariableGroup" "4136": "Run the game and see that we still hit the Arena->Size assertion" "4181": "handmade_debug_interface.h: Ensure that the debug system can be compiled out" "4241": "Run the game and see that we're back to our super speedy software rendered world" "4253": "Q&A" "4371": "Once collation is done, will we get hierarchies going next?" "4431": "Are you going to do some tricks for compile time string searches or something?" "4444": "The last software company I worked at, you would fail a code review MISERABLY right now. How do you feel about those practices?" "4592": "Do you use SQL and, if so, how do you structure your databases?" "4610": "I imagine that all the "paths" will be known at compile time, so you probably don't need to do strcmp but I'm not sure if just using the addresses would work" "4644": "By the way, I tried decltype() on clang and it worked in the same kind of context (I think). cl is probably broken" "4663": "Can you give us some programming challenges for until you get back?" "4702": "Would it be viable to write a game that uses a database model and its logic as database transformations?" "4842": "My mind cannot stop thinking about the scratch memory thing you talked with Jon the other day on the pre-stream, so I'm sorry if this is off-topic. It was a piece of memory that is kept per thread (and grows a little). Do I understand it correctly that you're passing it down the call stack, so that each function can push and pop a piece of scratch memory from it?" "4926": "I've never thought about metaprogramming much before, and it sounds really interesting. Do you have any recommendations for more information on it?" "4950": "What happens with the particles' (more simplified) collision detection if you at the same time hold and drag the window's title bar, since the game timer will be paused when the window is in the drag / size message loop built into Windows?" "5072": "How would you "abstract" a math library as in, the game / engine uses a v2 / v3 / v4 class and you have to use graphics libs with predefined vector classes they use for rendering but you don't want to couple your game with one of these libs?" "5127": "Close down" --- name: "day216" title: "On-demand Deallocation" markers: "34": "On easing the burden of returning to code after a break" "163": "Recap and set the stage for the day" "185": "build.bat: Turn the debug system back on and assess our situation" "268": "Run the game and note that the Last frame time looks weird" "341": "handmade_debug.cpp: Consider making FreeFrame work and be called" "475": "handmade_debug_interface.h: Talk through the debug system" "923": "handmade_debug.cpp: Consider looking at elements over multiple frames" "1235": "handmade_debug.cpp: Consider implementing FreeFrame" "1307": ""You'll have to excuse me if I yawn during this frame"" "1318": "handmade_debug.h: Look at debug_frame" "1433": "Blackboard: "Debug Element"" "1850": "handmade_debug_interface.h: Consider making the debug_table be a giant buffer" "2019": "Blackboard: Using a giant 64 MiB buffer" "2461": "handmade.h: Consider providing the ability to allocate memory on demand" "2577": "Yawn" "2625": "handmade.h: Pass the entire AllocationCode to FREELIST_ALLOCATE" "2800": "handmade_debug.cpp: Consider proving a way to free on demand or give memory_arena the ability to handle memory allocation" "2878": "handmade.h: Introduce ArenaHasRoomFor and GetEffectiveSizeFor" "3082": "handmade_debug.cpp: Introduce PushSizeWithDeallocation" "3408": "handmade_debug.cpp #define DebugPushStruct" "3444": "handmade.h: Fix compile errors" "3512": "handmade_debug.cpp: Replace PushStruct with DebugPushStruct" "3545": "handmade_debug.cpp: Pass the correct values to DebugPushStruct" "3588": "handmade_debug.cpp: #define DebugPushCopy" "3651": "handmade_debug.cpp: Continue fixing compile errors" "3683": "handmade_debug.cpp: #define DebugPushStruct and consider building in the Push functions to the arenas proper" "3772": "Compile and run the game, run out of memory and hit our "Not implemented"" "3828": "Q&A" "3855": "Have you heard of the DTrace tool? It allows dynamic tracing on running binaries and also kernel! (Not available on windows, though)" "3878": "You mentioned in the prestream a 'dynamic' memory_arena. How does that actually work since we allocate memory only once? What happens when the arena is full?" "3945": "You've mentioned the term "Collation" on this episode and several previous episodes. What exactly do you mean when you use that term?" "3997": "What keyboard do you use?" "4014": "Could you elaborate a bit more on what 'memory alignment' means?" "4117": "But wouldn't asking the OS for more memory expose more failure points thus be against Handmade Hero memory philosophy? Since the whole point of our scheme was that we're sure once we run the game we can't crash" "4239": "I'm always hesitant when using Linked Lists in engine and gameplay code (debug code is fine) because of their cache unfriendliness, random access of memory and difficulty in debugging (you'd have to dig down a node to find what you're looking for). Do you think it's not that big of a deal and I'm worrying too much?" "4502": "I'm debugging on Day 121. Do you used int instead of int32 for any reason?" "4524": "handmade.cpp and handmade_debug.cpp: Replace int with u32" "4616": "libs like the stb libs let you specify a custom malloc / free function. How would you integrate that into an arena-based system?" "4674": "Have you heard of VMem?" "4683": "If we wanted to use object pools (reusable / recyclable objects for enemies, for example), where would be the best place to store them? Permanent or transient memory? I guess they wouldn't be in transient cause the whole game shares the same pool, so I guess permanent?" "4734": "reinterpret_cast, static_cast and dynamic_cast: are they of any good use?" "4773": "There are libs that allow allocating and freeing multiple chunks of memory during runtime. How would you specify malloc / free for them in an arena-based game like Handmade Hero?" "4886": "The int use in question was a lot in SIMD'ing DrawRectangle -> DrawRectangleQuickly, and my version of the code is crashing on "Access violation reading location" when casting Pixel to __m128i at the start. Could iterating with int vs int32 be the reason?" "4931": "What do you think of pass by reference and references? I think they obfuscate the code because it's harder now to see from the calling site to find out if an object is passed by value (copy) or we are actually passing an address of it to modify it" "5147": "Wind it down" "5214": "Announcement: Handmade Hero Forums are now hosted on HandmadeDev.org" "5284": "Announcement: HandmadeCon 2015" --- name: "day217" title: "Per-element Debug Event Storage" markers: "154": "Run the game and hit our assertion in FreeVariableGroup" "229": "handmade_debug.h: Consider cleaning this stuff up as we do it" "322": "handmade_debug.h: Move RootGroup from debug_frame to debug_state" "428": "handmade_debug.h: Introduce debug_element to store a chain of Events" "594": "handmade_debug.h: Introduce debug_stored_event" "681": "handmade_debug.h: Provide a way to walk the existing debug elements and free them" "942": "handmade_debug.h: Add TotalFrameCount and calculate how long the debug system will then be able to run before the TotalFrameCount wraps around" "1122": "handmade_debug.cpp: #if 0 RegionIndex and work on VarLinkInteraction" "1371": "handmade_debug.cpp: Introduce GetEventFromLink" "1643": "handmade_debug_interface.h: Refresh our memory of DEBUGInitializeValue and RecordDebugEvent" "1895": ""Riddle me this, Batman"" "2129": "handmade_debug.h: Add ElementHash to debug_state and talk through the system" "2347": "handmade_debug.h: Add debug_tree *RootTree to debug_state" "2394": "handmade_debug.h: Reduce the size of the ElementHash array" "2479": "handmade_debug.cpp: Rewrite FreeFrame" "2788": "handmade_debug.h: Add debug_stored_event *FirstFreeStoredEvent to debug_state" "2824": "handmade_debug.cpp: Remove HackyGroup" "2983": "handmade_debug.cpp: Considering removing the concept of Region and sending all the BeginBlock and EndBlock into the ElementHash" "3048": "On coming towards a coherent architecture" "3166": "handmade_debug_interface.h: Figure out how to uniquely identify events" "3470": "handmade_debug_interface.h: Add GUID to RecordDebugEvent" "3556": "handmade_debug_interface.h: #define UniqueFileCounterString" "3682": "handmade_debug_interface.h: Remove FileName and LineNumber" "3714": "handmade_debug.cpp: Introduce HashThisEvent but turn off HANDMADE_INTERNAL" "3742": "Q&A" "3833": "For UI programming, what do you think of the MVC (Model View Controller) pattern? Is it of any practical use?" "4007": "Could you talk a bit about other debug system-y stuff you've done before? I've done all sorts of debug systems, not much like what you're doing now, and I'm curious what other stuff you may have done (just high level description, one-sentence descriptions are fine). Thanks!" "4273": "Can you explain what the macro-nastiness exactly does? Why do you have two underscore "levels"?" "4392": "Would you say that your engine makes it easy for a new programmer to come in and add functionality?" "4428": "I was implementing Shadow mapping in OpenGL. It seems that there's a lot of issues and artifacts: Shadow Acne, Peter Panning etc., and to work around those you end up with something more complex and expensive. I kind of find it hard to believe that games with decent graphics use this technique. Do you know of any other good way to implement shadows, or do we just have to work around its limitations?" "4745": "Is the mobile platform limit to Android-only (excluding iOS) for any particular reason?" "4821": "What if we just blur the edges of the shadows? (Gaussian blur)" "4863": "Do you think namespaces actually solve the problem of naming collisions? Or there's no need for them and the usual C-style 'SystemName_Function' suffices?" "4892": "Yes, but how is Windows any different, don't you need to compile Windows programs on Windows?" "5170": "On overcoming world hunger" "5222": "Close it down" --- name: "day218" title: "Hashing Debug Elements" markers: "80": "All You Can Eat" "110": ""We don't know which kind of a lunch buffet our debug system will be yet..."" "178": "Build and run and note how fast the guy zips around, before turning the debug system back on" "214": ""There will always a better lunch tomorrow"" "227": "handmade_debug_interface.h: Recap the GUID concept" "323": "On shifting the place settings when serving lunch" "353": "handmade_debug_interface.h: Pass in the GUID and make it work" "435": "Thoughts on the macro processor" "502": "On thinking about memory allocation over lunch" "580": ""It's more of a lunch thing"" "601": "handmade_debug.cpp: Make CollateDebugRecords put Elements into locations based on where they came from" "733": "handmade_debug.cpp: Introduce GetElementFromEvent" "964": "First Rule of Programming: "You don't eat lunch if you're already full"" "981": "handmade_debug.cpp: Continue implementing GetElementFromEvent" "1190": ""That's like getting lunch delivered..."" "1246": "handmade_debug.cpp: #if 0 CreateVariable, AddVariableToGroup, CreateVariableGroup and FreeVariableGroup" "1271": "handmade_debug.cpp: Introduce StoreEvent" "1434": ""Easy peasy lemon squeezy"" "1471": "handmade_debug.cpp: Continue working with the StoreEvent" "1558": "Thoughts on lunch despotism" "1584": "handmade_debug.cpp: Remove all of the Region stuff and #if 0 AddVariableToGroup" "1652": "handmade_debug.cpp: Implement StoreEvent" "1747": "handmade_debug.cpp: Fix compile errors" "1851": "Apologise for making a faux pas" "1860": "On the programming equivalent of sitting at the wrong seat at lunch" "1878": "handmade_debug.cpp: Vaporise PushSizeWithDeallocation" "1921": ""Don't let your whole life be defined by the one bad lunch you ate"" "1952": "handmade_debug.cpp: Make the StoredEvents be freed as necessary" "2218": "handmade_debug.cpp: Introduce FreeOldestFrame" "2376": "Compile, fix compile error and ensure everything else is doing something reasonable" "2414": "handmade_debug.cpp: Add if(ArenaHasRoomFor) to NewFrame" "2560": "handmade_debug.cpp: Make a PerFrameArena SubArena" "2684": "Debugger: Step into PushSize and discover that we didn't have enough debug memory" "2733": "Run the game and note that we're storing all of our debug data" "2785": "handmade_debug.cpp: Investigate why our Last frame time is wrong" "2890": "Debugger: Hit a FrameMarker and inspect values" "3006": "handmade_debug.cpp: Correctly set the MostRecentFrame" "3019": "Run the game and see that our Last frame time is now correct" "3032": "handmade_debug.cpp: Print out the memory usage of the arena" "3157": "Run the game and see our Per-frame arena space remaining" "3185": "handmade_debug.cpp: Reduce the size of that SubArena" "3221": "Run the game and see the new Per-frame arena space remaining" "3237": "Debugger: Step into StoreEvent and ensure that everything's still working properly" "3310": "Warn against eating more lunch than we can reasonably digest" "3343": ""There's always lunch tomorrow"" "3362": "Q&A" "3392": "When we come to do the AI system, do you think it'd be reasonable to give the dudes a "gather lunch" behaviour?" "3410": "What did you have for lunch?" "3444": "Imagine that you're young again and you're eating your lunch and you can choose between a C and Java-like language in what you can work with memory in much C-like way but that language would say you how to implement some ideas (like a Python is about line offsets, which is not good I think)? What would you choose then and why?" "3522": "During HandmadeCon will there be an organised lunch at the Campfire BBQ?" "3544": "Does Emacs offer more syntax support than what I am seeing at the moment?" "3576": "Is there anything that could be considered a "free lunch" in low level optimization?" "3587": "Fair warning: The optimizer might store the strings in the same place which will break the whole GUID thing" "3613": "Do you suggest programming should be snacked upon throughout the day as an alternative to a 3 course code feast?" "3748": "Why do you think that there have been no good new languages since C? Are all the language designers out to lunch these days?" "3853": "Do you feel there's a perfect balance between test-based coding, or more efficiency / optimization? Or do you prefer one over the other?" "3999": "What are your thoughts on clang?" "4051": "I think he meant string literals, like the -Og flag, I think" "4061": "What do you think about Unity, etc.?" "4189": "What's been the biggest hurdle you've had to overcome so far on this endeavor?" "4203": "What do you suggest that people who are in the first year of C++ do as projects for coding throughout the day? (Feel free to skip if you've answered this before)" "4281": "Have you seen John Cleese's talk on creativity? If so, what are your thoughts on it?" "4296": "How many more features will the debug system get? It already eats most other engines' lunch" "4345": "Do you feel that taking calculus 1/2 is needed to become a good programmer?" "4411": "It was actually the -GF flag for the MSVC compiler. It enables string pooling, lumping all string literals into a read-only portion of memory so it only stores one of each different string" "4482": "Do you think there really hasn't been a good language since C, period? Or just that there haven't been any good languages that do what C can, like a good "competitor"? For example, if someone needs a small app, use C regardless or some higher languages are good for that (in your opinion)?" "4560": "What if it doesn't pool strings and two same string literals get different addresses? Would the system lose its lunch?" "4626": "Pseudonym73: Note that "good language" is relative to what you're doing. I've done things in Prolog that I wouldn't want to do in C" "4814": "Wind down" "4954": ""Don't forget to eat lunch"" --- name: "day219" title: "Automatically Constructed Debug Hierarchies" markers: "2": "Intro" "31": "Background on the number 219" "70": ""You should fertilize that directory with human tears, and then you should see what grows from it. It will probably be black roses that crumble and blow away with the wind."" "99": ""The whole point of the existence of this system is because humans are so fallible and always do everything wrong."" "109": "Current state of the game when run" "124": "Brief explanation of unlimited debug info storage system from yesterday" "205": "Determining today's goal: bringing the debug system together" "271": "Starting work on hierarchical debug event UI" "292": "Describing how debug events should be grouped into a hierarchy of debug elements" "403": "Changing terminology of root tree back to root group" "443": "Re-enabling hierarchy generation for the new system" "518": "Considering whether or not to add free-list for the debug info" "565": "Updating AddVariableToGroup, CreateVariableGroup to work with elements in a tree hierarchy" "751": "Splitting AddVariableToGroup into AddElementToGroup and AddGroupToGroup" "829": "Noting names aren't stored in debug_variable_group, and fixing it" "941": "Removal of CreateVariable" "981": "Adding root variable group handling in GetGroupForHierarchicalName" "1057": "Creating root variable group" "1106": "Adding hierarchy lookup to GetElementFromEvent" "1165": "Thinking how BlockName and/or GUID should be used to create the hierarchy" "1334": "Use GetGroupForHierarchicalName when adding a new event to check for a parent group, and link them if there is one" "1423": "Enabling the drawing of the hierarchy" "1458": "Debugging crash due to not knowing how to draw certain debug elements" "1550": "Adding a default name for unhandled debug events to prevent crashing" "1569": "Running the game, now doesn't crash, but debug variables aren't listed" "1588": ""Sometimes even in the depths of despair, some little tiny thing goes your way, and the important thing to remember is not to let that go to your head"" "1619": "Start looking into why debug variables aren't appearing" "1791": ""I want to break down in tears. I want to just give up and let the horrors of the world continue unabated. But instead what I'm gonna do is set a breakpoint on MarkDebugValue"" "1809": "Add breakpoint to MarkDebugValue to see which events are getting through" "1846": "Explanation of the bug, partial fix by storing GUID in the event" "1909": "Rerunning the game, multiple events now correctly show up, but with incorrect text" "1917": "Storing BlockName into the event too, making the debug display slightly more correct" "2017": "Explaining how the debug names can be used to assemble the hierarchies" "2065": "Implementing the hierarchy building in GetGroupForHeirarchicalName" "2280": "Adding the GetOrCreateGroupWithName helper function" "2461": "Putting a name into the debug_variable_group struct, completing hierarchy creation code" "2643": "Adding a StringsAreEqual function with explicit length parameters" "2782": "Describing what more needs to be added for the debug hierarchy to display correctly" "2890": "Start branching the code to handle both single elements and hierarchies" "3099": "Running the game, now events are displayed hierarchically" "3233": "Adding interaction support to the hierarchical debug events" "3498": "Rewriting how groups are expanded" "3576": "Game running, interactions now working but with improper highlighting" "3703": "Debugging why multiple interactions are being highlighted as hot" "3731": "Found the bug" "3788": "Everything running correctly" "3825": "Q&A" "3851": "was this the 'depression oriented programming' approach i keep hearing about?" "3872": "you pass string length together with pointer to string data in several places. Do you think it would be better to create a string struct that holds length and a data point?" "3913": "You've talked a lot about languages lately, have you taken a look at Swift at all? Thoughts?" "3931": "How do you come up with that literacy stuff? That was Awesome!" "3953": "I DONT GET ANYTHING :(" "3972": "do you think that the bug in DebugInteractionsAreEqual would have been caught by a compiler-generated comparison operator as in C++?" "4028": "will handmadehero2 be written in JAI ?" "4036": "I meant literature talk sorry lol" "4077": "Who is your favourite figure in the computing world (dead or alive)? Mine's currently Claude Shannon" "4099": "how about handmadebrowser in JAI? :)" "4120": "Off topic but how old were you when you started coding" "4127": "prestream question: do you think that intel hitting the proccesa size limit will make video game falter of will they survive?" "4173": "Casey, you are as old as me. Are you also planning to retire from working ASAP ? :-)" "4258": "What do you think about Test-Driven Development?" "4273": "do you actually play games yourself? If so what?" "4294": "Why should i keep on going in this harsh cold reality, when i get lost on episode 005 of hmh :(" "4342": ""We just have to have faith that The Variable is looking down on us from The Great Memory, and that if we all just work hard and try to be good people that eventually The Variable will let us into The Great Memory and we'll live in peace and happiness with all of our other discretized values."" "4377": "would you prefer to ui in c code or use something like html or something else?" "4388": "If you could be given complete control over Microsoft or Apple, which one would you choose and what would be your number one priority?" "4428": "Mind giving a shout-out about your appearance on the indie(Radio); podcast tomorrow?" "4559": "Casey, the question was not entirely meant funny: Can you imagine to still code games and stuff when you are like 60?" "4615": "sometimes I compare myself with other great programmers and get depressed cause I'm far away from their level - I know I shouldn't be comparing cause they grew up in different environments etc and I know for sure I can reach their level if I apply myself and learn quick, but sometimes it just gets to me and I feel bad about it... have you ever felt that way? any tips how to overcome it?" "4990": "Do you think Japanese not adopting the OOP paradigm is because they are smarter or simply because of not even being interested in changing to new languages?" "5026": "Pseudo coder question: How would one go about learning Assembly language? And are compilers/linkers written in that?" "5172": "would you ever think about using C# or python?" "5187": "how do you approach getting an overview of a large code base, like clang or the linux kernel?" "5248": "Wind down" "5286": "Support episode guide extraordinaire Miblo" --- name: "day220" title: "Displaying Data Blocks in the Hierarchy" markers: "5": "Intro" "65": "Recap of the debug system" "142": "Ideas for today's work" "251": "Remembering how DEBUG_VALUE and DEBUG_BEGIN_DATA_BLOCK worked, considering unifying the unique IDs" "304": "Thoughts about using the string in BEGIN_DATA_BLOCK for debug UI layout" "350": "More thoughts on using EntityDebugID to differentiate entities without touching gameplay code" "393": "Recalling how debug data blocks work, and how they differ from the debug switches handled by the MarkDebugValue event type" "538": "Discussing the changes to debug data blocks that we want to implement, and how they'd help when debugging" "656": "Thinking about changing the allocation strategy of debug data blocks to match that of debug elements" "760": "An idea for unifying the debug data block + debug element code" "849": "Changes to the handling of the OpenDataBlock debug event type, to accommodate the new allocation idea" "897": "A quick look at how StoreEvent was working with debug elements" "932": "Clarification of how the debug system is currently working, and the planned changes" "1026": "Changes to the handling of the CloseDataBlock debug event type" "1051": "Updating the AllocateOpenDebugBlock function and open_debug_block struct to store a debug_element" "1127": "Allowing debug data blocks to override which debug_element StoreEvent stores into" "1164": "Actually using the right variable, running the game" "1175": "Removing erroneous quotes from the debug display by no longer passing strings to the DEBUG_BEGIN_DATA_BLOCK macro" "1199": "Running the game again, noticing a problem with a missing group, figuring out why" "1282": "Start trying to fix the debug data blocks not displaying as a group" "1352": "Adding a flag to GetGroupForHierarchicalName to optionally create an additional group" "1441": "Backtracking on the flag idea, deciding to directly turn the element into a group instead" "1507": "Verifying how the debug blocks work in the debugger" "1738": "Explaining how the workings shown in the debugger differ from what was expected" "1775": "Debugging GetGroupForHierarchicalName" "1971": "Gaining an understanding of the behaviour, explanation about how only debug_variable_groups have names" "2035": "Discussing potential solutions for getting the name passed in DEBUG_BEGIN_DATA_BLOCK to show up" "2071": "Choosing to store the OpenDataBlock event as well as the events for its contents, since it will contain the name" "2119": "Looking back at how the debug events are drawn, and adding a case for open debug data blocks (bitmap_id initially by mistake)" "2172": "Questioning why the erroneous change seemingly made a difference in output, figuring out why" "2219": "Back to thinking about why open data block names aren't showing up" "2251": "Adding a temporary change to the CloseDataBlock handling, which causes the data block endings to show up" "2283": "Adding some debug data block specific handling to DEBUGDrawMainMenu so the values inside the data block can be drawn" "2430": "Creating the DEBUGDrawElement and DEBUGDrawEvent functions to help in the drawing of debug information" "2538": "Talking about the complications of debug_events and debug_elements and how they both relate to the printing of debug info" "2580": "Changing DEBUGDrawElement to use debug_stored_event instead of debug_event so that it can walk through the next pointers" "2642": "Moving most code from DEBUGDrawElement into DEBUGDrawEvent" "2693": "Changing DEBUGDrawElement to extract the oldest event from the element, and determine if it needs to be forwarded to DEBUGDrawEvent or perform other work" "2818": "Fixing some compile errors by passing necessary variables to the new functions" "2844": "Adding the debug_tree to the layout struct and setting it in DEBUGDrawMainMenu" "2936": "Thinking about also adding the debug_variable_link to the layout struct, but choosing to re-factor the surrounding code to use debug_id instead" "3146": "Updating the interaction code, changing the function VarLinkInteraction to EventInteraction and passing the debug_id and debug_event instead of the debug_tree and debug_variable_link" "3251": "Removing the debug_tree from the layout struct since the interaction changes make it unnecessary" "3270": "Finishing off fixing the remaining compile errors" "3424": "Removing the now unused GetEventFromLink function" "3477": "Running the game" "3489": "Starting to add code to the DebugDrawElement function to loop through debug data blocks, and call DebugDrawEvent for each value held inside" "3530": "Changing DebugIDFromLink to DebugIDFromStoredEvent" "3575": "Adding a debug_tree argument to DEBUGDrawElement so that it can be passed to DebugIDFromStoredEvent, and finishing off its data block handling code" "3716": "Game running with the entity related data block now being added to the Simulation hierarchy" "3730": "Noticing problems related to the debug_id changing every frame for data block values" "3835": "Solving the problem by using event GUIDs to get stable debug_ids for data block values instead of the associated debug_stored_event address which wasn't stable" "3942": "Game running with the problem resolved" "4001": "Q&A" "4026": "What is the debug collator?" "4113": "https://hero.handmadedev.org/forum/code-discussion/902-day-211-gcc-clang-build-report" "4450": "How do game devs you work with typically handle temporary / non-shipping sound effects?" "4494": "Will there be a pass to strip unused code from HMH?" "4519": "What do you think about working in constraints and having limited resources? I think it makes programmers write less lousy code and force them to actually care and know what they're doing..." "4538": "Can we get rid of the build error (something about introspection of structs) that doesn't seem to affect anything?" "4711": "You missed Region->ColorIndex = (u16)OpeningEvent->BlockName;" "4749": "How many lines are we at now?" "4801": "Sure. What's a quick way to _produce_ temporary sound effects to, for example, figure out where/when they should be played?" "4876": "Not stripping unused code is how GTA Hot Coffee happened" "5029": "If a programming job wasn't available to you, what type of work would you be interested in doing other than programming for a living?" "5050": "What do you think of dlc then? ;)" "5201": "Do you play MMOs, if so, how do you feel about the way they do their leveling?" "5212": "Wind down" --- name: "day221" title: "Implementing Multi-layer Cutscenes" markers: "48": "Assets: intro_art.hha is released" "183": "Introduce this art pack" "253": "handmade_file_formats.h: Add our new asset types and tags to asset_type_id and asset_tag_id" "308": "Blackboard: CutScene Art" "556": "Recompile and see that we're running as expected" "678": "Blackboard: Calculate how much space the cutscene requires" "721": "handmade.cpp: Increase the amount of memory allocated for the assets" "781": "handmade_cutscene.cpp: Start writing the cutscene code" "854": "handmade_cutscene.cpp: Introduce RenderCutScene" "1183": "handmade.cpp: #include "handmade_cutscene.cpp"" "1212": "handmade.cpp: Call RenderCutScene and introduce UpdateAndRenderGame" "1444": "Compile and run and hit an assertion in CheckArena" "1502": "handmade.cpp: Do EndTemporaryMemory before CheckArena" "1525": "Compile and confirm that this is now correct" "1540": "handmade.cpp: Toggle from UpdateAndRenderGame to RenderCutScene" "1566": "Debugger: Step into RenderCutScene and ensure we're getting a bitmap" "1618": "handmade_cutscene.cpp: Pass a height to PushBitmap and see the cutscene in action" "1640": "handmade_cutscene.cpp: Tweak the size and encounter a bug in the debug stuff" "1678": "build.bat: Turn off HANDMADE_INTERNAL" "1696": "handmade_cutscene.cpp: Tweak that size until the image fits the screen, and add layers to the scene" "1789": "What we did today" "1811": "Blackboard: Positioning the layers in space" "1932": "handmade.h: Introduce CutSceneTime" "1969": "handmade_cutscene.cpp: Pass CutSceneTime to RenderCutScene and slowly zoom the camera" "2260": "Run the game and see the cutscene in action" "2281": "build.bat: Temporarily compile in -O2" "2313": "Note that the image has no depth to it" "2346": "handmade_cutscene.cpp: Position the layers in Z based on their LayerIndex" "2443": "See the parallax effect" "2499": "handmade_cutscene.cpp: Work on the layers' positioning" "2579": "handmade_cutscene.cpp: Introduce LayerPlacement" "2678": "handmade_cutscene.cpp: Special-case the sky background" "2810": ""Hey, look! It did what I expected!" "2879": "handmade_cutscene.cpp: Place the layers" "3423": "Note that the only problem we have left is that we're zooming towards nothing" "3463": "handmade_cutscene.cpp: Introduce CameraOffset and set the focus point" "3631": "Q&A" "3691": "Would you normally want to get the position / scale for each layer from the artist? If so, how would you go about doing that?" "3799": "I am new to programming and know intermediate Java only. Can you explain what you use emacs for if you're using Visual Studio?" "3829": "I think you should move the skylight up a tad bit" "3850": "I feel like we should have some deep voice narration. "Down in the valley..."" "3871": "Did you ever have trouble while learning to program? I'm currently getting my rump handed to me in my Java class" "3929": "Will we ever load png files? If so, will we be writing our own loader or use stb_image.h? I read that it's tricky to load pngs or no?" "3954": "Will your cutscenes be coded like this, or be setup as data in a separate file?" "3981": "Do you need to know in-depth linear algebra to do this?" "4002": "You mentioned your codebase is mostly independent for the most part: does that include random number generation or do you use the C library for that?" "4032": "How do you handle 3D audio in your other engines and games? OpenAL or you implement something yourself?" "4077": "The sky-light just has a gap at the top was all" "4094": "handmade_cutscene.cpp: Move the sky light a touch closer" "4114": "Have you talked further with Pat Wyatt about coming on the stream, or is that postponed for when networking becomes relevant? I thought his talk was very interesting in particular" "4151": "Is this code going to be for a cinematic in the game or are you just testing the functionality now?" "4163": "Should I use uint32_t over u32?" "4179": "What do you think about adding lighting effects to the cutscene, like a flickering or pulsing of the candlelight in the welcome sign?" "4218": "I meant the image format before we pack them in asset. I understand we're currently using BMP" "4257": "For adding more cutscenes or modding, wouldn't it make more sense to keep the parallax constants somewhere in the hha file?" "4318": "Don't you need to link to user32, gdi32 and opengl32 for a few things?" "4352": "If you're writing OpenGL stuff, do you use GLEW or write your own extension loader and load the function pointers yourself?" "4361": "You could make a 2D VR game, just room with a giant video wall" "4376": "Off-topic: Thank you for HandmadeCon, I have watched it twice already" "4382": "Not a question. Just wanted to thank you for doing HandmadeCon! And glad to see you back doing Handmade Hero" "4424": "Any plans for crude lighting and shadow support for things like lightposts?" "4455": "Will you show all content creation on stream too? Watching you spend hours doing cutscenes might not be fun" "4572": "Out of interest, if you wanted to implement a zoom that curved to the contours of the hill (forward, drop, forward), would you still look to implement that in code or look at a visual tool for something like that?" "4681": "Thanks for the stream, Casey" "4686": "Did you have to study algorithms in depth or did you learn from on-hand experience?" "4761": "Is VSYNC part of the renderer? At least on my end on the stream there is quite a bit of tearing. Not sure if that is the stream or not" "4860": "Have any of the responses to your questions at HandmadeCon affected your approach to certain problems?" "4908": "Was the snowman intentionally looking down to indicate a feeling of sadness, or am I reading too much into it?" "4986": "Has a programming problem ever stumped you? Even after googling and or collaboration?" "5095": "That's a good quote" "5106": "On using metrics to determine which implementation is the most appropriate for a given situation" "5201": "When you were an intermediate programmer how often is it that you used Google to help you look up solutions to hard problems? Or do you always try to first approach it yourself?" "5218": "It may be obvious but there is an entire class of programmers that seem to think otherwise" "5232": "Did you notice the triforce in the windows?" "5263": "One of my mentors used to say that there should be a book called "Algorithms, Data Structures, and Tradeoffs"" "5281": "Wrap things up" --- name: "day222" title: "Laying Out Cutscenes" markers: "32": "Recap yesterday's work on the cutscene" "88": "handmade_cutscene.cpp: Introduce struct layered_scene to hold all of the cutscene data" "195": "handmade_cutscene.cpp: Introduce RenderLayeredScene" "265": "handmade_cutscene.cpp: Define the layered_scene" "367": "On solving the problem and then generalising from that, i.e. compression oriented programming" "425": "handmade_cutscene.cpp: Clean up a few things" "478": "handmade_cutscene.cpp: Introduce scene_layer and scene_layer_flags" "692": "Run the game and see our scene" "718": "handmade_cutscene.h: Move in our structs from handmade_cutscene.cpp" "754": "handmade_cutscene.cpp: Setup to compose further shots" "848": "handmade_cutscene.cpp: Encode the Z-movement in CameraStart and CameraEnd" "963": "handmade_cutscene.cpp: Compose Shot 2" "1284": "Missing snowflakes..." "1350": "handmade_cutscene.cpp: Compose Shot 3" "1545": "handmade_cutscene.h: Add CounterCameraX and CounterCameraY to scene_layer_flags" "1637": "Compile and see that everything should change, apparently" "1675": "handmade_cutscene.cpp: Do the Z-case" "1694": "handmade_cutscene.cpp: Continue composing Shot 3" "2649": "handmade_cutscene.cpp: Compose Shot 4" "2839": "Missing children" "2951": "On misplacing children" "3052": "handmade_cutscene.h: Add MinTime and MaxTime to scene_layer and Transient to scene_layer_flags" "3104": "handmade_cutscene.cpp: Set Transient layers" "3217": "Watch the animated version" "3251": "handmade_cutscene.cpp: Compose Shot 5" "3311": "The money shot" "3481": ""That is video games"" "3523": "handmade_cutscene.cpp: Compose Shot 6" "3573": "When Krampus comes into the picture" "3921": "Q&A" "3952": "Why not pass how long each cutscene is instead of it being the same for all cutscenes?" "3986": "For the weird camera movement scene what do you think about interpolating against a curve instead of linearly?" "4028": "Yangtian's art is awesome!" "4060": "Please do more" "4086": "handmade_cutscene.cpp: Compose Shot 7" "4256": "handmade_cutscene.cpp: Compose Shot 8" "4561": "handmade_cutscene.h: Add v2 Param to scene_layer" "4651": "handmade_cutscene.cpp: Continue composing Shot 8" "4824": "handmade_cutscene.cpp: Compose Shot 9" "5104": "Do you enjoy the screaming of the linker lamenting and writhing in Sisyphean agony that he can't write to the .exe?" "5121": "Do you have someone lined up for voice acting?" "5151": "The first scene with a glove it was a left hand glove and the next it's a right hand glove" "5235": "The door was open in the first scene but closed before Krampus enters" "5265": "Way back on Shot 2 I noticed a gap at the top of the window. Is that still there?" "5317": "Can I adopt one of the children?" "5333": "Try the community for voice acting? Quite a few of us would be willing / have good mics" "5352": "Will this game have support for left handed people?" "5377": "Could you explain the fading for animation" "5385": "Sorry to put you on the spot, but we didn't have anything special on 200th day. Anything planned for 256th?" "5395": "What's the best way to get my repo blessed on GitHub? I know it's kinda random, but the current blessed Rust repo hasn't been updated in 3 months" "5411": "You should add a little bit of snow on that one, to add depth" "5465": "We still need our own trig functions so we can stop sin()'ing by using the C standard library" "5538": "You mentioned earlier that we could make the animation sequence smoother by fading. For example when Santa put a hat on the hero. I was wondering what that would look like" "5561": "I noticed the cutscene bitmaps don't scale with the window size. Why is that?" "5588": "win32_handmade.cpp: Temporarily switch to using a smaller backbuffer" "5668": "Floor and Ceil are difficult?" "5739": "Why do we want to redo sin()?" "5837": "Call it a night" --- name: "day223" title: "Playing Multiple Cutscenes" markers: "32": "Recap" "71": "handmade_cutscene.cpp: Compose Shot 10" "349": ""...he has a lot of hats"" "806": "handmade_cutscene.cpp: Compose Shot 11" "1907": "handmade_cutscene.cpp: Introduce IntroCutscene to make these shots play in a series" "2265": "handmade_cutscene.cpp: Bust out that emacs macro" "2342": "handmade_cutscene.cpp: Set the ShotChangeTime" "2402": "handmade_cutscene.h: Add Duration to layered_scene" "2512": "handmade_cutscene.cpp: Give RenderCutscene the ability to play all of the shots in sequence" "2718": "Run the game and see that the cutscene isn't actually going" "2774": "handmade_cutscene.cpp: Set &IntroCutscene index from ShotIndex" "2797": "Debugger: Step into RenderCutscene" "2857": "handmade_cutscene.cpp: Introduce b32 PrettyStupid to indicate the end of the cutscene" "2888": "Run the game and see our cutscene happening" "3056": "Q&A" "3074": "Will there be hat DLC?" "3105": "Wait for more Q's" "3109": "Do you prefer OpenGL or DirectX?" "3128": "Who draws all the pictures?" "3134": "I think there is still a tiny gap at the top of the window in shot 2, towards the very end of the shot" "3185": "handmade_cutscene.cpp: Tweak the position of the window in Shot 2" "3235": "Seems like the cutscene is nearly finished (for a first pass). Are we returning to debugging next?" "3250": "How do you compile so fast?" "3260": "Will there be sound effects in the intro scene (i.e. door opening sound effects)? Would this be separate or part of the voiceover?" "3284": "I'm starting out Game Development and know a good portion of C++, but trying to learn OpenGL or advanced graphics rendering libs is feeling too tedious to me. Any recommendations?" "3346": "Will the hat be in the cut scene after it's chosen?" "3376": "Excited for Vulkan?" "3386": "Could we just watch the cutscene on loop while we do Q&A?" "3409": "Know any good OpenGL tutorials?" "3444": "For that over the shoulder scene, what if you could give the boy a velocity as well, so that it partially exaggerated or countered the camera movement, giving him some actual movement?" "3479": "What do you have to say to the anti global variable zealots who would complain about all those globals in the cutscene code?" "3516": "I think the last shot still has clipping at the end (the hero's head)" "3578": "What's your favorite header file to include? The ones you will add when starting a project" "3626": "One day you mentioned the banding on the stream overlays and said that it would be really easy to fix. How would you fix it?" "3682": "Who is your ideal 'voice of Krampus'?" "3694": "Do the hats bestow magical powers upon you?" "3702": "I asked this during the pre-stream, but not sure if you caught it. Still catching up with the series, but have you written a better hash after the sim region episodes?" "3727": "Off-topic - How much planning for a large (longer than one year) software project do you do before you start the project? How do you estimate the time it takes to get the work done?" "3779": "When is Vulkan coming out? Why do you not like Vulkan?" "3787": "Are you familiar with FreeGLUT? Thoughts on that specifically" "3800": "I'm trying to go as independent as I can in my codebase as well. One thing that I'm not sure how to replace is GLEW, i.e. how to load the OpenGL functions myself. You mentioned you had your own library for that. Any tips / advice how to write / where to begin?" "3847": "What Did Krampus do with other children after he gifted that hand to our hero? What was the purpose of his visit?" "3859": "Do you at least include windows?" "3869": "There's a glitch in the graphic near the cockroach's antenna in the hats plane" "3926": "I have a feeling the clip plane might have been introduced when we were doing the multiple ground layers" "3978": "Maybe on Day 107: Fading Z Layers" "4011": "Krampus sounds so cool. How did you come up with the name?" "4069": "Does Krampus return to 0?" "4115": "Thank you, Casey" "4138": "Will you be doing Ludum Dare this weekend?" "4208": "Sometimes the transition from scene to scene is not perfect. Are you going to fix that?" "4387": "Windows Task Manager: Check our memory usage" "4517": "Windows Task Manager: Check our CPU usage" "4689": "Why make the CPU do it?" "4814": "Cockroach confirmed for familiar DLC?" "4820": "Is there some interface to use for using the GPU?" "4830": "Is this the most in depth game you've created (i.e cut scenes, game engine and so on)?" "4844": "NearClipPlane was introduced on Day 108: Perspective Projection (thanks to insofaras's git-fu)" "4854": "Isn't GLSL and the DirectX shader language good for this?" "4879": "Would it be possible to access the GPU without a driver?" "4947": "Moving graphics on-screen, get the CPU to do other calculations" "5040": "Don't mean to cramp your style. I made some stuff BitBlting too" "5093": "And gamma correction!" "5122": "Does bi-linear filtering hold up in 3D?" "5179": "Handmade cut scene screensaver for Christmas?" "5199": "Yeah, as far as I can tell, you set the NearClipPlane pretty darn arbitrarily" "5220": "Call it day" --- name: "day224" title: "Prefetching Cutscene Layers" markers: "84": "Recap, run the game and point out an objectionable artifact" "194": "Debugger: Step into RenderCutScene and note the unset State of the Asset" "372": "handmade.cpp: Play the cutscene back at an artificially fast rate" "409": "handmade_cutscene.cpp: Introduce RenderCutsceneAtTime" "565": "handmade_cutscene.cpp: Do an additional RenderCutsceneAtTime in RenderCutscene, passing 0 as the RenderGroup in order to do a PrefetchBitmap" "709": "Run the cutscene and see how it works" "744": "Do you guys know why there's [a glitch] on the beginning one?" "803": "handmade_cutscene.cpp: Create an initial black Shot lasting 20 (artificially accelerated) seconds" "860": ""n{un,one}?"" "928": "Run the cutscene and see the delay" "977": "handmade.cpp: Play the cutscene back at the natural rate" "1040": "win32_handmade.cpp: ToggleFullscreen on and watch the result" "1104": "handmade_cutscene.cpp: #define CUTSCENE_WARMUP_SECONDS" "1135": "win32_handmade.cpp: Issue a Clear if the LayerCount == 0" "1211": "win32_handmade.cpp: Figure out why the flicker is happening" "1285": "Internet: VirtualAlloc" "1392": "Debugger: Step into Win32ResizeDIBSection and inspect Buffer->Memory" "1430": "Internet: GetStockObject function" "1557": "win32_handmade.cpp: Draw the window background with GetStockObject(BLACK_BRUSH)" "1572": "Run the cut scene and see that the startup experience is pretty nice" "1603": "win32_handmade.cpp: Create the window without it being visible" "1659": "Consider possible directions" "1808": "handmade.cpp: Toggle back to the game and illustrate the concept of the game getting started" "1941": "handmade.h: Provide the ability to switch between the cutscene and the game" "2009": "Run the game, join it and note the need to prefetch the game assets" "2074": "handmade.cpp: Introduce DeleteLowEntity to be called upon pressing Esc" "2288": "Run the game and try killing the hero" "2326": "handmade.cpp and handmade_platform.h: Provide the ability to exit the game" "2538": "Run the game and try exiting it" "2555": "handmade.cpp: Check to see if the Esc key WasPressed" "2624": "Run the game and test the exiting" "2639": "handmade_cutscene.h: Introduce struct playing_cutscene to formalise what the cutscene is doing" "2742": "handmade_cutscene.cpp: Introduce MakeIntroCutscene" "2837": "handmade_cutscene.cpp: Pass in the CutScene to RenderCutscene" "2961": "handmade.h: Initialise CurrentCutscene" "3056": "handmade_cutscene.cpp: Note that the cutscene will no longer be hot reloadable" "3119": "handmade_cutscene.cpp: AdvanceCutscene to allow multiple cutscenes" "3149": "Run the game, test our new functionality and consider making the cutscenes reset" "3280": "Q&A" "3317": "Would adding a BlockUntilLoaded style function be a good idea to make sure even slower computers have all layers loaded before the scene starts?" "3354": "handmade_cutscene.cpp: Turn off the prefetches" "3427": "handmade.cpp: Check for AllResourcesPresent before doing TiledRenderGroupToOutput" "3528": "Isn't there a way to clear the back buffer using SIMD?" "3561": "Will there be any animated cutscenes or just zooming shots?" "3579": "Can you do a cloc?" "3605": "Would it be possible to fade from the desktop to the game's initial black screen? Failing that, I think it'd be cool if we fade into the cut scene from the black, and then back to black when we quit the game" "3702": "win32_handmade.cpp: Introduce FadeOut" "3870": "Internet: UpdateLayeredWindow" "4615": "Shut it down" --- name: "day225" title: "Fading In and Out from the Windows Desktop" markers: "75": "Recap our current situation" "105": "Internet: SetLayeredWindowAttributes" "176": "win32_handmade.cpp: Create a fullscreen window that's transparent but black, and gradually increase its opacity" "301": "Run the game and see the fade-out" "315": "win32_handmade.cpp: Make the fade-out routine something that can be called incrementally" "564": "Run the game and see that nothing happens" "587": "win32_handmade.cpp: Defer calling ShowWindow until FadeAlpha is 1.0f" "838": "win32_handmade.cpp: Enable the timing loop" "853": "Run the game and see a slight flicker on the transition" "964": "Debugger: Step into ShowWindow" "1115": "win32_handmade.cpp: Try doing ToggleFullscreen after showing it, then try and force a repaint" "1239": "win32_handmade.cpp: Set WindowsAlpha = 255 and test if(IsWindowVisible)" "1652": "Debugger: Break into ShowWindow in SetFadeAlpha and see it's not getting called" "1703": "Spy++: Look at the Window Styles" "1868": "win32_handmade.cpp: Correct the FadingComplete / ShowingComplete tests" "1903": "Run the game and see that we don't have our glitch" "1955": "win32_handmade.cpp: Introduce dFadeAlpha to fade back to the desktop" "2295": "win32_handmade.h: Introduce win32_fader_state and win32_fader" "2437": "win32_handmade.cpp: Introduce UpdateFade" "2483": "win32_handmade.cpp: Make a little finite state machine for the fades" "2665": "win32_handmade.cpp: Briefly describe the finite state machine" "2705": "win32_handmade.h: Add Win32Fade_FadingGame to win32_fader_state" "2806": "win32_handmade.cpp: Introduce InitFader, BeginFadein and BeginFadeOut" "3217": "win32_handmade.cpp: Only do BeginFadeToDesktop if Win32Fade_Inactive" "3268": "Run the game and see that we're working properly" "3299": "Q&A" "3344": "Casey, you need one more state to wait for alpha-enabled window to show, because you might have the same bug when you fade to desktop" "3445": "Your fading setup seems overcomplicated to me. Why not just take a screenshot, blit that to the back buffer, and fade that? What platforms wouldn't that work for?" "3626": "Why are you using a second window for the fade in, instead of just fading in the main window?" "3726": "Wow, thank you for such a comprehensive A: to my Q:. That's exactly what I wanted! Another small one: Would it be possible to make bits of the window transparent, e.g. for the situation where some monstar has torn a hole in the game window, revealing the desktop beneath?" "3811": "Suppose you're Microsoft, but instead of wanting all of the money in the world you just want to make a living selling your OS. Do you think you could do that while providing a good way for users of your platform to debug the code that uses your API?" "3917": "Can you not unset the layered window flag after doing the fade?" "4035": "Wait, why can I Alt-PrintScreen to capture HDCP with windows but I can't take a screencap manually? I have lots of screenshots of my PS3 through the player via prntscrnt" "4133": "So this detour was all about startup and shutdown fades, but how would you implement fading in between in-game scenes? This shouldn't involve the Windows API, correct?" "4165": "handmade_cutscene.h: Add tFadeIn to layered_scene" "4235": "handmade_cutscene.cpp: Implement fade to black between cutscene shots" "4376": "Run the game and see that fade" "4407": "Note that the alpha must be gamma corrected" "4601": "We are out of time" --- name: "day226" title: "Handling Multiple Metagame Modes" markers: "3": "Intro, plans" "79": "Description of the 'meta-game' elements that Handmade Hero needs" "294": "Setting up, compiling and running the current state of the game" "381": "Choosing the first programming task for today" "450": "Reviewing the cut-scene code" "696": "Adding the concept of game modes" "872": "Adding a union to game_state to hold individual state for each game mode" "1014": "Changing UpdateAndRenderGame to dispatch to other functions based on the current game mode" "1293": "Modifying the cut-scene code to use the new game mode concept" "1537": "Begin implementing the switching between game modes" "1647": "Changing the WorldArena in the game_state to ModeArena, to be used by all game modes" "1774": "Determining how parameters will be passed to game modes when switching between them" "1863": "Letting the caller of SetGameMode do the initialization of the new mode, to avoid having to pass unnecessary parameters" "2020": "Creating an arena in the World struct, for exclusive use by the main World game mode, instead of having it use the arena in the game_state struct" "2146": "Exposing the SetGameMode function, and updating PlayIntroCutscene and PlayTitleScreen to use the ModeArena" "2178": "Making world based functions use the new world-specific arena" "2241": "Finish implementing the game mode switch statement in UpdateAndRenderGame" "2314": "Adding initialization code for the world-specific arena" "2466": "Re-organising the main World game code to be in functions specific to the new World game mode" "2641": "Running the game to see how the new code is working" "2702": "Separating out the persistent elements of game_state from those specific to the World game mode" "2903": "Moving things around to more appropriate files and to appease the compiler" "3239": "Changing many world-specific functions to work with a game_mode_world struct instead of the game_state struct" "3706": "Adjusting the creation of memory arenas in the initialization code" "3914": "Fixing the remaining compile errors" "4001": "Out of time, running the game with the world mode currently inaccessible until the cleanup work is completed at a later date" "4028": "Q&A" "4087": "How do the memory areas work?" "4111": "Well since no one's asking, have you heard about AMD open sourcing a lot of their GPU stuff?" "4188": "Should the world mode changing be prefetched like the cut-scenes changing?" "4221": "So by 'meta-game' do you mean like the pre-game stuff?" "4231": "Hi! I just finished my first semester of computer science in school! Just learned some basic Java, but I was wondering on if you have any tips moving forward. Also, do you know of any colleges that have good computer science departments?" "4278": "Sorry slow night, the chat erupted into a flame war over the exclusion of option menus in games :-P" "4296": "I wonder if there's a specific reason you put the 3 game_mode structs into a union?" "4308": "So I have this generic USB controller that's not being detected by XInput, any ideas how to go about detecting it? Use DirectInput? Or try to use an Xbox controller emulator or something?" "4373": "Wrap up" --- name: "day227" title: "Switching Between Metagame Modes" markers: "7": "Intro" "102": "Plans for today" "160": "Looking back at what was achieved yesterday" "204": "Taking a detour to fix the zooming in a shot of the opening cut-scene" "439": "Restating how the mode switching should work" "568": "Final tweaks to the zooming" "676": "Adding input handling to the cut-scene and title-screen game modes" "1098": "Adding a loop to the game mode dispatch, to allow updating/rendering to be re-ran immediately by the new mode, if a mode switch occurs" "1222": "Moving original input handling code into the world game mode" "1275": "Fixing resulting compile errors and header file include order" "1468": "Making the world game mode switch back to the cut-scene mode when no heroes exist" "1578": "Debugging the new code" "1665": "Thinking about how the new mode switching code might interact with multi-threading" "1761": "Changing how the world is initialized" "1898": "Debugging why the world doesn't appear to fit in the arena" "2061": "Fixing the world game mode immediately exiting back to the cut-scene" "2243": "Running the game. It can now enter the game mode but there are still a few bugs remaining" "2297": "Fixing inability to move by re-enabling code that was #if 0'd yesterday" "2433": "Fixing the lack of camera following by making sure the arena is zero-initialized" "2658": "Running the game again with the bugs fixed" "2687": "Commenting on the previously mentioned potential threading issues with the mode switching" "2908": "Implementing a basic version of the title-screen" "3180": "Testing the title-screen code" "3224": "Quickly debugging and fixing a cut-scene crash related to mode switching" "3329": "Game running with all 3 game modes working as intended" "3400": "Q&A" "3417": "Could you leverage your debug code when trying to find the right values you want for the intro cutscene in realtime instead of recompiling?" "3440": "Add some credits and boom! We're done!" "3457": "How do you terminate or end each thread at the end?" "3475": "What are your thoughts on twitch asking you to switch labels to creative?" "3517": "Will we be reimplementing the profiler?" "3538": "The end of the executable" "3599": "Could you re-explain why you couldn't move the hero after cutscenes for a while?" "3616": "If someone wants to run your game in fullscreen but at a different resolution than native, how would they change it? You've said before you don't like menus, so would you use a launcher instead or something for those options?" "3795": "Could you do some resolution detection at startup to avoid starting at a broken resolution?" "3886": "You say "normal person" as if tech savvy people is something awful." "4024": "Talking more about resolution / 4K" "4124": "Do you generally do cutscene code before gameplay code when you're working on a game?" "4352": "Are we in a point where we're close to have to need to implement mixins?" "4373": "Will c++17 modules solve the #include dependency problem?" "4551": "Wrap up, episode guide info" --- name: "day228" title: "Waiting for Dependent Tasks on Metagame Mode Changes" markers: "13": "Gift Received in the Mail: Owl of Shame Baby" "126": "Recap and set the stage for the day" "314": "Describe a threading bug in tasks which access the game's mode state and which persist" "473": "Set out our choices for fixing this bug" "683": "handmade.h: Add b32 DependsOnGameMode to task_with_memory" "810": "handmade.cpp: Add Platform.CompleteAllWork and NeedToWait to SetGameMode" "1210": "Run the game and see that it does work right" "1233": "handmade_world_mode.cpp: Call PlayTitleScreen upon exiting from the game" "1263": "Debugger: Note that we may now be clearing a large block of memory to zero, run the game and use Debug->Break All to confirm that" "1386": "handmade.h: Introduce struct arena_push_params and inline arena_push_params in order to specify to the Push routines whether or not to clear to zero" "1634": "handmade.h: Introduce AlignNoClear and Align" "1791": "Propagate our new features to all of the Push calls that require it" "2138": "handmade.h: Introduce NoClear and finish writing these new functions" "2248": "Run the game and see that it runs much more snappily" "2281": "Consider making the memory arenas flow all the way down to the operating system level, making the debug system use a separate set of growable memory, and fixing the renderer's sorting" "2460": "handmade_render_group.cpp: Take a look at how the renderer currently works" "2612": "handmade_render_group.cpp: Consider removing the notion of the scanlines" "2661": "build.bat: Turn on HANDMADE_INTERNAL" "2697": "Run the game and watch our last frame time" "2776": "handmade_render_group.cpp: Remove the Even / Odd notion" "2869": "Run the game and enjoy our beautiful rendering" "2892": "handmade_optimized.cpp: Increment the Y counter by 1 rather than 2" "2953": "Run the game and see that we may have got a little faster" "2992": "handmade_render_group.cpp: Consider providing some way of knowing what we're sorting" "3191": "handmade_render_group.h: Add PushBufferElementCount to render_group to let us know how many elements have been pushed" "3327": "handmade_render_group.cpp: Introduce struct tile_sort_entry and use it in RenderGroupToOutput" "3655": "Run the game and see that it still works fine" "3691": "Q&A" "3726": "Could you tell us roughly how the expanding arena would be implemented?" "3777": "Is the lower level memory arena thing you mentioned for PC basically just what malloc / VirtualAlloc does?" "3805": "I got the K & R book to learn C. Any other useful resources? I take online stuff with a grain of salt" "3816": "Is interlaced the same as interleaved?" "3873": "What should I do with my life while Handmade Hero is on break?" "3906": "Which algorithm do you plan on using for sorting?" "3943": "Why are we running in a windows application (using WinMain) instead of a console one (using regular main(int, char**)), and still RegisterClass, CreateWindow, etc?" "3995": "Why was the interleaving added in the first place?" "4021": "How many TODOs are there in the code now?" "4049": "Is there much overhead to spawning the render threads every frame instead of keeping them around" "4065": "Do you always start with software rendering when working on games?" "4107": "For new year's can we get a marathon?" "4113": "Can you do really smooth animation in GDI, without vsync?" "4156": "Simple question, but how do you forward declare a struct in pure C? If I have "typedef struct foo {...} foo;" how do I forward declare this? I tried typedef struct foo foo; but it didn't work" "4189": "Do you have any optimization for not blending transparent pixels?" "4278": "Once you have sorting implemented, do you think you will change the renderer to draw front to back?" "4300": "Thanks, I was just curious in my console question. But sometimes I write utils that I would like to live in the background and not be visible on the screen, so I use a Windows application and hide the window. Is there any way to use a console instead and hide that (from taskmgr, etc.)?" "4328": "Can you give a quick overview of the way memory is managed at the moment? PushArena / BeginTempArena, etc?" "4366": "Blackboard: Memory Arenas" "4461": "Are you still using .bat file compilations?" "4485": "Wrap it up" --- name: "day229" title: "Sorting Render Elements" markers: "25": "Recap and set the stage for the day" "88": "Run the game and hit an assertion" "153": "handmade_world_mode.cpp: Turn off FillGroundChunk" "187": "Run the game and note the lack of sprite sorting" "274": "handmade_world_mode.cpp: Turn FillGroundChunk back on and note that we need some room in which to do the sorting" "329": "Debugger: Step into AllocateRenderGroup" "405": "handmade.cpp: Increase the amount of memory allocated to this TranState" "424": "Debugger: Step into BeginRender and inspect Work->Task->Arena" "483": "handmade_world_mode.cpp: Make RenderGroup use 512KB" "639": "Blackboard: Render Sorting" "836": "Blackboard: Sort buffer" "912": "Blackboard: Producing the sort key" "1141": ""For the love of god, Mischief"" "1203": "handmade_render_group.cpp: Consider how to sort" "1329": "handmade_render_group.cpp: Find the PushBufferOffset for each Entry in RenderGroupToOutput, and make the function take SortEntryCount and *SortEntries" "1529": "Blackboard: How we're currently rendering the screen" "1585": "Consider how best to do this sort" "1717": "handmade_render_group.h: Add u32 SortEntryAt to render_group" "1743": "handmade_render_group.cpp: Set that SortEntryAt in AllocateRenderGroup and use it in PushRenderElement_" "1816": "Blackboard: Pushing entries on from the top and sorts on from the bottom" "1857": "handmade_render_group.cpp: Implement these pushes, and make PushRenderElement_ take r32 SortKey" "1991": "handmade_render_group.cpp: Clean up compile errors and propagate the SortKey" "2319": "Run the game and see that it isn't quite right" "2380": "handmade_render_group.cpp: Reverse the sorting order" "2409": "Run the game and see that it is now correct" "2420": "Blackboard: The Clear was happening last, after rendering everything" "2465": "handmade_render_group.cpp: Introduce SortEntries" "2593": "Blackboard: Bubble Sort" "2856": "handmade_render_group.cpp: Implement SortEntries as a Bubble Sort" "3047": "Run the game and see that it might actually be right" "3111": "handmade_world_mode.cpp: Give the GroundBuffer some zBias" "3168": "handmade_world_mode.cpp: Turn off the GroundBuffer for now" "3188": "Run the game and see that the sorting is working properly" "3239": "handmade_world_mode.cpp: Increase the zBias and then apply the bias in the correct place" "3360": "Run the game and see that it all works correctly now (apart from the torso being in front all the time)" "3388": "Q&A" "3440": "Do you know the Vulkan release date?" "3476": "Well?" "3489": "Can you talk about pros and cons of heapsort and quicksort, and / or explain quaternions?" "3543": "Which sort are you planning to ultimately replace bubble sort with?" "3599": "Bubble Sort is the simplest sort? I worked my way to doing a Selection Sort in my practices, so assume that must be down there for simplicity" "3641": "n^2 is actually faster in most cases?" "3741": "Can't you just use binary insertion to put items into their correct position so the array is sorted the whole time? That way RenderGroupToOutput doesn't have to do anything" "3775": "Blackboard: Sorting After vs Sorting During" "3931": "Have you ever made something of this sort of a project before? When you stream, do you just do everything as you go, sort of "improv" coding, or do you do stuff off stream to prepare what you are actually going to code on stream?" "4027": "Are we going raid Shawn McGrath's stream tomorrow night after this one?" "4051": "How do you disable syntax highlight in Emacs while keeping comment and macro highlighted?" "4130": "Is your Visual Studio "custom" theme anywhere? I really like it" "4194": "Wrap it up" "4280": "Shout out to HandmadeDev, who are building a community site for projects like Handmade Hero, with nicer forums" --- name: "day230" title: "Refining Renderer Sort Keys" markers: "7": "Recap and set the stage for the day" "85": "Blackboard: Sort Key for Rendering" "366": "Blackboard: Treating Z purely semantically" "600": "handmade_world_mode.cpp: Disable the GroundBuffer, run the game and demo the situation with rendering entities on stairwells" "806": "Blackboard: On rendering entities on stairwells" "1062": "Unexpectedly hit an InvalidCodePath" "1123": "Debugger: Realise that we never reset SortEntryAt" "1154": "handmade_render_group: Introduce ClearRenderValues" "1427": "Run the game and watch the last frame time" "1498": "handmade_render_group.cpp: Consider how best to generate the SortKey" "1635": "handmade_render_group.h: Add b32 Upright to render_transform" "1686": ""Move this out to its own thang"" "1721": "handmade_render_group.cpp: Use Upright in the SortKey computation" "1828": "handmade_world_mode.cpp: Set the GroupBuffer to not be Upright" "1861": "Run the game and note that we don't leave a hole for the stairwells" "1948": "Try getting the stairwell thing working a little bit" "2028": "Run the game and note some rendering problems" "2098": "handmade_world_mode.cpp: Give the GroundBuffer some Z" "2187": "Run the game and find that the topmost GroundChunk now occludes everything, as expected" "2232": "handmade_world_mode.cpp: Get FadeTopStart to happen again" "2319": "Run the game and see that everything seems to be rendering properly" "2395": "Note that we're drawing the entire screen many times" "2488": "win32_handmade.cpp: Drop down the resolution to 960x540" "2588": "handmade_render_group.h: Separate the transform data into object_transform and camera_transform" "2718": "handmade_render_group.h: Introduce DefaultUprightTransform and DefaultFlatTransform" "2819": "handmade_render_group.cpp and handmade_debug.cpp: Propagate these changes" "3591": "Run the game and find that everything is exactly the same" "3644": "Q&A" "3685": "Brace yourself" "3713": "What is your preferred sorting method?" "3813": "Hi Casey. I'm currently working on an OpenGL framework for games. Wanted to ask whether I can use the code up to Day 023 (Live Code Editing), with the intend of making a commercial game eventually with it. Might be important to note that I'm also streaming, so the code might be visible sometimes when I stream framework development" "3838": "I know you said you really like discriminated unions, but how do you deal with managing the big case switch they may cause? That is usually handled by the OOP model by delegating to the object" "3936": "Demo: Switch statement vs dispatch" "4122": "Obviously we lost some performance over the last couple streams. Are you planning to try to optimize it back down, or just leave the software renderer as is and move into GPU rendering?" "4174": "A lot of the times when you develop something, you write it in the simplest way that just works, then you polish it to something good and more finished (e.g. what you did with dsound). For someone catching up, do you think it's good enough to just study and focus on that better version, or is there a value in writing that initial version ourselves?" "4247": "Hey Casey! I just found your series and was amazed that you are creating an entire game without using an external library like SDL (from what your episode one said, at least). I really wanted to watch your progress through the series but I have no Idea where to start in the 200+ episodes since I already am working on an SDL OpenGL game. What is your suggestion?" "4309": "I can't remember if you discussed this when it first cropped up but, when you are halfway up the stairs and blending the trees, you get a darker area where they overlap. What's the "fix" for that?" "4338": "Blackboard: On the need for compositing in order to fade" "4410": "Is std::qsort worth using compared to rolling your own?" "4464": "How do / would you deal with collisions between multiple entities in terms of collision resolution, not detection, like deciding how to resolve conflicts between multiple moving things? I kinda hit a wall there not seeing solutions that aren't very ugly (especially movement-order dependency)" "4588": "You said the scaling value is not used, but the camera transforms everything. What is the difference?" "4664": "What keyboard are you using these days? I know you're a connoisseur, so I'd love to hear a recommendation" "4706": "How would a front-to-back renderer actually work? Would it test every pixel before writing to it?" "4797": "Does multiple dispatch come up for you much (as in n types with n^2 branches)? How do you handle it when it does?" "4890": "Would you rather have an explicit fall-through statement with implicit break, instead of standard switch-statements? Seems much cleaner to me, or am I missing something?" "4961": "That's what I was afraid of but thought maybe you had some trick like a messed up precomputed alpha" "4997": "I know we just got over the holiday break, but will there be a break in Handmade Hero when The Witness launches? If it's a possibility, it might be better to ask the community if they want that" "5016": "Are you productive / feel good at programming no matter how many hours you work per week?" "5081": "Close up shop and glimpse into the future" --- name: "day231" title: "Order Notation" markers: "63": "Set the stage for the day" "177": "Blackboard: Order Notation" "253": "Blackboard: "unit"" "350": "Blackboard: Linear "scale", e.g. stamping envelopes" "519": "Blackboard: Nonlinear "scale", e.g. checking if any envelopes are addressed to the same person" "842": "Blackboard: Why we care about linearity" "957": "Blackboard: How this determines scalability" "1080": "Blackboard: Why we don't care about the constant when considering an algorithm's scalability" "1282": "Blackboard: How this translates into code" "1417": "Blackboard: Big O notation indicates "worst-case running time"" "1609": "Blackboard: "randomized algorithms"" "1714": "Blackboard: P (polynomial) vs NP (nondeterministic polynomial)" "2150": "Blackboard: On classifying problems as P or NP, e.g. "Boolean satisfiability problem"" "2445": "Blackboard: "NP-completeness"" "2712": "Blackboard: *Gotcha! e.g. "Travelling Salesman Problem"" "3134": "Blackboard: Sorting" "3219": "handmade_render_group.cpp: Note that the current SortEntries function is O(n^2)" "3242": "Blackboard: Why SortEntries is O(n^2)" "3317": "Blackboard: On how to make sorting not be O(n^2)" "3395": "Blackboard: Walk through our current (Bubble sort) algorithm" "3493": "Blackboard: Walk through a "divide and conquer" (Merge sort) algorithm" "3870": "Blackboard: Compare these two algorithms" "4028": "Blackboard: Divide and conquer algorithms are O(n log n)" "4115": "Blackboard: Solidify the concept of the merge sort algorithm and "dynamic programming"" "4468": "Q&A" "4496": "NP stands for Nondeterministic Polynomial. Plus some other minor problems. Otherwise, well done" "4599": "For the record the remark I made earlier about Rust was not serious. Also, isn't mergesort n*log(n)?" "4628": "So unit testing a function that computes a path for the traveling salesman problem would require writing the algorithm twice, the second one testing the first?" "4684": "Do you think a computer science major is a good path to go? I'm in it now" "4745": "You say "exponential"" "4748": "To say that a problem is not solvable in polynomial time, you just say "The problem is not in P"" "4872": "Has anyone definitively proven that Travelling Salesman could not be in P, or is that still potentially NP-hard?" "4964": "TSP is NP-complete, so it is also in NP, so it DOES have a polynomial verifier" "4992": "Have they proven that it doesn't have a P verifier?" "5133": "Well it depends which TSP problem we are actually talking about" "5204": "Wouldn't saying that something is "NINPY" imply that P != NP? (Did we win a $1M prize?)" "5225": "Blackboard: "in P" / "not in P" vs "NP-complete"" "5442": "Idea: The game should include a traveling salesman, who ponders these things..." "5454": "Will we go into more complex sort algorithms like radix sort? Also, is the space requirement of mergesort something that needs to be take into consideration for Handmade Hero?" "5505": "Since you didn't go to college, when did you first get interested in or at least start learning all about big O?" "5605": "I'm not sure we can prove something is not in P unless it is undecidable or we can prove P != NP" "5634": "By the way, 8^2 doesn't equal 16" "5851": "I shall dig through my copy of Computers and Intractability by Gary and Johnson tonight" "5861": "Hmm, first sentence contains the word whimsical so it's looking good so far" "5889": "Wrap up with a recap" --- name: "day232" title: "Examples of Sorting Algorithms" markers: "8": "Share a link from yesterday's chat" "114": "Blackboard: Problem "difficulty" scale" "779": "Blackboard: Travelling Salesman Problem" "1357": "Thank Longboolean for the link" "1457": "Blackboard: Sorting" "1493": "handmade_render_group.cpp: Note that the current SortEntries function is O(n^2)" "1517": "Blackboard: Reiterate why we don't care about adding the n in Order Notation" "1616": "Blackboard: Scaling only matters if you actually scale!" "1795": "Debugger: Break into SortEntries and inspect the Count" "1839": "Blackboard: The relevance of scale" "1977": "Blackboard: "Worse case"" "2094": "Blackboard: Why the default sort in the CRT is quicksort" "2236": "Blackboard: More sorts" "2393": "Blackboard: The expected running times for these sorts in the worst case" "2471": "Blackboard: Quick sort" "2928": "Blackboard: Picking your pivots" "3045": "Blackboard: Using randomness to potentially improve the running time of algorithms" "3141": "Blackboard: Radix sort" "3463": "Blackboard: (Pseudo) Insertion sort" "3634": "Q&A" "3688": "So why would you not always do radix sort with a sort(sizeof(), data_)?" "3706": "Blackboard: On using the most appropriate sorting algorithm for the dataset" "4332": "Any news on potential Pat Wyatt guest stream to go more in-depth with the network stuff?" "4337": "Did you mention sort stability at all?" "4350": "Blackboard: Sort stability" "4654": "What else, if anything, do you think we'll need to sort besides the sprites?" "4671": "Could we possibly generate / hint the ground chunks in such a way that using radix sort would be more optimal?" "4692": "Yes, it is proven, I'm pretty sure" "4736": "Is shell sort basically bubble sort with a variable span between values being compared (span decreases each run through)?" "4746": "Blackboard: "Shell sort"" "4858": "Is this cross-platform yet?" "4906": "Would something like a pivot table be a sort problem, or something else altogether? Is that more a sort / amalgamation / summarization?" "4924": "Off-topic: Which more do you like, the fixed-function API of OpenGL or the programmable one? I've been using the modern approach but reading examples from the fixed pipeline they seem to be a lot more intuitive and easier to understand the flow of things" "4957": "So by your description, is a stable sort resource intensive? Since it seems like it could be of max O(n^2*nlogn) depending on sort type? Since you have to run through the data twice?" "5051": "When will you stop teasing us with the interactive fiction posts and get to the details?" "5060": "Will you leave in some bugs for speedrunners to break the game with?" "5089": "With a sort, is this actually adjusting and rewriting the data on the disk, or would it just be updating indexes or pointers? Just, once you sort, could you read start to finish, or is it pointer intensive: read 10 records, jump, read next 5, jump, read 2 more?" "5144": "I mean, how you actually went about solving the problems, it seems so close for weeks, then... cliffhanger" "5221": "I read a post the other day that said syntax coloring is bad for programming practices and enforces skimming rather then understanding. Do you agree or not?" "5279": "Now I know that I have to buy a game to find out, that's fine. Thank you" "5354": "Wind down" --- name: "day233" title: "Can We Merge Sort In Place?" markers: "72": "handmade_render_group.cpp: Note that the current SortEntries function is O(n^2), and introduce an early-out condition" "188": "Introducing this condition changes the "expected running time" from O(n^2) to something less" "237": "handmade_render_group.cpp: Introduce MergeSort" "538": "Blackboard: Can we Merge Sort in place?" "862": "handmade_render_group.cpp: Introduce a validator for the sorting functions" "930": "Debugger: Run the game and hit that assertion, before correcting the test" "978": "handmade_render_group.cpp: Continue working on MergeSort, interleaving the tests" "1405": "Blackboard: Draw out the scenario" "1444": "handmade_render_group.cpp: Introduce Half0StackCount and write out all the cases explicitly" "1606": "Blackboard: Walk through the problem" "1696": "handmade_render_group.cpp: Introduce Swap" "1808": "handmade_render_group.cpp: Step 1 - Find the first out-of-order pair" "1899": "Blackboard: The two phases of this merge sort algorithm" "1916": "handmade_render_group.cpp: Label the steps" "2054": "Blackboard: Walk through the next phase" "2154": "handmade_render_group.cpp: Step 2 - Swap as many items as necessary" "2426": "Blackboard: Draw out the current situation" "2633": "handmade_render_group.cpp: Step 3 - Swap back as many swapped half0 items as necessary" "3097": "Blackboard: Rearranging the entries" "3320": "Blackboard: Consider how to swap the order of these blocks" "3562": "Blackboard: Consider the two cases" "3705": "Blackboard: Walk through what happens" "3966": "handmade_render_group.cpp: Just set ReadHalf1 = InHalf1" "4008": "Blackboard: Construct a case and see what happens" "4243": "Blackboard: On the apparent need to store those back pointers" "4395": "handmade_render_group.cpp: Make MergeSort take some temporary storage and rewrite SortEntries to use that storage" "4769": "Debugger: Hit an assertion before fixing the test and seeing that the sort is correct" "5029": "Q&A" "5049": "I didn't look this up so it might not work, but came up with: whenever an element from the upper half is chosen, put it in place in the lower half, shift the upper half down to fill the space that the chosen element used to take up, and store the non-chosen element from the lower half in the new space at the end of the upper half, setting the lower half's read pointer to that end bit. Thoughts?" "5108": "Off-topic, but I made a post about the 2^(2^n)) arguments for TSP on the forums, if you're interested" "5119": "Could you post the bit of rotation math in the pre-stream in the Youtube Channel?" "5138": "One of the variants in the Wikipedia article claims only one slot + O(1) extra pointers, required." "5282": "Wrap it up" --- name: "day234" title: "Implementing Radix Sort" markers: "47": "Recap and set the stage for the day" "82": "handmade_render_group.cpp: Pull out the BubbleSort functionality into its own function" "160": "Struggle with the headphone cable" "229": ""I'm still being oppressed by The Cable Man"" "235": "Blackboard: Radix sort" "282": "Blackboard: "Stable sort"" "594": "Blackboard: "Some number of successive stable sorts on some part of the sort key"" "1324": "Blackboard: 8-bits" "1364": "Blackboard: How radix sort works" "1654": "handmade_render_group.cpp: Introduce RadixSort" "2362": "handmade_render_group.cpp: Introduce SortKeyToU32" "2383": "Run the game and hit an assertion" "2404": "Debugger: Step through RadixSort and inspect Dest, First and Temp" "2457": "Blackboard: 32-bit IEEE float" "2737": "Debugger: Step into SortEntries and inspect Entries" "2945": "handmade_render_group.cpp: Cast to SortKey to u32" "2965": "Debugger: Inspect the casted Entries" "3090": "handmade_render_group.cpp: Consider inverting the meaning of the bits" "3135": "Blackboard: On flipping the bits" "3183": "handmade_render_group.cpp: Set Result = Result in SortKeyToU32" "3225": "Debugger: Step into SortKeyToU32 and inspect Result" "3339": "handmade_render_group.cpp: Feed some basic values to SortEntries and inspect them" "3641": "Baby Owl of Shame Moment: We need to iterate on the ByteIndex in eights" "3693": "Run the game and see that it works now" "3746": "Q&A" "3774": "Why didn't you build merge sort from the bottom up? It makes ping-ponging the buffers much easier" "3836": "Your radix sort looks like it's O(8n) because you're doing two passes over the list per byte. Couldn't you make it O(5n) by getting all the offsets / counts in one pass at the cost of 3 more 256 element arrays?" "3979": "Off-topic: I'm a bit confused about axis-angle rotations vs quaternion rotations. I thought quaternions do represent an angle and axis of rotation. What's the difference?" "4025": "Blackboard: "Euler angles"" "4109": "Blackboard: "axis / angle"" "4152": "Blackboard: "quaternion"" "4217": "Blackboard: "exp map"" "4313": "I noticed the frame times are growing quite large now. Are you planning to optimize the software renderer further or switch to a hardware accelerated scheme?" "4345": "win32_handmade.cpp: Switch down to 960x540, disable the debug system and run the game" "4453": "Shut down the stream" --- name: "day235" title: "Initializing OpenGL on Windows" markers: "53": "handmade.h: Consult the TODO list" "242": "win32_handmade.cpp: Promote hardware acceleration to the top of the TODO list and embark on it" "355": "Run the game and note the weird fade thing" "418": "Set the stage for OpenGl" "513": "build.bat: Link to opengl32.lib" "580": "win32_handmade.cpp: #include opengl32.h>" "786": "win32_handmade.cpp: Introduce Win32InitOpenGL" "930": "Blackboard: OpenGL on Windows" "1402": "Blackboard: "DC" -> Device Context" "1729": "win32_handmade.cpp Write Win32InitOpenGL" "1915": "win32_handmade.cpp: Disable Win32DisplayBufferInWindow" "1959": "win32_handmade.cpp: Insert some OpenGL in this function" "2248": "Run the game and note that "we have no such pink screen to speak of"" "2269": "win32_handmade.cpp: Call Win32InitOpenGL, run the game and hit an InValidCodePath" "2308": "Internet: PIXELFORMATDESCRIPTOR" "2648": "win32_handmade.cpp: Initialise this struct" "3379": "Q&A" "3389": "Funny the pink didn't show up on the stream. OBS problem?" "3395": "We all just saw a black screen, not a pink screen..." "3423": "According to this you should use 32 for the ColorBit" "3478": "Curious if the CPU or the GPU actually communicates the information to the screen. I feel you mentioned this, but I forgot" "3541": "What are your thoughts about Vulkan?" "3554": "If you're ever in the mood to do a straight-up unrelated tutorial stream, IO completion ports would be great cause I ain't reading about that ***" "3580": "What do you think of Nvidia GE Force does not clear memory?" "3594": "Came in late. Do we have our own GL function pointers loaded now?" "3639": "Try a color other than pink? OBS might treat that as transparent" "3669": "Do you know why they deprecate GL_ALPHA?" "3687": "You don't need the DescribePixelFormat call, since when you use ChoosePixelFormat it modifies your DesiredPixelFormat with the correct stuff" "3737": "Since we will have a depth buffer, does the Z-sort really matter anymore?" "3792": "My bad! Looks like OpenGL docs are lying to me again" "3802": "Going to be doing multiple GL versions, or just the minimum for general Win XP machines? (What version are most of them even on anyway?)" "3848": "Would there be any benifit of using the new versions of OpenGL for a game like Handmade Hero?" "3870": "Is there a difference when calling a function (like glClear()) on the opengl32.lib vs the one on the graphics driver dll?" "3886": "Blackboard: Code library vs Import library" "3996": "Since we are using OpenGL, will you be modifying our 2.5D'ness or keep the code as is?" "4009": "For ChoosePixelFormat() were we not supposed to specify iPixelType and set it to PFD_TYPE_RGBA?" "4047": "win32_handmade.cpp: Set DesiredPixelFormat.iPixelType" "4094": "So by linking against opengl32.lib we don't need to use GetProcAddress at all with OpenGL?" "4136": "Blackboard: Dynamic link table" "4496": "Since you are complaining about windows pretty often, why don't you use another operating system?" "4548": "Do you think for the OS X port will you need a wrapper written in Objective-C to get use OpenGL and make a window?" "4580": "This is probably dumb, but what about offloading much of the computing we are doing onto the GPU using OpenCL, then not use OpenGL and keep things mostly as is?" "4657": "Over the break I wrote a program that generates OpenGL function pointer declarations and initialization by scanning cpp/h files to determine what needs to be added. Do you plan on doing something similar for Handmade Hero or will you keep it simple?" "4674": "How bad is an if statement in a shader?" "4693": "Have you ever programmed for a console?" "4722": "Linux has windows vista beat" "4790": "Wind it down" --- name: "day236" title: "GPU Conceptual Overview" markers: "7": "Recap and glimpse into the future of streaming via a video capture card" "126": "Run the game and note that Casey can see the game and we can't" "180": "Recap where we're at" "271": "Blackboard: GPUs" "420": "Blackboard: How the CPU relates to the GPU" "659": "Blackboard: A typical mobile setup" "799": "Blackboard: The implications of the system RAM and graphics RAM being separated by a PCI bus, i.e. latency" "939": "Blackboard: CPU vs GPU, historically" "1362": "Blackboard: A high level overview of GPU architecture" "1743": "Blackboard: How a GPU core works" "1898": "Blackboard: "Shader" != "CPU code"" "1985": "Blackboard: How if statments are executed on a GPU" "2206": "Blackboard: How loops are worked through on a GPU" "2271": "Blackboard: "Warp"" "2308": "Blackboard: Summarise what a GPU is" "2476": "Blackboard: How we program for the GPU" "2774": "Blackboard: "Pushbuffer"" "3206": "Blackboard: Plan for tomorrow" "3398": "Q&A" "3424": "You can instead of two triangles use a single triangle twice as big. It avoids the overdraw at the diagonal" "3513": "Quick CPU question: All it does on barebones physics level is run electrons through if-statements, right? (Go left, go right, etc., with transistors)" "3574": "Can't you run a Xeon Phi as your main processor, or did they make them dedicated only? Not like price / performance makes sense there" "3615": "What barriers are there currently from just using the CPU as a GPU?" "3709": "Can we make a "first person" 3D mode of the game, just for education?" "3715": "Where does the PS4 / XBone processor lie on the CPU / GPU spectrum?" "3858": "Intel has killed off many projects that made good money but had bad margins" "3956": "I've been told that lots of graphics drivers optimize for specific games (at the driver level). How does this fit into the equation? How do those optimizations make some games run better?" "4085": "Why does everyone good that works at Intel hate Intel, yet simultaneously Intel's engineering is so far ahead of everyone else's? It doesn't compute!" "4116": "What did you think about Larrabee?" "4136": "Does Vulkan fix the problem with OpenGL of not being able to transfer buffer-objects between processes with separate address spaces?" "4176": "Intel's compiler is meant to be really good, right?" "4211": "Can you give us some insight (without breaking any NDAs) how different from OpenGL console graphics APIs are?" "4346": "Sharing objects between applications without CPU overhead" "4363": "Why do you think there's no games about programming / hardware / history of PC / hardware? The domain is unimaginably rich" "4402": "How does GDDR RAM for GPU or concept of "memory chip designed specifically for GPU" enter into this picture?" "4428": "Blackboard: The gist of GDDR" "4596": "Could you one day maybe do a pre / after-stream short summary about your thoughts on OS-design and what you would do differently given current hardware?" "4617": "I mustered up one more. How come The Witness has 4GB RAM as minimum requirement? I don't doubt it has great optimization (as Jon is an apex-level programmer). Is it because nowadays everyone has 4 gigs at least and they thought it's unfeasible or too limiting to go below that? What can be the design behind that requirement?" "4787": "Why does it always seem like PC games claim that they require much more hardware power than they need? Do they want the extra power - just in case something goes wrong - or what?" "4859": "Having OS-level support for GPU resources for compute and graphics so that 3D graphics tools etc. can interoperate efficiently, e.g. in VFX production where you have lots of tools using the same data" "4905": "What would be a disadvantage of having a big beefy cpu (if any) or are there none?" "4920": "Have you seen that guy that is going to recreate Quake in a Handmade Hero style?" "4941": "How long do you expect this project to take?" "4968": "From what I get, Fallout 4 just allocates itself an 8 gig block. Abhorrent" "4997": "Quick question about strict aliasing due to your forum post (not defending it), but how would you propose compilers to understand that pointers do not overlap (to optimize loads and so on)? Not sure how we could improve generated code without having that kind of guarantee, assuming we need to still support old code" "5127": "Out of curiosity, back then when it came out, was GDI just a wrapper for OpenGL?" "5189": "Restrict doesn't seem to work with vs2013 / 2015" "5208": "Isn't Restrict, like, stupid limited though? And you don't have Alias (one that's definitive at least)" "5238": "Why is it that games get more difficult to play as Windows OS gets more advanced, i.e. playing a game from Windows XP on Windows 7?" "5280": "Wind down" --- name: "day237" title: "Displaying an Image with OpenGL" markers: "73": "win32_handmade.cpp: Disable PFD_DOUBLEBUFFER" "124": "Give it a shot and see our pink window" "153": "Recap our current situation" "307": "Blackboard: Ways of drawing quads" "407": "Blackboard: Using two triangles to draw our quadrilateral textures" "472": "win32_handmade.cpp: Explain glVertex nomenclature" "668": "Blackboard: Covering the screen with triangles" "723": "win32_handmade.cpp: Construct our first OpenGL primitive, a triangle" "780": "Run the game and "see" our triangle" "843": "Blackboard: Fixed function vs programmable pipelines" "1009": "Blackboard: Matrix multiplication" "1206": "Blackboard: Homogeneous coordinates and affine transforms" "1475": "Blackboard: Model View and Projection matrices" "1612": "win32_handmade.cpp: Use glLoadIdentity to set the MODELVIEW and PROJECTION matrices to the identity matrix" "1739": "Run the game and see the same thing we started with" "1744": "Blackboard: How OpenGL does Clipping" "2104": "win32_handmade.cpp: Pass glVertex2i the unit cube and then 0.9f" "2171": "Run the game and see the smaller rectangle" "2207": "Blackboard: Moving from Clip space to Screen space" "2387": "Blackboard: Drawing a texture" "2434": "win32_handmade.cpp: Do glColor3f before the two trianges" "2520": "Blackboard: Establishing our u,v texture coordinates" "2545": "win32_handmade.cpp: Set our texture coordinates" "2657": "win32_handmade.cpp: Use glTexImage2D to submit a texture to the graphics card" "3458": "win32_handmade.cpp: Use glTexEnvi and glTexParameteri" "3616": "Note that we aren't yet specifying the stride" "3674": "win32_handmade.cpp: Explain these parameters" "3874": "Run the game and see that we actually are there yet" "3889": ""It's all a lie"" "3977": "Q&A" "4016": "You used static instead of local_persist for Init" "4024": "win32_handmade.cpp: Introduce global_variable GLuint BlitTextureHandle" "4112": "Can we verify the vsync somehow?" "4140": "Are there any stretching issues when going from u,v coordinates to screen coordinates? If so, how would you fix it?" "4193": "The texture name you are binding is always zero after the first iteration" "4218": "I think in old OpenGL you don't even need glGenTextures, you can just pick your own arbitrary ints" "4231": "win32_handmade.cpp: Set GlobalBlitTextureHandle = 1; rather than using glGenTextures" "4371": "Would Texture Filtering (->GL_NEAREST) even occur when image and texture size is the same as it is now?" "4419": "In your professional career what GPU library have you preferred, such as OpenGL, DirectX, GLSL, etc.? Which one do you currently use and why?" "4443": "Later on, after we upgrade to more modern OpenGL, will the game render into a framebuffer and then onto the same triangles, or will you just have it render directly to the main window buffer?" "4525": "Before you removed the Init variable and inline initialization of the texture you were always passing 0 as the name, by the way" "4556": "So there is no way to blit directly to the back buffer anymore?" "4649": "Is there a difference in speed now we use OpenGL to move the buffer to the GPU?" "4781": "Is there a way you know of to optimize PCI transfers between CPU and GPU using OpenGL?" "4959": "I dunno if this is applicable to the last question, I literally just got here, but glTexSubImage2D could be faster than glTexImage2D" "4983": "Blackboard: glTexImage2D vs glTexSubImage2D" "5366": "At what point in that chain of gl commands does the card actually get involved? Command dependent? Driver dependent?" "5402": "Wrap it up" --- name: "day238" title: "Making OpenGL Use Our Screen Coordinates" markers: "9": "Recap and set the stage for the day" "134": "Recall how our graphics architecture works at the moment" "404": "Run the game and refresh our memory about where we left off" "545": "handmade_render_group.cpp: Look at how the renderer currently works and talk about the notion of separating out the renderer" "808": "Create handmade_opengl.cpp and translate RenderGroupToOutput into it" "1198": "handmade_opengl.cpp: Introduce OpenGLRectangle" "1547": "Blackboard: Maths" "1581": "Blackboard: Projecting the P from clip space to screen space" "1947": ""Life is hard"" "1966": "Blackboard: Setting up our transformation matrix" "2469": "win32_handmade.cpp: Write our new OpenGLRectangle function inline, passing it the old values at first" "2594": "Run the game and see our old bug" "2649": "Internet: glLoadMatrix" "2729": "win32_handmade.cpp: Initialize Proj array to pass to glLoadMatrix" "2845": "win32_handmade.cpp: #include handmade_intrinsics.h and handmade_math.h" "2874": "Run the game and see that everything does not just work" "2893": "Blackboard: Mathematical vs Computational matrix multiplication" "3206": "win32_handmade.cpp: Re-encode the Proj array for OpenGL's benefit" "3377": "Q&A" "3424": "I'm gonna start? Yeah i installed a driver software company. Kapp?" "3436": "What keyboard layout do you use?" "3447": "Will handmade_opengl.cpp be included in the platform layer or game layer?" "3549": "Jumped in a bit late, so are we using the fixed-function OpenGL API right now, or will we write our own matrix struct at some point?" "3592": "Wrist braces - recommended for programmers in general, or just something you've had issues with?" "3607": "If you include handmade_opengl.cpp in the game layer, won't that force you to include windows.h and all the OpenGL headers in the game layer?" "3701": "Was push buffer rendering primarily in the software renderer because the real hardware renderer works that way due to GPUs?" "3736": "Will the game be given away to dev viewers for free?" "3761": "Off-topic: Have you worked with, talked to or met Andre Lamothe before?" "3786": "I feel uncomfortable with floating points representing pixels. Have you ever had problems with OpenGL and floating point values, like passing them to shaders, or texture coordinates?" "3925": "Do you use any EBO (element buffer object) or VBO (vertex buffer object) in your OpenGL code? If no, why?" "4115": "Did you do your own glOrtho call when you set up the projection matrix? Also, thanks for all the matrix explanations" "4316": "Stream has ended" --- name: "day239" title: "Rendering the Game Through OpenGL" markers: "8": "Recap and set the stage for the day" "86": "handmade_opengl.cpp: Look at the new hardware rendering code and consider how to enable the renderer to work through software as well as hardware" "341": "handmade_render_group.cpp: Introduce RenderToOutput to pick whether to render with OpenGLRenderGroupToOutput or TiledRenderGroupToOutput" "617": "handmade_platform.h: typedef platform_opengl_render and add *RenderToOpenGL to platform_api" "689": "Leave it as a little bit of a zygote" "704": "handmade_opengl.cpp: Make RenderGroupToOutput only take *RenderGroup" "761": "Run the game and wonder how THAT just happened" "789": "Debugger: Step into GameUpdate and realise that we're using the old function" "849": "Run the game again and hit a first-chance exception" "856": "win32_handmade.cpp: #include "handmade_opengl.cpp"" "914": "handmade_opengl.cpp: Make OpenGLRenderGroupToOutput take *OutputTarget" "1070": "Run the game and see just our debug info" "1116": "win32_handmade.cpp: #if0 the buffer drawing code" "1153": "Run the game and see a bunch of solid nonsense" "1173": "handmade_opengl.cpp: Send a texture to OpenGL every frame" "1272": "Run the game and see that it almost works" "1380": "Blackboard: Blending" "1898": "handmade_opengl.cpp: Enable GL_BLEND and use glBlendFunc to specify the blending equation" "2003": ""It's almost like the hardware is set up to do this!"" "2009": "Run the game and see that we are successfully reproducing our image" "2041": "handmade_render_group.h: Add Handle to loaded_bitmap to store whether the bitmap has been submitted" "2159": "handmade_opengl.cpp: Conditionally bind the texture or set the handle" "2266": "Run the game and see that it now runs much zippier" "2298": "Debugger: Learn that we have a bug in the validation code" "2349": "Run the game and point out that the image has a shimmering look to it" "2404": "handmade_opengl.cpp: Re-enable bilinear filtering with glTexParameteri" "2516": "Run the game again and note that we look a lot more like the software renderer, but that our ground chunks are now messed up" "2807": "Describe the problems with the current architecture, enabling the debug system in the process" "3056": "Blackboard: The previous and new flows of data" "3321": "Q&A" "3372": "Why did you choose OpenGL over DirectX?" "3634": "Did you notice that the ground tiles changed when you introduced sorting?" "3678": "I've asked this before, but I want to hear your case again, what specific things make a data-protocol based interface better than one with function calls?" "3948": "How is V-Sync controlled?" "3981": "Does the GPU do sRGB correction automatically?" "4060": "I wasn't paying close attention, but has the OpenGL texture name thing broken hot-reloading?" "4091": "What languages do you know" "4097": "Are there any performance reasons to choose compatible OpenGL API vs Core, or is it just the fact that we get to use programmable shaders in Core?" "4215": "Is there any good reason for desktop GPUs to not have programmable blend modes? Because I've seen that most mobile GPUs have that" "4251": "Blackboard: Tiled (mobile) vs Non-tiled (desktop) Framebuffer" "4646": "Do we get gamma correct rendering "for free" now?" "4676": "Doesn't the OS automatically V-Sync you, or does that only apply in windowed mode?" "4693": "So gamma curve is also a OpenGL extension?" "4700": "I know you're probobly sick of all the Vulkan questions, but here is another one. A lot of places online frame Vulkan as the next version of OpenGL, their thought being that once Vulkan is released development / adoption of OpenGL will dwindle to the point where OpenGL drivers are no longer developed by graphics card manufacturers. Could this happen? And in the event that it does, what is your plan?" "4826": "You stated that the APIs are very similar, but is there a visual effect that can be accomplished on DirectX and not on OpenGL or vice versa?" "4860": "Is there a good reason why windows OpenGL headers only offer the old legacy stuff while other platforms add new stuff?" "4913": "At some point can you go over the pros and cons of the different graphics APIs?" "5101": "Call it a day" --- name: "day240" title: "Moving the Renderer into a Third Tier" markers: "29": "Recap and set the stage for the day" "149": "handmade_platform.h: Replace game_offscreen_buffer with game_render_commands" "756": "handmade_platform.h: Introduce InitializeRenderCommands" "800": "handmade_platform.h: Point out that the #inline part of game_render_commands won't work, before turning it into a #define" "1064": "win32_handmade.cpp: Pass RenderCommands to everything that needs it" "1279": "Note that this is where the three-tiered architecture emerges" "1354": "win32_handmade.cpp: Conditionally display the software renderer via hardware or a StretchBlt" "1497": "handmade_opengl.cpp: Introduce DisplayBitmapViaOpenGL" "2375": "Blackboard: The three-tiered architecture" "2440": ""I didn't fall asleep yet, so that's good"" "2447": "handmade_render_group.cpp Work through the compile errors" "3499": ""These ground chunks have been nothing but annoying the entire time..."" "3654": "handmade.cpp: Continue cleaning up the compile errors" "4346": "Q&A" "4390": "So no more hot code reloading for renderer code?" "4442": "Did you see the Handmade Quake? Can you confirm whether it's of Handmade quality?" "4458": "Casey, you seem to have a grudge for the ground chunks. Do you really hate them that much?" "4547": "Less of a question but more of a thanks for doing this. You've inspired me to pick up C and C++ again after quite a long break, so thanks" "4556": "What was your original goal with the ground chunks and how has that changed? Also if you remove them what will you replace them with?" "4637": "You may want to include a note in today's zip file about how it won't compile" "4643": "build.bat: Leave a note from The Management" "4695": "Why are you wearing earbuds? Are you listening to something?" "4708": "Would you at some point compile a list of "stuff programmers should know"? I'd like some beginner level pointers like "these are algorithms / algorithm types you should know", sorting being one type and such" "4791": "Wrap it up" --- name: "day241" title: "OpenGL VSync and sRGB Extensions" markers: "8": "Reminder: The source code is not in the public domain yet" "57": "On the possibility of vomiting" "99": "Recap and set the stage for the day" "173": "win32_handmade.cpp: Make Win32DisplayBufferInWindow take SortMemory" "304": "handmade_render.cpp: Make SortEntries take that SortMemory and continue cleaning up compile errors" "433": "handmade_render.cpp: Rename RenderGroupToOutput to TiledCommandsRender and make it take game_render_commands *Commands" "519": "handmade_render.cpp: Pull tile_render_work in from handmade_render_group.h" "549": "handmade_render.cpp: Rename RenderGroupToOutput to RenderCommandsToBitmap" "594": "handmade_render.cpp: Consider using the AddEntry call directly" "676": "win32.handmade.cpp: Make platform_api available to the renderer" "731": "win32_handmade.cpp: Continue cleaning up compile errors" "1289": "handmade_platform.h: typedef u64 umm" "1368": "handmade_render.cpp: Move DrawRectangleQuickly in from handmade_optimized.cpp" "1423": "build.bat: Remove the handmade_optimized.cpp build" "1503": "Build and run and crash in PushRenderElement" "1552": "win32_handmade.cpp: Correctly allocate memory for the PushBuffer" "1589": "Build and run successfully the first time!" "1645": ""Everything just worked"" "1688": "win32_handmade.cpp: Introduce GlobalUseSoftwareRendering to enable us to switch between software and hardware rendering" "1782": "Run the game and toggle between the renderers" "2008": "Blackboard: VSync" "2207": "Blackboard: glSwapInterval" "2338": "Internet: docs.GL [see Resources]" "2372": "Internet: WGL_EXT_swap_control [see Resources]" "2447": "handmade_opengl.cpp: Try calling wglSwapInterval(0)" "2480": "win32_handmade.cpp: Call wglGetProcAddress to get wglSwapIntervalEXT" "2600": "win32_handmade.cpp: typedef BOOL WINAPI wgl_swap_interval_ext" "2692": "Run the game and see that we're now running at a locked 60 FPS" "2752": "win32_handmade.cpp: Note that we are not done yet" "2917": "Run the game and note that our hardware renderer doesn't understand the fact that we're using sRGB" "3006": "Internet: ARB_framebuffer_sRGB [see Resources]" "3189": "handmade_render.cpp: Look at how our software renderer does gamma correction" "3405": "win32_handmade.cpp: Conditionally use SRGB8_ALPHA8_EXT if the necessary extension is present" "3514": "win32_handmade.cpp: Turn on GL_FRAMEBUFFER_SRGB" "3595": "win32_handmade.cpp: #define the GL_ extensions we want" "3700": "Blackboard: ARB - "Architecture Review Board"" "3766": "win32_handmade.cpp: Comment out the checks to see if the extensions are available" "3814": "Run the game and find that we have actual sRGB rendering happening" "3875": "Q&A" "3935": "Will you be implementing multiple render paths depending on the OpenGL context version or available extensions at runtime?" "3968": "Can you fix the Santa sorting?" "3980": "handmade_cutscene.cpp: Fix the Santa sorting" "4186": "Your maximum frame time is about 2-3ms without VSync enabled, but with it enabled I see it stays at 16ms most of the time, but sometimes goes to 17ms. Does that mean it will skip a frame? Is that a problem with VSync?" "4216": "Blackboard: SwapBuffers" "4508": "Is object oriented programming bad in general or for game purposes, and why?" "4515": "I believe you do an strstr of GL_EXTENSIONS, then check if the end of the extension is null, a space or tab to see if it exists" "4534": "Is there any reason to make the swap interval larger than 1?" "4554": "Blackboard: Swap interval" "4593": "Is there an asynchronous way to do VSync? I mean, a way to "ask" OpenGL if it has displayed the frame or how much time you have to wait until the frame is going to be displayed" "4640": "How would you allow the game to run at a non-60 FPS rate and not speed up / slow down the animation speed?" "4675": "Apologies if you explained this before. Since rotation is stored in the upper 3x3 part of the transform matrix, and Scale is stored in the 0,0, 1,1, 2,2 diagonal, how do the play well together? I mean, wouldn't changing the rotation or scale affect the other?" "4698": "You mentioned 120hz. How do you handle skipping every other VSync event? Do you just detect the monitor refresh rate and if 120hz swap twice in a row?" "4721": "If VSync is disabled in windows, will there be no VSync at all?" "4739": "The glove in the scene where Krampus is giving it to the kid looks a bit strange with the thumb pointing downwards" "4747": "Why does VSync cause input lag on some machines?" "4791": "What are the trade-offs of storing the textures on disk in the same linear colorspace format you are using?" "4837": "Any update on when to implement sound effects?" "4844": "What is that bottle full of that Jon posted on twitter?" "4854": "We're still fading from / to the desktop. Did you have to reimplement that? Is it being hardware rendered? Is the fade here to stay?" "4880": "With WglSwapInterval() do we still have to do Sleep at the end of the frame? Could you also comment on glFinish / glFlush and how they're used?" "5040": "Will you use EXT_swap_tear? (-1 in the SwapInterval call)" "5047": "Should we wait after SwapBuffers if it returns too fast?" "5067": "Would it be better to minimize or maximize how much you do per frame? Like, would it be better to make your program take any time that it would be waiting for VSync, and instead focus it on performing more computations, even potentially computing things ahead of time?" "5124": "How do you easily detect if VSync is active?" "5151": "How do I VSync and prevent tearing with a dual-monitor setup? Is it any different than a single-monitor setup? [see Resources]" "5243": "Conclude" --- name: "day242" title: "OpenGL Context Escalation" markers: "8": "Recap and set the stage for the day" "221": "Run the game and point out that we experience a pause while textures get loaded in" "439": "win32_handmade.cpp: Clean up and consult the TODO list" "456": "win32_handmade.cpp: On checking for OpenGL extension strings" "547": "handmade_opengl.cpp: Move the GL_ defines in from win32_handmade.cpp and introduce OpenGLGetInfo" "1051": "Run the game and inspect our opengl_info" "1143": "handmade_opengl.cpp: Parse the available extensions and compare them with our requirements" "1352": "handmade.h: Write a new version of StringsAreEqual" "1411": "handmade_opengl.cpp: Use StringsAreEqual to continue with the extension comparison" "1757": "Debugger: Inspect the Extensions string" "1994": "Debugger: Run through OpenGLGetInfo and see what the parser is doing" "2106": "handmade_opengl.cpp: Introduce OpenGLInit" "2226": "Context escalation" "2539": "Internet: WGL_ARB_create_context" "2693": "win32_handmade.cpp: typedef and use wglCreateContextAttribsARB to check which OpenGL context we're on" "3213": "Debugger: Step into wglCreateContextAttribsARB and see if it works" "3573": ""And now it's like Mr. Doesn't-Want-To-Do-That-For-Me"" "3604": "handmade_opengl.cpp: #define GL_SHADING_LANGUAGE_VERSION and use it in OpenGLGetInfo" "3687": "Debugger: Step into OpenGLGetInfo and inspect the ShadingLanguageVersion" "3724": "Q&A" "3766": "Looking at winXP and cards, looks like they need GL 2.0 as the 'max' they can support, more or less (if you use era cards)" "3803": "In the function OpenGLGetInfo why did you do an "#if 0 ... #else ... #endif" rather than just commenting it out?" "3832": "For sRGB do you also have to set WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB when you choose the pixel format or is that something different?" "4162": "From connor_rentz (just left): What is umm data type and what is it used for? I will watch the recording" "4187": "Yes, that's what I was talking about. I didn't notice you did more there" "4191": "What's the difference between sRGB and RGBA?" "4219": "Blackboard: sRGB" "4618": "I just checked my Dell monitor. It has Adobe RGB as well as sRGB modes and they look fairly different. So what's the better one?" "4714": "I've heard a lot of monitors aren't even really 32-bit color. Sometimes less with dithering in the monitor" "4758": "Shut down now" --- name: "day243" title: "Asynchronous Texture Downloads" markers: "3": "Welcome back" "78": "Promote 4coder and discuss modal editing" "642": "Recap and set the stage for the day" "768": "Blackboard: Texture Downloads" "914": "Blackboard: Thinking of the GPU memory like a cache" "1126": "Blackboard: Swizzling" "1164": ""CBAD, that's my rapper name"" "1571": "Blackboard: Power of 2 textures and modern rectangular texture processing" "1752": "Blackboard: The problems with our current texture downloading scheme" "2039": ""Drivers and Windows. They conspire to "help" you"" "2045": "Blackboard: Asset stores" "2238": "Blackboard: How the CPU asset store works" "2332": "Blackboard: The GPU asset store" "2520": "handmade.cpp: Return to the codebase" "2525": "handmade_opengl.cpp: How our loading currently happens" "2654": "handmade_asset.cpp: Refresh our memories as to what LoadBitmap and LoadAssetWorkDirectly do" "2950": "handmade_opengl.cpp: Move glTex* calls to handmade_asset.cpp and consider holding the frame if we are not ready with the texture" "3067": "win32_handmade.cpp: Pull the pieces of the picture together" "3242": "win32_handmade.cpp: Call Win32CreateOpenGLContextForWorkerThread in ThreadProc" "3344": "win32_handmade.cpp: Introduce Win32CreateOpenGLContextForWorkerThread" "3738": "win32_handmade.cpp: Introduce struct win32_thread_startup" "3871": "win32_handmade.cpp: Pass Startup to Win32MakeQueue directly" "3979": "win32_handmade.cpp: Undo and introduce GlobalOpenGLRC and GlobalDC instead" "4273": "Run the game and see nothing" "4322": "win32_handmade.cpp: Add bool32 NeedsOpenGL to platform_work_queue" "4562": "Run the game and still see nothing" "4599": "handmade_platform.h: Add platform_allocate_texture and platform_deallocate_texture to platform_api and add their equivalent calls" "4803": "handmade_asset.cpp: Call Platform.AllocateTexture in the FinalizeAsset_Bitmap case" "5190": "win32_handmade.cpp: Write PLATFORM_DEALLOCATE_TEXURE" "5281": ""The stream actually hasn't ended..."" "5648": "handmade_asset.h: Add AssetType to asset_memory_header" "5996": "Run the game, see nothing and leave it at that" "6081": "Q&A" "6090": "Are we missing a Day in the episode guide? The guide only goes up to Day 242, but today's overlay was saying Day 244" "6159": "Is it possible to tell OpenGL which graphics card to use if you have more than one in a given machine?" "6326": "Is it really a good idea to keep the DC around forever? What if the user changes their monitor config while Handmade Hero is running?" "6367": "Wouldn't the allocate and deallocate texture fit better in the opengl.cpp layer instead of the platform?" "6386": "handmade_opengl.cpp: Move PLATFORM_ALLOCATE_TEXTURE in from win32_handmade.cpp" "6413": "What is Microsoft's rationale for not allowing exclusive fullscreen mode for Universal Windows Platform games? Seems like that would just shoot themselves in the foot" "6499": "Is there a way to preload vertices / normals / colors to the card in the same way as textures (e.g. before glDrawElements is called) or is that usually never an issue?" "6590": "Could you invite Jeff to "supervise" and "micromanage" you while coding sometime?" "6654": "For 3D models isn't it typical to upload the mesh to the GPU once and write a shader that takes a transform matrix for drawing each model?" "6778": "It was just for entertainment reasons, I wasn't implying anything else. Jeff saying: "you know, I really don't like the name of that "variable""" "6841": "How the heck do you even read code with one letter variables?" "7015": "Thank you for the stream. We are not doing a good job asking relevant questions, obviously" "7079": "Wrap it up for now" "7114": "Promote 4coder" --- name: "day244" title: "Finishing Asynchronous Texture Downloads" markers: "55": "Build and run the game and note that our textures don't get downloaded" "92": "Set the stage for the day with some thoughts on writing software from scratch and the occasional need to use systems which are black boxes" "315": "Debugger: Take a stroll through our new OpenGL code" "548": "win32_handmade.cpp: Make Win32InitOpenGL return an HGLRC" "740": "Debugger: Step into Win32InitOpenGL and consider creating the OpenGL context outside of the queue" "826": "win32_handmade.cpp: Claim the Window as a CS_OWNDC" "865": "Debugger: Step into Win32CreateOpenGLContextForWorkerThread" "920": "Explain what is happening in the debugger while two threads are initialising OpenGL" "1154": "win32_handmade.cpp: Assert if wglMakeCurrent fails" "1192": "Run the game and note that we never hit that assertion" "1233": "Debugger: Step through Win32AllocateTexture" "1308": "handmade_asset.cpp: Set FinalizeOperation to FinalizeAsset_Bitmap" "1352": "win32_handmade.cpp: Put in the pointers to AllocateTexture and DeallocateTexture" "1385": "Debugger: Step through Win32AllocateTexture and see the game correctly rendering in hardware" "1566": ""I don't know how that ended up working"" "1598": "Mention the fact that there's no synchronisation between the texture downloading and the rendering, and describe our goal with regard to failure cases" "1996": "handmade_opengl.cpp: Explain the importance of gamma correction" "2173": "handmade_opengl.cpp: Explain why there are two separate enables for sRGB" "2300": "Internet: Consult the OpenGL docs" "2704": "win32_handmade.cpp: typedef these WINAPI wgl_ functions and enable the extensions in Win32InitOpenGL" "4128": "Q&A" "4150": "Don't you have a race condition according to the C11 and C++11 memory models when you set the texture handle from the worker thread and read it on the rendering thread without any synchronization? I think you need to use an atomic operation or the compiler could mess up the generated code" "4243": "Why don't you render directly to the backbuffer at Molly?" "4460": "FYI, no you can't change pixel format once it's been set. Need to create a temp window & context, get the wgl*arb function pointers, then destroy context & window and create new window and context with wgl*arb. Very annoying but that's how it works on windows as far as I know" "4509": "Will we be back to the debug code and finish it up after this, or have we finished it now?" "4523": "Thanks for the in depth explanation. Will you be going over modern GL later?" "4635": "Apparently in DirectX 12 you can select a separate context for different GPUs" "4690": "Where did you upload the 4coder videos?" "4713": "Yes, D3D11, too" "4738": "Couldn't you also use a PBO for streaming in textures?" "4835": "Wrap it up" --- name: "day245" title: "Using wglChoosePixelFormatARB" markers: "47": "Blackboard: PBO's (Pixel Buffer Objects)" "171": "Blackboard: Virtual Addresses, Physical Addresses and the TLB" "299": "Blackboard: The GPU does not have access to the TLB" "380": "Blackboard: How the GPU transfers the textures into its memory" "772": "Load the code and set the stage for the day" "896": "win32_handmade.cpp: Move wglGetProcAddress until after we have created a Context" "1045": "win32_handmade.cpp: Nullify the Context and try setting the PIXELFORMATDESCRIPTOR again" "1129": "Debugger: Step into wglMakeCurrent" "1285": "win32_handmade.cpp: Try destroying the Context a little later and then step through again to see if the pixel format got successfully changed" "1448": "win32_handmade.cpp: Introduce LoadWGLExtensions" "1508": "Crash 4coder and investigate what happened" "1719": ""Minidump with heap, bro"" "1747": "A few words on the helpfulness of submitting crash reports to developers" "1809": "win32_handmade.cpp: Introduce Win32LoadWGLExtensions" "1964": "win32_handmade.cpp: Introduce Win32ChoosePixelFormat" "2484": "win32_handmade.cpp: Call Win32LoadWGLExtensions in Win32InitOpenGL and test to see whether or not we are able to get a ModernContext" "2693": "Debugger: Step into Win32LoadWGLExtensions and follow what happens" "2785": "win32_handmade.cpp: Revert to the old way of creating two DCs" "2891": "Debugger: See if we have any better luck with that" "2936": "Moment of realisation: We forgot to call Win32SetPixelFormat on WindowDC" "2996": "Debugger: Step into Win32SetPixelFormat and find that it works" "3132": "win32_handmade.cpp: Use WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB" "3228": "Run the game..." "3287": "...and see stuff that we cannot see on stream" "3337": "win32_handmade.cpp: Set WGL_DOUBLE_BUFFER_ARB to GL_FALSE for the benefit of the stream" "3363": "Run the game for us all to see" "3446": "Q&A" "3460": "Aren't pretty much all games double buffered? If so, why doesn't OBS have problems capturing game footage for other games?" "3535": "Does this mean Handmade Hero cannot be let's played?" "3574": "There's a scene switcher plugin in OBS" "3615": "Shouldn't we also call GetPixelFormat to make sure we got what we wanted?" "3741": "So for games that is fine, but for something like photoshop I am assuming you would have to care?" "3877": "Have you started thinking about cross-platform support? I've missed quite a bit of the stream" "3948": "Is the GPU doing pre-multiplied alpha?" "4114": "Are you staying with immediate mode?" "4146": "Could we do sRGB with a shader and not with glEnable?" "4234": "Are we still going to do work on the debug UI?" "4267": "Every time you go to answer a question and the cutscene loops, a pink screen appears" "4328": "Wrap it up" --- name: "day246" title: "Moving Worker Context Creation to the Main Thread" markers: "45": "Recap and set the stage for the day" "277": "win32_handmade.h: Move platform_work_queue in from win32_handmade.cpp" "388": "win32_handmade.cpp: Initialise a Thread and Queue in ThreadProc and change to testing to see that we have an OpenGLRC" "516": "win32_handmade.cpp: Make Win32MakeQueue take a win32_thread_startup" "638": "win32_handmade.cpp: Initialise some High and Low priority threads and make the first two LowPriStartups to be populated by Win32GetThreadStarupForGL" "784": "win32_handmade.cpp: Replace Win32GetThreadStarupForGL with one that returns a win32_thread_startup" "896": "Debugger: Step through the win32_thread_startup initialisations" "987": "win32_handmade.cpp: Remove GlobalOpenGLRC and GlobalDC global variables and try stepping through again" "1033": "Run the game and see our textures" "1083": "Internet: Consult the WGL_ARB_pixel_format docs" "1294": "handmade_opengl.cpp: Consider how to get the wgl extensions" "1406": "Internet: Consult the WGL_EXT_extensions_string doc to confirm that in order to check that you have a wgl extension, you have to have a wgl extension" "1474": "win32_handmade.cpp: Use wglGetExtensionsStringEXT to see what extensions strings we have" "1753": "Internet: ARB_framebuffer_sRGB" "1848": "Beg to differ" "1881": "Debugger: Inspect our Extensions" "2121": "todo.txt: Consult the TODO list" "2274": "Run the game and test out our hot code reloading" "2500": "win32_handmade.cpp: Note that the Entry.Callback is not in the same place between builds and consider how to solve this problem" "2659": "todo.txt: Update the TODO file" "2813": "Q&A" "2821": ""So what shall we do for the next 20 min? Maintain the TODO file"" "2865": "There is a bug in the new GL code, the if(!) you added is not checking the sRGB variable but a different one" "3222": "Thank you to imperiumtactics for following the channel! <3" "3252": "Totally serious when I say you should write an API book. I would never think of lots of stuff" "3320": "For the keyboard / gamepad inputs, can HalfTransitionCount ever go beyond 1? Or is it there if you put the input getting on a separate thread?" "3460": "Kind of graphics / Windows related: Why do so many games, especially Source games handle Alt-Tab poorly?" "3631": "Is there any benefit to moving the main windows message queue to another thread? I'm sorry if you've implemented / answered this already. I'm still catching up" "3907": "Do you use Windows's GDI outside of the educational usage you have been showing?" "4046": "Promote 4coder!" "4051": "Sounds like you know how to play drums?" "4058": "What do you think of Vulkan? Will it replace D3D?" "4217": "Selection buffer vs ray picking vs color picking for mouse picking?" "4233": "For detecting long presses on keyboards, would I put a timestamp in the input struct?" "4255": "What is the next "feature" you are going to work on?" "4266": "Do you think all the modern C++ nomenclatures like C++11, C++14, C++17, C++xy are an internal joke to obscure the mess the language is?" "4368": "Is it worth selling my soul and learning JS / Python for money?" "4488": "Any thoughts on SDL2?" "4496": "What technique are you going to use for path-finding?" "4503": "Been doing a lot of JS. What do you think I should do next? Kind of bored with JS" "4536": "Vulkan is extremely low level; that was requested by various game engine and hardware developers. There is probably a huge market for a dev-friendly API to sit on top of Vulkan to shield devs from those gory details. Don't think so?" "4769": "ow much do you follow the latest technologies? Do you think it is a waste of time to learn the latest graphics API for indie development?" "5006": "Why should no programmer work for Palantir?" "5076": "Does Jon use more C++ specific stuff than yours do?" "5158": "What you think about the new Snowdrop game engine?" "5184": "Do you plan on using Vulkan considering the performance differences that people have been claiming exist?" "5257": "Since you write everything from scratch, why not use a language like Go?" "5284": "If any, what games have you been playing recently and how did you like them?" "5318": "I have noticed that there is no more send email on the Handmade Hero website. Do you still reply to emails?" "5364": "Where do you see the game development community going in the next 5-10 years?" "5369": "What are the main differences in, for example, C and the language your friend is developing, in three sentences or less?" "5378": "Do you have experience with POSIX Linux system calls, fork() for example? I need to create a small Process Scheduler, but when I create a fork() inside a for cycle it messes up. I need to create N amount of processes, then save them to a FIFO list and start executing one at the time" "5470": "Would you want to be one of the first people to play around with JAI? Or would you wait 'till it gets more mature?" "5557": "Are you going to check out OBS Studio this weekend?" "5563": "Do you work on another game project other than Handmade Hero?" "5601": "Is fork a good API or a bad API?" "5679": "Forgive me if already asked: GDC is next week. What Handmade Hero representation at GDC?" "5748": "Wind things down" --- name: "day247" title: "Simplifying Debug Values" markers: "9": "Welcome. Details about the texture transfer saga." "86": "nvidia didn't respond yet about _how_ to properly transfer textures overlapped." "114": "Overlapping CPU work and GPU work are not the same thing. There are 2 required copies that have to happen in order for the textures to get to the GPU: one off of the disk into memory that GPU can _see_, and then from the memory that the GPU can see into the actual memory resident on the GPU." "171": "Direct GPU Mapping process description" "253": "How do we tell the driver to start transferring textures using the asynchronous memory transfer capabilities that the card has" "325": "Decision to wait for nvidia's response about what they think the best way to transfer textures would be" "352": "Reminder that we don't fence the download on either side and doubt about whether that creates problems" "399": "Alternative approach - we could just continue to download textures on a single thread" "518": "Decide to fix the debug code" "569": "Reminder that on the AMD machine that Casey uses, the texture download problems don't seem to happen" "594": "glFlush() seems to force the download to happen on a separate thread" "635": "Reminder about the original debug code purposes" "703": "Focus on the debug interface" "836": "win32_handmade.cpp GlobalPause and GlobalUseSoftwareRendering would be nice to be included in the interface" "1025": "win32_handmade.cpp - DEBUG_EDIT() as a means to include GlobalPause and GlobalUseSoftwareRendering" "1157": "Doubts on the usage of handmade_config.h as a means to specify debug variables" "1314": "win32_handmade.cpp - replacing DEBUG_EDIT() with DEBUG_VALUE() and checking if it works" "1475": "Unhandled End Data Block" "1533": "Debug interface is not visible in in-game mode" "1660": "Check if debug components are drawn by not rendering the world" "1751": "Add a clear before drawing" "1774": "Confirmation that the debug interface doesn't show up in-game because of a sorting problem" "1867": "handmade_render_group.cpp - Add a SortBias to PushBitmap -> Dim.Basis.SortKey" "1947": "handmade_render_group.cpp - Investigate where and why is CAlign still used. [just for debug drawing]" "2128": "handmade_debug.cpp - add a FLT_MAX sort bias to the PushBitmap call so that we get the debug interface closest to us (on Z)" "2195": "handmade_debug.cpp - add a drop shadow to the text by duplicating the PushBitmap call, slightly displacing the position and changing the color" "2316": "Getting back to what we were doing - check if if interactive selection works and confirming that End Data Block UNHANDLED is not a bug introduced by the addition of GlobalPause and GlobalUseSoftwareRendering" "2374": "Checking the debug printout hierarchy" "2403": "win32_handmade.cpp - Checking how "Platform" should work in DEBUG_BEGIN_DATA_BLOCK()" "2411": "handmade_world_mode.cpp - Simulation_Entity | Confirm that printing block names is not yet implemented properly" "2501": "handmade_debug_interface.h - Minimize complexity by removing DEBUG_IF and DEBUG_VARIABLE" "2572": "Pulling out calls to DEBUG_VARIABLE and DEBUG_IF into globals ourselves" "2655": "handmade_config.h - Change #defines to global_variable" "2742": "handmade_render_group.cpp - Check we don't have code that writes to handmade_config.h" "2765": "Checking where handmade_config.h is included [in handmade_platform.h] and moving the inclusion to handmade.h" "2823": "Correcting types and initializers for globals in handmade_config.h and changing DEBUG_IF and DEBUG_VARIABLE calls in the rest of the code, removing compile errors one by one until..." "2985": "...reaching Global_Renderer_ShowLightingSamples, which is moved directly to handmade_render.cpp" "3078": "win32_handmade.cpp - Moving (and afterwards eliminating) Global_Renderer_UseSoftware from handmade_config.h and creating an enum with the rendering type, which allows to manage the Win32DisplayBufferInWindow cases better." "3433": "win32_handmade.cpp - The reason for ordering the enum components is for having the 0 value being the default" "3498": "Plans for next day: hooking up debug printout for editing and maybe cleanup" "3537": "Q&A" "3630": "Casey, at what point is it _bad_ to separate everything into multiple files, and when is it _good_?" "4056": "Okay, so basically personal preference, compile time, and external impositions. Thank you very much for your answer :)" "4066": "Does "texture download" on this stream mean "glTexImage2D"?" "4223": "Have you ever used #pragma section(...) and grouped memory into sections, and read the map file, or have you always used this style of meta programming?" "4251": "Off-topic: If you wanted to extend the hot-code reloading to work with structure changes wouldn't you have to store meta data about each struct along with information about every allocation, so that you could walk the data, adjust the data, move things around and fix pointers?" "4334": "Do you specifically have to say inline for functions to be inlined or does the compiler do that automagically if it finds one/several to fit?" "4507": "Would you try to fix the memory in-place or would you copy it to a new memory arena?" "4547": "Programming style - why do you have the function return on the preceeding line? Is it just so that the function name is in the first column?" "4622": "Yeah I don't know what the deal was, when I asked about inlining last night it blew up everywhere." "4733": "I was messing around with loop unrolling by hand and got massive speedups, any idea why would that be?" "4795": "Wind things down" --- name: "day248" title: "Cleaning Up Data Block Display" markers: "62": "Launch the code, build the game, recap and set the stage for the day" "159": "handmade_debug_interface.h: Reacquaint ourselves with the debug system" "381": ""We set ourselves up for success"" "400": "handmade_debug_interface.h and handmade_debug.cpp: Prune irrelevant stuff" "495": "4coder: Demo some editing movements / commands and promote 4coder's power" "584": "handmade_debug.cpp: Note how GetOrCreateDebugViewFor gives us a way to lookup the debug view for a given ID" "630": "Consider ways to develop the debug system" "1297": "handmade_debug.cpp: Reorder functions and consider how the system currently works" "1459": "Run the game and look at the debug visualisation" "1580": "Debugger: Step into CollateDebugRecords, inspect the Event data and walk through what the system is doing" "2011": "Propose cleaning up the way we build and store these debug events" "2319": "Consider no longer storing data blocks as data blocks, but making it part of a standing structure" "2617": "handmade_debug.cpp: Prevent the OpenDataBlock and CloseDataBlock from getting printed and increment events" "2857": "Run the game and see our hierarchical debug view" "2898": "handmade_debug.cpp: Make the debug view collapsible" "3371": "Run the game and try out our newly collapsible debug view" "3509": "handmade_debug.cpp: Truncate the event name in DEBUGEventToText" "3657": "Run the game and see our partially truncated event names" "3694": "handmade_debug.cpp: Check for Flags & DEBUGVarToText_AddValue and add an AddValue flag to handmade_debug.h" "3786": "Run the game and see our fully truncated event names" "3796": "handmade.cpp: Stuff all of our control variables under #if HANDMADE_INTERNAL from handmade_config.h" "3947": "Run the game and see all of our values in the debug view" "4028": "Q&A" "4053": "The "Per Frame arena space remaining" debug counter is always going down! Is this okay?" "4088": "You mentioned a book that introduces relational databases. I lost the link" "4114": "Will you re-implement the profiler?" "4246": "Casey, how do you easily implement the standard output without using the iostream library?" "4292": "Which do you prefer and why? #if #ifdef #if defined()?" "4349": "Can you tell me the version of what you just said, but for Linux (and not Windows)? I'm on Arch" "4461": "In terms of interaction with the debug settings, what do you have in mind for modifying the values? Switches or sliders?" "4488": "What does a for each loop do?" "4575": "Not related to today's topic: when do you think you will be designing your game instead of writing the engine?" "4633": "What language do you think is best for programming games?" "4724": "The handles are just int ids numbered from 0, which map to per-process fd-table in kernel space" "4751": "Will you consider using Jon's language soon? Even just for trying stuff?" "4774": "Close down, thank you" --- name: "day249" title: "Cleaning Up Debug Macros" markers: "8": "Welcome, let's jump directly into the revamping of the debug code" "44": "Recap: The debug system is relatively usable, but all names are always forced through the hierarchy system, so it creates dummy nodes for things" "79": "We also want to make the profiler functional again" "117": "handmade.cpp: Add DEBUG_PROFILE() to the debug data block" "162": "handmade_debug_interface.h: Define DEBUG_PROFILE" "370": "We have debug elements (which can exist in multiple hierarchies) and debug events (things that came to the stream and which we are trying to record)" "406": "handmade_debug.cpp: Add an empty case for DebugType_CounterFunctionList and check if using the pre-existing debug element is sufficient for the profile" "561": "handmade_debug.cpp: Check it DebugType_MarkDebugValue is still used and remove it" "678": "handmade.cpp: Check if the debug system supports nested data blocks" "795": "handmade_debug.cpp: Include the DebugType_CounterFunctionList case in the DEBUGDrawElement" "887": "handmade_debug.cpp: Remove the previously added interception call for DebugType_CounterFunctionList (the empty case)" "965": "handmade.cpp: Refine the data blocks syntax" "1390": "handemade_debug_interface.h: Rewrite the DEBUG_DATA_BLOCK in order to accomodate the changes made to the API" "1553": "Implementing the constructor for the data block begin and end" "1648": "handmade_debug.cpp: Check to see where the GUIDs are used" "1750": "handmade_debug_interface.h: Considering passing GUIDs through the RecordDebugEvent call graph" "2032": "Add "Name" to the UniqueFileCounterString(), remove BlockName from RecordDebugEvent and the debug_event struct" "2226": "Rename UniqueFileCounterString to DEBUG_NAME" "2275": "Check if Counter is used and remove it, simplifying FRAME_MARKER()" "2362": "Clean up BEGIN_BLOCK_() and END_BLOCK_() and add GUIDs to calls to RecordDebugEvent" "2429": "Clean up BEGIN_BLOCK(Name) and END_BLOCK(Name) by passing only the DEBUG_NAME(Name)" "2485": "Clean up the timed_block struct" "2595": "Clean up the TIMED_BLOCK and TIMED_FUNCTION macros" "2735": "Analyze the END_BLOCK("~timed_block") call" "3088": "Preprocess and search for "~timed_block"" "3264": "The debug code was not preprocessed because of the missing -D_HANDMADE_INTERNAL=1 switch on the command line" "3344": "Changing GUID to GUIDInit in the RecordDebugEvent macro so that it expands properly" "3391": "Remove Name from the END_BLOCK macro" "3425": "Another benefit of using a "Single Compilation Unit Build" is that if we want to preprocess a file, we can easily do it" "3572": "Temporarily remove -DHANDMADE_INTERNAL=1 switch from the build.bat file and fix other build errors on data blocks" "3721": "Q&A" "3762": "How the heck do you quickly get back into some obtuse code that you haven't looked at in 6 months?" "3828": "Wrap up. Thank you" --- name: "day250" title: "Cleaning Up Debug GUIDs" markers: "12": "Setting the stage and getting right back into cleaning up the debug layer" "141": "Fixing compile errors after reactivating the -DHANDMADE_INTERNAL switch" "190": "handmade_world_mode.cpp: Removing EntityDebugID from the DEBUG_DATA_BLOCK() call and considering adding it in a DEBUG_VALUE() call, if needed" "286": "Replacing BlockName with GUID and further cleaning up the debug code" "358": "handmade_debug_interface.h: Wrapping names that pass through the system in DEBUG_NAME()" "497": "Fixing the TIMED_BLOCK macros" "598": "handmade_render.cpp: Changing various BEGIN_BLOCK() calls to reference strings" "691": "Removing names from END_BLOCK() calls" "830": "Running after fixing compile errors" "1018": "handmade_debug.h: Deciding to simplify the debug_state struct" "1063": "handmade_debug.cpp: Checking if and where HighPriorityQueue is used, and removing it afterwards" "1119": "Removing the compiler feature from the debug system, but leaving it in place in the platform layer for the moment" "1337": "Reacquainting with the debug view system" "1492": "Breakdown of debug_view, debug_stored_event, debug_element and debug_tree" "1714": "Parsing the content of the GUID in the debug_element in order to obtain a more readable format" "1804": "handmade_debug.cpp: Hashing the strings in order for having them persistent across hot-reloads" "2146": "handmade_debug.h: Re-adding the GUID to the debug_element struct" "2262": "Storing the GUIDs in the persistent storage DebugArena" "2315": "Parsing the GUIDs to obtain FileNameCount, LineNumber and NameStartsAt" "2476": "handmade_debug_interface.h: Optimizing the UniqueFileCounterString__ macro for parsing" "2712": "Adding functions to easily retrieve the name and filename using counted strings from the debug element GUID" "2837": "Fixing compile errors" "2946": "Running and verifying the results - the parsing partially works" "3021": "handmade_debug.cpp: Reassigning the correct GUID when storing events so that they are safe across hot-reloads" "3227": "Changing the pre-storing of the GUID with the already extracted name" "3268": "Changing the separators from underscores to slashes" "3400": "Q&A" "3416": "Please use the following hash computation: HashValue = HashValue * 65599 + *Scan; (sdbm, source: http://www.cse.yorku.ca/~oz/hash.html). Simply using a sum of chars *will* produce a lot of collisions. (source: http://programmers.stackexchange.com/a/145633)" "3647": "Yes, the reasoning behind the hash is that it's used for symbols in ELF. If you think about it, symbols tend to come in clusters: i, j, k, x1, x2, x3 etc. ElfHash is designed to behave sensibly in that case" "3809": "Do you have a stream schedule?" "3866": "Actually, could you humour me and look at the disassembly for that hash function? The 65599 one? I'm curious to know how well it compiles" "4173": "what is imul, int multiply?" "4578": "Dude, you inspired me to write a handmade Windows debugger. Thanks for everything you do" "4606": "Why did you put the delta time of each frame into the input struct (Input->dtForFrame). That seemed a bit strange to me while looking through the source code today" "4633": "Why are the half-bytes of the hex value 1003fh reversed in the instruction. I could understand the bytes being reversed, but the half-bytes?" "4841": "And you want Intel to ship a unifying ISA for all GPUs..." "4940": "I'll keep that in mind" "4974": "Why was it passed in that structure? I was specifically looking for the delta time variable and that was the last place I expected it to be" "5053": "To add on, since each player has their own input struct, passing it through each one when it's going to be the same for each player seems redundant" "5139": "Wrap up. Thank you" --- name: "day251" title: "Finishing the Debug Hierarchy" markers: "45": "Run the game and see where we're at in terms of the debug hierarchy" "165": "handmade_debug.cpp: Look through how the hierarchy is currently being built" "412": "handmade.cpp: Note that the DEBUG_VALUE should have appeared in the debug view" "475": "handmade_debug_interface.h: Confirm that DEBUG_VALUE should be being set correctly" "516": "handmade_debug.cpp: Investigate why DEBUG_VALUE is not appearing as expected" "625": "Debugger: Step into a DEBUGDrawEvent call and inspect the Event" "644": ""Somebody is doing something dumb"" "677": "Debugger: Try to step into a StoreEvent call and realise that the Event is already being parsed previously" "803": "handmade_debug.cpp: Delete the GetElementFromEvent call from CollateDebugRecords and call it on demand where it's needed" "939": "Propose putting everything into the hierarchy, to avoid the constant problem of needing to decide whether Elements should go into DataBlocks or not" "1014": "handmade_debug.cpp: Make the GUID get set correctly" "1082": "handmade_debug.cpp: Comment out the GUID setting in StoreEvent" "1202": "handmade_debug.cpp: Rework how the debug groups get set" "1441": "Run the game and see that it isn't working at all" "1479": "handmade_debug.cpp: Initialise Element to 0 when making an OpenDebugBlock" "1733": "handmade_debug.cpp: Introduce debug_parsed_name and DebugParseName" "1816": "handmade_debug.cpp: Call DebugParseName and continue reworking" "2070": "Debugger: Compile and hit a first-chance exception" "2129": "handmade_debug.cpp: Remove StoreEvent call for CloseDataBlock" "2138": "Debugger: Compile and run and see that we're almost there, with possibly only a data bug" "2168": "handmade.cpp and win32_handmade.cpp: Correct the names of our DEBUG_DATA_BLOCK" "2221": "Run the game and admire our debug information" "2293": "handmade_debug.cpp: Modify the logic in GetGroupForHierarchicalName to enable correct expansion of the hierarchy" "2740": "Run the game and see that we seem to be good, besides the fact that debug values are not editable" "2804": "Lodge a complaint against Mr Five minute warning" "2812": "handmade_debug.cpp: Delete everything related to OpenDataBlock" "2840": "handmade_debug.cpp: Investigate why we cannot edit the debug values" "2945": ""C++ is awesome and always does everything wrong"" "2950": "handmade_debug_interface.h: #define DEBUG_B32 to manually specifiy that it is a boolean" "2991": "handmade.cpp: Call DEBUG_B32" "3036": "Debugger: Run the game, see that the debug values are still not editable and start to investigate why" "3134": "handmade_debug_interface.h: Provisionally introduce the notion of needing to DEBUGHandleValueEdit in DEBUG_B32 and DEBUG_VALUE" "3337": "Q&A" "3372": "Wednesday, you talked about Microsoft's Xbox process to detect which vertex was closest to another to form quads / tris / faces. Do you have the math behind that or maybe a link about it? I tried looking for it since then without any success" "3406": "Blackboard: Triface meshes and "locality"" "3973": ""It's just a full tristrip and it touches itself maximally"" "3985": "Blackboard: A perfect patch for maximum throughput, without needing to restart the tristrip" "4107": "Blackboard: Primitive Assembly Cache and Vertex Transform Cache" "4360": "Well yes, what you are now figuring out, that was my question. How does it "know" to use which vertex point to make triangles when you add them? Like, in your first grid example, how does it know not to draw a triangle from your center vertex to the upper left vertex (or any opposing vertex, for that matter)?" "4446": "Blackboard: Primitive Assembly: Triangles, Tristrips and Trifans" "4494": "Blackboard: Triangles" "4546": "Blackboard: Tristrips" "4629": "Blackboard: Trifans" "4773": "You mentioned shortly to make Handmade Hero startup quicker which is slow now because of what OpenGL has to do. How? Would think we need to load the textures first before showing Handmade Hero?" "4837": "For people who do 3D meshes, it seems there's a rule (at least for Blender, as far as I know) that using anything else than quads for topology produces rendering artifacts, so it has to be avoided. Is this because when rendering in-game everything gets split again into triangles? Ignore the Q: if what I'm asking doesn't make sense" "4982": "With OpenGL context creation, which bit is the slow bit? Is it SetPixelFormat, as it may be VS2013 that is the problem? In VS2015 this is not as slow" "5029": "shell.bat: set _NO_DEBUG_HEAP=1 in order to disable the debug heap" "5147": "Debugger: Run the game and note that the startup is now probably a little faster" "5272": "Explain the debug heap" "5326": "Close down" "5374": "Promote Handmade After Dark" --- name: "day252" title: "Allowing Debug Value Edits" markers: "92": "Recap and set the stage for the day" "187": "Consider how to proceed in making the debug values editable" "263": "handmade_debug_interface.h: Introduce DEBUGEditEvent in DEBUG_VALUE which allows setting the Event to a new value" "502": "handmade_debug_interface.h: Introduce DEBUGValueGetEventData in DEBUG_VALUE and create function prototypes of it for all the types we need" "658": "4coder: Hit a bug while doing replace-in-region from v4 to rectangle2" "874": "4coder: Hit a bug loading the same buffer twice" "1005": "handmade_debug_interface.h: Reintroduce DEBUGValueGetEventData in DEBUG_VALUE, compile, receive compile errors as expected, and rewrite those DEBUGValueGetEventData function prototypes" "1236": "Note that the Entity->Type cannot be converted because it is an enum" "1341": "handmade_debug_interface.h: Make DEBUGValueGetEventData take an Ignored value" "1518": "handmade_debug_interface.h: Introduce DEBUGEditEventData in DEBUG_VALUE and DEBUG_B32 to update the Event if needed" "1617": "handmade_debug.cpp: Consider making GetElementFromEvent write the pointer to the debug element" "1802": "handmade_debug.cpp: Implement DEBUGEditEventData" "2476": "handmade_debug.cpp: Remove DEBUGEditEventData and simplify the system so all it needs to do is check if the two pointers for the GUIDs match" "3354": ""It's a little pointer-chasey"" "3375": "Run the game and note that the values cannot be edited but that we are in good shape" "3439": "handmade_debug.cpp: Copy in the *Event DEBUGEndInteract and introduce the notion of OriginalGUID" "3731": ""Whoops, that function doesn't exist in 4coder yet, you can't call it, Casey!"" "3741": "handmade_debug.cpp: Make GetElementFromEvent store the OriginalGUID" "3902": "Debugger: Set a breakpoint in DEBUGEndInteract and see that we do hit it" "4063": "Debugger: Investigate why the OriginalGUID is not being preserved upon editing the debug element" "4143": "Moment of realisation: GetElementFromEvent will itself overwrite the GUID" "4192": "handmade_debug.cpp: Set OriginalGUID in CollateDebugRecords" "4264": "Debugger: Break into DEBUGEndInteract and find that GetElementFromEvent doesn't know the original value" "4393": "handmade_debug.cpp: Stop rewriting the GUID in StoreEvent" "4423": "Run the game and see that we can actually edit these values okay now" "4457": "handmade.cpp: Change DEBUG_VALUE to DEBUG_B32 where appropriate" "4494": "Run the game and see that some of our textures have failed to load, but that all our boolean values are now editable" "4552": "Trigger the particle system" "4584": "win32_handmade.cpp: Switch the rendering type" "4701": "handmade_debug.cpp: Ensure that we clear out the debug EditEvent when we start debugging" "4853": "build.bat: Turn on -O2 and try switching between the two renderers" "4940": "handmade_world_mode.cpp: Provide the ability to toggle the GroundChunks" "5156": "handmade.cpp: Put GroundChunksOn in the menu" "5179": "Run the game and toggle the GroundChunks" "5239": "Close this down" --- name: "day253" title: "Reenabling More Debug UI" markers: "74": "Run the game, try out the debug system and set the stage for the day" "207": "build.bat: Switch to -Od" "249": "handmade_debug.cpp: Change StartAtLastSlash to ShowEntireGUID" "346": "handmade_debug_interface.h: Consider excising the debug_id in favour of the debug_element pointer" "687": "Apologise to the DebugIDs" "805": "Run the game, note that the DebugID does work to toggle and investigate why highlighting does not work" "1013": "Debugger: Step into DEBUGDrawEvent and inspect the values being passed to InteractionsAreEqual" "1162": "handmade_debug.cpp: DEBUGDrawElement" "1233": "Debugger: Break on the InteractionIsHot call in DEBUGDrawEvent and watch the value of Generic" "1366": "Apologise to the man in the tree" "1415": "handmade_debug.cpp: Replace debug_stored_event with debug_element" "1630": "Run the game and commit an access violation" "1657": "handmade_debug.cpp: Conditionally set the Event in DEBUGInteract" "1674": "Run the game and see that our highlighting now works" "1699": "handmade_debug.cpp: Call DEBUGMarkEditedEvent in DEBUGInteract" "1761": "handmade_debug.cpp: Implement DEBUGMarkEditedEvent" "1857": "Run the game and edit the DebugDistance" "1917": "handmade_debug.cpp: Re-enable tearing" "2438": "handmade_debug.cpp: Call CreateVariableGroup in the TearValue case" "2577": "handmade_debug.h: Introduce CloneVariableGroup" "2657": "handmade_debug.cpp: Do the TearValue ItemInteraction if we're using the AltUI" "2803": "Debugger: Break into the debug system and note that it is working the way it used to work" "2916": "handmade_debug.cpp: Implement CloneVariableLink" "3200": ""We clone because we care"" "3247": "handmade_debug.cpp: Implement CloneVariableGroup" "3395": "Run the game and commit an access violation" "3525": "Hear the helicopters outside" "3541": "Debugger: Step into CloneVariableGroup and inspect the Result" "3671": "handmade_debug.cpp: Replace SubGroup with Dest->Children in CloneVariableLink" "3695": "Run the game and tear off some elements" "3844": "Q&A" "3888": "Dude's still up there, just to let you know" "3895": "The guy actually thought it was a binary tree and that he would be on the ground if he gets to the leaves..." "3936": "What is the debug code to other code ratio now?" "4040": "What happens if you try to modify a dynamic variable, e.g. player position?" "4128": "In CloneVariableGroup() ... sizeof (Name) - 1, should this be the string length, not size of pointer - 1?" "4151": "handmade_debug.cpp: Pass the correct calculation to CreateVariableGroup in CloneVariableGroup" "4234": "Wrap it up" --- name: "day254" title: "Reenabling Profiling" markers: "91": "Run the game and propose getting the profiling system back in some semblance of working order" "451": "handmade_debug.cpp: Reacquaint ourselves with CollateDebugRecords" "735": "Savour the moment" "797": "handmade_debug.cpp: Simplify CollateDebugRecords and change what gets passed to StoreEvent" "996": "Blackboard: Call Attribution" "1110": "handmade_debug.h: Make a note to store call attribution data in debug_stored_event" "1225": "handmade_debug.cpp: Implement Call Attribution" "1330": "handmade_debug.cpp: Collapse DEBUGDrawElement and DEBUGDrawEvent down to one function" "1452": "Blackboard: Sketch out the overview profiler" "1556": "handmade_debug_interface.h: Begin to implement ThreadIntervalGraph" "1703": "Run the game and see END_BLOCK being printed out" "1872": "Debugger: Hit an assertion and investigate" "1929": ""Would you be a lamb and jump me there?"" "2095": ""We just have a bug bug"" "2163": "handmade_debug.cpp: Comment out the StoreEvent calls to determine that 32MiB is not enough memory" "2343": "handmade_debug.cpp: Make GetElementFromEvent take b32 CreateHierarchy in order to conditionally do GetGroupForHierarchicalName" "2569": "handmade_debug.cpp: Introduce the notion of ProfileGroup" "2709": "Run the game and check out the debug visualisation" "2881": "handmade_debug.cpp: Make DrawProfileIn draw one frame" "4221": "Run the game and check out the correct debug visualisation" "4270": "Q&A" "4295": "handmade_debug.cpp: Convert a PointerToU32 down to CloseEvent->GUID" "4367": "What do you think of using a "call tree" to track dependencies across multi-threading?" "4413": "What command do you use to change from cutscene to game" "4419": "Tomorrow is episode 0xff!" "4429": "How do you handle tasks that run in separate threads but take longer than a frame to compute? For example, I heard that in the new Forza the rear view mirror updates at half the framerate as everything else" "4485": "WHY WAS I NOT INFORMED THAT KRAMPUS IS IN THIS GAME?" "4575": "Is talking to the chat while coding helpful to work things out?" "4611": "Do you have a problem with Santa from your childhood?" "4659": ""Santa is not good"" "4693": "I DID NOT GET A PICTURE OF KRAMPUS" "4711": "Did you consider visualizing timing using flame graphs?" "4800": "Is this software renderering? The frame time has tanked" "4843": "handmade_debug.cpp: Stop looping through every event every time" "5003": "Close down here" "5044": "Do you have a secret phobia of writing game code?" "5236": "Can we make games in GameMaker and submit them to you for the final game?" "5395": "Q: After you stop recording, beckon people to stay in the chat for a bit" "5433": ""It would be weird..."" "5442": "Q: It has to do with won_3d and an interview with him" "5489": "Q: It's not a live interview..." "5500": "Close down the stream" "5536": "Recommend Won Chun" --- name: "day255" title: "Building a Profile Tree" markers: "11": "Set the stage for the day" "32": "Problem #1: No fast way to get out the profiling information for the previous frame" "66": "Problem #2: In order to print out the profile view we need some concept of the nesting of calls inside one another" "241": "Blackboard: Profile Queries" "403": "Hype the new version of 4coder" "472": "handmade_debug.cpp: Enable the profiler" "492": "Run the game and hit an InvalidCodePath as we overflow the PushBuffer of the renderer" "865": "handmade_debug.cpp: Disable the profiler" "902": "handmade_debug.h: Add StoredEventCount, ProfileBlockCount and DataBlockCount to debug_frame" "992": "handmade_debug.cpp: Increment these values in StoreEvent and CollateDebugRecords" "1057": "handmade_debug.cpp: Print out these values" "1125": "Run the game and see what those numbers look like" "1300": "Consider how to process this data" "1471": "handmade_debug.h: Introduce debug_profile_node" "1801": "handmade_debug.cpp: Make DrawProfileIn take a debug_profile_node and work through how to use it" "2355": "handmade_debug.cpp: Make the DrawProfileIn call in DEBUGDrawElement take RootProfileNode" "2635": "handmade_debug.h: Use debug_stored_events in debug_profile_node" "2845": "Be Mr Cheesy - Mr Cheesepants, Cheese man" "2883": "handmade_debug.cpp: Set debug_stored_event *Node to the result of StoreEvent (via *StoredEvent) and then immediately rewrite it" "3594": "Run the game and see that we're never adding anything to the RootProfileNode" "3634": "handmade_debug.cpp: Conditionally set the ParentEvent in BeginBlock" "3921": "handmade_debug.cpp: Setup the children in BeginBlock" "3995": "Debugger: Step into DrawProfileIn and inspect the RootEvent" "4086": "handmade_debug.cpp: Correctly set the Node's Duration" "4248": "Run the game and admire the bizarre results" "4271": "Q&A" "4311": "Need to find a whole os is that we get a taste again... For some! Implementing merge?" "4320": "Will the day-counter overflow tomorrow, or will The Variable provide more bits for us?" "4337": "How are you going to celebrate Handmade Hero episode 0xFF?" "4403": "Soon enough we will need 10 bits to store the day counter!" "4480": "We may even need 11 bits!" "4500": "How long will it take me to get your "flow" of coding? 40 years?" "4524": "What kind of data is the profiler intended to display?" "4586": "Do you know what the total line count is at?" "4615": "Will you be able to turn on / off profiling for certain functions with the debug UI?" "4656": " A big part of the slow startup for me is that the ModeArena is cleared to zero by default at the moment. That's about 256MB" "4719": "win32_handmade.cpp: Set GlobalRenderingType to software" "4807": "Run the game and witness a very slow fade" "4871": "build.bat: Stop linking with opengl32.lib" "4922": "win32_handmade.cpp: Switch back to OpenGL and witness a longer startup" "4968": "Wind down, wrap it up" "5027": "Anticipate new 4coder" --- name: "day256" title: "XBox Controller Stalls and Fixing GL Blit Gamma" markers: "8": "Hype 4coder 4.0.2 super" "156": "Recap and set the stage for the day" "189": "Run the game and view the current state of the profiler" "292": "handmade_debug.cpp: Review the profiling code" "520": "handmade_debug.cpp: Note that we are using the EndClock value before it's been written" "573": "handmade_debug.cpp: Compute that Duration in CollateDebugRecords and correctly set the ClockBasis" "691": "Run the game and view our more plausible profile result" "764": "handmade_debug.cpp: Reenable and rewrite the text on hover" "818": "Run the game and view this text on hover" "879": "Blackboard: Pointer alignment and random picking from an array" "1026": "handmade_debug.cpp: Make the Colors array be a non-multiple of four" "1067": "Run the game and see our different zones in the profiler" "1153": "handmade_render_group.cpp: Add SortBias to the object_transform so the SortKey automatically takes it into account" "1238": "On writing TODOs" "1333": "handmade_debug.cpp: Introduce Transforms in DEBUGTextOp" "1431": "Run the game and note that our problem hasn't been fixed" "1453": "handmade_debug.h: Add Transforms to the debug_state" "1555": "handmade_debug.cpp: Initialise the Transforms in DEBUGStart" "1618": "handmade_debug.cpp: Pass BackingTransform to the PushRect calls in DrawProfileIn" "1707": "Run the game and view our profiler" "1771": "Blackboard: What the profiler is showing us may be happening after the point SwapBuffers is called" "2058": "Point out how useful profiling is" "2203": "win32_handmade.cpp: Investigate what's happening in our input processing" "2393": "Run the game and note that we need the ability to narrow in on a profile region" "2442": "win32_handmade.cpp: Comment out the "Input Processing" block" "2466": "Run the game and discover that the XBox controllers are taking 2,000,000 cycles to poll" "2514": "Describe and consider how to work around a well-known XInputGetState bug when polling XBox controllers" "2745": "win32_handmade.cpp: Introduce XBoxControllerPresent, assume they're all plugged in at startup and stop polling for them when we realise they're not" "2924": "Run the game and see none of that controller polling nonsense" "3005": "Discover that the software renderer does not draw the profiler properly" "3084": "handmade_opengl.cpp: Make glTexImage2D take GL_SRGB8_ALPHA8" "3165": "Run the game and see that that was the problem" "3220": "Explain how gamma is treated in the renderer" "3331": "Note that we need to reserve one texture at startup in case we would like to do OpenGL bitmap display" "3378": "Demo the bug with switching between the renderers" "3447": "win32_handmade.cpp: Introduce OpenGLReservedBlitTexture and set one of them Win32InitOpenGL" "3537": "Run the game and see that we now no longer have that bug, but do have a bug with pixel centers for the fonts" "3640": "Q&A" "3668": "insobot What do you think of Microsoft's Tay bot?" "3682": "cmuratori Oh wow. I guess i should say? Wow, thought i came" "3690": "Q: Can't remember what OpenGL considers the center of the pixel...?" "3770": "Is romp just a synonym for clobber?" "3776": "Will the opening cutscene be narrated?" "3792": "Could you elucidate further on the waiting for VSync in the profiler?" "3942": "I actually prefer the fonts that the software renderer produces. Is there anything we can do to make them look that way in GL?" "3996": "Recommended entry-level programming language for aspiring game devs?" "4254": "Is there anything that can be done to help make it easier to hover / click on the debug visualization?" "4326": "popcorn0x90 You can implement most of it, replacing most of" "4333": "Are all the textures transferred every frame?" "4480": "In the debug UI will we be able to click on a frame and have it blit that frame?" "4542": "Could you explain in what consist the dynamic resolution? Texture rescale, viewport rescale?" "4576": "Are we going to have it auto-pause on long frames?" "4598": "What about checking for memory leaks?" "4658": "At what point would you make the transition from a more basic language like JavaScript over to a language like C?" "4915": "Sorry, have a fail-safe to see when we stutter to pause the system and debug it" "4985": "Close" "5042": "Promote 4coder" --- name: "day257" title: "Cleaning Up Some Win32 Issues" markers: "22": "Set the stage for the day" "119": "build.bat: Introduce and check for HANDMADE_STREAMING environment variable" "415": ""Where are you, Mr. Environment Variables?"" "533": "Double check to make sure that we can still stream" "575": "Delete a bunch of stuff we no longer use" "853": "handmade_platform.h: Rename PointerToU32 to U32FromPointer and call it where needed, in order to prevent GCC and clang from complaining" "1080": "Run the game and ensure that it does run" "1153": "win32_handmade.cpp: Remove the fader" "1411": "Consider removing the multi-threaded OpenGL contexts" "1523": "Run the game and point out a bug in the profiler upon hot-reloading" "1823": "Debugger: Manually write xor instructions into memory" "1965": "Run the game and verify that the strings are getting messed up" "2065": "handmade_debug.cpp: Fix the string handling" "2450": "Run the game, test the hot-reloading to see that the strings do remain stable, but crash" "2524": "Debugger: Inspect the Thread and find that the OpeningEvent does not have to be valid" "2599": "Q: Why did we make the GlobalDebugTable a static buffer?" "2745": "win32_handmade.cpp: Make the GlobalDebugTable in here be the authoritative one and rewrite how it gets collated" "3163": "Run the game and twiddle it a little bit" "3244": "Investigate what is wrong with our profile" "3690": "win32_handmade.cpp: Conditionally clear the debug event array if the game failed to load" "3759": "Run the game and resume our investigations" "3844": "Debugger: Step into BeginBlock and inspect the DebugState" "4181": "Debugger: Inspect the events' GUIDs and break into EventsMatch" "4218": ""I don't care about you"" "4273": "handmade_debug.cpp: Temporarily Assert that EventsMatch and inspect the Events when we hit that assertion" "4464": "handmade_debug.cpp: Note that the Event is transitory and instead use StoredEvent for now" "4576": "Debugger: Inspect the Events and StoredEvent" "4595": ""Something very strange is afoot"" "4652": ""So complicated. I rather enjoy it, though"" "4656": "handmade_debug.h: Make open_debug_block not store the entire debug_event but instead just store the data we want" "4824": "Run the game and see that we're still losing our profile" "4879": "Q&A" "4896": "Would it be reasonable to separate the debug UI into a separate program that communicates with the game over pipes / sockets? The game won't hold the debug data and won't waste cycles on debug collation, debug rendering; if game crashes, you can still inspect frames, or even save them to the disk independently of the game running" "4989": "You are referring to GlobalDebugTable outside a HANDMADE_INTERNAL guard, when you initialize it in UpdateAndRender" "5005": "Casey, your stream overlay disappeared at some point this evening. I'm pretty darn sure it might have happened out of protest when you removed the beautiful fade, so it could be worth reimplementing that, if only in the interest of overlay stability" "5019": "How are you finding modular editing so far?" "5079": "handmade.cpp: Initialise GlobalDebugTable inside HANDMADE_INTERNAL" "5110": "Why not use DebugBreak instead of *(int*)0=0 which will allow you to step over the assertion if you really want but will still trigger the breakpoint" "5131": "The Handmade twitter account says tomorrow is an off day" "5137": "What exactly is modular editing?" "5169": "When you're writing your own renderers and stuff, do you go for a left-handed coordinate system or right-handed (for vector-matrix multiplications, etc.), and why?" "5196": "Something I noticed when you disabled the trees rendering, the white dot used to resize the profiler view is hard to see over a light background, like the text was hard to read before adding a shadow" "5262": "Do you find that commentating as you work helps you reason or helps you overall when programming?" "5283": "Do you think 4coder is good enough to switch to coming from emacs? Or are you finding it's missing some stuff yet?" "5399": "And vertical- / block-kill / -selection?" "5432": "Off topic: I noticed that pragma pack will change the alignment of the struct. Is there a way of keeping the original alignment?" "5448": "Could you share your 4coder_custom.cpp?" "5542": "Do you think it would be neat to save a DebugUI "layout" with torn elements open as they were last?" "5582": "I include it in 4coder at the $10 level" "5610": "Is it possible to use with the $5 build?" "5629": "Call it a day" "5666": "Promote 4coder" --- name: "day258" title: "Fixing Profiling Across Code Reloads" markers: "39": "handmade.prj: Move the .prj files from the code to the root directory" "71": "Recap and set the stage for the day" "158": "Run the game, do a hot-reload and note that the profile is busted" "228": "Explain the debug collation situation in terms of multithreadedness" "525": "Consider how to potentially solve the problem" "739": "win32_handmade.cpp: Flush all the queues, do FrameEnd and then finally do the hot-reload" "898": "Run the game, attempt to hot-reload, and hang" "954": "Debugger: Investigate what's going on here" "1072": "Explain the bug: Upon hot-reloading, we go back through the collation code because there was no collation code to call" "1147": "win32_handmade.cpp: Try loading the game code multiple times during collation" "1303": "Run the game and try hot-reloading" "1341": ""How about you actually check to see if it's loaded, Muratori!"" "1354": "win32_handmade.cpp: Fix the LoadTry loop" "1383": "Run the game and try that one more time" "1412": "Debugger: Investigate what's going on" "1485": "Blame it on the code" "1581": "handmade_cutscene.h: Introduce struct cutscene and enum cutscene_id" "1766": "Run the game and find that we're not safe across reloads in the cutscene mode" "1829": "Debugger: Break on Win32UnloadGameCode and inspect the GlobalDebugTable" "2040": "A thought" "2064": "win32_handmade.cpp: Disable the EventRecording while we reload" "2358": "win32_handmade.cpp: Enable the EventRecording initially" "2391": "Run the game and..." "2423": "Admire the lovely profiler" "2455": "build.bat: Switch to -O2 and see how the profiler fares" "2516": "Happy puppy" "2523": "Q&A" "2560": "Not sure if this was asked before but is it worth to use static_cast instead of a C-style cast that does static_cast, dynamic_cast and reinterpret_cast, if you know that you only need the first?" "2612": "Demo: C-style cast" "2899": "Demo: C++ dynamic_cast" "3089": "How exactly did they mess up casting in C++?" "3201": "dynamic_cast will return 0 if it fails" "3219": "Is the debug view for bitmaps working again?" "3255": "For string manipulation, is there a library worth to use in C/C++? I could do it with Python but I'd like to use C" "3297": "You are spending a lot of time on debug tools before you need them. Is it going to be worth it?" "3487": "Speaking of string libraries, what kinds of things do you think should be in a good string library?" "3576": "expixel: Hand banana hero. You rock" "3580": "Andrew Chronister: "Insobot is a national treasure"" "3601": "Does using VirtualAlloc and reserving a lot of memory upfront count?" "3676": "Well I meant using MEM_RESERVE then MEM_COMMIT so that you can append quickly without the copy" "3700": "Go eat dinner" "3744": "Promote Martins Mozeiko" "3785": "Mention HandmadeCon 2016" "3826": "Promote 4coder" --- name: "day259" title: "OpenGL and Software Renderer Cleanup" markers: "8": "Recap and set the stage for the day" "90": "Run the game and demonstrate how we'd like to develop the profiler" "370": "handmade_debug.cpp: Look through the profiler code" "535": "handmade_debug.cpp: Use ThreadOrdinal to set the LaneIndex" "612": "Run the game and view the profiler information in LANES" "731": "handmade_debug.cpp: Investigate why the background colour is incorrect in the software renderer" "882": "handmade_debug.h: Introduce UITransform layer" "938": "Run the game, view the profile and investigate why it is pink" "1041": "handmade_render.cpp: Make DrawRectangle SIMD and do alpha blending" "1561": "Debugger: Break on FillRect and find that it and ClipRect never intersect" "1720": "handmade_render.cpp: Set FillRect earlier" "1757": "Debugger: Step through and inspect the rectangle values" "2070": "handmade_render.cpp: Use structured art to help debug this" "2117": "Debugger: Inspect the Blended values" "2202": "handmade_render.cpp: Multiply Color by 255 in order to get it into the correct space" "2262": "Run the game, see that the colours are incorrect and investigate why" "2511": "handmade_render.cpp: Square the ColorValues up front" "2668": "Run the game and see that the colours are now correct" "2719": "win32_handmade.cpp: Reenable our threads and view the profiler" "2766": "handmade_opengl.cpp: Take account of the 1-pixel border in OpenGLRectangle" "2970": "handmade_opengl.cpp: Pass the corrected coordinates to OpenGLRectangle in OpenGLRenderCommands" "3107": "Run the game and see that the fonts look more correct" "3180": "GitHub: Close issue #15" "3256": "win32_handmade.cpp: Check for OpenGLSupportsSRGBFramebuffer in Win32SetPixelFormau" "3353": "handmade_opengl.cpp: Make OpenGLInit take FramebufferSupportsSRGB" "3474": "Run the game and admire how close we match" "3501": "Fight the urge to go back and correct it" "3547": "handmade_opengl.cpp: Support the ARB versions of our extensions" "3685": "GitHub: Close issue #8" "3779": "Debugger: Break into OpenGLGetInfo and see what extensions this GPU supports" "3880": "Q&A" "3937": "I've implemented a quick and dirty flame graph for Handmade Hero" "3983": "Is the stream being off tomorrow an April Fool's joke?" "4000": "What happened to the software rendered performance? It was running at 30 FPS a few months ago! Even without -O2 it was pretty decent" "4027": "build.bat: Switch to -O2 and watch the profiler" "4141": "win32_handmade.cpp: Switch to Win32RenderType_RenderSoftware_DisplayGDI and again watch the profiler" "4272": "So let me get this straight, modern PCI-E connections have several GB/s of bandwidth and yet it takes several frames to upload a texture for the backbuffer?" "4400": "Go eat some dinner" --- name: "day260" title: "Implementing Drill-down in the Profiler" markers: "58": "Run the game and consider how to develop the profiler" "310": "handmade_debug.cpp: Make DrawProfileIn do PushRectOutline instead of PushRect" "356": "handmade_render_group.cpp: Introduce a PushRectOutline that takes the same arguments as PushRect" "394": "Run the game and see that the outlined rectangles don't seem to be correct" "564": "Debugger: Step into PushRectOutline and inspect its values" "763": "handmade_render_group.cpp: Make PushRectOutline use the thickness" "820": "handmade_debug.cpp: Get that thickness back in there" "843": "Run the game and view the profiler" "866": "handmade_debug.cpp: Introduce DrawProfileBars" "1161": "handmade_debug.cpp: Call DrawProfileBars in DrawProfileIn" "1211": "Run the game and see that the profile view is the same" "1219": "handmade_debug.cpp: Call DrawProfileBars recursively" "1267": "Run the game and view the entire call stack in the profile" "1322": "handmade_debug.h: Introduce MouseTextStackY to enable us to see information for multiple debug elements" "1408": "Run the game and see this information" "1458": "handmade_debug.cpp: Introduce GetLineAdvance to give us a more robust way to write multiple lines" "1610": "Run the game and see our correctly spaced lines" "1641": "win32_handmade.cpp: Increase the PushBufferSize" "1677": "Run the game, view the profiler and consider implementing zoom" "1852": "handmade_debug.cpp: Begin to implement zoom" "1911": "handmade_debug.h: Introduce debug_view_profile_graph" "2072": "handmade_debug.cpp: Provide the ability to set RootNode based on a search" "2775": "handmade_debug.h and handmade_debug.cpp: Provide the ability to set the profile graph root for zooming" "3178": "Run the game and try out the zoom" "3210": "Debugger: Break into DEBUGEndInteract and inspect the values upon zooming" "3672": "Debugger: Break on ZoomInteraction, inspect the values and find that we're currently picking the wrong Frame" "3886": "handmade_debug.cpp: Search for the correct Frame to set the RootNode" "4018": "Run the game and successfully try out the beautiful zoom" "4168": "Q&A" "4211": "Are you as productive in a single 8 hour period as you are on the show over 8 sessions?" "4238": "Do you have that in your current game at work?" "4254": "Is our debug tooling sophisticated enough to detect OS slowness, i.e. problems with heap / mem performance, etc?" "4394": "When doing playback, is the debug info showing the past CPU info?" "4429": "Only in C/CPP?" "4437": "What type of game is this, e.g. FPS, RPM etc?" "4445": "Yes profiler!" "4450": "I discovered why I didn't see the font rendering. I'm on a 2560 x 1440 screen with 200% DPI scaling. Do I have to use a specific resolution to make it work?" "4499": "Was there a factor in not implementing moving backwards in the threading system?" "4647": "Call it" "4700": "Promote 4coder" --- name: "day261" title: "Changing to Static Frame Arrays" markers: "108": "handmade_debug.cpp: Initialise the ProfileGraph dimensions to something relatively large" "241": "Run the game, see the profile at a more useable default size and set the stage for the day" "342": "handmade_debug.cpp: Introduce DrawFrameBars which draws stacked bars for multiple frames" "955": "handmade_debug.cpp: Call DrawFrameBars rather than DrawProfileIn" "1037": "handmade_debug.cpp: Cap the FrameIndex" "1082": "Run the game and see our stack" "1088": "handmade_debug.cpp: Increase the FrameCount to 10" "1250": "handmade_debug.cpp: Just set the RootNode to be the OldestEvent" "1323": "handmade_debug.cpp: Increase the FrameCount to 128" "1338": "Run the game and see a more granular view of what's happening over time" "1476": "handmade_debug.h: Remove debug_frame_region and MAX_REGIONS_PER_FRAME" "1558": ""None of that's a thing"" "1568": "handmade_debug.h: Introduce debug_element_frame to allow us to track and time events" "1867": "handmade_debug.h: Introduce FrameOrdinal and MostRecentFrameOrdinal and make functions in handmade_debug.cpp use it" "2289": "handmade_debug.cpp: Work on FreeFrame and FreeOldestFrame, and rework NewFrame as InitFrame" "2892": "handmade_debug.cpp: Introduce IncrementFrameOrdinal and GetCollationFrame" "3092": "handmade_debug.cpp: Work through compile errors" "3708": "Run the game and see that it is (almost) working" "3768": "Debugger: Break on FreeFrame and inspect the ordinals" "4173": "handmade_debug.cpp: Conditionally do a FREELIST_DEALLOCATE in FreeFrame" "4378": "handmade_debug.cpp: Scrutinise FreeFrame and do a ZeroStruct on *ElementFrame" "4488": "Run the game and reiterate the fact that we're leaking memory" "4585": "Q&A" "4630": "Do you need to wrap that + FrameOrdinal in the FreeFrame function?" "4668": "handmade_debug.cpp: Assert that FrameOrdinal is less than DEBUG_FRAME_COUNT" "4748": "handmade_debug.cpp: Keep track of the FreedEventCount" "4795": "Run the game, crash and find that we're freeing one more event than we're storing" "4870": "handmade_debug.cpp: Remove a FREELIST_DEALLOCATE" "4896": "Rebuild and run and find that the bug's gone" "4968": "I'm a bit behind on Handmade Hero, but do you typically bypass (for something like off-stream coding) all the simplified things like rendering a bitmap like how you were doing (DrawBitmap, like on episode 39), and go straight to the renderer? But as well as other things like structured assets and the like?" "5127": "Thoughts on using a static array instead of the lists?" "5176": "insobot had this to say today: "Inheritance and encapsulation two best inventions of mankind". Discuss" "5191": "Do you prefer to use modulo or masking for circular indexing? Do compilers replace modulos with bitwise-and if the operand is power of 2 -1?" "5301": "Are we still doing the marathon stream to account for the Q&A Monday madness?" "5313": "The profiler code you had running several weeks ago, what happened to it? Some of the things you had implemented like the multiple lanes seemed to have disappeared" "5347": "handmade_debug.cpp: Reenable the profile lanes" "5435": "Run the game, see the multiple lanes, enable the software renderer and crash" "5470": "handmade_debug.cpp: Disable the recursion for now and run the game" "5559": "What if you aren't really learning from Handmade Hero? Where I've gone through episodes 1-28 about four times and I thought I knew how to do so. I tried to make the simplified win32 layer to get to the independent layer, and I found that I couldn't do it. The documentation was rough and I forgot what things did what. What would you say to people who find that they aren't learning?" "5729": "handmade_debug.cpp: Switch from DrawProfileIn to DrawFrameBars and view the profiler" "5770": "Call it" "5862": "Promote 4coder" --- name: "day262" title: "Drawing Multi-frame Profile Graphs" markers: "64": "Recap and set the stage for the day" "209": "Apologise to folks not on the 4coder bandwagon yet" "217": "handmade_debug.cpp: Consider how to unify Element creation" "626": "handmade_debug.h: Add RootProfileElement to debug_state and pass that down the profiler system" "878": "Run the game and make sure that it works" "986": "Debugger: Step into RootProfile and erroneously follow the ParentGroup path" "1040": ""Arrrgggghhhhhh"" "1092": "Make this a very quiet, dignified edit" "1104": "handmade_debug.cpp: Do AddElementToGroup in the CreateHierarchy path" "1127": "Run the game and see that we're in better shape" "1161": "handmade_debug.cpp: Simplify the ViewingElement code using RootProfileElement" "1242": "Opine the low resolution" "1263": "handmade_debug.cpp: Simplify DrawFrameBars" "1571": "Blackboard: How the events are stored" "1713": "handmade_debug.h: Consider doing StoreEvent directly into the Element, without adding it to a Parent in CollateDebugRecords" "1831": "Blackboard: Why this might not work" "1932": "handmade_debug.cpp: Use debug_profile_node in DrawFrameBars" "2062": "Run the game and stress test the profiler" "2367": "handmade_debug.cpp: Switch to DrawProfileIn and make it take a debug_element RootElement" "2493": "Run the game and view the profiler with the old display" "2538": "Blackboard: Gracefully handling multiple events on a single frame" "2720": "handmade_debug.h: Remove AggregateCount from debug_profile_node and pack it a little differently" "2892": "handmade_debug.h: Remove TotalClocks from debug_element_frame" "3012": "handmade_debug.cpp: Introduce GetTotalClocks in order to compute TotalClock on demand" "3233": "Run the game and make sure the profiler still works" "3244": "handmade_debug.cpp: Space the EventRects based on the TotalClock" "3518": "Run the game and view our beautiful profiler" "3573": "Q&A" "3602": "Relationship status it's complicated for the movement to be it's own main function inside?" "3690": "Reasons performance was so bad with the new debug view? Isn't this still way fewer tris than a typical 3D game? Is the framerate reasonable if you switch to solid rectangles vs outlines?" "3836": "Will you make the UI immediate mode?" "3844": "Will the debug graphing update even if the game is paused?" "3868": "Right now the outlines on the profiler overlap each other. Makes it a little harder to make out the colors (or the change from one to the other). The obvious solution would be to draw them with a slight offset from the last each time, but are there any problems with that once the rectangles get really small?" "3907": "Is our current timestep code framerate independent? Will the game's simulation run the same at any framerate?" "4014": "Are we going to do the batch way then?" "4043": "(Off-topic) Have you ever defined structures inside of functions?" "4157": "Is there any advantage to making physics dependent on framerate other than convenience?" "4278": "Wrap it up" "4342": "Promote 4coder" --- name: "day263" title: "Adding a Debug Frame Slider" markers: "49": "Run the game and set the stage for the day" "116": ""You feel me, dawg?"" "167": "handmade_debug.cpp: Introduce case DebugType_LastFrameInfo and _DebugMemoryInfo and tie them into the system" "372": "handmade_debug.cpp: Introduce BasicTextElement" "470": "Hype 4coder and demo some indentation issues" "564": "Compile and run and find that BasicTextElement does work" "590": "handmade_debug.cpp: Propagate BasicTextElement" "632": "handmade_debug_interface.h: Define our new DebugTypes and DEBUG_UI_ELEMENT" "764": "Run the game and view the profiler" "790": "handmade_debug.cpp: Investigate why the DebugTypes appear in reverse order" "876": "handmade.h: #define DLIST_INSERT_AS_LAST" "954": "handmade_debug.cpp: Make AddGroupToGroup call DLIST_INSERT_AS_LAST" "987": "handmade_debug.h: Add ViewingFrameOrdinal to debug_state" "1068": "handmade.cpp: Add a DEBUG_DATA_BLOCK "Debug Control" for a FrameSlider" "1144": "handmade_debug.cpp: Implement DebugType_FrameSlider" "1324": "handmade_debug.cpp: Introduce DrawFrameSlider" "1571": "Run the game and see that we did totally mess it up" "1580": ""Nice work, Muratori. You're off the team"" "1585": "handmade_debug.cpp: Iterate through the for loop in DrawFrameSlider" "1630": "Song: 'Too Many Frames' by Casey Muratori" "1701": "handmade_debug.cpp: Make ViewingFrame yellow, the color of urine" "1848": "Run the game, view the FrameSlider and explain what will happen when we run out of per-frame arena space" "1969": "handmade_debug.cpp: Switch to a smaller SubArena for the debug information" "2001": "Run the game and hit an assertion when we have insufficient memory to store the debug data" "2132": "handmade_debug.cpp: ZeroStruct the Frame" "2154": "Run the game and watch the FrameSlider as we run out of space to store the debug data" "2282": "handmade_debug.cpp: Provide the ability to interact with the FrameSlider" "2523": "Run the game and crash upon interacting with the slider" "2540": ""Who wrote this ridiculous code?"" "2550": "handmade_debug.cpp: Put the interaction code in the correct place" "2581": "Run the game and interact with the slider" "2618": "handmade_debug.cpp: Replace MostRecentFrameOrdinal with ViewingFrameOrdinal" "2759": "Run the game and find that we can pick the ViewingFrame with the slider, but that the profiler expands weirdly" "3014": "Run the game and investigate why ToggleExpansion is happening" "3212": "handmade_debug.cpp: Conditionally set MostRecentFrameOrdinal if we're paused" "3250": "Run the game and admire the profiler" "3313": "handmade_debug.cpp: Implement the ability to pause the profiler" "3450": "Run the game and try pausing the profiler" "3501": "Demonstrate the fact that we track all of the data" "3600": "Q&A" "3631": "How much would it cost to save draw buffer snapshots so when you pause you can show the visual state it was in, or maybe save enough data to recentre the frame?" "3789": "It is impossible to keep the entire codebase in mind when developing a larger project? How does this impact "code design" decisions in Handmade Hero? What about other, larger projects (e.g. AAA titles)?" "3904": "Originally by Scykoh: "Is the engine portion expected to be the largest chunk of the Handmade Hero project?"" "4015": "Can you please explain again the problem with texture loading? Why does it not work occasionally?" "4074": "Wrap it up and glimpse into the future" --- name: "day264" title: "Adding Buttons to the Profiler" markers: "39": "Recap and set the stage for the day" "143": "handmade_debug.cpp: Switch to using the full memory arena" "249": "handmade_debug.cpp: Rework DEBUGDrawElement with the ability to switch an Element's type" "1077": "Run the game and see that nothing has changed" "1099": "handmade_debug.cpp: Introduce NullEvent to ensure that Events remain printed when their data is null" "1226": "Run the game and see our more pleasant profiler" "1276": "handmade_debug.h: Add DebugInteraction_SetElementType" "1326": "handmade_debug.cpp: Sketch out the call sites for BeginButtonRow, BooleanButton, EndButtonRow and ActionButton" "1676": "handmade_debug.cpp: Introduce ZoomRootInteraction and loft out this functionality into SetElementTypeInteraction" "1861": "handmade_debug.cpp: Implement the Button functions" "2200": "handmade_debug.cpp: Introduce BeginRow and EndRow to automatically wrap lines" "2427": "handmade_debug.cpp: Set the Root to 0" "2452": "Run the game and see that we can't interact with Threads or Frames" "2470": "handmade_debug.cpp: Implement the SetElementType case" "2735": "Run the game and successfully switch between Threads and Frames" "2747": "handmade_debug.cpp: Introduce AdvanceElement to handle spacing and line breaks" "3139": "Run the game and see that we're a little closer to correct" "3189": "handmade_debug.cpp: Make AdvanceElement aware of line heights" "3335": "Run the game and see our correctly carriage-returned information" "3396": "handmade_debug.cpp: Indent in AdvanceElement rather than EndElement" "3504": "handmade_debug.cpp: Make BasicTextElement more responsive" "3614": "Run the game and see the highlighting on hover" "3743": "Q&A" "3803": "(Not a serious question) Why not just import npm and use left pad to indent the strings?" "3832": "I think you were selecting the ground as an entity?" "3846": "[see Resources, John W. Peterson]" "3929": "You know how if you add 1 letter to HAL you get IBM? Did you know if you add one letter to VMS you get WNT?" "3955": "So this interface system is a very simple immediate mode design?" "4008": "Why there are some blue lines outside the profile window sometimes?" "4137": "VS2015, you can use clang as a compiler" "4197": "Are you using clang-cl?" "4243": "You were mentioning before about objects arising as a natural consequence of properly engineered code as the system requires. But do you do not mean a C++ object? So what do you mean as an object?" "4274": "handmade_render_group.h: Demonstrate how "objects" fall naturally out of the code" "4570": "You have a typo in the comment for object_transform" "4634": "Close it down" --- name: "day265" title: "Cleaning Up the UI Layout Code" markers: "1": "Welcome to this special day" "98": "Recap and set the stage for the day" "294": "handmade_debug.cpp: Implement a pause interaction with the FrameSlider" "411": "handmade_debug.h: Add DebugInteraction_SetUInt32" "512": "handmade_debug.cpp: Add another action button for oldest frame" "624": "handmade_debug.cpp: Turn SetElementTypeInteraction into a generic SetUint32Interaction" "1594": "Run the game and see that we are still working" "1698": "handmade_debug_ui.cpp: Pull out the user interface functions from handmade_debug.cpp" "1852": "handmade_debug_ui.h: Pull out the user interface structs from handmade_debug.h" "2200": "A few words on dividing files up" "2229": "Anticipate a programming world without files" "2287": "handmade_debug_ui.cpp: Remove the "DEBUG" prefix from everything" "2468": "handmade_debug_ui.cpp: Introduce BeginLayout and EndLayout in order to make the layout system more robust" "2723": "A few words on the expediency of compression oriented programming" "2795": "handmade_debug_ui.h: Add LineInitialized to the layout struct" "2911": "handmade_debug_ui.cpp: Use LineInitialized in BeginLayout, EndElement and AdvanceElement" "3100": "Run the game and see that our indentation bugs are gone" "3208": "handmade_debug_ui.cpp: Make the buttons look like buttons" "3643": "Run the game and admire our new buttons" "3691": "Q&A" "3729": "Remember to include your new casey_custom in the repo!" "3754": "Spoilers. Holy *** I managed about two months, the plane are reflected when no window currently has the intro?" "3782": "Could you explain your "poor man's lambda"? How it works, how it is like a lambda and how it is not?" "3928": "handmade_debug.cpp: Demonstrate "poor man's closure", or deferring things until later" "4071": "Do you ever turn on unused function / variable warnings?" "4082": "I am currently working on a 3D OpenGL project and implementing collision detection. I've been introduced to the idea of changing my vector space so my character is a perfect unit sphere (which should make collision detection easier). Do you have any opinion on this approach?" "4131": "Blackboard: Using a sphere for collision detection" "4230": "Close this up" --- name: "day266" title: "Adding a Top Clocks Profile View" markers: "95": "A few words on using third-party debugging tools or reusing ones own across projects" "194": "Launch the game and set the stage for the day" "428": "handmade_debug.cpp: Provide the ability to print debug elements in descending order of cycle counts" "589": "stb_truetype.h: Delete" "620": "handmade_sort.cpp: Pull out the sort code from handmade_render_group.h and handmade_render.cpp" "892": "handmade_debug_interface.h: Add DebugType_TopClocksList" "954": "handmade_debug.cpp: Introduce DrawTopClocksList" "1463": "handmade_debug_ui.cpp: Introduce GetBaseline" "1546": "handmade_debug.h: Introduce debug_element_add_op for more fine-grained control of how elements are profiled" "1871": "Run the game and view our DrawTopClocksList ouput" "1971": "handmade.cpp: Do TopClocksList by default" "2055": "handmade_debug.cpp: Darken the list's background" "2187": "handmade_debug.cpp: Just print out the elements' names" "2249": "Note that the Win32 Message Processing takes drastically longer when the mouse is moved" "2314": "handmade_debug.h: Add Sum to debug_statistic" "2483": "handmade_debug.cpp: Provide DrawTopClocksList the ability to print out percentages" "2813": "handmade_debug.cpp: Prepare DrawTopClocksList for sorting" "3104": "Run the game and see our sorted TopClocksList" "3164": "handmade_debug.cpp: Add the Count and Percentage to the list" "3303": "Run the game and view our TopClocksList" "3371": ""We won't add up to 100%"" "3480": "Q&A" "3562": "Can I avoid taxation by reinvesting into capital gains?" "3584": "Why won't we add to ~100%?" "3642": "How would you self-update an exe? Right now I have a second exe that copies a file that overwrites the current exe. So main exe calls updateme.exe, closes itself, updateme sleeps for 1/2 second, then copies... There's gotta be something smarter" "3687": "Can the percentage support a decimal place?" "3706": "handmade_debug.cpp: Print the percentage as a float" "3772": "How may you go about investigating the cycle count increase for the Input Processing when the mouse is moved?" "3829": "Admire the profiler" "3967": "win32_handmade.cpp: Bring PeekMessage out of the while condition and put it in a TIMED_BLOCK" "4098": "Owl of Shame Moment: The platform code does not get dynamically reloaded" "4141": "Compile and run and see PeekMessage in the profiler" "4162": "handmade.cpp: Move the FrameSlider into the Profile block" "4275": "%5.2f" "4311": "My problem is the exe downloads a new exe, then I want it to replace itself, but I can't delete the running exe or even rename it while it's running. I'm fine with the game going down and coming back up, it's for updating players, not for development" "4395": "win32_handmade.cpp: Implement the ability to replace and auto-reload a running executable" "4794": "Internet: MoveFile" "5249": "Try to replace handmade.exe with notepad.exe" "5460": "win32_handmade.cpp: Fix the condition of Win32TimeIsValid" "5650": "Try to replace handmade.exe with ColorCop.exe" "5716": "Debugger: Try to launch and kill" "5835": "Wind things down" "5907": "Promote 4coder" --- name: "day267" title: "Adding Per-Element Clipping Rectangles" markers: "60": "Recap and set the stage for the day" "307": "Pig Hat Time" "314": "handmade_debug.h: Add Duration and DurationOfChildren to debug_profile_node in order to separate out the clocks" "366": "handmade_debug.cpp: Compute the DurationOfChildren and make the TopClocksList exclusive of the children" "566": ""Clocks without children"" "605": "Run the game and see a clearer picture of where our time is being spent" "707": "handmade_world_mode.cpp: Make UpdateAndRenderWorld a TIMED_FUNCTION" "762": "Run the game and see what takes the time" "870": "handmade_debug_interface.h: Make RecordDebugEvent take Name rather than DEBUG_NAME" "961": "handmade_world_mode.cpp: Insert some TIMED_BLOCKs in UpdateAndRenderWorld" "1044": "Run the game and see that GroundChunksOn takes up so much of the time" "1055": "handmade_world_mode.cpp: Nuke GroundChunksOn and consult the profiler again" "1234": "handmade_debug.cpp: Clip the profiler drawing to ProfileRect.Min.Y" "1607": "Blackboard: Picking the correct line to clip to" "1652": "handmade_debug.cpp: Make the profiler overdraw by one line" "1710": "View the profiler and see this overdrawing" "1937": "handmade_render_group.h and .cpp: Consider how to enable the bitmaps to be clipped" "2204": "Blackboard: Respecifying bitmaps" "2342": "handmade_render_group.h: Try to introduce render_entry_cliprect, to pass the clipping area down the stream" "2405": "handmade_opengl.cpp: Consider the problem with sorting" "2546": "handmade_render_group.h: Add ClipRect to render_entry_bitmap and ClipRectIndex to render_group_entry_header in order allow clipping while sorting" "2656": "handmade_opengl.cpp: Call glScissor" "2710": "handmade_platform.h: Add ClipRectCount and *ClipRects to game_render_commands" "2969": "handmade_render_group.h: Introduce game_render_clip_rect" "3141": "handmade_render_group.h: Set CurrentClipRectIndex for the entire window in Perspective" "3337": "handmade_render_group.cpp: Introduce PushClipRect" "4005": "win32_handmade.cpp: Make Win32DisplayBufferInWindow take ClipRectMemory and to call LinearizeClipRects" "4233": "handmade_render.cpp: Introduce LinearizeClipRects" "4587": "Run the game and hit an InvalidDefaultCase" "4739": "handmade_render_group.cpp: Guard against overflow in PushClipRect" "4950": "handmade_debug.cpp: Do a PushClipRect in DrawTopClocksList" "5106": "Debugger: Step into ClipRectIndex and inspect the values" "5165": "handmade_opengl.cpp: Enable GL_SCISSOR_TEST" "5195": "View our correctly clipping profiler" "5247": "handmade_opengl.cpp: Disable GL_SCISSOR_TEST in OpenGLDisplayBitmap" "5280": "handmade_render.cpp: Implement clipping in the software renderer" "5352": "Blackboard: Intersecting tiles" "5521": "View the profiler and see that it clips in both renderers" "5550": "Q&A" "5651": "What are top three reason for FPS to go down?" "5676": "Will ClipRect be used outside of debug, and where?" "5746": "Can you elaborate on the ODE you plan to replace your drag function with in MoveEntity?" "5760": "How about making the toplist scrollable? Since we now clip it, can be painful when you start profiling a lot more" "5810": "When does clipping overdrawn areas cost more than just drawing them?" "5892": "That's not entirely true, the state change on the clip isn't free, and if the size change is minor it's probably not worth it" "5951": "When you switch between the renderers, the viewing frame time is (obviously) affected. Are the clocks in our newly clipped box also affected by the renderers, i.e. ordered / distributed differently?" "5976": "build.bat: Switch to -O2 and -DHANDMADE_SLOW=0 and view the profile" "6059": "handmade_render.cpp: Ignore IGNORED_TIMED_FUNCTION and IGNORED_TIMED_BLOCK" "6305": "handmade_render.cpp: Ignore DrawRectangle and "Pixel Fill"" "6434": "What does OpenGL do when you enable gl_scissor_test? What is it testing for?" "6455": "Blackboard: glScissor" "6502": "Wrap it up" "6526": "build.bat: Switch back to -Od and -DHANDMADE_SLOW=1" "6530": "todo.txt: Update the TODO list" "6594": "Announce that the forums will be going down this weekend [note: actually the 22nd April]" --- name: "day268" title: "Consolidating Debug Links and Groups" markers: "110": "Recap and set the stage for the day" "419": "handmade_debug.cpp: Delete a load of superfluous code" "530": "4coder: Rare crash" "624": "handmade_debug.h: Rename DEBUGDrawMainMenu to DrawTrees and split it out into a recursive function called DrawTreeLink" "923": ""Sweet child of mine"" "1297": "handmade_debug.cpp: Make DrawTrees call DrawTreeLink" "1356": "View our improved profiler and consider how to proceed with it" "1763": "Debugger: Jump into DrawTrees and inspect the Tree after cloning" "2114": "handmade_debug.h: Turn debug_variable_link into a linked struct with a fake Sentinel and port everything to it" "3294": "handmade_shared.h: Make StringsAreEqual handle NULL" "3409": "View our profiler and see that cloning works again" "3419": "handmade_debug.cpp: Make CloneVariableLink just do the direct clone and return it" "3545": "Test cloning the profiler" "3599": "Q&A" "3643": "I feel I kinda lost the forecast for the trees this episode. Would you mind recapping?" "3666": "Blackboard: Linked structs" "4372": "Blackboard: Walking the tree with a recursive function" "4538": "Thoughts on linked lists, and cache friendliness? I found that a simple array, and just copying when it changes length, was way faster" "4628": "Blackboard: Cache friendliness" "4872": "Concurrency also matters. Linked lists can be better if you need multiple threads working on the list at the same time" "4908": "How do you feel about object pools as a sort of middle ground between linked lists and arrays?" "5059": "Wrap it up" --- name: "day269" title: "Cleaning Up Menu Drawing" markers: "66": "Recap and set the stage for the day" "202": "handmade_debug.cpp: Just pass the Group to the DrawTreeLink call in DrawTrees" "265": "View the Root menu in the profiler" "331": "handmade_debug.cpp: Make the FrameSlider resizable" "456": "Try resizing the FrameSlider" "555": "handmade_debug.cpp: Make the Thread view in DrawProfileBars look a little nicer" "625": "View the Thread view and note that the hover text gets clipped" "680": "handmade_debug.cpp: Make DrawProfileBars draw multiple levels of Events" "875": "View the multiple levels in the profiler" "939": "handmade_debug.cpp: Correctly Z-sort the Events" "1016": "View the correctly Z-sorted levels" "1083": "handmade_debug.cpp: Make DrawFrameBars also draw multiple levels" "1118": "View our multiple levels of Frames" "1197": "handmade_debug.cpp: Make DrawFrameBars brighten the currently viewed frame" "1406": "View the Frames view and consider improving the tooltips" "1554": "handmade_debug_ui.cpp: Introduce AddTooltip" "1934": "handmade_debug.cpp: Introduce MouseTextLayout" "2074": "handmade_debug.cpp: Make the DrawFrameSlider call AddTooltip" "2098": "View the profiler and correctly see no tooltips" "2105": "handmade_debug_ui.cpp: Make AddTooltip functional" "2448": "View the tooltip and see that it still clips" "2505": "handmade_debug.cpp: Accidentally make TextOutAt immune to the graphs' ClipRects" "2620": "View the correctly not-clipping Tooltip, but find that the Threads view is not being clipped correctly" "2729": "handmade_debug_ui.cpp: Instead make AddTooltip immune to the graphs' ClipRects" "2784": "View the profile and find that our clipping is restored to proper working order" "2827": "handmade_debug.cpp: Make the Root print out arbitrary stuff" "3487": "View our new info in the menu" "3504": "Q&A" "3547": "What is the purpose of the internal syntax?" "3604": "I loath how the compiler tells you there is a param mismatch instead of telling you a list of actual params vs the ones you typed. It could at least try to be helpful! Is this an unsolved problem in computer science?" "3656": "What were the abbreviations in the new menu header?" "3777": "People have asked before what your thoughts are on functional languages in general, but I'm curious what your thoughts are specifically on the constructs they emphasize that other languages don't, for example closures and partial application (i.e. foo taking x, y, z being called with foo x y returning a closure that takes z)" "3900": "Does the debug bitmap viewer work now when you select an entity?" "3933": "handmade_debug.cpp: Draw the bitmap on top in DEBUGDrawElement" "4009": "handmade_world_mode.cpp: Provide the ability to draw debug bitmaps using their BID" "5036": "Run the game and see that we can write to the bitmap_id reliably" "5075": "handmade_debug.cpp: Ensure the bitmap gets drawn on top" "5166": "Are we going to make a bitmap of the memory that is used / unused and when we select a unit, show where in the memory arena it is?" "5204": "handmade_debug_interface.h: Add DebugType_ArenaOccupancy" "5390": "handmade_debug.cpp: Introduce DrawArenaOccupancy" "5810": "handmade.cpp: Add a Memory DEBUG_DATA_BLOCK for the three Arenas" "6270": "handmade_debug.cpp: Provide the ability to toggle the arena occupancy graphs" "6317": "Run the game and view our new graphs" "6359": "handmade_debug.cpp: Label these occupancy graphs" "6488": ""It's all white, like Donald Trump's America"" "6497": "Run the game and view our labeled occupancy graphs" "6620": "Close down for now" "6645": "Announce that the Handmade Hero forums will be going down this weekend while Handmade Network launches" --- name: "day270" title: "Making Traversable Points" markers: "40": "Recap and set the stage for the day" "155": "Design: Room-based camera movement" "319": "handmade_world_mode.cpp, handmade_asset.cpp and handmade.cpp: Delete the ground chunks" "464": "Run the game and see exactly the same thing" "509": "Blackboard: Tile- or cell-based movement and combinatorics" "952": "handmade_sim_region.h and handmade_world_mode.cpp: Transform EntityType_Space into EntityType_Floor to respecify the world as being built up rather than carved out" "1444": "Run the game and see that the floor tiles can be picked" "1467": "handmade_world_mode.cpp: Draw the tiles" "1496": "Run the game, see our new floor tiles and consider how to use them" "1598": "handmade_world_mode.cpp: Conditionally set the Traversable flag based on the tile" "1663": "Run the game and see the traversable flag in action" "1865": "handmade_sim_region.h: Introduce sim_entity_traversable_point" "1997": "Blackboard: Snaky paths" "2095": "Consider formalising the location of entities" "2252": "handmade_sim_region.cpp and .h: Remove Gravity, ZSupported and the Traversable code in MoveEntity" "2507": "handmade_world_mode.cpp: Introduce MakeSimpleFloorCollision" "2892": "Run the game, continuously move upwards and investigate why" "3248": "handmade_world_mode.cpp: Stop making space bar trigger the jump" "3294": "Run the game and stay on the floor" "3308": "Q&A" "3406": "So how will this tile-based movement work? Will you still be able to move freely within a tile, or will the character actually "snap" to a tile?" "3426": "When will we sort out the coordinate system?" "3451": "Is it possible to get access to the source code if I lost access to my old email account?" "3533": "How about stairwells? Their traversal used to be seamless, as far as I remember. Now that the rooms are locked, how will stairwells work?" "3573": "Any plans on changing to Visual Studio Code instead of the full IDE? I believe the full debugger is included" "3613": "What are the benefits / trade-offs in having each tile be an entity?" "3764": "Are you allocating your entities on the heap or stack? Heap, right? Could you even allocate enough stuff on the stack?" "3947": "Do you foresee complications with the new grid entity floor system and the texture splats given you want a variable height per Traversable entity?" "3985": "Handle Rbnelr confusion over atomics" "4013": "So if modern CPUs usually reorder or merge writes, how do they use memory mapped registers? Can you even bit-bang a serial protocol with it?" "4170": "What is the plan with rendering when the hero walks behind a piece of terrain that is on a higher level, and obscures the hero?" "4199": "Will this system fix the collision areas getting stuck in each other if stacked, e.g. two heroes loading at the same position?" "4248": "Shut down" "4276": "Announce that the Handmade Hero forums will be going down this weekend while Handmade Network launches" --- name: "day271" title: "Hybrid Tile-based Movement" markers: "20": "Recap and set the stage for the day" "232": "handmade_sim_region.h and handmade_world_mode.cpp: Disassociate the hero's head and body" "1057": "Run the game and move the head" "1106": "handmade_world_mode.cpp: Make the body follow the head along the traversable points" "1725": "handmade_sim_region.cpp: Introduce GetSimSpaceTraversable" "1922": "Run the game and see the body following the head" "2046": "handmade.cpp: Start up directly into the game, rather than the cutscene" "2162": "Debugger: Jump into PlayWorld and investigate what's going on" "2506": ""That's just super accidental"" "2565": "handmade_world_mode.cpp: Set WorldMode in PlayWorld" "2674": "handmade.cpp: Force the start button to be pressed" "2822": "Run the game and arrive directly at the game" "2923": "win32_handmade.cpp: Correct the GameUpdateHz computation" "2999": "Run the game and move at the more correct speed" "3072": "handmade_world_mode.cpp: Make the body accelerate towards the traversable points" "3425": "Run the game and see the body accelerate towards the head" "3578": ""My body will track me, but it will never come to rest"" "3610": ""I want the head to snap back to the body when you stop pushing"" "3629": "Q&A" "3658": "When I write event-driven code, I am often forced to use dynamic memory allocation to preserve some state until it is needed by the callback. How do you deal with those situations?" "3815": "Would the Handmade debug view enable viewing structs like world mode?" "3838": "When moving diagonally, will it be clear to the player which way the body will go to get to the diagonal entity? Right now it seems kind of random" "3955": "handmade_world_mode.cpp: Introduce DesiredDirection in order to make the body move more directly to the head" "4048": "handmade_math.h: Introduce NOZ (Normalize or Zero)" "4334": "Run the game and try out our new movement" "4357": "handmade_world_mode.cpp: Conditionally set the closest point" "4443": "Run the game and see the body stopping more close to the points" "4521": "handmade_world_mode.cpp: Revert to the original movement" "4603": "This may just be an illusion but it looks like the body is snapping to the corner of tiles. Usually in tile-based games, entities occupy the center of a tile. Is this intentional?" "4642": "handmade_world_mode.cpp: Make MakeSimpleFloorCollision draw the tiles" "4681": "Run the game, see the tiles and move around on them" "4720": "At the end of Q&A, can you announce a reminder that the forums are going down shortly?" "4734": "handmade_world_mode.cpp: #if 0 that tile drawing" "4748": "Close up shop" "4805": "Announce that the Handmade Hero forums will be going down very soon while Handmade Network launches" --- name: "day272" title: "Explicit Movement Transitions" markers: "19": "Announcement: Handmade Network has launched" "347": "Recap and set the stage for the day" "770": "Blackboard: Stand and Movement as two separate modes" "865": "Blackboard: Finite State Machines" "1138": "handmade_sim_region.h and handmade_world_mode.cpp: Implement the ability to switch between two movement modes" "1407": ""Nobody cares about square root at all anymore"" "1657": "Debugger: Step into the movement code and find that we're oscillating between the modes" "1736": "Run the game and find that we stop" "1751": "Blackboard: Hopping and changing course" "2066": "Blackboard: Gravity's arc and parabolas" "2254": ""That's... math"" "2318": "handmade_world_mode.cpp: Give the hero a parabolic hop" "2643": "Blackboard: An equation to calculate the hop parabola" "3189": "handmade_world_mode.cpp: Implement this hopping equation" "3338": "Run the game and see the movement with A set to 0" "3386": "handmade_world_mode.cpp: Make the hop parabolic" "3423": "Run the game and see the parabolic hop" "3508": "A few words on the concept of reducing algorithms down to a smaller set of variables" "3547": "Q&A" "3576": "No Q&A because xanbot banned hmd_bot" "3621": "That hopping looks so cool. Can we see a little more of it?" "3683": "How did you split the head from the body?" "3694": "How interesting do you think it would be to solve for the "force" and direction required to reach a certain height on each jump? Is it just more work than it's worth for no tangible gain?" "3768": "I am guessing that both the familiar and enemies will need to move similarly to the hero. Is there much more you need to do to make this work with them?" "3786": "Can we clean up the extra head and body on screen, or are they going to be used later on?" "3828": "Why doesn't the head just head just stay on top of the body? Is that a bug?" "3891": "When writing in a procedural, I sometimes end up with deeply nested code. Should this be avoided and are there good ways to minimize this?" "3936": "This is starting to look a lot like Crypt of the Necrodancer" "3964": "Missed a lot. Are you making an engine for this game or is that stuff just there purely for you / us right now?" "4064": "Debugger: Step into RenderCommandsToBitmap and see what's happening with the Clear" "4236": "handmade_render.cpp: Set the transparency that's passed to Clear" "4274": "Run the game and see our software renderer successfully clearing" "4378": "When Z-axis is defined will up / down hopping look different?" "4397": "What are limitations of game development using C#? Do you like C# overall as a language?" "4437": "What parts of C++ are you using if you are not programming in an OOP style?" "4458": "I'm currently using a Microsoft Natural Ergonomic 4000. Thinking about replacing it with a non-ergonomic mechanical keyboard. Thoughts?" "4504": "How many A's will this game have when it's done?" "4512": "The trees on the bottom row look like they are being clipped at the top. Also C# is compiled these days to some extent" "4584": "Is that a real clicky keyboard or is it just sound effects" "4648": "Have you seen very much of apple's Swift? What are your thoughts on it now that it is open source?" "4667": "How come I have to declare a political party in order to vote in the presidential primary" "4705": "Assets: Check out the tree bitmap, and note that the reason for clipped-like looking tree assets is that they don't have the 1-pixel apron" "4872": "Wind down" "4919": "Announce the upgraded forum site on Handmade Network" --- name: "day273" title: "Animation Overview" markers: "60": "Recap and set the stage for the day" "143": "Blackboard: Animation" "282": "Blackboard: Exposure Time and Intervals of Time" "566": "Blackboard: Instantaneous Animation" "1046": "Blackboard: Doing Numerical Integration with Euler steps to compute Instantaneous Animation" "1158": "Blackboard: Lots of functions of lots of t's" "1291": "Blackboard: Physics and Animation" "1375": "Blackboard: Animation techniques: B-splines and Euler angles" "1484": "Blackboard: Orders of B-splines" "1790": "Blackboard: Parameter Spaces, State Vector and Generalized Coordinates" "2174": "Blackboard: "Position Vector" vs "State Vector"" "2284": "Blackboard: The animation pipeline: Stored -> Render Input -> Sprite List" "2387": "Blackboard: "Skeletal animation"" "2549": "Blackboard: Rendering the animation" "2643": "Internet: The Illusion of Life: Disney Animation" "2698": "Blackboard: Anticipation and Follow-through" "2853": "Blackboard: Using "map into range" to split up the animation phases" "3045": "handmade_world_mode.cpp: Add these phases to the body's hopping animation" "3200": "Run the game and look at the jump" "3220": "handmade_world_mode.cpp: Give the body some springiness" "3314": "Blackboard: Using sine to compute the curve" "3457": "Run the game and see the springiness" "3523": "handmade_world_mode.cpp: Animate the ballistic phase" "3681": "Run the game and check out the hop" "3699": "handmade_world_mode.cpp: Give the animation some follow-through on the landing" "3734": "Run the game and check out the hop" "3768": "handmade_world_mode.cpp: Speed the hop back up again and check it out" "3830": "Q&A" "3852": "handmade_world_mode.cpp: Set the Entity->FacingDirection" "3885": "What's the difference between B-splines and Bezier curves?" "3900": "Blackboard: Bezier vs B-spline curves" "3954": "Blackboard: Bezier curve" "4246": "Blackboard: B-spline curve" "4482": "From a beginner's perspective, it seems that in software rendering, keeping "milliseconds per frame" in a certain controlled boundary is somewhat in the programmer's control (depending on the code quality and orientation towards performance). Does that become more difficult when going into hardware rendering (with drivers) territory? Or is it the other way around?" "4526": "Are we going to do any compression on the image, or only movement of the torso?" "4545": "Which game design decision requires hopping / tilejumps as opposed to the previous way of moving the hero?" "4564": "Is it possible to create animations like Looney Tunes where looking at still frames you could see multiple heads and limbs or features that are extremely exaggerated and distorted? Somehow it still looks fine in motion. Smear animation is a term I could find in 30 seconds of googling" "4647": "Why not use java instead of C?" "4822": "Jmonkey and LWJGL are professional open source libraries that are written in java, just to name a couple" "4924": "Probably time to just take questions from the Handmade Network IRC?" "4976": "In order to stretch the body to the head will we implement shearing in the SE?" "4998": "What would your ideal game programming language look like?" "5016": "Have you seen this video on Ubi's Rayman 2D animation editor?" "5065": "Will the animation function eventually be moved out so other entities can use them?" "5070": "s it recommendable to mix vector and raster graphics for a game?" "5086": "David Rosen at Wolfire had a GDC talk on procedural animation. Have you seen it? If so, thoughts? [see Resources: Wolfire Blog]" "5214": "How close is humanity to programming a facsimile of our universe?" "5223": "What do you have to say about the researchers that claim that java can be faster than C++ at times?" "5313": "It's pretty great. Also, re: metaprogramming, did you see Per Vognsen's btree metaprogramming thingy? Apparently it copies Jeff Roberts' AVL-tree configurability scheme" "5327": "Runescape is a browser based MMO" "5441": "Q: Minecraft was ported to C++ I thought" "5469": "The win10 edition is C++" "5504": "Wrap it up" --- name: "day274" title: "Dynamic Animation with Springs" markers: "42": "Recap and set the stage for the day" "112": "handmade.cpp and handmade_config.h: Introduce and make Global_Timestep_Percentage editable with the debug system" "240": "Run the game reduce that Global_Timestep_Percentage" "421": "handmade_world_mode.cpp: Look at the current hopping code and consider doing physics simulation on the springiness" "605": "Blackboard: Tracking the velocity and target position of the cape" "792": "handmade_world_mode.cpp: Simulate tBob using the standard equations of motion" "972": "handmade_world_mode.cpp: Set the acceleration to 0 and see that there's no movement on that joint" "996": "handmade_world_mode.cpp: Set a loop and tweak the hopping variables" "1320": "handmade_world_mode.cpp: Restore the position to 0" "1455": "handmade_world_mode.cpp: Simulate the landing phase" "1859": "handmade_world_mode.cpp: Tune the hop" "1961": "Control the hero directly and see that the hop is oscillating" "1984": "Blackboard: Springs" "2097": "Blackboard: Undamped spring" "2248": "handmade_world_mode.cpp: Add that undamped spring equation" "2311": "Blackboard: How this spring equation works" "2405": "Blackboard: Under-, over- and critically-damped springs" "2552": "handmade_config.h and handmade_world_mode.cpp: Run at 100% global speed and slow down the head and jump" "2641": "handmade_world_mode.cpp: Tune the downward motion on the anticipation phase" "2804": "handmade_world_mode.cpp: Consider making the head snap back to the body when stationary" "2955": "Blackboard: Applying the spring technique in different directions" "3453": "handmade_world_mode.cpp: Implement this spring equation for the head" "3881": "Rerun the game and get that restorative force, but see that the facing direction is being affected by something" "4032": "Blackboard: Recentering the head along the body's axis of movement" "4079": "handmade_world_mode.cpp: Recenter the head" "4573": "handmade_world_mode.cpp: Introduce a non-normalised ddP2 in order to compute the spring" "4641": "Run the game and see that the problem is fixed" "4676": "Q&A" "4710": "The other day ingenero likened the new movement to Crypt of the Necrodancer. I like that game and see where they're coming from, but Handmade Hero already looks like it feels so much sweeter to play" "4744": "I've probably missed it, but what exactly prompted switching the hero movement from analogue-rolling to digital-tile-based-wiggle-hopping?" "4784": "Does math exist?" "4787": "Is the body always going to move on a fixed grid?" "4838": "Can we get a keyboard cam?" "4852": "Will the player be able to see the points in the design" "4873": "Is the body going to lean towards the head or is it gonna stay detached?" "4924": "Shouldn't the head always draw on top of the cape?" "5011": "Will other entities only travel on these points, too? Or can they move freely?" "5048": "Is there a name for this technique of blending canned and simulated animations? Is it a common thing allowed in animation / 3D packages?" "5176": "Why would I use an animation package instead of doing what you just did (and whatever you will do)?" "5336": "Is there any plan for eventual addition of music?" "5374": "Ham-handed Q, could you use neural networks and make something like Boston Dynamics 'BigDog'?" "5477": "Close it up" --- name: "day275" title: "Passing Rotation and Shear to the Renderer" markers: "92": "Recap and set the stage for the day" "161": "A few words on responsiveness vs aesthetics" "361": "handmade_world_mode.cpp: Introduce GetClosestTraversable to enable the HeroHead as well as the HeroBody to search for and snap to the closest point" "700": "Run the game and see the head snap" "733": "handmade_sim_region.cpp: Make the head keep facing in the direction is was going" "799": "Run the game and watch the head's facing direction" "882": "handmade_world_mode.cpp: Disable the sword in favour of implementating strafe hop" "943": "Run the game and try out the strafing" "995": "handmade_world_mode.cpp: Make the head not recentre" "1039": "Run the game and try the movement" "1056": "handmade_world_mode.cpp: Use a weaker spring to recentre the head" "1112": "Run the game and try out the recentering" "1143": "handmade_world_mode.cpp: Make the head not recentre" "1189": "Run the game and try out the movement" "1387": "handmade_render_group.h: Add XAxis and YAxis to render_entry_bitmap" "1519": "handmade_opengl.cpp: Make OpenGLRenderCommands work with render_entry_bitmap" "1636": "Blackboard: Handling parallelograms" "1749": "handmade_opengl.cpp: Calculate the four points" "1971": "handmade_render.cpp and handmade_render_group.cpp: Make DrawRectangleQuickly and PushBitmap work with render_entry_bitmap" "2069": "Run the game and see that everything is messed up" "2101": "handmade_open.cpp: Correct the point calculation" "2116": "Blackboard: How we are calculating the points" "2155": "Run the game and see that we're good" "2166": "handmade_render_group.cpp: Consider how best to specify the axes" "2512": "Blackboard: Rotating the body's YAxis to point to the head" "2825": "handmade_render_group.cpp: Make PushBitmap and GetBitmapDim take XAxis and YAxis" "3057": "handmade_world_mode.cpp: Make the body's YAxis point towards the head" "3531": "Run the game and admire the stretching" "3582": "Q&A" "3619": "Zircon encrusted tweezers? Are you moving to Montana soon?" "3633": "Why does our limbless hero need suffer in such gruesome ways" "3659": "Do I need the payed version of Mischief to change the background color?" "3689": "Will you try rotation to visually compare against shearing before deciding?" "3746": "You wrote the scale / shear this way because it's already done in the software renderer but these transformations would usually be done in a vertex shader, right?" "3832": "Some other games have done similar move styles, but they use a floating indicator instead of separating the head from the body. Your thoughts?" "3846": "For collision detection will there be skewed boxes as well or will it just be AABB?" "3875": "So we move tile to tile? Haven't seen the new movement" "3886": "Are we eventually going to move these over to shaders?" "3983": "Any word on the new debugger?" "4029": "You had a stream about someone contacting you about making a debugger" "4130": "I doubt the concept of shaders is going anywhere soon" "4377": "Do you think you'll use the spring code from the other day on the camera movement? I'm imagining a critically damped spring would be the thing to use for that" "4526": "For camera stuff I just do x += (x - dest) / 10 or something like that. What would that be?" "4580": "That's not accounting for t, that's if it was instantaneous" "4648": "Should be (dest - x) I'm assuming" "4662": "I used to do like fixed FPS, so it was fine, but I've changed. Hold on I'll look it up" "4684": "Blackboard: GarlandoBloom's camera movement" "4866": "Plans on adding camera shake or blur or similar if the hero gets hit or a bolder hits the ground near the hero?" "4924": "Wrap it up" --- name: "day276" title: "Tuning the Body Animation" markers: "77": "Run the game, demo our problem with the stretching not looking great and consider moving to a more top-down perspective" "192": "Blackboard: How top-down art may solve the detachment problem" "315": "Run the game and demo the lack of collision on the side walls" "450": "handmade_world_mode.cpp: Move the head down and draw it in front of the cape" "509": "Blackboard: How the art assets are currently packed" "613": "handmade_render_group.cpp: Investigate the sorting" "717": "Debugger: Break on PushBitmap for the cape and head and inspect their SortKey" "963": "handmade_world_mode.cpp: Sort the body parts slightly more correctly" "1182": "handmade_world_mode.cpp: Limit the shearing" "1454": "handmade_world_mode.cpp: Mitigate the separation problem" "1953": "Run the game and consider disallowing diagonal movement" "2069": "handmade_world_mode.cpp: Disallow diagonal movement" "2341": "Run the game and try out the cardinal movement" "2534": "handmade_world_mode.cpp: Clean up the controller code" "2749": "Run the game and try out the controller code" "2781": "handmade_world_mode.cpp: Re-enable the head's recentering code" "2804": "Run the game and try out the recentering" "2852": "handmade_world_mode.cpp: Delay the recentering" "2995": "handmade_math.h: Introduce ClampAboveZero" "3161": "Run the game and try out the delayed recentering" "3307": "Q&A" "3331": "Do you think like a sort of rhythmic based movement where the hero would have to wait a bit before being able to move again (say he's getting ready for a jump instead of stamina-lessly jumping around non-stop) could perhaps help in this situation? Realise it's a design decision and might not be what you're looking for, but perhaps you haven't entertained the idea" "3381": "Do you think rotating the torso would help?" "3432": "For the Q&A can you have the hero walk around on a live loop?" "3464": "Try wrapping the body around bezier rather than just linear stretching?" "3504": "For the up-down motion, couldn't you forgo the stretch, and have a jump of each part?" "3518": "Why wouldn't you shear the top of the feet to stay under the moving body?" "3551": "What about a small translation of the body before and after the jump, say 10%-20% of the distance between adjacent dots?" "3592": "handmade_world_mode.cpp: Displace the body based on the distance of the head from the nearest traversable point" "3906": "Run the game and check out the displacement" "3935": "handmade_world_mode.cpp: Apply the floor displacement only to the cape" "3956": "Run the game and check out the cape's displacement" "3995": "The more I see the more I like this. I wonder whether a subtle head bob may add a feeling of believability. Just a thought" "4067": "Would it help if the body stayed on the tile, but the cape was positioned between the body and the head?" "4101": "Consider asking Yangtian for art that is more top-down" "4188": "Perhaps a minimum stretch length so you don't get disappearing bitmaps while moving down?" "4203": "Close up" "4241": "Announcement: HandmadeCon 2016" --- name: "day277" title: "The Sparse Entity System" markers: "14": "Introduce Milton" "85": ""I have no idea how to say Sergio properly, let alone sexily"" "382": "Recap and set the stage for the day" "627": "Blackboard: Entity systems" "887": "Blackboard: Current compositional approach" "1020": "Blackboard: Looking Glass's Act / React Model" "1288": "Blackboard: Problems with the AOS approach" "1485": "Blackboard: Sparse Entity System" "1626": "Blackboard: Inheritance" "2204": "Blackboard: When inheritance falls apart" "2425": "Blackboard: "Inheritance is compression"" "2807": "Blackboard: One epically huge entity struct" "3084": "Blackboard: Sparse matrix solver" "3157": "Blackboard: Summary of the plan" "3277": "Q&A" "3336": "Can you talk about the dynamic dispatch?" "3369": "Blackboard: Dispatch" "3653": "Blackboard: C++'s implementation of dynamic dispatch" "4050": "Blackboard: Why our system won't use dynamic dispatch" "4192": "Do you use the struct entry method in your current game?" "4222": "Have you seen my psuedo-hacked discriminated union inheritance system that I use in my game on stream? It's pretty cool" "4252": "What made you choose this approach over an AoS style + storing indices of each separate component in the main entity struct?" "4287": "I missed it. What about the matrix [i,j]? I was confused there" "4344": "How and where would you go about checking if a property existed on your 'mega-struct' whenever you want to do your operations? Would they all be null pointers if undefined?" "4395": "What are you going to use to track which struct members have been touched / set back to null?" "4453": "What portions of this design could you foresee causing perf issues?" "4742": "What are some alternatives to an entity system?" "4861": "Are you already thinking of a backup plan for the entities and how you would transition to that system if you had to?" "4947": "Do you play Street Fighter? Who is your favorite character?" "5034": "Will the entity system include things such as particle effects?" "5073": "Did you play Bomberman?" "5077": "You can't stand the Street Fighter pause but you liked the Mortal Kombat rotoscope?" "5127": "Yeah that seems reasonable, it does seem unlikely that you'd get 300 entities needing 60FPS simulation except, as you say, bullet hell with bullets-as-entities rather than being their own optimized thing" "5257": "Close down" --- name: "day278" title: "Moving Entity Storage into World Chunks" markers: "89": "Recap and set the stage for the day" "314": "Blackboard: How the simulation region streams in entities as you traverse the world" "572": "Blackboard: Entities referencing each other" "749": "handmade_world.h: Add a read / writeable EntityData and EntityDataSize to world_entity_block" "892": "Debugger: Compile and run and hit an assertion in PushSize_" "1011": "handmade_world.h: Change ChunkHash in world to be a pointer and add the Chunks as a singly-linked list" "1326": "handmade_world.cpp: Introduce ClearWorldEntityBlock" "1445": "handmade_world.cpp: Clean up CreateWorld" "1475": "Run the game and see what happens" "1489": "handmade_sim_region.cpp and handmade_world_mode.cpp: Excise the sword" "1586": "Run the game and find that we're still running okay" "1595": "handmade_world_mode.h: Remove the LowEntities from game_world_mode" "1745": "handmade_sim_region.cpp: Rewrite LoadEntityReference so that an entity can only been accessed if it is within your simulation region" "1846": "handmade_sim_region.cpp: Make BeginSim store the actual entities instead of indices" "2154": "handmade_sim_region.cpp: Disable some of EndSim for now just to see what breaks" "2226": "handmade_world_mode.cpp: Introduce BeginLowEntity and EndLowEntity and split AddLowEntity out into these functions in order to create a low entity and then pack it into its actual position location" "2863": "handmade_world_mode.cpp: Introduce PackEntityIntoChunk to be called in EndLowEntity" "2957": "handmade_sim_region.cpp and handmade_world_mode.cpp: Work through a plethora of compile errors to use entity_id" "3889": "Q&A" "3949": "This is more of a meta-question but I found myself placing TODOs in my code at places that I don't want to deal with while I work on something else. However, as we all procrastinate, how come back to the TODOs?" "4013": "What's the highest number of errors you've ever had after compiling?" "4029": "I arrived too late to the prestream to let you know that yesterday's episode hasn't yet made its way to YouTube" "4050": "Wrap it up" --- name: "day279" title: "Finishing World Chunk Entity Storage" markers: "52": "Blackboard: Why make an entity system using a SOA (Struct of Arrays) rather than an AOS (Array of Structs)" "293": "Recap and set the stage for the day" "590": "Explain the problem with pulling the world_entity_blocks out of the ChunkHash" "672": "Blackboard: Transactional Memory" "964": "Blackboard: Making the entity system multithreaded" "1163": "handmade_sim_region.cpp: Make BeginSim remove the Chunks and Blocks, and return them to the free list" "1355": "handmade_sim_region.cpp: Make EndSim pack the entities into a new chunk" "1832": "handmade_world.cpp: Delete ChangeEntityLocation and clean up compile errors" "2067": "Anticipate 4coder's code intelligence" "2152": "handmade_world_mode.cpp: Replace low_entity with entity" "2192": "handmade_sim_region.h: Replace sim_entity with entity" "2462": "handmade_world.cpp: Remove ChangeEntityLocationRaw and introduce PackEntityIntoWorld" "2925": "handmade_world.cpp: Introduce PackEntityIntoChunk" "3049": "handmade_world.h: Make FirstBlock be a pointer in world_chunk" "3202": "handmade_world.cpp: Introduce HasRoomFor" "3423": "handmade_world.cpp: Introduce AddBlockToFreeList and AddChunkToFreeList" "3585": "handmade_world.cpp: Introduce RemoveWorldChunk" "3661": "handmade_world.cpp: Split GetWorldChunk out to GetWorldChunkInternal in order to provide multiple entry points" "4063": "Run the game and let it crash and burn" "4093": "handmade_world_mode.h: Support creating multiple entities at the same time" "4309": "Q&A" "4367": "Blackboard: Using a Pointer to a Pointer to enable editing of chunks" "4577": "How are you finding Milton? I didn't catch the start of the stream sorry" "4658": "How do you pronounce your name?" "4690": "Is the Sparse Entity System the same as "mixins" that you mentioned before? If not, are we ever going to use or talk about mixins? I'm really curious as to what they are" "4708": "Blackboard: Mixin" "4785": "Do friend classes count as mixins?" "4832": "Couldn't you avoid having to compress the entities if you used some unions in the entity?" "4879": "How are you finding 4coder so far? Any features you find missing? Is it worth getting into coming from emacs?" "4955": "What do you think of the other more data-oriented entity system implementations online (like anax, EntityX, etc.)?" "5035": "Wrap it up" --- name: "day280" title: "Cleaned Up Streaming Entity Simulation" markers: "50": "Recap and set the stage for the day" "71": "handmade_world.cpp: Get the sizeof *Source in PackEntityIntoChunk" "135": "handmade_sim_region.h: Rename StorageIndex to ID in entity" "252": "handmade_sim_region.cpp: Rename GetHashFromStorage to GetHashFromID" "295": "handmade_sim_region.h and .cpp: Remove EntityFlag_Nonspacial from entity_flags and continue cleaning stuff up" "486": "handmade_world_mode.cpp and handmade_entity.h: Remove the Sword" "754": "handmade_world.cpp: Make PackEntityIntoWorld store the entity's location" "940": "Debugger: Step into BeginSim and find that we don't get any entities out in our initial pack" "1101": "Debugger: Step into PackEntityIntoWorld and follow the code through to RemoveWorldChunk" "1437": "handmade_world.cpp: Increment the Chunk->EntityCount in PackEntityIntoChunk" "1503": "Run the game and see that we're getting closer, but that the body has stopped tracking the head" "1666": "handmade_sim_region.cpp: Collapse down AddEntityRaw and AddEntity" "1934": "Run the game and see exactly the same thing" "1941": "handmade_sim_region.cpp: Introduce ConnectEntityPointers" "2095": "Run the game and find that the head and body remain connected" "2117": "handmade_entity.h: Move the entity-related structs in from handmade_sim_region.h" "2313": "handmade_world_mode.cpp: Disable the Z-movement and then try traversing the world" "2388": "handmade_sim_region.cpp: Introduce DeleteEntity" "2606": "Run the game and test entering and exiting it" "2713": "handmade_entity.h: Explain why world_position is no longer necessary and consider removing it" "2887": "handmade_sim_region.cpp: Make BeginSim compute world_position and pass ChunkDelta to AddEntity" "3079": "handmade_sim_region.cpp: Make the EntityP in EndSim relative to ChunkP" "3402": "Run the game and find that we can go off the screen okay" "3418": "handmade_sim_region.cpp: Set the Entity->P and chunk movements at the end of EndSim" "3468": "Run the game and find that the camera does now follow the hero" "3522": "Q&A" "3625": "Is there any real difference between #ifndef and #if !defined? I always use the first but I see you use the latter" "3655": "Do you feel like we take steps backward when we get into code we haven't been in in a while, e.g. the problems with moving the screen?" "3682": "Do you use a lot of header files?" "3713": "Remove all instances of #if !defined" "3967": "Why not #pragma once?" "4136": "Would you say the architecture of the entity system is based more on experience than on exploration?" "4168": "Do you have a plan for the "components" of the entities? Just use the flags like you are now?" "4187": "As a codebase grows new functions are created and others are no longer called anywhere. Are there any good ways that you recommend for finding out which functions / blocks of code are never used anywhere?" "4289": "Is there a way to run the game "entirely" and find out what parts of your code aren't being used, to get rid of?" "4382": "The dynamite jack entity system is similar (but without compression)" "4417": "Have you checked LOC recently?" "4454": "How is your arm now? Any chance of a streamathon?" "4479": "CTime needs cloc built-in" "4537": "Re code coverage, when Farbrausch was trying to cut down size of Kkrieger they wrote a quick code coverage tool called Lekktor and because someone didn't use a certain key in the menu, the code to handle it was left out in the released version" "4833": "Wrap it up" --- name: "day281" title: "Animating the Camera Between Rooms" markers: "88": "Recap and set the stage for the day" "204": "handmade_sim_region.cpp: Investigate the glitch in the room-based camera movement" "383": "Blackboard: How the camera was being moved" "447": "handmade_sim_region.cpp: Correct the displacement and run the game" "674": "Blackboard: Camera control, hysteresis and perception grammar" "1205": "Blackboard: Hysteresis" "1538": "Blackboard: What we need hysteresis for in Handmade Hero" "1818": "handmade_world_mode.h: Add CameraOffset to game_world_mode in order to decouple the camera and the simulation region" "2012": "handmade_world_mode.cpp: Test offsetting the camera" "2299": "handmade_sim_region.cpp: Introduce RoomDelta and hRoomDelta to make it easier to tweak values" "2429": "Run the game and try moving between rooms" "2431": "handmade_sim_region.cpp: Displace the camera away from the hero" "2474": "handmade_sim_region.cpp: Scroll the camera halfway into the apron" "2824": "Run the game and see the camera's half-interpolation" "2842": "handmade_sim_region.cpp: Scroll the second half of the transition" "2898": "Run the game and see the full scroll in action" "3033": "handmade_sim_region.cpp: Tune the camera control" "3262": "Blackboard: Parabolic arc equation" "3564": "handmade_sim_region.cpp: Give the camera this parabolic arc" "3592": "Run the game and enjoy the camera movement" "3708": "handmade_sim_region.cpp: Update the Entity->P before computing the CameraOffset" "3835": "Run the game and see that the glitch is gone" "3845": "Q&A" "3900": "Are you concerned about the player seeing outside the boundaries of the map or seeing into other rooms when the camera zooms out?" "3922": "So, no more smooth scrolling?" "3947": "I know the rooms are going to fit the screen, but will there be variable sized rooms with the camera making it fit to the screen?" "4009": "When thinking of enemies, would you have classifications for AI, e.g. Level 1 approach constantly (zombie)? What would be the main levels you'd say for difficulty or reward feeling?" "4024": "gasto5 When does he turn 39?" "4039": "Have you seen the warp glitch from Link's Awakening? How would you avoid that?" "4169": "You press start when before you enter a room and the link will end up on top of the screen" "4227": "Blackboard: Our coherent sense of world space vs What may be happening in Link's Awakening" "4387": "If you want a good hysteresis example a heater controller does the job" "4453": "We are done" --- name: "day282" title: "Z Movement and Camera Motion" markers: "160": "Run the game and show where we're at" "349": "handmade_world_mode.cpp: Randomise the heights of the traversable points" "585": "Run the game and traverse the room" "813": "handmade_sim_region.cpp: Provide the ability to interpolate the camera's height" "1052": "4coder: Spot a potential bug with a space being inserted after a square-bracket" "1173": "handmade_sim_region.cpp: Make AddStandardRoom form a ramp" "1258": "Run the game and attempt to hop up the ramp" "1404": "handmade_world_mode.cpp: Set HeadToPoint.z to 0" "1430": "Run the game and find that we can now hop upwards" "1508": "handmade_world_mode.cpp: Make AddStandardRoom produce a shallower ramp" "1539": "Run the game and traverse the shallower ramp" "1592": "handmade_world_mode.cpp: Comment out the HeadToPoint.z setting and again traverse the shallower ramp" "1706": "handmade_world_mode.cpp: Compute the HeadToPoint in order to prefer traversable points in the XY plane" "1860": "Run the game and traverse the world" "1998": "Blackboard: The Plan for Final Z" "2237": "handmade_world_mode.cpp: Let the ramp go below 0 and traverse it in an effort to see the alpha-fade" "2349": "handmade_world_mode.cpp: Investigate why the alpha-fade is not happening" "2467": "Debugger: Break on CameraRelativeGroupP initialisation and inspect the values" "2614": "handmade_world_mode.cpp: Only create one room" "2781": "handmade_world_mode.cpp: Add a DEBUG_VALUE for CameraRelativeGroundP to the HeroHead" "2810": "Run the game, traverse the ramp and watch that CameraRelativeGroundP" "2869": "handmade_world_mode.cpp: Add that DEBUG_VALUE to the Monstar" "2903": "Run the game and note that we don't load in the world one layer above us" "2948": "handmade_world_mode.cpp: Add fifteen floors to the SimBoundsExpansion" "2983": "Run the game and find that the alpha-fade is working" "3022": "handmade_world_mode.cpp: Add another column of trees to the room" "3103": "Run the game, trigger the fade and explain the problem with alpha blending multiple faded entities" "3304": "handmade_render_group.h: Consider ways to blend the alpha" "3504": "Q&A" "3544": "That up / down camera movement looks so cool. I do hope the terrain height of the rooms makes good use of this" "3582": "Could you do something with GL_MIN / GL_MAX blend equation for the alpha?" "3792": "Can you create the word of warcraft game?" "3859": "If the contour of your entities wasn't antialiased, you could have used the depth buffer and reverse the render order for the entities being faded (front to back), but alas, it is hard to do properly with the alpha blending around the contours" "3950": "You mentioned rendering to an offscreen buffer then compositing as one means of getting the desired alpha effect, but you also mentioned something along the lines of using a "fragment list"? could you please elaborate a bit more on that approach?" "3983": "Blackboard: Per-fragment atomic lists" "4688": "That sounds insane. Are there any modern games that use this?" "4732": "Could you just pre-render normally to an offscreen buffer, and then composite it with the primary frame buffer with the fade-out alpha?" "4762": "If the antialiasing didn't throw a wrench, you could have used the depth-buffer-front-to-back rendering method all the way, and compensate for some of the extra bandwidth on less overdraw" "4836": "I mean that sounds like it has huge performance implications" "5039": "Speaking of your smoke example, did you see what David Rosen posted today?" "5098": "I thought most games were only designed to max out console hardware?" "5155": "Wrap it up" --- name: "day283" title: "Making Standing-on a More Rigorous Concept" markers: "246": "Do you have any favorite insects?" "271": "Good evening, Casey! Had a bit of an "uh-oh" moment today while annotating as you went to the episode guide to double-check what Day it was, but the expected previous day was not there..." "378": "If there are multiple GL contexts in use at the same time, and both have workloads simultaneously, how does the GPU / GPU driver decide to schedule those workloads? I noticed that windows seems to prioritize the active window's OpenGL context if you happen to have multiple OpenGL apps open at the same time (i.e. the active window will perform much better), so that's kind of interesting..." "501": "What are your thoughts on flowchart-based programming, and do you think they are effective in game programming?" "544": "What's your opinion on the Vulcan API?" "562": "I'm thinking more along the lines of what UE4 implements in the form of blueprint" "681": "What do you think about structured editors?" "732": "I think that the main use case of boxes-and-arrows-type programming is to convince non-programmers that they're not programming" "750": "Where are we on the Handmade Hero todo? Seems like a long time since we last updated it" "789": "Stream Begins Now" "886": "Run the game and set the stage for the day" "1123": "Blackboard: Atomic Hop and Floating position" "1467": ""I forgot there's a me down there"" "1818": "Blackboard: The problem with merry-go-rounds and potential decapitation" "2354": "handmade_entity.h: Introduce traversable_reference and add two of those to entity" "2567": "handmade_sim_region.cpp: Introduce LoadTraversableReference and StoreTraversableReference" "2727": "handmade_sim_region.cpp: Move GetClosestTraversable in from handmade_world_mode.cpp and make it record the Index" "3268": "handmade_entity.h: Make entity track the traversable that we're on" "3409": "handmade_world_mode.cpp: Make AddPlayer take a traversable_reference and create players on the closest traversable" "3465": ""I don't want them to start invalid"" "3720": "Run the game to see what we have wrought, and hit the Assert in GetSimSpaceTraversable" "3878": "Debugger: Hit that Assert and find that Head->StandingOn is NULL" "4036": "handmade_world.cpp: Do all of the edits in PackEntityIntoChunk" "4203": "Run the game and successfully hop around" "4215": "handmade_world_mode.cpp: Make the HeroBody recover its position, and introduce AddFloatyThing" "4468": "handmade_world_mode.cpp: Make the FloatyThingForNow move up and down" "4554": "Run the game and try standing on the FloatyThingForNow" "4610": "handmade_world_mode.cpp: Make AddStandardRoom add only the FloatyThingForNow at its location" "4686": "Run the game and try again to stand on the FloatyThingForNow" "4775": "Q&A" "4822": "This sounds like a job for hysteresis, if I understand it right" "4864": "They implemented a structured editor for greenfoot" "4901": "So, we are planning to have the head detached forever?" "4929": "Where are the gloves? You will program in custom glove movement, right?" "4947": "Any idea when you plan on adding in the correct-perspective art so that the hero looks less strange?" "4971": "So in theory you could test this by adding a second hero with the xbox controller and making sure they don't stand on the same tile?" "5004": "Close this down" --- name: "day284" title: "Reorganizing the Head and Body Code" markers: "100": "Run the game and recap our current situation" "176": "Stand on the FloatyThingForNow and note a bug" "224": "handmade_world_mode.cpp: Set Found = false for the HeroBody" "318": "Run the game, note that the body cannot find a traversable and consider making the head operate more specifically" "466": "handmade_world_mode.cpp: Decouple of the hopping from the head and make it happen more predictably" "747": "Run the game, move the head and find that the body does not hop" "777": "4coder: Indentation request" "792": "handmade_world_mode.cpp: Make the controller also control the body, if one exists" "1297": "Run the game and hop around" "1308": "handmade_world_mode.cpp: Make the Head test to see if the Body can move to a traversable" "1568": "handmade_entity.h: Introduce IsEqual" "1701": "Run the game and find that nothing has changed" "1851": "handmade_world_mode.cpp: Investigate this behaviour with the FloatyThingForNow like a bug, starting with DEBUG_VALUE" "2127": "Record a loop in order to investigate it" "2760": "Blackboard: Figuring out the tile delta" "3576": "win32_handmade.cpp: Copy a loop and provide the ability to play one back independently of recording" "3712": "Run the game and try playing back a loop" "4994": "Moment of realisation: This isn't even a bug" "5084": "Owl of Shame Moment: FloatyThingForNow is hard-setting the P.z" "5105": "Blackboard: How the FloatyThingForNow messes with the relative coordinate system" "5240": "handmade_world_mode.cpp: Set the P.z as a delta for now and then hop onto the FloatyThingForNow and find that the bug has gone" "5319": "Blackboard: sine and cosine as derivatives of each other" "5706": "Q&A" "5766": "Is there a geometric explanation for the quaternion sandwich product? Where does the formula q * p * conj(q) come from?" "5820": "I am a bit unclear on why the relative positioning of Z worked. Is Z rebased somewhere in the code?" "5913": "I'm still quite newbie on programming, but wouldn't commenting your code a bit more help in situations like today?" "6040": "Only three swears? I have counted a lot more than that" "6064": "So, not only did that bug effect the floating thing going to high / low, but it also was the cause of the head picking the wrong point and the body jumping to it?" "6083": "Blackboard: What was causing the guy to jump" "6195": "What if you really wanted to set an absolute position for an entity? How would you handle that?" "6240": "Blackboard: Quaternion Sandwich Product or Similarity Transform" "6356": "Yes, that's the question" "6394": "Blackboard: The algebraic reason" "6536": "Blackboard: Things that represent a frame of reference" "6878": "Blackboard: Knowing what B is in the space of A" "7047": "Blackboard: The Similarity Transform" "7396": "Blackboard: Diagram of the transform" "7637": "Blackboard: Why do we care about this?" "7835": "Blackboard: Thinking about this algebraically" "7925": "Blackboard: Doing this transform, with P encoded in a different space" "8168": "Blackboard: Transforming a bone chain" "8462": "Blackboard: Inserting and expanding the identity" "8743": "Thank you, very insightful explanation. Can you recommend a book where I can learn more about these kinds of things? How did you learn it all in such an intuitive way?" "8961": "Would any of this have been mentioned in the comments in the Granny source code, or is it considered "obvious" to people working in that context?" "9051": "Wrap it up" "9092": "Relaunch the awesome Milton and find that everything is saved and undoable" --- name: "day285" title: "Transactional Occupation of Traversables" markers: "95": "4coder: New version 4.0.5, with indentation and scrollbars" "205": "Recap and set the stage for the day" "276": "handmade_world_mode.cpp: Disable the slope" "374": "4coder: Bug with editing in the left-hand pane" "449": "handmade_entity.h: Add an entity *StandingOn to entity_traversable_point" "571": "handmade_sim_region.cpp: Make LoadTraversableReference write to the entity's collision volume if they have a pointer set" "657": "handmade_world_mode.cpp: Colour the traversable if it has an Occupier" "703": "4coder: Swoon over the cool new indentation" "763": "Run the game and find that the traversables already have the new colour" "975": "handmade_entity.h: Make the Traversable a property of the entity" "1193": "Run the game and pacman up the traversable points" "1257": "4coder: Realise that we're now editing in the left-hand pane" "1281": "handmade_world_mode.cpp: Check if a traversable is available before hopping to it" "1394": "handmade_sim_region.cpp: Introduce TransactionalOccupy and GetTraversable" "1889": "Run the game and note a couple of problems" "2066": "Blackboard: Transitioning from Standing On to Moving To" "2238": "handmade_entity.h and handmade_world_mode.cpp: Assume that a 1-square-sized entity occupies only one square at once" "2329": "4coder: Outdated jump-to-error" "2585": "Run the game and find that the colouring of the traverables is working as expected" "2625": "handmade_world_mode.cpp: Reimplement the ability to add new heroes" "2713": "Run the game, try adding new heroes and enjoy the weirdness" "2824": "handmade_world_mode.cpp: Consider making AddPlayer more robust" "3211": "handmade_world_mode.cpp: Set HeroesExist in both cases, run the game and consider keeping AddPlayer as it is" "3281": "Q&A" "3322": "This debug world just gets progressively weirder every day" "3394": "Why don't the cloned players jump to points when their head moves over them?" "3441": "handmade_world_mode.cpp: Make the hopping happen whether or not a controller is controlling the hero" "3586": "Run the game and spawn a ton of heroes" "3612": "handmade_world_mode.cpp: Keep those heroes hopping" "3654": "Run the game and watch them hop" "3696": "handmade_sim_region.cpp: Introduce traversable_search_flag and add Unoccupied flag to GetClosestTraversable" "3741": "4coder: Praise Allen for the alignment" "3793": "4coder: Bogus indentation" "3861": "Run the game and spawn a line of heroes" "3914": "handmade_world_mode.cpp: Made AddPlayer take SimRegion in order to do GetClosestTraversable" "4046": "Run the game and find that we're still not quite right" "4100": "handmade.h: Add DebugSpawn to controlled_hero in order to test this adding" "4342": "handmade_sim_region.cpp: Make GetSimSpaceTraversable copy the Occupier" "4386": "Run the game and spawn some correctly positioned heroes" "4410": "handmade_world_mode.cpp: Make DebugSpawn not override us" "4434": "Run the game and just add new people" "4565": "Wind up" "4568": "4coder: Recap the one weirdness with the if [see 1:03:13]" --- name: "day286" title: "Starting to Decouple Entity Behavior" markers: "65": "Recap and set the stage for the day" "388": "handmade_entity.h: Consider how to eliminate Type from the entity struct" "690": "handmade_entity.h: Move things off the Type variable that need not be there" "964": "Run the game and see that we've lost nothing, besides the FloatyThingForNow" "1211": "handmade_entity.h: Partition the entity struct to separate the meaningful from the exploratory" "1274": "handmade_entity.h: Add an entity_reference *PairedEntities and a u32 PairedEntityCount in the meaningful area to provide some notion of pairing of entities" "1615": "Blackboard: Norm, and Pythagoras' Theorem" "1951": "handmade_world_mode.cpp: Write the usage code for pairing multiple entities" "2202": "handmade_world_mode.cpp: Consider making PackEntityIntoChunk pair aware and PairedEntities dynamically resize, and how to track the entity_id" "2829": "handmade_entity.h: Consider introducing enum entity_relationship to denote how an entity is paired" "3108": "handmade_entity.h: Introduce ReferenceIsValid, entity_stored_reference and ReferencesAreEqual" "3401": "handmade_world_mode.cpp: Make PackEntityReferenceArray correctly pack these variably-sized paired entities" "3819": "handmade_world.cpp, handmade_sim_region.cpp and handmade_world_mode.cpp: Fix compile errors" "4077": "Q&A" "4107": "A fairly simple way to describe or understand the infinity norm is to draw the unit hyperspheres for each of those common norms. The 1-norm would be a diamond shape, 2-norm is the regular circle / hypersphere, 3-norm gets more squareish / hypercubish and so on. You'd quickly see that this series converges towards a square / hypercube" "4142": "Have you seen Scott Meyer's talk on CPU caches? He talks about how it's better to store data of the same type together in memory because they end up on the same cache line, which is good for performance. Is this something that you think about, or will cover in Handmade Hero?" "4282": "Could you use the entity pairing concept for a vehicle-occupant relationship, like an airship and its passenger(s)? And, if so, (how) would movement work on it?" "4304": "I was just wondering why you don't have a subscriber button for those that enjoy your frequent broadcasts. From what I gather you were offered partnership but turned it down due to something in the contract. Can you tell me a little why you made that decision and what options do you have to donate?" "4510": "Is it not possible to subscribe to forum posts anymore now since the new stuff was made I don't get any posts to my mail" "4557": "Subscribe doesn't make it ad-free anymore, as far as I know" "4709": "This entity reference stuff feels premature to me since I don't think we have a lot of examples of how it will be used. Are you doing it now for a particular reason?" "4885": "Close down" --- name: "day287" title: "Adding Brains" markers: "56": "Blackboard: Dynamically controlling snake-like multi-segment entities" "415": "Blackboard: Controller templates" "882": "4coder: Reproduce the pane creation bug" "1023": "handmade_entity.h: Remove entity_relationship and ReferenceIsValid and, from entity, PairedEntityCount and PairedEntities" "1094": "handmade_entity.h: Introduce entity_controller_type, entity_controller_slot and entity_controller_id, and add one of each to entity" "1337": "handmade_entity.h: Consider how this system will replace entity_type" "1499": "handmade_entity.h: Rename entity_controller_* to brain_*" "1544": "handmade_sim_region.h: Introduce brain_hash and add an array of them to sim_region" "1830": "handmade_world.cpp: Rename PackEntityReferenceArray to PackEntityReference and make it work on only one entity" "2218": "handmade_world.cpp: Make PackTraversableReference and PackEntityIntoChunk take a sim_region" "2269": "handmade_entity.h: Introduce IsDeleted" "2335": "handmade_sim_region.cpp: Move some functionality from LoadEntityReference to GetEntityByID and make it call the latter" "2432": "handmade_sim_region.cpp: Make PackEntityIntoWorld take a sim_region" "2505": "handmade_world_mode.cpp: Remove BodyRefs and HeadRefs from AddPlayer, and initialise a brain_id and some brain data for the Body and Head" "2648": "handmade_world_mode.cpp: Introduce AddBrain" "2806": "handmade_sim_region.h: Add MaxBrainCount, BrainCount and *Brains to sim_region" "2820": "handmade_world_mode.cpp: Excitedly make UpdateAndRenderWorld loop through the brains and do the brain logic" "2941": "handmade_sim_region.h: Add a brain_type to brain" "2962": "handmade_world_mode.cpp: #if 0 out the PairedEntities code for now" "3046": "Run the game with our disabled controllers" "3079": "handmade_world_mode.cpp: Loft the hero head controller code up into Brain_Hero and begin writing the brain logic" "3194": "4coder: Bright white bug" "3312": "handmade_sim_region.h: Add a brain_id to brain" "3370": "handmade.h: Change entity_id to brain_id in controlled_hero" "3425": "handmade_world_mode.cpp: Fix compile errors" "3667": "handmade_world_mode.cpp: Make AddPlayer return a brain_id" "3722": "Q&A" "3856": "I must have missed the bit about the snake. What is that?" "3947": "It's actually a millipede" "3970": "How long do you hope this will go on for? Do you see yourself doing different game once this is finished?" "4043": "You mentioned you'd spend four hours cleaning code. Why not have a Handmade Hero day once every other month or so and deal with problems like that?" "4063": "About the one entity per grid spot checking, how will you handle leaving a spot just before a monster lands there? Right now it's binary. Do you plan to add a fuzziness as you step off a square onto another one and a monster lands on your spot?" "4193": "Someday I will have to ask you about how to think when representing data in a program. I understand structs, enums, arrays and such. But what regulates when to use which?" "4446": "So the idea is to have the entity system both be able to support groups of entities that change from one into another (like a monster that mimics other objects), and entities that when separated from the group can take action on their own (like a necromancer resurrecting a ripped off arm)?" "4545": "Slightly off-topic: On average how many hours a day do you work on 1935?" "4588": "On the note of UML, how much / often would you say you deal with that at work, if at all? In the gamedev industry, anyway" "4602": "Good answer, I understand what you mean. Just do it enough and you'll see what works. Experience. Thanks!" "4610": "Have you thought about using Vulkan? It is super low-level access to hardware" "4631": "Wrap it up" "4694": "Announce AndrewJDR's annotated_cpp repository" --- name: "day288" title: "Finishing Brains" markers: "60": "Recap and set the stage for the day" "161": "handmade_sim_region.cpp: Introduce GetOrAddBrain" "435": "handmade_sim_region.cpp: Introduce a GetHashFromID for brain_id" "543": "handmade_sim_region.cpp: Remove AddEntityRaw and inline AddEntity's functionality in BeginSim" "704": "handmade_entity.h: Move struct brain in from handmade_sim_region.h, add an array of Parts to it, and introduce brain_hero_parts" "988": "Run the game and find that nothing happens" "1009": "handmade_world_mode.cpp: Set the Head and Body for BrainHero in AddPlayer" "1061": "Run the game and spam the world with heroes" "1212": "Blackboard: ddP and the benefit of assigning accelerations before simulating them together" "1356": "handmade_entity.h: Add ddP to entity" "1428": "handmade_world_mode.cpp: Make the controller code in UpdateAndRenderWorld just get the controller that corresponds to the given hero" "1686": "handmade_world_mode.cpp: Be Mr Slypants Slypantsyman and base the ControllerIndex in UpdateAndRenderWorld on the Brain->ID.Value" "1783": "handmade_entity.h: Introduce reserved_brain_id" "1871": "handmade_world_mode.cpp: Make AddPlayer take BrainID and return void" "1989": "Run the game and find that we can change the hero's facing direction" "2024": "handmade_world_mode.cpp: Remove BrainID, ddP, dSword, dZ, Exited and DebugSpawn from controlled_hero in from handmade.h and make UpdateAndRenderWorld initialise them directly" "2300": "handmade.h: Add BraidID back to controlled_hero" "2460": "handmade_world_mode.cpp: #if 0 the Planted code in UpdateAndRenderWorld" "2540": "Debugger: Investigate how we got into Hopping mode without a CameFrom" "2826": "handmade_sim_region.cpp: Reenable and fix ConnectEntityPointers" "2909": "Debugger: Break into UpdateAndRenderWorld and investigate how Occupying is being set to 0" "2997": "Hunt this guy down before stopping" "3035": "handmade_sim_region.cpp: Make ConnectEntityPointers able to break on Entity->ID.Value 219" "3145": "handmade_world.cpp: Make PackEntityIntoChunk do the same for the Source" "3284": "handmade_world_mode.cpp: Make AddPlayer put the Body and Head in their correct BrainSlot" "3349": "handmade_entity.h: #define BrainSlotFor in order to name the slots using pointer arithmetic" "3625": "Rant on compiler vendors making programmers' lives difficult" "3692": "handmade_entity.h: Introduce BrainSlotFor_ to return a brain_slot" "3751": "Q&A" "3768": "Can we have a look at the ctime stats so far?" "3879": "What will we do for the "production" Assert?" "3896": "May this brain system allow for things like two characters carrying a felled tree between them, with both of their brains controlling the movement of the tree?" "4076": "Try not to make the brains self-aware. We can't have stumpy over there taking over the world" "4102": "For brain types, why not an enum for the array indexes?" "4297": "How would you go about making game entities moddable?" "4352": "I was thinking defining whole new types of entities" "4460": "I guess there's no way to mitigate dll security concerns?" "4560": "So all the brain code is now in the switch(Brain->Type). How many brains do you expect to have? What if we have 100 brains, will you keep all the code there?" "4598": "We are out of time" --- name: "day289" title: "Decoupling Visuals from Entity Types" markers: "80": "Recap and set the stage for the day" "152": "A few words on deciding when to make new files" "238": "handmade_brain.h and handmade_brain.cpp: Add these files and pull in the brain code from handmade_entity.h and handmade_world_mode.cpp" "398": "handmade_brain.cpp: Introduce ExecuteBrain" "529": "handmade_world_mode.cpp: Consider how to deal with HeroesExist" "608": "4coder: Bug with buffer position loss" "687": "handmade_world_mode.cpp: Make UpdateAndRenderWorld set HeroesExist by looping through the controllers" "1017": "handmade_world_mode.cpp: Shuffle UpdateAndRenderWorld and delete superfluous code" "1141": "handmade_brain.cpp: Move the Planted mode code in from handmade_world_mode.cpp" "1313": "handmade_entity.h: Add ddtBob and MoveSpec to entity" "1597": "handmade_brain.cpp: Make ExecuteBrain give the head some movement" "1824": "handmade.cpp: Add ddP to controlled_hero" "1955": "Debugger: Investigate why we're not getting any acceleration" "2087": "handmade_world_mode.cpp: Make UpdateAndRenderWorld correctly set the ddP" "2165": "Run the game and move around" "2205": "handmade_brain.cpp: Move in the Familiar, FloatyThingForNow and Monstar code from handmade_world_mode.cpp" "2388": "handmade_world_mode.cpp: Figure out a way to get rid of Entity->Type and remove the Stairwell and Floor types" "2529": "handmade_world_mode.cpp: Allow anyone to draw their collision rectangles" "2557": "Run the game and view the collision rectangles" "2633": "handmade_world_mode.cpp: Compress these entity types" "2776": "handmade_entity.h: Introduce entity_visible_piece" "3028": "handmade_world_mode.cpp: Reimplement the Wall using entity_visible_piece" "3224": "Run the game and see no walls" "3237": "handmade_world_mode.cpp: Make AddWall call AddPiece" "3288": "Describe this process of enabling entities to prescribe how they will be rendered" "3337": "handmade_world_mode.cpp: Introduce AddPiece" "3446": "Run the game and see the trees" "3465": "handmade_world_mode.cpp: Temporarily make AddWall apply some EffectsEntropy to the Piece->Color" "3557": "Run the game and admire the randomly coloured trees" "3612": "Q&A" "3725": "Recently came across this. Please read the abstract and tell me what you think" "3888": "Is there a limit to the colors you can have?" "3933": "Will you need to have an entity type at some level, like when generating the world, placing trees and whatnot?" "4005": "Consider the reaps paper" "4171": "Colors of the trees, the hero, enemies, etc." "4202": "I've been a little lost the last few days. Would you mind giving a brief recap of what you're trying to do to the entity system now?" "4404": "Thoughts on avoiding denormalized floating-point on console platforms? Do they all have a -ffast-math?" "4461": "My apologies. Yes, limits in the game design" "4501": "Can you explain the difference between how you manage memory at work and how you're currently doing it in Handmade Hero?" "4514": "Will monsters and other things be able to attack each other (friendly fire), like a witch accidentally shrinks a goblin or something?" "4536": "Would we do anything differently if we wanted to have HDR capabilities in the game?" "4585": "Can you answer my previous question? People would like to see your pre-streams on YouTube" "4631": "The reason I ask is because I really like the idea of allocating up front and managing all memory myself as in Handmade Hero, but I'm not sure if I'm just shooting myself in the foot by not using malloc / free" "4823": "Wrap it up" --- name: "day290" title: "Finishing Separated Rendering" markers: "61": "handmade_sim_region.cpp: Remove the EntityOverlapsRectangle call in BeginSim" "238": "Run the game and set the stage for moving all the entities to the new path" "285": "handmade_brain.cpp: Make ExecuteBrain use the ddP2 rather than the ddP" "431": "handmade_world_mode.cpp: Make AddPiece take an Offset" "541": "handmade_world_mode.cpp: Make AddMonstar call AddPiece" "761": "Run the game and see the Monstar" "804": "handmade_world_mode.cpp: Make AddPlayer call AddPiece" "902": "handmade_world_mode.cpp: Consider how to proceed with the HeroBody and Familiar" "1023": "handmade_world_mode.cpp: Make AddPlayer do AddPiece calls for the Shadow, Torso and Cape, leaving out the animated portion of it" "1240": "Run the game and see everyone but the Familiar" "1265": "handmade_world_mode.cpp: Make AddFamiliar call AddPiece" "1342": "Run the game and see everyone" "1382": "handmade_entity.h: Introduce entity_visible_piece_movement with AxesDeform and BobOffset" "1458": "handmade_world_mode.cpp: Make the Familiar set the BobOffset flag, and the Hero set the AxesDeform one for the Cape" "1558": "handmade_world_mode.cpp: Make the HeroBody do AxesDeform" "2132": "handmade_world_mode.cpp: Make BeginLowEntity correctly set the axes" "2185": "Run the game and see that we're properly deforming" "2204": "handmade_entity.h: Remove entity_type from entity and see who needed it" "2353": "Run the game with the notion of entity_types gone" "2764": "handmade_brain.h: Introduce brain_hero, brain_monstar and brain_familiar" "2850": "handmade_world_mode.cpp: Make a Brain_Familiar case" "3198": "handmade_brain.h: Make BrainSlotFor_ take Type" "3285": "handmade_entity.h: Remove BrainType from entity and deal with the resultant compile errors" "3402": "Run the game and find that nothing has changed" "3409": "Q&A" "3453": "Were you trapped in an elevator today?" "3467": "If you are nuking the concept of an entity type but still keeping everything tightly bound in the brain, what real gain does all of this work give us? Didn't we just shift responsibility into the brain?" "3589": "After all this time, are finally you used to programming live? Is this a comfortable habit now?" "3627": "Could you explain again what you just did with the brain slot? That went a little fast for me" "3842": "How would you handle something like mind-controlling other entities, or having your mind swapped into a differently-structured body?" "4000": "handmade_brain.cpp: Implement mind control in ExecuteBrain" "4166": "handmade_brain.h: Introduce NoBrain" "4290": "Run the game and take control of the familiar" "4349": "handmade_brain.cpp: Make ExecuteBrain swap the BrainID and BrainSlot" "4512": "handmade_world_mode.cpp: Make PlayWorld set everything to NullCollision" "4550": "Run the game and toggle between the familiar and the original hero" "4598": "handmade_world_mode.cpp: Make AddMonstar set a brain" "4623": "Run the game and mind-control the monstar and the familiar" "4683": "When will we implement the zombie brain?" "4726": "Wrap it up" --- name: "day291" title: "Hopping Monstar and Occupying Trees" markers: "108": "Run the game and set the stage for the day" "197": "handmade_brain.cpp: Give ExecuteBrain the ability to move the Monstar" "373": "handmade_world_mode.cpp: Make AddMonstar take a traversable_reference" "490": "handmade_world_mode.cpp: Make AddStandardRoom call AddMonstar" "764": "Run the game and see that the Monstar doesn't appear to be initialised correctly" "823": "handmade_world.cpp: Make PackEntityReference leave the Index the same if there's no SimRegion and no GetHashFromID" "892": "Run the game and see that the Monstar is no properly occupying a square" "898": "handmade_brain.cpp: Enable the Monstar to move, run the game and watch it move" "939": "handmade_world_mode.h: Add random_series GameEntropy to game_mode_world" "975": "handmade_world_mode.cpp: Make PlayWorld initialise GameEntropy and use that GameEntropy to generate the rooms" "1015": "handmade_brain.cpp: Make ExecuteBrain set the Monstar's Delta using the GameEntropy and take game_mode_world *WorldMode" "1300": "Kick back and eat some cheesy poofs while watching the Monstar hop around randomly" "1422": "handmade_world_mode.cpp: Introduce struct standard_room, and make AddStandardRoom return it and specify the StandingOn points" "1792": "handmade_world_mode.cpp: Make AddWall take world_position P and traversable_reference StandingOn, and specify that the Tree occupies squares" "1847": "Run the game and find that the Monstar cannot hop on the Trees, but that we can currently hop over them" "1931": "handmade_world_mode.cpp: Make the Head collide with the Trees" "2035": "handmade_brain.cpp: Stop ExecuteBrain checking for deletion and doing unnecessary controller code" "2271": "handmade_brain.cpp: Investigate why the Head is sticking by adding a DEBUG_B32 for NoPush and a DEBUG_VALUE for ddP2, and setting the Head's UnitMaxAccelVector to false" "2529": "Run the game and hit the Assert relating to MaxEntityVelocity" "2679": "handmade_sim_region.cpp: Stop MoveEntity taking the move_spec" "2821": "handmade_brain.cpp: Stop entity taking the move_spec" "2864": "handmade_brain.cpp: Change how ExecuteBrain sets the Head's ddP" "3280": "Run the game and find that we've fixed the bug" "3341": "handmade_world_mode.cpp: Make AddStandardRoom call AddFamiliar and make AddFamiliar take world_position P and traversable_reference StandingOn" "3427": "Run the game and see our Familiar occupying its square" "3452": "handmade_entity.h: Remove Moveable from entity_flags" "3537": "Q&A" "3590": "Why are the textures not loading properly sometimes?" "3651": "Why the decision to make the game grid-based?" "3660": "There were sirens earlier. Is #manintree back at it again?" "3675": "Do you think even after getting a four-year degree in MIS it's worth it to learn a language such as C#?" "3704": "I guess technically if the gameplay is centered around tiles and facing direction, you wouldn't necessarily need collision detection?" "3775": "What are the 18 threads that run with the game?" "4040": "What is going to replace the ground splat system? Just different tile types and seamless textures?" "4061": "Why don't you program in a UNIX-based OS?" "4240": "Why wouldn't multithreading work all that well? Complications? Limitations?" "4268": "How did you manage to make thinks work in Windows when you started your career, given that MSDN at least now is negligible or unreliable or both?" "4316": "A few words on the giant splatter of garbage that is the Windows API" "4415": "You said something about the multi-threading being funky?" "4448": "Do you have positive or negative thoughts when it comes to learning and using Python for building applications?" "4464": "MSDN came on 2 CDs" "4504": "Which programming languages do you use regularly?" "4535": "Thanks" --- name: "day292" title: "Implementing Snakes" markers: "74": "Recap and plan to implement a floating method of movement and make a snake" "209": "handmade_entity.h: Add MovementMode_Floating to entity_movement_mode" "288": "handmade_brain.cpp: Enable the Familiar to move towards the closest Hero" "346": "Debugger: Step into Type_brain_familiar and note that Type_brain_hero is the default value" "531": "handmade_brain.h: Introduce IsType and make the Familiar check for the Hero type" "672": "Run the game and see the Familiar orbit the Hero" "803": "handmade_world_mode.cpp: Introduce AddSnakePiece" "897": "handmade_brain.h: Introduce brain_snake" "1004": "handmade_brain.h: #define IndexedBrainSlotFor" "1256": "handmade_sim_region.h: Replace the entity *Array[16] in brain with a *Array" "1380": "Rant on pointer arithmetic in C++" "1454": "handmade_sim_region.cpp: Advance the Ptr through the Brain->Array, ensuring that it remains inside the Brain structure" "1626": "Underscore the necessity of languages to make simple operations easy to program" "1838": "handmade_world_mode.cpp: Make AddStandardRoom add a snake by calling AddSnakePiece" "1974": "handmade_brain.cpp: Make ExecuteBrain move the snake" "2306": "Run the game and see the Snake moving like a Monstar" "2318": "handmade_world_mode.cpp: Add more snake pieces" "2390": "Run the game and see the snake moving around just fine, until it traps itself" "2591": "handmade_world_mode.cpp: Try creating some additional screens" "2596": ""We have a lot of N-squaredy things"" "2760": "Run the game and watch the simulation" "3085": "Consider encouraging entities to move towards us from adjacent rooms" "3402": "todo.txt: Update the TODOs and add an Entity System note for geographically disparate entities" "3534": "Q&A" "3583": "Wasn't today an off-day?" "3609": "Can the compiler really mess up the pointer arithmetic? I mean, it is just integer ops, can't be that hard to mess up" "3748": "So is the way to fix the snake from getting stuck to just allow it to run over itself or to make the snake AI smart enough to not trap itself?" "3828": "I've recently watched your video on the GJK algorithm, it's great, thanks for that! Did you also do a video on the EPA algorithm?" "3842": "Will the snake head be able to move to the position of its last segment? So it can go in a circle / loop" "3890": "WTF you did a video on GJK? What other explanation videos have you done?" "3909": "Are you going to implement every AI thing in brain entity? When does path-finding and rest of AI coming on schedule? Also can you say some good reference book for AI? Cheers, Casey" "4007": "Yeah, and IMGUI, but what else?" "4038": "Expanding Polytope Algorithm" "4149": "Could you briefly explain how a snake segment knows which node to jump to? A non head segment, that is" "4165": "Don't forget the API video!" "4270": "Well I've got GJK + EPA implemented in 2D and GJK in 3D, but I am a bit struggling at EPA in 3D" "4343": "Wrap it up" --- name: "day293" title: "Moving Familiars" markers: "122": "Recap and set the stage for the day" "322": "handmade_entity.h: Add MovementMode_Floating to entity_movement_mode" "600": "Consider where the delineation between MovementMode and Brain should be" "820": "handmade_brain.cpp: Enable ExecuteBrain to make the Familiar occupy traversables and do transactional movement" "1310": "Debugger: Step into Type_brain_familiar in ExecuteBrain and investigate why the Familiar isn't moving" "1480": "handmade_sim_region.cpp: Make GetClosestTraversable set Entity.Index" "1499": "Run the game and see the Familiar move" "1587": "Blackboard: Proportional Derivative (and Integral) Controller" "1831": "handmade_brain.cpp: Make ExecuteBrain set a spring on the Familiar" "1875": "Run the game and see the spring in action" "2111": "handmade_brain.cpp: Introduce the notion of a TargetTraversable which the Familiar moves towards" "2229": "handmade_sim_region.cpp: Introduce IsOccupied" "2330": "Run the game and see that the Familiar follows us" "2347": "handmade_world_mode.cpp: Make AddStandardRoom randomly offset the grid points" "2491": "Run the game and see the irregular grid, with everyone able to function on it" "2660": "handmade_sim_region.cpp: Introduce GetClosestTraversableAlongRay" "2799": "handmade_brain.cpp: Make ExecuteBrain call GetClosestTraversableAlongRay for the Familiar" "2944": "Run the game and see that the Familiar is more stable" "3020": "handmade_sim_region.cpp: Add a TIMED_FUNCTION for GetClosestTraversable and GetClosestTraversableAlongRay" "3066": "Run the game and view the profiler" "3163": "build.bat: Temporarily switch to -O2 and then run the game and see how that affects our performance" "3371": "handmade_sim_region.cpp: Introduce GetClosestEntityWithBrain and closest_entity" "3617": "handmade_brain.cpp: Make ExecuteBrain call GetClosestEntityWithBrain for the Familiar" "3704": "Run the game and see that it works beautifully" "3719": "Q&A" "3764": "Any thoughts on multithreading the entity system?" "3781": "++ and += to reduce memory useage..." "3967": "How many more times will you get hit with the texture upload issue before you actually fix it?" "4002": "Do you have a max entity count at the sim region on the debug display?" "4166": "(Out of topic) Milton seems to be treating Wacom input as mouse input. Restart Milton? Will look into it" "4240": "Close things down" --- name: "day294" title: "Adding the Glove" markers: "48": "Prepare for combat" "461": "handmade_world_mode.cpp: Make AddPlayer initialise a Glove and call AddPiece for it" "633": "handmade_brain.h: Add Glove to brain_hero" "660": "handmade_world_mode.cpp: Make PlayWorld set the Glove to not collide" "799": "handmade_brain.cpp: Make ExecuteBrain position the glove next to the hero's body" "1030": "handmade_brain.cpp: Make ExecuteBrain offset the Glove according to the hero's FacingDirection" "1129": "Blackboard: Calculating the angle relative to the FacingDirection" "1237": "Run the game and see the "glove"" "1363": "handmade_brain.h: Add MovementMode_AttackSwipe to entity_movement_mode" "1473": "handmade_world_mode.cpp: Implement the AttackSwipe in UpdateAndRenderWorld" "1584": "Blackboard: Parameterising the arc of the swipe" "1710": "handmade_entity.h: Add SwipeAngleStart and SwipeAngleTarget to entity" "1836": "handmade_entity.h: Add MovementMode_AngleOffset and MovementMode_AngleAttackSwipe to entity_movement_mode" "2503": "handmade_brain.cpp: Provide the ability in ExecuteBrain to initiate an attack" "2749": "Run the game and try out the swipe" "2895": "handmade_entity.h: Add AngleCurrentDistance, AngleBaseDistance and AngleSwipeDistance to entity" "2931": "handmade_world_mode.cpp: Make UpdateAndRenderWorld parameterise the swipe's arc" "3046": "handmade_math.h: Introduce Sin01" "3099": "Blackboard: Cosine arc" "3333": "Run the game and try out the swipe" "3562": "handmade_math.h: Introduce Triangle01" "3626": "handmade_world_mode.cpp: Make UpdateAndRenderWorld call Triangle01 and then run the game to try it out" "3664": "Q&A" "3707": "Will it support Nintendo's power gloves?" "3737": "Are chain attacks going to be in by any chance (i.e. slash slash thrust)?" "3796": "What are your thoughts on switching to simulating adjacent rooms rather than using the simulation apron?" "3919": "How is the familiar intended to attack? Some kind of projectile or doing some kind of glide move and physically hitting a foe?" "4001": "Will there be a boot to match the glove?" "4007": "For the particle effects for the glove, are we going to be doing something similar to what we did earlier using head assets?" "4068": "I'm wondering if it could be a cool mechanic if you could swipe and change your facing direction while you swipe, thus prolonging the swipe into a potentially never ending spinning punch..." "4122": "Have you played Planescape: Torment? Handmade Hero totally needs a Morte-style familiar" "4164": "Will attacking be interrupt? Such as attacking unanimated entity, or someone attacked the player from behind and it jump opposite to the attack (e.g. old Zelda)?" "4245": "Why not leave the glove swipe to the artist / animator of the game?" "4348": "Wind down, with a glimpse into the future and some thoughts on how alive the world is starting to feel" --- name: "day295" title: "Stacking Rooms for Z Layer Debugging" markers: "11": "On determining which systems impact many other systems, and solidifying them early on" "165": "What Mike Acton had to say about the potential costliness of some game design decisions" "463": "Recap our current situation and set the stage for solidifying Z" "594": "handmade_world_mode.cpp: Make AddStandardRoom generate some stairs" "959": "Run the game and traverse the offset stairs" "991": "handmade_world_mode.cpp: Make PlayWorld generate more layers of rooms" "1038": "Run the game and see the multiple layers" "1094": "handmade_world_mode.cpp: Expand the TraversablePoint rectangles to fill the tiles and give them outlines" "1350": "handmade_render_group.cpp: Make PushRect multiply the Color by GlobalAlpha" "1371": "Run the game and see that we're already in pretty good shape, but need to more clearly specify Z" "1482": "handmade_world_mode.cpp: Make AddStandardRoom generate a hole in the ground" "1755": "Run the game and look down through the hole" "1801": "The snake just went up the stairs" "1824": "handmade_world_mode.cpp: Make UpdateAndRenderWorld draw the tiles green" "1897": "Run the game and consider the problem with drawing down so far" "2008": "handmade_world_mode.cpp: Make UpdateAndRenderWorld expand FadeBottomStartZ and FadeBottomEndZ" "2061": "Profiler: Note that BeginSim and UpdateAndRenderWorld are slow" "2308": "build.bat: Switch to -O2 find that we're now running at 60 FPS" "2399": "Profiler: Switch to the software renderer" "2461": "win32_handmade.cpp: Add more BEGIN_BLOCK and END_BLOCK pairs in Win32DisplayBufferInWindow" "2604": "handmade_world_mode.cpp: Add more BEGIN_BLOCK and END_BLOCK pairs in UpdateAndRenderWorld" "2652": "Run the game, view those timings and find that brains are not taking much time" "2704": "handmade_debug.cpp: Make DrawTopClocksList calculate and display a cumulative percentage" "2859": "handmade_debug.cpp: Make DrawTopClocksList call AddTooltip to draw this percentage" "3126": "Debugger: Step into DrawTopClocksList and find and investigate why our TextRect is not valid" "3296": "handmade_debug.cpp: Make DrawTopClocksList set TextRect off GetTextSize" "3359": "handmade_debug_ui.cpp: Introduce a version of GetTextSize that takes a v2 At" "3399": "handmade_debug_ui.cpp: Make AddTooltip draw a background" "3520": "handmade_debug.cpp: Make ToolTipTransform appear above everything" "3628": "Run the game and view our tooltip" "3768": "handmade_sim_region.cpp: Add a TIMED_BLOCK for SimUnpack in BeginSim" "3797": "handmade_sim_region.cpp: Make the PushArray calls in BeginSim do NoClear, and check that all of the necessary data is initialised" "3942": "Profiler: Find that BeginSim no longer takes so much time" "4012": "handmade_world_mode.cpp: Add BEGIN_BLOCK and END_BLOCK pairs for EntityRendering and EntityPhysics in UpdateAndRenderWorld" "4098": "Profiler: Find that EntityRendering is taking up the lion's share of the time" "4267": "handmade_world_mode.cpp: Move the EntityRendering block down to look only at the Piece list" "4296": "handmade_world_mode.cpp: Add BEGIN_BLOCK and END_BLOCK pairs for CollisionRendering, VectorClear, and HitpointRendering in UpdateAndRenderWorld" "4353": "Profiler: Find that CollisionRendering is the hog" "4367": "handmade_world_mode.cpp: Add BEGIN_BLOCK and END_BLOCK pairs for VolumeRendering and TraversableRendering in UpdateAndRenderWorld" "4414": "Profiler: Find that TraversableRendering is the most expensive" "4473": "handmade_world_mode.cpp: #if 0 the PushRectOutline calls for the traversables" "4535": "Consider turning on the optimiser just for these traversable drawing routines or blowing out the PushRect functions to be more explicit" "4579": "Q&A" "4641": "insobot Do you have a question for me?" "4648": "cmuratori: Duuuuude" "4654": "How much longer does it take to build Handmade Hero with release optimizations?" "4704": "Debugger: Demo the insufficiency of MSVC's debug information in optimised builds" "4979": "The switch is -Zo" "5026": "I missed the optimization due to buffering but I caught some stuff about the clear being bloated, but didn't catch what the fix was?" "5053": "Far-away floors turning transparent don't look quite right since you can see through them" "5083": "When peering down the hole at the more transparent layers, you can see characters through those ground layers. My guess is you would want to mix with a "fog color" instead of just making the tiles transparent?" "5124": "Would LLVM work on Windows / Handmade Hero?" "5238": "What editor is most similar to 4coder, and how long did it take to pick it up?" "5302": "Having many levels of rooms and having entities in each level actively executing, wouldn't that be heavy / expensive? Or have you think in a performance solution or a level limitation?" "5357": "Is there a way to tell the compiler to optimize just a particular section of the code? If not, how would you work around that?" "5467": "Clang++ is worse. Honestly, why can't the PDB just say "Hey, you are at this instruction? Okay, the value is in this register / address or whatever"?" "5626": "Wind it down" --- name: "day296" title: "Fog and Alpha for Layers" markers: "127": "Recap and set the stage for the day" "216": "handmade_world_mode.cpp: Set Volumes to not be Upright in UpdateAndRenderWorld" "278": "Run the game and see the difference that makes" "571": "handmade_render_group.h: Make GlobalAlpha in render_group a v4 and rename it to GlobalModulate" "641": "Consider clearly distinguishing between colours that have premultiplied alpha and those that don't" "759": "handmade_render_group.cpp: Introduce StoreColor and make PushBitmap, PushRect and Clear call it" "865": "Blackboard: Hadamard Product" "1025": "handmade_render_group.h: Add tGlobalColor and GlobalColor to render_group to allow us to do a linear blend as well as a modulate" "1208": "handmade_render_group.cpp: Pass the Group to the StoreColor calls" "1271": "Blackboard: Fade vs Haze" "1342": "handmade_world_mode.cpp: Conditionally compute the tGlobalColor and GlobalColor for fade and haze in UpdateAndRenderWorld" "1511": "Run the game and note that we're not handling alpha multiplication correctly" "1564": "handmade_render.cpp: Stop DrawRectangle, DrawRectangleSlowly and DrawRectangleQuickly from premultiplying the alpha" "1640": "handmade_render_group.h: Rename Color to PremulColor where appropriate" "1781": "Run the game, see that our two renderers draw solid filled rectangles in different colours and investigate why this is the case" "2272": "handmade_render.cpp: Try not squaring the Color when modulating incoming Color in DrawRectangle" "2361": "handmade_render.cpp: Try Squaring the Color up front in DrawRectangle" "2557": "handmade_render.cpp: Try multiplying all the Colors by 255 again" "2605": "Run the game and see that that's almost exact" "2618": "Blackboard: Ensuring that we remain in the same colour space" "2843": "Debugger: Step into UpdateAndRenderWorld when CameraRelativeP.z > FadeTopStartZ and inspect the Color values" "3159": "handmade_opengl.cpp: Try rendering everything at 50% opacity" "3327": "Debugger: Step into OpenGLRectangle and inspect the Entry->PremulColor values" "3428": "handmade_render_group.h: Conditionally add DebugTag to render_group_entry_header and render_group if we are in HANDMADE_SLOW mode" "3610": "handmade_world_mode.cpp: Make UpdateAndRenderWorld set DebugTag to 1 if CameraRelativeP.z > FadeTopStartZ" "3666": "Debugger: Break into our BreakHere line in OpenGLRenderCommands" "3738": "handmade_world_mode.cpp: Negate the alpha of tGlobalColor for the fade" "3776": "Run the game and see that the fade is now correct" "3842": "Investigate why we are seeing nothing below our level" "4052": "handmade_world_mode.cpp: Enable the correct blending in UpdateAndRenderWorld" "4075": "handmade_world_mode.cpp: Initialise a BackgroundColor in UpdateAndRenderWorld and pass this to Clear and the GlobalColor for the lowest floors" "4135": "Run the game and see the haze happening" "4167": "Q&A" "4203": "One thing you could try is having the center of the perspective projection be the player's position, so things on other levels line up straight" "4229": "The Hadamard transform seems like it can be used for a lot of things. What is it doing in handmade_world.cpp in the subtract function?" "4256": "Blackboard: Hadamard Product ~= Diagonal Matrix" "4592": "For the record, a circle with an x would be the tensor product" "4645": "Would it be difficult to implement textured or just different fog colors, so you could make, for instance, vignetted fog?" "4786": "How did you finally discover the gamma correction bug? What was the clue that made you say ah ha?" "4865": "Wind it down" --- name: "day297" title: "Separating Entities into Z Layers" markers: "64": "Recap and set the stage for the day" "130": "Demo the problem with alpha blending textures separately" "260": "handmade_render_group.h: Consider adding slice information to render_entry_cliprect" "423": "handmade_world_mode.cpp: Consider specifying relative floor layers" "724": "handmade_world_mode.cpp: Make UpdateAndRenderWorld loop over the LevelIndex, using PushClipRect to set the ClipRectIndex" "1068": "handmade_render_group.h: Introduce transient_clip_rect" "1241": "handmade_world_mode.cpp: Make UpdateAndRenderWorld put the three main layers into a different ClipRectIndex" "1404": "handmade_entity.cpp: Introduce UpdateAndRenderEntities" "1808": "handmade_world_mode.cpp: Make UpdateAndRenderWorld call UpdateAndRenderEntities" "1840": "handmade_entity.cpp: Test the clipping by halving the size of the screen for the current layer" "1968": "Run the game and see that we're clipped to the lower part of the screen" "2056": "handmade_entity.cpp: Make UpdateAndRenderEntities compute CameraRelativeGroundZ per LevelIndex" "2331": "handmade_entity.cpp: Set the CameraRelativeGroundP in UpdateAndRenderEntities immediately before rendering" "2544": "handmade_entity.cpp: Extract RelativeLayer from OffsetP.z in UpdateAndRenderEntities" "2754": "handmade_entity.cpp: Make UpdateAndRenderEntities set CameraRelativeGroundZ based on the Origin" "2965": "handmade_entity.cpp: Introduce ConvertToLayerRelative" "3209": "handmade_render_group.h: Introduce clip_rect_fx" "3269": ""We can handle it"" "3275": "Consider reducing the system down to two slices" "3554": "handmade_render_group.cpp: Make PushClipRect take a clip_rect_fx" "3606": "Run the game and see that the slices are not being perspective transformed" "3649": "Q&A" "3688": "I added some preliminary moderation code to insobot. At the moment it will just print out when it would time out" "3804": "It's been a while, did I see you programming without wrist braces? Are you not affected anymore?" "3984": "Is Jeff Atwood a good programmer?" "4107": "When you were working on switching between the software and hardware renderer yesterday, why did it look like there was still a very slight color difference?" "4199": "What would you say are the top three things that have made Molly Rocket successful in your eyes from a startup / business perspective?" "4386": "Do you mind name dropping her? I live in Seattle too and have a new wrist issue with programming" "4557": "As someone back at Episode 054, how far gone am I? Haha, just kidding. Thanks for everything, Casey!" "4595": "Do you find that your hands shake when holding a drinking glass? That's the only time my hands shake at all" "4635": "Wind it on down" --- name: "day298" title: "Improving Sort Keys Part 1" markers: "37": "On the two kinds of Z-values necessary for presenting multiple layers of rooms to the viewer" "159": "Recap and set the stage for the day" "376": "handmade_render_group.cpp: Look through how the perspective transform is currently programmed" "487": "Blackboard: Handling the "Changeover Point" between floors" "840": "Blackboard: Sorting entities in Y and Z using a "Hotpoint Rule"" "1485": "Blackboard: Consider these cases for any possible insights" "2183": "Blackboard: Placing the sort point differently depending on whether or not the entity is upright" "2348": "handmade_render_group.cpp: Look through PushBitmap to see how it currently does the sort" "2502": "handmade_render_group.cpp: Make GetRenderEntityBasisP calculate the SortKey using a PerspectiveZ, DisplacementZ, PerspectiveSortTerm, YSortTerm and ZSortTerm" "3358": "Consider the risk of having two important points on a bitmap, and to what degree they tend to line up" "3404": "Blackboard: Sorting multi-segment bodies" "3479": "handmade_render_group.cpp: Introduce ComputeSortKey in order to facilitate correct sorting of articulated figures" "3597": "handmade_render_group.cpp: Revert changes in GetRenderEntityBasisP for the time being" "3678": "Run the game and see the havoc" "3738": "handmade_entity.cpp: Plan for handling articulated figures next week" "3931": "Q&A" "3972": "Kind of didn't get it from the email - are you still up to putting a break sometime soon and make a little intro series to programming?" "4038": "Another use case to consider for the Y- / Z-sorting: "flat" things laying on top of other "flat" things (like a rug on a floor). How would the Y-sort position be set in this case, especially if the thing on top was larger than the thing(s) it was laying on?" "4143": "You wanted to go a bit more serious than Intro to C early on. Maybe you changed your mind since" "4158": "What do you think of representing entities as 3D objects to keep things simple? Like cylinders for characters, and cubes for tiles and rooms?" "4266": "Blackboard: Sorting rugs and floors" "4484": "Blackboard: Considering this in 3D" "4633": "Maybe you need to sort the objects separately in both Y and Z and then solve the conflicts if an object A is before object B in the Y-sort and in reverse order in the Z-sort?" "4828": "Close down, to be continued..." --- name: "day299" title: "Improving Sort Keys Part 2" markers: "11": "Recap and set the stage for the day" "111": "Blackboard: Tile Z Sorting" "158": "Blackboard: How to sort when looking directly top-down" "368": "Blackboard: The complication that arises from tilting the camera" "509": "Blackboard: Quantising entities to tiles" "614": "Blackboard: The problem with rugs" "782": "Blackboard: Painter's Algorithm" "875": "Blackboard: The cases of the rug situation" "1323": "Blackboard: Top-down 2D vs 3D" "1621": "Blackboard: Using planar maths" "1782": "Blackboard: Considering this as a 3-dimensional problem" "2162": "Blackboard: Flat vs Upright Entities" "2510": "Blackboard: The problem of Y inside a single cell" "2792": "Blackboard: The case with a tilted camera looking down on a hero standing on a rug" "2993": "Blackboard: Using the closest point entities have in common to determine the sorting" "3514": "Q&A" "3599": "If you're only concerned about sprites that exist on more than one cell, why not split the polygons on cell boundaries? There can't be that many / can't be that expensive?" "3748": "Wind down" --- name: "day300" title: "Changing from Sort Keys to Sort Rules" markers: "49": "How 2.5D Sorting Works in River City Ransom: Underground" "589": "On doing a semantic sort" "771": "handmade_render_group.h: Consider separating out the topological sorting from the render group" "888": "handmade_entity.cpp: Consider making UpdateAndRenderEntities() draw pieces in front of other pieces" "1078": "Blackboard: Sorting Rules" "1226": "Blackboard: Considering the fact that we only need to sort sprites that overlap" "1285": "Blackboard: The three nominal cases involving Z planar and Y planar sprites" "1379": "Blackboard: Z overlaps Z" "1845": "Blackboard: Y overlaps Z" "2083": "Blackboard: Y overlaps Y" "2343": "Blackboard: Consolidating these cases" "2683": "Blackboard: Considering whether this scheme will allow us to sort completely" "3032": "handmade_sort.cpp: Introduce sort_sprite_bound and make MergeSort() take it" "3179": "handmade_sort.cpp: Introduce IsInFrontOf() in order to handle our three cases" "3727": "handmade_sort.cpp: Introduce a Swap() that takes sort_sprite_bound" "3758": "Q&A" "3778": "Isn't it Y (vertical) sprites that have YMin == YMax?" "3797": "handmade_sort.cpp: Correct the sense of BothZSprites in IsInFrontOf()" "3811": "You always do == float comparisons. How can you ensure those will ever return true because of float precision?" "3901": "In the Y overlaps Z case, what about cliff sides that are holding up the ground sprites (so elevated ground isn't just floating there)? Would that cause an issue with anything?" "3920": "Blackboard: Breaking problematic sprites into two pieces" "3997": "I literally did the "float ==" thing last week and considered it acceptable for that exact reason, because I was just checking if a value had just been set by me to an exact value on the previous frame or whatever" "4169": "Close it down" --- name: "day301" title: "Sorting with Sprite Bounds" markers: "2": "Recap and set the stage for the day" "277": "handmade_sort.cpp: Double check that the sense of IsInFrontOf() is correct" "346": "handmade_sort.cpp: Consider how to get sorting into layers for free, and turning the whole renderer into sprite-bound sorting" "575": "handmade_render_group.h: Consider excising SortKey entirely from entity_basis_p_result" "652": "handmade_render_group.cpp: Make PushRenderElement_() take a sort_sprite_bound rather than SortKey" "793": "handmade_sort.cpp: Separate sort_sprite_bound out into sprite_bound and make IsInFrontOf() take sprite_bound" "901": "handmade_sort.cpp: Consider which are the correct values to pass to PushBitmap()" "1034": "handmade_render_group.h and *.cpp: Delete SortKey from entity_basis_p_result" "1135": "handmade_render_group.cpp: Make PushBitmap() set the SpriteBound.YMin and .ZMax for Upright sprites" "1422": "handmade_render_group.cpp: Make PushBitmap() set the SpriteBound.YMin, .YMax and .ZMax for non-Upright sprites" "1528": "handmade_render_group.cpp: SpriteBound" "1592": "handmade_render_group.cpp: Consider making PushRect() do the same calculations as PushBitmap(), and make Clear() sort below everything" "1668": "handmade_render_group.cpp: Introduce GetBoundFor() and pull functionality into it from PushBitmap()" "1754": "Run the game and run into a world of hurt very quickly" "1804": "handmade_sort.cpp: Introduce GetSortEntries() in order to cast Entries to sort_sprite_bound" "1948": "handmade_render.cpp: Make SortEntries() call GetSortEntries() and no longer call RadixSort() in favour of MergeSort()" "2065": "handmade_render.cpp: Pull GetSortEntries() in from handmade_sort.cpp: and introduce GetSortTempMemorySize()" "2123": "win32_handmade.cpp: Make WinMain() call GetSortTempMemorySize()" "2193": "handmade_sort.cpp: Make SortEntries() a TIMED_FUNCTION()" "2255": "Debugger: Step into SortEntries() and inspect the SortKey values for EntryA and EntryB" "2462": "handmade_sort.cpp: #if 0 the HANDMADE_SLOW code in SortEntries(), run the game and see nothing" "2530": "handmade.cpp: Make GAME_UPDATE_AND_RENDER() just play the Cutscene" "2580": "Debugger: Break into SortEntries() and ensure that the sense of the IsInFrontOf() and MergeSort() are correct" "2843": "build.bat: Disable HANDMADE_INTERNAL and #define DEBUG_ macros in handmade_debug_interface.h" "2946": "Debugger: Break into SortEntries() and inspect the SortKey() values for the first 8 Entries" "3023": "Mini Owl of Shame Moment: This is not a front-to-back renderer" "3054": "handmade_sort.cpp: Make IsInFrontOf() sort in the correct direction" "3107": "Run the game and find that our fundamentals are not completely messed up" "3155": "handmade.cpp: Make GAME_UPDATE_AND_RENDER() go straight to the game, and then run the game and determine that we never fail our check in an obvious linear sweep" "3216": "handmade_entity.cpp: Make UpdateAndRenderEntities() draw entities in Z without flattening them to the plane" "3279": "Run the game and find that we're not getting the expected sort" "3305": "build.bat: Enable HANDMADE_INTERNAL" "3368": "Q&A" "3425": "Hey Casey, managed to make the stream today. Just wanted to pop in and say hi" "3520": "The coordinates used for the sort rules are world space, right? Would another approach be to sort the screen space coordinates from the top of the screen down?" "3554": "Blackboard: Cases against being able to sort screen space without Z" "3886": "I have a question about your development approach: I don't think I've ever seen you create a separate program or environment to test stuff. You always seem to work within the running game. Do you ever find this "noisy"?" "4217": "I realise I tell a lie now. I have seen you do something along those lines on Witness Wednesdays, just less so on Handmade Hero" "4367": "How do you clean all the directories without deleting them?" "4465": "Demo Math Visualizations" "4980": "That was really awesome to see! Thanks!" "5008": "Close it on up" --- name: "day302" title: "Confirming No Total Ordering" markers: "75": "handmade_render_group.cpp: Correctly compute the SpriteBound values in GetBoundFor()" "143": "Recap and set the stage for the day" "402": "handmade_render_group.cpp: Enable SortEntries() to do a total ordering check" "734": "Run the game, try doing the new check and hit our Assertion" "766": "Debugger: Inspect the SortKey values for EntryA and EntryB" "928": "handmade_sort.cpp: Temporarily change the Assert in SortEntries() to a BreakHere, and count the SortErrors" "1042": "Debugger: Break into SortEntries() to see how many sort errors there were" "1093": "Blackboard: Sort Partial Ordering Problem" "1243": "Blackboard: Turning our Partial Ordering into a Total Ordering" "1440": "handmade_sort.cpp: Consider making IsInFrontOf() sort by distance from the camera" "1580": "Blackboard: Sorting by distance from the camera" "1783": "Blackboard: Orthographic camera" "1975": "Blackboard: Will taking the topmost point of cards be sufficient?" "2125": "handmade_sort.cpp: Introduce BuildSpriteGraph()" "2450": "Blackboard: Graph Theory" "2594": "Blackboard: Directed Graph" "2667": "Blackboard: Directed Acyclic Graph" "2803": "handmade_sort.cpp: Continue implementing BuildSpriteGraph()" "2985": "handmade_math.h: Introduce a version of RectanglesIntersect() that takes rectangle2" "3151": "handmade_sort.cpp: Consider partitioning the screen in order to build this graph and potentially using the Z-buffer" "3340": "handmade_sort.cpp: Consider leveraging the screen partitioning in order to optimise the software renderer" "3375": "Q&A" "3423": "How much more work would you have to do to get a full 3D sorting?" "3527": "I mean, use fake 3D data, since our cards are essentially flat, we can give an epsilon width to it for the sorting" "3555": "Blackboard: Sorting 3D objects" "3758": "Blackboard: Sorting all entities in a linear total ordering" "4255": "Blackboard: Common problematic cases in Handmade Hero" "4463": "Sorry if this was already answered, but what was the issue with a "return a_z != b_z ? a_z - b_z : a_y - b_y" style total ordering?" "4481": "Blackboard: The problem with sorting heroes behind walls on rugs on tiles" "4742": "Would the Y then Z sort work if Z is quantized to room layers, and sprites are split where they cross layers (and maybe the ground is special cased)?" "4810": "Wind it down" --- name: "day303" title: "Trying Separate Y and Z Sorts" markers: "50": "Be our own code fairy" "76": "Recap and set the stage for the day" "117": "Z-buffering is not a good idea for 2D stuff" "248": "quartertron's sorting suggestion, or potentially using an insertion sort to make a poor man's binary space partition" "424": "Blackboard: Separately sorting Z-sprites and Y-sprites, then merge sorting those sorted sprites" "863": "handmade_sort.cpp: Introduce versions of MergeSort() for MergeSortY() and MergeSortZ()" "1169": "handmade_sort.cpp: Introduce versions of IsInFrontOf() for IsInFrontOfY() and IsInFrontOfZ()" "1251": "Consider how to separate the Y- and Z-sprites" "1406": "handmade_sort.cpp: Make MergeSort() separate the Y- and Z-sprites" "1452": "Blackboard: Separating and compacting an array" "1514": "handmade_sort.cpp: Continue making MergeSort() separate out those sprites" "1675": "Blackboard: The sizes of the two arrays" "1748": "handmade_sort.cpp: Make MergeSort() call MergeSortY() and MergeSortZ()" "1861": "Blackboard: Copies of the sorted stuff" "1917": "handmade_sort.cpp: Consider making MergeSortZ() copy to the Temp buffer" "2004": "handmade_sort.cpp: Make MergeSort() copy to the Temp buffer if there are 1 or 2 Z-sprites to be sorted" "2356": ""It's no skin off our back"" "2358": "handmade_sort.cpp: Clean up compile errors" "2481": ""We probably need to go through this code more carefully"" "2534": "Run the game and see that we are sort of anywhere close" "2571": "Run the game and hit the assertion in SortEntries()" "2621": "Debugger: Break into MergeSort() and inspect the YCount and ZCount" "2702": "handmade_sort.cpp: Give MergeSort() some verification tests" "2731": "handmade_sort.cpp: Introduce IsZSprite()" "2787": "handmade_sort.cpp: Continue giving MergeSort() these tests" "2825": "Debugger: Break into MergeSort() and find that it passed the tests" "2839": "handmade_sort.cpp: Introduce VerifyBuffer() to verify the type of sprites in that buffer, and make MergeSort() call it" "2963": "Debugger: Break into MergeSort() again and find that everything is in the right place" "2998": "Consider making a better merge" "3098": "Blackboard: What the sort is doing" "3190": "handmade_sort.cpp: Look at what IsInFrontOf() is doing" "3328": "handmade_sort.cpp: Make VerifyBuffer() verify that the sprites are correctly sorted" "3386": "Debugger: Run the game and hit the assertion in VerifyBuffer()" "3413": "A few words on "test driven development"" "3482": "Debugger: Break into VerifyBuffer() and inspect the positions of the sprites upon failing" "3578": "handmade_sort.cpp: Turn MergeSortY() into MergeSort() in order to do IsInFrontOf() in both cases" "3637": "handmade_sort.cpp: Rename MergeSort() to SeparatedSort(), and remove MergeSortZ() entirely" "3677": "Debugger: Run the game and catch some sprites that our test thinks are incorrectly sorted" "3759": "handmade_sort.cpp: Temporarily toggle SortEntries() to do only the partial ordering check" "3774": "Run the game and see the visual results" "3792": "Q&A" "3937": "I'm trying to take a different approach, using the projected sprites on the screen to sort, and using the min / max y values (up) as a depth sorting key" "3979": "Working on it" "4044": "What is a full stack developer?" "4208": "Won't sorting fail because a lower Z sometimes needs to be drawn on top of a higher Z if a Y-sprite overlaps them?" "4265": "Blackboard: PoohShoes's diagram" "4372": "At the start you mentioned "insertion sort" and potentially automatically getting a binary tree representation of the sprites. What happened to that idea, assuming I roughly understand correctly what you've done?" "4391": "Blackboard: Graph sort" "4489": "How do you transform the sprites from world to screen coordinates?" "4511": "That's it for today" --- name: "day304" title: "Building and Traversing Graphs" markers: "74": "Recap and set the stage for the day" "172": "handmade_sort.cpp: Briefly look through what BuildSpriteGraph() does" "308": "Blackboard: Graph sort" "515": "Blackboard: Subgraphs, and marking each node you touch" "578": "Blackboard: Cycles" "701": "Blackboard: The steps involved in doing this graph sort" "832": "handmade_sort.cpp: Reorganise our graph structs" "1002": "handmade_sort.cpp: Begin to implement BuildSpriteGraph() for real" "1313": "Blackboard: Traversing the edges from foremost to backmost" "1417": "handmade_sort.cpp: Continue implementing BuildSpriteGraph()" "1471": "handmade_sort.cpp: Introduce WalkSpriteGraph()" "1567": "handmade_sort.cpp: Introduce RecursiveFromToBack()" "1770": "handmade_sort.cpp: Introduce enum sprite_flag, in order to mark sprites as visited and drawn" "1927": "handmade_sort.cpp: Make BuildSpriteGraph() and RecursiveFromToBack() use those flags" "2054": "Blackboard: Note that we've done the graph sorting steps out of order" "2102": "handmade_sort.cpp: Introduce struct sprite_graph_walk in order to keep track of our location in the graph" "2357": "Consider how we'll need to proceed" "2438": "handmade_sort.cpp: Clean up compile errors" "2538": "handmade_sort.cpp: Make BuildSpriteGraph() and SortEntries() take a memory_arena" "2630": "Consider doing the sort in pieces that don't interfere with one another" "2879": "Blackboard: Treating the game sort data and the debug sort data separately" "3160": "win32_handmae.cpp: Consider issuing RenderCommands() and LinearizeClipRects() in two separate places" "3309": "handmade_sort.cpp: Prevent BuildSpriteGraph() from calling PushStruct()" "3353": "win32_handmade.cpp: Prevent Win32DisplayBufferInWindow() from calling SortEntries()" "3376": "Run the game and find that the entries aren't sorted but that we don't crash" "3386": "Q&A" "3470": "Did you discuss why you are using recursion and any concerns with stack overflows?" "3544": "Working with graphs can be difficult; do you have any techniques for debugging them other than observing screen renders, or is that mostly sufficient?" "3646": "Okay for real, did you address the possibility for intersecting sprites?" "3670": "When I code I use the mouse a lot. You seem to be using a lot of shortcuts to jump here and there. Can you tell more about your shortcuts? Thanks!" "3722": "Do you know the dev Garry Newman? If yes, what do you think about his work?" "3760": "sssmcgrath I stopped using Razer's drivers as soon as you needed an account" "3783": "What's that shirt?" "3840": "Wind it down" --- name: "day305" title: "Using Memory Arenas in the Platform Layer" markers: "31": "Recap and set the stage for the day" "122": "handmade_opengl.cpp: Consider making this whole file platform independent" "298": "handmade_platform.h: Consider moving platform_opengl_display_bitmap and platform_opengl_render_commands in from handmade_opengl.cpp" "430": "Consider (the downsides of) making all the platform layers include bindings and link the dll with opengl" "599": "win32_handmade.cpp: Make Win32DisplayBufferInWindow() call SortEntries(), and consider moving the sorting or the memory arena into the platform specific layer" "691": "Create handmade_memory.h and #include it handmade_shared.h" "1027": "Consider the concept of an overflow memory state" "1213": "win32_handmade.cpp: Make Win32DisplayBufferInWindow() take a memory_arena and create some temporarary_memory for SortEntries() and LinearizeClipRects() to use" "1440": "handmade_opengl.cpp: Make OpenGLRenderCommands() call GetSortedIndices()" "1503": "handmade_render.cpp: Make RenderCommandsToBitmap() call GetSortedIndices()" "1562": "handmade_platform.h: Introduce game_render_prep struct and make the necessary functions take it" "1904": "handmade_render.cpp: Introduce PrepForRender()" "1997": "4coder: Request a mode that automatically creates a boundary in the bottom-right corner" "2032": "win32_handmade.cpp: Stop WinMain() from dealing with the ClipMemory and make LinearizeClipRects() in handmade_render.cpp do it itself" "2137": "On the importance of good utility functionality" "2489": "Create handmade_render.h and stick the sprite structs in there" "2990": "Run the game and hit the assertion in OpenGLRenderCommands()" "3130": "handmade_render.cpp: Assert that OutIndex - OutIndexArray == InputNodeCount in WalkSpriteGraph(), and make SortEntries() traverse the nodes and write the indices of them" "3281": "Run the game and see that all of our stuff is flowing without crashing" "3315": "handmade_render.cpp: Make RecursiveFromToBack() correctly increment the OutIndex" "3349": "Run the game and hit the assertion in BuildSpriteGraph()" "3370": "handmade_render.cpp: Explain how RecursiveFromToBack() is working" "3510": "handmade_render_group.cpp: Make PushRenderElement_() clear Flags" "3582": "Run the game, confirm that our sort isn't working and consider how to make it work" "3763": "Q&A" "3872": "Line 31?" "3965": "Since no on-topic, off-topic: Will the final game be orthographic?" "4002": "When you're calculating pre-allocated buffer locations with offsets, do you find the pointer bugs that pop up sometimes difficult to track down, or is that kind of a non-issue when you do it often enough?" "4434": "Which system did you start programming on, way back in the previous millennium?" "4495": "I know there is debug code for how long functions take. Is there any debug code for how much of a memory arena is being used?" "4547": "Recollections of the Rainbow 100 and Turbo Pascal" "4846": "Did you program on the Amiga?" "4867": "Did it have Word Star key bindings? That's really the test" "4874": "Close down" --- name: "day306" title: "Debugging Graph-based Sort" markers: "11": "Recap and set the stage for the day" "100": "Run the game and see the current state" "231": ""Let's use the word "evolucent""" "246": "handmade_render_group.cpp: Make PushRenderElement_() take and set the ScreenArea" "301": "handmade_render_group.cpp: Make PushRect() set the ScreenArea" "414": "handmade_render_group.cpp: Make PushBitmap() set a provisional ScreenArea for the sprite" "490": "Blackboard: The ScreenArea for Regular vs Rotated Sprites" "711": "handmade_render_group.h: Add ScreenArea to render_group and make Clear() take it" "1023": "handmade_render_group.cpp: Make Perspective() set the ScreenArea" "1095": "Debugger: Run the game, crash in BuildSpriteGraph() and inspect the ScreenArea values" "1218": "handmade_render_group.cpp: Look through GetRenderEntityBasisP() and note that NearClipPlane is set so that 0 is clipped out" "1259": "Debugger: Inspect the values of B" "1308": "handmade_render_group.cpp: Assert in PushRenderElement_() that GetArea(ScreenArea) < 2000 * 2000" "1408": "handmade_math.h: Introduce GetArea()" "1476": "Debugger: Run the game and hit that assertion, then step out and see who called that function" "1573": "handmade_render_group.cpp: Comment out that assertion, run the game and look at the actual bug" "1588": "handmade_render.cpp: Reenable the PushStuct() call in SortEntries()" "1614": "Run the game and see that we're running incredibly slowly" "1647": "handmade_render.cpp: Make BuildSpriteGraph() and WalkSpriteGraph() a TIMED_FUNCTION" "1678": "build.bat: Switch to -O2" "1704": "Run the game and realise that we can't see the debug display because it isn't sorted correctly" "1746": "build.bat: Switch back to -Od" "1792": "Run the game and see that we're getting some pretty non sequitur results" "1846": "handmade.cpp: Switch back to the title sequence in order to see how the sorting routine performs on these" "1903": "Note that the drop shadow of the text is being sorted incorrectly" "2022": "handmade_cutscene.cpp: Try and scramble the order of the first scene's layers" "2062": "Run the game and see that the scene is now incorrectly sorted" "2125": "Debugger: Break into BuildSpriteGraph() and inspect the values for A and B" "2156": "handmade_render.cpp: Prevent BuildSpriteGraph() from comparing NodeIndexA with itself" "2211": "Debugger: Break into BuildSpriteGraph() and see that A and B are now different" "2330": "Debugger: Step through BuildSpriteGraph() and see if it behaves as expected" "2463": "Debugger: Step through WalkSpriteGraph() and RecursiveFromToBack() and see if they behave as expected" "2737": "Debugger: Step through OpenGLRenderCommands() and inspect the SortedIndices array" "2829": "handmade_cutscene.cpp: Make RenderLayeredScene() DebugTag the cutscene layers" "3034": "Debugger: Run the game, step through BuildSpriteGraph() and RecursiveFromToBack() and watch the DebugTag values" "3150": "handmade_cutscene.cpp: Revert the cutscene layers to their original order" "3175": "Debugger: Step through RecursiveFromToBack(), watch the DebugTag values and confirm that the code is doing what we think it is doing" "3267": "handmade_render.cpp: Look through how the sort_sprite_bound flows through the functions" "3410": "handmade_cutscene.cpp: Note the reason why the cutscene was sorting as it was" "3492": "handmade_world_mode.cpp: Make UpdateAndRenderWorld() only generate one screen and disable the Monstar" "3618": "handmade_world_mode.cpp: Prevent AddStandardRoom() from calling BeginGroundedEntity()" "3636": "Run the game and hit the Assert in OpenGLRenderCommands() because ClipRectCount == 0" "3699": "Debugger: Investigate how we ended up with no ClipRects" "3927": "handmade_render_group.cpp: Make BeginRenderGroup() rather than Perspective() take the PixelWidth and PixelHeight in order to compute the ScreenArea, and call PushClipRect()" "4166": "handmade_world_mode.cpp: Make AddStandardRoom() create one tile" "4197": "Run the game and see that our sort appears to handle our Y-sprites just fine, but that our Z-sprites are all messed" "4232": "Defer questions until Monday and end it now" --- name: "day307" title: "Visualizing Sort Groups" markers: "11": "A few words on the bonuses of programming on stream" "127": "Run the game and demo the bug" "160": "handmade_world_mode.cpp: Reenable the else clause in AddStandardRoom() to generate the rest of the room" "203": "handmade_render_group.cpp: Correct RectMinMax to RectMinDim in PushRect()" "274": "Run the game and see how the sprites are sorted with that typo having been corrected" "426": "build.bat: Toggle HANDMADE_INTERNAL on" "492": "Run the game and see the profiler being sorted improperly" "542": "Consider augmenting our ability to see how the sort is behaving" "707": "handmade_entity.cpp: Disable the volume highlighting and the PushRectOutline for the traversables" "772": "Run the game and note that the speed has increased, and that the trees are all now sorted properly" "874": "handmade_world_mode.cpp: Make AddStandardRoom() add a room above" "904": "Run the game and see that the sort is actually wrong" "935": "handmade_opengl.cpp: Make OpenGLRenderCommands() draw the sprite bounds" "1093": "handmade_render.h: Add Sprite_DebugBox to the sprite_flag enum" "1122": "handmade_opengl.cpp: Continue working on OpenGLRenderCommands()" "1165": "handmade_opengl.cpp: Introduce OpenGLDrawBoundsRecursive()" "1327": "handmade_opengl.cpp: Make OpenGLRenderCommands() draw each bound in a different colour" "1624": "Run the game and see that it does nothing" "1636": "handmade_opengl.cpp: Make OpenGLRenderCommands() call glDisable(GL_TEXTURE_2D) before the bounds drawing routine" "1677": "handmade_opengl.cpp: Make OpenGLDrawBoundsRecursive() draw a line between the centres of two sprite bounds" "1839": "handmade_opengl.cpp: Introduce OpenGLLineVertices()" "1913": "handmade_opengl.cpp: Make OpenGLDrawBoundsRecursive() call OpenGLLineVertices()" "1947": "Run the game and see our new debug visualisation" "2015": "handmade_world_mode.cpp: Disable the Clear() in UpdateAndRenderWorld() for now" "2031": "Run the game, see it without the Clear and consider how best to slipstream that Clear into the process" "2224": "handmade_opengl.cpp: Make OpenGLRenderCommands() call glClear() and consider leaving the Clear() off in UpdateAndRenderWorld()" "2242": "handmade_opengl.cpp: "Get our hideous pink on"" "2301": "handmade_platform.h: Add a ClearColor to the game_render_commands struct and change how the screen clearing works in general" "2506": "Run the game and see what happens now" "2566": "handmade_opengl.cpp: Enable OpenGLRenderCommands() to toggle drawing the sprite bounds" "2686": "Run the game and try toggling the sprite bounds" "2714": "handmade_world_mode.cpp: Make AddStandardRoom() draw multiple layers" "2754": "Run the game and see the state of our sorting" "2799": "Blackboard: Sort Error Sources" "2850": "Blackboard: Bugs" "2869": "Blackboard: Bad Comparison" "2936": "Blackboard: Graph Cycle Resolution" "3066": "Consider drawing graph cycles, and ways to resolve cycles" "3180": "Blackboard: Generation Tag" "3272": "Blackboard: Erasable Bit" "3333": "handmade_render.h: Add Sprite_Cycle to the sprite_flag enum" "3382": "handmade_render.cpp: Make RecursiveFromToBack() first set and later clear the Sprite_Cycle" "3434": ""You know it's been a bad day when you don't know where the ~ key is"" "3440": "handmade_render.h: Add HitCycle to the sprite_graph_walk struct" "3484": "handmade_render.cpp: Make WalkSpriteGraph() and RecursiveFromToBack() work in tandem with that HitCycle" "3574": "handmade_opengl.cpp: Make OpenGLRenderCommands() only draw the sprite bounds for sprites that cycle" "3620": "Run the game and see no cycles" "3659": "Q&A" "3685": "Wherefore art thou... Can't wait to watch that stream begins?" "3746": "Programming won't necessarily be in your life forever. I feel like you will eventually settle down and write fiction novels" "3760": "How do you decide when a problem is complex enough to need visualization?" "3951": "Is the build graph still O(n^2)?" "4071": "When can we download JACS Season 5?" "4095": "Wrap it up" --- name: "day308" title: "Debugging the Cycle Check" markers: "13": "Recap and set the stage for the day" "79": "Run the game and show where we left things" "126": "handmade_opengl.cpp: Make OpenGLRenderCommands() draw a black border around the render entries" "501": "Run the game and see what our outlines are telling us" "618": "handmade_opengl.cpp and handmade_render.cpp: Look through the collision group drawing routines and consider what could be wrong" "735": "handmade_render.cpp: Rename RecursiveFromToBack() to RecursiveFrontToBack()" "794": "handmade_render.cpp: Make RecursiveFrontToBack() set and check things in the correct order" "860": "Run the game, see the cycles in our sort graph and investigate them" "994": "handmade_world_mode.cpp: Make AddStandardRoom() only generate one room, run the game and see what happens with cycles" "1262": "handmade_opengl.cpp: Make OpenGLRenderCommands() draw collision groups lightly, then increase their alpha when they cycle" "1322": "Run the game and view the cycles" "1432": "Consider how we're doing the sorting in the first place" "1638": "Continue to investigate what's happening with the cycles" "1774": "handmade_render_group.cpp: Change where PushRectOutline() draws the four edge rectangles" "1863": "Blackboard: Drawing an outline out of non-intersecting rectangles" "2114": "Blackboard: What RectanglesIntersect() is currently doing" "2226": "handmade_render_group.cpp: Make PushRectOuline() add an epsilon into the equation" "2251": "Run the game, see that our outlines no longer cause a cycle, but that our hero still does" "2645": "handmade_debug.cpp: Make DEBUGEnd() draw one character, run the game and step through SortEntries" "2849": "handmade_render_group.cpp: Make GetBoundFor() use the SortBias" "2931": "Run the game and see that the debug text is now correctly sorted" "3067": "handmade_render.cpp: Look at IsInFrontOf()" "3247": "Blackboard: How IsInFrontOf() is working" "3330": "Run the game and illustrate the possibility that we may actually be in okay shape here" "3410": "handmade_world_mode.cpp: Toggle AddMonstar() and AddFamiliar() back on" "3482": "Q&A" "3545": "I couldn't drop that into The Witness, then. FailFish Really. Kappa?" "3566": "It looks like the torso sprite occasionally draws on top of the head sprite, e.g. going up stairs" "3601": "Blackboard: How the hero is constructed" "3678": "Does collision work between stairs and hero? Because body under and head above the stairs should not happen" "3849": "Do you anticipate similar (if not identical) graph sorting would be used for any other game purpose (other than sprite sort)?" "3940": "What language is this?" "4000": "What are a few pieces of advice you would give to a new programmer?" "4145": "What is your estimate time it will take for you to finish Handmade Hero? And how different is it from the original estimate? (I assume you are about halfway)" "4373": "Off-topic: At the start of the show, you said that every game programmer uses a dev setup similar to what we use: debug with Visual Studio, but code with a different editor. Why?" "4505": "Are you enjoying this project as a programming challenge or are your efforts mainly put into the teaching part of it?" "4632": "What do you think about unit testing and test driven development applied to C++ code? Is this technique really useful and worth trying?" "5202": "It's because you are the only programmer! When working in a team that will use your code, you need const" "5364": "I programmed in 100% const correct for 5 years. Never again" "5381": "Close it on out" --- name: "day309" title: "Grid Partitioning for Overlap Testing" markers: "9": "Recap and set the stage for the day" "113": "Run the game and see where we left off" "245": "handmade_entity.cpp: Toggle off the volume highlighting in UpdateAndRenderEntities()" "273": "Lose the hoodie" "291": "Run the game and consider putting good data into the sorting routine so that it can do stable sorts" "358": "Consider how to proceed" "453": "Determine to solve our n^2 problem" "596": "Blackboard: The problem with determining which sprites overlap" "743": "Blackboard: Grid Partitioning as a way to mitigate routines proportionate to n^2" "861": "Blackboard: Testing for overlap in one dimension" "1064": "Blackboard: How to do this bucketing, or spatial partitioning" "1208": "Blackboard: Breaking up each entity" "1247": "Blackboard: Creating a more hierarchical notion of what the space looks like" "1447": "Blackboard: Quadtree, KD Tree and BSP Tree" "1610": "Blackboard: Favouring a very simple grid bucketing scheme" "1788": "Run the game and consider how expensive the BuildSpriteGraph() is" "1930": "Start with something fairly stupid" "1945": "handmade_render.cpp: Introduce sort_grid_entry struct and make BuildSpriteGraph() record if a sprite occupies a grid square" "2278": "handmade_render.cpp: Consider some immediate possibilities for optimisation" "2399": "handmade_render.cpp: Consider making RecursiveFrontToBack() not create the edges of the graph" "2545": "handmade_render.cpp: Introduce GetGridSpan()" "2839": "Blackboard: Adding edges from the perspective of grid testing" "3035": "handmade_render.cpp: Make GetGridSpan() bin the incoming screen area versus the total screen area" "3218": "handmade_render.cpp: Make BuildSpriteGraph() compute the InvCellDim" "3384": "handmade_render.cpp: Make GetGridSpan() work a little differently" "3599": "Run the game and note that we are now bucketing" "3622": "Q&A" "3686": "Using the grid system, do you think that would be good to use for pixel perfect collision?" "3711": "Blackboard: Determining whether rectangles and then possibly pixels intersect" "3834": "Why not have the debug overlay render to a separate layer, and have it draw in the order submitted instead of wasting time sorting?" "3940": "I think a sort-free mode would work well with the cutscene as well" "4030": "Missed the stream again, why do you not use the summed rectangle of the hero sprites for draw sorting, and draw the individual parts in a set order?" "4105": "Something exciting happening over at Molly Rocket?" "4119": "Can using C programming optimize the game more than C++?" "4375": "RTTI" "4449": "Wind it down" --- name: "day310" title: "Finishing Sort Acceleration via Gridding" markers: "9": "Recap and set the stage for the day" "103": "win32_handmade.cpp: Toggle on GlobalShowSortGroups, run the game and view those graphs" "239": "handmade_render.cpp: Accelerate BuildSpriteGraph() by making it loop through everything in each grid cell when we do an insertion" "525": "Run the game and see how our ACCELERATED_SPRITE_SORT fares" "608": "handmade_render.h: Increase the resolution of the SORT_GRID, run the game and see how this affects the speed of BuildSpriteGraph()" "720": "build.bat: Temporarily switch to -O2, run the game and see that this drastically improves the speed of BuildSpriteGraph()" "775": "handmade_render.cpp: Pass NoClear() to the PushStruct() calls in BuildSpriteGraph()" "914": "Run the game and consider the possibility that we may be checking things multiple times" "1049": "Blackboard: How the grid partitioning makes us check things multiple times" "1159": "Blackboard: Our two options for avoiding this" "1234": "Consider how to tag the sprites as having been touched" "1373": "handmade_render.h: Move the existing flags in the sprite_flag enum into the high bits and add Sprite_IndexMask" "1511": "handmade_render.cpp: Make BuildSpriteGraph() & the B->Flags with Sprite_IndexMask" "1624": "Run the game and see that the cycles are much rarer" "1654": "Explain what just happened" "1752": "win32_handmade.cpp: Toggle GlobalShowSortGroups off, run the game and see how our changes have affected the speed of BuildSpriteGraph()" "1886": "Blackboard: Manual Sort Override" "2248": "Blackboard: Edges Added Manually" "2394": "Blackboard: Specifying Sprites to be Drawn as a Group" "2560": "handmade_render.h: Consider adding a Count to the sort_sprite_bound struct" "2672": "handmade_render_group.h: Try adding a NextOffset to the render_group_entry_header struct" "2798": "handmade_opengl.cpp: Make OpenGLRenderCommands() daisy-chain the render entries" "2997": "Run the game, demo a sorting situation we need to resolve and consider how to resolve it" "3180": "Blackboard: Why put the daisy-chaining into the actual sorting system" "3321": "handmade_render_group.cpp: Provisionally make PushRenderElement_() only sort a NewElement, otherwise merge the Existing entry" "3683": "Compile and run properly" "3694": "Q&A" "3727": "Thanks to the grid partitioning, do we now have a convenient way of doing the graph sort in SIMD, possibly processing four grid squares, or four sprites within a square, at once? Or is it not quite that simple?" "3938": "With regards to the flags and the order checking, if you are &ing the flags with the id, to test if you have seen it before, what happens when another item does the same check and &s it with the same (changed) unit? Doesn't that make the result different to the check flags & mask = id for the new item? Did I miss something (or did you & the flags with the mask before you set the id to clear it (the old id) first?" "4019": "Blackboard: How the Flags and the Sprite_IndexMask is working" "4177": "handmade_render.cpp: Streamline BuildSpriteGraph() a touch" "4419": "Will we ever do any network programming on Handmade Hero (i.e. multiplayer)?" "4448": "I love how you said "we don't want to solve this with hacks" for a particular sorting condition. Do you think the engine should cover most / all boundary conditions or is there room for "boundary hacks" in certain / extreme circumstances?" "4493": "Blackboard: On not having the necessary information to do a correct sort in 2D" "4665": "Close down" --- name: "day311" title: "Allowing Manual Sorting" markers: "10": "Recap and set the stage for the day" "268": "Plan to provide the ability to sort a collection of sprites" "338": "Blackboard: Our options for sorting a collection of sprites" "672": "Run the game and see our current situation" "738": "handmade_render_group.cpp: Remove NewElement from PushRenderElement_(), and introduce the notion of a writeback for the SortKey which overwrites a previously written SortKey with new information" "973": "handmade_render_group.cpp: Consider making PushBitmap() return something for PushRenderElement_() to take and modify" "1051": "handmade_entity.cpp: Make UpdateAndRenderEntities() call BeginAggregateSortKey() and EndAggregateSortKey() which marks which entities share a SortKey" "1382": "handmade_render_group.cpp: Implement BeginAggregateSortKey() and EndAggregateSortKey()" "1825": "handmade_render_group.cpp: Enable PushRenderElement_() to correctly set the AggregateBound for Y- and Z-sprites" "1910": "handmade_render.cpp: Introduce IsYSprite()" "2178": "Run the game and see that it actually looks somewhat workable" "2255": "handmade_render_group.h: Remove the daisy-chaining from the render_group_entry_header struct" "2392": "Run the game and consider the question of what order we put the hero sprites in" "2411": "handmade_world_mode.cpp: Reorder the AddPiece() calls in AddPlayer()" "2444": "handmade_world_mode.cpp: Stop those AddPiece() calls from taking such tweaky values" "2556": "Consider how to articulate the intention that one sprite (e.g. the head) must always draw in front of another (e.g. the aggregated body)" "2995": "Blackboard: Manual Edge Specification" "3228": "Q&A" "3378": "How do I get insobot to ask a question?" "3414": ""insobot is kind of a national treasure"" "3418": "Close it down" --- name: "day312" title: "Cross-entity Manual Sorting" markers: "8": "Recap and set the stage for the day with an embarassing confession" "95": "Run the game and assess our current situation" "286": "Blackboard: Manual Edge Specification" "422": "handmade_entity.cpp: Make UpdateAndRenderEntities() only call BeginAggregateSortKey() if the PieceCount is > 1" "475": "Consider how to articulate the intention that one sprite (e.g. the head) must always draw in front of another (e.g. the aggregated body)" "635": "handmade_entity.h: Add ManualSortInFrontOf and ManualSortKey to the entity struct" "677": "handmade_brain.cpp: Make ExecuteBrain() set those values when a Head and Body are linked" "910": "handmade_brain.cpp: Enable ExecuteBrain() to talk to the RenderGroup" "981": "handmade_entity.cpp: Consider how to specify the render order in UpdateAndRenderEntities()" "1182": "handmade_render_group.cpp: Consider making BuildSpriteGraph() add some additional edges that force sorts" "1298": "Consider simplifying things" "1386": "Blackboard: Putting something into the SortKey to tag it as AlwaysInFrontOf or AlwaysBehind" "1425": "handmade_render.h: Add AlwaysInFrontOf and AlwaysBehind to the sort_sprite_bound struct" "1473": "handmade_render.cpp: Make IsInFrontOf() check if sprite_bound A is AlwaysInFrontOf or AlwaysBehind B, to save having to manually specify edges" "1659": "handmade_platform.h: Add LastUsedManualSortKey to the game_render_commands struct" "1675": "handmade_render_group.cpp: Introduce ReserveSortKey()" "1845": "handmade_entity.cpp: Make UpdateAndRenderEntities() set AlwaysInFrontOf and AlwaysBehind" "1926": "handmade_render.h: Introduce manual_sort_key struct" "1988": "handmade_render_group.cpp: Erase ComputeSortKey() and make GetBoundFor() copy the ObjectTransform.ManualSort to SpriteBound.Manual" "2137": "handmade_platform.h: Move manual_sort_key in from handmade_render.h with a mini-rant on the language" "2206": "Run the game and see how we're doing" "2242": "Debugger: Break into ExecuteBrain() and see if we're setting the SortKey" "2351": "handmade_entity.cpp: Add a BreakHere in UpdateAndRenderEntities() when an EntityTransform is not AlwaysInFrontOf or AlwaysBehind" "2407": "Debugger: Break in there and inspect the values" "2565": "handmade_render.cp: Correct a typo in IsInFrontOf()" "2584": "Run the game and see that that wasn't our only bug" "2595": "handmade_render.cpp: Make IsInFrontOf() check AlwaysInFrontOf and AlwaysBehind separately and correctly" "2881": "Run the game and see that we're in a better situation, but not quite perfect" "3049": "Toggle on GlobalShowSortGroups and identify that, when the sorting is incorrect, we have a cycle" "3238": ""Thank you, Mr Cycle Detection"" "3255": "Q&A" "3295": "Perhaps breaking the cycle on the in-front / behind pair?" "3409": "Will there ever be a case when the character's facing direction will change what we want for the sort order? I can think of a possible case if the characters had arms. Does the current method take these cases into account?" "3454": "Looking forward to rewatching that simplification from early on. I don't think I quite followed that live" "3521": "I'm the communications director at a game development studio in Montreal. I just found your stream minutes ago and it's very fascinating. Your trailer seems to convey the idea that a game is "better" if it's entirely handmade, from scratch. Do you feel a game can't be made with as much "love" if it uses a premade engine as opposed to one that's made entirely from scratch? Do you not feel like reinventing the wheel may be a waste of time?" "3572": "On the amount of love involved in making games whether from scratch or using a pre-made engine" "3776": "On reinventing the wheel, and the educational responsibility of Handmade Hero" "4072": "On the assumption that someone made a wheel" "4129": "Blackboard: Where the game industry is at in terms of inventing the wheel" "4255": "There is no wheel" "4552": "On love and money" "4594": ""Your goal has to be that the reason you want money is to make games, not the reason you make games is to make money"" "4743": "Close up shop" --- name: "day313" title: "Returning to Work on Z Layers" markers: "11": "Recap and set the stage for the day" "128": "handmade_world_mode.cpp: Make AddStandardRoom() generate multiple layers, run the game and see how wrong the sorting is" "204": "A few words of encouragement on exploratory programming and embracing the forward flow of the architecture" "336": "handmade_entity.cpp: Make UpdateAndRenderEntities() work as it did before the work on the sorting, run the game and see how it looks" "517": "Blackboard: Z Slices and Two Separate Conceptualisations of What it Means to be Up" "689": "Blackboard: Layered Alpha Blending" "1077": "Blackboard: Solving this Problem" "1174": "Blackboard: Render Buffers" "1292": "Blackboard: Back of the envelope calculation on the potential Graphics Memory available to us" "1453": "Blackboard: Back of the envelope calculation on the potential Memory Bandwidth available to us" "1761": "Consider how to proceed" "1818": "handmade_entity.cpp: Introduce a TestAlpha in UpdateAndRenderEntities()" "2041": "Run the game and see what happens" "2086": "Debugger: Break into UpdateAndRenderEntities() and inspect the fade values" "2405": "handmade_entity.cpp: Tweak the FadeTopEndZ and FadeTopStartZ values in UpdateAndRenderEntities(), and again break into it" "2547": "handmade_opengl.cpp: Pass Entry->PremulColor.a to the rectangle drawing glColor4f() call in OpenGLRenderCommands()" "2629": ""So I'm going to go work this out on the blackboard and figure out if I'm just... uh... on crack"" "2714": "handmade_entity.cpp: Subtract WorldMode->CameraOffset.z from the CameraRelativeGroundZ computation in UpdateAndRenderEntities()" "2742": "Run the game and see that we're fine again" "2820": "Blackboard: What RecanonicalizeCoord is doing" "2971": "Blackboard: Offsetting Z" "3061": "handmade_world_mode.cpp: Make ChunkPositionFromTilePosition() Offset the entities' Z downwards" "3192": "handmade_world_mode.cpp: Make ChunkPositionFromTilePosition() compute TileDepthInMeters differently" "3260": "Debugger: Break into ChunkPositionFromTilePosition() and inspect the offset values" "3458": "Debugger: Break into ConvertToLayerRelative() and inspect the Z values" "3590": "handmade_entity.cpp: Provisionally compute the relative layer we want for the entities" "3726": "Q&A" "3827": "Um. Because undefined behavior?" "3870": "What keyboard do you have?" "3940": ""Like putting your finger in a cloud"" "3960": "Do you expect that the final game will contain enough sprites to warrant using a texture atlas to reduce the number of texture binds per frame?" "4113": "I don't understand why the "base" Z value of each floor would be negative, it seems really contrived. It seems very logical to me to have 0 as as the "bottom". Maybe it has to do with rendering? I have not followed the latest shows" "4190": "Blackboard: Canonical Point for a Chunk" "4402": "Wrap it up" --- name: "day314" title: "Breaking Sprites into Layers" markers: "43": "Recap and set the stage for the day" "181": "Run the game and see where we're at" "320": "handmade_entity.cpp: Stop UpdateAndRenderEntities() from calling ConvertToLayerRelative() and instead calculate the RelativeLayer as worked out yesterday" "488": "handmade_entity.cpp: Make UpdateAndRenderEntities() get a WorldPos from MapIntoChunkSpace() in order to compute that RelativeLayer" "629": "Run the game and see that we're in much better shape" "662": "Consider introducing a concept in the render of the layer Z and the actual Z value" "764": "handmade_render.h: Add ChunkZ to the sprite_bound struct" "794": "handmade_render.cpp: Make IsInFrontOf() test that ChunkZ" "907": "handmade_render_group.h: Add ChunkZ to the object_transform struct" "940": "handmade_render_group.cpp: Make GetBoundFor() set the ChunkZ" "964": "Run the game and see that that doesn't affect anything" "981": "handmade_entity.cpp: Make UpdateAndRenderEntities() set that ChunkZ" "1003": "See how that affects the sort" "1101": "handmade_entity.cpp: Make UpdateAndRenderEntities() expand the bounds of the traversables to draw them like actual tiles" "1174": "Run the game and consider our cycling situation" "1252": "handmade_render.cpp: Shrink the sizes passed to the RectanglesIntersect() call in BuildSpriteGraph()" "1323": "handmade_debug.cpp: Make DEBUGStart() set the ChunkZ for the debug elements" "1393": "Run the game and toggle on the debug groups" "1495": "Consider how to leverage the layer data in the renderer" "1691": "handmade_entity.cpp: Simplify UpdateAndRenderEntities() so that it only knows about the alpha and the fog levels" "1945": "handmade_entity.cpp: Turn off the Alpha" "2015": "handmade_render_group.cpp: Make StoreColor() take a pointer to an object_transform and change all other functions to take a pointer to it" "2443": ""In theory this is a computer, yes?"" "2468": "handmade_entity.cpp: Make UpdateAndRenderEntities() set the Color and tColor for the top layer and the far fog" "2580": "Run the game, break into UpdateAndRenderEntities() and inspect the EntityTransform values" "2637": "handmade_entity.cpp: Make UpdateAndRenderEntities() reverse the TestAlpha computation" "2680": "handmade_world_mode.cpp: Make AddStandardRoom() generate multiple layers of rooms" "2700": "Run the game, see how those layers of rooms look and consult the profiler" "2739": "build.bat: Switch to -O2, run the game and consult the profiler again" "2776": ""Oh my god! Why are there so many heads following me?"" "2921": "Consider always rendering everyone with the ChunkZ they started with" "3034": "Blackboard: Sort Barriers" "3182": "handmade_render.h: #define SPRITE_BARRIER_OFFSET_VALUE" "3237": "handmade_render.cpp: Make BuildSpriteGraph() take and return NodeIndexA, which SortEntries() will pass to it" "3427": "Run the game and see that we have no change" "3442": "build.bat: Switch back to -Od, run the game and enable the sort groups" "3495": "Q&A" "3524": "Where are all those familiars coming from?!" "3675": "Snake looks broken?" "4007": "Wrap it up" --- name: "day315" title: "Un-reversing Sort Key Order" markers: "11": "Recap and set the stage for the day" "127": "Blackboard: Layered Sorting" "267": "Blackboard: How we currently pull entities out of the simulation for sorting" "464": "Blackboard: Our choices for doing this layered sorting" "650": "handmade_render.cpp: Consider how the code is currently working" "760": "handmade_entity.cpp: Make UpdateAndRenderEntities() sort on the old position of the Entity" "826": "handmade_entity.h and .cpp: Add ZLayer to the entity struct and make BeginSim() set that Dest->ZLayer" "866": "handmade_entity.cpp: Make UpdateAndRenderEntities() keep track of and conditionally operate based on the CurrentAbsoluteZLayer" "1113": "handmade_render_group.cpp: Introduce PushSortBarrier()" "1200": "Run the game and hit the assertion in BuildSpriteGraph()" "1223": "handmade_render.cpp: Read through BuildSpriteGraph() and make it break after incrementing the NodeIndexA" "1300": "Debugger: Hit the assertion in BuildSpriteGraph() and investigate what's happening" "1432": "handmade_render.cpp: Change LastIndex to OnePastLastIndex in SortEntries() and operate on it accordingly" "1597": "Debugger: Run the game, hit the assertion in RecursiveFrontToBack() and investigate why" "1723": "handmade_render.cpp: Prevent BuildSpriteGraph() from taking NodeIndexA but rather set it relative, and then simplify SortEntries()" "1913": "Debugger: Run the game and hit the assertion in OpenGLRenderCommands()" "1941": "handmade_render_group.cpp: Make PushSortBarrier() increment the PushBufferElementCount" "2033": "handmade_render.cpp: Make SortEntries() change the total number of things to reflect how many there are without barriers" "2177": ""It's like Doctors Without Barriers, you know what I'm saying?"" "2208": "Run the game and see that we are actually running, but that the sorting doesn't appear to be right per se" "2247": "Debugger: Step into UpdateAndRenderEntities() and investigate what's happening with the sorting" "2402": "handmade_render_group.cpp: Make PushSortBarrier() reverse the sense of the sort" "2498": "handmade_platform.h: Consolidate game_render_commands and game_render_prep into something more sane" "2627": "handmade_platform.h: Introduce GetSpriteBounds()" "2677": "handmade_render_group.cpp: Make PushSortBarrier() call GetSpriteBounds() and operate according to what it returns" "2818": "handmade_render_group.cpp: Make PushRenderElement_() similarly operate according to what GetSpriteBounds() returns" "2895": "handmade_render_group.cpp: Make BeginAggregateSortKey() and EndAggregateSortKey() work a little differently" "3052": "handmade_platform.h: Rename GetSpriteBounds() to GetSortEntries() and fix compile errors" "3267": ""Go away, Five minute warning!"" "3568": "Run the game and crash and burn" "3628": "handmade_render_group.cpp: Introduce push_buffer_result struct and PushBuffer() to do some of the work of PushRenderElement_()" "3928": "handmade_render_group.cpp: Make PushClipRect() call PushBuffer()" "4035": "handmade_render_group.cpp: Make PushBuffer() correctly set Result.SortEntry" "4051": "Run the game and hit the assertion in SafeTruncateToU16()" "4073": "Q&A" "4141": "Debugger: Step into PushRenderElement() and GameUpdateAndRender() and inspect the values" "4252": "handmade_platform.h: Make RenderCommandStruct() take the correct default values" "4322": "You mentioned earlier that the compiler would optimize the code making pointer comparison unsafe. When does that happen?" "4344": "Blackboard: "Memory Region" / "Allocation", and Pointer Arithmetic" "4619": "Assign homework" "4676": "Wrap it up" --- name: "day316" title: "Multiple Software Render Targets" markers: "57": "Recap and set the stage for the day" "91": "Debugger: Step into OpenGLRenderCommands() and inspect the Header" "143": "handmade_render_group.cpp: Make PushRenderElement_() correctly compute the Entry->Offset" "231": "Run the game and see how we're doing" "285": "handmade_world_mode.cpp: Make AddStandardRoom() only generate one room, run the game and again assess our situation" "338": "handmade_render_group.cpp: Ensure that PushRenderElement_() is correctly setting the Offset" "387": "Run the game and see our baseline" "390": "handmade_render_group.cpp: Tweak how BeginAggregateSortKey() and EndAggregateSortKey() work" "664": "handmade_world_mode.cpp: Revert AddPlayer() to pushing the player sprites in logical order" "701": "Run the game and identify that the head can still be sorted incorrectly when we have a cycle" "852": "handmade_world_mode.cpp: Make AddStandardRoom() generate multiple rooms" "882": "Run the game and find that we're now not getting those blinking tree bugs" "963": "Run the game and consult the profiler" "1040": "build.bat: Switch to -O2, run the game and again consult the profiler" "1164": "Run the game and demo the problem with alpha blending" "1252": "handmade_entity.cpp: Make UpdateAndRenderEntities() draw the traversables in red" "1285": "Run the game and demo the alpha blending problem" "1326": "handmade_entity.cpp: Make UpdateAndRenderEntities() draw the traversables half as wide as normal" "1356": "Run the game and most clearly demo the alpha blending problem" "1430": "handmade_render.cpp: Consider introducing the notion of a coherent block for SortEntries() to use" "1556": "Run the game and toggle between the software and hardware renderers" "1644": "Blackboard: Multiple Render Targets" "1906": "handmade_render.cpp: Make SoftwareRenderCommands() take a TempArena, take a renamed FinalOutputTarget and reserve a second OutputTarget" "2219": ""Oh, we VirtualAlloc'd that. Wow, aren't we fancy!"" "2234": "handmade_render.cpp: Make SoftwareRenderCommands() pass to PushSize() a call to AlignNoClear(16) in order to align it to 16-byte boundaries" "2261": "Run the game and see nothing on the screen" "2279": "handmade_render.cpp: Make SoftwareRenderCommands() copy the pixels from the OutputTarget in the FinalOutputTarget" "2329": "Run the game and see that we've made our renderer slower" "2343": "Blackboard: What SoftwareRenderCommands() is now doing" "2377": "handmade_render.cpp: Consider enabling SoftwareRenderCommands() to render to multiple render targets" "2501": "handmade_render_group.h: Add a RenderTargetIndex to the render_entry_cliprect struct" "2594": "handmade_render_group.cpp: Make PushClipRect() take a RenderTargetIndex in order that it can specify the RenderTarget to which it wants to render" "2695": "handmade_debug.h: Add RenderTarget to the debug_state struct" "2721": "handmade_render_group.cpp: Make PushClipRect() set RenderTargetIndex" "2771": "handmade_platform.h: Add MaxRenderTargetIndex to the game_render_commands struct" "2794": "handmade_render.cpp: Make SoftwareRenderCommands() clone the render buffers based on that RenderTargetCount" "2993": "handmade_render.h: Change OutputTarget to be a RenderTargets array in the tile_render_work struct" "3021": "handmade_render.cpp: Make RenderCommandsToBitmap() take a RenderTargets array" "3174": "handmade_debug.cpp: Make DEBUGBegin set the RenderTarget to 1" "3213": "Run the game and watch the debug information disappear into that other RenderTarget" "3247": "Q&A" "3291": "Next week?" "3371": "A bit unrelated to the project, but what do you think about the Rust language?" "3399": "So when do we think we will be ready for the new graphics assets? I'm excited" "3446": "Can you explain what this game is?" "3556": "Is writing to that other currently invisible render target much / any less computationally expensive than also sending it to the display?" "3650": "With multiple rendering targets, are there other effects you can do other than the alpha blending?" "3724": "Are you going to support shaders and, if so, will you try to support multiple render targets in the shaders?" "3842": "Are you excited to get an AArch64 toolchain up and running to get this thing to run on a Raspberry Pi 3?" "3877": "Are you still working full time? Why only stream one hour a night?" "3890": "How would you go about rendering huge tilemaps? Some batching techniques, or any tips?" "3965": "Would that be a good technique to use to create an overhead map?" "4036": "Soa and aos questions can be made with as minimal interference in timing the host operating" "4057": "Close down" --- name: "day317" title: "Alpha Blending Multiple Render Targets" markers: "66": "Run the game and show our current situation with render targets" "176": "handmade_entity.cpp: Make UpdateAndRenderEntities() create two different ClipRects for the alpha and normal floors" "368": "Run the game and see that the alpha stuff is gone" "413": "Consider ways of using multiple render targets" "568": "handmade_render.cpp: Add a RenderGroupEntryType_blend_render_target in RenderCommandsToBitmap() and introduce BlendRenderTarget()" "876": "handmade_render.cpp: Implement BlendRenderTarget() based on DrawRectangle()" "1484": "handmade_render.cpp: Introduce Pack4x8()" "1560": "handmade_render.cpp: Continue implementing BlendRenderTarget(), making it do gamma properly" "1647": "handmade_render_group.h: Add RenderGroupEntryType_blend_render_target to the render_group_entry_type enum and introduce render_entry_blend_render_target struct" "1754": "Run the game and see that it does nothing" "1773": "handmade_render.cpp: Make RenderCommandsToBitmap() clear everyone" "1915": "handmade_render_group.cpp: Introduce PushBlendRenderTarget() based on PushClipRect(), which will do the composite" "2379": "handmade_entity.cpp: Make UpdateAndRenderEntities() call PushBlendRenderTarget()" "2490": "Debugger: Run the game and crash in Win32CompleteAllWork()" "2511": "build.bat: Switch to -Od, run the game and crash in BlendRenderTarget()" "2553": "handmade_entity.cpp: Make UpdateAndRenderEntities() use AlphaFloorRenderTarget and pass it to BlendRenderTarget()" "2587": "build.bat: Switch to -O2, run the game and see how slowly the game now runs" "2656": "Debugger: Step through BlendRenderTarget() and investigate what's happening" "2691": "handmade_render.cpp: Make BlendRenderTarget() correctly set the DestColor and Result" "2732": "Run the game, see no alpha blending happening and investigate why" "2800": "handmade_render.cpp: Try making BlendRenderTarget() hardcode the Alpha to 0.5f" "2817": "Run the game and see that the Alpha is not taking effect" "2881": "build.bat: Switch to -Od, step in to BlendRenderTarget() and see what happens when we have a source pixel with something in it" "2963": "handmade_entity.cpp: Remove the transient_clip_rect from UpdateAndRenderEntities() and make it manually set the CurrentClipRect" "3012": "Run the game and see the prettiness before switching to -O2" "3045": "Run the game and marvel at the indescribable cacophony of epileptic color" "3096": "handmade_render.cpp: Make BlendRenderTarget() use SRGB255ToLinear1() and Linear1ToSRGB255()" "3231": "Run the game and again see the sparkly" "3251": "handmade_render.cpp: Prevent Pack4x8() from doing the multiply" "3271": "Run the game and see that we're getting closer to being correct" "3287": "handmade_render.cpp: Make BlendRenderTarget() use the correct Alpha" "3378": "handmade_entity.cpp: Make UpdateAndRenderEntities() set TestAlpha as a single r32 rather than an array of them" "3520": ""I love how it can't ever tell you any values in release mode"" "3526": "Debugger: Step into UpdateAndRenderEntities() and investigate how TestAlpha got to be set to 1.0f" "3702": "handmade_entity.cpp: Make UpdateAndRenderEntities() pass FadeTopEndZ and FadeTopStartZ to TestAlpha() in the opposite order" "3718": "build.bat: Switch to -O2, run the game and see the alpha blending working beautifully" "3792": "handmade_render.cpp: Make RenderCommandsToBitmap() clear both the MaxRenderTargetIndex and the previous TargetIndex" "3821": "Run the game and see that now it looks like we're good" "3840": "Note that the clear is clearing at 1.0f alpha, and that it has to actually clear, not blend" "3886": "Q&A" "3957": "Giger / Lovecraft-themed Handmade Hero DLC confirmed?" "3968": "Are you writing to the second buffer all the time? If so, is it possible to only use when you need it (like during the transitions)?" "3997": "handmade_entity.cpp: Make UpdateAndRenderEntities() only do the multiple buffers stuff if the alpha is enabled" "4165": "How does a limbless child "limp along", exactly?" "4174": "How many floors can this code support? I envision a tall tower or stairwell, peering down 20 or so floors and seeing NPCs acting as normal. Was that your intent?" "4256": "How do you use trace files to debug? Someone trying my game prototype had a crash and sent me a (95MB) dump file, since you once said it's helpful. I don't doubt that, but what do you do with the damn thing?" "4419": "Wrap it up" --- name: "day318" title: "Optimizing Render Target Blends and Clears" markers: "40": "Run the game and set the stage for the day" "115": "handmade_render.cpp: Accelerate BlendRenderTarget() with SIMD instructions" "666": "Run the game and see that it's fine" "700": "handmade_render.cpp: Introduce ClearRectangle() based on BlendRenderTarget(), and make RenderCommandsToBitmap() call it" "1101": "Run the game and see how that does" "1167": "build.bat and win32_handmade.cpp: Switch to -Od and disable threading in order that we can step in to the code" "1273": "Debugger: Step in to ClearRectangle() and inspect the Color values" "1330": "handmade_render.cpp: Make ClearRectangle() correctly compute those Color values" "1426": "Debugger: Step in to ClearRectangle() and inspect the Sr values" "1505": "Blackboard: Operating on reciprocal square-root of X in such a way that we end up with the square-root" "1598": "handmade_opengl.cpp: OpenGLRenderCommands() glClearColor()" "1671": "Internet: Consult the EXT_framebuffer_sRGB documentation" "1695": "handmade_render.cpp: Make ClearRectangle() operate in linear space, not gamma space" "1748": "Run the game and see that we're a little better" "1795": "handmade_render.cpp: Revert ClearRectangle() to operate in gamma space, and investigate why the clear color is not correct" "1919": "handmade_render.cpp: Make BlendRenderTarget() use the SourceColor in the blend" "2109": "Run the game and see that the alpha blending now works" "2141": "handmade_entity.cpp: Make UpdateAndRenderEntities() draw the traversables at their full size" "2202": "handmade_render.cpp: Investigate why the hero's body isn't being skewed correctly in the software renderer" "2263": "Run the game and demo the incorrect bending" "2324": "handmade_render.cpp: Trim out some superfluous stuff from DrawRectangleQuickly()" "2521": "Run the game and demo our bugs" "2578": "Debugger: Look through ClearRectangle() and consider what could be going wrong" "2830": "handmade_render.cpp: Make ClearRectangle() set the Color values in the 65534 space" "2843": "Run the game, see how close we are and wonder why we suddenly see pink upon switching back to the software renderer" "2897": "handmade_opengl.cpp: Prevent OpenGLDisplayBitmap() from doing the blending" "2943": "Run the game and see that we're good to go" "3037": "handmade_render.cpp: Investigate why DrawRectangleQuickly() is not bending the hero correctly" "3432": "handmade_render.cpp: Remove extraneous initialisations from DrawRectangleQuickly()" "3532": "Blackboard: Doing the dot-product on unit vectors vs vectors with length" "3654": "Blackboard: Doing that in a non-orthogonal coordinate space" "3728": "Q&A" "3757": "Earlier when that pink color showed up, that was the color you used long long ago when you were setting up the OpenGL renderer" "3776": "Blackboard: Why we were seeing the pink" "3888": "Are the PynX and V calculations correct?" "3916": "As far as the vectors go for movement, can you just add U and V to get the new movement?" "3934": "Could normal maps be render targets here with appropriate enums / branching to blend / light, or do they still belong outside of the current render targets array?" "3974": "Do you think you could transform this game into a network game that multiple players can have different kinds of character assets, and, if yes, will you consider doing it?" "4001": "As in, it looked like there might be an X-Y swap in those two variables" "4040": "Makes sense, I'm comparing it to deferred rendering, which I'm no expert on" "4107": "You should do networking. You could charge for extra items or levels, etc. continuously, thus making you a "reliable" stream of money" "4117": "I mean you used an X variable when you meant a Y variable" "4226": "Blackboard: Inverting the matrix to solve for UV coordinates" "4410": "What is the blackboard software you are using?" "4421": "Nub3sock asked if you would consider local multiplayer" "4469": "Speaking of normal maps, could we have used those to help sort the sprites? I know they don't give you 3D data, but is there anything in there that we could leverage?" "4605": "Wrap it up" --- name: "day319" title: "Inverse and Transpose Matrices" markers: "17": "Recap and set the stage for the day" "89": "Blackboard: Skew UV Mapping" "228": "Blackboard: A conceptual explanation of transforming a texture map" "435": "Blackboard: Our matrix equation" "488": "Blackboard: The components of this equation" "567": "Blackboard: Adding and taking the origin out of equation" "636": "Blackboard: Transforming the U and V" "731": "Blackboard: Multiplying these matrices out" "851": "Blackboard: Backward transform, using dot products" "978": "Blackboard: Why use dot products to compute the transformed U and V?" "1122": "Blackboard: Getting from wanting to invert the matrix, to taking the dot product shortcut" "1187": "Blackboard: Inverting an orthonormal matrix" "1328": "Blackboard: What it means to invert" "1514": "Blackboard: The algebraic explanation for why any orthonormal matrix multiplied by its transpose (i.e. inverted) gives you the identity matrix" "1898": "Blackboard: Putting it in meta algebraic terms" "2002": "Blackboard: The geometric explanation for this" "2248": "Blackboard: Columnar vs Row-based Matrices" "2389": "Blackboard: How non-uniform (yet still orthogonal) scaling affects our matrix" "2471": ""I hope everyone was interested in the matrix thing today"" "2536": "Blackboard: Transposing the matrix for non-uniformly scaled vectors, and compensating for that scaling" "2694": "Blackboard: The beginnings of a formal algebraic explanation of this compensation" "2813": "Blackboard: Matrix multiplication is order dependent" "3001": "Blackboard: How this order dependence of the transform is captured by matrix maths" "3161": "Blackboard: A formal algebraic explanation for the scale and rotation compensation" "3359": "Blackboard: A glimpse into the future of actually inverting the matrix" "3434": "Q&A" "3482": "You've got some salty dogs in your chat tonight, Casey" "3512": "A few words on how cool linear algebra can get" "3586": "Did you know you were going to have to implement the sort of reverse mapping when you took that shortcut before? Was it a deliberate choice or just a cut corner that had to be uncut?" "3635": "Is your elbow okay? Are you okay?" "3744": "Other than transpose, do you need much more from linear?" "3903": "We had one example from my linear algebra class in the book, that used computers. Was surprised to see it here" "3981": "sssmcgrath said this once, but math papers should be published with C source code" "3998": "Have you seen Gilbert Strang's lectures on linear algebra?" "4060": "You suggest students not knowing how to solve linear algebra problems by hand?" "4182": "Would you consider using C++ templates for matrices, say in 3D programming?" "4257": "We are done" --- name: "day320" title: "Inverting a 2x2 Matrix by Hand" markers: "14": "Recap and set the stage for the day" "114": "Blackboard: Inverting a 2x2 Matrix" "208": "Blackboard: Producing the four scalar equations for the inverse of the A matrix" "520": "Blackboard: Solve for y by back-substituting" "728": "Blackboard: Simplify the term for y" "854": "Blackboard: Solve for x, noting how it is a similar term to that for y" "974": "Blackboard: Consider taking a shortcut to the solutions for z and w" "1056": "Blackboard: Solve for w" "1253": "Blackboard: Solve for z" "1328": "Blackboard: Call for an algebraic blackboard program and note how the terms have the same divisor, before double-checking the workings" "1456": "Blackboard: Try multiplying our new matrix by the original one in order to see if we end up with the identity matrix" "1593": "Blackboard: Double-check the workings for z" "1647": "Blackboard: Compact our inverse of the A matrix" "1697": "Blackboard: Mnemonically remembering the determinant of a 2D matrix" "1782": "Blackboard: Matrix transpose vs matrix inverse" "2001": "Blackboard: Our actual equation for doing the UV mapping" "2175": "Run the game and demo the current situation" "2201": "handmade_render.cpp: Look through how DrawRectangleQuickly() is currently working" "2340": "Blackboard: Note that we can compute UxVy - UyVx ahead of time, keeping the code otherwise identical" "2408": "handmade_render.cpp: Make DrawRectangleQuickly() compute the variables according to our equation" "2604": "Run the game, see that it's not right and investigate why" "2898": "build.bat: Switch to -Od, break into DrawRectangleQuickly() and inspect the values" "3120": "handmade_render.cpp: Make DrawRectangleQuickly() correctly compute the nXAxis and nYAxis" "3144": "Run the game and see that it now works perfectly" "3203": "A few words on the importance of understanding maths concepts in diagnosing and solving programming problems" "3366": "Q&A" "3403": "Semi-off-topic: Any chance you could describe a little more what you'd want of an algebraic blackboard program?" "3438": "Blackboard: Why Casey Doesn't Like Mathematica" "3757": "Whoa..." "3768": "Will there be more things like this that require math like this in further parts of the game? Although it was pretty basic, my math is a bit rusty" "3995": "Do you consider math to be more of a tool to solve problems or more of a learned art to be mastered?" "4118": "Googling what I believe you wanted turned up: http://reduce-algebra.com/ Automatic and user-controlled simplification of expressions and calculations with symbolic matrices" "4157": "I just wanted to note how your intuition of the transform seemed really important at finding the bug, way more important than typing the correct formula. Uh no wait" "4486": "I actually just learned about determinants in Linear Algebra today. Do you think we will see them later on? Are determinants used often?" "4548": "Do you get annoyed by some symbols meaning different things in different subcategories of math?" "4626": "What about 3D with an isometric view?" "4690": "What do you think of Khan Academy as a math learning resource?" "4779": "Yeah, I mean a 2D game that is drawn in 3D" "4847": "Recognizing "the kinds of things you are working with, and the kind of problem you are working on" is a fundamental skill. I'm not all that sure how to teach that directly, though, beyond doing something like what you are doing here, and / or repeated experience with solving problems" "5097": "Imagining a series that is more focused on mathematical problem identification and solving" "5170": "Close down" --- name: "day321" title: "Multiple OpenGL Render Targets" markers: "32": "Recap and set the stage for the day" "147": "Determine to enable the OpenGL renderer to work with multiple render targets like the software renderer" "274": "Our two tasks: 1) Talking about render targets to OpenGL; 2) Using those render targets as textures" "403": "Consult docs.GL in order to learn how to get multiple render targets" "603": "handmade_opengl.cpp: Make OpenGLRenderCommands() prepare the render targets, based on the software renderer's RenderCommandsToBitmap()" "939": "handmade_opengl.cpp: Make OpenGLRenderCommands() bind the correct framebuffer" "1231": "Compile and note that glGenFramebuffers() and glBindFramebuffer() are not available" "1284": "handmade_opengl.cpp: Add GL_ARB_framebuffer_object to the opengl_info struct" "1477": "win32_handmade.cpp: typedef the OpenGL calls that we need" "1648": "win32_handmade.cpp: Load these OpenGL calls into memory" "1709": "handmade_opengl.cpp: #define GL_FRAMEBUFFER" "1825": "Run the game and see that we run, but super slowly when the layered alpha blend is due to happen" "1874": "handmade_opengl.cpp: Make OpenGLRenderCommands() check that we have glBindFramebuffer()" "2070": "win32_handmade.cpp: Make Win32InitOpenGL() check whether it ought to load the OpenGL extensions" "2123": "handmade_opengl.cpp: Make OpenGLRenderCommands() call glFramebufferTexture2D() to attach a texture image to our framebuffer object" "2344": "handmade_opengl.cpp: Make OpenGLRenderCommands() generate our textures" "2616": "handmade_opengl.cpp: #define GL_COLOR_ATTACHMENT0" "2660": "Run the game and see what we're doing" "2696": "handmade_opengl.cpp: Make OpenGLRenderCommands() blend the render targets in the RenderGroupEntryType_render_entry_blend_render_target case" "2896": "handmade_opengl.cpp: Make glBlendFunc() use non-premultiplied alpha" "2952": "Run the game, see that we are blending with white and investigate why" "3165": "handmade_opengl.cpp: Make OpenGLRenderCommands() call glCheckFramebufferStatus()" "3329": "Debugger: Run the game to see if we are getting a valid framebuffer, and investigate what's happening" "3476": "handmade_opengl.cpp: Make OpenGLRenderCommands() store the TextureHandle" "3507": "Run the game and see that the alpha blending now works beautifully" "3526": "Q&A" "3742": "What are the biggest challenges you have faced with the game thus far?" "3852": "Does AZDO work across NVIDIA, AMD and Intel" "3942": "Compare the Handmade Hero engine complexity vs 1935" "3968": "For catching up to the previous episodes, do you recommend going through all the videos, or to try to understand the current codebase?" "4142": "That's the end of it" --- name: "day322" title: "Handling Multiple Display Aspect Ratios" markers: "10": "Recap and set the stage for the day" "35": "Consult the issues" "131": "Determine to fix the "Wrong glViewport parameters" issue" "232": "Run the game and demo the resizing situation" "301": "handmade_opengl.cpp: Make OpenGLDisplayBitmap() and OpenGLRenderCommands() pass the WindowWidth and WindowHeight to glViewport()" "387": "Run the game and see how it now looks" "540": "Blackboard: Aspect Ratio Resize" "663": "Blackboard: No aspect ratio support" "777": "Blackboard: Aspect-awareness" "1008": "Blackboard: Black bar" "1092": "Blackboard: Our two cases" "1178": "handmade_render.cpp: Introduce AspectRatioFit()" "1423": "Blackboard: Calculating aspect ratios" "1636": "handmade_render.cpp: Make AspectRatioFit() calculate the optimal dimensions based on that fundamental aspect ratio" "2062": "handmade_opengl.cpp: Make OpenGLRenderCommands() take the DrawRegion and pass it to glViewport()" "2141": "handmade_math.h: Introduce GetWidth() and GetHeight()" "2360": "handmade_opengl.cpp: Introduce OpenGLBindFramebuffer()" "2454": "Run the game and see that it looks the same" "2466": "win32_handmade.cpp: Make Win32DisplayBufferInWindow() call AspectRatioFit() to set the DrawRegion" "2528": "Run the game and try out the new resizing" "2604": "handmade_opengl.cpp: Make OpenGLDisplayBitmap() take the DrawRegion and pass it to OpenGLBindFramebuffer()" "2704": "Run the game and see that it just works" "2733": "handmade_opengl.cpp: Make OpenGLDisplayBitmap() clear to the ClearColor and prevent OpenGLRenderCommands() from drawing the outlines" "2873": "Run the game, see how it all is and close that issue" "2973": "Determine to fix the "Incorrect Unproject" issue" "3113": "win32_handmade.cpp: DrawRegion WinMain()" "3197": "win32_handmade.cpp: Remove the win32_rendering_type enum in favour of a single GlobalSoftwareRendering" "3261": "Run the game and ensure that toggling the software renderer still works" "3283": "win32_handmade.cpp: Make WinMain() compute DrawRegion early on and make all the appropriate functions take it" "3412": "win32_handmade.cpp: Make WinMain() map the mouse position to the DrawRegion" "3536": "Run the game and see if the mouse cursor is now working okay" "3601": "win32_handmade.cpp: Make WinMain() base the mouse position on the RenderCommands dimensions" "3631": "Run the game and see that the mouse cursor is still failing" "3719": "Debugger: Resize the window, step in to WinMain() and inspect the MouseU and MouseV" "3801": "win32_handmade.cpp: Make WinMain() correctly compute the MouseY" "3836": "Run the game and see that the mouse coordinates are now being passed correctly" "3858": "Q&A" "3922": "Close that issue" "3999": "(Before today) I have a 1600x900 monitor and when I change the code to render at that resolution, both the UI picking and the collision detection for the player get all sorts of messed up, but I haven't tested that since you removed the free moving stuff" "4017": "Can you make it so that holding shift while resizing the window makes it just scale at the intended aspect ratio?" "4072": "Casey, you forgot to change "UseHeight" to "UseWidth" on the second case of the black bar size's definition" "4089": "Two parter, if that's okay: A) I'd like to start working on a homemade 3D game engine of my own. How much of what you have done here transfers over? B) When do you define how long a second is in the game? How does the lighting work in regards to time?" "4148": "How would you suggest a younger developer to get into OpenGL and all of its useful extensions?" "4268": "Did you ever go through the NSight plugin on stream?" "4289": "Off-topic: Which keyboard layout do you use? Have you tried the various layouts? I've read that QWERTY can be a bit less efficient for programming, what do you think?" "4317": "I have some experience in OpenGL but not with the extensions" "4627": "win32_handmade.cpp: Make Win32MainWindowCallback() handle fixed aspect ratio window resizing based on Raymond Chen's advice" "5036": "Blackboard: Calculating that new window height" "5158": "Run the game and try resizing the window" "5191": "win32_handmade.cpp: Make Win32MainWindowCallback() only do aspect ratio constrained resize if the shift key is held down" "5250": "Run the game and try resizing with the shift key held down" "5397": "Debugger: Break into Win32MainWindowCallback() to determine what the cx and cy are, and investigate what is happening with the flicker" "5759": "Debugger: Run the game and observe our WM_WINDOWPOSCHANGING output" "5855": "win32_handmade.cpp: Make Win32MainWindowCallback() set the NewPos based on which coordinate is closer" "5933": "Run the game and see if that helps" "6010": "win32_handmade.cpp: Make Win32MainWindowCallback() output the aspect ratio" "6057": "Run the game and observe that aspect ratio" "6106": "win32_handmade.cpp: Make Win32MainWindowCallback() adjust the aspect ratio to ignore the window decorations" "6196": "Blackboard: Computing the aspect ratio for the ClientRect" "6419": "Run the game and see what that does" "6536": "Blackboard: Double-check the maths" "6556": "win32_handmade.cpp: Make Win32MainWindowCallback() compute the NewCx and NewCy differently" "6641": "win32_handmade.cpp: Make Win32MainWindowCallback() set GetWindowRect, run the game and see that it works" "6723": "Yes, it helps" "6734": "For AdjustWindowRect you should pass WS_OVERLAPPEDWINDOW which is different from WS_OVERLAPPED, although perhaps you meant that?" "6763": "Wrap it up" --- name: "day323" title: "Fixing Miscellaneous Bugs" markers: "69": "Run the game and note a bug when walking up the stairs after resizing the window" "352": "Consult docs.GL to see whether or not the glScissor operates relative to the viewport" "423": "handmade_opengl.cpp: Make OpenGLRenderCommands() do glScissor() in the space of the DrawRegion" "743": "handmade_math.h: Introduce a version of Offset() which takes a rectangle2i" "791": "Run the game and see if that is now correct" "808": "handmade_opengl.cpp: Enable OpenGLRenderCommands() to reset the glScissor() whenever we clear" "1067": "Run the game, see how that now looks and investigate why the render target is being offset" "1581": "handmade_opengl.cpp: Make OpenGLRenderCommands() call OpenGLBindFramebuffer()" "1639": "Run the game and see that it works" "1697": "handmade_opengl.cpp: Make OpenGLRenderCommands() instead set the CurrentRenderTargetIndex to a bogus value up front, so we know we're going through the same path" "1744": "Run the game and see that this uses the correct viewport" "1788": "Consult the issues" "1806": "handmade_render.cpp: Make BlendRenderTarget() set the SourceRowAdvance to the SourceTarget->Pitch" "1823": "Run the game, see no change but that it will indeed now be correct, and close the "Wrong pitch" issue" "1885": "Determine to fix the "sRGB typo fix not saved?" issue, regarding the GL_VERSION comment" "2112": "handmade_opengl.cpp: Make OpenGLGetInfo() call glGetIntegerv() to get the GL_VERSION" "2338": "Run the game, hypothesise that we've fixed the issue, and close it" "2398": "Determine to fix the "Check GL init fallback" issue" "2438": "win32_handmade.cpp: Make Win32InitOpenGL() always call Win32SetPixelFormat()" "2496": "Run the game, believe the issue to be fixed and close it" "2548": "Consider the "Unnecessary DescribePixelFormat" issue" "2713": "Close that issue and determine to fix the "UseRenderTargets Bug" issue" "2794": "handmade_opengl.cpp: Make OpenGLGetInfo() assume we don't have a framebuffer object" "2832": "Run the game and crash" "2853": "handmade_opengl.cpp: Make OpenGLRenderCommands() handle the situation in which we don't have a framebuffer object" "3262": "Run the game and see that that's okay in both cases" "3337": "Close that issue and determine to fix the "PackEntityIntoChunk linked list bug" issue" "3416": "handmade_world.cpp: Fix the linked list in PackEntityIntoChunk()" "3586": "Run the game, assume that it's fixed and close the issue" "3650": "Q&A" "3760": "Not sure what the minimum OpenGL version the game supports, but according to OpenGL.org, the GL_MAJOR_VERSION and GL_MINOR_VERSION are only available in OpenGL 3.0 and above. On lower versions you have to parse the GL_VERSION string" "3793": "handmade_opengl.cpp: Make OpenGLGetInfo() parse the GL_VERSION string" "3951": "handmade_opengl.cpp: Introduce OpenGLParseNumber()" "4120": "Debugger: Run the game and check out our parsed OpenGL version number" "4175": "So I am designing a 3D game engine and want to first write a software renderer for it to learn more about renderers. Do you think I should go straight for OpenGL or software renderer and then OpenGL?" "4228": "sscanf(str, "%d.%d", major, minor)" "4341": "Wrap it up" --- name: "day324" title: "Moving Away from Multiple OpenGL Contexts" markers: "13": "Recap and consult the issues list" "274": "Run the game, demo our current situation and determine to fix the "PackEntityIntoChunk linked list bug" issue" "331": "handmade_world.cpp: Tweak the linked list in PackEntityIntoChunk()" "457": "Run the game, close this issue and determine to fix the "Wrong MetersToPixels" one" "664": "Blackboard: MetersToPixels" "790": "handmade_world.mode.cpp: Make UpdateAndRenderWorld() compute MetersToPixels oppositely and tweak the camera values" "1035": "handmade_opengl.cpp: Toggle on the debug outlines, run the game and tweak those camera values" "1163": "Consider that issue fixed and determine to fix the "Asynchronous Texture Downloads" one" "1325": "handmade_opengl.cpp: Describe how the AllocateTexture works" "1409": "handmade_opengl.cpp: Remove the glFlush call, run the game and see that it kind of works on an AMD GPU" "1557": "win32_handmade.cpp: Consider the problem with the OpenGL multithreaded stuff" "1650": "Blackboard: How the texture currently gets moved to the GPU" "1793": "Blackboard: Using pinned memory to streamline the transfer into texture memory" "2032": "handmade_opengl.cpp: Introduce OpenGLManageTextures() in order to defer the AllocateTexture and DeallocateTexture" "2140": "Blackboard: Deferring the texture download" "2176": "handmade_render.h: Introduce texture_op, texture_op_allocate and texture_op_deallocate structs" "2326": ""I find that concurrency is one thing, but flow control is really the harder thing"" "2410": "handmade_asset.cpp: Consider how better to set the TextureHandle in LoadAssetWorkDirectly()" "2535": "handmade_render.h: Add ResultHandle to texture_op_allocate and Handle to texture_op_deallocate to enable us to ensure that the asset stays around long enough for the allocate call to complete" "2629": "handmade_opengl.cpp: Make OpenGLManageTextures() loop through the textures and allocate / deallocate them as required" "2795": "handmade_opengl.cpp: Introduce OpenGLAllocateTexture()" "2955": "A few words on producers and consumers, and ticket taking" "3082": "handmade_asset.cpp: Consider doing some general cleanup and removing the asset lock" "3183": "handmade_asset.cpp: Introduce AddOp() with a view to implementing it tomorrow" "3327": "Run the game and see that we're in no man's land" "3342": "Q&A" "3411": "It's a bit late now, but I was thinking debug sliders for FOV and camera distance could be useful" "3465": "On the bug list, what is that Clang compatibility issue? I'm working on a Macbook using LLVM, so may be able to work it out" "3649": "I still see flickering on the stairs. Is the sort solution finalized?" "3714": "Is the issue list private?" "3756": "Would you normally skip straight to OpenGL or hardware acceleration, or would you start with software rendering?" "3798": "In terms of asynchronous textures loading, the OpenGL website talks about pixel transfer operations and references glPixelStore. Did you look into these?" "3982": "Is that persistent texture mapping?" "4164": "I saw the tweet by Sean Barrett about the Vulkan API vs the OpenGL API. What are the main flaws in the OpenGL API?" "4312": "Tweet by Sean Barrett" "4407": "Wrap it up" --- name: "day325" title: "Ticket Mutexes" markers: "23": "Recap and set the stage for the day" "91": "Blackboard: Ticket Taking" "251": "Blackboard: Singly-linked list" "405": "Blackboard: A way to atomically add to a linked list" "464": "Blackboard: Removing from a list" "576": "Blackboard: Multithreaded addition to linked lists" "706": "Blackboard: Multithreaded removal from linked lists" "809": "Blackboard: Ticket Taking as a way to implement a fast, simple mutex for little chunks of code" "877": "Blackboard: Atomic compare exchange" "1061": "Blackboard: Atomic increment" "1142": "Blackboard: Ticket Taking and Mutex (mutual exclusion)" "1377": "Blackboard: volatile int mutex" "1659": "Blackboard: Annoyingly, this implementation provides no guarantee that any thread will ever get a turn" "1804": "Blackboard: Ticket Taking as a way to ensure that threads get retired in order" "2112": "handmade_shared.h: Introduce struct ticket_mutex, BeginTicketMutex() and EndTicketMutex()" "2377": "handmade_asset.cpp: Implement AddOp()" "2569": "handmade_platform.h: Introduce and add a platform_texture_op_queue to the game_memory struct for AddOp() to use" "2748": "handmade_asset.cpp: Consider not setting Work->Asset->State in LoadAssetWorkDirectly()" "2841": "handmade_asset.cpp: Continue implementing AddOp()" "2996": "handmade_platform.h: Move the ticket mutex in from handmade_shared.h" "3083": "Consider building separate lists for each threads inside task_with_memory" "3145": "handmade_asset.cpp: Add platform_texture_op_queue to load_asset_work and pass it to the necessary functions" "3354": "Run the game and hit the assertion in AddOp()" "3372": "win32_handmade.cpp: Make WinMain() populate the TextureOps free list" "3533": "handmade_opengl.cpp: Make OpenGLManageTextures() return a texture_op" "3577": "win32_handmade.cpp: Make WinMain() call OpenGLManageTextures() inside a mutex" "3675": ""You ALMOST only live once"" "3889": "Run the game and see that it almost worked" "3906": "Q&A" "3950": "handmade_asset.cpp: Note that we haven't dealt with Work->Asset->State" "4027": "Handmade Vulkan renderer when?" "4041": "Do you need a safety write barrier before the current ticket increment (inside mutex_unlock)?" "4147": "Do you use an sRGB framebuffer and / or premultiplied alpha?" "4220": "win32_handmade.cpp: Remove Win32GetThreadStartupForGL()" "4284": "Run the game and note that our texture loading bug is 100% reproducible" "4321": "Can you explain about the secondary framebuffer not being premultiplied? What's the secondary framebuffer for?" "4385": "And it might be pointless to do but, since you are using C++, have you used any ASM calls inside your code?" "4463": "Is there a reason you're not using scoped mutex guards that handle unlocking whenever the guard goes out of scope?" "4478": "win32_handmade.cpp: Demo the difference between our mutex and a scoped mutax guard" "4668": "Wrap it up with a few words on what is likely going wrong with the texture loading" --- name: "day326" title: "Vararg Functions" markers: "16": "Recap and set the stage for the day" "54": "win32_handmade.cpp: Consult the code and note what the bug is" "107": "Run the game and demo the bug" "138": "win32_handmade.cpp: Make WinMain() reset the Last element in the ticket taking system" "199": "handmade_opengl.cpp: Make OpenGLManageTextures() return nothing" "247": "Run the game, see that the texture downloads are all synchronous and consult the profiler" "358": "build.bat: Switch to -O2, run the game and again consult the profiler" "506": "Consider doing some work on the pixel buffer objects to reduce the transfer time" "675": ""And the bug is gone"" "783": "todo.txt: Update the TODO list, consult the issue and determine to fix the "CLANG compatibility" issue" "967": "win32_handmade.cpp: Remove HandleDebugCycleCounters(), Win32DebugDrawVertical() and other instances of _snprintf_s()" "1036": "handmade_debug.cpp: See what features of _snprintf_s() we are currently using with a view to implementing our own printf()" "1195": "handmade_debug.cpp: Try to determine what DebugParseName() should do if PipeCount == 1" "1324": "handmade_shared.h: Introduce S32FromZ()" "1394": "A few words on printing floating point numbers" "1459": "handmade_shared.h: Provisionally introduce FormatString() and FormatStringList()" "1569": "Debugger: Consult the definitions of _crt_va_start(), _crt_va_arg() and _crt_va_end()" "1664": "Blackboard: Variable Arg Lists" "1962": "Blackboard: va_start and va_end" "2065": "handmade_shared.h: Consult the code for variable arguments and _INTSIZEOF" "2239": "handmade_shared.h: Implement FormatString() and FormatStringList()" "2566": "handmade_shared.h: Introduce OutChar()" "2739": "handmade_debug.cpp: Replace all instances of _snprintf_s() with FormatString()" "3086": "handmade_shared.h: Make FormatStringList() return the length of the list" "3159": "build.bat: Switch to -Od, run the game, crash in OutChar() and investigate why" "3395": "handmade_shared.h: Correct the typo in FormatStringList()" "3403": "Run the game and see that we're printing things out, just without any formatting" "3444": "Q&A" "3513": "Is this it?" "3563": "Short recap of what we've done today? I have a hard time tracking everything, especially at 6am" "3584": ""Blame" in Github lets you see file change history" "3603": "What does -1 in Dest.At[-1] do?" "3674": "I want to start getting into this series - is there a way to easily compile / run this code on Mac OSX?" "3838": "Wrap it up" "3899": "How long is the break?" --- name: "day327" title: "Parsing Printf Format Strings" markers: "23": "Announcement: Early registration for HandmadeCon 2016 ends soon" "78": "Announcement: Casey will be speaking at PWLConf 2016" "306": "Recap and set the stage for the day" "376": "A few words on the difficulty of printing floating point numbers" "547": "handmade_shared.h: Enable FormatStringList() to process the %s specifier" "686": "Debugger: Go to definition of va_arg()" "847": "Run the game, crash in FormatStringList() and investigate why" "912": "handmade_shared.h: Make FormatStringList() skip other % specifiers than %s" "1008": "Run the game and see how that works" "1126": "handmade_shared.h: Enable FormatStringList() to handle the flags in the printf spec" "1505": "handmade_shared.h: Enable FormatStringList() to handle the width field and introduce S32FromZInternal()" "1876": "handmade_shared.h: Enable FormatStringList() to handle the precision" "1999": "handmade_shared.h: Begin to enable FormatStringList() to handle each of the % specifiers" "2082": ""No sense not dotting your t's, crossing your i's and so on..."" "2284": "handmade_shared.h: Enable FormatStringList() to handle the length" "2522": "handmade_shared.h: Introduce ReadVarArgInteger() and ReadVarArgFloat(), with a few words on the ugliness of this in C" "2751": "handmade_shared.h: Continue enabling FormatStringList() to handle each of the % specifiers" "2886": "handmade_shared.h: Separate ReadVarArgInteger() out into ReadVarArgUnsignedInteger() and ReadVarArgSignedInteger()" "2948": "handmade_shared.h: Continue working on the % specifiers in FormatStringList()" "3151": "Debugger: Step through FormatStringList() and inspect what's happening" "3195": "handmade_shared.h: Make FormatStringList() consume the ." "3219": "Run the game, see the printing in action, hit our assertion in FormatString() and investigate why" "3490": "handmade_shared.h: Make FormatString() increment At at the end" "3557": "Run the game and see that we're now all good" "3642": "Q&A" "3769": "Will you be doing a sprintf?" "3829": "Is the GitHub repo accessible to preorders?" "3893": "I'm following your series from beginning and I'm writing my own game (obviously from scratch too!). Is it okay to use in my win32 layer similar code (with same thought by mostly written by myself)?" "3956": "What are you using for DRM?" "4003": "Neres909: Casey is currently using a Razer BlackWidow Tournament Edition Stealth. See also: !switches" "4029": "Throw in a hardware keyfob for good measure" "4067": "Shut this down" --- name: "day328" title: "Integer and String Support in Printf" markers: "26": "Recap and set the stage for the day" "85": "handmade_shared.h: Consider what we must implement in FormatStringList()" "291": "handmade_shared.h: Begin to enable FormatStringList() to handle decimal, hexadecimal and octal integers [see Resources: C++ Reference]" "674": "handmade_shared.h: Introduce U64ToASCII()" "818": "Blackboard: printf" "1007": "handmade_shared.h: Implement U64ToASCII()" "1137": "handmade_shared.h: Enable FormatStringList() to process the data returned by U64ToASCII()" "1228": "Run the game and see our integer printouts" "1281": "handmade_shared.h: Enable FormatStringList() to handle write back for the %n format and obey flags" "1631": "handmade_shared.h: Enable FormatStringList() to handle AnnotateIfNotZero and introduce OutChars()" "1817": "handmade_shared.h: Enable FormatStringList() to handle Prefixes" "2114": "Run the game and checkout the printout" "2147": "handmade_shared.h: Enable FormatStringList() to handle UseWidth and UsePrecision" "2314": "A few words on this approach of boiling down complexity to simplicity" "2346": "handmade_shared.h: Continue enabling FormatStringList() to handle UseWidth and UsePrecision" "2790": "handmade_shared.h: Enable FormatStringList() to handle LeftJustify and PadWithZeros" "2944": "Run the game and see the beautiful printout" "3038": "Homework: Enable FormatStringList() to handle floating point values" "3212": "handmade_shared.h: Make FormatStringList() only create temporary buffers where necessary, and enable it to obey precision for the %s format" "3522": "Run the game, see that the strings print backwards and hit the assertion in FormatStringList()" "3606": "handmade_shared.h: Make FormatStringList() correctly increment the At, run the game and note that the strings are backwards" "3637": "handmade_shared.h: Give FormatStringList() the ability to choose whether or not to reverse the characters" "3722": "Run the game and admire the beautiful printout" "3737": "handmade_debug.cpp: Play with the formatting in DrawTopClocksList(), running the game and seeing it all working fine" "3898": "Q&A" "3939": "I posted my question twice on pre-stream but both times it wasn't addressed. I experienced a bit of lag back then so I checked on archive what's up and it wasn't there. Am I doing something wrong?" "3991": "A few people in the twitch chat are asking about what level of math do you think is required to be an effective programmer" "4106": "Casey, I understand that you are replacing all the string header functions (strlen, etc.). Are you not worried about optimization for these new functions you plan to write?" "4154": "I'm just trying to learn how to code. I'm following Stroustrup's book and he insists on teaching using math. All the good beginner books tend to assume math knowledge" "4347": "And again. Just let me know if you see it" "4466": "Hey. In one year I'm graduating and it will be time to find a job. All I always wanted was to work in the game industry but I have no work experience or projects that I am proud of to show as my portfolio. I guess you were leading programmer in your projects and you were responsible for making decision who to hire" "4552": "How you see people like me in this decision? Should I take whichever offer as a programmer I could find which might not even be connected with games, or maybe try to make the best game I can do in one year, or save some money and do an internship without salary (I didn't see any studios with a paid one in my region)? What's your opinion?" "5266": "Thank you for the in-depth explanation! I have one more Q: Since you're going on a break, can you trash out OOP just a bit so we don't get confused in the time you're not there, and stick to beloved compression oriented programming" "5352": "Wrap it up" --- name: "day329" title: "Printing Out Floats Poorly" markers: "28": "Recap and set the stage for the day" "149": "Run the game and refamiliarise ourselves with the code" "231": "handmade_shared.h: Fix an ArrayCount() call in FormatStringList()" "337": "handmade_shared.h: Introduce F64ToASCII() and consider precision" "527": ""I am not a floating point guru"" "546": "Blackboard: Float Printing" "697": "Blackboard: The problematic concept of the decimal point" "868": "Blackboard: Breaking this fractional problem down" "925": "Internet: modf" "1041": "Blackboard: Summing the fractional parts together" "1260": "handmade_shared.h: Implement F64ToASCII()" "1716": "Compile and run, see that our precision looks messed up and investigate why" "1785": "handmade_shared.h: Make FormatStringList() set Precision if not set, and bake the string reversal code in to U64ToASCII()" "2223": "Debugger: Step in to U64ToASCII() to take a look at what that does" "2463": "handmade_shared.h: Endeavour to handle precision correctly" "2551": "Internet: Consult the printf spec" "2571": ""Chrome? Chrooooooome?"" "2765": "handmade_shared.h: Make FormatStringList() handle the Width in accordance with the printf spec" "2838": "Run the game and see that the printouts are untouched" "2857": "handmade_shared.h: Make FormatStringList() correctly compute the Precision" "2963": "Run the game, see the floating point values looking better and consider what the Width specifier actually means" "3300": "Q&A" "3386": "Does the float printout account for left or right alignment?" "3497": "Are we stuck on what something %3d means? I was away" "3557": "Sorry if it sounds rude, but why do you even care about the specs? Why don't you just print whatever you want it to be? I mean, it's your code?" "3588": "handmade_shared.h: Deduplicate the float cases" "3661": "As far as I know %3.3f means 3 numbers before the decimal and precise to three decimal numbers" "3695": "Use the http://cppreference.com it has better docs than cplusplus.com, and cppreference states it's a minimum width" "3741": "Guess I have been wrong all this time" "3762": "Can you say something quotable for test purposes?" "3771": ""I feel like it's hard to say something quotable on demand"" "3792": "Minimum width would make it more consistent across all types of printf" "3804": "So wait, is it a behavior problem or a bad spec problem?" "3844": "Do you think it's worth implementing a custom string class that uses a custom heap for allocation and disposition of memory instead of dealing directly with null-terminated C-strings (talking mostly for tools programming)?" "3879": "Thanks for the stream, have a good evening, going to work, are you gonna stream at this time from now on?" "3924": "Is text printing speed interfering with your profiling accuracy in a significant way?" "3956": "What advantages does this version of printf have over the standard library printf?" "4092": "Right now you are padding with zeros, "the spec", at least in one example, looks like it pads with spaces" "4113": "When is the next Handmade Con?" "4208": "What else is left other than printf that would need to be removed?" "4412": "Could you explain briefly why this simple approach of printing floats can lead to precision errors?" "4493": "Will everything be recorded at HandmadeCon? Considering what nearly happened last year, I'm a little worried" "4588": "Wrap it up" --- name: "day330" title: "Fixings Bugs from the Issue List" markers: "3": "Recap and set the stage for the day" "83": "Consult and update the issues" "272": "Blackboard: Constant Power Panning" "457": "handmade_audio.cpp: Double-check how the panning currently works" "724": "Close the "Switch to constant power panning instead of linear panning in audio mixer" issue" "760": "handmade_opengl.cpp: Make OpenGLInit() call glTexEnvi()" "864": "Run the game, see that it's fine and close that issue" "888": "Consider the "Improve spinlock efficiency in BeginTicketMutex()" issue" "1063": "Read about the PAUSE instruction in the Intel 64 and IA-32 Architectures Software Developer's Manual" "1417": "handmade_platform.h: Make BeginTicketMutex() call _mm_pause(), run the game and find that its execution hasn't changed" "1448": "Close that issue and consider the other ones" "1581": "handmade_shared.h: Make ReadVarArgUnsignedInteger() promote all smaller types to 32-bit ints" "1748": "Determine to fix the "Clang: Passing va_list as a pointer" issue" "1879": "handmade_shared.h: Change ReadVarArgUnsignedInteger(), ReadVarArgSignedInteger() and ReadVarArgFloat() into macros" "2102": "Run the game to verify that nothing broke here, and then close this issue" "2155": "handmade_render.h: Introduce GetStandardCameraParams() in order to unify the camera computations" "2417": "Run the game and tweak the camera settings" "2615": "Close that issue and endeavour to fix the "Failsafe: If DEBUGGameFrameEnd Pointer fails to load while HANDMADE_INTERNAL=1" issue" "2820": "win32_handmade.cpp: Make WinMain() call DEBUGSetEventRecording() right after Win32LoadGameCode()" "2872": "Run the game and see how it goes" "2924": "win32_handmade.cpp: Make Win32LoadGameCode() set DEBUGFrameEnd" "2943": "Close that issue and request help from clang users to address the final clang compatibility issue" "3043": "Q&A" "3070": "Casey, is there a bug with chunk creation? You added a free list but are not using it?" "3138": "When doing copy & pasta you left (f64) cast in wrong place for ternary operator - ((f64)va_arg(ArgList, f64)) : (va_arg(ArgList, f32))" "3154": "handmade_shared.h: Fix ReadVarArgFloat()" "3179": "When you found yourself unable to write code for something, what would you do to try to find something to do for said project?" "3512": "Looking to start a career in programming / computer science. I am currently 16 and in grade 12. Any tips on what I should do? "Also thanks chat for all the help"" "3585": "It has been a while since we've seen some of the CTime stats that are being collected. If you have time?" "3658": "Consult the CTime stats" "3736": "What is the current schedule for the stream? It seems that we have been dealing with bugs for a while - sorry I may have missed the explanation if you provided it a little while ago" "3752": "When we get the chunk in GetWorldChunk() it seems we always allocate new memory. We never reuse the old chunks after removing them? I assumed you would add the removed chunk to the free list on the world and then reuse these when creating a new chunk rather than allocate more memory using the push struct? But you are currently not using this free list?" "3871": "handmade_world.cpp: Enable GetWorldChunk() to recycle old chunks" "3991": "Run the game" "4015": "What makes a bad programmer in your opinion?" "4048": "About your build.bat file, why do you disable exceptions and warnings?" "4088": "A related thing mentioned in a creative writing course I did was to "postpone perfection"" "4184": "Wind it down" --- name: "day331" title: "Activating Entities by Brain" markers: "9": "Recap and set the stage for the day" "77": "handmade_shared.h: Fix the ReadVarArgFloat() logic" "223": "Run the game to make sure that we're still working properly, and close the issue" "320": "todo.txt: Consult the TODO list" "527": "Run the game and consider how the multi-segment snake guy gets streamed in" "726": "Determine to treat multi-segment entities as active if as few as one segment is within an active sim region" "826": "handmade_entity.h: Introduce EntityFlag_Active" "974": "handmade_brain.cpp: Introduce MarkBrainActives()" "1339": "handmade_brain.cpp: Implement MarkBrainActives()" "1592": "handmade_platform.h: Introduce OffsetOf()" "1656": "handmade_brain.h: Introduce GetEntityInSlot()" "1756": "Run the game and update the TODO list" "2653": "Blackboard: Multiple Sim Regions and Active Entities" "2887": "Blackboard: When sim regions coincide" "3065": "Blackboard: Merging sim regions" "3312": "Q&A" "3376": "What are the reasons for separate regions again?" "3461": "Is Bob the guy in the tree?" "3466": "(Related to JayPhi's Q) So I was playing Kingdom: New Lands recently, and it seemed like there were some really bad frame rates that coincided with battles involving hundreds of entities on the opposite side of the world... (like, opposite to where the camera was)" "3578": "Have you considered only merging with the hero's region, and deactivating ones past that, or having the regions aligned to a grid / rooms, so they don't overlap?" "3682": "Blackboard: Active Region + Apron" "3783": "Could you have smaller regions and load nine active at a time so you always have every boundary region loaded all the time?" "3931": "Blackboard: On needing to load a part of adjacent regions" "3971": "Couldn't you just make sure regions that get pulled in by the apron don't have their own apron activated?" "4088": "Blackboard: Time-slicing and merging with only one overlapping region" "4182": "What is the actual problem again when two active regions overlap?" "4255": "You could always artificially keep the non-player agents away from each other" "4273": "What do you think about a boolean flag on each update-able thing, flip it when you update, and alternate each frame which value you check for?" "4330": "Why does it not suffice to use the total area of all overlapped regions (and just refuse to exceed a limit)?" "4420": "Close this down" --- name: "day332" title: "Disabling Sort for Debug Overlays" markers: "8": "Recap and set the stage for the day" "63": "Consider how to address the problem of sorting the debug overlay" "206": "Run the game, toggle on the sort groups and see the extent of the sorting in the debug overlay" "274": "build.bat: Temporarily switch to -O2, run the game and consult the profiler" "350": "handmade_debug.cpp: Consider how DrawFrameBars() could aggregate the rectangles" "434": "handmade_render_group.h: Introduce render_entry_rectangle_batch and render_entry_bitmap_batch structs" "628": "handmade_debug.cpp: Make DrawFrameBars() initialise a batch to pass to PushRect()" "795": "handmade_render_group.cpp: Begin to implement BeginRectangleBatch() and EndBatch()" "1001": "handmade_render_group.h: Introduce rectangle_batch struct" "1053": "handmade_render_group.cpp: Implement BeginRectangleBatch() as NewRectangleBatch() and leave out EndBatch() for now" "1323": "handmade_render_group.cpp: Consider how the SortKey aggregation works" "1523": "handmade_render_group.cpp: Make NewRectangleBatch() take SortZ and introduce a version of PushRect() that takes a rectangle_batch" "2010": "handmade_render_group.cpp: Consider how to aggregate the bounds" "2102": "handmade_render_group.cpp: Revert everything, in favour of turning off the sorting for the debug overlay" "2300": "handmade_render.cpp: Enable SortEntries() to skip sorting and simplify BuildSpriteGraph()" "2671": "handmade_render.cpp: Introduce UnsortedOutput()" "2842": "Run the game and consult the profiler" "2858": "handmade_render_group.cpp: Make PushSortBarrier() take a TurnOffSorting boolean and DEBUGEnd() set that value" "3055": "Run the game and find that the debug overlay is now unsorted" "3111": "handmade_debug_ui.cpp: Change the order in which TextOp() and BasicTextElement() draw" "3180": "Run the game and consult the profiler" "3258": "handmade_debug_ui.cpp: Enable the tooltips to be drawn last" "3386": "handmade_debug_ui.cpp: Introduce DrawTooltips() and rework AddTooltip()" "3712": "handmade_debug.cpp: Make DEBUGEnd() call DrawTooltips()" "3783": "Run the game and see the tooltips correctly hovering" "3826": "Q&A" "3931": "Is internal a #define static internal" "3939": "Could you talk a bit about the metaprogramming stuff you use at work? I'm kind of annoyed at the limitations of C/C++ and it looks like the JAI compiler won't be released anytime soon. Do you actually parse the code and construct an AST, or is it simpler than that?" "3957": "Also, are you a fan of templates or do you use void * instead" "3969": "Why was the grouping approach for speeding up the debug sorting the first one you tried? Would it have been better in some way?" "4111": "So would you recommend using a .bat file or bash script over a cmake file, for instance" "4181": "And finally, at your work are there any people that program in OOP, or are they shunned and thrown out?" "4264": "Related to yesterday's sim region issue, would it be feasible to merge overlapping regions, and then make a pass to slice it back up into non-overlapping regions?" "4290": "Can you imagine any scenarios where batched rendering might be useful in Handmade Hero?" "4326": "I've only recently started to think about metaprogramming. Not expecting you to go in-depth, but could you briefly list some of the features you've implemented?" "4344": "Will you be composing the music / SFX for Handmade Hero (if any) or do you have someone else doing that?" "4484": "That's about it" --- name: "day333" title: "Floor-relative Perspective Transforms" markers: "8": "Recap and set the stage for the day" "302": "Consult the issues list before jumping right into the Z stuff" "427": "handmade_render_group.cpp: Take a look at GetRenderEntityBasisP() and run the game to demo how the perspective transform is currently happening" "550": "handmade_render_group.cpp: Temporarily prevent GetRenderEntityBasisP() from applying the persepective transform to everything" "634": "Run the game and see how that looks" "658": "handmade_render_group.cpp: Prevent GetRenderEntityBasisP() only from transforming X" "728": "Run the game and see how things are now aligned" "774": "handmade_render_group.cpp: Temporarily enable GetRenderEntityBasisP() to preserve the UnscaledXY" "841": "Run the game and see how that looks" "917": "Consider how to transform the surrounding floors" "1154": "Blackboard: Multiple Z's" "1478": "handmade_render_group.cpp: Reset GetRenderEntityBasisP() and instead enable it to operate differently on multiple floors" "1748": "Run the game, see how that looks and determine to set the scaling" "1800": "Note a potential bug with the floor entities being considered upright" "1892": "handmade_entity.cpp: Enable UpdateAndRenderEntities() to set the scaling" "2042": "Run the game and see the scaling in action" "2123": "handmade_entity.cpp: Consider a separate problem with UpdateAndRenderEntities() possibly marking every entity as upright" "2258": ""Everyone can relax, and by "everyone", I mean "me""" "2291": "handmade_world_mode.cpp: Make AddStandardRoom() stagger the floor's terrain in Z, run the game and see what that looks like" "2425": "handmade_world_mode.cpp: Make AddStandardRoom() create only two floors, with the bottom floor containing a stairwell up" "2598": "handmade_platform.h: #define b32x" "2721": "Run the game, traverse the stairs and demo the pop transform when jumping down the stairwell" "2774": "Blackboard: A zone between floors in which we scale entities" "2877": "handmade_render_group.cpp: Enable GetRenderEntityBasisP() to interpolate between floors" "3121": "handmade_entity.cpp: Enable UpdateAndRenderEntities() to scale entities between floors" "3174": "Run the game and see what that does" "3233": "Consider what is currently happening and how to fix it" "3289": "handmade_render_group.cpp: Prevent GetRenderEntityBasisP() from doing the perspective transform, run the game and see how boring that looks" "3403": "Consider specifying a range in which the scaling doesn't occur" "3576": "Q&A" "3667": "Are there any particular reasons not to prefer continuous scaling in Z besides easing sorting?" "3697": "Blackboard: Avoiding perspective transform for the scenery" "3884": "I may have missed it, but what's the reasoning for typedef'ing a b32x as a b32 and not just use b32?" "4030": "Thought: Have the floor above transform with the Y-displacement respective to the current floor, until you jump over to it, at which point the view cuts to be relative to the now-current floor" "4077": "I just watched your Papers talk and I didn't get the Minkowski sum exactly. I don't get where you deduce the points to subtract from each other" "4134": "Did you explain it on stream before? If so I can go to the archives" "4179": "For the stairs have you considered stairs on a particular floor go down instead of up, then you wouldn't have to worry about alpha?" "4250": "So instead of the above floor perspective-transforming into place as you move up the stairs, it stays still and jump-cuts to the proper perspective once you hop to a tile in that floor" "4322": "Amusing ancdote from the Papers We Love conference" "4391": "Are you doing a whole layer transform at once, or per object?" "4404": "Yes, but currently stairs are owned by the floor below them. If they are owned by the floor above them then you wouldn't see the stairs two floors above, since they would be two floors above (thus not blocking your way and not needing any alpha)" "4443": "Now I'm curious if Casey speaks faster or slower than Buckminster Fuller did" "4469": "Go ahead and close it down" --- name: "day334" title: "Adding Boost Pads" markers: "74": "Run the game and demo an unfortunate artifact when transitioning between floors" "200": "Consider the current issues with the stairwells in general, and alternative means of transitioning between floors" "716": "Determine to implement boost pads" "819": "handmade_render_group.h: Remove the concept of a floor apron" "909": "handmade_entity.h: Add a traversable_reference AutoBoostTo to the entity struct" "1020": "handmade_world_mode.cpp: Make AddStandardRoom() take LeftHole and RightHole booleans and generate those holes on alternate floors" "1233": "Run the game and admire the hole" "1267": "handmade_world_mode.cpp: Determine to enable AddStandardRoom() to generate boost pads between floors" "1420": "Describe the need for an editable room, without the sim and the apron, and consider how to go about making that" "1714": "handmade_world_mode.cpp: Make PlayWorld() start the player off at the last screen created" "1833": "Run the game and see that we're starting off on top" "1932": "Blackboard: Linking floors with teleporters" "1981": "handmade_world_mode.cpp: Enable PlayWorld() to link holes to locations on the floor below" "2184": "handmade_world_mode.cpp: Enable AddStandardRoom() to generate teleportation points between those locations" "2312": "handmade_entity.cpp: Make UpdateAndRenderEntities() colour the boost pads" "2460": "Run the game, see no boost pads and investigate why" "2655": "handmade_world.cpp: Make PackEntityIntoChunk() and ConnectEntityPoints() operate on the AutoBoostTo" "2687": "Run the game and see that the boost pad is set" "2707": "handmade_world_mode.cpp: Make AddStandardRoom() position the boost pad at the top-left of the hole" "2763": "Q&A" "2836": "About my first question, will I be able to view it again, because I was really interested about your answer?" "2869": "Are you using entity component system architecture or different?" "2973": "Have you come up with a story for the game yet?" "2985": "I recall when you were writing the head / body behavior code you wanted to ensure the player always had control of the head. Is this "auto-hopping" going to interfere with that?" "3046": "Can the player fall in the hole versus jumping on purposes?" "3060": "In theory could these jump pads be on the same level and used like the jump pads in Portal 2?" "3121": "Will multi-part entities like the snake be able to go through holes?" "3215": "What are your thoughts on voxel rendering and / or ray tracing?" "3439": "Regarding head / body, the player controls the head onto the jump pad, but then the game needs to animate both the head and body down, right? I thought so far the head was always responsive to player input (not tied to an animation), and the body just followed. Sorry, I may not be explaining clearly" "3516": "Opinion on Vulkan, other than it being really hard?" "3611": "How are holes and teleport pads going to help us find The Variable?" "3666": "Any tips for someone interested in game engines considering getting into the games industry?" "3706": "Do you have a set streaming schedule?" "3716": "Go right into mentioning the streaming schedule" --- name: "day335" title: "Moving Entities on Boost Squares" markers: "40": "Demo the difference between calling a function via a pointer and as a regular function call" "307": "A cursory explanation of what the processor is doing" "682": "Demo what happens when you call a function via a pointer" "1086": "Demo the difference in the assembly when building as an x64 executable, and then in release mode" "1281": "Demo what has to happen when you call a C++ virtual function" "1749": "Run the game and determine to get teleportation working" "1793": "handmade_world_mode.cpp: Enable UpdateAndRenderEntities() to teleport entities when they stand on a boost pad" "2071": "Run the game and try out the boost pad" "2217": "handmade_brain.cpp: Enable ExecuteBrain() to make the hero's head spring back to the body" "2350": "Run the game and try out the boost pad to find that the head follows the body" "2441": "handmade_entity.cpp: Make the body hop from the boost pad to the landing location" "2650": "Run the game and try hopping off the boost pad" "2735": "todo.txt: Update and consult the TODO list" "3058": "Q&A" "3089": "My 3 year old would like to know "why he angry?" re: the hero" "3140": "I think the snakes choose their next jump destination while still on the upper floor, so after they get boosted down they can jump back up again" "3187": "If you look at Kirby, the American version always has an angry face and the Japanese version is always smiling" "3204": "What happens if someone blocks the place someone gets boosted down to" "3241": "Can we talk again about Euro time stream?" "3292": "Close "Solution ideas for the floor relative perspective transition issues"" "3352": "Streams at times for Europe like you did at the start of the project" "3405": "Are more general software questions okay?" "3427": "Not being boosted down would clue the player in that there is an enemy there. Will that affect gameplay much?" "3473": "Any reason why you don't just let the hero jump down and only use jump pads for moving up levels?" "3516": "In case you care, my problem with Minowski sums before was that when you drew it, the way it was drawn, my brain assumed you meant the origin of the shapes and not the origin of the graph" "3574": "demetrispanos told me about time reversible debuggers, and it sounds kinda bonkers. How would you implement it without making a huge strain on the runtime?" "3733": "Thoughts on VR? Have you had a chance to try out modern VR experiences? Developed any software for VR or thought about it?" "3946": "I looked for calls to the OS to give me the page size and I couldn't find it" "4015": "I meant the allocated pages" "4052": "Have you had a chance to look into the Rust programming language? Thoughts?" "4060": "Is the penalty for polymorphic calls in non-intensive sections of codes worth the trade-off of usage benefits? Also, do you think you could beat John Carmack in a fight? You seem buff" "4195": "To be real, my other question didn't matter. I don't care about polymorphism" "4267": "How long do you think until a new low-level-capable language will be produced to surpass C++?" "4558": "Dlang!" "4688": "Everything worth noting is made in C++, though" "5034": "Do you think the fundamental issue with programming languages is not giving access to memory and treating memory as first class?" "5201": "A classmate in my graphics class actually cursed me out last week because malloc() "is too complicated to use in large programs." It's nuts how ardent people are about believing obviously wrong things. Just bonkers" "5448": "This sounds like a good argument for requiring software engineering students to ship a game as one of the requirements for graduation" "5490": "Do you think it's worth moving to C++ from C99?" "5511": "Picking the less of two evils here, what's your advice between GNU Emacs and MCS?" "5532": "If JAI doesn't work out, will you have to take it into your own hands and make a language?" "5589": "Is there a practical way to use C in place of web languages like JavaScript and HTML? Is it possible to give them competition on the web?" "5717": "When I started at University we started learning OOP and Java. Do you think that this is part of the problem? I'm pretty sure if we'd started learning about Hardware then Assembly then C I would have been a better programmer earlier" "5797": "How high is getting rid of windows.h and std libraries on your TODO list?" "5827": "So you still need to convert to HTML, JavaScript, etc, but you do your main development in C?" "5901": "Yes, getting rid of std libraries and windows.h on Handmade Hero" "5957": "What do you think about the new Coffee lake processor announcement? Seems like Intel is losing it" "5971": "Do you think TDD is efficient for a learning tool?" "5980": "What is your opinion on high level features that are predicated on the unobservability of various low level details?" "5996": "How is it even possible to remove windows.h? I thought that was the lowest possible choice without writing an OS yourself" "6055": "Have you done any JavaScript programming?" "6071": "The announcement was "10nm for low performance machine, and 14nm for high end, but more cores for them"" "6109": "Shawn I know has his own file for just the windows function prototypes he uses. I've tried this in C, and it worked practically flawlessly, but I've had a problem getting it to work in C++. Do you know anything about that, that it could help me? Or should I try the forum?" "6155": "Have you considered getting a team together and maybe making a new language, doing it the right way?" "6215": "I am currently writing the renderer for my own engine and I don't know if I should future proof it by writing it in Vulkan or stick with OpenGL 4.3. Do you have any opinions on the importance of multithreading for rendering?" "6343": "Remove context from OpenGL? What do you mean?" "6470": "Interesting that you and Jonathan Blow disagree about the usefulness of AZDO (but you both seem to agree that we should just have a stable ISA and not even bother with programming GPUs through an API anymore)" "6642": "Do you think DX12 is going to be a big improvement over 11?" "6654": "Done" --- name: "day336" title: "Adding a Particle System Cache" markers: "5": "Set the stage for working on the particle system" "195": "Blackboard: Sim Regions and a Persistent Particle System" "403": "Blackboard: Deterministic f(t) Particle System" "590": "Blackboard: f(delta*t) Particle System" "657": "Blackboard: The expense of a persistent f(t) particle system" "890": "Blackboard: Cached particles" "1197": "Set the stage for tomorrow" "1358": "Run the game and see our current situation, before taking a look at the sim_region stuff" "1512": "Create handmade_particles.h and handmade_particles.cpp, and talk a little about writing the usage code first" "1634": "handmade_sim_region.cpp: Make BeginSim() assert that we have a Source" "1721": "handmade_sim_region.cpp: Start to add the calling site code for the particle system to BeginSim()" "1969": "Blackboard: Shutting down the particle code" "2191": "handmade_sim_region.cpp: Make BeginSim() activate the particle system upon unpacking" "2276": "handmade_entity.cpp: Make UpdateAndRenderEntities() initialise the particle_cache and call UpdateAndRenderParticleSystem()" "2454": "handmade_particles.cpp: Introduce UpdateAndRenderParticleSystem(), GetOrCreateParticleSystem() and TouchParticleSystem()" "2637": "handmade_world_mode.cpp: Make UpdateAndRenderWorld() rather than UpdateAndRenderEntities() call UpdateAndRenderParticleSystem()" "2688": "handmade_particles.cpp: Pluralise UpdateAndRenderParticleSystems()" "2767": "handmade_particles.h: Introduce particle_system and particle_cache structs" "2889": "handmade_particles.cpp: Implement TouchParticleSystem()" "3014": "Calculate the number of cache lines required by our scheme" "3111": "handmade_particles.cpp: Start to implement GetOrCreateParticleSystem()" "3306": "handmade_particles.cpp and *.h: Introduce InitParticleSystem() and particle_spec struct" "3363": "handmade_sim_region.cpp: Make it optional to pass a ParticleCache to BeginSim() and do general clean-up" "3493": "handmade_entity.h: Introduce a version of IsEqual which takes entity_id" "3526": "handmade_particles.cpp: Slightly flesh out TouchParticleSystem() and UpdateAndRenderParticleSystems()" "3636": "handmade_entity.h: Add particle data to the entity struct and finish bookkeeping" "3774": "handmade_world_mode.cpp: Make PlayWorld() initialise the ParticleCache" "3908": "Run the game and crash and tie up some loose ends" "4045": "handmade_particles.cpp: Introduce InitParticleCache()" "4133": "Run the game, crash in EndSim() and investigate why" "4263": "handmade_particles.cpp: Make UpdateAndRenderParticleSystems() assert that the Cache is the correct size" "4438": "Investigate whether or not we're reclaiming the ParticleCache memory" "4803": "Spot the bug in GameUpdateAndRender() with our needed memory arena being closed" "5031": "todo.txt: Add "Arena upgrade!"" "5105": "handmade_world_mode.cpp: Make PlayWorld() allocate the ParticleCache from the ModeArena for now" "5180": "Run the game and see that it's fine now" "5208": "Q&A" "5254": "I think you should be searching for MaxFramesSinceTouched instead of MinFramesSinceTouched" "5269": "handmade_particles.cpp: Make GetOrCreateParticleSystem() test on the MaxFramesSinceTouched" "5301": "So was the problem that the transient memory vaporized per frame, while the particle cache needs to stay across frame?" "5475": "Not sure if this has been answered on a previous stream (still trying to catch up). When you introduced the threading model, you mentioned that we would want one thread per core, but since the OS creates threads for us (so helpful) for things like audio, does it matter then that we end up with more threads than cores?" "5616": "Do you know if he fully swapped out of emacs?" "5646": "Demo and plug (in-development) 4coder features" "6077": "Wrap it up" --- name: "day337" title: "Convenient SIMD for Particles" markers: "9": "Recap and set the stage for the day" "133": "Run the game and note that entities may now have a particle system attached to them" "216": "Look in the art pack for some particle art" "307": "handmade_particles.cpp: Move in the existing particle system code from handmade_world_mode.cpp" "451": "Blackboard: Particle Efficiency" "745": "Blackboard: Texture Atlases" "802": "Blackboard: Texture Arrays" "984": "Determine to use a texture atlas for the particle system" "1093": "handmade_particles.h: Change the data in the particle_system struct to use SIMD registers, with a few words on vectorising" "1348": "handmade_particles.cpp: Introduce PlayAround() and rework it to operate on our SIMD data" "1743": "handmade_particles.cpp: Introduce MMSetExpr() and continue implementing PlayAround()" "1942": "Note that we can't do the Lagrangian grid four-wide without upping the minimum system requirements to AVX-512" "2091": "handmade_particles.cpp: Forego the grid for now and continue implementing PlayAround()" "2215": "handmade_particles.cpp: Introduce operator+() and operator*() to operate on __m128 registers for PlayAround() to use" "2645": "handmade_particles.h: Introduce particle_v3 struct in order to simplify the operations in PlayAround()" "2989": "handmade_particles.h: Introduce particle_v4 struct" "3108": "handmade_particles.h and *.cpp: Introduce particle struct and GetParticle() for PlayAround() to use" "3468": "handmade_particles.h: Introduce v3_4x and versions of operator+=(), operator*() and operator+() to operate on and return those" "3910": "Q&A" "3952": "On MSVC it is possible to create non-member inline operator += for __m128. It is done in same way as you did for v2/v3/v4 types. But for gcc / clang you cannot do += for __m128, because they already have it builtin operator" "3993": "handmade_particles.h: Tweak &operator+=()" "4050": "Instead of doing the particle_v3 struct, could you accomplish the same thing with macros and some pointer math?" "4106": "How much of your time would you say you spend refactoring as compared to writing new code?" "4298": "Have you changed the way the particles look? If so, please show them" "4373": "Do you often write code using SIMD without a non-SIMD implementation of the same operation?" "4450": "If JAI releases before the end of this project and is good enough, would you ever consider rewriting the project in JAI, or is the project too big and the gains too small?" "4548": "Is it hard to debug SIMD in Linux? Have you tried it?" "4624": "It would be cool to see a stream or two of a good programmer (you) going through the motions of learning JAI" "4714": "Closing gambit" --- name: "day338" title: "Simulation-space Particles" markers: "8": "Recap and set the stage for the day" "82": "Blackboard: Particle Cache" "367": "handmade_particles.h: Remove the notion of a particle system cache" "457": "handmade_particles.cpp: Remove GetOrCreateParticleSystem(), TouchParticleSystem() and InitParticleSystem(), rename PlayAround() to UpdateAndRenderFire() and rework InitParticleCache()" "709": "Run the game and see that this is all fine, although slower than it should be" "832": "handmade_particles.cpp: Consider why UpdateAndRenderFire() is so slow" "991": "handmade_particles.h: Introduce particle_4x, simplify particle_system and remove particle_v3, particle_v4 and the operator*()" "1075": "handmade_particles.cpp: Remove GetParticle() and make UpdateAndRenderFire() work on particle_4x" "1223": "handmade_particles.h: Introduce operator+=() for v3_4x" "1282": "Run the game and see that we are now running as fast as expected" "1363": "handmade_particles.h: Introduce operator*(), operator+() and operator+=() for v4_4x" "1488": "Run the game and see that we're still good" "1565": "Reflect on the importance of the profiler" "1729": "handmade_particles.cpp: Make UpdateAndRenderFire() take a dt and FrameDisplacementInit" "1863": "handmade_particles.h: Introduce ToV34x()" "1917": "handmade_particles.cpp: Enable UpdateAndRenderFire() to render particles through the standard path" "2644": "Run the game, note that we are theortically generating particles and investigate why we aren't seeing them" "2829": "handmade_world_mode.cpp: Prevent everything but the particles from being rendered, run the game and see them" "2862": "handmade_particles.cpp: Introduce SpawnFire()" "2994": "handmade_entity.cpp: Make entities call SpawnFire() when they land" "3043": "Run the game and see no spawning occurring" "3100": "handmade_world_mode.cpp: Reduce ScreenIndex to 1, run the game and see that the particle spawning is working just fine" "3135": "handmade_world_mode.cpp: Generate two horizontally aligned screens, run the game and see what happens to the particles upon leaving a room" "3315": "handmade_particles.cpp: Make UpdateAndRenderParticleSystems() take the FrameDisplacement" "3388": "handmade_world_mode.h: Add LastCameraP to the game_mode_world struct and make UpdateAndRenderWorld() compute that LastCameraP" "3486": "Run the game, see that the particles are not being displaced correctly and investigate why" "3711": "Blackboard: Calculating that displacement" "3753": "handmade_world_mode.cpp: Correctly compute the FrameToFrameCameraDeltaP and LastCameraOffset" "3874": "Run the game and see that our particles may now be correctly displaced" "3898": "handmade_particles.cpp: Tweak SpawnFire() to shorten the lifetime of the particles, run the game and check them out" "3997": "handmade_world_mode.cpp: Remove LastCameraOffset and displace the particles with the WorldTransform" "4191": "Run the game and admire the particles" "4233": "Q&A" "4280": "gcc & clang don't have m128_f32 member for __m128. They need _mm_store_ps or something like ((float*)&A->P.x)[index] (or union with float array)" "4325": "handmade_particles.cpp: Use the M macro for rendering the particles and introduce handmade_simd.h" "4564": "soysaucethekid was suggesting to slow down the time to make sure it is now right" "4792": "Not too long ago, you changed world coordinates to be s32 instead of u32. I think they were unsigned originally so that overflow would work correctly to have the world wrap around" "4827": "Does the Z position of the particles not get affected by the perspective transform?" "4978": "But when your position goes from INT_MIN to INT_MAX, won't it cause undefined behavior?" "5029": "todo.txt: Update the TODO list" "5056": "Signed integer overflow?" "5145": "Lament the absence of real 3D and close things down" --- name: "day339" title: "Debugging Particle Camera Offset Motion" markers: "77": "Run the game and consider our current situation with entities being incorrectly displaced while the camera moves" "249": "handmade_particles.cpp: Try temporarily nullifying the FrameDisplacement, run the game and see what happens" "364": "handmade_particles.h: Add FloorZ and ChunkZ to the particle_4x struct" "488": "handmade_particles.cpp: Make SpawnFire() take FloorZ and ChunkZ and enable UpdateAndRenderFire() to compute the transform from these values" "828": "Run the game to see if that affects things and consider why we see that sinusoidal slippage" "1573": "Debugger: Step in to SpawnFire() and compare the transforms of a particle and its calling entity" "1807": "handmade_particles.cpp: Make UpdateAndRenderFire() set the particle's OffsetP to OffsetP + P, before nullifying that P" "1986": "Run the game and see if this is more correct" "2060": "handmade_particles.cpp: Keep the particles in one place, run the game and watch how they move" "2296": "build.bat: Switch to -O2, run the game, crash and investigate why" "2683": "Explain the bug with us doing an unaligned load" "2806": "handmade_world_mode.cpp: Pass AlignNoClear(16) to the PushStruct() call which sets the ParticleCache, run the game and find that that fixed it" "2839": "Switch to the software renderer, observe the corkscrew motion in the particles and consider how to fix it" "3029": "handmade_particles.cpp: Make UpdateAndRenderFire() pass 0 as the alignment to PushBitmap(), run the game to see if that affects it, and continue investigating" "3297": "Q&A" "3317": "Look at the screen border while you're doing it" "3437": "Entities get displaced by the modified CameraP during room transitions, I think" "3472": "What if you disable the parabolic camera transition between rooms?" "3507": "handmade_sim_region.cpp: Toggle off the parabolic camera, run the game and see that the entity displacement is now solid" "3777": "handmade_world_mode.cpp: Try setting CameraP.z and then CameraP.y to 0, run the game and see how that affects it" "3903": "handmade_entity.cpp: Note that UpdateAndRenderEntities() is erroneously using the CameraOffset.z to set the floor height, and make it use CameraP" "4020": "handmade_particles.cpp: Make UpdateAndRenderParticleSystems() and UpdateAndRenderFire() take CameraP" "4118": "Run the game and see that it sort of worked" "4236": "Full on 3D would probably be less complicated at this point" "4473": "What is the difference between Handmade Hero and 1935?" "4496": "So just now the fix only applied to the particles? Because the borders are still moving" "4512": "In the code, I think they mean" "4752": "Are we able to change the projection in this game?" "4776": "In UpdateAndRenderEntities (in handmade_entity.h) is the MovementMode_AngleAttackSwipe case missing a break or is the fall-through intentional" "4789": "How far would you say you are with developing the game? How many episodes can we still expect?" "4876": "Do you find it difficult to context-switch between 1935 and Handmade Hero, and, if so, has it gotten easier with time?" "5034": "Go back and end the stream" --- name: "day340" title: "Cleaning Up World / Sim-Region Interactions" markers: "8": "Welcome back after having moved to the Molly Rocket offices" "45": "On switching to a full 3D pipeline" "598": "todo.txt: Consult the TODO list" "713": "Blackboard: Sim Region and World" "867": "Blackboard: Creation" "986": "Consider how the entity (un)packing currently works" "1140": "handmade_sim_region.cpp: Pull in the entity packing functionality from handmade_world.cpp" "1374": "handmade_world.cpp: Rename PackEntityIntoChunk() and PackEntityIntoWorld() to overloaded UseChunkSpace() functions" "1483": "handmade_world_mode.cpp: Consider allowing many entities to be stuffed into a sim region" "1644": "handmade_world_mode.cpp: Simplify BeginEntity() and EndEntity()" "1745": "handmade_sim_region.cpp: Introduce CreateEntity()" "1807": "handmade_sim_region.h: Add a NullEntity to the sim_region struct for CreateEntity() to use if we've hit the MaxEntityCount" "2010": "handmade_sim_region.cpp: Consider how to insert the entity into the hash table" "2185": "handmade_sim_region.cpp: Reorganise BeginSim() to only add an entity if there's room for it" "2274": "handmade_sim_region.cpp: Introduce AddEntityToHash() for CreateEntity() to call" "2456": "handmade_world_mode.cpp: Introduce AllocateEntityID() for BeginEntity() to call" "2494": "handmade_world_mode.cpp: Make PlayWorld() create a dummy sim region for BeginSim() and EndSim() to use" "2821": "Run the game and see what we've destroyed" "2910": "handmade_world_mode.cpp: Make AddPlayer() set and unset the creation region" "2956": "Run and investigate what else is failing" "3017": "handmade_sim_region.cpp: Make TransactionalOccupy() check that we have a desired traversable_reference" "3138": "Step into EndSim() and inspect the Region and Entity" "3375": "handmade_sim_region.cpp: Consider removing ChunkDelta from EndSim()" "3622": "Step back into EndSim() and inspect the DestE and Entity" "3671": "handmade_world.cpp: Prevent UseChunkSpace() from taking a sim_region" "3729": "Q&A" "3796": "handmade_sim_region.cpp: Comment out the MaxEntityVelocity assertion in MoveEntity(), run the game and continue investigating" "3875": "handmade_sim_region.cpp: Make GetSimSpaceTraversable() only operate if it has an Entity, run the game and see the cool" "3924": "Did you resolve the kerning / horizontal advance for kanji characters? I found when implementing it myself on OSX (at the font table level) that Arial doesn't actually have kanji in it. It seems Windows (and Mac - the higher level APIs like CoreText) load multiple font files for you if it detects that you are trying to load a codepoint that is outside the range of a particular font file" "4044": "handmade_sim_region.cpp: Look through EndSim()" "4142": "Can you explain what the idea is behind using a zero-sized sim region bounds?" "4212": "Run the game and note how everything is gravitating towards that lower-left area" "4308": "handmade_world_mode.cpp: Make EndEntity() correctly compute the Entity->P" "4441": "Run the game and see that we're a little better" "4638": "Consider why other entities are able to traverse the trees, while we aren't" "4748": "I've just started watching this stream. How often have you needed to refactor major parts of your code?" "5255": "Is the ms counter in the corner the render time for the frame?" "5418": "build.bat: Switch to -O2, run the game and consult the profiler" "5531": "Need OpenGL query timers" "5570": "I was about to ask what would happen if one of those snakey guys got themselves stuck in a corner, but I see one already did" "5699": "Off-topic: Since there wasn't any sound in the pre-stream, are there any sneak peaks regarding HandmadeCon you can give us?" "5901": "todo.txt: Add the trees on traversables bug to the TODO list" "5950": "Close it down" --- name: "day341" title: "Dynamically Growing Arenas" markers: "15": "Recap and set the stage for the day" "72": "Blackboard: Expanding Arenas" "429": "Blackboard: How our arenas currently work" "572": "Blackboard: Dynamic Array" "833": "handmade_memory.h: Enable PushSize_() to expand the memory arena by at least the MinimumBlockSize" "1550": "handmade_memory.h: Introduce a version of InitializeArena() that takes the MinimumBlockSize" "1684": "handmade_memory.h: NOTE(casey): PROGRAMMING! RAII = bad :( ZII = good :)" "1819": "handmade_memory.h: Add MinimumBlockSize to the memory_arena struct and clean up compile errors" "2109": "Run the game and see nothing different happen" "2166": "win32_handmade.cpp: Remove the DebugStorageSize" "2374": "handmade_debug.cpp: Enable the debug system to use a dynamically growing arena" "2751": "handmade_debug.cpp: Introduce DEBUGInit()" "3003": "Run the game and step through DEBUGInit() to see what happens" "3114": "handmade_debug.cpp: Stop DEBUGInit() from initialising unnecessary data" "3155": "Continue stepping through DEBUGInit()" "3329": "handmade_debug.cpp: Make StoreEvent() assume that it never frees" "3368": "Run the game with our new dynamically growing arena in action" "3453": "Q&A" "3508": "Chink. Kappa?" "3528": "If you allocate a new block after calling BeginTemporaryMemory, EndTemporaryMemory is going to restore incorrect values, isn't it?" "3590": "How easy or possible is it to transfer code from Java to an engine that does graphics well and, if it is possible or easy to transfer, which one would you recommend?" "3792": "Would it be a good idea to store a pointer to the allocator function inside the arena struct instead of using a global?" "3876": "How do we free old memory blocks if the base pointer always points to the newest allocated block?" "3901": "Perhaps I am missing something, but how do you go back to previously allocated memory blocks? Like for freeing memory and saving it out and reloading it" "3949": "So are you a cat in your off time?" "3966": "Wind it down" --- name: "day342" title: "Supporting Temporary Memory in Dynamic Arenas" markers: "2": "Recap and set the stage for the day" "172": "Run the game to see that we are still running and can do looped live code editing" "272": "handmade_memory.h: Determine to provoke some deleterious effects" "459": "handmade_platform.h: Replace TransientStorage with a TransientState" "613": "handmade.cpp: Enable DEBUGGetMainGeneration() to initialise a TransientState" "659": "handmade_memory.h: Introduce BootstrapPushSize_() and BootstrapPushStruct() for all of the transient arena initialisation sites to use" "1221": "Run the game and crash in EndTemporaryMemory()" "1352": "Blackboard: Temporary Memory for Dynamic Arenas" "1511": "handmade_memory.h: Introduce memory_block_footer struct and GetFooter() and make PushSize_() stick that footer onto the end of blocks" "1977": "handmade_memory.h: Add Base to the temporary_memory struct to enable EndTemporaryMemory() to loop back over the blocks, and introduce FreeLastBlock()" "2178": "Run the game to see that we're totally running as we were before" "2255": "Consult perfmon to verify that we're not leaking memory" "2424": "Switch over the entire codebase to run through dynamic allocation" "3081": "Run the game successfully" "3252": "handmade_memory.h: Enable Clear() to handle dynamically allocated blocks" "3525": "handmade_world.h: Make all modes use the arena they're given rather than sub-allocating out of it" "3628": "4coder feature: Stream mode" "3690": "Run the game to see that our poor cutscene is gone" "3799": "Reflect on our first part of the memory upgrade" "3847": "todo.txt: Update the TODO list" "3888": "Q&A" "3958": "Have you ever tried reserving a very large amount of memory, and then committing memory as needed, so the arena can grow without the base pointer changing?" "4028": "Thoughts on placing the "footer", at the beginning of the memory area, so bad co-workers don't overwrite it (because it is at the end currently)" "4209": "You spend so much time on memory management. If programming games for windows / Linux would it be better to use malloc and then create custom allocation for hot parts?" "4263": "Casey, how strict are you on minimizing the amount of memory is used by the game?" "4341": "Your article didn't even touch on the horrors of ETW. I had to manually fill out several GUIDs that msft decided not to include in their headers for some reason by pulling them off three different, very obscure MSDN pages that were auto generated for C# markup. I had to reverse engineer several void * pointers by using partial data on MSDN and inspecting the memory and guessing sizes, offsets and types. There was a variable listed on MSDN as "object UserSID"... Yes, the type was "object", and guess what! It's not a SID, it's 2 unknown / undocumented pointers then a SID! What are those pointers? Who knows. They also intermixed ASCII and UTF16 strings, one after the other with no documentation... Yay!" "4408": "When we're dynamically allocating, we could potentially end up allocating every last drop of memory available to us, right? Are there situations in which we'd want to make sure we allocate "some amount" less than the max and, if so, how would we best do that?" "4556": "So currently you can only free memory in the last memory blocks? If you wanted to free stuff near the beginning of the arena and keep the stuff at the end, you would need to do things differently?" "4677": "If you are planning on large worlds, are you planning then on compressing and decompressing from the mandala on the fly?" "4752": "Will Handmade Hero use texture compression in OpenGL?" "4819": "The term "arena" refers to a region of memory from which multiple objects are allocated and which can be deallocated all at once. Some arenas support object freeing, some do not" "4863": "Close up" --- name: "day343" title: "Saving and Restoring Dynamically Allocated Memory Pages" markers: "3": "Recap and set the stage for the day" "247": "Run the game to demo the current situation with regards to the looped live code editing" "371": "win32_handmade.h: Introduce a win32_memory_block struct and add a MemorySentinel to win32_state to enable us to iterate over the memory blocks" "607": "win32_handmade.cpp: Enable PLATFORM_ALLOCATE_MEMORY() and PLATFORM_DEALLOCATE_MEMORY() to handle multiple linked memory blocks" "1280": "Note a caveat: This linked list is not thread-safe" "1370": "win32_handmade.cpp: Make PLATFORM_ALLOCATE_MEMORY() thread-safe" "1534": "win32_handmade.cpp: Think through how to enable Win32BeginRecordingInput() and Win32BeginInputPlayBack() to handle multiple memory blocks" "1811": "win32_handmade.cpp: Get rid of MapViewOfFile() and Win32GetReplayBuffer() and other cruft" "2148": "win32_handmade.h: Introduce win32_saved_memory_block struct and enable Win32BeginInputPlayBack() to play from blocks of that type" "2465": "win32_handmade.cpp: Enable Win32BeginRecordingInput() and Win32EndRecordingInput() to handle multiple blocks" "2823": "Reflect on what we've done, run the game, crash in a Win32DeallocateMemory() call and investigate why" "3079": "Reproduce the bug and investigate what's happening" "3203": "win32_handmade.cpp: Make the linked list in PLATFORM_ALLOCATE_MEMORY() thread-safe" "3262": "Run the game and try in vain to reproduce the bug, before describing what was happening" "3309": "Run the game again and crash in inside KernelBase.dll in Win32BeginInputPlayBack()" "3385": "win32_handmade.cpp: Make Win32BeginInputPlayBack() pass &BytesRead to ReadFile()" "3451": "Run the game and find that that fixed it" "3535": "win32_handmade.cpp: Make Win32BeginRecordingInput() pass &BytesWritten to WriteFile()" "3563": "Run the game and determine that we're not quite reloading correctly" "3599": "Q&A" "3651": "Could you explain the padding you used for the memory struct? I believe you said it was for cache-line stuff, so if you omitted it, would it just result in more cache line misses or would it crash the game?" "3795": "How did you get to where you are today and how did you do it, in terms of coding knowledge?" "3844": "It's a bit early to ask, but will there be a HandmadeCon 2017?" "3988": "Would you recommend any specific resource for learning C++? So far I've been using the "learncpp" website" "4005": "Have you ever used a rope to manipulate strings?" "4111": "Aren't you going to read in pages that have been deallocated?" "4311": "So with memory systems, do you always try to put extra bits of data at the end to ensure if they ask for memory from a specific address then it doesn't ruin their day?" "4402": "Close it down with a glimpse into the future" --- name: "day344" title: "Selective Memory Restoration" markers: "14": "Recap and set the stage for the day" "65": "Run the game and take a look at where we're at with the looped live code editing" "186": "Step into Win32BeginRecordingInput() and inspect what is going on" "241": "win32_handmade.cpp: Make Win32BeginRecordingInput() write to the right handle" "320": "Run the game to see that we've got our looped live code editing working with dynamic allocations" "386": "Consider how to save and restore the loop edits more efficiently" "503": "handmade_asset.cpp: Look at how the asset system currently operates" "664": "win32_handmade.h: Introduce win32_memory_block_flags in order to enable a win32_memory_block to be bypassed by the save / restore process" "894": "win32_handmade.cpp: Make Win32BeginRecordingInput() obey those flags" "996": "handmade_asset.cpp: Make AllocateGameAssets() bootstrap its own arena as NonRestoredMemory" "1134": "Run the game and see it work just fine" "1165": "handmade_memory.h: Make BootstrapPushSize_() take AllocationFlags, and introduce DefaultBootstrapParams() and NonRestoredArena()" "1407": "handmade_platform.h: Make the platform_memory_block_flags platform independent" "1456": "Run the game, try out the save / restore, hit the assert in BeginGeneration() and investigate why" "1589": "handmade_asset.h: Try disabling the InFlightGeneration code" "1804": "Run the game to see that it's all working, and consider whether or not to support InFlightGeneration" "1901": "handmade.h: Try putting the InFlightGeneration code in the transient_state" "2239": "Run the game with the asset locking being stored and check the size of loop_edit_1_input.hmi" "2409": "Consider handling mid-recording memory allocations / deallocations" "2643": "win32_handmade.cpp: Enable Win32EndInputPlayBack to handle memory AllocatedDuringLooping" "2996": "win32_handmade.cpp: Introduce Win32ClearBlocksByMask() and Win32FreeMemoryBlock()" "3475": "win32_handmade.cpp: Make PLATFORM_ALLOCATE_MEMORY() and PLATFORM_DEALLOCATE_MEMORY() set the LoopingFlags, and introduce Win32IsInLoop()" "3617": "Run the game and leave a loop running" "3626": "Q&A" "3654": "nxsy !qa" "3750": "What happened to the black dot?" "3855": "I'm scared to look back at my own library reload (not even looped editing) after I stopped using it for a few months. Probably 10+ hours of debugging ahead of me" "3892": "Besides UI, what things must use threads in games? Just started learning threads and I'm curious. There are some things that somehow run slower threaded than single" "4270": "For the moment I have a thread job system. It's for rebuilding a mesh. For a big mesh it takes like 20 ms, so I thought maybe it would make it faster but not that much, maybe like 13% faster" "4375": "Go ahead and close things down" "4462": "Announcement: HandmadeCon 2016 speaker list" --- name: "day345" title: "Protecting Memory Pages for Underflow Detection" markers: "1": "Recap and set the stage for the day" "76": "Blackboard: Buffer Overruns" "167": "Blackboard: VirtualAlloc() and virtual memory mapping" "383": "Blackboard: Playing with how this memory works" "503": "Blackboard: Guard Page with VirtualProtect()" "578": "Blackboard: Faulting at the smallest error" "809": "handmade_platform.h: Add PlatformMemory_OverflowCheck and PlatformMemory_UnderflowCheck flags" "891": "handmade_memory.h: Enable PushSize_() to perform bounds checking by passing every allocation down to the system every time" "1046": "Run the game and see nothing in particular happen" "1057": "handmade_memory.h: Make PushSize_() set the OverflowCheck flag on everything, run the game and grind to a halt" "1164": ""You're an operating system. Have some self-respect"" "1191": ""It's 2016, and all you have to do to kill Windows is just allocate some memory"" "1235": "Return with the determination to provide a way to free our memory" "1308": "handmade_memory.h: Change PushSize_() to ensure arenas only keep the exact size they need" "1424": "Run the game to give that a shot" "1472": "handmade_memory.h: Rename memory_block_footer to memory_block_chain" "1622": "Blackboard: Positioning that memprotect in order to catch underflows" "1646": "win32_handmade.cpp: Make PLATFORM_ALLOCATE_MEMORY() allocate one blank 4K page at the beginning" "1813": "handmade_memory.h: Consider unifying the arena and allocator's data structures" "1900": "win32_handmade.cpp: Make PLATFORM_ALLOCATE_MEMORY() allocate" "1954": "Run the game to see it run exactly the same" "1965": "win32_handmade.cpp: Make PLATFORM_ALLOCATE_MEMORY() call VirtualProtect()" "2223": "Blackboard: What actually happens with the guard page" "2340": "win32_handmade.cpp: Pass PAGE_NOACCESS to that VirtualProtect() call" "2378": "win32_handmade.cpp: Verify that the guard pages are happening properly" "2411": "Run the game with the expectation to crash and investigate why we don't" "2438": "handmade_memory.h: Make PushSize_() set the UnderflowCheck flag, run the game and successfully crash" "2488": "win32_handmade.cpp: Enable PLATFORM_ALLOCATE_MEMORY() to perform underflow checking" "2822": "win32_handmade.cpp: Enable PLATFORM_DEALLOCATE_MEMORY() to handle the checking" "3066": "handmade_world.cpp: Make GetWorldChunk() write off the beginning of the buffer, run the game and see nothing being detected" "3117": "handmade_memory.cpp: Toggle on the underflow checking in PushSize_(), run the game and immediately catch that offending write" "3169": "handmade_world.cpp: Make GetWorldChunk() write off the end of the buffer, run the game and see nothing being detected" "3214": "handmade_memory.cpp: Determine to enable PushSize_() to perform overflow checking" "3316": "todo.txt: Update the TODO list" "3339": "Q&A" "3359": "!qa" "3406": "Yes" "3496": "I'm following an Linux with SDL because I'm not sure if it's worth building on X11 or if Wayland is ready yet. Have you thought about building on X11, Wayland or both?" "3568": "Before when you had fixed allocation, you could do a between-runs save state kind of thing (if I recall correctly). How would you make that happen with the dynamic blocks?" "3588": "Do you have any insight into if you are developing this game in a similar timeflow to major devs, e.g. you spent some time today working on under / overflow before such a thing came into play. Is this just because of the format of the show?" "3666": "Why do you look so different from Handmade Hero Day 001?" "3705": "Does it really work between runs of the program? I saw it work with looped editing, but not different runs. Wouldn't you need to muck with base pointers?" "3826": "I know this isn't relevant to the code, but does it seem strange streaming in a different location?" "3845": "Seems that Arena started out as a fast, stack-style allocator and is now moving towards a dynamic heap. You've demonstrated the benefits of VirtualAlloc etc. but can you comment on the performance hit and why you choose it over malloc?" "3922": "Don't recognize the tune" "3945": "Are any days (streams) missing from the YouTube archive?" "4025": "Was memprotect the primary motivation for moving to dynamic memory, or were there other reasons?" "4162": "Wrap it up" --- name: "day346" title: "Consolidating Memory Block Headers" markers: "11": "Recap and set the stage for the day" "67": "Run the game and assess our current situation" "202": "Blackboard: Memory Protection" "428": "Consider sharing the memory protection block with the operating system" "610": "handmade_platform.h: Introduce platform_memory_block struct which is shared with win32_memory_block" "728": "handmade_platform.h: Collapse the memory_block_chain into platform_memory_block" "931": "handmade_memory.h: Make PushSize_() use our new platform-provided struct" "1349": "handmade_memory.h: Make Clear() and FreeLastBlock() operate on this struct" "1488": "win32_handmade.cpp: Rewrite PLATFORM_ALLOCATE_MEMORY() and PLATFORM_DEALLOCATE_MEMORY() to implement our new shared scheme" "1830": "Run the game and fix miscellaneous bugs" "1988": "Run the game to see that we're running okay" "2019": "win32_handmade.cpp: Enable PLATFORM_ALLOCATE_MEMORY() to perform overflow checking" "2397": "Blackboard: Checking for any set bits" "2495": "win32_handmade.cpp: Continue enabling overflow checking" "2619": "Run the game to see it successfully catch our overflow bug" "2658": "handmade_world.cpp: Remove that bug, run it again, crash in PushAndNullTerminate() and investigate why" "2783": "Calculate what we would expect" "2897": "Step through PushSize_() to see what it's computing" "3137": "Consider our choices for getting the correct alignment" "3237": "handmade_memory.h: Enable PushSize_() to compute the size using the alignment" "3277": "Run the game to find that we are maintaining alignment" "3345": "handmade_memory.h: Prevent PushSize_() from enabling the bounds checking, run the game and try looped code editing" "3379": "Investigate what's happening with the SourceBlock.Size" "3492": "win32_handmade.cpp: Make PLATFORM_ALLOCATE_MEMORY() set the PageSize directly to aid our investigations" "3717": "Q&A" "3757": "Bashing Tim Berners-Lee, inventor of the outer loop from 0 to freee everything?" "3777": ""It's kind of like insobot is the beat poet of our generation"" "3831": "Maybe set the default alignment to 1 when in memory checking mode?" "3858": "todo.txt: Update the TODO list" "3903": "I know this is a little off-topic to what you are currently doing on stream, but what role does a software driver play if any at all?" "4016": "No, you can make a C++ project that enables you to use resources that you can't use in user mode in the kernel" "4252": "Done" --- name: "day347" title: "Debugging Win32 Memory List Corruption" markers: "9": "Recap and set the stage for the day" "109": "Run the game to demo the bug with the looped live code editing, and begin investigating it" "348": "win32_handmade.cpp: Walk through how PLATFORM_ALLOCATE_MEMORY(), PLATFORM_DEALLOCATE_MEMORY() and Win32FreeMemoryBlock() work" "695": "Step in to Win32FreeMemoryBlock() to gauge the rarity of this bug" "934": "win32_handmade.cpp: Introduce Win32VerifyMemoryListIntegrity()" "1151": "win32_handmade.cpp: Make PLATFORM_ALLOCATE_MEMORY() call Win32VerifyMemoryListIntegrity() at the end and start, run and hit the one at the start" "1499": "win32_handmade.cpp: Make Win32VerifyMemoryListIntegrity() increment a FailCounter, run the game and locate the failure case" "1720": "Step in to Win32VerifyMemoryListIntegrity() and identify who is getting written and when" "1835": "Set a data breakpoint on the Size, run the game and see who touched that memory location" "2158": "Look at where we set PushBufferBase, fix up RenderCommandsStruct() and correctly initialise the PushBuffer" "2281": "Run the game and find that the bug is dead" "2326": "win32_handmade.cpp: Remove the calls to Win32VerifyMemoryListIntegrity(), run the game and see that we're still okay" "2416": "win32_handmade.cpp: Introduce Win32GetMemoryStats() in order to initialise arenas with debug information" "2623": "handmade_platform.h: Introduce DEBUG_PLATFORM_GET_MEMORY_STATS()" "2786": "handmade_debug.cpp: Enable DEBUGEnd() to print the memory stats" "2968": "handmade_shared.h: Enable FormatStringList() to handle the l case" "3072": "Run the game and consult the profiler" "3159": "Q&A" "3209": "long is >= 32 bits, long long is >= 64 bits" "3300": "Windows is LLP64, everything else is LP64. The only difference between the two is the size of long. Everything else (short, int, long long) is the same" "3455": "Is there any plan on organizing the episodes in a manner such as "Worked on mandalas on these episodes"?" "3589": "We'll have "category tagging" in the new annotation system" "3655": "Would Handmade Hero get a version for Linux or is it strictly a windows project? If it's true, why not using Linux in work? Is it personal choice or is it harder to debug something on windows?" "3854": "Winners don't use drugs message needs to be added in the game's loading screen" "3870": "Seems like the questions aren't polling in... Do you usually put your rendering / updating / input processing in the same function like you have been doing?" "3912": "Is the bending of the hero's body going to be like it is now? Looks a bit weird" "3943": "On moving from Windows to Linux, how much of the onus of making this change lies on the consumers vs Linux OS "designers"? Linux distros aren't normally ordinary-user friendly" "3991": "What do you think about free software (Stallman, FSF, GPL)?" "4388": "Close it up" --- name: "day348" title: "Debugging Cutscene Z and Traversable Creation" markers: "9": "Reflect on our recent dynamically allocated arena upgrade" "174": "todo.txt: Consult the TODO list" "292": "Consider upgrading to a traditional 3D pipeline" "470": "Reflect briefly on the series thus far" "645": "Build and run and investigate what's happening with the cutscene" "876": "handmade_cutscene.cpp: Make RenderLayeredScene() set the FloorZ, run the game and step through the code" "997": "handmade_cutscene.cpp: Try flipping that computation of the FloorZ and run the game to see if that's the correct thing to do" "1230": "Step into GetRenderEntityBasisP() and inspect the P and OffsetP" "1294": "handmade_cutscene.cpp: Make RenderLayeredScene() set the OffsetP.z as well as the FloorZ, run the game and see that the cutscene has been restored" "1433": "Run the game and demo the bug with the traversables in the initial creation phase" "1500": "handmade_sim_region.cpp: Consider how entities are created and packed" "1613": "Run the game, step in to AddWall() and inspect StandingOn" "1695": "handmade_world_mode.cpp: Make AddStandardRoom() set the StandingOn.Entity.Ptr, run the game and see that all is fixed" "1811": "Consider how to clean up where arenas are used and how" "2153": "Look at all the places a memory_arena is used" "2410": "Run the game to verify that we're not leaking memory, and leave the arena where it is" "2540": "Blackboard: Overlapping Sim" "2797": "build.bat: Run in O2 and consult the profiler to gauge the cost of the simulation" "3002": "handmade_world_mode.cpp: Make PlayWorld() create more rooms, run the game and consider implementing a debug camera that shows multiple sim regions" "3147": "handmade_world_mode.cpp: Introduce UpdateAndRenderSimRegion() to do some of the work of UpdateAndRenderWorld()" "3712": "Q&A" "3729": "Run the game and try out the boost pad" "3761": "hadnmade_world_mode.cpp: Make AddStandardRoom() move the boosters down one tile, run the game and check it out" "3873": "Will the switch to 3D affect the artwork for Handmade Hero?" "3948": "Can I ask an off-topic question?" "4022": "Hi, I am way behind you in the series, but you talked about "mixin". I don’t know if you did this yet, but can you please explain it?" "4304": "Are you working on entity interactions soon (like fire weapons vs ice monster, poisonous arrows and stuff like that)?" "4315": "(Very off-topic) Can you think of the last time you took a dynamic programming approach to a problem (e.g. shortest edit distance, optimal BSTs, etc)? DP algorithms are allegedly a common interview topic, despite how silly that seems" "4416": "Blackboard: Divide & Conquer vs Dynamic Programming" "4564": "handmade_render.cpp: Describe RecursiveFrontToBack() as an example of dynamic programming" "4706": "How about movable boosters, that you can set up to chain-boost you?" "4734": "Consider possibilities for dynamic programming" "4828": "So part of the dynamic programming question mentioned the coding interview. Do you do one for new hires?" "4857": "On asking people about problems" "5087": "Chris Hecker's tech interviewing method" "5419": "On putting people on their own turf" "5594": "Is there any time that you've talked about deep learning in depth? Also wondering if you've thought about it in terms of IF parsing problems" "5625": "Speaking of past jobs, would you rather see a job at a Java shop (industry experience) vs. a local college's faculty for High Performance Computing (academia)?" "5771": "Great interview answer, thanks. The only issue I've had with that is candidates who have no projects they're proud enough to really talk about, and I feel like I'm judging them unfairly for not having the same interest for programming outside of work / class" "5862": "What are some things that can cause a smart individual who has a good understanding of programming to not be productive, and what can be done to eliminate these causes?" "6018": "But people do come with big claims on their resume, you got to at least ask about pointer math if you're hiring a C expert" "6106": "Who wouldn't know how to reverse a linked list? You can do that on the spot" "6277": "Often I have a hard time digging in to people's past projects because they throw out tons of acronyms, jargon, frameworks, etc., that I'm not familiar with. Maybe they've worked in a completely different industry, like medical or defense, and their work context is totally unfamiliar to me. How do you handle that?" "6394": "I like this interview methodology. Maybe in a chat stream one day you could mock interview someone (me?) as a demonstration" "6430": "I think we need to title it "Casey Muratori's Enhanced Interview Techniques"" "6463": "I'll do it another day if you want (can't tonight)!" "6502": "This is actually already how I do interviews. The problem is people tend to be totally blindsided by being asked about their own experience" "6574": "On how this technique is impervious to hacking" "6728": "Gotta go and reboot the machine" --- name: "day349" title: "Running Multiple Sim Regions" markers: "14": "Recap and set the stage for the day" "102": "Run the game and consider the plan for implementing multiple sim regions" "347": "handmade_world_mode.cpp: Consider how the UpdateAndRender*() functions are currently operating, and whether or not to split them up" "684": "handmade_brain.cpp: Look into why RenderGroup gets passed down to the brain" "765": "handmade_brain.cpp: Prevent ExecuteBrain() from setting AlwaysBehind and AlwaysInFrontOf, and run the game to see how the body and head are sorted" "861": "handmade_world_mode.cpp: Carve off the rendering code in UpdateAndRenderSimRegion() and determine which of its arguments may be optional" "1291": "handmade_entity.cpp: Do that same process for UpdateAndRenderEntities()" "1570": "handmade_world_mode.cpp: Run the game, then toggle off the rendering in UpdateAndRenderWorld()" "1625": "handmade_brain.cpp: Make ExecuteBrain() only run the controller code if it has an Input" "1834": "handmade_world_mode.cpp: Make UpdateAndRenderSimRegion() only process the mouse if it has Input" "1961": "handmade_world_mode.cpp: Make UpdateAndRenderWorld() call UpdateAndRenderSimRegion() twice, run the game and see what happens" "2138": "handmade_world_mode.cpp: Make UpdateAndRenderWorld() do an UpdateAndRenderSimRegion() on a second region" "2218": "Run the game and zoom out to see two regions being simulated" "2296": "Q&A" "2368": "Did you make that debug UI yourself?" "2412": "Have you thought about refactoring your "brain" code to make use of virtual methods? Switch statements on "type" is basically replicating the type system and is a bit of a code smell" "2656": "Do you use keyboard only at your day job? Are you faster without the mouse?" "2698": "I missed the reason the two areas on the screen are discontinuous. Are these two sim regions of a larger world?" "2726": "Run the game in -O2 and traverse the world towards the other sim region" "2862": "What do you think about changing float values in the debug system by the distance you drag? Example: longer drag distance == bigger increments / decrements of the value, shorter drag distance == smaller increment / decrements" "2944": "Couldn't you use CMake to generate visual studio solutions for windows?" "3036": "What books do you recommend for C programming?" "3101": "How about for learning OpenGL?" "3220": "Plug Nsight" "3356": ""RenderDoc" is a pretty amazing tool, and I've found it to be more compatible than Nsight" "3426": "Wind it down" "3486": "Announcement: A potential change in the format" --- name: "day350" title: "Multithreaded World Simulation" markers: "35": "On two-hour blocks enabling a more continuous workflow" "103": "Run the game and set the stage for the day" "168": "handmade_world_mode.cpp: Consider reworking UpdateAndRenderSimRegion() for state visibility minimisation" "474": "Run the game and consider how we want UpdateAndRenderSimRegion() to operate differently in the debug and the regular view" "692": "On when and why to pass in a superset of arguments to a function" "896": "handmade_world_mode.cpp: Introduce CheckForJoiningPlayers() to contain the player joining code from UpdateAndRenderSimRegion()" "1086": "handmade_world_mode.cpp: Consider how to split up UpdateAndRenderSimRegion()" "1305": "handmade_world_mode.cpp: Break out UpdateAndRenderSimRegion() functionality into UpdateAndRenderWorld()" "1411": "handmade_sim_region.cpp: Consider how the simulation and the packing sides are two different functions" "1487": "handmade_sim_region.cpp: Rename BeginSim() to BeginWorldChange() and EndSim() to EndWorldChange()" "1550": "handmade_world_mode.cpp: Introduce new, higher level BeginSim() and EndSim() functions, and Simulate()" "1977": "handmade_world_mode.cpp: Make UpdateAndRenderWorld() call our new functions" "2272": "Run the game to see that we're still getting the same results" "2306": "Consider reworking the passing of input to ExecuteBrain() and Simulate()" "2508": "handmade_entity.cpp: Introduce DEBUGPickEntity()" "3004": "handmade_debug_interface.h: Add MouseP to the debug_table struct and introduce SET_DEBUG_MOUSE_P() and GET_DEBUG_MOUSE_P()" "3224": "Run the game to see that's all good now too" "3253": "Q&A" "3303": "Can you try compiling with debug off?" "3341": "handmade_world_mode.cpp: Enable DEBUGPickEntity() and DEBUG_PLATFORM_GET_MEMORY_STATS() to be compiled out" "3459": "CTime stats. I know I know. It's irrelevant for the code" "3511": "Run CTime" "3588": "What does the "..." do in the define?" "3606": "handmade.cpp: Demo varargs" "4166": "How about documentation? I see you don't have too much comments in your code" "4365": "I sometimes receive comments from colleagues during code reviews that I should put long pieces of code into functions for "cleanliness". What parameters go into your thought process when deciding if a piece of code should be placed under a function? How do you make the decision?" "4696": "How much code is debug code vs real code?" "4815": "Expand the files and take the diffs?" "4874": "Restart, recap the first block of work and set the stage for the second block" "4994": "handmade_world_mode.cpp: Delineate the primary and non-primary region simulation routines in UpdateAndRenderWorld() and consider how to thread them" "5115": "Run the game and consult the profiler to see the expense of GetClosestTraversable()" "5254": "handmade_render.cpp: Recap how RenderCommandsToBitmap() creates work orders to distribute to our threads" "5413": "handmade_world_mode.cpp: Introduce DoWorldSim() in order to thread the simulation" "5552": "Note the fact that the arenas are not multithreaded constructs" "5633": "handmade_world_mode.cpp: Make BeginSim() take a TempArena that we pass in, to enable it to be multithreaded" "5783": "Consider reworking memory allocaton in terms of multithreading" "6047": "Blackboard: Memory and Multiple Threads" "6393": "handmade_world_mode.cpp: Make DoWorldSim() allocate memory that exists only for the lifetime of the work" "6631": "handmade_world_mode.cpp: Enable UpdateAndRenderWorld() to create world_sim_work orders" "6966": "Run the game and consult the profiler to see a lot of debug events being generated" "7052": "handmade_world_mode.cpp: Toggle UpdateAndRenderWorld() to take the multithreaded path, run the game and consider why it doesn't work" "7221": "handmade_world_mode.cpp: Consider why Simulate(), ExecuteBrain() and UpdateAndRenderEntities() take the WorldMode" "7366": "handmade_world_mode.cpp: Remove AddCollisionRule() and ClearCollisionRulesFor(), and prevent functions from unnecessarily taking the WorldMode" "7633": "handmade_world_mode.cpp: Make Simulate() take a particle_cache" "7724": "handmade_brain.cpp: Make ExecuteBrain() take a random_series Entropy" "7793": "handmade_entity.cpp: Make UpdateAndRenderEntities() take the TypicalFloorHeight directly for now" "7906": "handmade_sim_region.cpp: Prevent BeginWorldChange() and EndWorldChange() from taking WorldMode, and consider how better to deal with the camera" "8103": "handmade_world_mode.cpp: Make DoWorldSim() lock a mutex around BeginSim() and EndSim()" "8301": "Run the game on the multithreaded path, and investigate why the World is null" "8318": ""The world is null... the world is null!"" "8392": "handmade_world_mode.cpp: Make DoWorldSim() call Platform.CompleteAllWork(), run the game and consult the profiler" "8516": "Consider how to improve this multithreading of the simulation, with a few words on functional programming" "8622": "todo.txt: Update the TODO list" "8682": "Q&A" "8715": "(vicariously asked via Miblo) o7 Casey! Two questions: 1) Have you finished Sausage Roll? I have! >:D 2) I have been Shilling Knight for you to play Shovel Knight, and now I have to add Undertale to the list. That game a gift from gods on high" "8777": "Isn't simulating the world in several threads, can't that make the game non deterministic? Isn't the point of the RNG having a starting kernel for deterministic play for competition and stuff?" "8954": "Blackboard: RNG in Handmade Hero" "9152": "When do you go back and complete "TODO" tasks you've given yourself in the code? Is each one going to be completed before you're done, or are they simply wishlists?" "9194": "Is it important for a game programmer to have a portfolio in the same way artists do and, if so, what would be important to include?" "9293": "In a tight inner loop do you think these memory copies for the temporary scratch memory could become an overhead concern? If I understood the stream correctly, that is" "9331": "Currently what is the behavior when walking several rooms over, into another chunk?" "9373": "Save scumming?" "9381": "Will there be streams from the job fair people?" "9408": "What's the relation between IQ and success at programming?" "9440": "Off-topic question which can be answered later if necessary. I've been developing a new programming language to replace my needs for C/C++ and pretty much every other language. The main areas of research for me at the moment are: Metaprogramming, SSA optimizations, Concurrency. You being a metaprogramming "expert", other than Compile Time Execution (CTE) that is Jon's language, what other forms of metaprogramming would you like?" "9470": "Sorry, it was in context: if I open a chest, and don't get what I want, reloading a save game and playing slightly differently might get me a different RNG for the chest" "9636": "Will the game have different "levels" like the Binding of Isaac, or will the entire game be a single "level"?" "9733": "Wind it down" --- name: "day351" title: "Optimizing Multithreaded Simulation Regions" markers: "35": "A few words on the new format" "101": "Recap and set the stage for the day" "163": "Run the game, consult the profiler and assess our current situation" "572": "handmade_entity.cpp: Stop profiling the entity system, run the game and consult the event count" "708": "handmade_world.cpp: Stop profiling GetWorldChunkInternal(), run the game and consult the profiler" "802": "handmade_world_mode.cpp: Make PlayWorld() set the WorldChunkDimInMeters larger, run the game and consider drawing the bounds of those chunks" "1006": "handmade_world.cpp: Introduce GetWorldChunkBounds()" "1285": "handmade_world_mode.cpp: Make UpdateAndRenderWorld() call GetWorldChunkBounds() and draw them" "1402": "Run the game and view that debug visualisation for the chunk" "1612": "handmade_world_mode.cpp: Make PlayWorld() set the chunk size roughly equal to the room size, run the game and view the visualisation" "1771": "handmade_sim_region.cpp: Change BeginWorldChange() to only simulate one room's worth" "1880": "Run the game and note how our simulation region erroneously splits entities" "1949": "handmade_world_mode.cpp: Make UpdateAndRenderWorld() operate on the eight rooms above, below and around the player" "2193": "Run the game to take a look at how that's working" "2326": "handmade_platform.h: Add BeginTicketMutex() to the profiler, run the game to consult the profiler and consider how to improve the multithreading" "2531": "handmade_sim_region.cpp: Enable BeginWorldChange() to do a bunch of work without needing to be in a mutex" "2777": "handmade_world.cpp: Enable AddToFreeList() to insert the whole list in one go" "2885": "Run the game and consult the profiler" "3027": "handmade_world.cpp: Make RemoveWorldChunk() and AddToFreeList() themselves begin and end the mutex" "3174": "handmade_world.cpp: Consider what UseChunkSpace() does, make it begin and end a mutex, run the game and consult the profiler" "3382": "handmade_sim_region.cpp: Consider how to improve the ticket-taking in BeginWorldChange()" "3578": "Run the game and consult the profiler until we hit a deadlock and investigate why" "3763": "handmade_world.cpp: Make the correct version of UseChunkSpace() begin and end a mutex, run the game and consult the profiler again" "3880": "handmade_world.cpp: Add RemoveWorldChunk() and AddToFreeList() to the profiler, run the game and consult it" "3960": "handmade_sim_region.cpp: Add more timing blocks and functions to the profiler, running the game and consulting that profiler" "4204": "handmade_sim_region.cpp: Establish that the PushStruct() call in BeginWorldChange() is taking half our time" "4237": "Note that the timer totally failed" "4269": "handmade_memory.h: Investigate why that PushStruct() is so expensive" "4391": "handmade_sim_region.cpp: Add a timing block around that PushStruct() call in BeginWorldChange(), run the game and inspect the profiler" "4451": "Consider why we are clearing this buffer" "4580": "Break" "4895": "Return and wonder if the chat figured out what's wrong with the code" "5010": "handmade_sim_region.cpp: Make BeginWorldChange() pass NoClear to that PushStruct() call and run the game to consult the profiler" "5111": "handmade_sim_region.cpp: Time the ZeroStruct() call, run the game to consult the profiler and consider how to optimise this routine" "5307": "handmade_debug_ui.cpp: Enable DrawTopClocksList() to print out the cycles per invocation" "5398": "handmade_math.h: Introduce a 64-bit version of SafeRatio0()" "5424": "Run the game and consult the profiler" "5472": "Break into the ZeroStruct() call in BeginWorldChange() and determine that the clear is costing 7 cycles per byte" "5635": "handmade_sim_region.cpp: Verify that the clear's cycle-time is reasonable" "5841": "Consider ways to minimise the memory footprint" "6055": "handmade_sim_region.h: Add EntityHashOccupancy and BrainHashOccupancy to the sim_region struct in order to enable doing the clear with a bitfield" "6243": "handmade_sim_region.cpp: Introduce MarkOccupied(), MarkBit() and IsEmpty()" "6543": "Run the game, hit the assert in AddEntityToHash(), and fix that assertion to handle the new scheme" "6672": "handmade_sim_region.cpp: Fix the sense of IsEmpty(), run the game and crash in ExecuteBrain()" "6722": "Build and run in -Od and investigate what's happening" "6858": "handmade_sim_region.cpp: Add an assert in AddEntityToHash() to validate the hash, run the game and do not hit that assertion" "6907": "Step through AddEntityToHash() and investigate what's happening" "6990": "handmade_sim_region.cpp: Walk through GetOrAddBrain()" "7058": "handmade_sim_region.cpp: Make GetOrAddBrain() set the Hash->ID, run the game and crash in FreeFrame()" "7111": "handmade_sim_region.h: Remove the ID from the entity_hash and brain_hash and instead use their Ptr to identify them" "7176": "Run the game and note that "our brains are still not working properly"" "7435": "handmade_sim_region.cpp: Add assertions to GetOrAddBrain() in order to verify ID resolution" "7611": "handmade_sim_region.cpp: Make BeginWorldChange() and GetOrAddBrain() clear the Brains, run the game and note that we're still getting weird behaviour" "7686": "handmade_memory.h: Enable overflow checking in PushSize_(), run the game and..." "7721": ""So we don't seem to be having any overflow problems at the moment... *stream crashes*"" "7783": "Wait for Windows to decide to suspend the process" "8003": "Run the game normally having removed that overflow checking, and watch the memory counter" "8070": "handmade_sim_region.cpp: Make BeginWorldChange() clear the SimRegion, run the game and watch the profiler" "8140": "handmade_sim_region.cpp: Temporarily make BeginWorldChange() clear the EntityHash and BrainHash, run the game and watch the profiler" "8259": "handmade_sim_region.cpp: Make GetHashFromID() clear upon encountering an empty Entry for now" "8322": "Run the game successfully and consult the profiler" "8392": "Q&A" "8417": "The stream is down" "8571": "Did you fix the bug?" "8625": "There's a TODO in ZeroSize. Not sure if you noticed it" "8647": "handmade_memory.h: Remove the TODO from ZeroSize()" "8663": "What was the bug?" "8726": "We should have something built into the build script that won't let you compile if the stream has gone down. Is this possible to do in a batch script?" "8837": "Update the TODO list" "8881": "Is it an option to never clear to zero for arenas, and maybe only clear when resetting temporary memory?" "9030": "ctray.cpp: Investigate why the overlay disappeared" "9197": "Is there a still a benefit to using the sim region? Since chunks are room-sized, and simulation is room-based, why not use the chunks directly?" "9352": "Wrap it up" "9393": "Anticipate HandmadeCon 2016" --- name: "day352" title: "Isolating the Camera Update Code" markers: "7": "Recap the career-switching side-streams" "206": "todo.txt: Consult the TODO list and set the stage for the day's programming" "736": "Run the game to remind ourselves of where we are" "879": "handmade_world_mode.cpp: Reacquaint ourselves with how the region simulation works" "1109": "handmade_sim_region.cpp: Reacquiant ourselves with how EndWorldChange() updates the camera" "1288": "A few words on dependency reduction and functional programming" "1474": "handmade_sim_region.cpp: Pull out the camera updating code from EndWorldChange() into a new UpdateCameraForEntityMovement() function" "1685": "Run the game to find that the camera no longer functions" "1703": "handmade_world_mode.cpp: Make UpdateAndRenderWorld() call UpdateCameraForEntityMovement()" "1891": "Run the game to find that the camera now follows the hero again" "1922": "handmade_sim_region.cpp: Reorganise the code and consider BeginWorldChange() and EndWorldChange()" "2010": "handmade_world_mode.h: Introduce game_camera struct and make the necessary functions use it" "2206": "handmade_world_mode.cpp: Prevent AddStandardRoom() from generating boost pads" "2266": "Run the game to find that we have the same functionality as before" "2280": "handmade_sim_region.cpp and handmade_world_mode.cpp: Make every function that uses the camera take game_camera" "2498": "A few words on supporting multiple-sized rooms" "2755": "handmade_sim_region.cpp and handmade_world_mode.cpp: Continue making functions take a world rather than game_mode_world" "3018": "handmade_world_mode.cpp: Isolate the CameraP computation from BeginSim()" "3761": "Run the game to find that everything appears to be working properly, but that the game is running faster" "3819": "handmade_world_mode.cpp: Consider preventing Simulate() from taking a game_mode_world" "3987": "handmade_entity.cpp: Consider preventing UpdateAndRenderEntities() from taking the TypicalFloorHeight" "4057": "handmade_world_mode.cpp: Temporarily make Simulate() take the TypicalFloorHeight and GameEntropy rather than a whole game_mode_world" "4223": "handmade_world.h: Make GameEntropy belong in the world struct" "4528": "handmade_world.h: Consider specifying rooms as entities" "4703": "handmade_entity.h and handmade_world_mode.cpp: Add EntityType_Room to the entity_type struct and change AddStandardRoom() to create rooms as entities" "5139": "handmade_entity.cpp: Re-enable UpdateAndRenderEntities() to do volume rendering debug visualisation" "5348": "handmade_render_group.cpp: Disable entity rendering and run the game to see the volume bounds more clearly" "5528": "handmade_particles.cpp: Re-enable UpdateAndRenderFire() to do the full particle effect" "5559": "handmade_world_mode.cpp: Enable AddStandardRoom() to make the added rooms encompass the shape that the room actually is" "5607": "handmade_entity.h: Remove the entity_type struct" "5653": "handmade_entity.cpp and handmade_world_mode.cpp: Disable rendering of traversables and addition of trees" "5764": "Run the game to see the bounding box of the room, and consider how to make rooms encompass their contained entities" "5894": "handmade_brain.h: Consider adding Type_brain_room to the brain_type struct" "6281": "handmade_brain.h: Add Type_brain_room to the brain_type struct" "6392": "handmade_world_mode.cpp and handmade_brain.h: Make AddStandardRoom() give the room a brain, and introduce SpecialBrain() and SpecialBrainSlot()" "6580": "Run the game to find that the brain system isn't broken" "6594": "handmade_sim_region.cpp: Enable UpdateCameraForEntityMovement() to determine which, if any, room we are in and move the camera accordingly" "7207": "Run the game to find that the camera fails to follow the hero" "7259": "Q&A" "7297": "1) Do you ever work on large (multimillion LOC) codebases like Chrome, GCC, Unreal, etc? The full build dev process you've been using works for small projects, but how do you scale?" "7522": "2) Why is past video archiving disabled?" "7573": "3) Are you in a closet? The back wall looks really close" "7579": "I don't know if unrelated questions are allowed, but how do you stay so focused on your programming and are so efficient?" "7761": "I think the speedup is due to wrong offsets of the simulation regions for the multithreaded tasks: you used tile size for your calculation, not chunk / room size" "7787": "Now that you intend to use 3D, will the code support software rendering?" "7803": "Is the career advice episode uploaded anywhere? I'm having trouble finding it" "7825": "You said you wanted to remove the notion of rooms / layers from the drawing routine, but don't you still need it for fading in the room above you?" "7888": "You said that 20 seconds to build is a reasonable amount of time? It's huge! 10 seconds is too much" "7989": "Off-topic: Will HandmadeCon 2016 VOD be on YouTube soon?" "8008": "How long did The Witness take to build?" "8115": "I would think it would take about 5-10 mins" "8149": "Wrap it up" --- name: "day353" title: "Simple RLE Compression" markers: "18": "Set the stage for the day" "70": "Blackboard: RLE vs LZ" "113": "Blackboard: On exploiting the properties of the data we want to compress" "356": "Blackboard: Run-length Encoding" "504": "Blackboard: Distinguishing between "literals" and "runs"" "599": "Blackboard: Various formats developed by Electronic Arts: IFF, ILBM, PCX" "713": "Blackboard: LZ (Lempel-Ziv) as a more heavy-duty form of compression" "963": "Blackboard: Encoding an additional offset in LZ" "1207": "Blackboard: How LZ gives you RLE almost for free" "1550": "Blackboard: Replicating blocks" "1948": "Blackboard: Why LZ schemes use relative positioning, and choosing how many bits to allocate for the look-back distance" "2346": "Blackboard: LZ encoding" "2690": "Blackboard: Keeping a hash table and information of overlapping runs for the back catalogue" "2808": "Blackboard: Entropy encoding and backends, e.g. Huffman, Arithmetic, rANS / tANS" "2992": "Blackboard: Charting the frequency of values" "3190": "Blackboard: Huffman" "3681": "Blackboard: On the inefficiency, size-wise, of Huffman compared to Arithmetic" "3752": ""Please take it with a grain of salt, or even a cube of salt"" "3807": "Blackboard: rANS / tANS" "4003": "Determine to compress our art assets" "4096": "Save test_scene_layer_00.bmp as a png and compress it with 7zip for comparison" "4269": "simple_compressor.cpp: Setup the code to make an actual command-line compressor" "4496": "Run the compressor and view the documentation" "4516": "simple_compressor.cpp: Parse the Args" "4666": "simple_compressor.cpp: Introduce file_contents struct for ReadEntireFileIntoMemory() to return" "4839": "simple_compressor.cpp: Set up the call sites for Compress() and Decompress()" "5333": "simple_compressor.cpp: Introduce Compress(), Decompress() and Copy()" "5558": "Run the compressor on test1.hha" "5700": "simple_compressor.cpp: Introduce RLECompress() and RLEDecompress()" "6181": "simple_compressor.cpp: Implement RLEDecompress()" "6332": "simple_compressor.cpp: Enable RLECompress() to encode a run" "6693": "Run the compressor in the debugger" "6798": "simple_compressor.cpp: Make RLECompress() and RLEDecompress() more symmetric" "6899": "Step in to RLECompress() and inspect the values" "7100": "simple_compressor.cpp: Make RLECompress() correctly loop to the MAX_RUN_COUNT and compute the OutSize" "7181": "Run the compressor on test1.hha to find that it has output exactly the same size" "7268": "simple_compressor.cpp: Make Compress() use the MaxOutSize value, run the compressor on test1.hha and find that the output is much smaller" "7335": "Run the decompressor on test1.scp to find that it doesn't work at all" "7376": "simple_compressor.cpp: Correctly store the InFile.FileSize" "7502": "Step in to the compressor and inspect what it does" "7624": "Step in to the decompressor to find that it works fine, and diff the files it produced" "7719": "Run the compressor on intro_art.hha to see how it fares with that" "7834": "Q&A" "7881": "Compress test1.hha and intro_art.hha with 7zip for comparison" "7958": "Awesome stuff! I hadn't been making the distinction between "literals" and "runs" in my thing. My test stuff has been just 0s and 1s, mind, so I was just storing the first Token and then the Counter values" "8054": "Tomorrow you will show us what again?" "8136": "Are hardware image decompressors still a thing?" "8574": "Conclude" --- name: "day354" title: "Simple LZ Compression" markers: "21": "Recap and set the stage for the day" "115": "simple_compressor.cpp: Look through the code and note the relative simplicity of the decompressor" "528": "simple_compressor.cpp: Introduce LZDecompress()" "659": "Blackboard: What CopyDistance refers to" "795": "simple_compressor.cpp: Simplify and empower LZDecompress()" "1284": "simple_compressor.cpp: Consider the respective trade-offs of LZDecompress() and RLEDecompress()" "1415": "simple_compressor.cpp: Introduce LZCompress(), in order first to do RLE with an LZ backend" "1880": "simple_compressor.cpp: Introduce a "test" command, which compresses and decompresses, and then tests that the output matches the original" "2063": "Step through LZCompress() and LZDecompress() and watch what they do" "2221": "Assess how effectively it compresses test1.hha and intro_art.hha" "2341": "simple_compressor.cpp: Enable LZCompress() to perform look-backs for actual LZ compression" "3038": "Run the compressor on test1.hha and assess its effectiveness" "3144": "simple_compressor.cpp: Make LZCompress() output runs under stricter conditions" "3249": "Consider the compressor's new effectiveness, run it on intro_art.hha and break briefly to get a drink" "3415": "Blackboard: Optimal Parse" "3624": "Blackboard: Parsing interleaved data" "3868": "Assess the compressor's effectiveness on intro_art.hha" "3914": "simple_compressor.cpp: Note some fun things we can do with this code to try and make it better" "4158": "simple_compressor.cpp: Introduce the ability to gather and output statistics" "4359": "simple_compressor.cpp: Define handlers for the compressors and decompressors" "4833": "Run the compressor on test1.hha, crash and step in to investigate what's happening" "4899": "simple_compressor.cpp: Fix up the documentation and typos" "4957": "simple_compressor.cpp: Output the supported compression algorithms and continue implementing statistic gathering" "5111": "simple_compressor.cpp: Introduce GetStatName(), PrintStats(), Percent() and Increment()" "5643": "simple_compressor.cpp: Enable RLECompress() to gather stats, and make it and LZCompress() flush the buffer if they are at the end" "5867": "Run the compressor and make RLECompress() encode runs more smartly" "6195": "simple_compressor.cpp: Call PrintStats()" "6279": "Run the compressor, crash and fix up Percent() and PrintStats()" "6339": "Run the RLE compressor on test1.hha and consult the statistics" "6395": "simple_compressor.cpp: Enable LZCompress() to gather statistics" "6486": "Run the LZ compressor on test1.hha and consult the statistics" "6607": "Q&A" "6711": "Amazing. I think I followed it, but definitely want to re-watch (during and after annotating)" "6724": "Forgive me if this information was somehow implicit in today's lecture and I missed it, but is compression ever used for locality wins?" "6763": "Do you know off-hand what kind of compression ratio and decompression speed are needed before it's faster to load compressed data and decompress, over loading decompressed data?" "6841": "inttypes.h and PRIu64 is probably what you are supposed to do for %llu for 64-bit printfs" "6878": "You still have to uncompress your images for display, right? So do you have plans for using block compression?" "6916": "Make data fit in cache" "7028": "Why is 255 not a good look back limit for images? You wanted to elaborate on that" "7067": "Blackboard: Choosing your look back window for image compression" "7162": "Have you ever heard of random seed data compression?" "7186": "Probably more of Jeff and Fabian's territory, but is there generally such a thing as a compressor that compresses a lot and fast? Would some RAD compressor leave 10% of initial size and be considerably faster than LZ? I guess BINK is hyperfast, isn't it like live decompression or something?" "7259": "I meant block compression that's GPU-supported (BC1-BC7). You upload the compressed image to the GPU, and hardware decodes it when sampled" "7423": "Close this off" --- name: "day355" title: "Clearing Out Pending GitHub Bugs" markers: "10": "Set the stage for clearing out pending GitHub bugs" "58": "ctray.cpp: Fix "enterring" typo" "137": "readme.txt: Update links to point to the new locations" "305": ""You never upgrade anything during the development of the game"" "430": "Determine to enable the game to compile without warnings or errors in VS 2015" "465": "simple_preprocessor.cpp: Make ParseMember() cast everything to int" "600": "On the two different versions of the CRT's maths routines" "702": "handmade_intrinsics.h: Make AbsoluteValue() call fabsf()" "736": "handmade_platform.h: Determine to enable AlignPow2() to compile without warning" "1014": "handmade_platform.h: Make AlignPow2() add (Value-Value) to force integral promotion to the size of Value" "1117": "handmade_entity.cpp: Make DEBUGPickEntity() cast Entity->ID.Value to a umm before converting to pointer" "1169": "win32_handmade.cpp: Make WinMain() cast the GlobalBackbuffer values to u32" "1193": "Fix many "hides function parameter" and "hides previous local declaration" warnings" "2030": "Close that issue and request help for the CLANG compatibility issue" "2232": "Determine to reduce the PeekMessage latency" "2291": "On message queues and how Windows implements theirs" "2617": "On PeekMessage()" "2856": "win32_handmade.cpp: Enable Win32ProcessPendingMessages() to make PeekMessage() circumvent WM_PAINT and WM_MOUSEMOVE" "3103": "Run the game to see that it all still works and close that issue" "3234": "Determine to fix the PushClipRect and glScissor issue" "3270": "win32_handmade.cpp: Pass a lower resolution to Win32ResizeDIBSection() and run the game to see that we're in bad shape" "3385": "On food and feeding the world" "3588": "win32_handmade.cpp: Switch to the software renderer and run the game to determine that the problem is only in the hardware renderer" "3668": "Compare the code for the software and hardware renderers" "3992": "Run the game in windowed mode, and resize it to exhibit the bug" "4143": "Consult the glScissor documentation" "4199": "Consult the glViewPort documentation and endeavour to understand the difference between the renderers" "4883": "Run the game and eyeball how the cliprect is scaling" "5104": "handmade_opengl.cpp: Determine to enable OpenGLRenderCommands() to perform the glScissor() in the correct space" "5263": "Blackboard: glScissor coords" "5343": "Blackboard: Normalized device coordinates" "5462": "Blackboard: Calculating our correct glScissor coordinates" "5610": "handmade_opengl.cpp: Enable OpenGLRenderCommands() to correctly scale the region passed to glScissor()" "5992": "Run the game to see that the hardware renderer's cliprect is now correct, and close that issue" "6126": "handmade_render.cpp: Enable DrawRectangle() to AND the StartClipMask and EndClipMask together for rectangles <= 3 pixels wide" "6482": "handmade_entity.cpp: Toggle off rendering of Traversables, run the game and see the effects of the DrawRectangle() change" "6755": "handmade_render.cpp: Change DrawRectangle() to test == 4" "6857": "Recompile and run to see that the drawing of narrow rectangles is now correct" "6910": "handmade_render.cpp: Consider removing the ClipMask from DrawRectangleQuickly(), before closing the issue with it still intact" "7105": "Reflect on the day's work" "7138": "Q&A" "7151": "It's rolled over 'round these parts already so Happy New 2017, everyone" "7175": "In the compression code there is an assert(LiteralCount == 0) it seems to fire on some files, should the literal buffer be flushed after the loop in case it didn't end on a run?" "7255": "simple_compressor.cpp: Enable RLECompress() and LZCompress() to correctly flush the literal buffer" "7386": "Are you going to consider resizing the debug display for lower display resolutions, or would that not really be worthwhile since it's not part of the final game?" "7670": "A wee bit off-topic, but have you ever considered setting up a green screen / chromakey for your stream?" "7729": "What are your 2017 resolutions for Handmade Hero?" "7762": "Shouldn't the cliprect only be rescaled at the same point that the offset is done? Only the main buffer should have it" "7836": "No high production values? Stream looks good and there's a frame around the scare-cam and a nice little fade-in timer. That seems like more effort than a lot of what I see" "7954": "So that black box is a window, not just an overlay in OBS?" "8044": "Please consider demonstrating NVidia's cmdlist extension as a way of thinking about modern graphics dev" "8110": "Close it down with a glimpse into 2017" --- name: "day356" title: "Making the Debug System CLANG Compatible" markers: "31": "Set the stage for the day with a few words on compiling for multiple platforms" "200": "Determine to make the debug system compatible with CLANG" "348": "handmade_debug_interface.h: Explain the RecordDebugEvent() and DEBUG_NAME macros" "539": "Describe our problem and demo string concatenation" "846": "Consult the GCC documentation (see Resouces, GCC Manual)" "892": "handmade.cpp: Demo the difference between GCC's and Visual Studio's implementations of string concatenation" "1048": "Consider how to workaround the problem" "1567": "Consider adding support for constant string concatenation to CLANG" "1624": "handmade_debug.cpp: Reacquaint ourselves with the code" "1713": "4coder feature request: A standard way to send a platform message to 4coder in order to jump to a file at a given line" "1876": "handmade_debug.interface.h: Consider having two versions of UniqueFileCounterString__()" "2065": "handmade_debug_interface.h: Add Name to the debug_event struct and make BEGIN_BLOCK and END_BLOCK take it" "2506": "handmade_debug.cpp: Change DebugParseName() to take a ProperName" "2734": "handmade_debug_interface.h: Make the TIMED_BLOCK macros take a Name" "2812": "Run the game to see what that produces" "2927": "Step through DebugParseName() and inspect what it does" "3031": "handmade_debug.cpp: Make GetElementFromEvent() set a Name rather than NameStartsAt" "3168": "handmade_debug.cpp: Make DEBUGInit() set the Name" "3244": "Run the game and see what we're recording" "3294": "handmade_debug_interface.h: Ensure that everyone is passing the correct information down" "3450": "Inspect the assembly for the debug system during the cutscene rendering" "3767": "Step through GetElementFromEvent() and StoreEvent() to see what they do" "3947": "handmade_debug.cpp: Make DEBUGEventToText() use our newly passed Name and run the game to see what it produces" "4061": "Determine that we've solved our problem and close the issue" "4282": "Run the game and assess our situation" "4368": "Determine to fix the camera tracking" "4503": "Step into UpdateCameraForEntityMovement() and investigate why the player is never being found by EntityOverlapsRectangle()" "5027": "handmade_sim_region.cpp: Make UpdateCameraForEntityMovement() test on IsInRectangle() rather than EntityOverlapsRectangle()" "5292": "Step into UpdateCameraForEntityMovement() and receive a positive result" "5386": "handmade_sim_region.cpp: Make UpdateCameraForEntityMovement() record the RoomDelta differently" "5570": "Run the game and find that the camera is incorrectly positioned" "5615": "handmade_sim_region.cpp: Make UpdateCameraForEntityMovement() correctly set the RoomRelP, run the game and find that it's having trouble snapping back" "5688": "handmade_sim_region.cpp: Change UpdateCameraForEntityMovement() to snap to the room centers" "5822": "Run the game and find that the camera snaps correctly" "5853": "handmade_sim_region.cpp: Enable UpdateCameraForEntityMovement() to interpolate between camera positions" "5909": "Run the game to see that it correctly interpolates between camera positions" "5934": "Consider supporting differently sized rooms" "5990": "handmade_world_mode.cpp: Make AddStandardRoom() take RadiusX and RadiusY in order to create variably sized rooms" "6493": "Run the game to see that we're creating rooms as we were doing" "6518": "handmade_world_mode.cpp: Enable AddStandardRoom() to align the rooms and support different radii" "6787": "Run the game to see what that does" "6816": "handmade_world_mode.cpp: Try changing the sizes of the rooms" "6908": "Run the game to find that we have different sized rooms" "6971": "handmade_world_mode.cpp: Enable AddStandardRoom() to know the sizes of abutting rooms" "7112": "Run the game to see our variably sized rooms and consider making the camera zoom to correctly frame the rooms" "7166": "Q&A" "7229": "Hey Casey, is anyone planning on doing a more boiled down version of Handmade Hero, to take apart the game and give a breakdown of the aspect of each system in the project?" "7273": "Or make the camera pan within the room?" "7293": "Long time archive viewer, but first time live streamer! I have two pre-stream questions but I can never make the pre-stream time. 1) Do you have a strong opinion about why int *p is "superior style" than int* p, or are you impartial to whatever the developer prefers?" "7332": "Demo: Pointer declaration style" "7480": "2) Do compiler optimisations (-O2) guarantee that the same output is generated for time-independent code? That is, does the out-of-order processing ever introduce some nasty logic / contol flow bugs that -Od wouldn't?" "7681": "You said you didn't want to use PRETTY_FUNCTION because that wouldn't work because of duplicate GUIDs. But the only place where PRETTY_FUNCTION would have been used is in TIMED_FUNCTION, which should never be used more then once in any function anyway. So not using DEBUG_NAME in TIMED_FUNCTION would solve the problem. All the other calls to TIMED_BLOCK_ would still work with DEBUG_NAME and thus use the COUNTER to be unique. So I think the extra field for the Name is really not necessary." "7735": "You talked about GCC / CLANG at the start. To be clear, you will be dropping visual studio at some point?" "7783": "What is your opinion on Minkowski Portal Refinement for collision detection and response? I feel it is much nicer as it gives you much of the collision information (normal, depth, etc.) without having to implement an entire separate algorithm like GJK does" "7826": "Have you tried -Ox for optimizations? I believe it gives even faster code (it's a fast hand for multiple optimization flags, I believe)" "7956": "I would like to cast my vote that we should do the slides some day" "7977": "How long do you think it will take for JAI to take over the C++ space in the game industry? It's not even out yet and I can already say that language is the best thing ever designed" "8094": "Are you using SDL? If not and, assuming the answer isn't just "everything needs to be hand-made", is there another reason? What are your thoughts in general on SDL?" "8270": "I guess what I was really asking was will you be dropping it?" "8342": "Do you have any thoughts on when to use multiple threads? Is the answer any more in depth than "when single-threaded isn't fast enough"?" "8486": "Do you still have a TODO list like you used to? Could you show it? I'm still on Day 110 with the videos" "8511": "Wrap it up" --- name: "day357" title: "Room-based Camera Zoom" markers: "9": "Promote Handmade.Network's new "Submit a Project" functionality" "119": "A few words on "Handmade" and the projects currently in the Network" "403": "Promote the Handmade.Network Forums" "464": "Consult the issues and determine to fix the CLANG compatibility" "652": "On ending macros with __VA_ARGS__" "744": "handmade_debug_interface.h: Prevent the TIMED_FUNCTION() macro from taking __VA_ARGS__, and the TIMED_BLOCK() ones from taking Number" "910": "Run the game to see everything running properly, and comment on the issue" "1044": "Consider working on the camera code" "1397": "Illustrate how the camera system is currently working" "1533": "handmade_entity.h: Introduce CameraHeight variable" "1635": "handmade_sim_region.cpp: Enable UpdateCameraForEntityMovement() to offset Z based on CameraHeight" "1679": "handmade_world_mode.cpp: Enable AddStandardRoom() to compute the CameraHeight based on the room proportions" "1817": "Run the game to see that it's already sort of working" "1979": "Blackboard: Room Camera Fitting" "2260": "Blackboard: Computing the camera's viewing distance" "2505": "Blackboard: Solving for the desired distance" "2763": "handmade_render_group.cpp: Explain Uproject()" "2895": "handmade_render_group.cpp: Introduce FitCameraDistanceToRectangle()" "3082": "Blackboard: Focal length" "3378": "handmade_render_group.cpp: Introduce FitCameraDistanceToDimension()" "3557": "handmade_render_group.cpp: Rename both FitCameraDistanceToRectangle() and FitCameraDistanceToDimension() to FitCameraDistanceToHalfDim(), one which returns a v2 and calls the other twice" "3686": "handmade_render_group.h: Consider removing DistanceAboveTarget from the camera_transform struct" "3916": "handmade_render_group.h: Replace DistanceAboveTarget in the camera_transform struct with a v3 CameraP" "3985": "handmade_render_group.cpp and handmade_world_mode.cpp: Change all necessary functions to use this CameraP" "4298": "handmade_entity.cpp: Make UpdateAndRenderEntities() set the CameraP" "4415": "handmade_world_mode.cpp: Make AddStandardRoom() manually offset the CameraHeight by 11, run the game and consider our problems" "4606": "handmade_world_mode.cpp: Consider what UpdateAndRenderWorld() is doing" "4815": "handmade_particles.cpp: Remove CameraP entirely from the particle pipeline, run the game and see our restored particles" "4908": "handmade_entity.cpp: Make UpdateAndRenderEntities() correctly compute CameraRelativeGroundZ, run the game and see our entities restored" "5046": "handmade_world_mode.cpp: Make AddStandardRoom() create an entity_collision_volume_group RoomCollision" "5215": "handmade_world_mode.cpp: #define TileSideInMeters" "5381": "Run the game and see that the bound properly encompasses the room" "5479": "handmade_sim_region.cpp: Enable UpdateCameraForEntityMovement() to set the Camera->Offset differently" "5663": "Run the game and consider camera centering" "5846": "handmade_sim_region.cpp: Add assertion in UpdateCameraForEntityMovement() that we are InRoom, run the game and do not hit that assertion" "6023": "handmade_sim_region.cpp: Consider the impact of the changeover coinciding with the time the sim region moves between blocks" "6258": "handmade_sim_region.cpp: Prevent UpdateCameraForEntityMovement() from setting the Offset, run the game and crash in the debug system" "6331": "handmade_debug.cpp: Look at GetElementFromEvent()" "6426": "handmade_sim_region.cpp: Document the assumption that the camera center be the sim region center" "6478": "Run the game and consider the camera displacement" "6759": "handmade_world_mode.cpp: Make UpdateAndRenderWorld() draw a rectangle around the sim region, run the game and find that it is not lined up with the room" "7021": "Step through BeginWorldChange() and inspect the SimRegion dimensions" "7091": "Step through UpdateCameraForEntityMovement() and inspect the room entity's P" "7169": "handmade_world_mode.cpp: Make UpdateAndRenderWorld() reduce the Z offset for the debug rectangles" "7242": "handmade_render_group.cpp: Consider the possibility that GetRenderEntityBasisP() is computing a bogus HeightOffFloor" "7297": "Q&A" "7339": "Hi! For how long is this bliss of weekend episodes gonna continue? Got any news in the making for us?" "7431": "You didn't answer about the news, though" "7459": "Q: A bit off-topic, but why do you use your headphone mic rather than the nice studio mic you have on the Jeff and Casey show?" "7528": "The camera doesn't seem to be centered perfectly. Working as intended?" "7546": "Could you disable the Y displacement to test your theory?" "7602": "Started following the series on YouTube, and have made it to episode 14. Loving it so far. When I try to build solution in VS, I am unable to do so unless I put the #defines and typedefs into every file. Is this a VS thing or am I doing it wrong? Sorry for going way back" "7990": "Promote Handmade.Network and the new "Submit a Project" functionality" "8466": "That's it for today" --- name: "day358" title: "Introduction to Depth Buffers" markers: "36": "Promote Handmade.Network's new "Submit a Project" functionality" "200": "Determine to fully finish the CLANG compatibility" "263": "handmade_debug_interface.h: Cast the __FUNCTION__ to a char * in the TIMED_FUNCTION() macro, and close the issue" "371": "A few words on compiler differences" "482": "On engine programming and the licensing of the code" "568": "Blackboard: 3D Update" "726": "Blackboard: On the distastefulness of 2D regarding sorting and perspective" "855": "Blackboard: Call the 2D renderer a failed experiment" "890": "Run the game to take a look at what we've already got" "996": "Blackboard: Surgery and engaging more with the 3D API, including shaders" "1301": "Blackboard: Sorting and overdraw" "1551": "Blackboard: On how sorting primitives becomes problematic" "1710": "Blackboard: Z-buffer or "Depth" buffer" "1939": "Blackboard: On the screen being a buffer to which we write RGBA values" "2145": "Blackboard: Augmenting the pixel data to include depth and stencil values" "2325": "Blackboard: Old Pixel Fill, Take #1" "2417": "Blackboard: Old Pixel Fill, Take #2" "2542": "Blackboard: New Pixel Fill, with the augmented pixel data" "2893": "Blackboard: "Pass" Comparisons before Blend" "3039": "Blackboard: Per-pixel sorting and order independence" "3284": "Blackboard: Stencil" "3580": "Blackboard: Caveat Emperor: Blend is not order independent for transparency" "4061": "Blackboard: Changing the blend equation to be order independent" "4226": "Blackboard: Framebuffer Atomics and Per-pixel Sorting" "4582": "Blackboard: Partitioning opaque and transparent objects" "4790": "Blackboard: Overdraw Still Matters!" "5087": "Blackboard: Z Prepass" "5320": "Blackboard: On the potential wasteage of GPU wide operations" "5498": "Q&A" "5512": "Is it possible to use dithering (and possibly post-processing and super-resolution) for order independent transparency?" "5523": "Blackboard: Screen door effect" "5634": "Per-pixel sorting on the graphics card. What, if any, software control is available via shaders, or is this just a hardware optimization that some graphics cards do behind the scenes to handle the opacity issue without a pre-filtered Z-buffer?" "5660": "Blackboard: The point of atomics" "5872": "What do you think of frame buffering like Vulkan's mailbox present mode to decouple the game update rate from the display device's refresh rate? You can render as many frames as you want, but only the most recently rendered frame is swapped in on vertical retrace" "6232": "Is it valid to render to sub-buffers and then render those sub-buffers to the back buffer so as to be able to render more than one sub-buffer at a time?" "6471": "Do you feel you're still on the path to finishing the game in 600-ish episodes?" "6629": "Do you find the weekends go by faster with streaming on them? And you have more time for 1935?" "6651": "What if I want my game to be deterministic, or what if my game does physics calculations and I need to update at a fixed rate for stability. Different people have different monitors with different refresh rates. Most people seem to then interpolate but this adds latency. Isn't mailboxing the better approach in this situation?" "6747": "Skip this if you'd like / explained it already: Could you explain Z-fighting and solving it as a problem?" "6790": "Wrap it up" --- name: "day359" title: "OpenGL Projection Matrices Revisited" markers: "3": "Recap and set the stage for the day" "265": "A few words on what "stepping through GPU code" entails" "539": "Run the game to see our 2D pipeline running, and determine to remove the screen-space transform" "613": "handmade_render_group.cpp: Look at how GetRenderEntityBasisP() transforms the world coordinates into screen coordinates" "770": "handmade_opengl.cpp: Look at how OpenGLSetScreenSpace() works and fits into the pipeline" "826": ""We're going to go over that in very excruciating detail in a moment"" "972": "Blackboard: Projection Matrix" "1183": "On "column major" vs "row major", and defining an array in C or C++" "1369": "Blackboard: What our projection matrix is doing" "1468": "Blackboard: Homogeneous matrix" "1556": "Blackboard: Matrix multiply" "1804": "Blackboard: |xyz1| == point; |xyz0| == vector" "2052": "Blackboard: More on what our "projection" matrix is doing" "2275": "Blackboard: Why OpenGL operates in a -1 to 1 space" "2341": "Blackboard: Clipping" "2540": "Illustrate "texture warping"" "2583": "Blackboard: On the necessity for correct sub-pixel fill and texture coordinate picking" "2785": "Blackboard: How OpenGL handles its coordinates system: bilateral unit cube" "2929": ""As is the rule on Handmade Hero: I never get to do any preparation"" "3015": "Blackboard: Transforming from "clip space" to "window space"" "3236": "Consult the OpenGL 2.0 specification" "3323": "Blackboard: Fix up the terminology in accordance with the OpenGL spec" "3481": "Blackboard: Perspective projection" "3632": "Blackboard: Projecting to the screen using a relationship of similar triangles" "3757": "Blackboard: Matrix multiplication doesn't allow for dividing" "3914": "Blackboard: How OpenGL provides for one divide operation, normalisation of the vector by its w coordinate, in order to compute correct perspective" "4080": "Blackboard: Implementing our own perspective projection and why we compute z" "4211": "Double-check the OpenGL spec on coordinate transformations" "4383": "Blackboard: Performing the near plane clipping before moving into the -1 to 1 space" "4593": "Blackboard: Recap what our perspective transform must accomplish" "4770": "Blackboard: The Z-buffer and near and far clip planes" "4916": "Further reading: W-buffer; infinite far clip plane; disable far clip plane" "5026": "Blackboard: Camera space, and getting the effects we want out of the projection matrix" "5207": "handmade_render_group.cpp: Consider how our perspective transform is currently happening" "5404": "handmade_opengl.cpp: Temporarily make OpenGLSetScreenSpace() calculate the height dimension based on the width and run the game to see what that does" "5474": "handmade_render_group.cpp: Prevent GetRenderEntityBasisP() from adding CameraTransform->ScreenCenter to the Perspective computation, and run the game to see what that has done" "5543": "handmade_opengl.cpp: Shuffle the projection matrix initialised in OpenGLSetScreenspace(), and run the game to see that our transform is correct, but the sorting is not" "5632": "handmade_render_group.cpp: Consider what the MetersToPixels value is contributing to GetRenderEntityBasisP()" "5807": "Blackboard: How MetersToPixels passes through the pipeline" "6080": "handmade_render.h: Consider how to simplify MetersToPixels" "6134": "handmade_opengl.cpp: Make OpenGLSetScreenspace() compute the Width and Height more simply" "6214": "handmade_render.h: Prevent GetStandardCameraParams() from taking WidthInPixels into account in the MetersToPixels computation, and run the game" "6269": "handmade_render.h: Remove WidthOfMonitor from the camera_params struct and rename MetersToPixels to WorldScale" "6431": "handmade_render_group.cpp: Consider simplifying the ProjectedXY computation" "6525": "handmade_render_group.h: Remove the render_entry_coordinate_system struct" "6590": "handmade_render_group.h: Make the entity_basis_p_result struct contain a 3D coordinate, and propagate that change" "6981": "Run the game with everything being passed down as 3D, and consider how we'll proceed" "7071": "Q&A" "7107": "Concerning the "homogeneous" use. The "homogeneous" word indeed comes from mathematics. Homogeneous is used for mathematical objects that have some scalability property. Here, p0 = (x, y, z, 1) and p1 = (2x, 2y, 2z, 2) represent the same point in space (but p1 = 2 * p0 mathematically speaking). Therefore the usage of homogeneous coordinates and homogeneous matrices here" "7203": "Turn off the sorting so we won't have flashing" "7318": "handmade_render.cpp: Temporarily make SortEntries() set ShouldSort to false and run the game to see how that affects it" "7400": "Debug UI is broken?" "7525": "I was reading the article from Fabian about his optimizations on the Intel software renderer and I saw him doing the clipping in a very simple manner in screenspace, where he takes the min / max between the pixel and screen dimensions because he was using orient2d and barycentric coordinates to rasterize. The clipping was only four lines of code and easy to understand. Why does OpenGL have to do complicated homogeneous clipping?" "7678": "In practice, does the camera near plane and the camera focal length really differ? I would expect them to be the same" "7837": "Are we going to continue supporting the software renderer in 3D as well?" "7867": "If I set the near clip plane to, say, 10, does that mean that entities with a world space Z less than 10 would be clipped? Just trying to make sure that near / far clip planes are defined in terms of world space" "8015": "Can you use the GPU to bypass the OpenGL or DirectX API / pipeline and just use compute shaders to implement your own pipeline that's also running on the GPU?" "8211": "So, to avoid Z fighting, should we have dynamical near / far planes? I mean that their values should change according to the nearest and the farthest objects we want to render in order for the near / far plane space to be as small as possible?" "8570": "Does any of that clip and projection math change if we change the rendering technique that we're using? Say, rasterizing vs raytracing or voxels" "8800": "Close out" --- name: "day360" title: "Moving the Perspective Divide to OpenGL" markers: "1": "Recap and set the stage for the day" "78": "Run the game and demo our current situation with the sorting" "122": "Reacquaint ourselves with our work moving the perspective operations over to OpenGL" "420": "handmade_render.h: Remove WorldScale from the camera_params struct, and consider removing MetersToPixels and PixelsToMeters globally" "746": "handmade_render_group.h: Replace ScreenCenter in camera_transform with ScreenDim" "808": "handmade_render_group.h: Introduce SetCameraTransform() and simplify Orthographic() and Perspective()" "830": ""This would take a super set of the parameters"" "984": "Run the game to see that we're at the wrong zoom level" "1005": "handmade_world_mode.cpp: Make AddStandardRoom() set the camera height lower, and run the game" "1054": "Determine to fix the debug visualisation rectangles" "1155": "handmade_render_group.h: Remove MonitorHalfDimInMeters from the render_group struct" "1347": "handmade_render_group.cpp: Remove UnprojectOld() and make GetCameraRectangleAtDistance() compute the correct rectangle" "1623": "handmade_world_mode.cpp: Make UpdateAndRenderWorld() compute WorldCameraRect and ScreenBounds" "1765": "Run the game pnd fail to see the debug rectangles" "1856": "Step in to UpdateAndRenderWorld() and inspect the bounds" "2325": "handmade_render_group.cpp: Make Unproject() correctly compute the UnprojectedXY" "2604": "Step into UpdateAndRenderWorld() and inspect the WorldCameraRect" "2665": "A few words on easing the process of changing your code" "2836": "Run the game and determine to get the Z-sorting working by augmenting the ClipRect to be about transforms in general" "3174": "handmade_opengl.cpp: Start to change OpenGLSetScreenSpace()" "3356": "handmade_platform.h: #define NotImplemented()" "3658": "Blackboard: Projection coordinates" "3888": "handmade_opengl.cpp: Prevent OpenGLRenderCommands() from scaling the incoming dimensions" "3908": "Run the game and consider the incoming dimensions" "4055": "Blackboard: Z in the Projection Matrix and normalising by W" "4432": "Blackboard: Divide by incoming Z" "4592": "handmade_opengl.cpp: Write the Proj matrix in OpenGLRenderCommands() to enable the divide by Z" "4711": "handmade_render_group.cpp: Make GetRenderEntityBasisP() compute the correct Scale and P" "4797": "Run the game to see it unexpectedly working, and investigate why" "5118": "Step in to OpenGLRenderCommands() and inspect the values" "5222": "handmade_opengl.cpp: Make OpenGLRenderCommands() pass the Z for the bitmaps, and run the game" "5292": "handmade_render_group.cpp: Remove Basis.Scale from all functions, and remove the entity_basis_p_result struct" "5449": "handmade_render_group.cpp: Simplify GetRenderEntityBasisP()" "5600": "Run the game to assess our current situation" "5715": "handmade_render_group.h: Add FocalLength to the render_entry_cliprect struct and propagate it" "6018": "Run the game and consider cleaning this up" "6056": "handmade_render_group.h: Remove ScreenDim from the camera_transform struct and add CurrentClipRect_ to the render_group struct" "6404": "Remove all of the sorting code" "7051": "Q&A" "7156": "Can you please go double-check your matrix math in your last drawing in Milton?" "7268": "More scroll right-ish" "7297": "No, I'm just blind" "7327": "Are you planning on making a video featuring everything you made?" "7405": "What do you have in mind when it comes to shaders? You plan to use them to sort?" "7576": "How long till ship?" "7616": "I'm running out of excuses to clean the garage, so... someone ask something long" "7631": "Could you expand on the topic of refactoring (sometimes all the code)? I use git, to move on but keep my old code. So I think I'm scared of changing things" "8342": "I keep missing the pre-stream, so at what time tomorrow will it start?" "8400": "How often do you clean your garage? If you don't have a garage, where do you park your car? If you don't have a car, how do you get to Kansas?" "8564": "I wonder if Jon and Casey are in the same city" "8590": "Close it down with a glimpse into the future" "8694": "Plug Asaf's annotation searcher" "8856": "Yeah, we will roll it into the new annotation system. Planning on working on the new system probably in a month from now, after HMN v1 is settled" "8896": "Thank Asaf for building the annotation searcher" --- name: "day361" title: "Introduction to 3D Rotation Matrices" markers: "7": "Recap and set the stage for the day" "117": "Run the game to demo the current state, with a few words on moving towards a more direct streaming approach" "318": "handmade_platform.h: Remove the sort data from game_render_commands" "599": "handmade_opengl.cpp: Make OpenGLRenderCommands() correctly push textures" "850": "handmade_render_group.cpp: Make PushClipRect() call PushRenderElement()" "1001": "handmade_opengl.cpp: Enable OpenGLRenderCommands() to handle the cliprect case, and run the game to see it working" "1153": "todo.txt: Update the TODO list with a few words on making a freely rotatable camera" "1480": "Blackboard: Rotation Matrices" "1842": "Blackboard: Deriving a Rotation Matrix" "2185": "Blackboard: 3D Rotation Matrices" "2418": "Blackboard: 2D vs 3D Axes of Rotation" "2636": "Blackboard: Coordinate system handedness" "3045": "Blackboard: Rotating in 3D around the cardinal Z axis" "3508": "Blackboard: Generalising this to the other axes" "4243": "Blackboard: Solving for a freely movable camera, using matrix multiplication" "5000": "Blackboard: Matrix multiplication in summation notation" "5277": "handmade_math.h: Introduce operator*() that operates on a 4x4 matrix" "5827": "Blackboard: Determining the shape of the matrix product" "5963": "Blackboard: Transforming points" "6099": "handmade_math.h: Introduce Identity(), XRotation(), YRotation() and ZRotation()" "6484": "handmade_math.h: Introduce Transpose()" "6501": "Blackboard: Matrix Transpose" "6635": "handmade_math.h: Introduce Projection()" "6829": "handmade_opengl.cpp: Make OpenGLRenderCommands() project and transpose our matrix" "6932": "Step into OpenGLRenderCommands() and inspect the projection matrix" "7000": "handmade_math.h: Make our new operator*() and Transpose() loop over all the values" "7034": "Step into OpenGLRenderCommands() again to see the transpose working correctly" "7108": "Q&A" "7164": "You once said that people don't really use matrices as the storage in real world things. Can you talk about the alternatives?" "7361": "Will we use quaternions? Producing rotation matrix from quaternions seems a good idea" "7389": "So from now on, you will only be streaming on Saturday and Sunday?" "7399": "Would it be worth investing time doing a SIMD optimization for matrix multiplication, or is it like killing ants with a rifle?" "7465": "Are you going to use simpler rotation functions that are mainly focused on smaller matrices such as your 4x4, then emphasizing another method on much larger matrices?" "7494": "Is it worth having code for producing a full rotation matrix (x, y and z) at once instead of multiplying three different matrices?" "7583": "I'm inferring that those braces encompassing the four rows in those matrix operations aren't doing anything? (It isn't creating an extra dimension in the matrix?)" "7688": "Hi Casey, haven't caught a stream in a while. How are things going?" "7749": "Don't you have to return a value in the multiplication function?" "7893": "Q: Casey, might be worth pointing out that that behavior in MSVC is specific to inline functions" "8001": "I kind of just joined on to this channel. Sorry about the lack of the knowledge of the code so far, but I was referring to the case of having such large matrices that you would consider partitioning the matrices into separate parts for quicker rotations" "8221": "Would it not be better to make the matrix struct use an r32 array of 16 elements instead of a two dimensional one? In that should we SIMD the math operation?" "8350": "Forgive the dumb question, but why are your include guards defined at the bottom of the header instead of the top? Is this purely what you chose to do, or is there another purpose? (#if is checked at the top, but the #define is at the bottom. Most code I've seen does it at the top)" "8507": "Sorry, Casey, I am still looking at older streams. I guess you may have changed that already" "8578": "Get going with a glimpse into the future" --- name: "day362" title: "Matrix Multiplication and Transform Order" markers: "8": "Recap and set the stage for the day" "148": "Run the game to show where we're at with randomly ordered drawing" "354": "Blackboard: Matrix Multiplication" "540": "Blackboard: Order dependence" "829": "Blackboard: Scaling matrix" "936": "Blackboard: Rotation matrix, and why order dependence is important for us" "1293": "Blackboard: Matrix- and vector-multiplication are exactly the same thing" "1518": "Blackboard: Multiplication order of a long series of matrices" "1709": "Blackboard: Translation and 4x4 augmentation" "2250": "Blackboard: Object Transform, conceiving of the matrix in columns" "2587": "Blackboard: Camera Transform, conceiving of the matrix in rows" "2974": "Blackboard: Row vs Column Picture" "3225": "Blackboard: What is a camera transform and why does this do it?" "3603": "Blackboard: Camera translation" "3690": "Blackboard: Moving the world to align with the camera's axes" "3941": "Blackboard: Inner product" "4077": "Blackboard: Dot producting incoming points with the camera axes" "4188": "Blackboard: Rows are Camera axes; Columns are Object axes" "4371": "Blackboard: For an orthogonal matrix, the inverse is the transpose" "4640": "Blackboard: The camera transforms we want to implement" "5120": "Blackboard: Combining translation and rotation in camera transforms" "5552": "handmade_math.h: Introduce CameraTransform(), Columns3x3(), Rows3x3() and Translate()" "5883": "handmade_math.h: Introduce Transform() and an overloaded operator*() which takes a 4x4 matrix and a vector of length 3" "6233": "handmade_math.h: Introduce GetColumn() and GetRow()" "6349": "handmade_opengl.cpp: Consider how to implement our camera transform" "6442": "handmade_render_group.cpp: Make PushClipRect() responsible for computing the focal length" "6597": "Run the game to see the same thing we got before" "6707": "Q&A" "6783": "Can you interpolate if you wanted a smooth rotation about a point or axis over time?" "6875": "There have been some problems with trolls causing flame wars in the chat. I forget who you dedicated the management of the chat to?" "6946": "You mentioned (about six months ago, I think) that you have new art work. What's the plan with adding that?" "6976": "Did you know beforehand that you where going to discard the sorting code? Did you do all that for the sake of teaching a variety of techniques?" "7158": "Do you know anything about DirectX 12?" "7266": "When are you gonna do OOP?" "7324": "Ever heard of design patterns?" "7345": "Try unit testing your code so we can actually see if something is working" "7444": "Will the Molly Rocket team be at Emerald City Comicon this year?" "7451": "In terms of profiling, how would you tell when you are hitting upper bounds of CPU, PCI Bus and GPU? Obviously, we already have a CPU profiler, wondering more about PCI Bus and GPU" "7557": "Will you use Vulkan in your game at all, will it still be too new on release, or do some kind of tutorial on it?" "7668": "Do you think writing my own ring 0 driver would bypass VAC?" "7787": "Is there any way to do that from our own code, or do we have to rely on external tools?" "7938": "Near the beginning of the stream the back of my chair fell off. I spent the entire stream fixing my chair. It feels more solid now and squeaks less but I'm afraid to lean back on it?" "7975": "Not sure if anyone has mentioned this but Mac OSX doesn't support OpenGL core profile with OpenGL 1.x functions. This means that, if using glBegin etc, the maximum version of GL allowed is 2.1" "8084": "Can you name one of those exploits for my driver?" "8302": "Can you give Shawn M & Sean B's stream a plug before you go please?" "8360": "Plug Shawn, Sean and Jon's streams" "8451": "Would ring 0 driver bypass the anti cheat protection of Destiny" "8539": "Sean and Shawn are doing a specific stream today" "8584": "How do I read the RAM memory on an XBox or PS4?" "8864": "I'm not sure if anyone has mentioned this but in the cutscene shot 6, layer 3 and 4 are both at z=3.0f. Layer 3 should be at z-3.01f instead. Layer 4 is the child's tears and layer 3 is the child" "9025": "Will the order of matrix multiplication be reversed if we use transposed matrices and vectors?" "9064": "Blackboard: Multiplying a matrix and a vector" "9303": "Yes, that's what I was asking. Earlier in the video you said that matrix application order is unintuitive, and this way we can reverse the order" "9534": "Wrap it up" --- name: "day363" title: "Making an Orbiting Debug Camera" markers: "8": "Recap and set the stage for the day" "47": ""It's always very bad to forget your water bottle"" "141": "Run the game to see the current camera, and consider unifying the camera and clip rect operations" "283": "handmade_render_group.cpp: Put the PushClipRect() functions together" "387": "Consider the cleanliness of the 3D pipeline" "632": "handmade_entity.cpp: Prevent UpdateAndRenderEntites() from taking DrawBuffer and make it set the AlphaFloorClipRect with PushRenderTarget()" "742": "handmade_render_group.cpp: Introduce PushRenderTarget()" "783": "handmade_render_group.cpp: Prevent PushClipRect() from taking RenderTargetIndex and rename the main PushClipRect() to PushSetup()" "915": "handmade_render_group.h: Change the render_group struct to store an m4x4 LastProj and LastRenderTarget" "1037": "handmade_render_group.cpp: Make PushSetup() set the render_group values, and implement PushRenderTarget()" "1194": "handmade_render_group.cpp: Make SetCameraTransform() take the m4x4 CameraTransform and conditionally call Orthographic() and Projection()" "1427": "handmade_render_group.cpp: Simplify GetRenderEntityBasisP()" "1566": "handmade_render_group.cpp: Consider the need to invert the projection matrix in Unproject(), and clean up compile errors" "1771": "handmade_render_group.cpp: Remove Perspective() and Orthographic()" "1881": "handmade_entity.cpp: Simplify and prevent UpdateAndRenderEntities() from computing the Z for the fog" "2343": "handmade_render_group.cpp: Enable UpdateAndRenderWorld() to perform perspective projections using SetCameraTransform()" "2551": "handmade_math.h: Implement PerspectiveProjection() and OrthographicProjection()" "2678": "Step into UpdateAndRenderWorld() and inspect the camera-related values" "2900": "Fantastic auto-update" "2958": "Continue stepping through UpdateAndRenderEntities()" "3349": "Step through OpenGLRenderCommands()" "3403": "handmade_opengl.cpp: Prevent OpenGLRenderCommands() from setting a cliprect for a render_entry_cliprect" "3543": "Continue stepping through OpenGLRenderCommands()" "3654": "Investigate why the W is being set to a negative value" "3867": "Continue stepping through OpenGLRenderCommands() and inspect the XAxis and YAxis" "4025": "handmade_math.h: PerspectiveProjection() near and far clip plane" "4170": "Research how OpenGL wants the perspective projection matrix to be set up" "4711": "handmade_math.h: Make PerspectiveProjection() set up the matrix as per the diagram" "4924": "handmade_render_group.cpp: Prevent GetRenderEntityBasisP() from negating the Z coordinate" "5030": "Blackboard: Z Inversion" "5202": "Run the game to see that we're getting closer to reasonable" "5445": "Blackboard: Conceptualising rotation around an axis" "5528": "handmade_world_mode.cpp: Enable UpdateAndRenderWorld() to rotate the camera around X" "5627": "Run the game to see the tilted world" "5662": "Blackboard: Tilting the camera" "5703": "handmade_world_mode.cpp: Negate that CameraD computation, with a few words on understanding what's happening" "5806": "handmade_world_mode.cpp: Double-check what this transform is doing, and add a Z rotation" "5874": "Run the game and consider increasing the focal length" "5912": "Blackboard: Moving the camera to maintain focus on the same point" "6034": "handmade_world_mode.cpp: Make UpdateAndRenderWorld() factor in that counter-rotation" "6097": "Blackboard: Camera counter-rotation" "6216": "Step into UpdateAndRenderWorld() and inspect what it's doing" "6280": "handmade_world_mode.cpp: Enable UpdateAndRenderWorld() to set the rotations from the mouse position" "6566": "Run the game to try moving the camera and consider introducing a moveable debug camera" "6771": "handmade_render_group.cpp: Add LastUserProj to the render_group struct" "6938": "handmade_world_mode.cpp: Enable UpdateAndRenderWorld() to zoom the camera" "7036": "Run the game and try zooming" "7072": "A few words on zooming at a speed proportional to the distance to the target with this poor man's differential equation" "7296": "Q&A" "7327": "Sorry for being a dummy: In the camera transform in 3D games (as far as I've been watching tutorials), there's something called an "Up" vector. What's the purpose of it and do we have it in Handmade Hero? Since it's a 2D game I guess it's different. Your explanations have been wonderful and I would love it if you could explain it. And also thanks for doing EU friendly streams Kappa" "7424": "Blackboard: Object- vs Camera Transform" "7618": "Blackboard: Up Vector" "7777": "Blackboard: Constructing a camera transform without already having the camera object itself" "8296": "Blackboard: "Sense of Up" vector" "8600": "Blackboard: Look-at matrix / camera equations" "8676": "Wow, that was amazing, thanks a lot!" "8687": "Would it be weird to change the focal length as the pitch changes or should the focal length always stay constant?" "8747": "Minor point, you called your variables pitch and orbit: Should probably be pitch and yaw" "8782": "Wrap it up" --- name: "day364" title: "Enabling the OpenGL Depth Buffer" markers: "92": "Run the game, recap and set the stage for the day" "295": "Blackboard: Using the Z-buffer to sort ground tiles" "395": "Blackboard: Slanting the upright sprites to make them occlude each other properly" "835": "Run the game and illustrate why this scheme will be important for debugging purposes" "848": ""We're going to write some code and hope that it's right"" "896": "Determine to turn on the Z-buffer" "936": "handmade_opengl.cpp: Make OpenGLRenderCommands() enable GL_DEPTH_TEST and call glDepthMask() and glColorMask()" "1300": "win32_handmade.cpp: Make Win32SetPixelFormat() set cDepthBits" "1500": "win32_handmade.cpp: Make Win32SetPixelFormat() specify the colour bits" "1719": "Run the game, see nothing on the screen and investigate why" "1764": "handmade_opengl.cpp: Make OpenGLRenderCommands() pass GL_DEPTH_BUFFER_BIT to glClear()" "1916": "Run the game to see that we're getting Z-tested drawing" "1962": "Blackboard: Preventing fully transparent pixels from entering the Z-buffer" "2185": "handmade_opengl.cpp: Make OpenGLRenderCommands() enable and call glAlphaFunc()" "2304": "handmade_opengl.cpp: Temporarily make glAlphaFunc() operate for alpha values greater than 0" "2344": "Blackboard: No blending if sprites happen to be drawn in the wrong order" "2526": "handmade_opengl.cpp: Make OpenGLRenderCommands() call glDepthFunc()" "2599": "Run the game to see that the drawing order is being respected, but that the sort is unstable" "2765": "Determine to process the Z-values" "3046": "Blackboard: Near and Far Clip (Planes)" "3230": "Blackboard: Mapping the Z-values in the correct direction to the -1 to 1 range" "3387": "Blackboard: Determining the structure of the mapping function" "3548": "Blackboard: Solve these equations for a and b" "3731": "Blackboard: Verify these equations" "4129": "Blackboard: Solve the equations again, passing in the correct values" "4664": "handmade_math.h: Make PerspectiveProjection() compute d and e to pass to the matrix" "4742": "Run the game to see the finer grained Z-fighting" "4803": "handmade_render_group.cpp: Enable PushBitmap() to increase the sprites' height relative to their Z" "4972": "Run the game to see the slanted sprites, and consider why we must take the camera into account for shearing" "5103": "handmade_render_group.cpp: Make PushBitmap() also modify the sprites' Y and X values" "5241": "Consider using the camera's relative position to compute these modifications" "5328": "Q&A" "5360": "When adjusting the sprite like that, don't you need to interpolate the texture coordinates in screenspace instead of clipspace (the default)?" "5429": "What is Alpha to Coverage? Any good references on that?" "5508": "Would an orthogonal projection matrix be applicable for your game?" "5539": "Is the -n and -f because OpenGL has the camera on the negative -z?" "5586": "Why are you using legacy OpenGL?" "5689": "Do you typically use an infinite far plane for increased precision? Shawn McGrath mentioned it in his stream awhile back" "5780": "Would it be simpler to use Orthographic transforms for upright objects? Are you not simply undoing the Perspective Projection there?" "5848": "Would it be possible to use a shader to do the Z-buffer rendering?" "6017": "So the near and far plane are linearly mapped. I have read somewhere where the mapping is not linear, in which case do we not make them linear?" "6193": "Blackboard: Accounting for the -z in our coefficients" "6495": "Consult the OpenGL spec" "6744": "Oh yeah, sorry, I mixed two things up" "6754": "Blackboard: Computing a and b, accounting for the -z" "7350": "handmade_math.h: Try to make PerspectiveProjection() compute the non-perspective corrected terms for orthographic" "7523": "End it there" --- name: "day365" title: "Adjusting Sprite Cards to Counter Projection" markers: "2": "Recap and set the stage for the day" "67": "handmade_math.h: Make PerspectiveProjection() set the near clip plane to a positive value and perform some test multiplications" "238": "Step into PerspectiveProjection() and inspect Test0 and Test1" "402": "Blackboard: Check our clip plane equations" "749": "handmade_math.h: Swap the perspective and non-perspective code in PerspectiveProjection(), step into it and inspect Test0 and Test1 again" "1002": "Blackboard: Solving for d and e" "1324": "handmade_math.h: Make PerspectiveProjection() compute Test0 and Test1 using negated n and f, step into it and inspect them again" "1417": "handmade_math.h: Switch PerspectiveProjection() to use the perspective correct equation, step in and inspect the Test0 and Test1" "1482": "Blackboard: Checking the math for the perspective correct terms" "2012": "handmade_math.h: Simplify the d term for the perspective correct equation" "2083": "Blackboard: Solving for d and e in the perspective correct clip plane equations" "2331": "handmade_platform.h: Rename w to __ in the v3 union" "2448": "Step into PerspectiveProjection() and inspect Test0 and Test1" "2526": "Run the game to see that we're back in business" "2610": "handmade_render_group.cpp: Make PushBitmap() tilt upright sprites and run the game" "2680": "Reflect on our unwitting correctness" "2847": "Blackboard: Sprite Cards" "3084": "Run the game to demo the squatness of the trees" "3221": "Blackboard: Producing the sprites' depth and height using the camera's relative position" "3318": ""Watch this point"" "3554": "Blackboard: Approaching this problem using ray intersections" "3788": "Blackboard: Solving for ray intersects ray" "4142": "Blackboard: Simplifying this down" "4376": "Blackboard: Handling the case when the vectors are parallel" "4813": "Blackboard: Determining the conditions under which this equation is unsolvable" "5009": "handmade_math.h: Introduce RayIntersect2()" "5221": "Blackboard: Producing a ta that goes with the same denominator" "5983": "handmade_math.h: Make RayIntersect2() compute ta and tb using the same denominator" "6201": "Try to solve our equations using an online tool" "6487": "handmade_render_group.cpp: Make PushBitmap() compute and call RayIntersect2() on the camera and card positions" "6862": "handmade_render_group.h: Add CameraP, CameraX, CameraY and CameraZ to the render_group struct" "7076": "handmade_render_group.cpp: Make SetCameraTransform() take the Camera position values" "7277": "Run the game to see that it is not nearly as messed up as expected" "7327": "Q&A" "7389": "There was a lot of chat about Wolfram expecting 1-letter variable names and interpreting rbx as r * b * x" "7403": "Didn't we do this math when doing the screen projection?" "7452": "Do you think we needed an epilepsy warning there?" "7484": "Hello, yesterday I was asking about shaders and the z-buffer. Could I rephrase the question? It will be the last time" "7500": "Maybe if you swap the order of the sum on 'tb = ...' you get an equation more similar to 'ta = ...'?" "7526": "handmade_math.h: Try swapping the order of the sum in RayIntersect2()" "7563": "Can you show again the equation?" "7631": "Is the stream weekends only now or is it temp thing?" "7651": "1935 is Molly Rocket's upcoming volitional fiction game, set in the criminal underworld of New York City in the 1930s" "7657": "As Handmade Hero is a 2D game, my idea would be to treat the z variable not as the z coordinate but as a variable that the pixel shader will use to kill hidden pixels and do alpha blending with the GPU power" "7828": "Are you doing this so you can mix perspective projection and orthographic projection for game objects?" "7891": "Now we have the alpha issue with the 3D stuff, is this easier to fix than the 2D sort because you already know how to fix that?" "8012": "This could be the solutiun at least for Matlab: [ta = -(Pax*rby - Pay*rbx - Pbx*rby + Pby*rbx)/(rax*rby - ray*rbx), tb = -(Pax*ray - Pay*rax - Pbx*ray + Pby*rax)/(rax*rby - ray*rbx)]" "8277": "handmade_render_group.cpp: Make PushBitmap() use CardRyz to set the YAxis" "8304": "Run the game to see that we're surprisingly good" "8401": "It seems like vaualbus' solution is negated in relation to yours" "8594": "handmade_render_group.cpp: Enable PushBitmap() to produce a standard sprite card and run the game to see that" "8714": "handmade_opengl.cpp: Temporarily make OpenGLRenderCommands() clip out all transparent pixels, and run the game" "8867": "Consider addressing transparency in the sort, and close it down" --- name: "day366" title: "Adding Cubes to the Renderer" markers: "8": "Recap and set the stage for the day" "88": "Run the game to demo the trees always facing the camera" "313": "Blackboard: Camera-Facing Cards" "577": "Blackboard: Talking about X/Y planes in camera space" "666": "handmade_render_group.cpp: Show the PushBitmap() code which maps the world space positions into camera space" "721": "Run the game to demo the camera tilt, and consider sorting and the concept of a debug camera" "917": "handmade_render_group.h: Introduce camera_transform_flag to aid implementing a debug camera" "1063": "handmade_world_mode.cpp: Enable UpdateAndRenderWorld() to call SetCameraTransform() twice with different arguments" "1433": "Run the game to try toggling between the two cameras, and consider how to handle sprite cards intersecting" "2008": "Blackboard: Introducing a cube primitive" "2303": "handmade_render_group.h: Introduce render_entry_cube struct" "2471": "handmade_render_group.cpp: Introduce PushCube() and remove RendersInBackground" "2819": "Run the game and see that nothing has happened" "2945": "Investigate where we're placing the hero, and why tweaking the P.Offset_.z causes it to fail" "3393": "Determine that we're not doing the room sizing stuff correctly" "3529": "handmade_entity.cpp: Enable UpdateAndRenderEntities() to call PushCube() for the traversables" "3943": "handmade_world_mode.cpp: Introduce an AddPiece() that takes a Height and translates it to a V2" "4013": "handmade_world_mode.cpp: Make AddStandardRoom() call AddPiece() for the traversables" "4286": "handmade_opengl.cpp: Enable OpenGLRenderCommands() to handle the cube case" "4402": "Blackboard: Mr. Cube" "4589": "handmade_opengl.cpp: Enumerate the eight faces for the cube" "4790": "Blackboard: Specifying the points for triangles in a counter-clockwise fashion" "4879": "handmade_opengl.cpp: Introduce GLQuad()" "5001": "Blackboard: Winding, and backface culling" "5169": "handmade_opengl.cpp: Specify the eight faces of the cube for OpenGLRenderCommands() to pass to GLQuad()" "5621": "handmade_opengl.cpp: Enable OpenGLRenderCommands() to generate the cube points" "5772": "Run the game to see our first cube" "5808": "handmade_entity.cpp: Make UpdateAndRenderEntities() pass the offset to PushCube() and run the game to see all the cubes" "5971": "handmade_world_mode.cpp: Make AddStandardRoom() reduce the variance of the traversable position offsets and run the game to check it out" "6061": "handmade_opengl.cpp: Set the cubes' colour to white, give them a texture and run the game to check it out" "6220": "Demo the case in which a tree and a cube interpenetrate and Z-fight, and consider how to combat this" "6471": "handmade_render_group.cpp: Re-enable PushBitmap() to perform shearing, and run the game" "6605": "Q&A" "6685": "Any particular reason for using counter clockwise for front faces (as opposed to clockwise)?" "6720": "Blackboard: Coordinate system right-handedness and counter-clockwise winding" "6983": "A debug camera pan control might be a good idea" "6995": "Why have everything slightly tilted? Wouldn't it make more sense to sort the assets according to their bottom or, if you're using 3D space, go for an orthogonal camera and using the Z position for sorting?" "7029": "Run the game to demo the visual interest of the tilting" "7288": "Recommend Andrew Russell's blog on the sorting in River City Ransom" "7601": "I noticed the camera in Handmade Hero is defined by Camera X, Y, Z and P. Can I get X, Y and Z from a Quaternion? Is that a good idea? I mean, if you had Quaternions on Handmade Hero would you define the camera using a Quaternion and P?" "7698": "What is the 'x' in b32x and u32x?" "7721": "Blackboard: "Exactly n bits" vs "At least n bits"" "8027": "How much time and effort do you spend preparing for each episode (e.g. what you're going to do, and which problems you foresee running into)? Or is it just the years of experience that allow you to do this without preparation?" "8068": "Why b32x and not b1x or b8x? (I really don't know)" "8146": "Q: Can you do cubic splines sometime?" "8220": "Close it down" --- name: "day367" title: "Enabling OpenGL Multisampling" markers: "3": "Recap and set the stage for the day" "144": "Run the game to demo the Z-fighting and fringing that we need to eliminate" "291": "Consider switching to a different computer with a newer graphics card" "410": "Determine to enable multisampled antialiasing" "474": "handmade_opengl.cpp: Disable the cube texturing and colour the sides of the cubes in a gradient" "767": "Run the game to see our visually parsable cubes" "1144": "Run the game to see our green cubes" "1158": "Blackboard: Fake Cube Lighting" "1553": "Run the game to illustrate areas requiring better lighting" "1733": "Blackboard: MSAA (Multisample Antialiasing) + ATC (Alpha to Coverage)" "1804": "Blackboard: Aliasing and Apparent Error in Discretizing" "2065": "Blackboard: Our current implementation of antialiasing" "2250": "Blackboard: Multisample antialiasing on graphics cards" "2649": "Blackboard: Typical MSAA pipeline in GPU APIs" "2942": "Blackboard: Alpha to Coverage" "3043": "Blackboard: Where are the samples?" "3355": "Blackboard: Alpha to Coverage continued" "3440": "Research OpenGL's specification alpha to coverage" "3929": "Research glSampleCoverage" "4096": "handmade_opengl.cpp: Make OpenGLRenderCommands() enable GL_SAMPLE_ALPHA_TO_COVERAGE, GL_SAMPLE_ALPHA_TO_ONE and GL_MULTISAMPLE" "4232": "Blackboard: Screen Door Transparency" "4317": "Research how to set up a buffer suitable for multisampling" "5017": "A few words on GPU programming" "5201": "handmade_opengl.cpp: Make OpenGLRenderCommands() call glTexImage2DMultisample()" "5647": "handmade_opengl.cpp: Set up for multisampling, based on glcorearb.h" "6140": "Step in to OpenGLRenderCommands() to find that our graphics card may not support multisampling" "6646": "handmade_opengl.cpp: Make OpenGLRenderCommands() pass MaxSampleCount - 1 to glTexImage2DMultisample(), and step in to find that we have 8x multisampling, but that it is not working properly" "7294": "handmade_opengl.cpp: Try passing MaxSampleCount to glTexImage2DMultisample(), and run the game to find that it works" "7350": "Q&A" "7407": "Can you check if the status has changed after updating bind texture?" "7433": "Did you remember to prefix your glTexImageMultisample2D with a WINAPI) (aka __stdcall prefix)? That's usually the cause of access violations for me" "7520": "win32_handmade.cpp: Make Win32InitOpenGL call glTexImage2DMultisample()" "7597": "Your glTexParameteri needs to use GL_TEXTURE_2D_MULTISAMPLE instead of GL_TEXTURE_2D" "7716": "Is there a way to debug or have a visual example of the multisampling process?" "7743": "Maybe we should use glDebugMessageCallback and glEnable(GL_DEBUG_SYNCHRONOUS) sometime, then we can assert in the callback and are able to see just where we gl error in the debugger" "7807": "You mentioned in a previous episode that one of the reasons for moving to 3D was due to performance concerns with the sorting. Would it have been a viable alternative to keep the sorting results in permanent storage and then each frame only re-sort the entities that have moved? Just considering that many entities like trees and traversables don't move" "7949": "Casey, I have started working on Handmade Vulkan port earlier today, is that okay? I got it to initialize properly and have done some groundwork for outputting rects. My current plan is to work on it this week" "8133": "So Alpha to Coverage does order-independent transparency just like that? Any serious limitations you can think of?" "8270": "For those of us who are very interested in engine development, what are some of the more advanced platform features that you would recommend investigating?" "8417": ""The only reason that we ever did it is because Won insisted that we do it"" "8486": "On the platform side like any debugging features, you mentioned a while ago that 1935's engine was light years ahead in that it is far more advanced" "8691": ""Problem exists between Khronos and Casey"?" "8719": "Close everything down with a glimpse into the future" --- name: "day368" title: "Compiling and Linking Shaders in OpenGL" markers: "8": "Recap and set the stage for the day" "246": "Attend to the "Getting max allowed samples for texture correctly" issue" "376": ""Martins is almost always right"" "420": "handmade_opengl.cpp: #define GL_MAX_COLOR_TEXTURE_SAMPLES and GL_MAX_DEPTH_TEXTURE_SAMPLES for OpenGLRenderCommands() to use" "564": "handmade_opengl.cpp: Drawing to the framebuffer and why we must call glBlitFramebuffer() to do a multisample resolve" "732": "Research glBlitFramebuffer()" "859": "Research how to do the multisample resolve" "948": "handmade_opengl.cpp: Enable OpenGLRenderCommands() to bind the framebuffer and perform the multisample resolve" "1228": "handmade_opengl.cpp: #define GL_READ_FRAMEBUFFER and GL_DRAW_FRAMEBUFFER from the corearb.h" "1273": "win32_handmade.cpp: typedef gl_blit_framebuffer" "1407": "Run the game to see that it just worked" "1429": "handmade_opengl.cpp: Re-enable the Z-buffer in OpenGLRenderCommands()" "1772": "Consider which Image Format to use" "2005": "Run the game to see that we have a depth buffer and multisample antialiasing, but that our colours are wrong" "2201": "handmade_opengl.cpp: Make OpenGLRenderCommands() correctly iterate over the render targets" "2277": "Determine that we are unable to set sRGB texture rendering on this graphics card" "2361": "win32_handmade.cpp: Prevent Win32SetPixelFormat() from setting the depth bits" "2492": "Run the game to see that the depth buffering is still working just fine" "2541": "Why we did the multisample" "2704": "View the cutscene and note that the projection and sRGB are incorrect" "2812": "Blackboard: Our rendering pipeline" "3260": "Blackboard: Using a Z-bias to cheat the values passed to the depth buffer" "3521": "Blackboard: Object placement matrix" "3658": "handmade_render_group.h: Add a ZBias to render_entry_bitmap" "3789": "Run the game to see disastrous results and explain why" "3864": "handmade_render_group.cpp: Make PushBitmap() set the ZBias and run the game to see everybody sucked out to infinity and beyond" "3925": "handmade_render_group.cpp: Make PushBitmap() compute the ZBias in proportion to the Height" "3967": "A few introductory words on shaders" "4172": "Creating shaders in OpenGL" "4377": "handmade_opengl.cpp Remove OpenGLSetScreenspace()" "4402": "handmade_opengl.cpp: Introduce OpenGLCreateProgram() in conjunction with docs.GL" "4891": "Summarise the shader creation process" "4972": "win32_handmade.cpp: Bind the shader functions we need" "5567": "Compile and run to see our crazy w coordinate" "5636": "Create handmade_opengl.h" "5778": "handmade_opengl.cpp: Make OpenGLInit() call OpenGLCreateProgram(), and write here docs for Header, Vertex and Fragment code" "6117": "Run the game to find that we got through the compilation phase okay, and determine to enable OpenGLCreateProgram() to perform error handling" "6261": "handmade_opengl.cpp: Enable OpenGLCreateProgram() to log shader info and assert on validation failure" "6803": "Compile and step into OpenGLCreateProgram() to see that we pass shader validation" "6906": "Q&A" "6913": "Cam died" "6965": "For some of the OpenGL function typedefs, you have the WINAPI entrypoint and others don't. I thought it was necessary to have it or else you get run-time errors when calling those functions (or at least I did)" "7033": "Instead of Z-bias, why not make the sprite cards stand up at a steeper angle, and make them trapezoidal to undo the perspective foreshortening?" "7094": "When you started writing the placeholder shader code you mentioned something about “C++ ??? docs” that are not yet fully implemented. What is this feature exactly?" "7296": "Do you think the Google's angle library (that translates OpenGL to DirectX calls) would solve the sRGB problem on your graphics card?" "7344": "Why are you downsizing 8 pixels into one using blit and not using 32 bit math and rendering 6 back into 2 with a subtract to finalize 8? 2 pass out of 8 bit back to render allows alpha on/off values and colour value attach. ( A|C| instead of colour value) where alpha belongs in blit, define each pixel" "7404": "You can pass NULL as the length param to glShaderSource and it treats all the strings as null terminated" "7415": "handmade_opengl.cpp: Make OpenGLCreateProgram() pass NULL to glShaderSource()" "7484": "Can't we just adjust gamma in the shaders?" "7527": "Regarding checking shaders status. Believe best practice is checking GL_COMPILE_STATUS after compiling a shader and then GL_LINK_STATUS after linking a program" "7585": "Are you eventually going to move shader code into the asset packs, or are you going to keep it inline?" "7605": "Won't there still be problems if a tree is in front of a tall block, if the sprite still technically intersects the tile above?" "7684": "Will you implement shader "hotloading"?" "7801": "Hotloading seems safest with the use of BindAttribLocation, correct, so as not to have to chase locations all over the place?" "7846": "Last time I was here you talked about the int32x types. What are your thoughts on type space vs cache utilization?" "7937": "If you recreate the program when hot reloading, you should probably free the old shaders and program" "8032": "Are those programs cleared automatically when the game exits?" "8083": "Do you have opinions about Temporal AA?" "8092": "I assume that you dont give much thought to how hot data is? I remember a talk by Andrei that you could get a few percent speed up just from organizing the data according to hotness" "8224": ""Unless there is a bug in the driver or in Windows..." Yeah, there are never any bugs in those" "8294": "Will you eventually be doing such a pass over Handmade Hero?" "8312": "Should you add a \n at the end of each line with the format you are using? Wouldn't it be parsed by OpenGL as a long comment as it is now?" "8384": "Hey Casey, I got a job as a gameplay programmer! Wouldn't have happened without this stream, not in a million years" "8423": "A few words on gameplay programming" "8557": "Wrap the rest of the stream up with well wishes for starchypancakes" --- name: "day369" title: "Introduction to Vertex and Fragment Shaders" markers: "1": "Recap and set the stage for the day" "141": "Blackboard: Shaders" "202": "Blackboard: How hardware does pixel processing vs how we did it in software with SIMD" "458": "Blackboard: Processing a 4x4 square of 16 pixels at a time, also called "warp"" "656": "Blackboard: Writing a pixel shader, with the understanding that everything operates on many pixels at once" "955": "Blackboard: Leveraging the capabilities of the hardware" "1189": "Blackboard: An example illustrating the need to understand the ramifications of operating wide" "1490": ""You're going down"" "1647": "Blackboard: "Fragment" shader" "1815": "Blackboard: "Vertex" shader" "2016": "handmade_opengl.cpp: Make OpenGLCreateProgram() check GL_LINK_STATUS and GL_COMPILE_STATUS rather than GL_VALIDATE_STATUS" "2148": "Run the game and successfully receive compile errors" "2168": "Note that Martins pointed out that multiline strings are supported in Visual Studio 2013" "2377": "handmade_opengl.cpp: Introduce VertexCode and FragmentCode here docs in OpenGLInit()" "2469": "Research the Core Language (GLSL) versioning" "2646": "handmade_opengl.cpp: Set #version 130 in HeaderCode and run the game" "2673": "The OpenGL Shading Language 1.50 Quick Reference Card" "3049": "handmade_opengl.cpp: Sketch out a shader in VertexCode" "3200": "The Built-in Inputs, Outputs and Constants" "3382": "handmade_opengl.cpp: Enable the VertexCode to take the Transform, using a uniform" "3459": "handmade_opengl.cpp: Start to enable OpenGLRenderCommands() to pass Transform to the shader" "3592": "Blackboard: How the shader compiler references a uniform" "3767": "handmade_opengl.h: Add GLSLTransformID to open_gl" "3819": "handmade_opengl.cpp: Start to sketch out a shader in FragmentCode in conjunction with the OpenGL Shading Language 1.50 Quick Reference Card" "3986": "Note that there is no colour value in the fragment language's gl_FragDepth" "4137": "handmade_opengl.cpp: Continue sketching out the FragmentCode" "4203": "handmade_opengl.cpp: Enable OpenGLRenderCommands() to setup a uniform matrix using glUniformMatrix4()" "4411": "handmade_opengl.cpp: Make OpenGLRenderCommands() call glUseProgram() in order to actually run the shader" "4499": "win32_handmade.cpp: Pull glGetUniformLocation(), glUniform4fv() and glUniformMatrix4fv() from glcorearb.h" "4742": "handmade_opengl.cpp: Correctly declare main() in the shader code and run" "4879": "Read about glGetProgram()" "4902": "handmade_opengl.cpp: Make OpenGLCreateProgram() only check GL_LINK_STATUS and run the game to see that it works" "4948": "handmade_opengl.cpp: Make VertexCode set the InputVertex.w to 1.0 and run the game to see that the vertex shader is running" "5012": "handmade_opengl.cpp: Enable VertexCode to perform a ZTransform" "5151": "Run the game to see that we're getting the biasing we want" "5192": "handmade_opengl.cpp: Rewrite the VertexCode more instructively" "5321": "Run the game and reiterate what the VertexCode is doing, with a few words on its efficiency" "5417": "handmade_opengl.cpp: Determine to enable FragmentCode to operate on textures" "5625": "Blackboard: Variables in the fragment shader: "flat", "noperspective" and "smooth"" "5876": "handmade_opengl.cpp: Enable the FragmentCode to sample from textures, using a uniform" "6099": "Run the game and unexpectedly receive no error" "6110": "handmade_opengl.cpp: Enable VertexCode to pass FragUV and FragColor out to the FragmentCode" "6303": "Run the game" "6308": "handmade_opengl.cpp: Make VertexCode correctly set FragUV using gl_TexCoord[0].xy" "6471": "Run the game in the belief that we're passing down everything we need" "6531": "handmade_opengl.cpp: Make OpenGLRenderCommands() set a TextureSamplerID to pass to the FragmentCode shader" "6773": "Research glUniform" "6854": "win32_handmade.cpp: Pull glUniformli() from glcorearb.h" "6977": "Q&A" "7018": "Fuss with OBS" "7185": "Check your global settings" "7277": "Maybe just have one scene? So it can't switch" "7328": "Now that we've gone OpenGL, do you still think the RaspberryPi option is still on the list?" "7379": "Would you show us the code for what you have done in the last 2-4 minutes?" "7396": "handmade_opengl.cpp: Recap the FragmentCode here doc, and setting the TextureSamplerID" "7582": "gl_TexCoord is an output from the vertex shader, which is why everything is black, you should use gl_MultiTexCoord0 (no brackets)" "7600": "handmade_opengl.cpp: Make the VertexCode use gl_MultiTexCoord0 to specify the FragUV, and run the game to see that it works" "7629": "handmade_opengl.cpp: Remove the setting of TexSample.a to 1.0 from the FragmentCode, and run the game to see what we expect to get" "7752": "Are you receiving the Qs from HMN IRC/#hero? Your usual invocation of !qa didn't appear there today" "7781": "You mentioned the new assets will not be rectangular like the current assets. Do we need to update the asset pipeline for this?" "7862": "Are we completely dropping support for the software renderer now?" "7896": "I mean the hero head vs body vs cape are all the same shape" "7919": "Can you explain with a little bit more detail about how the Z-bias thing works? I'm not sure I understand it" "7932": "Blackboard: How the Z-bias prevents sprites from intersecting" "8281": "So we are going to implement some form of Z-buffer in software?" "8299": "The key part for me was that the Z is only used for the ZBuffer and the W does the perspective divide, thanks" "8360": "Go ahead and close it down with the determination to upgrade the graphics card" --- name: "day370" title: "Shader Fallback sRGB" markers: "4": "Introduce our special guest, donated by quartertron: owlbot" "91": ""He kinda has a USB butt"" "282": "Run the game to recap with a few words on supporting sRGB" "538": "handmade_opengl.h: Consider adding sRGBSupport to the open_gl struct" "688": "win32_handmade.cpp: Try setting WGL_CONTEXT_MAJOR_VERSION_ARB to 4, run the game and find that we don't get a context" "822": "handmade_opengl.cpp: Enable OpenGLInit() to call glTexImage2DMultisample() in order to check whether we support sRGB" "1018": "Consult docs.GL to see if we can call glDeleteTextures()" "1066": "handmade_opengl.cpp: Continue making OpenGLInit() check support for and enable an sRGB framebuffer" "1554": "Run the game and see that it's working" "1578": "Blackboard: sRGB conversions" "1832": "handmade_opengl.cpp: Enable OpenGLInit() to perform atomic tests on the sRGB conversions" "2286": "handmade_render.cpp: Look at how DrawRectangleQuickly() performs the sRGB conversions" "2482": "handmade_opengl.cpp: Enable the shader's FragmentCode to perform the sRGB conversion" "2567": "Consult the The OpenGL Shading Language 1.50 Quick Reference Card to see how to do the sqrt" "2588": "handmade_opengl.cpp: Fix errors in OpenGLInit()" "2619": "Run the game and note that our sprite colours are sRGB correct but that the other colours are not" "2914": "handmade_opengl.cpp: Note that the rendering code contains duplication, and consider changing the format in which we submit textures" "3084": "handmade_render_group.h: Introduce textured_vertex and render_entry_textured_quads structs" "3363": "Blackboard: nVidia allows us to use a texture pointer in shaders" "3495": "handmade_render_group.h: Spec out the render_entry_textured_quads struct" "3591": "Blackboard: CPU vs GPU memory and mapping regions between them" "3925": "Blackboard: Using locked memory to facilitate GPU transfers" "4105": "handmade_render_group.h: Continue to spec out render_entry_textured_quads" "4288": "handmade_opengl.cpp: Enable OpenGLRenderCommands() to process textured quads" "4658": "handmade_opengl.cpp: Enable OpenGLRenderCommands() to specify the glColor4ub" "4929": "handmade_opengl.cpp: Try sending GL_QUADS and run the game to see that it's fine" "5015": "A few words on texture atlases" "5087": "handmade_opengl.cpp: Determine to feed some sprites to OpenGLRenderCommands()" "5165": "handmade_platform.h: Make RenderCommandsStruct() take a VertexArray and consider how to write our loaded bitmaps out" "5366": ""It's high allergy season here, folks, and I'm a snotty boy"" "5372": "handmade_render_group.h: Add CurrentQuads to the render_group struct and introduce Begin" "5483": "handmade_render_group.cpp: Make PushBitmap() blow out the bitmap data inline" "5772": "Check out the commotion" "5835": ""It might be a protest, or it might be a parade of some kind"" "5931": "Live police & fire scanner" "6011": "handmade_render_group.cpp: Continue working on PushBitmap()" "6258": "handmade_math.h: Introduce BGRAUnpack4x8(), BGRAPack4x8(), RGBAUnpack4x8() and RGBAPack4x8()" "6333": "handmade_render_group.cpp: Enable PushBitmap() to pack the color" "6425": "handmade_platform.h: Make RenderCommandsStruct() take a VertexCount" "6487": "handmade_render_group.cpp: Enable PushBitmap() to write out the vertices and the render entry for the quads" "6830": "Run the game to see that it is not exactly a stunning success, and investigate why we're not seeing the textures" "6945": "Step in to OpenGLRenderCommands() and inspect the Bitmap and Vertex values" "7001": "handmade_math.h: Make PushBitmap() multiply by 255 before passing the PremulColor to RGBAPack4x8()" "7049": "Run the game to see some pretty good texture stretching" "7062": "handmade_render_group.cpp: Make PushBitmap() set the axes correctly, and run the game to admire it" "7099": "Q&A" "7120": "Emulating sRGB texture loads and sRGB fragment writes is not enough: sRGB also affects blending, which you can't emulate" "7267": "Do you have a licence for all those cubes?" "7277": "What texture will you use for rects and cubes?" "7312": "Is it worth testing sRGB and MSAA in the non-OpenGL compatibility mode?" "7387": "Will you be using more than one ShaderProgram? If so, how do you minimize switching between programs when rendering?" "7460": "You could unset it and just see if the assert will fail?" "7518": "win32_handmade.cpp: Research WGL_CONTEXT_PROFILE_MASK_ARB and specify the CORE_PROFILE in Win32OpenGLAttribs" "7569": "Run the game and see that it unexpectedly works, then step through OpenGLInit() to see that it still errors out" "7675": "Are you passing a major / minor version too? I think the bit might not be enabled sub 3.2?" "7776": "Wind this down with the promise of a question for insofaras and a mention of daylight savings time" --- name: "day371" title: "OpenGL Vertex Arrays" markers: "4": "Recap and set the stage for the day" "94": "Run the game and note that the sprites are all being submitted separately" "261": "handmade_render_group.cpp: Enable PushBitmap() to append new textured quads to the CurrentQuads array" "787": "Run the game to see where we were before" "801": "handmade_render_group.cpp: Enable PushBitmap() to push the quads on in a coherent way" "989": "Run the game and step in to OpenGLRenderCommands() to inspect the QuadCount" "1145": "handmade_render_group.cpp: Introduce GetCurrentQuads()" "1490": "handmade_render_group.cpp: Make PushCube() construct the cube data inline" "1657": "handmade_render_group.cpp: Introduce PushQuad()" "1915": "handmade_render_group.cpp: Clean up compile errors" "2056": "Run the game to see textured cubes and note that we must bind some texture to the sampler" "2231": "Consider creating a permanently resident plain white asset" "2375": "handmade_opengl.cpp: Create a WhiteBitmap" "2790": "handmade_render_group.cpp: Introduce a version of PushCube() that takes the WhiteBitmap directly" "2935": "handmade_opengl.cpp: Initialise WhiteBitmap to 0xFFFFFFFF and run the game to admire the fanciness" "2996": "Investigate what's going on with that colouring" "3159": "Step in to OpenGLAllocateTexture() and inspect the Data" "3220": "handmade_opengl.cpp: Prevent OpenGLInit() from returning anything, and tweak the WhiteBitmap" "3360": "Run the game and investigate the hypothesis that it's the vertices of the cube, rather than our texture, that are broken" "3776": "handmade_opengl.cpp: Prevent OpenGLAllocateTexture() from doing linear filtering, and run the game to see that this looks correct" "3885": "Consult the documentation on glTexParameter" "3908": "handmade_opengl.cpp: Make OpenGLAllocateTexture() use GL_CLAMP_TO_EDGE" "3955": "Run the game to see that this also looks correct" "4025": "Consult the OpenGL 4.5 and 2.0 documentation on CLAMP" "4178": "Run the game and determine that we're drawing what we expect to draw" "4207": "handmade_opengl.cpp: Ensure that sRGB is being correctly passed through the pipeline" "4523": "handmade_render_group.h: Remove bitmap and rectangle from render_entry_group_type" "4555": "handmade_render_group.cpp: Enable PushRect() to push on to the CurrentQuads array" "4934": "Run the game, note that everything is going through the new path and inspect the QuadCount" "4996": "A few words on why this is an improvement" "5120": "handmade_opengl.cpp: Force a call to OpenGLRectangle(), step into it and inspect the assembly" "5336": "A few words on going fully bindless in order to do this in bulk completely" "5695": "Consult the documentation on glDrawArrays and glVertexAttribPointer" "6047": "handmade_opengl.cpp: Enable OpenGLRenderCommands() to setup arrays for the texcoord, color and position" "6332": "Blackboard: Striding through our vertex array" "6423": "handmade_opengl.cpp: Continue working on OpenGLRenderCommands()" "6669": "Consult the documentation on glGetAttribLocation" "6734": "handmade_opengl.cpp: Make OpenGLInit() allow us to specify the vertices to pass to the shader" "7002": "handmade_opengl.cpp: Make OpenGLRenderCommands() call glDrawArrays()" "7158": "handmade_opengl.cpp: Make OpenGLRenderCommands() pass the vertices directly to the shader program" "7345": "win32_handmade.cpp: Pull in the necessary functions from glcorearb.h" "7647": "Run the game to admire the loveliness and investigate it" "7688": "handmade_opengl.cpp: Make OpenGLRenderCommands() correctly loop through the vertices and run the game to see that we're getting close" "7717": "handmade_opengl.cpp: Make OpenGLInit() set the correct VertUVID" "7782": "Run the game and note that we're in a good place, using fewer OpenGL calls" "7938": "Q&A" "7970": "Would it be better to expose an OpenGLGetProcAddress method in the platform layer and do the lookups in the handmade_opengl layer?" "8062": "We will use VBO and IBO? In that case you prefer using glBufferData to send TGE data into the buffer or using glMapBuffer / glUnmapBuffer to send the data?" "8250": "Will you use 4coder in full window mode (4ed.exe -F) in the future?" "8296": "By moving the construction of the vertex array to the RenderGroup, we kind of miss the opportunity of writing the quads directly into driver-owned memory, e.g. glMapBuffer. Is that statement correct? If so, is that a problem?" "8408": "Couldn't OpenGLGetProcAddress just return the method directly on some platforms, using string lookup?" "8496": "Why not build one massive vertex buffer and just draw that once?" "8631": "I see, thanks! Any chance we can see a render callstack from nsight or renderdoc just to see what the driver has to work through?" "8664": "Install RenderDoc" "8764": "Run the game in RenderDoc" "8877": "Press F12 to capture" "8987": "Does the Debug UI still work? If so, how does one activate it?" "9008": "Have you set a version target for the pipeline? Will you go full Embedded Systems bananas (OpenGL ES)?" "9030": "Close it down with a glimpse into the future" --- name: "day372" title: "Using Strictly OpenGL Core Profile" markers: "16": "Run the game to recap and set the stage for the day, with a few words on using 3D APIs" "284": "Determine to field debug messages and conditionally disable compatibility contexts" "655": "glDebugMessageCallback" "874": "glDebugMessageControl" "976": "GL_ARB_debug_output" "1398": "win32_handmade.cpp: Pull in GLDEBUGPROC() and glDebugMessageCallbackARB() from corearb.h" "1771": "handmade_opengl.cpp: Make OpenGLInit() call glDebugMessageCallbackARB()" "1813": "Run the game to successfully receive our callback and view an error" "1942": "handmade_opengl.cpp: Make OpenGLInit() perform the callback later" "1972": "Run the game and receive no errors" "1998": "win32_handmade.cpp: Switch to the OpenGL Core Profile and set WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB" "2082": "Run the game and get an error message" "2176": "handmade_opengl.cpp: Prevent OpenGLInit() from calling glTexEnvi()" "2184": "Run the game to find that glAlphaFunc() has been removed" "2211": "On why glAlphaFunc() is no longer necessary" "2303": "handmade_opengl.cpp: Make the FragmentCode conditionally apply blending and OpenGLRenderCommands() no longer call glAlphaFunc()" "2440": "handmade_opengl.cpp: Prevent OpenGLRenderCommands() from enabling GL_ALPHA_TEST" "2460": "Note that depth testing doesn't occur in the shader" "2534": "handmade_opengl.cpp: Prevent OpenGLRenderCommands() from enabling GL_TEXTURE_2D and the glMatrixMode() stuff" "2602": "Run the game and realise that we must create and bind a vertex array object" "2689": "handmade_opengl.cpp: Make OpenGLInit() call glGenVertexArrays() and glBindVertexArray()" "2908": "Run the game and receive apparently the opposite error from before" "3133": "Note that we are using client-side memory and consider switching to GPU-mapped memory" "3453": "handmade_opengl.cpp: Make OpenGLInit() call glGenBuffers() to store the vertex array" "3692": "handmade_opengl.cpp: Make OpenGLRenderCommands() call glBufferData() for that GL_ARRAY_BUFFER" "3868": "A few words on how this buffer has improved the rendering pipeline" "4028": "handmade_opengl.cpp and win32_handmade.cpp: Pull in the necessary calls from corearb.h" "4221": "Run the game to find that we have passed the glVertexAttribPointer error, and that the final error is relating to GL_QUADS" "4317": "On why there may not be a fix for this GL_QUADS error" "4508": "Blackboard: Vertex Sharing" "4645": "Blackboard: Specifying the vertices with an Index stream" "4951": "handmade_opengl.cpp: Re-enable GL_QUADS, turn off the debug messages, and run the game to find that we're not getting a working image" "5011": "win32_handmade.cpp: Turn off WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, and run the game to find that it's now okay" "5057": "Blackboard: Our options regarding the WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB bit, GL_QUADS and GL_TRIANGLE_STRIP" "5501": "handmade_opengl.cpp: Change GL_QUADS to GL_TRIANGLE_STRIP in OpenGLRenderCommands(), and re-enable the debug message" "5579": "Run the game to see that this is not correct because the vertex order is wrong" "5604": "handmade_opengl.cpp: Re-enable the debug message and WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB" "5651": "Run the game to see that we're completely compliant, but just drawing wrong" "5661": "handmade_render_group.cpp: Switch PushQuad() to push the vertices in the correct order for GL_TRIANGLE_STRIP" "5718": "Run the game to see that it is now correct, and note that this won't work if we had a texture atlas" "5933": "Determine to get the orthographic projection back online for the debug view" "6205": "handmade_math.h: Enable OrthographicProjection() to use the near and far clip planes" "6316": "Run the game and note that we'll need to deal with the camera part of the transform for the debug UI" "6457": "handmade_debug.cpp: Consider how the SetCameraTransform() call in DEBUGStart() is now massively wrong" "6542": "handmade_debug.cpp: Make SetCameraTransform() use and scale the CameraX and CameraY" "6616": "Blackboard: Mapping the extremities of the screen to -1 to 1" "6756": "Run the game and assess our clip plane situation" "6854": "handmade_debug.cpp: Begin to consider what else in DEBUGStart() may be problematic" "6929": "Q&A" "7009": "Where's owlbot? He's not online" "7159": "About the QUAD thing, you might want to do something like this, maybe" "7293": "You could avoid geometry shaders by instancing a triangle strip that is just a quad" "7341": "What do you think about using a different set of program / shader for debug text, one which has no projection matrix at all? Would it be bad to switch programs for GUI text performance-wise?" "7540": "There is a third way of setting the vertex data through ARB_separate_attrib_format (went to core in 4.3). This separates the vertex format from the buffer it reads the data from which is more optimal for the driver" "7592": "When the engine uses a deprecated function like GL_QUADS, what are the main issues that people would have to deal with playing this game, because it is running, right?" "7745": "Is OpenGL 3.0 the target version?" "7874": "Any idea why one can have stuttering problems using OpenGL DWM stuff related?" "8041": "What do you like better in OpenGL AZDO as opposed to Vulkan?" "8315": "Would it be interesting to implement OpenGL on top of OpenCL?" "8394": "Since Handmade Hero is using multithreaded processing of the game entities, how would the game even stutter when time wouldn't be enough 'til the next frame?" "8461": "Shut this down" --- name: "day373" title: "Inverting the Full 3D Transform" markers: "9": "Recap and set the stage for the day" "185": ""This will be a stream filled with mucus"" "254": "handmade_debug.cpp: Consider how to enable DEBUGStart() to correctly place the debug text" "413": "handmade_math.h: Make OrthographicProjection() set the near clip plane to be behind the camera" "552": "Run the game to see that it's drawing okay, but that we cannot perform a debug click" "656": "handmade_debug.cpp: Temporarily make DEBUGStart() shrink the debug text" "698": "Determine to get Unproject() working again" "802": "Run the game to see those pixel coordinates" "840": "handmade_render_group.cpp: Look at how Unproject() currently works" "908": "Blackboard: The Projection, Clip-space, Screen-space pipeline" "1193": "handmade_render_group.cpp: Prevent Unproject() from baking in the aspect ratio" "1307": "Blackboard: Inverting a matrix" "1544": "Blackboard: Producing the inverse of our projection matrix" "1835": "Blackboard: Check our working" "2132": "Blackboard: Producing the bottom row of the identity projection matrix" "2686": "Blackboard: Plug in those terms and see if that checks out" "2811": "handmade_render_group.cpp: Note that our projection matrix is slightly different" "2853": "Blackboard: Computing the inverse projection matrix for our actual matrix" "2978": "handmade_math.h: Introduce m4x4_inv struct and augment PerspectiveProjection() to produce both the Forward and Inverse matrices" "3236": "Step in to PerspectiveProjection() and inspect the resulting matrix" "3335": "Blackboard: Producing the identity orthographic projection matrix" "3665": "handmade_math.h: Augment OrthographicProjection() to produce both the Forward and Inverse matrices" "3735": "Step in to OrthographicProjection() and inspect the resulting matrix" "3781": "handmade_render_group.cpp: Set up SetCameraTransform() to compute both the Forward and Inverse matrices" "3882": "handmade_math.h: Determine to augment CameraTransform() to produce both the Forward and Inverse matrices" "3934": "Blackboard: Beginning to produce the identity camera matrix" "3984": "Blackboard: Isolating pieces of the matrix" "4213": "Blackboard: Producing the identity camera matrix" "4365": "Blackboard: Handling different length, yet still orthogonal axes" "4484": "handmade_math.h: Augment CameraTransform() to produce both the Forward and Inverse matrices" "4601": "Blackboard: Getting the inverse of a vector's own length" "4642": "handmade_math.h: Continue to augment CameraTransform()" "4688": "handmade_math.h: Introduce an operator/() that operates on vectors" "4781": "Blackboard: Producing our rightmost and bottom vectors for the identity camera matrix" "4951": "handmade_math.h: Enable CameraTransform() to compute our inverse components" "5150": "Step in to CameraTransform() and inspect the resulting matrix" "5215": "handmade_math.h: Fix typos in CameraTransform()" "5232": "Step back in to CameraTransform() and inspect the resulting matrix" "5319": "Blackboard: Producing our inverse components" "5507": "Blackboard: Set up the matrixes in the correct orientation" "5584": "handmade_math.h: Make CameraTransform() correctly compute the iP" "5658": "Step in to CameraTransform() to see that we're now rock solid" "5703": "handmade_render_group.cpp: Enable SetCameraTransform() to compute both matrices, and PushSetup() to take a m4x4_inv" "5823": "Run the game and note that we can always access the inverse of our projection" "5843": "handmade_render_group.cpp: Determine to enable Unproject() to perform the reverse transform on the z" "5921": "Blackboard: Unprojecting the z" "5990": "handmade_render_group.cpp: Enable Unproject() to perform the reverse transform on the z" "6186": "Consider restoring the mouse picking of entities" "6315": "handmade_render_group.cpp: Make Unproject() take a WorldDistanceZ" "6448": "handmade_math.h: Extend Transform() to take a v4" "6500": "handmade_render_group.cpp: Make Unproject() compute the ClipZ from ProbeZ" "6560": "handmade_math.h: Introduce an operator*() that takes a v4" "6580": "handmade_render_group.cpp: Make GetCameraRectangleAtDistance() use WorldDistanceFromCameraZ directly" "6650": "Run the game to see how it currently works" "6699": "handmade_render_group.cpp: Enable SetCameraTransform() to check the inverse of the composite" "6740": "Step in to SetCameraTransform() and inspect that identity composite matrix" "6842": "Step in to Unproject() and inspect the Clip coordinates" "6930": "handmade_debug.cpp: Make DEBUGEnd() set the MouseX to 0 and MouseY to 1079" "6963": "Step in to Unproject() to see that the Clip coordinates are now wrong" "7017": "handmade_render_group.cpp: Make Unproject() correctly compute the ClipSpaceX and ClipSpaceY" "7086": "Blackboard: Dividing by half of the width" "7146": "Step through Unproject() and inspect the values" "7271": "Run the game to find that debug clicking works correctly again" "7334": "todo.txt: Update the TODO list" "7401": "Q&A" "7450": "Am I right in thinking that today's work has had the cool, and not immediately expected, side effect of beginning to level up the debug camera, in terms of mouse picking of entities? Or did the debug camera have that before anyway?" "7492": "Blackboard: 3D Picking of Entities" "7546": "Do you plan to keep the Assert in OpenGLDebugCallback? My driver is sending a lot of debug information that fires the assert" "7554": "handmade_opengl.cpp: Disable the OpenGLDebugCallback error message" "7698": "Why do you think it is not popular to do x-forward coordinate systems? Jon Blow was talking about it yesterday and it seems like a good idea, at least in terms of rotations" "7745": "Why use Square(Length(..))? How does it compare to LengthSq(..)?" "7761": "handmade_math.h: Make CameraTransform() use LengthSq() directly" "7847": "Will you consider a faster matrix multiplication algorithm other than inner product?" "7893": "Is there a roadmap for what you will be working on over the coming months?" "7910": "The ProbeZ thing went a bit too quick for me. I didn't fully understand the role of WorldDistanceFromCameraZ and how you are going to generate it. Are you going to talk more about that next time?" "7924": "Blackboard: The 3D Picking Procedure" "8036": "Since you are only doing quads, wouldn't it be possible to upload a constant index buffer once with the max number of vertices and then never touch it again?" "8099": "Is it possible that Square Length can result in a zero and blow up?" "8139": "I get OpenGL messages with severity DEBUG_SEVERITY_NOTIFICATION and DEBUG_SEVERITY_MEDIUM" "8159": "Even a simple pass-through geometry shader is a decent perf hit" "8175": "Sorry, didn't see the whole stream, but why no 60fps with the move to core GL?" "8191": "build.bat: Temporarily switch to -O2 and disable the debug system" "8325": "Run the game in the belief that this is 60fps" "8401": "e.g. MEDIUM: "Recompiling fragment shader for program 3"" "8424": "handmade_opengl.cpp: Pull in the severities from corearb.h and only make the OpenGLDebugCallback occur on GL_DEBUG_SEVERITY_HIGH" "8492": "Run the game to see that it still works" "8500": "We are about done for today" --- name: "day374" title: "Debugging Z Transform and Bias" markers: "12": "Recap and set the stage for the day" "266": "Determine to fix the "glGetString(GL_EXTENSIONS) fails with error GL_INVALID_ENUM issue"" "388": "handmade_opengl.cpp: Make OpenGLGetInfo() use glGetIntergerv() and glGetStringi() rather than glGetString()" "806": "handmade_opengl.cpp: Pull in GL_NUM_EXTENSIONS and glGetStringi() from corearb.h" "894": "win32_handmade.cpp: Pull in glGetStringi() from corearb.b" "1038": "Run the game, step through OpenGLGetInfo() and close that issue" "1105": "Run the game and consider what we have to do" "1216": "handmade_world_mode.cpp: Make PlayWorld() always make rooms above and below us" "1360": "Run the game to see that our zoom isn't working, and investigate why" "1396": "handmade_world_mode.cpp: Make PlayWorld() only make one room" "1438": "Run the game, try to switch to the debug camera and hit the assert in RecanonicalizeCoord()" "1586": "Step through UpdateAndRenderWorld() to see what's going on" "1734": "handmade_render_group.cpp: Make Unproject() correctly compute the ProbeZ" "1798": "Blackboard: Camera transform matrix" "1891": "handmade_render_group.cpp: Make Unproject() grab the Z row out of the camera projection matrix" "2006": "Run the game and step in to Unproject() to inspect the ProbeZ" "2280": "Run the game and step through Unproject() more carefully" "2385": "handmade_render_group.cpp: Make Unproject() compute the ProbeZ using the correct CameraZ" "2431": "Run the game and step into Unproject() to find that we have a more correct ProbeZ, but a busted ClipZ" "2506": "Blackboard: Our combined projection matrix" "2564": "handmade_render_group.cpp: Make Unproject() compute the ProbeZ fully correct" "2584": "Run the game to see that we get a better ClipZ, just not exactly what we'd expect" "2908": "Run the game and step through PerspectiveProjection() to see how it is building the matrix" "3031": "handmade_math.h: Make PerspectiveProjection() perform a full transform in the tests" "3091": "Run the game and step in to PerspectiveProjection() to inspect the results of the tests" "3194": "Run the game and step through SetCameraTransform() to see how that is working" "3300": "handmade_render_group.h: Introduce render_transform struct, and make render_group contain one each for the game and camera" "3363": "handmade_render_group.cpp: Make the necessary functions take this render_transform" "3792": "handmade_render_group.cpp: Make SetCameraTransform() build the correct transform matrix" "3986": "Run the game to see that the central debug rectangle is stable, and continue to investigate Unproject()" "4289": "handmade_world_mode.cpp: Force UpdateAndRenderWorld() to call Unproject() right at the near clip plane" "4403": "Run the game and step in to Unproject() to inspect the ProbeZ and ClipZ" "4522": "handmade_world_mode.cpp: Force UpdateAndRenderWorld() to call Unproject() right at the far clip plane" "4542": "Run the game and step in to Unproject() to inspect the ProbeZ and ClipZ" "4561": "handmade_world_mode.cpp: Force UpdateAndRenderWorld() to call Unproject() at 0.8" "4578": "Run the game and step in to Unproject() to inspect the ProbeZ and ClipZ" "4597": ""It's the inverse-square law kicking our butts"" "4611": "handmade_math.h: Try to make PerspectiveProjection() move the near clip plane out" "4660": "Run the game and step in to Unproject() to inspect the ClipZ" "4706": "todo.txt: Fix Z buffer to be better resolution" "4724": "4coder feature request: TODO list formatting" "4916": "Consider getting our Z story sorted out and return to debugging the problem with multiple stacked screens" "4965": "Run the game to find our camera encased in some degenerate geometry" "5002": "handmade_world_mode.cpp: Make PlayWorld() set DoorDirection to 2" "5021": "Run the game and determine that the problem only occurs when the floors are generated to the camera" "5072": "handmade_render_group.cpp: Make PushBitmap() reduce the ZBias" "5095": "Run the game, zoom out and determine that our bias is being applied incorrectly" "5131": "handmade_opengl.cpp: Investigate how the VertexCode is applying the ZBias" "5386": "handmade_opengl.cpp: Try making OpenGLRenderCommands() pass GL_DEPTH_COMPONENT32F to glTexImage2DMultisample()" "5394": "Run the game to see the same behaviour, and consider it not to be a precision issue" "5524": "handmade_opengl.cpp: Try commenting out the ZVertex.z biasing" "5543": "Run the game to see that all of the stuff seems pretty consistent" "5696": "handmade_world_mode.cpp: Try increasing the far clip plane" "5803": "Run the game and watch the incorrect clipping behaviour" "5862": "handmade_math.h: Tweak the near and far clip plane in PerspectiveProjection()" "5934": "Try to find a source for the standard projection perspective matrix" "6228": "Run the game to see some projection wonkiness" "6366": "handmade_render_group.cpp: Try turning off the ZBias in PushBitmap()" "6385": "Run the game to see that everything is sorting as expected" "6525": "Consider that the ZBias is pre-transformed and appears to be being applied in clip space" "6705": "Moment of realisation: Our ZMaxTransform.z depends on the w value to counter-divide it" "6778": "Blackboard: Computing ClipZ" "6932": "handmade_opengl.cpp: Make VertexCode compute a ModifiedZ for use in the gl_Position computation" "6985": "Run the game to see that that was exactly what we needed, and consider how to handle blocks obscuring other blocks" "7264": "Blackboard: How the sprites are being generated aligned with the camera" "7322": "handmade_render_group.cpp: Enable PushBitmap() to draw the Upright sprites actually standing upright" "7382": "Run the game to see what that looks like" "7447": "handmade_render_group.cpp: Play with how PushBitmap() combines the upright and camera-facing styles" "7630": "Run the game to admire our trees" "7757": "Q&A" "7822": "I am a fairly amateur programmer. I have dabbled in Java, flavors of C, Python, and Ruby while I was in university. My question is, how would you suggest with progressing your proficiency in a particular language? Is it best to follow tutorials?" "8147": "What is Z transform?" "8272": "How many draw calls with the profiler open?" "8288": "A few streams ago you showed a function that tells OpenGL to call us back with messages. Do you think it can help debug OpenGL issues instead of sticking glGetError after every call?" "8353": "When the new assets gonna be ready?" "8375": "Scenario is that Handmade Hero is expanding to three programmers and two need to understand the architecture you have designed. How would you recommend that they get into the code and understand the architecture? What would you need to do to prepare the system for such a scenario?" "8709": "I know you don't really like OOP design, but can you provide some ways you might take advantage of OOP design in Handmade Hero?" "9059": ""Don't OOP. OOC"" "9306": ""What are the chances that there's one way to always write code?"" "9352": "What do you think about "const correctness"? How often do you use const?" "9515": "const is mainly for teams" "9658": "Wrap it up" --- name: "day375" title: "Adding Distance-based Fog" markers: "9": "Recap and set the stage for the day" "171": "Run the game and show where we left off" "198": "handmade_world_mode.cpp: Make PlayWorld() stack up 10 rooms and run the game to view them" "297": "handmade_world_mode.cpp: Make AddStandardRoom() create holes on every floor" "318": "Run the game to view the entities each floor comprises, and determine to reintroduce fog" "717": "handmade_opengl.cpp: Try to introduce a GlobalFrameBufferDepth for OpenGLRenderCommands() to output a bitmap" "891": "Run the game to find that glFramebufferTexture2D() failed, and undo our changes" "1067": "handmade_opengl.cpp: Begin to reintroduce fog" "1213": "Blackboard: "Fog" darkening based on distance" "1530": "handmade_opengl.cpp: Enable the VertexCode to linearly interpolate between the FragColor and FogColor, using GLSL's mix()" "2176": "Run the game to see the blending between the two colours" "2213": "handmade_opengl.cpp: Investigate why the bitmaps are not getting fogged" "2502": "handmade_opengl.cpp: Enable the FragmentCode to perform the fogging lerp" "2649": "Run the game to see what we'd expect to see" "2673": "handmade_opengl.cpp: Enable the VertexCode to compute the FogAmount based on the distance from camera" "2954": "handmade_opengl.cpp: Introduce Clamp01MapToRange() in the shader" "3074": "handmade_opengl.cpp: Make the VertexCode call that Clamp01MapToRange()" "3152": "Run the game and assume that nothing is incorrect there" "3165": "handmade_opengl.cpp: Make OpenGLInit() and OpenGLRenderCommands() setup our fog data" "3378": "A few words on threading cables through conduits" "3498": "handmade_render_group.h: Consider removing render_entry_cliprect in favour of render_entry_textured_quads" "3663": "handmade_render_group.h: Remove render_entry_bitmap, render_entry_rectangle, render_entry_clear and render_entry_saturation" "3758": "Note that this simplification provides us with the ability to view the fog from a different direction" "3814": "handmade_render_group.h: Add fog data to render_entry_cliprect" "3834": "handmade_opengl.cpp: Make the render_entry_textured_quads case in OpenGLRenderCommands() set the fog data" "3908": "win32_handmade.cpp: Pull in glUniform1f, glUniform2fv, glUniform3fv and glUniform4fv from corearb.h" "4086": "Run the game to determine that we are passing everything through correctly" "4096": "handmade_render_group.h: Add a render_entry_cliprect LastSetup to render_group and propagate that change" "4416": "handmade_render_group.cpp: Clean up how the render_entry_cliprect NewSetup gets used" "4798": "handmade_math.h: Introduce versions of RectMinMax() and RectMinDim() that return a rentangle2i" "4892": "handmade_render_group.cpp: Continue cleaning up the use of NewSetup" "4962": "Run the game to see nothing yet" "4981": "handmade_render_group.cpp: Make BeginRenderGroup() initialise the fog distances" "5025": "Run the game to see our game drawing correctly, and note why" "5087": "handmade_render_group.cpp: Enable SetCameraTransform() to compute the fog by its distance" "5196": "Run the game to see the fog taking effect through the hole" "5241": "handmade_opengl.cpp: Enable the FragmentCode to take a FogColor and blend part of it" "5419": "handmade_render_group.h: Add FogColor to render_entry_cliprect" "5428": "handmade_opengl.cpp: Make OpenGLRenderCommands() set that FogColor" "5500": "Run the game to see our programatically set fog colour" "5505": "handmade_render_group.cpp: Tweak the FogColor in BeginRenderGroup()" "5594": "handmade_render_group.cpp: Investigate how Clear() is working" "5757": "handmade_math.h: Introduce LinearTosRGB()" "5793": "handmade_render_group.cpp: Make BeginRenderGroup() Square the FogColor, and run the game to determine that the Clear does not go through sRGB" "5826": "handmade_platform.h: Label the ClearColor in game_render_commands as not in linear space, but in sRGB space" "5945": "handmade_render_group.cpp: Make Clear() set the FogColor" "6081": "Run the game and consider that to be quite good" "6150": "Consider handling alpha fading of levels nearer to the camera than the hero's current level" "6219": "handmade_world_mode.cpp: Enable AddStandardRoom() to generate stairs" "6563": "Run the game and hop down the stairs" "6685": "handmade_render_group.h: Rename render_entry_cliprect to render_setup for render_entry_textured_quads to contain, and propagate this change, simplifying PushSetup() and OpenGLRenderCommands()" "7997": "handmade_render.cpp: Remove LinearizeClipRects() and PrepForRender()" "8079": "Run the game to see that that worked just great, with a few words on how much cleaner the render commands are now" "8157": "Q&A" "8210": "Has the framerate tanked after implementing fog? Or was that a wrong impression of mine?" "8222": "Compile and run with various optimisation settings" "8394": "Now that we're full 3D, may it be worth extending the debug visualisation rectangles into the third dimension?" "8419": "Why would you (in this case) compile without optimizations? I don't get how it changes your framerate that much (sorry if this is a dumb question)" "8488": "handmade_sim_region.cpp: Make a KillSwitch to disable GetClosestTraversable()" "8622": "Run the game and compare the framerate with and without GetClosestTraversable() running" "8743": "Step in to GetClosestTraversable() and calculate how many operations it performs, and the number of cycles in which it must execute" "9012": "Look at the disassembly for GetClosestTraversable() when compiled with -Od" "9180": "Switch to -O2 and look at the disassembly for GetClosestTraversable() again" "9368": "Compiling with optimisations on inhibits our ability to debug the code effectively" "9595": "How do you feel about Uniform Buffer Objects? Am I right to assume the Render Setup struct could be passed to the shader as an UBO instead of separate Uniforms?" "9624": "How does the hero know it should hop to the lower level instead of the upper level at the end of the stairs? Where is the code for that?" "9670": "What does the software renderer look like at the moment?" "9693": "I assume the problems you solve in Handmade Hero are fairly representative of problems you face as a game dev. Can you comment about any social aspects of being a game dev, e.g. how collaborative or supportive the community is, or what it's like sharing a codebase with a number of others?" "9858": "How many lines of code does Handmade Hero have?" "10062": "Wind it on down with a glimpse into the future" --- name: "day376" title: "Drawing Debug Volumes" markers: "2": "Recap and set the stage for the day" "186": "Consider approaching alpha fade and upgrading our understanding of the camera" "348": "Run the game to assess our current situation" "524": "Determine to fix the camera code" "581": "handmade_world_mode.cpp and handmade_render_group.cpp: Make PlayWorld() generate fewer rooms and SetCameraTransform() disable the fog in debug mode" "759": "Run the game to see that the fog is disabled, and consider how to define the extents of a room" "970": "Determine to extend the debug rectangles into the third dimension as per Miblo's request" "1059": "Blackboard: Drawing rectangles on sheets" "1109": "handmade_render_group.cpp: Introduce PushVolumeOutline() based on PushCube()" "1326": "Blackboard: Cube edges, faces and vertices" "1389": "handmade_render_group.cpp: Enable PushVolumeOutline() to set the cube vertices" "1516": "Blackboard: Defining cube vertices and edges" "1694": "handmade_render_group.cpp: Enable PushVolumeOutline() to call PushLineSegment() for each edge" "1878": "Blackboard: Cube edges" "2163": "handmade_render_group.cpp: Introduce PushLineSegment()" "2496": "Blackboard: Computing thickness for our line segment, an end user-facing approach being to use a distance field in a shader, but using the cross product in a debug scenario" "2703": "Blackboard: Differential Geometry (gradient, divergence and curl) and Geometric Algebra (dot and cross product)" "3060": "Blackboard: Inner / dot product" "3184": "Blackboard: Cross product" "3607": "Blackboard: Solving for the cross product vectors that go in the same direction" "3975": "Hunt for a computer algebra system to solve our equation" "4411": "Consult the documentation for YACAS" "4520": "Try to plug our equations into YACAS" "4620": "Blackboard: Computing the angle between two vectors" "4781": "Try to prescribe the angle between the vectors" "4835": "View the supposed solution to our equations" "4942": "Continue the hunt for a computer algebra system" "5112": "Consult the documentation for Maxima" "5256": "Try to plug our equations into Maxima" "5358": "View the non-solution" "5409": "Prescribe that the sine must be 1 and view this solution" "5436": "Reflect on our foray into computer algebra systems" "5570": "Cross product" "5743": "handmade_math.h: Introduce Cross()" "5957": "Blackboard: How the cross product helps us to produce thickness" "6091": "handmade_render_group.cpp: Enable PushLineSegment() to compute the normalised perpendicular using Cross() and NOZ()" "6298": "handmade_render_group.cpp: Enable PushVolumeOutline() to pass the C and Thickness to PushLineSegment()" "6415": "handmade_world_mode.cpp: Enable PlayWorld() to call PushVolumeOutline()" "6475": "Run the game to see our 3D debug cube" "6527": "handmade_render_group.cpp: Sanity check PushLineSegment()" "6579": "Blackboard: Pre-projecting down to the screen" "6657": "handmade_render_group.cpp: Temporarily make PushLineSegment() keep the Line in line with the camera's Z axis" "6699": "Run the game to see that debug cube" "6726": "handmade_math.h: Sanity check Cross() and consider what is happening" "6829": "handmade_render_group.cpp: Temporarily make PushVolumeOutline() only draw one segment, and run the game to see how that looks" "6993": "handmade_world_mode.cpp: Reduce the thickness and run the game to see the problem when the line is head-on" "7054": "handmade_render_group.cpp: Enable PushLineSegment() to compensate for the LinePerpLength" "7171": "Blackboard: On losing our length as the angle between the edges reduces to 0" "7221": "handmade_render_group.cpp: Continue to enable PushLineSegment() to compensate for the LinePerpLength" "7344": "Run the game to see our current problematic behaviour" "7423": "Blackboard: Computing the perpendicular to the CameraZ" "7509": "Q&A" "7584": "hmd_bot handles the Q&A message and seems to be dead" "7614": "Here's your equations solved in Maxima [image], and here's your equations solved with expanding (sinθ)^2 through dot product: [image]. I think this approach is completely wrong when trying to derive cross product" "7670": "What would be the downside of drawing your debug lines as 3D cylinders or extruded rectangles? It seems like that would look a little nice when viewed from all angles" "7818": "Also shall we draw the cubes around the room?" "7847": "handmade_entity.cpp: Make UpdateAndRenderEntities() draw collision volumes" "7926": "Run the game to see what that does" "7957": "handmade_render_group.cpp: Make PushVolumeOutline() take the ObjectTransform into account" "8012": "Run the game to see the collision volumes" "8110": "handmade_render_group.cpp: Enable SetCameraTransform() to set the DebugXForm in both modes, and run the game to see the collision volumes in the game mode" "8204": "You mentioned that you use discriminated unions. Have you seen Rust's implementation of sum types?" "8219": "I was looking at how the vector types are set up in Handmade Hero as unions. As far as I know, it's undefined behaviour to write value to one type of a union and then read as another type. Is doing something like this well defined - vec1.x = 5.0f and then read as vec1.E[0] - or is it one of the cases where we rely that a reasonable compiler will do the right thing?" "8439": "Would you describe discriminated union to the general public?" "8450": "Blackboard: Struct, as a representations of data in memory" "8652": "Blackboard: Union, as a combination of structs" "8781": "Blackboard: Discriminated union, as a union containing a type field" "9003": "Blackboard: Inheritance in C++" "9152": "Can you give a motivating example for these discriminating unions?" "9191": "Blackboard: A "single dispatch" example in which a discriminated union and inheritance work equally well" "9534": "Blackboard: The tractability of Single vs Double Dispatch" "9600": "Blackboard: A "double dispatch" example in which a discriminated union excels" "9966": "Blackboard: Generating a sparse matrix containing the cases you care about" "10174": "Blackboard: Discriminated unions shine in enabling the ability to write code which looks at the way in which types are set among more than one object" "10424": "How would you feel if you wrote the functions for colliding each pair or types, and allowed the compiler to generate the sparse matrix of function calls for you?" "10509": "Recommend researching category theory, with a call for Pseudonym73" "10812": "Are you hoping JAI will have discriminated unions?" "10832": "Wind down here" --- name: "day377" title: "Improving Collision Volumes and the Camera" markers: "2": "Recap and set the stage for the day" "274": "Run the game to see our debug collision volumes, and determine to implement room-based collision volumes" "512": "handmade_entity.h: Add CollisionVolume to the entity struct and propagate that change" "1050": "handmade_sim_region.cpp: Introduce EntityOverlapsEntity(), remove EntitiesOverlap() and continue propagating CollisionVolume" "1427": "handmade_math.h: Introduce a version of HasArea() that takes a rectangle3, and continue propagating the entity struct change" "2112": "Run the game to see that the volumes are being offset unnecessarily" "2135": "handmade_entity.cpp: Prevent UpdateAndRenderEntites() from calling DrawVolume()" "2157": "Run the game to see that we are back to something relatively sane" "2177": "handmade_entity.cpp: Enable UpdateAndRenderEntites() to colour the collision volumes according to whether they are colliding" "2218": "Run the game to see our properly bounded rooms" "2314": "handmade_world_mode.cpp: Make AddStandardRoom() only bias the floor tiles upwards" "2408": "Run the game to see what that looks like" "2601": "handmade_world_mode.cpp: Make PlayWorld() increase the TypicalFloorHeight, run the game to see how that height feels and note a graphical artefact when going downstairs" "2801": "handmade_world_mode.cpp: Try to increase the tile size, and decrease the hero size in an effort to combat that clipping artefact when on the stairs" "2931": "Run the game and consider fixing the problem by moving the camera over to the stairs" "2965": "handmade_world_mode.cpp: Temporarily make AddStandardRoom() generate the stairwell in the centre and run the game to see that the artefact does not occur" "3167": "handmade_sim_region.cpp: Consider giving the camera a physical location in the world, which gets unpacked into the sim region" "3438": "Blackboard: Camera Target Position" "3534": "handmade_sim_region.cpp: Construct the notion of a camera target position in UpdateCameraForEntityMovement()" "3736": "Run the game and note that the camera is currently unable to articulate to the game where it is trying to view" "3788": "handmade_sim_region.cpp: Make UpdateCameraForEntityMovement() position the camera in a sim region" "3871": "handmade_world_mode.cpp: Make UpdateAndRenderWorld() set the SimulationCenter based on the camera target" "4060": "Run the game and consider how best to locate the camera in the world" "4358": "handmade_world_mode.h: Add OffsetZ to the game_camera struct for UpdateCameraForEntityMovement()" "4420": "Run the game to see that the focusing still works" "4442": "handmade_sim_region.cpp: Enable UpdateCameraForEntityMovement() and UpdateAndRenderWorld() to lock the camera to the hero's location" "4656": "Run the game to see the camera following the hero" "4750": "handmade_sim_region.cpp: Introduce the notion of a SpecialCamera region in UpdateCameraForEntityMovement()" "4923": "handmade_world_mode.cpp: Enable AddStandardRoom() to create a collision volume which triggers the SpecialCamera" "5326": "Run the game to see our collision volume" "5375": "handmade_world_mode.cpp: Temporarily disable the familiars, and extend the collision volume upwards" "5451": "Run the game to try triggering that collision volume" "5669": "Q&A" "5759": "Hi Casey! Two questions: 1) How come RAD aren't owning every avenue of compression in existence, like video codecs? and 2) Will Handmade Hero at some point be beautifully, 2D-animated like the excellent, excellent Hollow Knight, that everyone should play, by the way?" "5971": "Why don't you search and replace for the new short sexy data types" "5981": "That was Shovel Knight! Hollow Knight is a new game!" "6019": "Is the camera for this game gonna be plenty smart or just a little smart? In this staircase I imagine you might want to measure the velocity of the player to not have it affect the camera if the player is rushing straight past" "6082": "handmade_sim_region.cpp: Prevent the camera from panning to the staircase unless the hero is traversing the stairs" "6141": "Run the game to see how that works" "6187": "Is the Debug Text draw order still inverted? It seems so by the looks of the Debug text. Is the profiler still working?" "6221": "Greetings Casey! Last week during the wonderful Handmade Chat you demonstrated how to dynamically create code in memory. You have mentioned in the past how you do a fair bit of meta-programming and I always envisioned that you would generate C / C++ code to files. When you tackle meta-programming, do you write out to disk first and then have it compiled? Do you do it all in memory similar to what you did last week? Combination of both?" "6328": "Hey Casey. I was messing around with 4x4 matrix multiplication implementations and whipped out ten variations, some of which naive and others more optimal with SIMD. Out of curiosity I performance tested them all on MSVC, clang and gcc. I was very surprised by the results as the compilers seem to be doing very different things for this simple task. For example, on gcc the naive versions sometimes beat what I thought would be optimal SIMD (seems like it was able to output better intrinsics) but on clang it was the opposite. MSVC seems to have failed at unrolling a loop and all implementations were crap except for a manually unrolled SIMD version. I realize this is a rathole of a problem but is this really where we're at in terms of the philosophy of "write once and let each compiler do the best thing for the platform"? Any thoughts?" "6811": "I remember you mentioned at some point that you were really interested in Salt & Sanctuary. Have you played it? Did you work on that game?" "6831": "Can you please explain once more why you kept CameraOffsetZ? Is it for movement beetwen tilemaps or for something else?" "6845": "Blackboard: Encoding the location the camera is looking at" "6967": "If it's too off-topic I'll ask tomorrow during pre-stream, follow up on devirtualization: Your main criticism about virtual functions was the overhead you get from the indirection, so with devirtualization would you consider using them, or are there any other downsides compared to tagged unions?" "7099": "Close it down with a plug of AsafGartner's searcher" --- name: "day378" title: "Adding More Camera Behaviors" markers: "8": "Recap and set the stage for the day" "108": "Run the game to see how the camera is working and consider introducing the notion of camera movement while lingering" "359": "handmade_sim_region.cpp: Begin to enable UpdateCameraForEntityMovement() to move the camera gradually towards a target" "435": "A few words on the commonness in games of moving gradually to a target" "492": "handmade_sim_region.cpp: Make UpdateCameraForEntityMovement() set the camera's target" "605": "Run the game to see no camera movement" "637": "handmade_sim_region.cpp: Enable UpdateCameraForEntityMovement() to snap the camera to its target" "845": "Run the game to see the camera snap between locations" "859": "handmade_sim_region.cpp: Enable UpdateCameraForEntityMovement() to gradually drive the camera from its current location to its target" "885": "Run the game to see that camera interpolation in action" "905": "Blackboard: Moving along a vector by a simplified rate" "1279": "Run the game to show the constant velocity of the camera" "1307": "Blackboard: Prentending that our velocity is encoded in the length of p" "1442": "Blackboard: Computing instantaneous velocity, without acceleration, using a resolved rate equation" "1677": "Run the game and determine to move the camera when lingering" "1713": "handmade_entity.h: Add CameraBehavior to the entity struct" "1781": "handmade_sim_region.cpp: Begin to enable UpdateCameraForEntityMovement() to handle camera behaviors" "1835": "handmade_world_mode.cpp: Make AddStandardRoom() generate a CollisionVolume near the hole to trigger camera movement" "2062": "Run the game and try triggering that CollisionVolume" "2088": "handmade_sim_region.cpp: Introduce the notion of a SpecialCamera, and make UpdateCameraForEntityMovement() handle it on a timer" "2342": "Run the game to try out the timed triggering" "2394": "handmade_sim_region.cpp: Enable UpdateCameraForEntityMovement() to zoom the SpecialCamera" "2664": "Run the game to see that timed camera movement with zoom, and tweak the movement" "2818": "handmade_sim_region.cpp: Make UpdateCameraForEntityMovement() only trigger the camera movement when the hero is not moving" "2925": "Run the game to try the camera, and determine to create a camera movement for the stairwell" "3026": "handmade_world_mode.cpp: Prevent AddStandardRoom() from randomising the stair positions" "3505": "Run the game to see our even stairwell, and tweak its dimensions" "3862": "handmade_world_mode.cpp: Enable AddStandardRoom() to generate the stair tiles separately from the hole generation" "3993": "Run the game to try out our wider stairwell, and tweak it" "4234": "handmade_world_mode.cpp: Define the two StairsCam CollisionVolumes in AddStandardRoom()" "4651": "Run the game and determine to create movement logic" "4722": "handmade_sim_region.cpp: Implement some velocity constraints for the SpecialCamera in UpdateCameraForEntityMovement()" "5565": "handmade_math.h: Introduce IsInRange()" "5619": "handmade_sim_region.cpp: Enable UpdateCameraForEntityMovement() to distinguish between a Player and an Area camera" "5725": "Run the game to try out those cameras" "5763": "handmade_entity.h: Introduce the notion of a CameraMinTime in entity" "5836": "Run the game to try out the timers" "5857": "handmade_world_mode.cpp: Set GeneralVelocityConstraints for the HoleCam and StairsCam" "6134": "Run the game to try triggering the StairsCam, and investigate the snapping" "6533": "handmade_world_mode.cpp: Determine to enable UpdateAndRenderWorld() to correctly update the camera position when changing sim region" "7037": "Q&A" "7072": "There seems to be a second problem with StairCam 1 vs StairCam 2, i.e. you need to be moving even though you're on the first stair, so the collision areas are out a bit?" "7118": "Why are the trees below smaller than the trees up top?" "7296": "Are you going to experiment zooming by changing the FOV rather than changing the distance?" "7329": "Why use velocity and not, for instance, acceleration as a constraint parameter?" "7363": "Why are the health bars flickering? Seems to be most noticeable when the hero is at standstill (the familiars move all the time and they don't flicker as much)" "7410": "handmade_entity.cpp: Enable DrawHitpoints() to prevent Z-fighting" "7459": "Off-topic: Is it normal for a trivial code change to lead to a 250MB diff file? Is this optimization / MIPS architecture weirdness?" "7518": "What do you want to fit in the camera view? Whole room, or some amount of tiles so camera movement per room is needed" "7553": "Hey Casey, in the PushBitmap function of the handmade_render_group you have a shadowed v4 parameter Color that is masked by the u32 Color. Compiles as a warning (to an error) in VS 2015" "7641": "handmade_render_group.cpp: Move in PushSetup() and transient_clip_rect from handmade_render_group.h" "7759": "Does the profiler still work? If not, what is a quick overview of the work that is needed to get it working again? And was it purely a display issue that we could not see it?" "7840": "handmade_render_group.cpp: Fix GetClipRect() to correctly clip the profiler's text" "8139": "handmade_render_group.cpp: Introduce GetScreenPoint() for GetClipRect() to call" "8351": "Run the game to see that it's getting closer to working" "8403": "Blackboard: Mapping screen dimensions to -1 to 1" "8538": "handmade_opengl.cpp: Try disabling the ClipRect bounds setting" "8793": "Run the game to see what's going on with the clipping" "8889": "Thanks Casey, appreciate you walking through it" "8924": "handmade_render_group.cpp: Temporarily prevent the clipping from occuring and run the game to see that" "8981": "Can you click "Threads" on the Profile window?" "9075": "Is the mouse over text working now?" "9115": "Sign off" --- name: "day379" title: "Debug Overlay Cleanup and Render Group Performance Investigation" markers: "30": ""Today's episode might be a little bit of a potpourri"" "66": "Determine to address the "Fix for profiler clipping issue on threads/frames/clocks view" issue" "127": "Run the game and demo the incorrect clipping of the profiler" "234": "handmade_render_group.cpp: Fix GetClipRect() to use Rectangle.Min" "300": "Run the game to see that the profiler clipping is fixed" "360": "handmade_debug.cpp: Make DEBUGStart() offset the text Z" "502": "Run the game to see that the text drop-shadow looks correct" "548": "handmade_debug.cpp: Greatly increase the Z offset for the tooltip, so it draws above the profile bars" "620": "Run the game to see the tooltip box above the profile bars, but not its text contents, and discuss possible reasons why" "1073": "handmade_debug_ui.cpp: Consider simplifying the text system" "1448": "handmade_debug_ui.cpp: Enable DrawTooltips() to draw its text above everything" "1502": "Run the game to see our tooltip text back" "1696": "handmade_debug_interface.h: Temporarily conditionally append the function name to the UniqueFileCounterString__" "1759": "Run the game to see those function names" "1842": "handmade_debug.cpp: Enable DrawProfileBars() and DrawFrameBars() to put the Element->Name in their tooltip" "1979": "Run the game to see our complete tooltips" "2056": "Investigate why UpdateAndRenderEntities() takes so much time" "2230": "Run the game to see that the EntityRender routine is the main culprit" "2385": "handmade_entity.cpp: Further Isolate EntityRender" "2461": "Run the game to see that RenderVolume and RenderPieces are both slow" "2484": "Investigate this slowness" "2623": "Step through the assembly for the RenderPieces block" "2836": "handmade_render_group.cpp: Rewrite GetBitmapDim() without function overloading" "3040": "Inspect the assembly for the RenderPieces block and note that GetBitmapDim() has now been inlined, as has PushQuad()" "3423": "Investigate why RoundReal32ToInt32() isn't being inlined" "3569": "Determine to excise roundf()" "3655": "Consult the Intel Intrinsics Guide for rounding instructions" "3833": "handmade_intrinsics.h: Make RoundReal32ToInt32() and RoundReal32ToUInt32() use _mm_cvtss_si32()" "3925": "Run the game to see that RenderPieces now takes 0.87% of the time, and consider the importance of profiling and looking at the assembly" "4167": ""Death by a thousand function calls"" "4205": "Investigate why the RenderVolume block takes a lot of time" "4255": "Inspect the assembly for PushLineSegment()" "4427": "handmade_intrinsics.h: Make SquareRoot() use _mm_sqrt_ss()" "4669": "Run the game to see that that just works, but that RenderVolume is not faster" "4805": "handmade_opengl.cpp: Add some debug timing blocks in OpenGLRenderCommands()" "4950": "Run the game to see that OpenGL::TexturedQuads takes the most time, and investigate why" "5151": "Consider how to speed up passing the textures to the GPU" "5288": "handmade_opengl.cpp: Experiment with ways to speed up the OpenGL::QuadLoop block in OpenGLRenderCommands()" "5741": "Run the game to see garbage, note the speed up of the block, but back out those changes in favour of potentially using texture arrays" "5900": "Run the game to see that the cutscene does not work with the new 3D system" "5973": "Calculate how large of a texture array we would need for the cutscene" "6186": "handmade_cutscene.cpp: Reacquaint ourselves with the cutscene code" "6569": "Run the game and try to interpret how the cutscene is being drawn" "6614": "handmade_render_group.cpp: Make SetCameraTransform() take the NearClipPlane and FarClipPlane" "6799": "handmade_cutscene.cpp: Make RenderLayeredScene() specify the clip planes" "6827": "Run the game and note that our distance based fog is knocking out some of the cutscene" "6868": "handmade_render_group.cpp: Make SetCameraTransform() take Fog" "6994": "Run the game to see all the pieces of the cutscene" "7083": "handmade_cutscene.cpp: Make RenderLayeredScene() set the FocalLength and run the game to see it" "7305": ""Where Santa Claus went, I don't know"" "7317": "Run the game and investigate where Santa Claus went" "7725": "Discover that the w values passed to PushQuad() are not all 0" "7797": "handmade_render_group.cpp: Make PushBitmap() only set the ZBias for upright sprites" "7824": "Run the game to see that Santa Claus is back" "7830": "Q&A" "7865": "What will be our way forward to reduce glDrawArray calls? Will we look into texture atlases, megatextures, or invent our own way? Is it better to separate cutscene rendering because it's so different?" "7923": "Are we forced to use SIMD registers to use those intrinsics or are there some ways to do that without those, like inline assembly or something else?" "8208": "Have you seen musl standard library? It has very good code quality. sqrtf on x86_64 is one instruction on it. It's for Linux, but parts of it are very portable" "8477": "Do you know whether the sqrt function in math.h uses processor instructions or calculates the results via some software algorithm?" "8622": "Close it down" --- name: "day380" title: "Attempting (and Failing) to Fix the Clock" markers: "2": "Recap and set the stage for the day" "164": "Run the game, consult the profiler and note that the game only updates itself as if it's running at 60FPS" "591": "Determine to enable the game to play properly at various frame rates" "753": "win32_handmade.cpp: Temporarily set TargetSecondsPerFrame to twice the expected rate, and run the game to see that it feels like the 60FPS version" "1014": "win32_handmade.cpp: Initialise TargetSecondsPerFrame in the game loop" "1282": "Blackboard: Computing the TargetSecondsPerFrame based on observed seconds elapsed" "1497": "win32_handmade.cpp: Compute MeasuredSecondsPerFrame and ExactTargetSecondsPerFrame" "1566": "Blackboard: Rounding seconds, accounting for jittering" "1618": "Run the game to show the jittering frame rate" "1730": "win32_handmade.cpp: Round the ExactTargetSecondsPerFrame and run the game to show that" "1814": "win32_handmade.cpp: Make the debug system display the ExpectedFramesPerUpdate" "1900": "Run the game and consult the profiler to see the ExpectedFramesPerUpdate oscillating" "2074": "win32_handmade.cpp: Consult the documentation on wglSwapInterval" "2260": "win32_handmade.cpp: Pass 2 to wglSwapInterval(), run the game and investigate what wglSwapInterval is doing" "2451": "Temporarily disable HANDMADE_STREAMING and run the game to see that the wglSwapInterval works more correctly" "2644": "Determine the refresh rate of the monitor" "2880": "win32_handmade.cpp: Set the TargetSecondsPerFrame to the MeasuredSecondsPerFrame of the previous frame" "2973": "Run the game and note all the jitter" "3076": "Try (unsuccessfully) to set a Swap Interval Override in the video driver" "3419": "Run the game and note that the movement speed is correct at lower frame rates" "3623": "Determine to get back to working on the camera, fading out floors above the hero" "3696": ""ATI peed on our cake"" "3724": "Run the game and consider how to fade out upper floors" "3782": "handmade_world_mode.cpp: Increase the NearClipPlane and run the game to see that upper floors have been clipped out, and peel away gradually while moving between floors" "3968": "handmade_opengl.cpp: Enable the shader to modulate the fragments' alpha amounts by their distance from the camera" "4095": "Run the game to see how that looks" "4313": "Blackboard: The original idea for clipping out upper levels" "4413": "Blackboard: Depth peel" "4600": "Blackboard: Depth peel vs multi-sampling with alpha to coverage" "4890": "handmade_opengl.cpp: Enable OpenGLRenderCommands() to handle GL_TEXTURE_2D slots" "5299": "Run the game without multisampling on" "5375": "Blackboard: Comparing two depth buffers" "5473": "handmade_opengl.cpp: Introduce a DepthSampler" "5607": "Consult the documentation on gl_FragCoord" "5805": "handmade_opengl.cpp: Enable the DepthPeel code to discard fragments nearer the camera than the ClipDepth" "5987": "handmade_opengl.h: Introduce opengl_program struct and CompileZBiasProgram()" "6272": "handmade_opengl.cpp: Introduce UseProgramBegin() and UseProgramEnd()" "6502": "handmade_opengl.cpp: Make the shader call CompileZBiasProgram() for NoDepthPeel and DepthPeel, and fix compile errors" "6815": "Run the game to see that we can run the DepthPeel and regular versions" "6853": "Q&A" "6953": "While we wait for other questions, have you had a good experience with gdb?" "7190": "How to stabilize the volume outlines?" "7233": "handmade_render_group.cpp: Make PushLineSegment() give the debug line segments some ZBias" "7274": "Run the game to see that the Z-fighting has gone" "7319": "To follow the rule of writing the usage code first, don't believe that the project is at a point where it is better to advance in the game now, and when the game needs more engine features, then go and implement them?" "7592": "Clarification: what to do when the angles are too close together?" "7622": "The debug text is drawing behind tree sprites, by the way" "7651": "handmade_render_group.h: Add a depth_clear render_group_entry_type and introduce PushDepthClear() for DEBUGStart() to call" "7797": "Run the game to see the debug text always drawn on top" "7837": "Do you have any idea when the engine layer will be finished, and you move to just gameplay programming?" "7901": "I'm not sure if the profiler shows some insightful information about CPU cache hit / miss rates. How might you implement something like that?" "8068": "Can the depth buffer contain infinity as a floating point value?" "8184": "Off-topic: What part of game programming do you enjoy the most? Engine, gameplay, etc?" "8202": "Close things down" --- name: "day381" title: "Two-pass Depth Peeling" markers: "8": "Recap and set the stage for the day" "41": "Note a couple of things in milton to fix, syncing and stuttering" "91": "Blackboard: Using atomics to write more than one piece of information to a framebuffer" "306": "Blackboard: Depth Peeling, as a lighter version of atomics" "640": "Could we get rid of multisampling altogether?" "787": "Run the game and point out the beautiful fade out" "922": "handmade_opengl.cpp: Disable multisampling and alpha to coverage, and run the game to show what it looks like" "1094": "handmade_opengl.cpp: Determine to implement just the alpha compositing part" "1442": "handmade_opengl.cpp: Enable the render loop to properly prepare and target the render buffers for depth peeling" "1683": "Blackboard: Front and Back Pictures" "1714": "handmade_opengl.cpp: Disable GL_BLEND and write out the values directly into the framebuffer" "1758": "Run the game to see the front picture" "1816": "Blackboard: The contents of the Front and Back Pictures" "1943": "handmade_opengl.cpp: Enable OpenGLRenderCommands() to target a second framebuffer" "2231": "handmade_opengl.cpp: Enable the textured_quads case to assume that the framebuffer is bound properly" "2295": "Run the game to see the front buffer still there" "2309": "handmade_opengl.cpp: Enable UseProgramBegin() to bind the DepthSampler framebuffer" "2532": "handmade_opengl.cpp: Enable OpenGLRenderCommands() to read from more than one texture" "2866": "win32_handmade.h: Pull in glActiveTexture() from corearb.h" "2926": "Run the game to see everything working fine" "2966": "handmade_opengl.cpp: Display GlobalFramebufferHandles[1] and run the game to see that back buffer" "2989": "handmade_world_mode.cpp: Make UpdateAndRenderWorld() call BeginDepthPeel() and EndDepthPeel()" "3121": "handmade_render_group.h: Introduce BeginDepthPeel() and EndDepthPeel()" "3149": "Run the game and hit a glActiveTexture error" "3177": "win32_handmade.h: Pull in the glActiveTexture() enums from corearb.h" "3223": "Run the game to see the depth peel, and note that the depth comparison is not reliable" "3345": "handmade_opengl.cpp: Enable the FragmentCode to draw the FragZ" "3511": "Run the game to see the interesting Z values" "3613": "handmade_opengl.cpp: Switch to showing the front buffer and run the game to see that it looks correct" "3664": "Run the game and note that all except the white texture is wrong" "3799": "handmade_opengl.cpp: Investigate where we're sampling from, and how the framebuffer is stored" "4161": "handmade_opengl.cpp: Try to move FragZ into the 0 to 1 range, and make it a floating point depth buffer" "4267": "Run the game and note that it's oddly accurate for the white textured cubes" "4345": "handmade_opengl.cpp: Enable culling" "4486": "Run the game and determine that everything in the game is wound backwards" "4577": "Blackboard: Winding" "4626": "handmade_render_group.cpp: Double-check that the code should be winding it properly" "4711": "handmade_opengl.cpp: Try unsuccessfully to switch to using GL_QUADS" "4910": "handmade_opengl.cpp: Switch to GL_TRIANGLES" "4961": "Run the game to confirm that we are binding triangles correctly, but that the triangle strips must be backwards" "4982": "handmade_render_group.cpp: Fix PushQuad() to push the vertices in the right order" "5022": "Run the game to see our culling working properly" "5084": "Determine to ruminate on the incorrect non-white textures" "5171": "handmade_opengl.cpp: Introduce CompilePeelComposite()" "5903": "handmade_opengl.cpp: Enable OpenGLRenderCommands() to composite the depth peels" "6279": "handmade_opengl.cpp: Just a pass a colour to the shader, so we have less variability" "6409": "Run the game to see our composited picture" "6486": "handmade_opengl.cpp: Determine to ensure that the shader is passing the colour without alpha" "6656": "Blackboard: Solving for unadulterated red" "6688": "handmade_opengl.cpp: Make the shader undo the alpha modulation of the colours" "6762": "Run the game to see our current status" "6809": "handmade_opengl.cpp: Double-check the frame buffer creation code" "6894": "Step in to OpenGLRenderCommands() and inspect the frame buffers" "6952": "handmade_opengl.cpp: Make OpenGLRenderCommands() loop over the correct frame buffers" "6982": "Run the game to see that we're much better" "7020": ""Happy day happiness of special deliciousness"" "7032": "Determine to implement the depth peel shader tomorrow" "7051": "Q&A" "7099": "I tend to see in a lot of APIs (for example SDL) things like DestroyWindow calls. If this is the last thing you do before exiting the app, doesn't the operating system take care of this for you?" "7185": "Have you considered keeping the shader code as separate files so you can do automatic reload on save in the editor, for example, or do you think there won't be enough shader code to motivate the work?" "7255": "handmade_opengl.cpp: Investigate why glDrawArrays() is busted" "7420": "I think your last hardcoded giant triangle strip UV mapping coordinate has a cut and paste error. Should be {1.0, 0.0} instead of {1.0, 1.0}?" "7432": "handmade_opengl.cpp: Fix the final coordinate in Vertices and run the game to see that that wasn't enough to save us" "7450": "By the way, it was pointed out that the compatibility bit only works in 3.2+ (and I think you specify 3.0 currently)" "7459": "A bit off-topic, but why is not The Jeff and Casey Show Season 5 on the Molly Rocket website?" "7487": "Consider what may be going wrong in our shader" "7652": "I was told that you had some issue(s) with RenderDoc. Do you know if it was related to you having a old GPU or was it a real bug in Renderdoc?" "7732": "Could you view in the debugger and see if the shader outputs sensible values?" "7750": "In the future when Jon Blow's language is released for public (in case it will be before Handmade Hero completion), will you switch to use it for finishing unfinished parts of the game, or would you stay with C/C++ until the bitter end?" "7818": "That is it" --- name: "day382" title: "Depth Peel Compositing" markers: "3": "Recap and set the stage for the day" "170": "Run the game to take a look at the situation as it stands" "351": "handmade_opengl.cpp: Establish that we can set the viewport correctly" "628": "handmade_opengl.cpp: Simplify the shader down so that it just draws red" "851": "Step through OpenGLRenderCommands() to verify the vertex data" "1083": "handmade_opengl.cpp: Correctly set the vertices' W coordinates" "1178": "Run the game to see red where we expect" "1241": "handmade_opengl.cpp: Remove our debug test code" "1332": "Run the game to see that our composite is working" "1348": ""Cheers"" "1361": "handmade_opengl.cpp: Verify that we can read from our framebuffers and run the game to see that the Peel0 value is wrong" "1426": "handmade_opengl.cpp: Investigate what is wrong, noting that AMD wasn't letting us use multisampling sRGB" "1574": "handmade_opengl.cpp: Make the shader perform the blend without sRGB, and run the game to see that it looks close to correct" "1760": "handmade_opengl.cpp: Enable OpenGLInit() to use sRGB without multisampling, and run the game to see that the halo has gone, but the trees have fringing" "1949": "handmade_opengl.cpp: Make OpenGLRenderCommands() only clear the top layer, and run the game to see that the fringing has gone" "2014": "Consider how best to handle multiple overlapping alpha'd elements" "2122": "Blackboard: Alpha + Z Buffer" "2209": "Blackboard: The standard way of handling transparency in multiple passes" "2315": "Blackboard: A smarter way of handling transparency" "2593": "Blackboard: Single Framebuffer, Multiple Depth Peels" "2865": "handmade_opengl.cpp: Make OpenGLRenderCommands() always draw to the same colour buffer and blend multiple depth peels into it" "3154": "Run the game to see Z fighting" "3264": "handmade_opengl.cpp: Investigate the Z fighting" "3415": "Realise that we do need two colour buffers for sorting, and back out our single-buffer code" "3552": "handmade_opengl.cpp: Make OpenGLRenderCommands() write into multiple depth buffers, and the shader sample from multiple peels" "3955": "handmade_opengl.h: Split opengl_program out into new zbias_program and peel_composite_program structs" "4177": "handmade_opengl.cpp: Introduce versions of UseProgramBegin() that take these new structs" "4419": "Run the game and look at the different peels" "4471": "handmade_opengl.cpp: Enable OpenGLRenderCommands() to draw to all the peels" "4608": "Run the game and investigate the failing compositing" "4756": "handmade_opengl.cpp: Make CompilePeelComposite() copy the peels across, run the game and only see the profiler" "5025": "handmade_opengl.cpp: Gather up the first texture into all the peels" "5078": ""You can't just start talking about variables that don't exist yet"" "5083": "handmade_opengl.cpp: Investigate the incorrect blitting" "5207": "handmade_opengl.cpp: Make OpenGLRenderCommands() correctly set the ActiveTexture, and run the game" "5274": "handmade_opengl.cpp: Enable everything until we're back at the composite path, and run the game" "5361": "handmade_opengl.cpp: Investigate how we are doing the peel composite" "5540": "Run the game and note that the depth peel doesn't handle identical Z values" "5624": "handmade_particles.cpp: Make SpawnFire() randomise the P.z" "5821": "Run the game and consider making a more controlled test case" "5864": "handmade_particles.cpp: Make SpawnFire() throw the particles upwards in Z" "5950": "Run the game to admire the particles" "5962": "handmade_particles.cpp: Make SpawnFire() give the particles more poof, and run the game to admire them" "6137": "handmade_opengl.cpp: Determine that we only have two peels and investigate why" "6376": "Step into CompilePeelComposite() and inspect the PeelSampler values and GlobalFrameBufferTextures" "6691": "handmade_opengl.cpp: Make OpenGLRenderCommands() not mipmap the textures when binding" "6787": "Run the game to see that that fixed it" "6833": "handmade_opengl.cpp: Reenable everything and perform the full blend" "6872": "Run the game to see that it looks quite nice" "6952": "handmade_opengl.cpp: Work towards enabling CompileZBiasProgram() to alpha fade the clip plane" "7328": "Run the game to see the awesome depth peel at half alpha" "7370": "handmade_opengl.cpp: Complete implementing the near clip plane fading" "7717": "Run the game to admire the near clip plane fading" "7792": "Q&A" "7811": "Note that it doesn't seem to line up with the near clip plane" "7845": "handmade_world_mode.cpp: Increase the NearClipPlane and run the game to see it" "7970": "Could you try disabling the randomisation of the ground tile Z? I'm interested to see if that'll adversely affect the sexiness of the depth peel" "8006": "handmade_world_mode.cpp: Temporarily disable the randomisation and run the game to see that" "8068": "Debug menu's broken now" "8095": "handmade_render_group.cpp: Make SetCameraTransform() correctly set the clip alpha distances for the debug menu, and run the game" "8190": "For depth peeling: would it be possible to discard all pixels in the 2nd layer that have an alpha value of 255 in the front layer because they are not interesting for the composition anyway?" "8360": "I'm behind on day 130, just finished the SIMD / thread introduction. What feature of the game eventually forced you to use the GPU? (Totally love the software rendering)" "8472": "Is the game going to be more 3D-ish gameplay-wise than originally planned?" "8552": "So is the depth peeling being used for order-independent transparency with the sprites?" "8624": "Can you go into more detail on what fixed layers 2 / 3 from being all black? It wasn't an old card only being able to read two textures, but I missed the actual resolution" "8644": "OpenGL assumes that textures are mipmapped" "8812": "Do you actually have to have wireframe models to be considered 2.5D, or would this count as well?" "8908": "You could define your own render definition for HMD" "8987": "Is the floor below us being drawn completely and the one we are on on top of it, or is the one below clipped so only the pixels we see through the holes are drawn?" "9093": "Wrap it up with a glimpse into the future of new art integration" --- name: "day383" title: "Fixing Depth Peel Artifacts" markers: "22": "Recap and set the stage for the day, improving the depth peeling" "134": "Run the game, note the rendering artifacts while depth peeling, and consider what may be causing them" "443": "handmade_opengl.cpp: Consider how CompilePeelComposite() is computing the ResultColor" "616": "handmade_opengl.cpp: Make CompilePeelComposite() clamp the ResultColor to 0 to 1" "657": "Run the game to see that that did not improve our situation, but did change our background colour" "703": "handmade_opengl.cpp: Investigate how CompilePeelComposite() is drawing the peels" "958": "Run the game to determine that the alpha inverse computation is wrong" "1004": "handmade_opengl.cpp: Prevent CompilePeelComposite() from putting alpha in Peel3" "1068": "handmade_opengl.cpp: Make CompilePeelComposite() clamp the colours again, and run the game to determine that this part of the composite is not the problem" "1156": "handmade_opengl.cpp: Make CompilePeelComposite() colour the peels" "1270": "Run the game to see the coloured peels" "1363": "handmade_opengl.cpp: Make CompilePeelComposite() multiply the peel colour by its alpha, and run the game to see that the error occurs where many peels overlap" "1517": "handmade_opengl.cpp: Enable CompileZBiasProgram() to fog pixels out before their alpha is 0" "1579": "Run the game and erroneously see colour on pixels that should have been fogged completely out" "1687": "handmade_opengl.cpp: Make CompileZBiasProgram() correctly clip out transparent pixels from the depth peel" "1781": "Run the game to see that we're a lot better" "1907": "handmade_opengl.cpp: Try making CompileZBiasProgram() draw Peel3 as bright pink and run the game to see purple where the artifact occurs" "2030": "Consider how best to mix the peels together" "2186": "Blackboard: Depth Peel Sandwich" "2426": "Run the game and think about what's actually happening with the artifact" "2604": "handmade_opengl.cpp: Enable CompileZBiasProgram() to draw something in the last peel above a given alpha threshold" "2898": "Run the game to see that that did help" "3051": "handmade_opengl.cpp: Make OpenGLRenderCommands() clear the alpha to 1, and the shader to undo the premultiplied alpha" "3140": "Run the game to see that it looks worse" "3173": "handmade_opengl.cpp: Note that our art asset packer does not handle sRGB" "3354": "handmade_opengl.cpp: Consider that clamped values cannot be used at the vertex level" "3432": "Blackboard: Incorrect clamping" "3490": "handmade_opengl.cpp: Make the FragmentCode itself in CompileZBiasProgram() clamp and compute the fog" "3534": "Blackboard: Vertex and Fragment Shader Output" "3623": "Run the game, crash in shader compilation and reorganise the code" "3699": "Run the game to see that the effect is very different, and the artifact is gone" "3878": "Note that we probably would still want to use multisampling on fast GPUs" "4006": "handmade_opengl.cpp: Begin to enable OpenGLRenderCommands() to conditionally perform multisampling" "4388": "Consider changing the renderer to draw at the size at which the game is running" "4627": "handmade_opengl.cpp: Change OpenGLRenderCommands() to draw at the correct aspect ratio" "4866": "Run the game to see the correct letterboxing" "4901": "handmade_opengl.cpp: Enable OpenGLBindFramebuffer() to blit to the correct size" "5111": "Run the game to see that it's nice and clean" "5138": "win32_handmade.cpp: Draw to a lower resolution, stretched up" "5162": "Run the game and see some weird artifacts and investigate those artifacts" "5313": "handmade_opengl.cpp: Try to force real sRGB off" "5407": "Run the game and consider that, because the alpha is not computed with sRGB, it does not line up right when stretched" "5478": "handmade_opengl.cpp: Consider that the bilinear filter on the depth peel composite may not be correct" "5627": "handmade_opengl.cpp: Make OpenGLRenderCommands() use a raw texel sample in the depth peel" "5678": "Run the game to see that the fringing while stretching has gone" "5702": "Blackboard: Correctly sampling from texels for stretching" "5965": "handmade_opengl.cpp: Determine to composite to an intermediate framebuffer, and then stretch that to the final image" "6177": "handmade_opengl.cpp: Introduce CompileFinalStretch()" "6514": "handmade_opengl.cpp: Introduce CreateFramebuffer()" "7023": "handmade_opengl.cpp: Enable CreateFramebuffer() to conditionally apply filtering" "7117": "handmade_opengl.cpp: Make OpenGLRenderCommands() create the final GlobalResolveFramebuffer" "7354": "Run the game to admire the correct composite and then stretching" "7415": "win32_handmade.cpp: Draw to decreasingly smaller resolutions" "7558": "Run the game in pixel art mode" "7624": "Q&A" "7656": "OpenGL sucks" "7856": "The problem is there is no way for me to know what the "good API" is any more..." "8070": "In Win32InitOpenGL(), why do you use two different forms for assigning modern OpenGL function pointers, i.e. using Win32GetOpenGLFunction(Name) macro for some but assigning others directly?" "8101": "Just so you know, your stream no longer shows up in either the "Game Development" or "Programming" categories on twitch. It's almost a hidden stream now just for those who already followed" "8170": "I tried your anonymous union and structs trick and the compiler (g++) screams at me saying I need some label in the struct name to conform to the standard. So I looked it up on google and it appears to be undefined behavior to use this trick. Should I be afraid of that?" "8396": "The cursor always seems to be on the loading(?) icon. Is there a way to fix that? (I'm running into this issue and am not sure if there is some windows message I need to process)" "8418": "win32_handmade.cpp: Try to stop the wait cursor displaying once we have finished loading" "8918": "You can set the cursor on the WNDCLASS struct .hCursor = LoadCursor(0, IDC_ARROW);" "9006": "You said on one stream that you don't need header guards because you have only one translation unit. I guess you meant that you're sure you only include each header once? Because even if you only have one translation unit you still can have problems if you include the same header twice" "9097": "Multiple anonymous unions inside one struct, is that allowed?" "9157": "Wrap it up with a plug of Lysa" "9319": "Promote CaptainKraft's Patreon" "9421": "That's about it for today, with a glimpse into the future" --- name: "day384" title: "Dynamically Responding to Render Settings" markers: "8": "Recap and set the stage for the day" "71": "Run the game with the determination to enable dynamic responding to render settings" "248": "A few words on our good fortune with GPU programming" "312": "handmade_opengl.h: Introduce hardware_rendering_switches" "489": "handmade_opengl.cpp: Remove the render_entry_blend_render_target case from OpenGLRenderCommands(), and PushBlendRenderTarget()" "580": "handmade_platform.h: typedef b32x and u32x with a description of these types" "697": "handmade_platform.h: Introduce game_render_setings" "843": "handmade_opengl.cpp: Break OpenGLRenderCommands() out into OpenGLPrepareForSettings() which conditionally enables features based on the game_render_settings" "1843": "handmade_opengl.h: Add necessary data to the open_gl struct and begin to clean up compile errors" "1994": "handmade_platform.h: Introduce AreEqual()" "2122": "Rant on the approach of C++ to automating specific instances of programming routines, rather than providing flexible general tools" "2488": "handmade_opengl.cpp: Fix up compile errors in OpenGLRenderCommands()" "2660": "handmade_platform.h: Change the RenderCommandStruct() macro to DefaultRenderCommands()" "3071": "handmade_opengl.cpp: Enable OpenGLBindFramebuffer() to work without the GlobalFramebuffer variables" "3342": "Run the game and crash in CreateFramebuffer()" "3361": "handmade_opengl.cpp: Force multisampling to off, run the game, crash in CreateFramebuffer() and investigate why" "3604": "handmade_opengl.cpp: Make OpenGLRenderCommands() pass the new settings to OpenGLPrepareForSettings(), renamed to OpenGLChangeToSettings()" "3643": "Run the game and see a grey screen" "3666": "Re-emphasise that, if on more recent hardware, we would switch to a graphics debugger" "3840": "handmade_opengl.cpp: Hard set values in the OpenGL pipeline in order to diagnose the bug" "4428": "handmade_opengl.cpp: Enable OpenGLRenderCommands() to target our framebuffers" "4483": "Run the game to see that we're getting closer" "4494": "handmade_opengl.cpp: Change how OpenGLRenderCommands() renders to our depth peels" "4716": "Run the game to see that something else is messed up" "4743": "win32_handmade.cpp: Make DefaultRenderCommands() reset the RenderCommands" "4824": "Run the game to see that we're not quite depth peeling" "4854": "handmade_opengl.cpp: Make OpenGLRenderCommands() bind the framebuffer at the end of the depth peels" "5093": "Run the game to see that it looks correct" "5110": "handmade.cpp: Add some render settings to the debug system" "5181": "Run the game, try changing these render settings and determine to enable multisampling and clean-up" "5253": "Check the time" "5266": "87 minutes into the main stream. 33 until Q&A. (based on NOTE)" "5282": "handmade_opengl.cpp: Introduce FreeFramebuffer() and FreeProgram() for OpenGLChangeToSettings() to call" "5795": "Advertise the Web" "5836": "win32_handmade.cpp: Pull in glDeleteProgram(), glDeleteShader() and glDeleteFrameBuffers() from glcorearb.h" "5984": "Run the game and note that there isn't a good way to test our resource freeing code without GPU debugging tools" "6082": "handmade_opengl.cpp: Add a TODO in OpenGLChangeToSettings() to use a tool to test our freeing code" "6151": "handmade_opengl.cpp: Make OpenGLChangeToSettings() correctly free the depth peel buffer" "6182": "Run the game and try to gauge if we are correctly freeing" "6258": "Consult the documentation on glGet()" "6327": "handmade_opengl.cpp: Add a TODO in OpenGLChangeToSettings() to fix the enabling of multisampling" "6486": "Q&A" "6544": "So one of my left-field questions: Do you think there is a case to be made for a GL implementation to be written in OpenCL, OpenCL having the capacity to natively run on the CPU and is compatible with visual studio, so you could CPU debug your OpenGL code in visual studio. Would that capacity solve the OpenGL debug problem, or is the problem typically somewhere else, like actual problems with opaque GPU functionality, if that all made sense?" "6577": "Rant on GPU programming" "7129": "Casey, I've started to program more like the way you teach and I'm liking it so far, but there's one thing that makes me feel strange: When using structs to set up some data that will be used by a function later, how can I make sure that I won't forget to set some member of that struct before calling that function? Is there a way to make sure I always initialize every member of the structure to a value (other than zero)?" "7231": "Why do you typedef some structs in the render layer, but not all of them?" "7294": "Casey, do you remove asserts when shipping a game?" "7306": "In a sense, Vulkan provides you an ISA with strict specification, but the initialization code is quite fat" "7441": "I didn't quite understand how OpenGL and multithreading can cooperate. I believe you once said in an episode that an OpenGL context is specific to the thread that created it. So if I create the context on a main thread, can I not have other worker threads call into OpenGL without somehow setting the context for each thread?" "7711": "We're done" "7814": "Plug Lysa" --- name: "day385" title: "Trying Multisampled Depth Peels" markers: "28": "Recap and set the stage for the day" "106": "Run the game and demo the aliasing around our geometric primitives" "388": "Describe the two processes at play: Artistic and Analytical Antialiasing" "655": "Consider our two options for handling this: Multisampling and Conservative Rasterization" "1089": "handmade_opengl.cpp: Review our depth peeling for sprite rendering" "1304": "handmade_opengl.cpp: Determine to enable OpenGLChangeToSettings() to perform multisampling only on the front-most depth peel buffer" "1580": "handmade_opengl.cpp: Consider how to perform the composite" "1862": "handmade_opengl.cpp: Add ResolveHandle to opengl_framebuffer, and introduce SetDefaultFramebufferTextureParameters() and FramebufferTexImage()" "2462": "handmade_opengl.cpp: Enable CreateFramebuffer() to create a ResolveFramebuffer for multisampling" "2607": "Run the game to make sure that it works okay" "2618": "handmade_opengl.cpp: Enable the multisampling path" "2849": "Note that we cannot render from a multisampled texture as if it was a regular texture" "2940": "handmade_opengl.cpp: Look into making OpenGLRenderCommands() conditionally bind depending on whether or not we're multisampling" "2994": "handmade_opengl.cpp: Back out our changes and instead just create two framebuffers: one multisampled, one not" "3193": "handmade_opengl.cpp: Make OpenGLRenderCommands() set the correct PeelBuffer for multisampling" "3278": "handmade_opengl.cpp: Introduce GetDepthPeelReadBuffer()" "3383": "Run the game to see a black screen, as expected" "3403": "handmade_opengl.cpp: Enable OpenGLRenderCommands() to resolve our framebuffers" "3612": "Run the game to see that everything appears at first glance to be working, but is a lot slower than we'd like" "3803": "Consider using conservative rasterization" "3933": "Determine to do everything multisampled, consulting the OpenGL documentation for sampler2DMS" "4466": "When evaluating a given sample from a multisampled buffer, we want to get its corresponding depth sample" "4672": "Note that conservative rasterization would definitely solve our problem" "4771": "Consult the OpenGL Hardware Database to see which cards support GL_NV_conservative_raster and GL_INTEL_conservative_rasterization" "4844": "Run the game and consider what's causing the slowness" "4957": "handmade_opengl.cpp: Toggle back to non-multisampling, run the game to see that the frame rate is fine, and continue considering the slowness" "5077": "handmade_opengl.cpp: Determine to enable the multisampling path to pick the closest depth value" "5449": "handmade_opengl.cpp: Introduce ResolveMultisample()" "5911": "handmade_opengl.cpp: Introduce CompileResolveMultisample() shader" "6349": "Begin to consider the dilemma surrounding the averaging process" "6468": "handmade_opengl.cpp: Fix compile errors" "6533": "Q&A" "6586": "I think it will be useful to bind a key to topmost window as there is a key to full screen, then you will not have to resize your editor for live code editing. Also, since I bound the ` key to -> in my editor I'm a very happy panda, warm recommendations" "6627": "Why s32 for the count, instead of u32?" "6663": "Could you up the bitrate? It's really hard to watch when there's too much movement on the screen. It gets all blurry and pixelated. Not exaggerating when I say it makes my eyes watery" "6770": "Wrap things up with a plug of the episode guide's new search feature" --- name: "day386" title: "Implementing a Custom Multisample Resolve" markers: "22": "Recap our depth-peeling-with-multisampling puzzler and set the stage for the day" "232": "cheap and easy solution for enabling multisampled antialiasing on the target platform" "330": "Describe an old method to perform smoothing, using glHint and glEdgeFlag" "619": "Consult the OpenGL 3.2 Specification for POLYGON_SMOOTH" "763": "handmade_opengl.cpp: Disable multisampling in OpenGLChangeToSettings()" "812": "handmade_opengl.cpp: Try turning on GL_POLYGON_SMOOTH_HINT in OpenGLRenderCommands()" "869": "Run the game and see no difference" "959": "handmade_opengl.cpp: Reenable multisampling back on in OpenGLChangeToSettings(), and run the game to see that it's much slower" "1039": "Consider why the multisampling is so much slower" "1150": "win32_handmade.cpp: Switch to a lower resolution and run the game to see that the frame rate is fine now" "1200": "Inspect the artifacts caused by the multisampling failing to pick from the correct value for depth peeling" "1359": "Consult Wikipedia to see if the discard creates a place where things will get sampled more" "1487": "Run the game and assess the quality improvement brought by multisampling, if only the depth picking was correct" "1705": "Consider drawing some structured art to help us diagnose this artifacting" "1845": "handmade_opengl.cpp: Make CompileZBiasProgram() hard set the ModColor.a to 0.5, and run the game to validate where the artifacts occur" "1987": "Consider the possibility that we don't have a problem at all, if we include the 1-pixel transparent border, or only evaluate the Z value at the centroid" "2142": "Consult the OpenGL ES Shading Language specification on the storage qualifiers centroid" "2302": "handmade_opengl.cpp: Try to make CompileZBiasProgram() preserve the FragZ coordinate across all depth buffers" "2655": "Run the game to see Z-fighting" "2682": "handmade_opengl.cpp: Make CompileZBiasProgram() correctly set that FragZ" "2780": "Run the game and still see the artifacts" "2824": "handmade_opengl.cpp: Undo those changes in CompileZBiasProgram()" "3028": "Look closely at the tree bitmap, and consider inserting a 1-pixel border around everything" "3350": "Read about CLAMP_TO_BORDER in the OpenGL 3.2 spec" "3491": "Read about gl_FragDepth in the OpenGL Shading Language 4.3 spec" "3851": "Consider our two things at play: We only get artifacts where multisampling occurs at the edges of primitives; perhaps the resolve is picking a bad Z value" "4054": "handmade_opengl.cpp: Consider how to fix CompileResolveMultisample()" "4364": "handmade_opengl.cpp: Enable CompileResolveMultisample() to compute CombinedColor, and UseProgramBegin() to set up the color and depth samplers" "4550": "handmade_opengl.cpp: Make OpenGLRenderCommands() setup the framebuffers to pass to ResolveMultisample(), and fix compile errors" "4899": "handmade_opengl.cpp: Determine that the (f32)SampleCount line in CompileResolveMultisample() is causing the error" "5047": "handmade_opengl.cpp: Continue fixing compile errors in CompileResolveMultisample()" "5124": "Run successfully, but see nothing" "5195": "handmade_opengl.cpp: Make UseProgramBegin() set the Prog->SampleCount for CompileResolveMultisample() to use" "5315": "Run the game to see that the alpha value isn't getting written properly, and investigate why" "5423": "handmade_opengl.cpp: Make CompileResolveMultisample() disable GL_DEPTH_TEST, and run the game to see our old artifacts gone, but a new one present" "5561": "win32_handmade.cpp: Switch to a higher resolution, and run the game to see that this is still slow" "5716": "handmade_opengl.cpp: Assess OpenGLRenderCommands() and note that multisampling is not actually off" "5845": "Run the game to see that it looks the same whether multisampling is enabled or not" "5886": "handmade_opengl.cpp: Disable multisampling in OpenGLChangeToSettings() and run the game to see the debug information" "5952": "handmade_platform.h: Make DefaultRenderCommands() set the MultisamplingHint to false, and run the game to see that the multisampling is responsible for the debug system disappearing" "6077": "handmade_opengl.cpp: Determine that there's a problem in ResolveMultisample(), and investigate what" "6207": "handmade_opengl.cpp: Make ResolveMultisample() read from the correct framebuffer" "6278": "handmade_opengl.cpp: Try making OpenGLRenderCommands() follow both multisampling paths and run the game to verify that it is a state-based problem" "6326": "handmade_opengl.cpp: Reorder the OpenGL calls in ResolveMultisample() so that they are last-in-first-out" "6425": "Run the game to see that it works" "6539": "Q&A" "6570": "Casey, you often argue that we don't need to free memory and clean up upon exiting the program. Does the same reasoning apply to glDeleteProgram() and others? I saw you use that and wondered what is the reasoning behind it" "6691": "Casting in GLSL is done: f32(Value) instead of (f32)Value" "6822": "Is there a vim version of your colorscheme?" "6839": "Could you try using Mesa for debugging?" "6929": "How often do we need to free and allocate memory compared to the early 2000s?" "6956": "What video card do you use?" "6978": "Compare the ATI FirePro V8700 with a modern GPU" "7276": "Slightly off topic, I recently found out that AVE exists, for SSE there are pretty clear mathermatical applications for it such as mat mul. Do you see the benefits of using AVE and in which context?" "7332": "Q: What is the name of your colorscheme?" "7352": "He meant AVX" "7617": "A few words on the AVX512 instruction set and Larrabee" "7965": "Wrap it up" --- name: "day387" title: "Further Attempts at Multisampled Depth Peeling" markers: "8": "Recap and set the stage for the day" "88": "Run the game to show our custom multi-resolution resolve with and without multisampling, and describe the problem that multisampling introduces for our depth peeling scheme" "605": "handmade_opengl.cpp: Read through CompileResolveMultisample(), and tweak it to specify GLSL version 1.50" "656": "Run the game to see that it works with GLSL 1.50 specified" "700": "Continue reading through CompileResolveMultisample()" "760": "Show the offset bug with Milton" "852": "Blackboard: Multisample Resolve" "1447": "Blackboard: Picking a primitive's most distant sample from the camera" "1731": "handmade_opengl.cpp: Make CompileResolveMultisample() sample the colour from the most distant pixel of primitives" "2488": "Compile and run to see weird artifacts" "2525": "handmade_opengl.cpp: Read through CompileResolveMultisample() and make it correctly set the Depth" "2714": "Run the game to see that we're not getting smoothing along edges" "2742": "handmade_opengl.cpp: Increase the DepthThreshold in CompileResolveMultisample() and run the game to see the smoothing" "2794": "Consider always taking a particular depth sample for depth peeling purposes" "2940": "handmade_opengl.cpp: Revert the DepthThreshold, and rewrite CompileResolveMultisample() to only track the DepthMin" "3077": "Run the game to see artifacts at the primitive edges" "3108": "handmade_opengl.cpp: Introduce a centroid to set FragZ in a way that won't vary per sample in CompileResolveMultisample()" "3404": "Run the game to still see the artifacts" "3435": "handmade_opengl.cpp: Enable CompileResolveMultisample() to visualise the number of unique samples" "3957": "Run the game to see our debug visualisation" "4013": "handmade_opengl.cpp: Enable CompileResolveMultisample() to colourise our debug visualisation" "4069": "Run the game to see that we are getting two unique depth samples throughout the scene, and consider why" "4223": "handmade_opengl.cpp: Make CompileResolveMultisample() hard set the InputZ to 0.5" "4273": "Run the game to view our debug visualisation" "4337": "handmade.cpp and handmade_platform.h: And a MultisamplingDebug toggle to the debug system" "4756": "Run the game and toggle between the debug visualisation and regular view" "4808": "handmade_opengl.cpp: Make CompileResolveMultisample() correctly set the InputZ, run the game and inspect the MultisamplingDebug view" "4936": "Propose taking the background out of the equation" "4980": "handmade_opengl.cpp: Enable CompileResolveMultisample() to skip sampling the background" "5169": "Run the game to see that we don't get multisamples when there's only one primitive" "5213": "handmade_opengl.cpp: Prevent CompileResolveMultisample() from using the InputZ and run the game to see that everything has multisamples" "5556": "Inspect a screenshot to see that no blending occurs where there is only one depth value" "5592": "handmade_opengl.cpp: Make CompileResolveMultisample() compute the InvSampleCount from the full SampleCount" "5688": "Run the game to see that it now computes the correct colour, but does not sum up properly, and consider why" "5800": "Note that premultiplied alpha and gamma correction don't work well together" "5903": "handmade_opengl.cpp: Try to make CompileResolveMultisample() un-premultiply alpha and then reintroduce the alpha after producing the average colour value" "5991": "win32_handmade.cpp: Switch back to 1280x720 and run the game" "6089": "Consider two things: It'd be nice to fix the unique sample picking, but there still may be issues with multiple depth peels across the scene" "6195": "handmade_platform.h and win32_handmade.cpp: Use 2x oversampling, run the game and inspect a screenshot" "6406": "handmade_opengl.cpp: Consider enabling OpenGLRenderCommands() to correctly perform oversampling" "6503": "win32_handmade.cpp: Switch to 1920x1080, run the game and consider downsampling that to a much lower resolution on our card" "6562": "Consider getting the depth peel buffers to work in multisampling mode" "6619": "Q&A" "6703": "I can't compile the code, it's saying "Requires extension support: sampler2DMS (GL_ARB_texture_multisample)". But not having support for this makes no sense because I have an R9 390, which is a newer AMD card than you" "6750": "Haven't really followed along with how you've implemented peeling but what if you separate out 3D objects and run them through a different shader that doesn't do peeling?" "6771": "Would doing a depth pre-pass without multisampling help?" "6809": "What do you think about ffmpeg and its likes? In your opinion is there a better way to implement a video-oriented program (with multiple codec support) without going nuts?" "6830": "If you want the same depth for each multi-sample, couldn't you write the depth as a separate vertex shader output with centroid interpolation?" "6915": "Run the game to show how the centroid sampling works great, but that at the seam between triangles we do get multiple samples" "6982": "It works! Is that version defining what version of OpenGL that's going to be used? Which version is 150?" "7056": "Hey Casey. Sorry about the cursor bug! Could you try creating a new canvas to see if it still happens? I missed the start of the stream but people told me that it only happens with wacom input. Is that true?" "7084": "Blackboard: Show the offset input with the wacom tablet" "7359": "Hi Casey! Do you have a few more good scientific-programmy papers to get me started on a good habit of reading long stuff for coding? I do remember those from "Papers I Loved" and the rasterization bridge one. Maybe there are some lighter reads for to begin on this road?" "7687": "How's 1935 coming along? Long time no news" "7734": "If thread behavior is considered to be completely random, can we leverage it to our random number generator?" "7892": "Isn't PCG less favorable than something like Xorshift for games because the stepping function can't be SSE optimized?" "8233": "How come there are different Z values on the diagonal on the same sprite? Is it an epsilon issue, or did I miss something?" "8399": "Wrap it up" --- name: "day388" title: "Successful Multisampled Depth-Peeling" markers: "12": "Thank serge_rgb for fixing the offset bug in Milton, and determine to try CodeXL" "95": "Try to run the game in CodeXL" "373": "Inspect the history of OpenGL function calls" "446": "Try without success to continue to the next frame, and determine to update the machine" "637": "Read Mox's bug report on the depth buffer being disabled in ResolveMultisample()" "990": "handmade_opengl.cpp: Reduce the DepthThreshold in CompileResolveMultisample()" "1177": "handmade_opengl.cpp: Prevent ResolveMultisample() from disabling the entire depth buffer in favour of disabling depth testing only, and leaving depth writes on" "1256": "Compare our code with Mox's report" "1411": "Run the game and try to toggle on multisampling" "1487": "win32_handmade.cpp: Switch to 960x540 and enable multisampling by default" "1568": "Run the game and inspect a screenshot to confirm that we get 1-to-2 pixels" "1646": "Run the game and point out our diagonal lines in the ground cube primitives" "1712": "handmade_opengl.cpp: Make CompileResolveMultisample() use all the samples and run the game to see that we're in a better place" "1863": "handmade_opengl.cpp: Try to restore the depth range testing in CompileResolveMultisample()" "1964": "Run the game to see some artifacts" "2020": "handmade_opengl.cpp: Revert CompileResolveMultisample() to set, but not only pick from, the minimum depth and run the game to see some artifacts during the peel where the primitives abut" "2195": "Consider the fact that we don't actually need multisampling here" "2343": "handmade_opengl.cpp: Try to make CompileResolveMultisample() only pick the minimum depth again" "2412": "handmade_opengl.cpp: Try turning off sRGB in CompileResolveMultisample() and run the game to determine that it is more correct with sRGB on" "2494": "Blackboard: Producing a premultiplied colour from a percent-coverage value of any given pixel in a primitive" "2629": "Blackboard: Storing each of those colour values in the peel" "2748": "handmade_opengl.cpp: Read how CompilePeelComposite() handles sRGB" "2850": "Blackboard: Considering the case with two triangles touching, that have the same colour value" "2946": "handmade_opengl.cpp: Consider the possibility that CompileResolveMultisample() is computing slightly different sample positions" "3192": "handmade_opengl.cpp: Make CompileResolveMultisample() set the InvSampleCount up front and add in that colour every time" "3238": "Run the game to see that it looks basically the same" "3311": "Wonder if we necessarily know how many samples there are in a pixel" "3409": "handmade_opengl.cpp: Double-check the CompilePeelComposite() code, and wonder if the framebuffer's recording of Z values couldn't also be involved in this" "3500": "handmade_opengl.cpp: Make CreateFramebuffer() use GL_DEPTH_COMPONENT32F in an effort to avoid quantisation errors" "3549": "Run the game to see no effect" "3616": "Closely inspect the diagonal artifact across the hero's face, and consider why that occurs" "4027": "Consult the documentation on glSampleCoverage" "4165": "Read about Fixed-Function Primitive Assembly and Rasterization in the OpenGL 4.5 (Core Profile) spec" "4531": "handmade_opengl.cpp: Disable multisampling, try to make OpenGLRenderCommands() enable GL_POLYGON_SMOOTH, run the game and see no smoothing" "4821": "Read about Pixel Ownership Test in the OpenGL 4.5 (Core Profile) spec" "4932": "Run the game and wonder if the summation from depth peel to depth peel is not correct" "5002": "handmade_opengl.cpp: Try to make CompileResolveMultisample() hard set the alpha to 1, run the game and still see the summation error across the primitive boundary" "5135": "Blackboard: How the alpha summation is wrong" "5264": "handmade_opengl.cpp: Make CompileResolveMultisample() sum all the colours starting from the furthest depth" "5338": "Run the game to see artifacts where trees overlap, but not at the triangle primitive boundaries" "5476": "handmade_opengl.cpp: Set an AlphaThreshold in OpenGLRenderCommands() and run the game to see how that affects it" "5648": "handmade_opengl.cpp: Try preventing CompileResolveMultisample() from performing centroid sampling, and run the game to see that it's a lot nicer" "5793": "handmade_opengl.cpp: Fully remove centroid sampling and run the game to see that it's nice and smooth, but subtly wrong at some edges" "6074": "Blackboard: Multisampling colours with low alpha values" "6198": "handmade_opengl.cpp: Make CompileResolveMultisample() track both the min and max depth and halve that the range" "6246": "Run the game to see a lot less artifacts" "6286": "handmade_opengl.cpp: Make OpenGLRenderCommands() set AlphaThreshold to 0, run the game and now only see artifacts during peeling" "6506": "Q&A" "6531": "Close the "GLSL version / extension for sampler2DMS" and "Two small compiler warnings VS17" issues" "6685": "Run the game to see that all is good" "6732": "gl_polygon_smooth is not supported by many modern cards" "6755": "What about the type cast?" "6776": "Hi, I'm new here, sorry if this has been asked before. Looks like you're doing an engine right now. Any idea about what the game would be?" "7002": "As it appears you are nearing the end of the main engine dev, will you be adding in the non-Win32 layers too, or have others already done those?" "7145": "Wrap it up for the day with a reflection on how well the multisampling works, and thanks to mtsmox for reporting the bug" --- name: "day389" title: "Adding Simple Lighting" markers: "10": "Recap and set the stage for the day, with a mention of mtsmox's discovery of that problem with our depth enable" "81": "A few words on the month-long failure of Google Drive to download the HandmadeCon videos" "141": "Blackboard: Multisampled Depth Peeling" "441": "Run the game to show off the artifact-free smoothing" "607": "Blackboard: Splitting the min and max depth to perform the depth peeling" "692": "Run the game, consider packing the new art into a texture atlas, and determine to get some lighting in" "1090": "Blackboard: In Graphics, Light = Photons" "1313": "Blackboard: Off-line rendered lighting, as a probabilistic sampling problem" "1537": "Blackboard: Real-time rendered lighting, and falloff" "1977": "Blackboard: Falloff affected by Distance, and the inverse square law" "2416": "Blackboard: Perceivable Brightness, and the projection equation as the inverse of the photon spread equation" "2682": "Blackboard: Falloff affected by Participating Media, e.g. dust, air, water droplets" "2901": "Blackboard: Falloff affected by Reflection" "3353": "Blackboard: Surface Diffusiveness" "3845": "Blackboard: Cosine falloff, affected by the angle at which photons hit a surface" "4036": "Blackboard: Regional lighting, as in Stardew Valley" "4282": "Blackboard: Normal mapped lighting, as created by Sprite Lamp" "4405": "handmade_opengl.cpp: Add a regional light source in CompileZBiasProgram()" "4808": "Run the game to see our light source" "4920": "handmade_opengl.cpp: Create a second, brighter light in CompileZBiasProgram()" "4985": "Run the game to see our two lights, and note that we may want to pre-compute the lights into a voxel grid" "5104": "Consider using the facing direction of our surfaces to improve the lighting" "5239": "Blackboard: Light scattering, and cosine falloff" "5462": "Practical experiment: Glancing light off a piece of paper" "5570": "Blackboard: Surface normal" "5629": "handmade_platform.h: Add N to textured_vertex" "5702": "Blackboard: Using the cross product to produce normals" "5743": "handmade_render_group.cpp: Make PushQuad() produce the surface Normal" "5993": "handmade_opengl.cpp: Enable UseProgramBegin() to use that Normal" "6155": "handmade_opengl.cpp: Make OpenGLCreateProgram() take an opengl_program_common to write into directly" "6403": "Step in to UseProgramBegin() to see if anything looks weird" "6503": "handmade_opengl.cpp: Insert space for the normals in the Vertex arrays" "6555": "Q&A" "6589": "For the lighting of the sprites, do you need to compensate for the angle offset if it's using the same light source as the terrain?" "6660": "There seems to be a lot of banding around the lights" "6739": "handmade_opengl.cpp: Try to make OpenGLInit() use a full floating point resolution back buffer" "6975": "handmade_opengl.cpp: Try to make OpenGLRenderCommands() enable GL_DITHER" "7230": "As our hero does not represent the actual hero that saves our lives every day all over the world, I took liberty and made some corrections to the game art..." "7253": "What kind of rendering pipeline does this use? Forward? Deferred? Both?" "7284": "is the debug text being lighted?" "7289": "Use sampler with shift key pressed to get info window" "7300": "I miss the little line showing the current filename inside 4coder. It was easier to follow that way" "7328": "How expensive it will be if the light source is moving, for example, following the torch that hero could be carrying or the flying light projectile?" "7381": "Update CodeXL. It will not be able to step into the shader, but you should be able to see the OpenGL state" "7413": "Wind it down, with the determination to investigate the banding, noting that the light moves with the hero" --- name: "day390" title: "Adding Simple Phong Lighting" markers: "2": "Recap and run the game to show off the radial fade" "156": "handmade_render_group: Recap what PushQuad() does" "210": "On specifying normals per vertex, separately from the triangles" "375": "handmade_opengl.cpp: Make CompileZBiasProgram() pass VertN to the fragment shader" "505": "handmade_render_group.cpp: Make PushCube() colour all faces the same, and run the game" "593": "handmade_opengl.cpp: Determine to edit the lighting equation in CompileZBiasProgram() to use the normals" "672": "Blackboard: Normal Interpolation" "944": "Blackboard: Linearly interpolating on the curve of a perfect circle" "1082": "Blackboard: We don't need to worry about the speed problem or need to renormalise" "1143": "Blackboard: Reflection equation" "1234": "handmade_opengl.cp: Make CompileZBiasProgram() compute LightDistance falloff" "1320": "Run the game to make sure we're computing the falloff correctly" "1335": "Blackboard: Dot product" "1469": "Blackboard: Understanding cosing falloff" "1651": "Blackboard: An equation to compute cosine falloff" "1927": "Determine to check our equation against the physical lighting transfer equations" "1988": "Blackboard: Defining our angles and getting this to work for cosine 0" "2203": "Blackboard: Making better sense of cosine falloff for different angles of reflection" "2696": "Blackboard: Understanding cosine falloff from the collector's viewpoint, with the need to research this" "3056": "Blackboard: On the apparent need for an inverse relationship beween the light source and collector" "3342": "handmade_opengl.cpp: Make CompileZBiasProgram() compute and clamp the cosine angle" "3437": "Run the game to see black" "3455": "handmade_opengl.cpp: Rephrase the ToLight computation in CompileZBiasProgram() and investigate why the normals are not working" "3741": "Run the game to see apparent darkening at oblique angles" "3896": "handmade_opengl.cpp: Read carefully through CompileZBiasProgram()" "4115": "Inspect screenshots of the darkening at oblique angles" "4261": "handmade_opengl.cpp: Make CompileZBiasProgram() set and pass WorldN from the VertexCode to FragmentCode" "4354": "Run the game to see our light source reflecting more correctly" "4404": "handmade_render_group.h and handmade_render_group.cpp: Add DebugLightP to render_setup and enable SetCameraTransform() to set it" "4576": "Run the game to see the light at the centre of the world" "4587": "handmade_world_mode.cpp: Make UpdateAndRenderWorld() set the DebugLightP" "4637": "Run the game to see the light in its original position" "4647": "handmade_world_mode.cpp: Make UpdateAndRenderWorld() attach the light to the hero" "4788": "Run the game to see the light moving with the hero" "4930": "Blackboard: Better lighting: 1) More lights" "5040": "Blackboard: Better lighting: 2) Reflected light / "bounce" light" "5136": "Blackboard: Better lighting: 3) Surface variability" "5262": "handmade_opengl.cpp: Enable CompileZBiasProgram() to take into account the angle and distance of the viewer" "5580": "handmade_opengl.cpp: Introduce in CompileZBiasProgram() the notion of specular light" "5753": "Blackboard: Reflection vector" "5954": "Blackboard: Computing that reflection vector" "6121": "handmade_opengl.cpp: Enable CompileZBiasProgram() to compute that RefVec" "6165": "Run the game to see the light reflection adapting to our viewpoint" "6196": "handmade_opengl.cpp: Enable CompileZBiasProgram() to make a very bright and tight specular highlight, and run the game to see that" "6412": "Q&A" "6467": "The problem you could not find when you thought about dividing by cos(phi) is that the only reason diffuse surfaces can exist is surface roughness, which invalidates the assumption that you will collect photons from the entire surface. Roughness blocks some photons. One trick to check your model: a photon must have the same probability of going one way as the opposite way. All formulas for diffusive light are approximations, all diffuse surfaces are different. In order to render a physically correct diffuse surface you'd have to measure a 4-dimensional dataset of light distribution (reflectance depending on two angles of incidence and two angles of reflection)" "6527": "GLSL has reflect function" "6551": "Should you normalize the worldN in the fragment shader?" "6575": "Ever done website dev work?" "6649": "Can you take a quick shot at reducing the banding?" "6711": "Also, I opened an issue where the game crashes when you go backwards after starting the game" "6764": "win32_handmade.h: Prevent SetCursor() and LoadCursor() from calling MAKEINTRESOURCE" "6840": "Would HDR / tonemapping be worth implementing?" "6872": "Is bumpmapping a feature you're looking into implementing?" "7051": "SIMD on CPUs are pretty cool. However, it sounds painful to make use of the newest and the best instructions (e.g. AVX512) while remaining compatible with older CPUs. I don't see programs being compiled separately for different SSE capabilities. I assume a program will just crash if the CPU encounters an unsupported instruction? Would you dispatch at runtime for different code paths to flexibly use supported SIMD instructions, or does that sound dumb?" "7082": "Words of wisdom on the rarity of needing to optimise for newer instruction sets" "7354": "What if you have a deal with Intel to benchmark higher on the newest hardware?" "7445": "Any plans to create different types of lighting as in Room X is lit like a summers day while Room Y is contrasted and dark like a film Noir? (Or would you have all this done in the assets, maybe?)" "7484": "Close things down" --- name: "day391" title: "Planning Better Lighting" markers: "3": "Recap and set the stage for the day" "61": "Run the game to show our Phong lighting, and consider how to improve it" "586": "Blackboard: Light Rendering" "1005": "Blackboard: Phong reflectance model" "1326": "Blackboard: Moving beyond the simplification of the Phong model" "1487": "Blackboard: Light Probes" "1521": "Everybody needs to get lit"" "1534": "Blackboard: Light Probes and Cube Map" "1852": "Blackboard: How light probing can solve the problem completely, but not for us" "2011": "Blackboard: Producing hemispheres of light ad infinitum" "2252": "Blackboard: "Monte Carlo" Integration" "2482": "Blackboard: Unbiased vs Biased rendering" "2890": "Blackboard: Breaking the infinite bounce nastiness with Monte Carlo integration" "3073": "Consult examples of offline renderers" "3333": "A few words on the offline rendering system in The Witness" "3421": "Blackboard: The lighting requirements of our online renderer" "3689": "Blackboard: Turning an aerial lighting problem into a point lighting problem" "3921": "Blackboard: Light source occlusion" "4337": "Blackboard: Consider various techniques for lighting" "4579": "Consider the attractiveness of using a system that doesn't bifurcate the renderer into two parts" "4897": "Consult Alex Evans' 'Fast Approximations for Lighting of Dynamic Scenes'" "5357": "Consider flipping a coin" "5426": "Blackboard: Voxel cone tracing" "5892": "Consider that we want a simpler approach, e.g. the point light propagation model" "6241": "Blackboard: Lighting Process Proposal" "6563": "Q&A" "6621": "Don't we already need acceleration, because the lookups for the closest traversable are already "slow"?" "6642": "Blackboard: Closest Point Query vs Line Query" "6877": "Blackboard: Ray tracing through a grid" "7015": "Why not use signed [sic] distance fields? Best for line queries. (Sorry, a bit of context, just joined your stream)" "7088": "Blackboard: Signed distance field" "7302": "k-d tree?" "7355": "Shouldn't we get the frame rate to a reasonable range before adding more complexity (lighting)? How do we know our budget?" "7383": "Run the game in release, to check out the frame rate" "7430": "Are there (obvious) visual differences in these different lighting methods?" "7482": "On top of this, how we will manage shadows? Is that another big problem to solve?" "7535": "Do you know if your broadcasts have inspired improvements in "popular" game engines out there?" "7723": "So all of this is still not a physically based rendering renderer? So almost all the time light is pre-calculated at asset creation?" "7960": "Really slow on my old PC in debug mode. But it was more how do we know our budget?" "8156": "Wind it down" --- name: "day392" title: "Creating Lighting Textures" markers: "3": "Recap and set the stage for the day with a few words on renderer programming" "178": "Light probing" "241": "Try to run the game, but be told that our Visual Studio Community 2013 license "has gone stale"" "462": "Consider our options" "594": "Check for a build of Milton for Linux" "725": "Consider taking a poll" "821": "Try putting in our credentials" "1063": "Run the game and note the problem imposed by the 2.5D world with respect to lighting" "1243": "Consider making a voxelisation pass in order to give us some usable geometry" "1390": "Blackboard: Looking up our lighting from a texture" "1613": "Blackboard: Extending this texture sampling into three dimensions" "1877": "Blackboard: Spherical harmonics and Fourier transform" "2284": "Blackboard: Lighting Equation" "2374": "handmade_opengl.cpp: Make CompilePeelComposite() not use the specular but only the diffuse coefficient, and run the game to see what that looks like" "2451": "Blackboard: Specular and Diffuse" "2641": "Blackboard: Reflections" "2988": "Blackboard: Texture encoding for the lighting" "3392": "handmade_opengl.h: Add lighting data to the open_gl struct" "3506": "handmade_platform.h: Enable DefaultRenderCommands() to set lighting settings" "3552": "handmade_opengl.cpp: Enable OpenGLChangeToSettings() to create a lighting framebuffer" "3760": "Consider the need for a different type of storage from the depth peels" "3881": "handmade_platform.h: Add lighting data to the game_render_settings struct" "3914": "handmade_opengl.cpp: Start to enable OpenGLChangeToSettings() to create a light texture" "3979": "handmade_platform.h: Specify that the lighting data in game_render_settings is a power of 2" "4016": "handmade_opengl.cpp: Finish enabling OpenGLChangeToSettings() to fully create a light texture" "4128": "Blackboard: Consider storing three directional and one intensity value" "4386": "hanmdade_opengl.cpp: Enable CreateFramebuffer() to handle floating point textures" "4495": "Run the game with a floating point depth buffer" "4569": "handmade_opengl.cpp: Try using GL_DEPTH_COMPONENT24 and run the game to see how that is" "4684": "handmade_opengl.cpp: Set up CompilePeelComposite() to handle our new lighting texture encoding" "5024": "Run the game to see the exact same thing" "5061": "handmade_opengl.cpp: Make CompilePeelComposite() produce coloured light" "5085": "Run the game to see that coloured light" "5167": "Q&A" "5204": "12 minutes into the main stream. 108 until Q&A. (based on NOTE)" "5258": "On a scale of 0-15, how disappointed are you that Visual Studio continued working as normal today?" "5330": "Don't you find this lighting way too advanced for a 2.5D game?" "5399": "Can I stream C => D conversion of Handmade Hero, without infringing on the copyright?" "5467": "How excited are you for Per's project?" "5529": "No, he is making an entire computer from scratch using FPGAs and hardware" "5551": "Mention riskyfive's FPGA-based project" "5566": "Will Jon ever do handamde compiler?" "5621": "It's actually miotatsu who's doing RISCY BUSINESS" "5739": "Short of the fact that most gamers use Windows, is there any reason to do most of the development on Windows?" "5896": "Do you have any anecdotes of horrible debugging (CPU) experiences using Linux debuggers?" "6016": "Have you considered vscode over Visual Studio? Still Microsoft, but much more lightweight, and you get the visual studio debugger" "6033": "Have you tried visual debugging using QT Creator? Does not seem to have the issues you describe, at least not for moderately large projects" "6062": "On windows. on Linux you don't get the vc++ debugger" "6085": "Try Visual Studio Code" "6414": "Reload" "6428": "Reload Visual Studio Code" "6646": "Open Folder -> select source folder" "6664": "Have doubts about Visual Studio Code" "6765": "I think in this particular case you're being dumb because you complain about a program you don't have experience in" "6837": "Open folder code, add configuration for C++, add breakpoint wherever you want, start debugging" "6951": "Yeah, you can add more include directories" "6980": "Gauge the single-stepping speed of Visual Studio Code" "7247": "Help -> Toggle Developer Tools" "7314": "You can view the disassembly" "7325": "But I think you have to debug with -exec disassembly" "7383": "If I recall correctly, it's in args" "7426": ""You can view disassembly in vscode using the -exec disassembly command in the debug console. Registers can be viewed the same way (-exec info registers)"" "7509": "Just disassembly is the command" "7569": "You could try using command palette to look for disassembly (press Ctrl-Shift-P)" "7715": "What's the reason behind checking out this atrocity of a program?" "7757": "Plug Lysa and RemedyBD" "7858": "How do you feel after today's stream. We nearly switched to Linux and now you're looking for answers regarding a web editor on stackoverflow" "7876": "Are you still tempted at moving the project to Linux?" "7940": "Don't forget to delete the .vscode folder that it created" "7988": "Wrap it up" --- name: "day393" title: "Planning Lighting from Depth Peels" markers: "7": "Recap and set the stage for the day" "144": "Run the game to show off the renderer and camera movement" "355": "Launch the code with a few words on the tweaked 4coder UI, and our intentions for the light textures" "549": "Blackboard: Light accumulation pass" "788": "Run the game and note that there's no shadowing, with a few words on shadow maps" "1038": "Blackboard: Using our depth peels as geometry for the bounce lighting" "1139": "Blackboard: Screen-space ambient occlusion (SSAO)" "1249": "Blackboard: Voxel cone tracing" "1385": "Hunt for a paper on ambient occlusion" "1579": ""I don't want pirate stuff, I want Pirates of the Caribbean"" "1792": "Consult 'Dynamic Ambient Occlusion and Indirect Lighting'" "2113": "Blackboard: Writing out the normal with the depth buffer, filtered down in resolution" "2341": "Blackboard: The expense of this scheme" "2615": "Blackboard: Sampling from the textures" "2868": ""We are out in complete La La Land, and I admit that, but, I mean, it's lighting, what do you want from me?"" "2877": "Blackboard: Multigrid lighting, modulating incoming values at successively finer resolutions" "3402": ""That's my stupid idea. I hope you like it"" "3414": "Blackboard: Possible discontinuities caused by the mipmap boundaries" "3502": "Consider going for this hierarchically merged lighting idea" "3655": "Blackboard: Lighting memory requirements" "4105": "Blackboard: Hardware capability requirements" "4398": "Consult the OpenGL Hardware Database and OpenGL Core Profile 4.4" "4569": "handmade_opengl.h: Add MaxColorAttachments and MaxSamplersPerShader to open_gl, and enable OpenGLInit() to poll for those values" "4806": "Run the game and inspect the MaxColorAttachments and MaxSamplersPerShader values for our card" "4844": "Consult the OpenGL Hardware Database for GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS" "4939": "Go for it, considering first how many mip levels to use" "5411": "handmade_opengl.h: Introduce light_buffer and add an array of them to the open_gl struct" "5803": "handmade_opengl.cpp: Enable OpenGLChangeToSettings() to free and allocate lighting framebuffers" "5948": "handmade_opengl.cpp: Try to make FramebufferTexImage() pass 0 as the Format, Type and Data to glTextImage2D()" "6093": "Run the game and hit a GL_INVALID_ENUM error" "6111": "handmade_opengl.cpp: Enable OpenGLChangeToSettings() to attach our textures to the lighting framebuffer" "6718": "Run the game and see our surfaces ready to go" "6764": "Q&A" "6808": "Are you planing on taking a different / non-conventional approach to lighting?" "6823": "Any recommended programs to use for a noob?" "6858": "Is that metal music coming from the stream or am I trippin'?" "6878": "Will you port the game to JAI? Or make a part of it in JAI once it comes out, and just link to the original?" "6937": "Which do you think will take longer, coding the engine or coding the actual game?" "7079": "Editor for programming" "7147": "Do you work on Handmade Hero outside of the streaming time? How representative is the time on stream to the total time you put down on the programming / architecture?" "7276": "Off-topic and not really a question: There exists an IDE in Linux called "code::blox". It works great but I don't know if it has feature parity with vs. But something to look into, perhaps" "7328": "About Retained and Immediate mode, do you think these paradigm boxes work for game code (as opposed to engine code) as well?" "7455": "Retention" "7708": "If so, would you write your game logic code in Immediate mode or Retained mode?" "7825": "I plan on starting a project this summer, a 4D perspective projection voxel game. May I ask you for some tips on graphics, then? (Like, how do I utilize the graphics card the best, because it is not optimized for 5x5 matrices and it's hard to think with other concepts for me?)" "7862": "Blackboard: GPUs aren't actually [XYZW] vectors" "8179": "Wind it down" --- name: "day394" title: "Basic Multigrid Lighting Upward Iteration" markers: "3": "Recap and set the stage for the day" "54": ""You can't win 'em all but you're certainly not gonna win if you never roll"" "59": "Run the game to see where we're at with respect to lighting" "253": "A few words on multigrid solvers" "414": "The two halves of our problem: 1) Getting our lighting information down to the renderer" "562": "2) We will need normals" "599": "handmade_opengl.h: Rename WriteEmit to WriteEmitFramebuffer in the light_buffer struct, and describe the framebuffers in this struct" "873": "Blackboard: On the possible need for an additional texture to write into" "1206": "handmade_opengl.cpp: Toggle on the framebuffer visualisation code in OpenGLRenderCommands()" "1370": "Research glReadBuffer" "1467": "handmade_opengl.cpp: Enable the framebuffer visualisation code to pick from a colour buffer" "1650": "Run the game a get a black screen" "1678": "handmade_opengl.cpp: Introduce FakeSeedLighting() and ComputeLightTransport()" "1817": ""I assume it's "hare-brained", like the rabbit. Or is it "hair-brained", like the follicle?"" "1829": "handmade_opengl.cpp: Implement FakeSeedLighting() and introduce OpenGLBeginScreenFill() and OpenGLEndScreenFill() to perform some of ResolveMultisample()" "2106": "Run the game to make sure that that still works" "2123": "handmade_opengl.cpp: Finish implementing FakeSeedLighting()" "2232": "handmade_opengl.cpp: Introduce CompileFakeSeedLighting() based on CompileResolveMultisample(), with some structured artwork" "2472": "handmade_opengl.h: Introduce fake_seed_lighting_program struct and add it to open_gl" "2534": "handmade_opengl.cpp: Introduce a version of UseProgramBegin() that only takes a Prog and Setup, and enable OpenGLRenderCommands() to set up the debug lighting framebuffer" "2670": "Run the game to see a green screen, and investigate why we do" "2745": "Consult the Quick Reference Card and the OpenGL Spec to determine how to line up the output fragments with the framebuffer's bound colour attachments" "3023": "handmade_opengl.cpp: Specify the fragments into which CompileFakeSeedLighting() should write our test colours" "3078": "Run the game to see that that worked" "3081": "handmade_platform.h: Add DebugLightBufferIndex and DebugLightBufferTexIndex to game_render_settings" "3290": "Determine to provide debug keys to control the lighting framebuffers" "3382": "handmade_opengl.h: Move the DebugLightBuffer settings into open_gl" "3410": "win32_handmade.cpp: Add debug keys in Win32ProcessPendingMessage() for cycling through the lighting framebuffers" "3490": "Note the "Sign extension bug" issue" "3525": "win32_handmade.cpp: Continue adding these debug keys in Win32ProcessPendingMessage()" "3654": "handmade_opengl.cpp: Make OpenGLRenderCommands() keep our framebuffer indices in bounds" "3778": "handmade_math.h: Introduce a version of Clamp() that works on s32s" "3812": "win32_handmade.cpp: Tweak those bindings in Win32ProcessPendingMessage()" "3860": "Run the game to try cycling through the framebuffers, and investigate why nothing happens" "3939": "win32_handmade.cpp: Change Win32ProcessPendingMessage() to use 0 and 9" "4007": "Run the game to see that 0 and 9 do work" "4032": "Investigate which VK_ keys are available to us" "4206": "win32_handmade.cpp: Make Win32ProcessPendingMessage() use VK_OEM_PLUS and VK_OEM_MINUS" "4246": "Run the game to try out our key bindings, and investigate why we can't cycle between the textures" "4349": "handmade_opengl.cpp: Double-check CompileFinalStretch()" "4385": "Consult the documentation on Framebuffer" "4500": "handmade_opengl.cpp: Make OpenGLChangeToSettings() specify the mapping table and call glDrawBuffers() for both framebuffers" "4672": "Run the game and cycle between our texture" "4710": "win32_handmade.cpp: Enable Win32ProcessPendingMessage() to print out debug text for the keyboard input" "4826": "Run the game and inspect that output" "4865": "win32_handmade.cpp: Fix Win32ProcessPendingMessage() to only handle the lighting keys in the IsDown path" "4925": "Run the game to see that this is more stable" "4945": "handmade_opengl.cpp: Try to make CompileFakeSeedLighting() use vec3 textures" "5055": "Run the game to see that that seems to work" "5102": "handmade_opengl.cpp: Enable CompileFakeSeedLighting() to light the scene with an emitter that is red on the left and green on the right" "5761": "handmade_opengl.cpp: Make CompileFakeSeedLighting() use a v4 for the output gl_FragData" "5783": "Run the game, see nothing and investigate why" "5949": "handmade_opengl.cpp: Force CompileFakeSeedLighting() to draw a red blob" "6057": "Run the game, see a 10 pixel blob in the corner of the screen and investigate why" "6185": "Realise that we're rendering at 960*540" "6205": "handmade_opengl.cpp: Make CompileFakeSeedLighting() centre the light and slow down its movement" "6283": "Run the game and try moving the light" "6316": "handmade_opengl.cpp: Implement the upward phase of ComputeLightTransport(), building successively less detailed light buffers" "6639": "handmade_opengl.cpp: Introduce OpenGLBindTex() for ComputeLightTransport() to call" "6829": "handmade_opengl.cpp: Introduce CompileMultiLightUp() based on CompileFinalStretch()" "7381": "handmade_opengl.cpp: Introduce a blank CompileMultiLightDown() and fix compile errors" "7541": "Run the game to see that one of our lower detail textures is black, and investigate why" "7803": "handmade_opengl.cpp: Try to make ComputeLightTransport() use the FakeSeedLighting() program at every level" "7846": "Run the game to determine that there's something wrong with CompileMultiLightUp()" "7902": "handmade_opengl.cpp: Manually set all the values in CompileMultiLightUp()" "7936": "Run the game to see no pixels being filled" "7954": "handmade_opengl.cpp: Make CompileMultiLightUp() correctly set the input position" "7970": "Run the game and successfully cycle through the colours" "7981": "handmade_opengl.cpp: Remove the debug code from CompileMultiLightUp()" "7990": "Run the game and cycle through the detail levels, but see that texture 1 uses red rather than green, and investigate why" "8223": "Additional semicolon in glGetUniformLocal "SourceBackEmitTex;"" "8241": "handmade_opengl.cpp: Remove spurious semicolon from CompileMultiLightUp()" "8248": "Run the game and cycle through all the textures and detail levels" "8268": "Q&A" "8354": "Is this going to be pulled out of the final ship to pull aside as DLC content to charge for?" "8379": "Ideas for a good IDE-integrated debugger for Linux, like VS and CDB?" "8468": "Could you recap / outline the idea for this lighting scheme?" "8537": "Will I be able to pay money for an expansion that crashes every so often?" "8573": "Is this a single player game or will there be some network / multiplayer features?" "8677": "Close it down" --- name: "day395" title: "Basic Multigrid Lighting Down Iteration" markers: "7": "Recap and set the stage for the day" "72": "Run the game and consider how to make the light spread further" "168": "handmade_opengl.cpp: Make CompileFakeSeedLighting() set the Front and Back emitter colours to 100" "220": "Run the game and check out the light propagation" "364": "Blackboard: Multigrid Up and bilinear sampling" "599": "handmade_opengl.cpp: Introduce ManualSample() in CompileMultiLightUp()" "741": "Run the game to see everything is fine" "749": "handmade_opengl.cpp: Determine to enable ManualSample() to perform the bilinear sampling" "987": "handmade_opengl.cpp: Force OpenGLChangeToSettings() to set the TexWidth to 1024 and TexHeight to 512" "1004": "Run the game to see how the downsampling occurs at this perfect 2:1 ratio" "1135": "Blackboard: Blending light sources" "1405": "Blackboard: Destructive downsampling" "1646": "handmade_opengl.cpp: Make OpenGLChangeToSettings() perform a safe divide-by-two and use the RenderWidth and RenderHeight again" "1699": "Run the game and see the light propagating up correctly" "1786": "handmade_opengl.cpp: Introduce Light() in CompileFakeSeedLighting(), and create a second light source" "2325": "Run the game to see how the lights blend" "2505": "handmade_opengl.cpp: Make CompileFakeSeedLighting() black out the whole area" "2573": "Run the game and consider having separate textures for emission and surface" "2816": "handmade_opengl.cpp: Make CompileFakeSeedLighting() set the NP to 0, 1, -10, and run the game to see that" "2894": "Determine to implement downward propagation in CompileMultiLightDown()" "3029": "Blackboard: Downward light propagation, with reflectance from neighbours" "3434": "Consult 'Dynamic Ambient Occlusion and Indirect Lighting'" "3948": "Blackboard: Disk-to-disk form factor approximation" "4524": "Consider having our reflectors as disks and emitters as spheres" "4605": "handmade_opengl.cpp: Implement downward propagation in CompileMultiLightDown()" "4787": "Blackboard: Sampling light from the parent and neighbour grids" "5023": "handmade_opengl.cpp: Enable CompileMultiLightDown() to sample from the parent grid" "5751": "handmade_opengl.cpp: Introduce TransferLight() in CompileMultiLightDown()" "5990": "Blackboard: Computing NPz" "6045": "handmade_opengl.cpp: Complete the implementation of ParentSample() in CompileMultiLightDown()" "6224": "handmade_opengl.cpp: Introduce ReconstructNormal() and ReconstructPosition() for ParentSample() to call in CompileMultiLightDown()" "6340": "handmade_opengl.cpp: Fix compile errors in CompileMultiLightDown()" "6524": "handmade_opengl.cpp: Implement the downward phase in ComputeLightTransport(), transferring light from less-detailed light buffers to higher-detailed ones" "6845": "handmade_opengl.cpp: Introduce a version of UseProgramBegin() for multigrid_light_down_program" "6937": "handmade_opengl.cpp: Fix compile errors" "7128": "Run the game, but simply running is not going to get us very far" "7196": "Q&A" "7208": "handmade_opengl.cpp: Fix up the DestFrontEmit and DestBackEmit computations" "7260": "Have you seen Doom 2016 rendering paper?" "7284": "You have an Up in your Down line" "7289": "handmade_opengl.cpp: Fix up the TransferLight Down call" "7294": "On Doom's rendering" "7367": "I'm on Day 18 and I'm looking at the stream for the first time and I'm wondering, what happened? I have these sweet-ass colourful gradients and sound, and all you have is two round circles!" "7384": "handmade_opengl.cpp: Toggle off the debug lighting and run the game to show our actual state" "7468": "Do you usually do a lot of programming before you run, like you did today, or do you program a bit then run and debug? Is it because you know what you are doing that you take big chunks of programming then run?" "7563": "Try running now that we fixed the stupid error in the shader" "7607": "How long do you think this project is gonna take?" "7623": "New here, sorry if this was asked before. If you were working on this on your own time (not streaming / teaching or anything), how long do you think it would take you to complete?" "7731": "Do you think that game engines have a place or is it just pure evil?" "7823": "Do you have any good practice to keep your brain motivated after months and months of programming?" "7946": "If we feed you sandwiches and keep you alive, what would you work on for the rest of your life?" "8007": "I'm down with patreoning Molly so I think you have no worries if we all chip in" "8064": "Have you found the need to write certain algorithms directly in assembly for performance reasons?" "8266": "Any word on getting other programmers to work on some code on Handmade Hero? Shawn (adult hour edition) for graphics, Fabian for optimizations, Jon for game design, Sean to dance and party, etc." "8465": "So you know stuff about 360 hardware? How much of a problem was in-order execution? Did that cause performance problems? Do you view out-of-order execution as the performance convenience it claims to be, at least with respect to instruction-level parallelism?" "8812": "A few words on the Load-Hit-Store penalty of PowerPC" "9033": "If you had SIMD code for SSE2 but also had the same algorithms for AVX 256-bit, is there a way to only run the AVX in the shipping version if the hardware supports it? Must it be decided at compile time?" "9217": "Wind it down" --- name: "day396" title: "Rendering Lighting Information from the Game" markers: "1": "Recap and set the stage for the day" "51": "handmade_opengl.cpp and handmade_opengl.h: Rename UVStep to SourceUVStep everywhere CompileMultiLightDown()" "186": "Run the game and consider using different textures for the up and down sampling" "234": "handmade_opengl.cpp: Make TransferLight() in CompileMultiLightDown() use the reflection colour and enable ComputeLightTransport() to combine the colours with glBlendFunc()" "513": "Run the game to see that we're now seeing unlit dots, despite the scene being lit yellow by them" "617": "handmade_opengl.cpp: Reduce the colour intensity of the lights in CompileFakeSeedLighting() and run the game to see the scene's yellow light still not affecting the interior of the red and green light sources" "724": "handmade_opengl.cpp: Make TransferLight() in CompileMultiLightDown() reduce the amount of light transferred, running the game to see how that affects it" "887": "Run the game and describe exactly what we're expecting" "932": "handmade_opengl.cpp: Prevent TransferLight() in CompileMultiLightDown() from using the reflection colour" "954": "Run the game to see the red and green light sources being affected by each other" "972": "handmade_opengl.cpp: Make TransferLight() in CompileMultiLightDown() clamp the light transfer and run the game to see that" "1024": "handmade_opengl.cpp: Make TransferLight() in CompileMultiLightDown() use the reflection colour again, and run the game" "1063": "handmade_opengl.cpp: CompileFakeSeedLighting() increase the colour intensity of the lights, running the game to see how that affects it" "1150": "Run the game and note the problem with the light bleeding" "1224": "Consider creating a way to switch between game and test mode" "1383": "handmade_opengl.cpp: Toggle off the lighting debug visualisation in OpenGLRenderCommands() and run the game" "1466": "Prepare to enable lighting toggling" "1596": "handmade_opengl.cpp: Make CompilePeelComposite() render the game at full brightness, preserving the directional lighting" "1742": "Run the game to see the lit scene a lot more cleanly" "1780": "handmade_opengl.cpp: Try to make CompileResolveMultisample() only blend with colours from above" "1879": "Run the game to see that a lot of the blending has been eliminated" "1917": "handmade_opengl.cpp: Flip the direction of the depth test in CompileResolveMultisample() and run" "1946": "handmade_opengl.cpp: Back out those changes" "1978": "Run the game and consider how to get everything into the lighting system" "2037": "handmade_opengl.h: Describe the opengl_framebuffer struct, noting that we'll need some space to store the emitter" "2263": "handmade_opengl.h: Extend opengl_framebuffer to contain multiple ColorHandle types" "2607": "Blackboard: Emission Specification" "2771": "handmade_opengl.h: Specify opengl_color_handle_type enum, noting the heavily increased write bandwidth required" "3073": "handmade_opengl.cpp: Make CreateFramebuffer() and FreeFramebuffer() operate on multiple framebuffers" "3328": "Run the game correctly" "3347": "handmade_opengl.cpp: Make CreateFramebuffer() operate on OpenGLAllColorAttachments" "3546": "Run the game to see it rendering just fine" "3598": "handmade_opengl.cpp: Move the lighting code out of CompilePeelComposite()" "3772": "Run the unlit version of the game" "3794": "handmade_opengl.cpp: Replace deprecated gl_FragData in CompileFakeSeedLighting() and CompileMultiLightUp()" "4087": "Run the game to see that it looks fine, and close issue #9" "4203": "handmade_opengl.cpp: Propagate this gl_FragData replacement to all shaders" "4357": "Rant on how things have to be named in GLSL" "4509": "handmade_opengl.cpp: Rename colours" "4612": "Run the game to see it working almost alright" "4639": "handmade_opengl.cpp: Fix up the naming" "4796": "Run the game to see it working correctly" "4816": "handmade_opengl.cpp: Enable CompileZBiasProgram() to write light out to multiple textures" "5431": "Run the game to see that we're good" "5434": "handmade_opengl.cpp: Enable CompileResolveMultisample() and ResolveMultisample() to blend multiple light sources" "5985": "Run the game to see that stuff going" "5991": "handmade_opengl.cpp: Switch back to the game renderer, and run the game to see that's okay" "6021": "handmade_opengl.cpp: Enable ComputeLightTransport() to override the ordinary texture with the surface emission buffer" "6176": "Run the game and see nothing in the emission framebuffer" "6255": "handmade_opengl.cpp: Hard set BlendUnitColor[0] in CompileResolveMultisample() to the surface emission buffer and run the game" "6401": "handmade_opengl.cpp: Hard set BlendUnitColor[0] in CompileResolveMultisample() to factor in the CombinedNPL and run the game to see a Stephen's Sausage Roll-esque scene" "6459": "handmade_opengl.cpp: Ensure that OpenGLInit() does not encode the lighting framebuffers as sRGB" "6615": "Run the game and consider that the colours may be being decoded in sRGB space" "6648": "handmade_opengl.cpp: Investigate why CompileResolveMultisample() is not writing out the emission buffer" "6850": "handmade_opengl.cpp: Enable CompileResolveMultisample() to apply light from a wider radius" "6918": "Run the game to see that it makes a difference" "6960": "handmade_opengl.cpp: Toggle on the lighting debug visualisation in OpenGLRenderCommands() and the downward light transfer in ComputeLightTransport()" "7026": "Run the game and see glowy hero" "7035": "Q&A" "7165": "We can set the spread of the emitter, but can we also set the direction of the spread?" "7184": "Blackboard: Emitter vs sprite facing" "7292": "Why not doing a marathon stream in lighting? Maybe if doing so will be more productive as you remember what hack you have done, and maybe forget the next weekend" "7364": "Don't know if this is the right place, but with your assert macro, it could currently cause bugs if you place it inside and if / else that doesn't use curly braces. Adding an else to this macro could solve this" "7444": "I have been looking into compression schemes for skeletal animation data. Currently I have only implemented basic quantisation, but I would like to add curve fitting to the mix. Could you give me some pointers on this? If I were to use Catmull-Rom splines, what are some methods on estimating the error of a segment and finding a good split point? And how could I apply this stuff to quaternions?" "7478": "Do you plan to allow sprites to use emit textures that could, for example, make eyes glow?" "7523": "Alternative if / else syntax?" "7610": "About the Nx Ny Lp0 Lp1 texture, is a 16-bit texture worse than a 32-bit in any way? I felt like you added Lp0 and Lp1 just because it wouldn't make much of a difference performance-wise? Is that true?" "7751": "handmade_opengl.h: TODO(casey): Think about making only one opengl_color_handle_type store RGB" "7835": "(Off-topic) I'm playing with the debug cycle counters. Is there a way to find out for how long Windows puts our process to sleep? I'm missing millions of cycles in my main loop" "7974": "How do you define a good API and a bad API, or do you have examples of very good APIs?" "8463": "A few words on compressing animation data" "8650": "Speaking of, ever thought of releasing old talks you've done if you still have slides / notes and the like laying around?" "8688": "Scan through archival slides for 'In-Depth 3D Exporter: Design and Implementation'" "8796": "Scan through archival slides for 'Character Animation Programming I'" "8888": "Scan through archival slides for 'Requirements for Real=time Geometry'" "8905": "Wrap it up" --- name: "day397" title: "Converting Depth Peel Data to Lighting Data" markers: "8": "Recap and set the stage for the day" "125": "Consider how to resolve the issue that we're only computing the lighting on the topmost of four depth peels" "341": "Mention that multigrid lighting may not work out" "569": "Run the game to see the current state of the lighting system" "751": "handmade_opengl.cpp: Fix "Minor copy-paste error in handmade_opengl.cpp" issue" "853": "handmade_opengl.cpp: Prevent ComputeLightTransport() from pulling the emit colour from the DepthPeelResolveBuffer" "903": "Run the game to see the existing fake lighting" "922": "handmade_opengl.cpp: Enable ComputeLightTransport() to bind lighting textures that come from the depth peel" "1200": "handmade_opengl.cpp: Introduce CompileDepthPeelToLighting() based on CompilePeelComposite()" "1756": "handmade_opengl.cpp: Make CompilePeelComposite() compute the FrontEmit, BackEmit, SurfaceColor and NP" "1970": "handmade_opengl.cpp: Change CompilePeelComposite() to use the layout(location) syntax and take an opengl_program_common" "2275": "Run the game and see bright white" "2292": "Research the OpenGL Layout qualifier" "2555": "handmade_opengl.cpp: Revert CompilePeelComposite() to not use the layout(location) syntax, and make all the programs explicit" "2720": "handmade_opengl.cpp: Make OpenGLCreateProgram() reset the SamplerCount, and introduce OpenGLLinkSamplers()" "3015": "Run the game to see what we had running before" "3031": "handmade_opengl.cpp: Make all the shader programs use OpenGLLinkSamplers(), as a partial way towards layout(location)" "3360": "handmade_opengl.cpp: Make UseProgramBegin() set up all of the samplers for the program" "3419": "Run the game to see that we're back to normal, view the beautiful depth buffer and investigate why we are seeing it" "3667": "handmade_opengl.cpp: Hard set CompileZBiasProgram() to write red into BlendUnitColor[0]" "3703": "Run the game to see that it isn't all red, and determine that some other phase must be wrong" "3793": "handmade_opengl.cpp: Make CompileResolveMultisample() pass the samplers to OpenGLLinkSamplers() in the correct order, and run the game to see that we're back to normal" "3815": "handmade_opengl.h and handmade_opengl.cpp: Remove peel_composite_program, final_stretch_program and multigrid_light_up_program, and their corresponding OpenGLProgramBegin() functions" "3969": "Run the game to see that we're still fine" "3975": "handmade_opengl.cpp: Try and force CompileResolveMultisample() to use layout(location = 8)" "4245": "handmade_opengl.cpp: Toggle back on the depth peel importing in ComputeLightTransport()" "4277": "Run the game to see that this does appear to have imported the lighting values" "4432": "Determine to bounce the light around" "4650": "Blackboard: Multigrid light transport" "4842": "Blackboard: The multigrid dream" "5274": "handmade_opengl.cpp: Consider what we can do in CompileMultiLightDown()" "5366": "Blackboard: Bouncing light" "5421": "Blackboard: Figuring out how aligned light sources are" "5462": "handmade_opengl.cpp: Make CompileMultiLightDown() compute the facing term, the distance between lights and the falloff" "5685": "Note that we're not reconstructing the light positions" "5719": ""That's gonna be a whole bailiwick in and of itself"" "5768": "handmade_opengl.cpp: Make ReconstructPosition() in CompileMultiLightDown() use UV" "5812": "Run the game, crash in ExecuteBrain() and investigate why" "5942": "win32_handmade.cpp: Reduce the resolution in WinMain() and run the game to see that that looks better" "6066": "handmade_opengl.cpp: Make CompileZBiasProgram() create a white light and run the game to see what's happening" "6169": "handmade_opengl.cpp: Investigate why we are not seeing any colour contribution from textures" "6292": "handmade_opengl.cpp: Fix TransferLight() in CompileZBiasProgram() to use the Falloff, and run the game to see colour contributon" "6313": "handmade_opengl.cpp: Make TransferLight() in CompileZBiasProgram() transfer based on the facing direction and run the game to see that that is not working" "6463": "handmade_opengl.cpp: Investigate why the facing direction isn't producing the expected transfer" "6764": "handmade_opengl.cpp: Make CompileMultiGridDown() write the reconstructed normal into our second channel, and run the game to inspect that channel" "6927": "handmade_opengl.cpp: Make ReconstructNormal() in CompileMultiGridDown() overwrite the Z with 0 and run the game to see that upward facing components still contain green" "7022": "handmade_opengl.cpp: Make CompileDepthPeelToLighting() correctly compute the Nx and Ny and run the game to see better values" "7068": "handmade_opengl.cpp: Make ReconstructNormal() in CompileMultiGridDown() use the computed Z and run the game with more confidence that the normals are plausible" "7108": "handmade_opengl.cpp: Continue investigating why we're not getting any light transference" "7236": "handmade_opengl.cpp: Make CompileZBiasProgram() output the negative inner product of the surface normals" "7280": "Run the game to see that negative product" "7299": "handmade_opengl.cpp: Make CompileZBiasProgram() output the non-negative inner product of the surface normals" "7307": "Run the game to see this non-negative product" "7446": "Q&A" "7490": "Could some of our lighting code end up being used by the audio system to figure out where and how obstructed / reflected sound sources are?" "7561": "Try 1 - clamp()!" "7587": "Blackboard: Clamping normals" "7683": "Should you add a fake ceiling for lighting (or a non-fake ceiling based on the floor above the current one)?" "7728": "Not entirely related to today's stream, but will you perhaps use something like a pipeline state object for binding resources? I personally find that I get a few annoying debug messages telling me about resource hazards and I'd like a better way than randomly throwing in null binds in the middle of my code and would like a better way to bind resources to minimize API calls, and would love to see a good PSO implementation" "7894": "We are done for today" --- name: "day398" title: "Applying Lighting Back to Depth Peels" markers: "7": "Recap and set the stage for the day" "104": "Run the game to show where we left off with the lighting" "360": "A few words on playing around with new rendering techniques, considering what to do now" "439": "handmade_opengl.cpp: Prevent TransferLight() in CompileZBiasProgram() from attentuating based on the facing direction, and run the game to show that" "537": "Determine to produce an output image using the lighting data" "736": "handmade_opengl.cpp: Consider how to extend CompilePeelComposite() to use our lighting data" "874": "handmade_opengl.cpp: Augment CompilePeelComposite() to pull in the normals for each peel sampler" "1070": "handmade_opengl.cpp: Introduce LightPeel() in CompilePeelComposite()" "1200": "handmade_opengl.cpp: Introduce UnpackNormal2() and UnpackNormal3() in the GlobalShaderHeaderCode" "1407": "handmade_opengl.cpp: Continue to implement LightPeel() in CompilePeelComposite(), performing our lighting equation computation" "2115": "handmade_opengl.cpp: Introduce MaxLightIntensity global_variable, as a poor person's tone mapping" "2248": "Blackboard: Light Value Mapping" "2558": "Blackboard: Picking a "response curve" based on film stock" "2693": "handmade_opengl.cpp: Enable CompilePeelComposite() to sample and compute a response curve for LightC" "2993": "handmade_opengl.cpp: Pass ToCamera to LightPeel()" "3006": "handmade_opengl.cpp: Try and #define BeginShaderString and EndShaderString to enable 4coder to indent the heredocs" "3207": "handmade_opengl.cpp: Introduce ExtendNormalZ() for CompilePeelComposite() to call" "3380": "handmade_opengl.cpp: Enable CompilePeelComposite() to link up our samplers and bind our textures" "3679": "handmade_opengl.cpp: Make CompilePeelComposite() set ToCamera" "3820": "Run the game to see what it does" "3826": "Toggle off the debug lighting visualisation and run the game to see a pure black screen" "3862": "handmade_opengl.cpp: Investigate why CompilePeelComposite() is failing to correctly light the scene" "4044": "handmade_opengl.cpp: Make CompilePeelComposite() write out the normal directly, and run the game to see that" "4104": "handmade_opengl.cpp: Make CompilePeelComposite() write out RefN, and run the game to see that it does not look good" "4143": "handmade_opengl.cpp: Fix UnpackNormal2() and PackNormal2() for CompilePeelComposite() to call" "4324": "Run the game to see more sane normals" "4347": "handmade_opengl.cpp: Make CompilePeelComposite() write out the DiffuseInner, and run the game to see that" "4443": "handmade_opengl.cpp: Make CompilePeelComposite() write out the SpecInner, and run the game to see that that is the problem" "4490": "handmade_opengl.cpp: Prevent CompilePeelComposite() from raising SpecInner to the power, and to make SpecularPower range from 1 to 16" "4541": "Run the game to see that" "4568": "handmade_opengl.cpp: Make CompilePeelComposite() output our computed lighting and run the game to see that it is sane" "4586": "handmade_opengl.cpp: Prevent CompilePeelComposite() from accounting for the LightC, and run the game to see nothing" "4616": "handmade_opengl.cpp: Prevent OpenGLRenderCommands() from calling FakeSeedLighting(), and make it call ComputeLightTransport() before binding the ResolveFramebuffer" "4683": "Run the game to see our lit scene" "4750": "handmade_opengl.cpp: Try to make LightPeel() in CompilePeelComposite() use the computed LightN, and run the game to see almost black" "4777": "handmade_opengl.cpp: Revert LightPeel() to overwrite that LightN again" "4836": "Run the game" "4868": "handmade_opengl.cpp: Enable OpenGLRenderCommands() to switch between all the lighting buffers" "5115": "Run the game to switch between the lighting buffers" "5118": "win32_handmade.cpp: Swap the keys in Win32ProcessPendingMessages() for shifting up and down the levels of detail" "5141": "Run the game and switch between the different buffers" "5183": "handmade_opengl.cpp: Start to investigate the artifacting" "5355": "Check the time" "5383": "Blackboard: Diffuse mapping, sampling an entire hemisphere of incoming light" "5665": "Consider treating the light like a fluid, or at least making the down sample be more controlled" "5857": "handmade_opengl.cpp: Determine to make the texture dimensions in CompileMultiLightUp() not based on the render dimensions" "5973": "handmade_intrinsics.h: Introduce FindMostSignificantSetBit()" "6056": "handmade_opengl.cpp: Make CompileMultiLightUp() set the lighting texture dimensions to the closest power of two to the render dimensions" "6213": "Run the game to see the lighting buffers are more squat than expected, and investigate why" "6264": "handmade_opengl.cpp: Make CompileDepthPeelToLighting() take the FragUV" "6445": "Run the game to see that we're in better shape" "6501": "handmade_opengl.cpp: Consider setting the normals to something more sane" "6553": "Run the game and consider basing the lights' directional values on where they came from" "6732": "Blackboard: Building a vertex buffer of reflector facing directions" "7113": "Blackboard: Writing reflectors directly into a 3D texture, rather than using the depth peel pass" "7239": "Q&A" "7306": "So, I would like to ask something: Any advice for beginners? Most likely asked before, but I just heard about this, and while I am interested in game development and programming in general, I never managed to learn a language. I want to try again with C# and a course from Microsoft" "7356": "Is there going to be a top-level that doesn't have a ceiling and instead would have direct sunlight?" "7420": "Does "no library" include no standard library?" "7484": "To do smooth edges, do you need to do the multisampling on all the buffers (normal, diffuse, etc)?" "7542": "Any advice to working with all-OOP 'n' const programmers?" "7714": "Does GL have support for fully 3D textures?" "7764": "As someone who was taught and always worked with OO programming, how does one enlighten themselves?" "8087": "Could you overlay an additive gradient on top of the "card" geometry to make them seem to have more depth (to emulate more of a cone shape)?" "8168": "Wouldn't trilinear sampling for a 2D texture imply sampling across different MIP levels? If so, what T value does the GPU use to interpolate between the layers?" "8207": "Blackboard: Picking the correct MIP level for trilinear sampling" "8607": "What are your opinions on DRM?" "8610": "Okay, since we're low on questions. I'm working on an AI to play a game, and I'm wondering if you have any general tips for it. More specifically, the game is World of Warcraft. Right now I'm only at basic functions and working on the image processing pipeline" "8647": "Wind it down" --- name: "day399" title: "Creating a CPU-side Lighting Testbed" markers: "9": "Recap and set the stage for the day, with a few words on loadable shaders and heredoc indentation" "165": "handmade_opengl.cpp: Try out mmozeiko's idea to put a closing quote before the heredoc text" "221": ""Unfortunately it looks like here 4coder is too smart for us"" "267": "Spec out a possible string opener for 4coder to understand" "331": "Oh, that worked: __blablaFOO" "337": "handmade_opengl.cpp: Play further with the heredoc stuff, before admitting defeat for now with thanks to mmozeiko" "439": "Run the game to see where we last left off, noting that we are perhaps taking an unproductive approach in developing the system for the GPU" "695": "Switch our development of the lighting system to the CPU-side" "833": "handmade_render_group.cpp and handmade_world_mode.cpp: Introduce LightingTest() in order to enable UpdateAndRenderWorld() to hijack the RenderGroup" "1156": "Run the game to see our sprites" "1180": "handmade_render_group.cpp: Enable LightingTest() to edit the vertices" "1305": "Run the game to see a completely whitewashed screen" "1378": "handmade_render_group.cpp: Introduce struct lighting_element" "1572": ""Don't scratch your eye"" "1595": "handmade_render_group.cpp: Make LightingTest() initialise an array of lighting_element" "1655": "Blackboard: Extracting the vertex data of sprites" "1724": "handmade_render_group.cpp: Enable LightingTest() to copy that vertex data in to the Elements array" "1993": "Blackboard: Computing the radius" "2014": "handmade_render_group.cpp: Fix compile errors in LightingTest()" "2097": "Run the game and see no difference" "2103": "handmade_render_group.cpp: Enable LightingTest() to copy the lighting back out to the quads in a diamond shape" "2435": "Blackboard: Producing a full coordinate system from a vector for drawing out the lighting" "2780": "handmade_render_group.cpp: Enable LightingTest() to produce that coordinate system and draw out the diamond" "3070": "Run the game and see pure grey" "3082": "handmade_render_group.cpp: Investigate what LightingTest() is drawing" "3248": "handmade_render_group.cpp: Replace V0 and V2 with Vert0 and Vert2 in LightingTest()" "3325": "Run the game to determine that it's probably the pack that is incorrect" "3367": "handmade_render_group.cpp: Make LightingTest() multiply the RGBAUnpack4x8() and RGBAPack4x8() calls into the correct colour space" "3508": "Run the game to see that we're getting a little closer" "3513": "handmade_render_group.cpp: Continue to investigate the problem" "3570": "Step in to LightingTest() and inspect the Vert0 and Element->RefC" "3652": "handmade_render_group.cpp: Make LightingTest() work on Element when computing the lighting" "3666": "Run the game to see that we're good to go" "3674": "Step in to LightingTest() to inspect the positional values" "3725": "handmade_render_group.cpp: Make LightingTest() correctly set the Y" "3738": "Step in the LightingTest() and again inspect the positional values" "3770": "handmade_render_group.cpp: Make LightingTest() correctly set the base" "3858": "Step in to LightingTest() and inspect our expected positions" "3869": "Run the game to see how we're doing" "3882": "handmade_render_group.cpp: Make LightingTest() set the vertices in the same order as PushQuad()" "3953": "Run the game to see our diamond reflectors" "4060": "handmade_render_group.cpp: Toggle off the copying out of the lighting, and run the game to consider the pink and yellow debug rectangles" "4122": "handmade_render_group.cpp: Try to make LightingTest() more sanely set the span for long, thin rectangles" "4327": "Run the game to still see large pink rectangles" "4432": "handmade_render_group.cpp: Make LightingTest() use the correct winding when copying the lighting in" "4464": "Run the game to see that that fixes it, and consider this representation of the lighting" "4591": "handmade_render_group.cpp: Introduce a moveable light source in LightingTest()" "4781": "Run the game and move our light source" "4803": "handmade_render_group.cpp: Enable LightingTest() to propagate the light in an O(n²) fashion" "5170": "Run the game to see black, because the rendering is so slow" "5280": "handmade_world_mode.cpp: Toggle off the particles and only create one screen" "5376": "Run the game to see our room" "5392": "handmade_world_mode.cpp: Reduce the room size in AddStandardRoom()" "5448": "Run the game and move around our tiny room" "5494": "handmade_render_group.cpp: Reenable our O(n²) loop and run the game to see our lit room" "5564": "handmade_render_group.cpp: Change how LightingTest() sets the light colour" "5585": "Run the game to see the disco lighting" "5608": "handmade_render_group.cpp: Make LightingTest() clamp the emitters' colours" "5671": "Run the game to still see a little flickering" "5687": "handmade_render_group.cpp: Make LightingTest() sum into a separate colour accumulator" "5810": "Run the game to see that it's somewhat incorrect" "5828": "handmade_render_group.cpp: Make LightingTest() factor in the distance to the light" "5973": "Run the game to see that it's still a little bit wonky" "6075": "handmade_render_group.cpp: Make LightingTest() factor in the distance falloff" "6118": "Run the game and consider that we may have too much angular flickering" "6199": "handmade_render_group.cpp: Make LightingTest() propagate the light in three loops" "6253": "Run the game to see a lot of flickering, and consider the sanity of developing on the CPU" "6301": "handmade_render_group.cpp: Prevent LightingTest() from using the distance falloff, and only do one iteration" "6332": "Run the game and wonder why lateral movement causes so much flickering" "6404": "handmade_render_group.cpp: Consider where LightingTest() may be wrong" "6486": "Q&A" "6547": "Could you enable the overlay. Your head is in the way" "6575": "Consult Microsoft Spy++ for the currently open programs" "6758": "Sorry the trick didn't work, it works for editor I use. There is an option to try to use old non-raw string literals: char* shader = STRINGIFY( ... write multiline code here ... ); where STRINGIFY is macro with # preprocesor thing. Compiler will smush multi-line code into one-line string and you'll lose line numbers in error messages, but they don't seem to be used on stream anyway" "6824": "handmade_opengl.cpp: Try to #define SHADER_CODE in an effort to enable 4coder to indent our shader code" "7108": "Hi! Not sure if this might be something for the forums, but I am on Day 60 and I just swapped to develop on my laptop and am noticing that I am missing the frame rate pretty frequently when Sleep is called: it misses with a few ms. My output log is not as smooth as yours with 33.33m/s every log message, but instead it fluctuates a bit over it. Is this something that gets addressed further down in the episodes?" "7124": "Did the black overlay disapear during the stream, or during Q&A? From the code, if TargetActive, we fade in the CornerWindow. But if the countdown has finished and what not, then it is not active any more" "7201": "You can do char* shader = SHADER_CODE(n#include "shader.h"n); and then put code in new shader.h file, maybe then indentation will be fine afterwards" "7238": "No, it will work" "7348": "Close it down" --- name: "day400" title: "Adding an Ambient Occlusion Pass" markers: "1": "Recap and set the stage for the day" "89": "Run the game to see the lighting diamonds" "331": "handmade_render_group.cpp: Make LightingTest() correctly sum the Dest->FrontEmitC" "355": "Run the game to see the correctly summed colours" "368": "handmade_render_group.cpp: Make LightingTest() account for the DistanceFalloff" "436": "Run the game with DistanceFalloff and summation, and consider our way forward" "497": "handmade_render_group.cpp: Make LightingTest() set DiffuseInner to 1.0f" "515": "Run the game to see the flickering" "542": "Determine to introduce the ability to add light sources" "747": "handmade_platform.h: Add Emission to the textured_vertex struct" "851": "Run the game to see that nothing bad happens" "870": "handmade_render_group.cpp: Make PushQuad() and LightingTest() set the emission" "1000": "Run the game to see everything unlit" "1007": "handmade_render_group.cpp: Introduce PushLight()" "1163": "handmade_world_mode.cpp: Make UpdateAndRenderWorld() call PushLight()" "1259": "Run the game and see a cube light that is not emitting any light" "1288": "handmade_render_group.cpp: Make PushQuad() take Emission" "1347": "Run the game to see our emitting light, with less flickering, but that the light itself is not lit up" "1495": "handmade_render_group.cpp: Add a BreakHere in LightingTest() for the light" "1558": "Step in to LightingTest() and inspect the values for the light" "1679": "handmade_render_group.cpp: Make LightingTest() correctly set the FrontEmit" "1715": "Run the game to see our lit light" "1758": "handmade_render_group.cpp: Make LightingTest() iterate three times" "1769": "Run the game to see our much brighter scene, now with flutter" "1803": "handmade_render_group.cpp: Revert LightingTest() to perform one iteration" "1810": "Run the game and consider building a wall" "1845": "handmade_world_mode.cpp: Make AddStandardRoom() add a wall" "2015": "Run the game to see our wall" "2156": "handmade_render_group.cpp: Enable LightingTest() to compute the colours differently in the debug and game view" "2364": "Run the game to see the beautiful game view" "2479": "handmade_render_group.cpp: Consider gathering the light from the cubes' corners rather than their faces" "2573": "handmade_config.h: Add Global_Renderer_Lighting_ShowReflectors and Global_Renderer_Lighting_IterationCount" "2708": "win32_handmade.cpp: Try to add keys in Win32ProcessPendingMessages() to control the reflectors and lighting iteration count" "2807": "handmade_opengl.cpp: Prevent OpenGLRenderCommands() from calling ComputeLightTransport()" "2832": "win32_handmade.cpp: Increase the resolution in WinMain()" "2854": "Run the game to see that it's totally usable for lighting" "2865": "handmade.cpp: Add lighting controls to the debug system" "2923": "Run the game and try out those lighting controls" "2993": "Determine to compute the lighting hierarchically" "3132": "Consult the multipass shadowing algorithm" "3307": "Run the game and consider the problem of shadowing" "3430": "Blackboard: Comparing reflectors, being an O(n³) problem" "3531": "Read 14.3 Indirect Lighting and Area Lights" "3626": "Run the game and consider an iterative solution across multiple frames" "3716": "handmade_render_group.cpp: Start to enable LightingTest() to compute some shadowing" "3837": "Consult the disk-to-disk occlusion algorithm" "3932": "handmade_render_group.cpp: Enable LightingTest() to compute the disk-to-disk occlusion" "4104": "Blackboard: Shadow Approx." "4798": "A mini rant on papers giving partial solutions" "4926": "Consider what their saturate function is meant to be doing" "5191": "Blackboard: Understanding their shadow approximation equation" "5365": "handmade_render_group.cpp: Enable LightingTest() to compute this shadow approximation equation" "5528": "handmade_intrinsics.h: Introduce ReciprocalSquareRoot()" "5567": "handmade_render_group.cpp: Continue to implement the shadow equation in LightingTest()" "6088": "Blackboard: Occlusion from in front and behind" "6106": "handmade_render_group.cpp: Break out the shadow equation values in LightingTest()" "6322": "Correcting for occlusion by overlapping objects" "6403": "handmade_render_group.cpp: Enable LightingTest() to iteratively occlude" "6607": "Run the game to see the shadowing looking kind of reasonable" "6681": "handmade_render_group.cpp: Make LightingTest() perform one shadowing iteration, and run the game to see that the wall's front face is not all black" "6740": "handmade_render_group.cpp: Move the Dest->Visibility setting one scope out in LightingTest()" "6759": "Run the game to see that the wall's front face is still black here" "6831": "handmade_render_group.cpp: Read carefully though the shadowing code in LightingTest()" "6961": "handmade_render_group.cpp: Add assertions in LightingTest() and compile in debug mode" "7003": "Run the game and fail to hit those assertions" "7124": "handmade_render_group.cpp: Assert in LightingTest() that the Visibility >= Dest->Visibility on the first iteration" "7173": "Run the game, hit that assertion and consider why" "7237": "handmade_render_group.cpp: Add a Shadow in LightingTest() to accumulate based on the Visibility" "7482": "Run the game to see our ambient occlusion solution" "7520": "Q&A" "7603": "square root (A/pi + r²) = square root (r² * ( A/(pi * r²) + 1) = r * square root (A/(pi * r²) + 1)" "7651": "Blackboard: Pulling the r out of square root (A/π + r²)" "7836": "Thank you very much for 400 days of programming. Had I remembered I would've sent you a golden crown to wear today. You're awesome!" "7843": "What do extra iterations do for ambient occlusion? I understand it for bouncing light, but shadows?" "7859": "Blackboard: Calculating ambient occlusion over multiple iterations" "8172": "Should the accumulator for the light passes be reset to zero at the start of the next pass?" "8200": "handmade_render_group.cpp: Make LightingTest() reset the accumulator" "8270": "Run the game to see the current lighting" "8294": "handmade_render_group.cpp: Make LightingTest() perform ambient occlusion" "8335": "Run the game to see how that looks with ambient occlusion" "8450": "handmade_config.h: Increase the Global_Renderer_Lighting_IterationCount and run the game to see how that looks" "8542": "It seems like the ground colors are off. Looks like it goes light green > gray > dark green" "8664": "handmade_render_group.cpp: Make LightingTest() cast the Element->Visibility calculation to a V4 in the setting of FrontEmit" "8725": "Run the game to see how that looks" "8800": "Wind it down" --- name: "day401" title: "Debugging Lighting Transfer" markers: "7": "Recap and set the stage for the day" "74": "Run the game to see how the lighting is looking at the moment" "459": "Note some oddities in the lighting solution" "614": "handmade_render_group.cpp: Prevent the ambient occlusion code from running and run the game to still see the bright flashes" "710": "handmade_config.h: Only do one pass of the lighting solution, and run the game to see that this is relatively stable" "794": "handmade_config.h: Add Global_Renderer_Occlusion_IterationCount for LightingTest() to use" "823": "Run the game doing two ambient occlusion passes" "884": "handmade_config.h: Switch to the game view, with two ambient occlusion passes, and run the game to see how that looks" "1081": "handmade_config.h: Increase the number of lighting iteration passes and run the game with the determination to investigate the flashes" "1235": "Launch Milton and try out the tablet tracking" "1378": "Blackboard: Light Conservation" "1725": "Blackboard: Converging on a good lighting solution" "1800": "handmade_render_group.cpp: Consider making emission a first-pass-only process" "1960": "Blackboard: Occluded Reflectors, and Total Emittance" "2257": "The difficulty of parallelised summation" "2388": "Blackboard: Radiosity, and stabilising the contribution of light by multiple proximate reflectors, with a recommendation to read literature on the problem" "2617": "Blackboard: Considering how to handle over-contribution of light distribution" "2884": "handmade_render_group.cpp: Organise lighting_element to aid our conceptualisation of the light conservation problem" "3198": "Hit an error in OpenGLDebugCallback()" "3270": "Blackboard: All light must go somewhere" "3333": "handmade_render_group.cpp: Enable LightingTest() to make RefC converge towards 0, and track the transference and accumulation of light" "3805": "handmade_render_group.cpp: Enable LightingTest() to correct for the wrongness of the transfer" "4270": "Step through LightingTest()" "4390": "Consider how to handle emission" "4426": "handmade_render_group.cpp: Prevent LightingTest() from performing the correction and just letting the light bounce ad infinitum" "4467": "Run the game to see the flickery results" "4496": "handmade_render_group.cpp: Let LightingTest() perform the correction again, and run the game to see the flickering still" "4536": "Consider how to handle the total light transfer" "4655": "handmade_render_group.cpp: Add PhotonsToSend and PhotosReceived to lighting_element, for LightingTest() to use" "4934": "handmade_render_group.cpp: Enable LightingTest() to draw the photons" "5011": "Run the game to see the photons transference" "5048": "handmade_render_group.cpp: Assert in LightingTest() that PhotonsToSend <= TotalPhotonCount, run the game, hit that assertion and investigate why" "5203": "handmade_render_group.cpp: Make LightingTest() actually multiply in the correction" "5234": "Run the game in release, and see that it is more correct but that the flickering is still there" "5436": "Run the game on a loop and change the lighting iteration count to see how that affects it" "5560": "handmade_world_mode.cpp: Prevent AddPlayer() from adding any body parts and hit points" "5646": "Run the game and move just the light, to determine that the hero himself was causing the flickering problem" "5799": "handmade_render_group.cpp: Make LightingTest() strictly sum the FrontEmitC, and run the game without flickering, noting that the occluders are spaced far apart" "5971": "Determine to fix the distance falloff for close objects" "6011": "handmade_render_group.cpp: Let LightingTest() temper the FrontEmitC by the number of lighting iterations" "6102": "handmade_render_group.cpp: Remove PhotonsToSend and PhotonsReceived from lighting_element" "6154": "Run the game to see the stable light" "6164": "handmade_world_mode.cpp: Let AddPlayer() add body parts, and run the game noting that these body parts are very bright" "6268": "handmade_render_group.cpp: Fix the DistanceFalloff computation in LightingTest()" "6284": "Blackboard: Distance Falloff" "6505": "Run the game to see that the flickering has gone" "6567": "handmade_world_mode.cpp: Make AddStandardRoom() draw the walls in red" "6678": "Run the game to see if we get red light bleeding from the walls" "6713": "handmade_config.h: Perform two ambient occlusion passes and run the game" "6874": "Q&A" "6887": "Is it supposed to be Square(...) and not SquareRoot(...)?" "6975": "handmade_render_group.cpp: Make LightingTest() prevent the DistanceFalloff from getting below 1" "7004": "Run the game to see how that looks" "7078": "Now we don't need to do a global pass to normalize light?" "7147": "Is it useful to convert the surface color from RGB to YUV in these equations, as in using Y to modulate light contribution somehow?" "7255": "Do you know how much does a GPU gather cost compared to a load from a linear memory read?" "7321": "I wrote GPU, not CPU" "7357": "handmade_config.h: Play with the lighting IterationCount and run" "7397": "Spectral lighting is something I never heard of before. Can you point out some good resources on the topic?" "7544": "In CPU it's much more efficient to read a cache line using _mm_load and not use the gather commands. Is the same true of the GPU?" "7945": "Thanks, so you usually don't want to swizzle it yourself?" "8159": "Is HMCon 3 still at the start of 2018?" "8192": "ctray improvement: Would you be so kind as to give a suggestion of how you tackle saving the day? Do you prefer temp files (i.e. in %AppData%)? Just keep it simple like how you read settings.ctray. Should I look at how you save state like in ctime? I can try to tackle an alternative this week for I do need to become more confident in reading / writing to files" "8284": "But that's what I did! I made it an ini file and rewrote that" "8355": "Is it possible to mode-change monitor frequency nowadays (say from 75Hz to 60Hz) so I always try to get my game loop to run at 60Hz?" "8527": "ctray question: As an exercise, I would like to investigate the cost of just bringing the overlays to the top and checking first if the overlays need to be brought forward. What should I look for? Should I profile the calls? Should I run it continuously to see if I get an error case? I realize this may not be the best thing to use as an example, but it was something I struggled with" "8675": "Close that" --- name: "day402" title: "Adding Raycasting to the Lighting" markers: "17": "Recap and set the stage for the day" "95": "Run the game and consider how we can improve the lighting quality" "216": "Determine to work on directional shadowing or light bleeding" "475": "Light transference between reflectors" "784": "Blackboard: Cube mapped reflectors" "1036": "Gesture wildly" "1070": "Blackboard: The magic of the Z-buffer" "1214": "Blackboard: Emulating the effects of a Z-buffer in the lighting system" "1422": "Blackboard: Casting cones" "1583": "Blackboard: Ray / Plane Intersection" "2094": "Blackboard: Modelling reflectors as disks for the purposes of shadowing" "2536": "Determine to pick one reflector on which to do the computations" "2657": "Welcome votes to be freely cast in the chat" "2669": "On democracy..." "2692": "...and oppression" "2698": "handmade_render_group.cpp: Enable LightingTest() to pick and highlight a reflector for us to use" "2983": "Run the game and find our picked reflector" "3130": "handmade_render_group.cpp: Enable LightingTest() to isolate our test reflector in the compute lighting path" "3275": "Run the game and see that our test reflector didn't bleed out any light" "3370": "handmade_render_group.cpp: Enable LightingTest() to strengthen the yellow of our test reflector and run the game" "3437": "handmade_render_group.cpp: Enable LightingTest() to cast rays from our test reflector out into the scene" "3738": "Blackboard: Casting rays from the reflector" "3788": "handmade_render_group.cpp: Continue to enable LightingTest() to cast rays from our reflector" "3962": "Blackboard: Computing the intersection point of a ray with the plane of a reflector" "4044": "handmade_render_group.cpp: Start to enable LightingTest() to determine whether reflectors intersect" "4194": "Blackboard: Determining whether reflectors intersect" "4227": "handmade_render_group.cpp: Finish enabling LightingTest() to determine whether reflectors intersect and then compute shadowing for them" "4557": "Run the game to see that our test reflector is black" "4615": "handmade_world_mode.cp: Toggle off the hero's body and run the game again to see that our light does not affect the reflector" "4684": "handmade_world_mode.cpp: Increase the radius passed to PushLight() by UpdateAndRenderWorld()" "4758": "Step in to LightingTest() to inspect what it does" "4820": "handmade_render_group.cpp: Make LightingTest() only cast rays out of the front of our reflector" "4875": "Run the game to see that our light does light up our test reflector" "4914": "handmade_render_group.cpp: Try running the ray casting on everybody" "4958": "Run the game to see everyone apparently unlit" "4993": "handmade_render_group.cpp: Make LightingTest() cast out eight rays in many directions" "5124": "Run the game to see reflectors getting lit up" "5209": "handmade_render_group.cpp: Enable LightingTest() to perform cone-based ray tracing" "5276": "Run the game to see more pick-up of the light" "5335": "Blackboard: Needing to determine how much of a cone is being intersected" "5513": "handmade_render_group.cpp: Make LightingTest() generate 32 rays pointing in random directions" "5733": "Run the game to see the ray traced lighting, and increase the number of rays" "5900": "handmade_render_group.cpp: Reduce the number of rays to 16" "6017": "Step in to LightingTest() and inspect the rays" "6149": "handmade_render_group.cpp: Enable LightingTest() to cast narrow cones, and run the game" "6229": "handmade_render_group.cpp: Enable LightingTest() to direct rays more cleverly" "6416": "Run the game and note that we are getting a real shadowing solution now" "6502": "handmade_brain.cpp: Make ExecuteBrain() clamp the spring down" "6649": "Run the game and look at our lighting solution" "6729": "handmade_world_mode.cpp: Make AddStandardRoom() build a second wall" "6785": "Run the game to see how the walls occlude and reflect the light, with different numbers of lighting passes" "6966": "handmade_world_mode.cpp: Make AddStandardRoom() build different coloured walls" "7007": "Run the game to see how the two walls behave in the light" "7064": "handmade_render_group.cpp: Make LightingTest() increase the max emission" "7097": "Run the game to see the brighter light" "7218": "Q&A" "7268": "Are there engine features or ideas that emerged during the Handmade Hero streams and that you've since "backported" to the 1935 engine?" "7365": "For the random series you picked (at random) 1234. Could it have made any sense to pick 360 there, for 360 degrees, or would absolutely any number do?" "7539": "Probably the ingest server hiccuped or something" "7632": "I think you can keep files open in visual studio by clicking the icon next to the close icon" "7789": "Tools > Options > Environment > Tabs and Windows > deselect allow new files to be opened in preview tab" "7836": "Not related to lighting but I've been catching up with the multithreaded sim regions tonight and noticed that we never unset the entity active flag if an entity is not contained in the updatable bounds" "7918": "handmade_sim_region.cpp: Enable BeginWorldChange() to clear the EntityFlag->Active" "8007": "handmade_world_mode.cpp: Let PlayWorld() call AddMonstar() and run the game" "8038": "handmade_world_mode.cpp: Let PlayWorld() put the snake in the world, and run the game to say hello to it" "8151": "handmade_entity.h and *.cpp: Add a Light entity_visible_piece_flag and make UpdateAndRenderEntities() call PushLight()" "8312": "handmade_world_mode.cpp: Introduce AddPieceLight()" "8447": "handmade_world_mode.cpp: Make AddSnakeSegment() call AddPieceLight()" "8529": "Run the game to see the lit up snake" "8656": "Run the game and note that our lighting scheme does not incur a cost per light source" "8754": "handmade_render_group.cpp: Enable LightingTest() to distribute light with no occlusion after some iterations, and run the game" "8923": "ctray license question. May I continuously update my GitHub branch of your timer (ctray) code from Handmade Hero, until you say otherwise, meaning you are preemptively giving unlicense / public domain to any further code in that folder? Would you prefer I ask every time for permission so you don't need to worry? I can do whichever is more convenient to you" "8954": "Close it down" --- name: "day403" title: "Off-line Lighting and Per-vertex Reflectors" markers: "7": "Introduce the new location, recap and set the stage for the day" "118": "Run the game and consider the current state of the block lighting" "359": "Blackboard: Multiresolution and Quality" "1005": "Blackboard: Aggregating reflectors" "1132": "Run the game and consider switching to rectangular reflectors" "1347": "Blackboard: Figuring out a multiresolution raycasting scheme" "1765": "Run the game and consider switching to an offline lighting solution, for experimentation purposes" "1850": "handmade_render_group.cpp: Make LightingTest() cast out 64 and then 256 rays and run the game to demonstrate how unusable this is" "1952": "handmade_render_group.cpp: Set up LightingTest() to compute the lighting offline" "2095": "handmade_render_group.h: Introduce lighting_solution for LightingTest() to use" "2184": "handmade_world_mode.cpp: Set up UpdateAndRenderWorld() to output the lighting on a key press" "2214": "handmade_render_group.cpp: Split out some of LightingTest() into a new OutputLighting() function" "2977": "handmade_world_mode.cpp: Make LightingTest() store the bitmaps when copying the lighting in" "3141": "win32_handmade.cpp: Enable Win32ProcessPendingMessages() to handle the F-keys" "3388": "handmade_world_mode.cpp: Enable UpdateAndRenderWorld() to toggle ShowLighting mode on a key press" "3547": "Run the game, try toggling to ShowLighting mode and hit an assert in PushQuad()" "3651": "handmade_render_group.cpp: Make OutputLighting() call GetCurrentQuads() up front" "3706": "Run the game and toggle to ShowLighting mode" "3745": "Infinite waters" "3787": "handmade_render_group.cpp: Make OutputLighting() loop through all the Elements, and LightingTest() write out the correct Bitmaps" "3861": "Run the game and toggle to ShowLighting mode" "3881": "win32_handmade.cpp: Make Win32ProcessPendingMessages() correctly clear the pressed key" "3956": "Run the game, toggle to ShowLighting mode and consider the solution" "4130": "handmade_render_group.cpp: Temporarily make ComputeLighting() set the lighting to full white, and run the game to confirm that we are correctly writing out the lighting" "4196": "Get some water" "4238": "Return with water" "4268": "handmade_render_group.cpp: Make LightingTest() cast 8 rays, run the game and consider if we are accumulating and not averaging" "4362": "handmade_render_group.cpp: Make LightingTest() correctly accumulate the rays" "4444": "Run the game to see that our lighting solution is a lot better" "4525": "handmade_render_group.cpp: Make OutputLighting() wind the vectors in the correct order" "4570": "Run the game and consider using the quad structures themselves as reflectors" "4866": "handmade_render_group.cpp: Make LightingTest() cast 256 rays, run the game and consider using the ray count as a divisor" "4986": "handmade_render_group.cpp: Make LightingTest() factor in the ray count" "5037": "Run the game to see a more stable lighting solution, in terms of its brightness" "5163": "Run the game and consider smoothing out the lighting solution across reflectors" "5722": "handmade_render_group.cpp: Split out LightingTest() into a new ExtractReflectorsFromQuads() function" "5926": "handmade_render_group.cpp: Introduce ExtractReflectorsFromVerts()" "6224": "Run the game and view just the reflectors" "6362": "handmade_render_group.cpp: Make ExtractReflectorsFromVerts() correctly create the four vertices" "6392": "Run the game to see our reflectors' vertices" "6492": "Run the game and temporarily believe that it is correct" "6559": "handmade_render_group.cpp: Consider making ExtractReflectorsFromVerts() position the vertices correctly" "6627": "Blackboard: Evenly distributing reflectors across a face" "6684": "handmade_render_group.cpp: Make ExtractReflectorsFromVerts() distribute the reflectors" "6826": "Run the game and take a look at the fairly regularly tiled reflectors" "6859": "handmade_render_group.cpp: Introduce OutputLightingQuads() and OutputLightingVerts()" "7160": "Run the game and check out the lighting solution, now with vertex-based banding" "7252": "Q&A" "7341": "You can triangle order the verts for the banding issue?" "7363": "Blackboard: Triangle vertex order picking" "7469": "Forgive me, but is the game currently running in the hardware renderer, or software?" "7484": "So I had the idea of maintaining all geometry in a geometrically determined hash table, computing the trajectory of the reflections and looking up where the resulting geometry is. Is that something that would be workable, or am I missing something?" "7520": "Blackboard: Using a geometrically determined hash table to compute the trajectory of reflections" "8016": "WeeChat works pretty well, if this is on Linux" "8066": "If you figure it out, tell Autodesk how to fix how MAYA's weight painting looks" "8121": "Would it be possible to write a transpiler so that we could take this C code and run it on the GPU trivially after debugging on CPU?" "8243": "In your lighting formulae, you use negative spans like "-0.25f*Span10". What if everything is supposed to be a displacement off Vertex0? Shouldn't you have "+0.75f" at some point instead of something negative?" "8295": "You're using square, so why not filter bilinearly along the square axes rather than interpolating over the triangles? That should avoid the diagonal seams" "8341": "Blackboard: Interpolating perpendicularly between the squares' edges" "8467": "Light doesn't behave linearily. That's why the banding occurs in the first place" "8532": "Wrap it up" "8573": ""It's not live now"" --- name: "day404" title: "Voxel-Indexed Lighting Samples" markers: "8": "Recap and set the stage for the day" "42": "Run the game and consider the problem of reconstructing per-pixel lighting from our coarse computations" "515": "Blackboard: Sending down four interpolation points per quad, instead of doing a global gather" "904": "Blackboard: Radial-normalised interpolation" "1051": "Run the game and consider whether or not to interpolate across primitives" "1241": "Blackboard: Lighting Lookups" "1485": "Blackboard: Storage format for a spherical query" "1534": "Blackboard: Quick spatial query" "1860": "Consider the problem of packaging up this data for parallel access by the GPU" "2358": "Consult the Texture Lookup Functions in the OpenGL Shading Language 1.50 Quick Reference Card for sampling from a 3D texture" "2475": "Blackboard: Artifacts across cell boundaries" "2668": "Determine to create a voxel-based lighting solution" "2714": "handmade_render_group.cpp: Introduce OutputLightingTextures()" "2785": "handmade_world_mode.h: Augment lighting_solution to contain voxel and storage information" "3125": "handmade_world_mode.h: Introduce lighting_texel linked list for fast access lookup" "3354": "handmade_world_mode.h: Introduce lighting_textures" "3406": "handmade_render_group.cpp: Begin to enable OutputLightingTextures() to pack our lighting data" "3574": "handmade_render_group.cpp: Determine to prevent OutputLightingQuads() from considering the reflector's own colour" "3612": "Run the game to see that it's running slower than expected" "3737": "Run the game and note that we want to stop the reflectors from considering their own colour during the lighting pass" "3771": "handmade_render_group.cpp: Change LightingTest() to multiply in the reflector's colour at the start, and ExtractReflectorsFromVerts() and ExtractReflectorsFromQuads() to not use the reflector's own emission colour" "3982": "Run the game to see that the red and blue reflectors do not show their own colour, but that these colours are also not bouncing off other reflectors, and investigate why" "4313": "handmade_render_group.cpp: Continue to enable OutputLightingTextures() to pack our lighting data into a linked list" "4574": "Blackboard: Mapping world space positions into a screen space lookup table" "4845": "handmade_render_group.cpp: Make OutputLightingTextures() index into voxels" "5123": "Blackboard: Picking a cell from a grid" "5220": "handmade_render_group.cpp: Make OutputLightingTextures() map the lighting into our voxel" "5559": "handmade_world_mode.cpp: Make UpdateAndRenderWorld() call OutputLightingTextures() on test textures" "5731": "handmade_render_group.cpp: Introduce OutputTextureDebug() for OutputLighting() to call" "6193": "Run the game, toggle to the lighting view and see nothing" "6236": "Step in to OutputLightingTextures() and..." "6340": "Wish for the ability to optimise just one routine while waiting for our lighting solution to be computed" "6397": "...inspect the values produced by OutputLightingTextures()" "6512": "handmade_render_group.cpp: Fix OutputTextureDebug() to index into the correct locations" "6550": "Run the game in release mode and see weirdly positioned light voxels" "6645": "handmade_render_group.cpp: Try to put #pragma optimise around OutputTextureDebug() to disable optimisations" "6670": "Step through OutputTextureDebug() to see that the colour is not a sane value" "6786": "handmade_render_group.cpp: Try to make OutputTextureDebug() set the colour to white, and run the game to see that we are storing lighting samples, but that only the colour value is incorrectly computed" "6852": "handmade_render_group.cpp: Fix OutputLightingTextures() to multiply the colour into the correct space" "6871": "Run the game and see our voxelised lighting samples" "6895": "Q&A" "6897": "handmade_render_group.cpp: Remove the #pragma optimize" "6923": "Run the game and express interest in seeing how this works" "7069": "Greetings Casey! For after the stream, here is a collaborative work from us in #hero for a help guide to setting up WeeChat" "7207": "Maybe it's a non-issue, but because the entity is tilted, when it walks in front of a cube it is being cut. Is there an elegant solution for it?" "7294": "handmade_world_mode.cpp: Make AddPlayer() draw the hero bitmap and run the game" "7330": "handmade_render_group.cpp: Increase the ZBias in PushBitmap() and run the game to see that the hero gets clipped differently by the geometry" "7515": "When we made the high and low priority thread queues, how did we make the high queue actually have a higher priority? I can't find the difference between them in the implementation, if that makes sense" "7883": "If I was to guess, I would say the problem is not the 2D entities in 3D space, but rather 2D entities with 3D entities. If those cubes were sprites like the trees, it would work just fine" "7983": "In the software renderer we aligned the memory to 16 bytes for SIMD but then we used the unaligned load and store instructions. Why is that?" "8178": "Blackboard: False sharing of one cache line by two threads" "8292": "That's about it for today" --- name: "day405" title: "Crashing the Stream with a Fragment Shader" markers: "4": "Recap and set the stage for the day" "77": "Determine to handle the "Unable to compile Z Bias program on GTX 1070" issue" "257": "Run the game to see the current voxel-based lighting solution" "300": "handmade_opengl.cpp: Change all the shaders to use GLSL version 3.30" "450": "Run the game to see everything working as before" "490": "Close that issue" "739": "Determine to fix the "Shader layout issue" issue" "802": "win32_handmade.cpp: Set GLSL version 3.30 in Win32OpenGLAttribs, run the game, and close that issue" "866": "Close the "Not compiling under VS2015" issue" "988": "Run the game, describe the voxel lookup scheme and determine to transfer this lighting solution to the GPU" "1223": "handmade_world_mode.h: Consider how to specify the lighting_textures to the GPU" "1406": "handmade_render_group.h: Introduce render_entry_lighting_transfer" "1541": "handmade_render_group.cpp: Introduce PushLighting()" "1745": "handmade_render_group.cpp: Make OutputLighting() call PushLighting()" "1805": "Run the game and hit the InvalidDefaultCase in OpenGLRenderCommands()" "1833": "handmade_opengl.cpp: Add a case in OpenGLRenderCommands() for the lighting_transfer" "2417": "handmade_platform.h: Move in lighting_texel and lighting_textures from handmade_opengl.h" "2452": "win32_handmade.cpp: Pull in glTexImage3D() and glTexSubImage3D() from corearb.h" "2617": "Run the game and hit an error, presumably because we haven't bound our lighting texture" "2683": "handmade_opengl.cpp: Make OpenGLChangeToSettings() bind and free the lighting textures" "3273": "Run the game without error" "3304": "handmade_render_group.cpp: Make OutputLightingTextures() call PushLighting()" "3404": "Run the game under the assumption that our lighting solution is now available on the GPU" "3427": "handmade_opengl.cpp: Remove the old lighting code from CompileZBiasProgram(), and enable it to lookup into our voxel-based lighting solution" "4629": "handmade_opengl.cpp: Make CompileZBiasProgram() and its UseProgramBegin() set up the voxels and link the samplers" "4845": "handmade_render_group.cpp: Make PushLighting() take the voxel data" "4943": "Run the game and see black" "4973": "handmade_opengl.cpp: Make OpenGLRenderCommands() bind the lighting textures" "5113": "Run the game and see no obvious errors, but still black" "5160": "handmade_opengl.cpp: Investigate what CompileZBiasProgram() is drawing" "5337": "Run the game and see red" "5340": "handmade_opengl.cpp: Investigate why we are always getting an index value of 0" "5616": "Run the game, toggle to the lighting view and inspect the values produced by OutputLightingTextures()" "5848": "handmade_render_group.cpp: Temporarily add volatile global variables for DebugX, DebugY, DebugZ and DebugColor" "5986": "Run the game and inspect those debug lighting values" "6011": "handmade_opengl.cpp: Force CompileZBiasProgram() to lookup into those debug values" "6058": "Run the game, toggle to the lighting view and determine that we are not getting valid values from the texture" "6148": "handmade_opengl.cpp: Change CompileZBiasProgram() to use usampler3D rather than sampler3D for the lookup sampler" "6775": "handmade_opengl.cpp: Revert CompileZBiasProgram() to use sampler3D, and itself convert the incoming colour to the 0 to 65535 range" "6851": "Run the game and crash the stream, to be lost forever were it not for the magic of Mārtiņš Možeiko" --- name: "day406" title: "Getting a Graphics Debugger Working" markers: "2": "Welcome to the new setup" "188": "Open up and begin to reacquaint ourselves with the code" "258": "Run the game to see that it is running correctly, but with weird artifacts" "340": "handmade_render_group.cpp: Continue to reacquaint ourselves with the lighting code" "1099": "handmade_platform.h: Describe the lighting_textures struct, from where we left off" "1328": "handmade_world_mode.cpp: Check our hotkeys" "1394": "Run the game and toggle on the lighting solution" "1467": "handmade_opengl.cpp: Make CompileZBiasProgram() set UseLightC to 1, 0, 0" "1568": "Run the game to see red" "1618": "Graphics debuggers" "1787": "Run our game in RenderDoc" "2139": "Install Nsight and update the graphics driver" "2901": "Run our game with the Nsight HUD enabled, try to capture a frame but remain stuck in the HUD" "3236": "Inspect our captured rendering data" "3427": "Try to capture a frame with the game window not fullscreen" "3598": "Inspect our shader data" "3788": "handmade_opengl.cpp: VoxMinCorner and VoxInvCelDim" "3845": "Run the game, toggle on the lighting, try to Alt-Tab to Visual Studio and crash in Win32ProcessPendingMessages()" "3989": "build.bat: Remove the HANDMADE_STREAMING workaround" "4153": "Run the game, crash in the same manner in Win32ProcessPendingMessages() and investigate why" "4782": "Read the disassembly in the TIMED_BLOCK PeekMessage, and guess that our debug events are piling up and overflowing" "5011": "build.bat: Toggle off HANDMADE_INTERNAL and run the game without problem" "5190": "Investigate our debug events overflow" "5369": "win32_handmade.cpp: Count our loops through TIMED_BLOCK("PeekMesssage") in Win32ProcessPendingMessages()" "5532": "Find a massive number of messages" "5656": "win32_handmade.cpp: Buffer up our messages" "5720": "Find that all those messages are 0x738, and try to identify that message" "5965": "Describe WM_USER" "6062": "Launch Spy++" "6326": "Use Spy++ to try and determine who is issuing the 0x738 messages" "6757": "Reflect on the situation" "7130": "win32_handmade.cpp: Temporarily prevent Win32ProcessPendingMessages() from calling TIMED_BLOCK("PeekMessage")" "7174": "Run the game to find that we avoid the crash" "7261": "Q&A" "7306": "Regarding message 0x738" "7534": "win32_handmade.cpp: Make Win32ProcessPendingMessages() skip the 0x738 message" "7740": "Run the game without crashing" "7895": "Consult our rendering data" "8008": "What do you mean by "generated" message?" "8136": "This seems to be a known big since Windows 10 build 1703" "8183": "How is the performance of the from-scratch-written renderer compared to OpenGL?" "8197": "How in 4coder you make it possible to have typedef highlight?" "8245": "If this has been answered many times, I’ll dig back through YouTube, but when and why did Handmade Hero move from being a fully software rendered project to using graphics APIs?" "8313": "Any chance to run the game with the lighting actually on, just for old time's sake?" "8319": "How would you cast a pointer and call it directly without an extra typedef?" "8419": "How about 2D? How is the performance there?" "8436": "Function pointer, yeah" "8440": "Demo calling a function pointer without making a typedef" "8704": "Blackboard: Mathematical operator precedence, and Dijkstra's shunting yard algorithm" "9004": "Blackboard: Abstract syntax tree" "9157": "Blackboard: Parsing a cast expression into an abstract syntax tree" "9247": "Blackboard: Understanding the function pointer cast" "9828": "I was doing some compiler things a few months ago. Could a parser programming (maybe operator parsing only) stream?" "9857": "Can you explain how you would fix some stuff such as the fog in PUBG someday? Maybe like a 9-hour lecture?" "9871": "What "blackboard" program are you using?" "9920": "A few words on C's type definition syntax" "10082": "Wrap it up" --- name: "day407" title: "Starting to Debug Volume Textures" markers: "8": "Recap our woes from yesterday regarding Windows and graphics drivers" "384": "Run the game to see where we left off" "505": "Continue to investigate why our lighting solution is not producing the expected colours" "957": "Step in to OutputLightingTextures() and inspect the lighting positions and elements" "1207": "Step in to PushLighting() and inspect the destination lighting entries" "1721": "handmade_render_group.cpp: Enable OutputTextureDebug() to average and visualise each voxel's colour values at its centre" "2196": "Run the game to see nothing in our lighting debug visualisation" "2358": "handmade_render_group.cpp: Make OutputTextureDebug() correctly compute the CellDim" "2403": "Run the game to see our lighting debug visualisation" "2473": "handmade_opengl.cpp: Make CompileZBiasProgram() use the lighting colour passed to it" "2488": "Run the game to see our coloured debug visualisation, and determine that we seem to be setting up the texture data correctly" "2654": "handmade_opengl.cpp: Make OpenGLChangeToSetting() store the lighting lookup in a GL_R16 texture" "2793": "Step in to OpenGLRenderCommands() and inspect the voxel lookup parameters" "2972": "Capture a frame and inspect the graphical data to determine that we are sending down our values properly" "3357": "handmade_opengl.cpp: Investigate how we are looking up into our texture" "3631": "handmade_opengl.cpp: Initialise LookupSampler as a usampler3D and try to store the LightingLookup as a GL_R16UI" "3958": "Investigate why we can't store the LightingLookup as a GL_R16UI" "4454": "handmade_opengl.cpp: Store the LightingLookup as a GL_R32F" "4576": "Capture a frame with a view to stepping through the shader" "5055": "handmade_opengl.cpp: Toggle off the setting of VoxI and the simulation bounds debug visualisation" "5446": "handmade_opengl.cpp: Try to set UseLightC manually" "5610": "Capture a frame and inspect the values in the lookup sampler" "5721": "handmade_platform.h: Try to force our voxel's LookupAt data to be floating point" "6082": "win32_handmade.cpp: Make the game launch windowed by default" "6115": "Capture a frame and inspect our voxel populated with values" "6407": "handmade_opengl.cpp: Try to enable CompileZBiasProgram() to read the stored values out of the texture" "6483": "Run the game and see that we still get nothing" "6520": "handmade_opengl.cpp: Make CompileZBiasProgram() colour the voxels by their UV position" "6611": "Run the game to see that the voxel positions are incorrect" "6708": "handmade_opengl.cpp: Try to make CompileZBiasProgram() draw the voxels as red if we are outside the voxel" "6903": "Run the game to confirm that we have a voxel alignment problem" "7121": "Q&A" "7161": "Try using GL_RED_INTEGER instead of GL_RED" "7192": "handmade_opengl.cpp: Make OpenGLRenderCommands() use GL_RED_INTEGER for the LookupTexture" "7287": "Run the game to see that our texture lookup is now correct" "7322": "handmade_opengl.cpp: Switch the lookup texture back to using the regular integer" "7500": "Run the game now storing the texture in integers" "7531": "Needs more 0x738" "7554": "I was wondering if you checked out GPUOpen" "7566": "How much prep do you do before every episode?" "7624": "I'm curious if fixing the WM message bug also fixed the crash in RenderDoc" "7645": "re shader debugging: "[1] Shader debugging is supported on Kepler family GPUs for Direct3D 11 and OpenGL [4.2 to 4.5]. Direct3D 12 & Vulkan APIs and Maxwell & Pascal family GPUs will be supported in upcoming releases." -- source: https://developer.nvidia.com/nsight-visual-studio-edition-requirements" "7665": "In my experience it's very good for developing GLSL to keep shaders in files, and have the software automatically reload them if they're changed. You can change them on the fly to try out different things. You also get syntax highlighting, and you can use #line to offset the line number for better error messages" "7715": "Off topic, so it's ok to ignore if you're in a hurry. Do you have any experience with rendering "impossible" spaces? Like in Antichamber or the secret levels of Duke Nukem 3D?" "7779": "Inspect our integer image" "7826": "Try to debug in RenderDoc with 0x738 fixed" "7935": "Close it down" --- name: "day408" title: "Finishing Debugging Volume Textures" markers: "3": "Recap and set the stage for the day" "38": "Fix the monitor's colour" "115": "Resume our investigations into the volume texture lookup" "286": "Determine to use structured art to verify that we are transmitting the correct values" "478": "handmade_render_group.cpp: Make OutputLightingTextures() write a monotonically increasing value into the lookup sampler" "630": "handmade_opengl.cpp: Make CompileZBiasProgram() use that value directly" "792": "handmade_render_group.cpp: Temporarily disable OutputTextureDebug()" "835": "Run the game and see nothing" "903": "handmade_world_mode.cpp: Prevent UpdateAndRenderWorld() from calling OutputLighting()" "992": "Run the game and hunt for a key binding to capture a frame" "1133": "Capture a frame and see that the lookup sampler contains all 0" "1218": "Run the game, run PushLighting() and capture a frame to see our expected values in the lookup sampler" "1315": "handmade_render_group.cpp: Make OutputLightingTextures() set the fragment shader's lighting texels and colour to known values" "1516": "Capture a frame, but find that the compiler has optimised out the lighting texels and colour" "1593": "handmade_opengl.cpp: Investigate why the texelFetch in CompileZBiasProgram() is not using our structured art, with a few words on graphics programming" "1873": "handmade_opengl.cpp: Verify VoxP in CompileZBiasProgram() by colouring the voxels by their address" "1941": "Run the game to see our colour-coded representation of the voxel lookup" "1990": "handmade_opengl.cpp: Make CompileZBiasProgram() set the colour from the VoxP after flooring" "2021": "Run the game to see that this is still as expected" "2088": "handmade_opengl.cpp: Make CompileZBiasProgram() perform texelFetch() on our verified values" "2219": "Run the game and still see black" "2248": "Consult the OpenGL Shading Language Specification for texelFetch()" "2648": "handmade_opengl.cpp: Initialise LightI as a uint, and continue to wonder why we are not successfully fetching from the LookupSampler" "3048": "handmade_opengl.cpp: Try setting the UseLightC to individual colours from the LookupSampler, to see exactly what texelFetch() returns" "3279": "Run the game to see that the alpha channel unexpectedly is a high value before submitting the texture" "3363": "Reflect on our findings, that texelFetch() is returning 0, 0, 0, 1" "3654": "Maybe up your level of debug message notifications?" "3672": "handmade_opengl.cpp: Print out all of the debug messages" "3812": "3rd comment: https://stackoverflow.com/questions/26770216/why-is-texelfetch-always-returning-0-for-a-1d-single-channel-texture" "4025": "handmade_opengl.cpp: Make OpenGLChangeToSettings() set GL_TEXTURE_MIN_FILTER and GL_TEXTURE_MAG_FILTER to GL_NEAREST" "4307": "Run the game to see that this totally fixed it, and wonder why texelFetch() applied filtering" "4544": "Consult the OpenGL Specification for texelFetch()" "4742": "Read about Texture Completeness" "4985": "handmade_opengl.cpp: Enable CompileZBiasProgram() to use our structured art fetched from the LookupSampler" "5573": "handmade_opengl.cpp: Enable CompileZBiasProgram() to sample our real lighting values" "5641": "Run the game to see that we are getting the colours we'd expect" "5685": "handmade_opengl.cpp: Make the lighting grid more coarse" "5777": "Run the game and note that we are not covering all the space with light" "5838": "handmade_opengl.cpp: Introduce SumVoxelLight() to enable CompileZBiasProgram() to sample from neighbouring voxels" "6363": "Run the game to see that running fast" "6468": "handmade_opengl.cpp: Make CompileZBiasProgram() modulate the texture colours by the lighting values" "6509": "Run the game to see our lit scene" "6531": "handmade_opengl.cpp: Enable CompileZBiasProgram() to weight the lighting values by their proximity" "6744": "Run the game to see that we don't have dense enough lighting coverage" "6768": "handmade_opengl.cpp: Make the lighting grid more fine grained" "6789": "Run the game to see our more smoothly lit scene" "6901": "handmade_opengl.cpp: Change the coarseness of the lighting grid" "7009": "Q&A" "7034": "Why no indentation on the shader code?" "7109": "Have you tried CUDA? Do you think it's a reasonable way to do GPU programming? AMD is trying to get a CUDA compatible compiler so it could be usable on both vendors soon" "7228": "Could you try to use #include and the multi line strings together for the shader code?" "7280": "I've just started a project and am working through the setup on Day 002. You had set up a PatBlt on WM_PAINT to alternate black and white. If I made no mistakes then it doesn't work on windows 10, I'm instead getting all white and if I drag the window around, the new part of the window becomes black? Do you know if there are any caveats for windows 10 I should be worried about? Should I keep going or is it important to get this working exactly the same?" "7339": "Do you have any suggestions on how to start going about voxelising more complex 3D meshes rather than simpler geometric shapes? Break them up into simpler geometric version / LOD meshes first? Should each mesh be pre-voxelised, or do you need to recalculate relative to the world / view position (and possibly distance from camera)?" "7448": "Not necessarily doing it on the GPU, but to provide what the GPU needs to do this sort of lighting with more complex meshes" "7614": "Blackboard: 2D rasterization" "7696": "Blackboard: Conservative rasterization" "7937": "Blackboard: Faster voxelization, using Reyes rendering" "8244": "Recommend crawling references" "8549": "Close down the stream" --- name: "day409" title: "Smoother Blending of Lighting Samples" markers: "8": "Recap and set the stage for the day, proceeding with lighting" "60": "Run the game to see our current lighting solution" "288": "Milton feature request: Hide title bar" "339": "Blackboard: Light Interpolation" "710": "Blackboard: Weighted sampling of multiple lighting samples per voxel" "995": "Run the game to see the lighting discontinuities" "1025": "handmade_opengl.cpp: Make SumVoxelLight() in CompileZBiasProgram() map the lighting sampling to the radial dimensions of the voxels" "1113": "Run the game to see the circular blending" "1155": "handmade_opengl.cpp: Make SumVoxelLight() in CompileZBiasProgram() constrain the lighting sampling to each voxel" "1489": "Run the game to see the constrained and sparse circular lighting" "1582": "handmade_opengl.cpp: Reduce the size of the voxels" "1628": "Run the game to see the denser lighting" "1838": "handmade_opengl.cpp: Try to set the surface reflectance directly to the lighting colour" "1868": "Run the game to see that we are not storing the lighting premultiplied" "2011": "handmade_opengl.cpp: Increase the size of the voxels" "2063": "Run the game to visualise the lighting sampling, and consider how to improve the voxel lookup scheme" "2409": "handmade_opengl.cpp: Make CompileZBiasProgram() only sum eight voxels" "2517": "Blackboard: Interpolating lighting between fewer voxels" "2618": "handmade_opengl.cpp: Make CompileZBiasProgram() sample from the centre of voxels" "2722": "Run the game to see the incorrect sampling" "2774": "Blackboard: Sampling from the centre of voxels" "2840": "handmade_opengl.cpp: Correctly make CompileZBiasProgram() offset the lighting sampling to the voxel centres" "2873": "Run the game to see the incomplete sampling" "2903": "handmade_opengl.cpp: Enable SumVoxelLight() in CompileZBiasProgram() to normalise the lighting samples in each voxel, and then interpolate between the voxels" "3387": "Run the game to see the square, yet incorrect blending" "3463": "handmade_opengl.cpp: Correctly compute VoxF" "3567": "Run the game to see the stable, bilinearly filtered lighting" "3682": "handmade_opengl.cpp: Make SumVoxelLight() modulate the voxel's lighting by a contribution value" "3801": "Run the game to see the modulated lighting" "3831": "handmade_platform.h: Reduce the size of the voxels" "3860": "Run the game to see the light blending" "3885": "handmade_opengl.cpp: Play with the contribution computation" "3983": "Run the game and consider adding directional information to the voxels" "4196": "handmade_platform.h: Consider the possibility of shrinking the lighting data" "4338": "handmade_platform.h: Add D (direction) to the lighting_textures struct" "4472": "handmade_opengl.cpp: Introduce a DSampler" "4992": "Run the game to see that everything is black" "5011": "handmade_render_group.cpp: Determine to enable the lighting scheme to use the lighting directions" "5258": "handmade_render_group.cpp: Read LightingTest() and determine that it is incorrect" "5684": "handmade_render_group.cpp: Reorganise LightingTest()" "6176": "Run the game to see our lighting looking roughly the same" "6229": "handmade_render_group.cpp: Add IncidentLight and AverageDirectionToLight to the lighting_element" "6438": "Close the stream as normal" --- name: "day410" title: "Tracking Incident Light" markers: "9": "Recap and set the stage for the day computing the lighting in software" "128": "handmade_opengl.cpp: Comment out the LightingD contribution in CompileZBiasProgram()" "161": "Run the game to see the current, non-directional lighting solution" "276": "handmade_world_mode.h: Remove ambient occlusion from the lighting_element" "677": "Blackboard: Incident Light" "892": "Blackboard: Forward propagating emitters to reflectors" "1229": "handmade_render_group.cpp: Introduce RayCast(), ComputeLightPropagation() and GatherFinalLighting()" "1666": "Blackboard: Surface facing direction" "1755": "handmade_world_mode.h: Only store one direction in the lighting_element" "1843": "handmade_render_group.cpp: Continue to implement RayCast()" "1948": "handmade_render_group.cpp: Implement GatherFinalLighting()" "2447": "Blackboard: Emittance distance contribution" "2619": "handmade_render_group.cpp: Continue to implement GatherFinalLighting() without diminishing by distance" "3093": "handmade_render_group.cpp: Determine to implement ComputeLightPropagation()" "3184": "Blackboard: Projecting from emitters vs from reflectors" "3350": "handmade_render_group.cpp: Implement ComputeLightPropagation() casting from emitters to reflectors" "3642": "Consider prohibiting ourselves from hitting the same reflector twice" "3859": "handmade_render_group.cpp: Continue to implement ComputeLightPropagation() weighting the emission contribution" "4465": "handmade_render_group.cpp: Enable ExtractReflectorsFromQuads() and ExtractReflectorsFromVerts() to use our newly computed emittance" "4806": "Run the game to see the trippy disco lights" "4899": "handmade_world_mode.cpp: Prevent AddSnakeSegment() from emitting light" "4938": "Run the game to see our current lighting solution with just our hero's light source" "5014": "Q&A" "5030": "Before I forgot, please increase the font size in visual studio for debugging; the font size is pretty small. It's not the same size as 4coder uses. Thanks!" "5086": "Ah well... shareware visual studio" "5121": "Haven't you made an account for VS on a previous stream?" "5137": "Has 4coder open, runs notepad to write a TODO" "5179": "Yeah, no malicious intent with my statement. I just find it funny how it expires after 30 days without you giving them "customer data"" "5406": "Did you try ConEmu instead of stock Command Prompt? I love Quake Console effect it delivers" "5433": "The good times for paying software and are happy are totally over" "5463": "Couldn't follow for a long time. Have you done something with automated (unit) testing or are you planning to?" "5596": "How do you keep your motivation going on long running projects?" "5747": "Wrap it up" --- name: "day411" title: "Switching to Rectangular Lighting Elements" markers: "9": "Recap and set the stage for the day" "400": "Run the game to see our current lighting solution" "543": "handmade_world_mode.cpp: Let UpdateAndRenderWorld() call OutputLighting()" "567": "Run the game to see our lighting voxel grid visualisation" "627": "handmade_render_group.cpp: Make OutputLighting() draw the reflectors" "634": "Run the game to see our reflectors debug visualisation" "752": "handmade_render_group.cpp: Prevent OutputLighting() from drawing any debug visualisations" "774": "Run the game and consider that the final gather may be producing the bleed-through lighting" "1071": "Run the game, noting that we had decided not to have 2-sided geometry any more" "1113": "handmade_world_mode.cpp: Make OutputLighting() draw the reflectors" "1125": "Run the game to see the giant hole in the relectors, and consider how to deal with this" "1272": "Run the game, toggle between the debug and regular views, and determine to switch to rectangular lighting elements" "1488": "Blackboard: Intersection of a Ray with a Rectangle" "1772": "Blackboard: Storing the rectangular lighting elements' X and Y axes to operate on them in their parametric space" "1899": "Blackboard: Defining the axes in unit-length and using the inner product to determine if we are inside the rectangle" "2119": "Blackboard: Simplifying our rectangle bounds equation" "2428": "Remove ExtractReflectorsFromVerts(), and make LightingTest() call ExtractReflectorsFromQuads()" "2533": "Run the game and determine to extract lighting from exact quads" "2567": "handmade_world_mode.h: Change R to Width and Height, and add XAxis and YAxis to the lighting_element" "2780": "Blackboard: Coordinate system winding" "2810": "handmade_render_group.cpp: Make ExtractReflectorsFromQuads() set the rectangle dimensions and axes" "3050": "handmade_render_group.cpp: Enable RayCast() to use our newly encoded rectangle data" "3541": "handmade_render_group.cpp: Remove OutputLightingVerts() and enable OutputLightingQuads() to reconstruct the quads from our encoded data" "3671": "Run the game to see our diamond lighting reflectors" "3686": "handmade_render_group.cpp: Fix OutputLightingQuads() to produce a right-angle rectangle" "3723": "Run the game to see our rectangular lighting reflectors, and consider how to shrink them" "3945": "handmade_render_group.cpp: Make OutputLightingQuads() shrink the reflectors slightly" "4011": "Run the game to see the gaps between reflectors" "4042": "handmade_render_group.cpp: Start to make ExtractReflectorsFromQuads() dice up the reflectors" "4154": "handmade_world_mode.h: Remove OrigBitmap and OrigV from lighting_element" "4242": "Run the game to see that we're good to go" "4296": "handmade_render_group.cpp: Continue to make ExtractReflectorsFromQuads() subdivide the reflectors" "4561": "Run the game to see our smaller reflectors" "4575": "handmade_render_group.cpp: Allow smaller subdivisions of the reflectors" "4650": "Run the game to see our lighting solution, and consider that either the ray cast is incorrect or our indirect bounce may be too powerful" "4798": "Q&A" "4851": "Hi! No shave November? That stache's gun be epic" "4935": "Forward rendering or deferred rendering" "4985": "Would the subdivision of the rectangles be something that you would do in a tesselation shader if you were using OpenGL?" "5062": "Are you going to be implementing shadowmaps?" "5106": "1) Any more Handmade Ray episodes? 2) Remember when someone took your raytracer a few steps further on twitter: what do you do to move to this picture from the one you stopped at?" "5139": "Is your keyboard any good?" "5226": "So, as far as know, if I would want to implement a real time rendering system there should have been some differences? Or for now the light bounces can also be used in that situation?" "5270": "Is there a specific reason to recalculate 1.0/255 rather than store it as a value or does the compiler optimise that anyway?" "5296": "I'm a new CS student with limited free time. Do you recommend watching your series from the beginning, or would time be better spent working on a new project and using your videos to learn something as needed?" "5393": "I was wondering what sort of data strucures / algorithms you would recommend to learn to get a wider grasp on programming?" "5580": "In my previous question I was wrong: I wanted to ask if we want to have physically based rendering techniques" "5657": "Which physics engine, if any, will you implement" "5669": "Are you planning to have any procedural generation in your levels later?" "5688": "You once said that you wanted to use Vulkan on HMH. Is that still on the table or are you sticking with OpenGL?" "5699": "What are the things you've solved yourself?" "5781": "I watched that live, how could you?" "5796": "Haha yeah, I didn't have anything specific in mind, just where to go after having learned the basics of coding, like the stuff you mentioned. But also where to start to slowly start understanding the more "complex" algorithms. Like there's probably a hundred ways to sort something, trees etc, but to get the basic understanding, where should I start?" "5929": "That's the one I'm reading right now!" "5969": "Yeah fine fine haha, I just wanted to know if there was a "shortcut"" "6006": "You once mentioned a numerical book" "6105": "Meh. Just read Knuth. Easy read" "6161": "I was kidding" "6253": "Recommend disabling internet access" "6381": "There's more people in my flat depending on that connection, but I could program a tiny thingie to cut my own connection" "6567": "If you have enough space and budget, having a separate room / desk and machine for development that you never use for anything else works for me" "6638": "But how do you code without source control" "6673": "Not cmirror though?" "6724": "Yeah, I'm kidding. Just another bile round at them gits and cmakes" "6758": "Gonna share cmirror 2 at some point?" "6801": "Handmade Source Control episodes?" "6832": "So you never access MSDN, the OpenGL docs, or other documentation on your work machine?" "6897": "I would like to program without being connected to the internet, but how do you do it without stack overflow or other references? Does breaking that reliance just come from practice and experience?" "7085": "Shut things down" --- name: "day412" title: "Debugging Voxel Interpolation" markers: "7": "Recap and set the stage for the day" "121": "Run the game to see our current lighting situation" "342": "Consider the current problems in the lighting" "554": "Determine to validate RayCast()" "764": "Make RayCast() tint the light grey" "853": "Run the game to see less light in the scene" "881": "Investigate the possibility that we are wrapping" "1006": "Make GatherFinalLighting() set the IncidentLight to pure red" "1041": "Run the game and do not see a red scene" "1100": "Run the game and switch away from the "just emitters" debug visualisation" "1144": "Scrutinise the lighting code" "1366": "Make CompileZBiasProgram() multiply the DirFalloff in to the final result" "1640": "Run the game to see a little difference, but still no ambient lighting" "1707": "Read through GatherFinalLighting() and OutputLightingTextures()" "1817": "Step in to OutputLightingTextures() and inspect the IncidentLight, Colour and Directional values" "1935": "Note that we don't have a way to directly visualise lighting quads" "2105": "Make CompileZBiasProgram() renormalise the contribution colour if the alpha is greater than 0" "2164": "Run the game to see still nonsense results" "2200": "Hard set the lighting colour to green in CompileZBiasProgram()" "2219": "Run the game to see pure green, except on the blue surface" "2257": "Verify that all pure colours hard set by CompileZBiasProgram() produce the expected results" "2336": "Run to see pure white and note that the voxel interpolation isn't totally busted" "2367": "Hard set the LightC to white and the DirFalloff to 1.0f in CompileZBiasProgram()" "2466": "Run the game to see white light, but some incorrectly dark spots" "2594": "Try to make CompileZBiasProgram() set the colour to pure yellow where there is no light sample" "2665": "Run the game to see spots of yellow in unexpected places" "2691": "Temporarily prevent CompileZBiasProgram() from setting the colour to yellow, and instead set the SurfaceReflect directly to the light colour, rather than multiplying it in" "2745": "Run the game to see the incoming light colour" "2764": "Make CompileZBiasProgram() set the colour to pure yellow where there is no light sample" "2780": "Run the game to see yellow where we cannot compute lighting results" "2829": "Try to make CompileZBiasProgram() set the colour to red" "2838": "Run the game to see some red places" "2859": "Make CompileZBiasProgram() track the Contrib value all the way down the pipeline and introduce VoxLerp() to use this value" "3056": "Run the game to see that it already looks better" "3094": "Begin to enable VoxLerp() to handle the case when the lighting contribution is 0" "3181": "Consider how better to handle voxels that have no lighting contribution" "3218": "Revert the passing of Contrib() all down the pipe in CompileZBiasProgram()" "3257": "Take a quick break" "3303": "Run the game to see our current red-tinted lighting situation" "3344": "Make OutputLightingTextures() gather the colour of voxels whose lighting contribution is 0 from their neighbour" "3648": "Run the game to see no difference" "3687": "Make OutputLightingTextures() zero-initialise the Neighbour" "3696": "Run the game and consider that the artifacts may only be occurring on voxels at the edge of the scene" "3887": "Temporarily assert in OutputLightingTextures() that Neighbor != 0" "3910": "Run the game to determine that we are doing some filling" "4064": "Make CompileZBiasProgram() colour the voxels by their location" "4150": "Run the game to see this debug visualisation confirming that the voxel interpolation is fine" "4202": "Make CompileZBiasProgram() colour the voxels green / red to indicate the presence / absence of lighting samples" "4249": "Run the game to see this debug visualisation" "4334": "Toggle OutputLighting() on" "4347": "Run the game to see the lighting solution visualised in voxel form" "4446": "Change OutputLightingTextures() to perform the Neighbor filling in a for() loop expanded to the whole voxel" "4656": "Run the game to see that we are filling nearly everything" "4675": "Introduce ClampVox() to clamp the voxel lookups only to the neighbouring voxels that are in the scene" "4817": "Run the game to see that the red patches are gone" "4855": "Make CompileZBiasProgram() take the LIGHT_LOOKUP positions to enable easy tweaking of the clamp" "5017": "Run the game to see the same debug visualisation" "5030": "Remove the red / green debug visualisation from CompileZBiasProgram()" "5057": "Run the game to see spherical weirdness" "5090": "Consider how CompileZBiasProgram() should compute the Contrib value" "5376": "Make CompileZBiasProgram() multiply in the VoxInvCelDim to the Contrib value" "5550": "Run the game and still see the weird gradient falloff patterns" "5592": "Temporarily make CompileZBiasProgram() hard code the Contrib to 1" "5667": "Run the game to see no gradient falloff pattern" "5675": "Try to make CompileZBiasProgram() factor in the dimensions of all neighbouring voxels to the Contrib value" "5769": "Run the game to see that it's a little better" "5789": "Make CompileZBiasProgram() factor in to the Contrib value merely the lighting sample distance" "5832": "Run the game to see no gradient falloff" "5856": "Prevent CompileZBiasProgram() from stomping on the LightC" "5882": "Run the game to see fewer artifacts" "5904": "Make CompileZBiasProgram() hard set the DirFalloff to 1.0f" "5958": "Run the game to see pure red everywhere" "5998": "Make CompileZBiasProgram() set the LightC to the LightD" "6060": "Run the game to see this debug visualisation" "6300": "Read through the lighting code to consider which routines we could verify" "6524": "Make CompileZBiasProgram() set the LightC to WorldN" "6536": "Run the game to see that the world normals look reasonable" "6596": "Prevent CompileZBiasProgram() from stomping on the LightC" "6602": "Run the game and consider what may be causing the artifacts" "6780": "Prevent GatherFinalLighting() from stomping on the IncidentLight and AverageDirectionToLight" "6791": "Run the game to see the lighting solution" "6833": "Prevent RayCast() from tinting the light grey" "6857": "Run the game and note that we're getting closer to sane" "6888": "Make CompileZBiasProgram() attenuate the SurfaceReflect by the Light" "6915": "Run the game to see that it's getting a lot better" "7113": "Consider the next steps" "7188": "Re-enable RayCast() to tint the light grey" "7208": "Run the game to see the brighter scene" "7244": "Make GatherFinalLighting() divide the RayCount in to the IncidentLight" "7317": "Run the game to see the ambient grey light" "7395": "Q&A" "7427": "Q: Regarding win calc, the size of the window determines how many buttons are shown. You can either stretch the window vertically or you can press the up arrow button (in the UI) to make the shown buttons shift into the other set like 1/x and e^x" "7485": "Q: I think the error in the color are in the same position where the normals calculation looks funny" "7543": "Q: Not sure if you heard, but someone rewrote depends.exe for win 10" "7702": "Q: Seeing you used emacs without code completion, and now 4coder, how do you work without code completion? Don't you think it could help you with both productivity and discoverability? I'm a fan of YouCompleteMe for vim" "7826": "Q: When the lighting is in realtime will that tend to hide some of the more minor artifacts?" "7897": "Q: Like in this gif" "7985": "Q: It's showing a heads up display of the possible arguments" "8036": "Q: I know finding a bad API is not hard, but out of curiosity did you ever run into an API that was great to work with? One that you seemed to magically just click with?" "8268": "What about this gif?" "8440": "Close everything down" --- name: "day413" title: "Encoding Light Values" markers: "3": "Address Patreon's proposed fee change of December 2017" "151": "Plug the Annotated Episode Guide, Handmade Network - began by abnercoimbre, ChronalDragon and Kelimion - mr4thdimension's 4coder and serge_rgb's milton" "312": "Continue to address Patreon's fee change" "1067": "Mention the chair, a SPACE Seating Professional AirGrid Dark Back and Padded Black Eco Leather Seat…" "1274": "Segue out of the preamble" "1328": "Run the game to see our current lighting solution" "1576": "Make CompileZBiasProgram() clamp the DirFalloff" "1687": "Run the game to see dramatically different lighting results" "1754": "Prevent RayCast() from tinting the light grey" "1791": "Run the game and consider that the ray caster is wrong" "1871": "TODO(casey): Need a skylight method that works with our propagation" "1957": "Mention the office espresso machine" "2041": "Read through RayCast()" "2150": "Wax lyrical on milton and its creator serge_rgb" "2193": "Raycast Debugging" "2623": "Explain RayCast() complete with blackboard illustrations" "3249": "Consider what may be going wrong in RayCast()" "3382": "How GatherFinalLighting() may be incorrectly generating uniform samples without a hemisphere" "3560": "Run the game to see light sailing out of the back of geometry" "3600": "Introduce SampleHemisphere()" "3692": "Run the game to see the same lighting results" "3724": "Consider how to improve SampleHemisphere(), preventing the back-face problem" "3987": "Halve the range of normals that SampleHemisphere() will produce" "4007": "Run the game to see light still emanating from back faces" "4098": "Increase light intensity" "4150": "Run the game to see that we must be capping the maximum light brightness" "4267": "Consider how better to encode the lighting" "4422": "Introduce the notion of LightPower in OutputLightingTextures()" "4599": "Enable CompileZBiasProgram() to handle LightPower" "4694": "Run the game to see that we didn't do that correctly" "4730": "Make OutputLightingTextures() use the Element to compute the LightColor" "4766": "Run the game to see our much more powerful light and the back-face leakage" "4972": "Assert in SampleHemisphere() that we never sample from behind the hemisphere" "4998": "Run the game and do not hit that assertion" "5003": "Enable OutputTextureDebug() to correctly interpret the lighting alpha values" "5128": "Run the game to see that our lighting samples are heavily red" "5179": "Increase the voxel resolution" "5203": "Run the game to see different artifacts" "5260": "Temporarily try to make RayCast() collide against back faces" "5291": "Run the game to see different light leakage" "5422": "Toggle OutputLighting() over to OutputLightingQuads()" "5457": "Run the game to see the lit quads, noting that we have a double-counting problem" "5561": "Add LightingDisabled to game_render_settings and enable CompileZBiasProgram() to honour this setting" "5717": "Add a LightingDisabled switch to GameUpdateAndRender()" "5750": "Run the game and unsuccessfully toggle LightingDisabled" "5787": "Introduce MemoryIsEqual()" "5949": "Run the game and successfully toggle LightingDisabled" "6008": "Introduce DecodePower()" "6187": "Run the game and take a look at the lighting" "6225": "Reduce the light power and run the game to see hot lighting" "6310": "Consider enabling us to dynamically set the Lighting Iteration Count" "6394": "Run the game to confirm the presence of Iteration Count in the debug system ui" "6455": "Provide the ability to set the Lighting Iteration Count dynamically" "6503": "Run the game and try increasing the lighting iteration count" "6656": "Consider the future of lighting" "6720": "Q&A" "6760": "Q: Don't forget that you can now indent your shaders (if you updated 4coder)" "6801": "Q: Could the raycasting be bouncing off the bounds of the scene?" "6821": "SpeedCrunch for a great replacement of wincalc" "6885": "Q: Could Liberapay be a replacement for Patreon? It's nonprofit and payed for by donations to its own Liberapay account" "7060": "Q: Just hopped into the stream, are you working on a global illumination approach specific for 2.5D?" "7254": "Q: I'm out of the loop. What's up with Patreon?" "8470": "Q: I've been having a lot of trouble staying motivated / inspired for new projects. Do you have any tips on how to take an idea and actually bring it fully into existence?" "8722": "Q: Did you get depends to work (the new version)" "8735": "I'm fairly new to the series (only on Day 013) do you recommend coding along with the series? I personally like to just watch and learn rather than copying everything you type, but I don't know" "8797": "Q: Have you considered applying for twitch partner? (I would subscribe)" "8841": "Q: Consider getting a bitcoin, litecoin, and ethereum wallet, it's an easy way for people to donate. It's hard to get your money out of it, though, but I think it could be worth it" "8906": "Blog post about Patreon onboarding" "9223": "“What is a .1 engineer?”" "9264": "Continue to address the blog post" "9673": "Q: What do you think of git lfs, or any other git large asset plugins over centralized source control such as svn or perforce? I've been taking a look and for free (as in pay) solution I actually came to mercurial with its large asset plugin. What do you recommend?" "9902": "Wrap it up" --- name: "day414" title: "Improving Light Distribution" markers: "6": "Recap and set the stage for the day" "30": "Plug the SendOwl-powered contribution page" "464": "Run the game to see our current lighting solution" "685": "Read through ComputeLightPropagation()" "937": "Bouncing light between emitters and reflectors" "1083": "Try to make ComputeLightPropagation() reduce the ray count per iteration" "1134": "Run the game to see how that looks" "1374": "Try to decrease the voxel resolution" "1410": "Run the game to see much smoother lighting" "1463": "Make RayCast() tint the scene grey" "1494": "Run the game to see how that looks with the skylight" "1548": "Lighting Improvement" "1762": "Check out Ward's 'Irradiance Caching Algorithm'" "1896": "Irradiance cache" "2001": "Photon tracing" "2047": "Replace the notion of next emission weight from ComputeLightPropagation() with an ever-decreasing accumulation of colour per ray cast iteration" "2146": "Run the game to see that the light looks a little more correct" "2176": "Prevent RayCast() from producing ambient light" "2196": "Run the game to check out the lighting solution without the ambient light" "2226": "Remove NextEmitW from lighting_element" "2259": "Run the game to see the straight photon distribution" "2376": "Consider how to record the photon distribution" "2424": "Try to make ComputeLightPropagation() accumulate the emittance colour" "2537": "Run the game to see the scene getting brighter with each iteration" "2746": "Try toggling off the hero in AddPlayer()" "2779": "Run the game to see the lighting solution without the hero obscuring great swathes of it" "2830": "Try to prevent GatherFinalLighting() from accumulating light but just use the emitter colour and destination normal directly" "2926": "Run the game to see the lighting solution without the final gather" "3000": "Try to make ComputeLightPropagation() modify the AverageDirectionToLight by its power" "3182": "Run the game to see how that looks, and consider improving the voxel scheme, hemisphere sampling and sprite cards" "3397": "Enable ComputeLightPropagation() to apply skylight contribution specially" "3766": "Run the game with our skylight in place" "3909": "Make ExtractReflectorsFromQuads() clear the IncidentLight and AverageDirectionToLight" "3998": "Run the game to see the more correct lighting solution" "4051": "Check out CodeItNow's 'Better Sampling' article" "4351": "Make SampleHemisphere() merely flip the result if the randomly chosen sample is in the reverse hemisphere" "4474": "Run the game to see how that looks" "4535": "Consider adding a Sun-style light to ComputeLightPropagation()" "4618": "Install ColorCop" "4729": "Introduce the notion of a Sun-style light in ComputeLightPropagation()" "4995": "Run the game to see our sunlit scene" "5065": "Make ComputeLightPropagation() create a more powerful sun, and sample its direction" "5377": "Run the game to see how that looks" "5397": "Prevent ComputeLightPropagation() from bundling the sky color into the sun color" "5429": "Run the game to see this more directional sun" "5519": "Introduce AccumulateSample() for ComputeLightPropagation() to call" "5843": "Run the game to see no change" "5874": "Temporarily try to get rid of the sunlight" "5890": "Run the game without the sunlight" "5919": "Replace IncidentLight from lighting_element with the Hadamard product of EmitC" "6061": "Run the game to see how that looks" "6087": "Toggle off most of ComputeLightPropagation()" "6116": "Run the game to see no light" "6123": "Reenable UpdateAndRenderWorld() to call PushLight()" "6137": "Run the game to see the current lighting solution" "6171": "Glimpse into the future" "6200": "Q&A" "6223": "Q: Why is there a dark horizontal band on the Red / Blue voxels (approximately at the height of bottom of the push light box)? Note: Possibly fixed at the end of stream render" "6323": "Try to increase the voxel resolution" "6336": "Run the game to see that our lighting samples are now too isolated" "6418": "Q: Is there a good tutorial for using (modern) OpenGL in CAD-like applications, where you need to draw many sharp and precise lines and filled planes, mostly in 2D?" "6554": "Q: Has anyone tried to give you an actual 3D model of a cartoon spruce by now?" "6565": "Q: I remember you mentioning you didn't go to college... how did you learn C?" "6630": "Q: In how much time did you learn game development?" "6723": "Q: What's the most "oops, I may have deleted the database" thing you have seen?" "6781": "Q: Does C++17 bring anything you like? Do your metaprograms output templates at all?" "6897": "Q: What's your favourite game from your youth? M.U.L.E. on the Atari 8-bit for me" "6944": "Q: I'm looking for the best tools to begin learning coding / game design from scratch. Is visual studio, in your opinion, a good start?" "6993": "Q: Did you have any input on JAI?" "7104": "Q: Do you have any language in mind to replace C++?" "7287": "Q: What is your experience with macOS, especially their “cocoa API”?" "7291": "Q: I see you switched to 4coder from emacs. How do you like 4coder compared to emacs?" "7354": "Q: Do you agree with those who say "source code is text" or do you think we should push for more structure awareness in editors and tools?" "7364": "Q: What will come next after we're done with lighting?" "7385": "Q: Is there ever gonna be a handmade compiler?" "7409": "Close this down with another plug of the SendOwl-powered contribution page" --- name: "day415" title: "Per-primitive Lighting Samples" markers: "8": "Recap and set the stage for the day" "222": "Decrease the voxel resolution" "269": "Run the game to see our lighting solution" "338": "Increase the voxel resolution" "375": "Run the game to see our ruined lighting" "437": "Further increase the voxel resolution" "525": "Run the game to see that the lighting is way too sparse" "604": "Voxel Interpolation of Lighting" "809": "Using a spatial query to reconstruct the lighting sample locations" "1047": "Reflect on the efficacy of this approach" "1243": "Boundary problem" "1462": "Specifying our ideal lighting solution" "1623": "Consider using lighting samples directly" "1836": "Run the game to show how the reconstruction problem may go away" "1901": "Specifying lighting sample locations per primitive" "2142": "Begin to switch to specifying lighting sample locations per primitive" "2426": "Add LightOffset and LightCount to textured_vertex and enable CompileZBiasProgram() to use these values, passing them right through using GLSL's "flat" interpolation qualifier" "3022": "Introduce SumLight() based on SumVoxelLight()" "3275": "Run the game and note that we're still fine" "3290": "Describe structured art, as introduced to Casey by Mike Biddlecombe" "3423": "Set up the rendering pipeline to enable CompileZBiasProgram() to display Red, Green, Blue and White on the corners of each quad" "4008": "Run the game and note that we may have a bug" "4105": "Make CompileZBiasProgram() set the FragLightIndex and FragLightCount" "4132": "Run the game and get slower and slower" "4161": "Investigate this slowdown" "4396": "Prevent CompileZBiasProgram() from setting any of the light" "4416": "Run the game to determine that this loop was the problem" "4433": "Prevent CompileZBiasProgram() from fetching the next light index" "4463": "Run the game to see that we're still wrong" "4487": "Try to hardcode LightCount to 4 in CompileZBiasProgram()" "4498": "Run the game to determine that LightCount is not properly getting set to 4 always" "4539": "Read through the code looking for the potential culprit" "4668": "Determine to do some graphics debugging" "4745": "Make CompileZBiasProgram() clamp the LightCount to 4" "4772": "Capture a frame and find that we are still binding only one GL_UNSIGNED_SHORT array" "4812": "Fix CompileZBiasProgram() to correctly set the FragLightCount" "4856": "Run the game and still see no data" "4872": "Trim down OutputLightingTextures() in preparation to excise voxels, augment lighting_element to contain PackIndex, and enable ExtractReflectorsFromQuads() to use that PackIndex" "5296": "Run the game to see that this indeed doesn't work" "5343": "Temporarily make SumLight() in CompileZBiasProgram() output red" "5412": "Run the game to see red" "5479": "Note that shader debugging isn't supported on newer Nvidia GPUs, as explained by JamesWidman" "5546": "Capture a frame to inspect our lighting arrays, and note that ExtractLightingQuads() cannot do the remap" "5963": "Make ExtractLightingQuads() set the PackIndex from Vert0" "6050": "Run the game" "6063": "Capture a frame and inspect the buffers from which the fragment shader is sampling" "6284": "Change FragLightIndex and FragLightCount from unsigned short to unsigned int" "6327": "Run and freeze" "6419": "Make SumLight() clamp LightCount to 4" "6526": "Q&A" "6565": "Q: What texture file type will you use?" "6618": "Q: Can you increase the font size in the calculator?" "6747": "Q: In what structure do you organize world objects?" "6798": "Q: I think you missed an equals sign in one of the shaders when defining Inv {1, 1, 1}" "6815": "Make OutputLightingTextures() correctly set InvCelDim" "6833": "Q: Any comments on using SQLite as a file format for a game?" "6876": "Q: Man, isn't it weird how OpenGL is with how you have to interface with it to do things, like you send it a string and then you put two shaders together to make a program. It's like esoteric and stuff" "6981": "Q: What percentage of the way through the game do you think you are?" "6995": "Q: Curious question: Why f32 has a lower case F while F32Max has a upper case F?" "7006": "Q: In what video index did you start with the discussion about using a 3-dimensional voxel for lighting?" "7037": "Q: Could we just normalize the light count / index to 1 and use them to build a color? Maybe this allows us to see what value we see" "7059": "Make CompileZBiasProgram() normalize the FragLightCount and FragLightIndex to 1" "7197": "Run the game and see all yellow" "7219": "Change FragLightCount and FragLightIndex back to shorts" "7243": "Run the game and still see bogus lighting results" "7331": "Q: Have you considered Cascaded Voxels (as in Cascaded Voxel Cone Tracing) as a data structure for Handmade Hero lighting samples?" "7352": "Q: Have you ever seen the source code of a GPU driver?" "7393": "Q: You have not run the light calculation" "7461": "Q: What kind of work did you do on the Intel driver?" "7528": "Q: What kinds of things do you most enjoy coding and what things the least?" "7624": "Q: If you were coding for a console would you be able to debug the graphics part of it? Do they give GPU hardware info down to implementation details?" "7692": "Q: Do you normally comment more than you do for this stream? Your code is clean to look at, but it feels like at big companies they would eat you up for not documenting a lot more" "7923": "Q: I work for a large company, but in a very research-y area. Honestly I feel like I have the best of both worlds" "7978": "Q: I worked at Frostbite and I think you would fit right in" "8262": "Q: Having worked in a few large companies, I've found the need for commenting code arises from disproportionate skill levels among the developers. Less skilled or less interested engineers tend to complain about uncommented code..." "8459": "Wind it down" --- name: "day416" title: "Separating Lighting and Geometry Submission" markers: "15": "Recap and set the stage for the day" "63": "Run the game to see a debug visualisation of our current lighting solution" "113": "Make UseProgramBegin() use glVertexAttribIPointer() rather than glVertexAttribPointer() for LightIndex and LightCount" "322": "Run the game to see our correctly coloured scene, and thank seventh_chord for the suggestion" "412": "Try to make VertLightIndex, VertLightCount, FragLightIndex and FragLightCount regular signed ints" "472": "Run the game to see the exact same results" "491": "Let SumLight() loop over the whole LightCount and call SumLight()" "536": "Run the game to see that we're in striking distance" "641": "Cursorily investigate why the light seems to be so blown out" "732": "Run the game and consider what we need to do" "973": "Light / Geometry Specification: 1) Occluders separate from sprites" "1243": "Light / Geometry Specification: 2) Sampling Control" "1461": "Our tasks: 1) "No Lighting" Lighting; 2) Occluder Buffer; 3) Samples for Occluders" "1512": "Make CompileZBiasProgram() keep FragLightIndex unlit" "1608": "Run the game to see our one unlit primitive" "1631": "Add LightingEnabled and LightIndex to render_group, and enable PushQuad() to use these values" "1793": "Run the game to see nothing lit" "1835": "Try to increase the main resolution to 1920x1080" "1842": "Run the game to see that it runs fine" "1873": "Introduce EnableLighting() for UpdateAndRenderWorld() to call" "2020": "Run the game to see our debug system correctly unlit" "2050": "Make UpdateAndRenderWorld() only call EnableLighting() if we are not ShowLighting" "2067": "Run the game to see that everything is lit as expected" "2157": "Demonstrate the necessity of an occluder buffer caused by the tree sprites" "2342": "Try to run the lighting in real time" "2392": "Run the game to see that it is surprisingly fast, but exhibiting flickering artifacts" "2640": "Explain the necessity of having separate occluders and world geometry" "2759": "Separate lighting_element out into lighting_surface, lighting_point and lighting_intermediate" "3152": "Gradually get all necessary functions to use these new structures" "4243": "Duplicate the emanating surface normal in the lighting_point" "4560": "Choosing where in the surface to record the light" "4632": "Make ComputeLightPropagation() accumulate the light of all lighting points" "4803": "Continue to propagate the new lighting structures to all necessary functions, including removing GatherFinalLighting()" "5232": "Run the game to see no lighting, and step through it to debug why" "5326": "Make ExtractReflectorsFromQuads() correctly set the PointCount" "5343": "Run the game to see our working and sped-up, although still flickering, lighting solution" "5493": "Consider merging lighting_point into lighting_intermediate" "5624": "Merge lighting_intermediate into lighting_solution and propagate that change to the necessary functions" "6368": "Step through ExtractReflectorsFromQuads() and inspect the values" "6498": "Remove EmitC from lighting_point and make ComputeLightPropagation() set the correct EmitC" "6562": "Run the game as we were before" "6597": "Introduce the notion of SamplePower in ComputeLightPropagation()" "6659": "Run the game to see that this doesn't quite provide what we want" "6748": "Make ComputeLightPropagation() call AccumulateSample() only once, outside the surface point loop if it gets a ClosestPointIndex" "6979": "Run the game to see the light still not really doing what we want" "7006": "Read through CompileZBiasProgram() and ExtractReflectorsFromQuads() for any blunders" "7072": "Run the game and wonder why we are still getting uniform lighting" "7111": "Read through the code, wondering why we rarely get gradients" "7241": "Run the game and take another look at the lighting" "7277": "Q&A" "7317": "Q: Hi Casey! Wanted to pick your brain about metaprogramming a bit. 0 - Short of a manual comparison, how do you obtain an enum field's name by supplying a corresponding numeric value? E.g. 1 -> Sunday? Or metaprogramming is overkill for this? 1 - If you have a gigantic struct printf which you want to "automate", in the way of not having to manually enlist all its fields, metaprogramming is the way to go here, right? Probably take the definition of the struct from the (Vulkan) spec, store it in a file, for example, and match it with the struct going by the sizes and offsets of the fields?" "7390": "Q: Would doing the ray tracing on the GPU with OpenCL or CUDA be viable?" "7408": "Q: Do you have any issues with the (ms) CRT on windows? Do you think memory management could be improved?" "7476": "Q: Concerning the flickering, when does mixing between frames give appropriate results, when not?" "7520": "Q: So, mentioning this is probably a bit premature because I haven't looked into it very thoroughly, but there's a CPU implementation of OpenGL and DirectX called "swiftshader". Could be useful for debugging purposes" "7612": "Close things down" --- name: "day417" title: "Adding a Debug View for Lighting Points" markers: "13": "Recap and set the stage for the day" "146": "Run the game to see our current lighting solution" "394": "Read through ExtractReflectorsFromQuads()" "512": "Run the game to illustrate the need for some debug visualisation" "601": "Note that SampleHemisphere() is not uniform as mentioned on the forums" "682": "Remove OutputLightingQuads() and clean up lighting structs and dependent functions" "1161": "Wish for the ability to fetch from a buffer in a fragment shader" "1454": "Pack lighting_textures differently, remove DecodePower() and trim down OutputLightingTextures()" "1942": "Propagate the new lighting_textures to the OpenGL side of things" "2232": "Z-Value Reconstruction" "2348": "Enable CompileZBiasProgram() to reconstruct the Z-value" "2585": "Run the game to see colour washes" "2645": "Determine to draw lighting sample points" "2779": "Run the game, try adjusting the lighting iteration count and note our apparent power leakage problem" "3006": "Replace OutputLightingQuads() with OutputLightingPoints()" "3179": "Run the game and try toggling between the regular view and debug visualisation" "3210": "Enable OutputLightingPoints() to output the lighting sample points" "3655": "Run the game to see our lighting sample points" "3690": "Try to enable UpdateAndRenderWorld() to perform the simulation even in the debug visualisation" "3957": "Run the game to see that this doesn't quite work" "3970": "Revert our simulation update attempt" "4049": "Run the game to see our lighting sample points" "4183": "Read through ComputeLightPropagation()" "4367": "Make RayCast() account for the Source Position in the Position computation" "4435": "Run the game to see that it looks much more correct" "4547": "Temporarily increase the RayCount in ComputeLightPropagation()" "4561": "Run the game to see the lighting solution with more rays" "4625": "Determine to make the light sampling more unbiased" "4738": "Run the game and determine to enable lighting recomputation while showing the debug visualisation" "4774": "Enable UpdateAndRenderWorld() to recompute the lighting while showing the debug visualisation" "4818": "Run the game and try out our new ability" "4841": "Increase sample point size in OutputLightingPoints()" "4861": "Run the game to see our bigger sample points" "4926": "Toggle off the snake in PlayWorld()" "4949": "Run the game to see our current lighting solution" "4986": "Consider how to get the lighting bounce to work better" "5113": ""Energy Conservation"" "5313": "Introduce the notion of LightRetention in ComputeLightPropagation() to only retain 50% of the light" "5491": "Run the game to see that the light gets dimmer and dimmer" "5534": "Enable ComputeLightPropagation() to retain light if rays do not hit" "5697": "Run the game to see that the light still gets dimmer" "5770": "Read through ComputeLightPropagation()" "5837": "“It could just be floating point nonsense but it's probably something real”" "5849": "Change AccumulateSample() to return the Power for ComputeLightPropagation() to use" "5909": "Run the game to see that it's better but still not right" "5931": "Read closely through ComputeLightPropagation() to try and see where we lose power" "6028": "Make ComputeLightPropagation() compute the DestEmitC from the SourceEmitC" "6049": "Run the game to see that we are so close" "6091": "Thoroughly consider how to correctly retain light" "6294": "Describe the problem" "6333": "Introduce the notion of a retention coefficient in ComputeLightPropagation()" "6401": "Run the game to see that it still gets down to zero eventually" "6420": "Make AccumulateSample() return the full colour for ComputeLightPropagation() to use as the retainer" "6541": "Run the game to see that we're still losing power" "6577": "Read through ComputeLightPropagation() one last time" "6632": "Run the game and look at our lighting samples" "6759": "Q&A" "6821": "cmuratori Am I right in thinking that you're taking into account the geometric (cos theta) factor on the receiving surface, but not on the emitting surface?" "6835": "Q: In a trade like blacksmithing, you use your tools to make better tools over time. Do you think programming should be like this, where you build tools that you reuse every project? Or should you rebuild most of your code every project?" "7008": "Q: That may explain why it wasn't energy preserving" "7039": "Q: Could you explain the purpose of multiple pointer levels like void *****whatever? Is it just an array of array of array of array... I can't think of a viable example, can you give one?" "7081": "Q: Is the direction of the light correctly recalculated if you only take positive z into account, negative z is also a correct normal, right?" "7128": "Make OutputLightTextures() and CompileZBiasProgram() correctly recalculate the light for both positive and negative Z values" "7260": "Run the game to see the lighting solution" "7289": "Q: In the case of the red wall only being lit by the 3rd or 4th bounce, shouldn't the red wall not reflect any red light because the blue wall is mostly only reflecting blue light?" "7346": "Q: Yeah, but think back. The original problem was that the solution was blowing up, wasn't it?" "7406": "Q: void ** is clear, everything above is bogus" "7420": "Pointers to Pointers" "7559": "Q: Just as a suggestion, the ultimate solution might be to use temporal coherence. Do one bounce per frame, and use the previous frame's solution for the indirect lighting term" "7621": "Q: Two weeks ago I asked about sound input. I just want to specify that I was thinking about the data structure to store the sound input. So like you have it setup with the platform layer handling the sound input and passing it to the game" "7671": "Shut it down" --- name: "day418" title: "Smoothing Light Samples Over Time" markers: "1": "Recap and set the stage for the day" "86": "Run the game to see the flickering lighting" "162": "Flicker / Sampling: "Monte Carlo" → "Random" → "Stochastic"" "409": "How Monte Carlo - as opposed to uniform - sampling can effectively estimate shapes" "830": ""Importance" sampling" "923": ""Importance" sampling in the context of lighting" "1063": "The cosθ property of surfaces" "1353": "Our current "Pure Monte Carlo" sampling scheme, and how SampleHemisphere() is biased" "1578": "Our problem: Low Sampling Rate vs Discontinuities in the Function" "2015": "Run the game to see the flickering" "2043": "Make ComputeLightPropagation() use a different random series every frame" "2113": "Run the game to see this even more pronounced flickering" "2223": "Provide the ability to toggle the lighting computation" "2363": "Run the game and recompute the lighting at will" "2407": "Dramatically increase the RayCount in ComputeLightPropagation()" "2420": "Run the game to see less flicker" "2446": "Reduce the RayCount in ComputeLightPropagation()" "2455": "Run the game to see more flicker" "2534": "Consider how to perform temporal smoothing on the lighting" "2751": ""Spatial Correspondence"" "2858": "Remembering light indices" "3092": "Add a LightingIndex to entity_visible_piece" "3365": "Consider examples of poor spatial correspondence" "3461": "Upgrade PushQuad() to set a LightingIndex" "3564": "Run the game and see no lighting" "3591": "Make PushCube() set LightCount and LightIndex" "3727": "Run the game to see lighting restored on the cubes but not the sprites" "3763": "Enable PushCube() to read from the LightIndexStore" "4180": "Run the game to see that it doesn't work" "4212": "Add DebugLightIndex to game_mode_world for PushLight() to use" "4314": "Run the game to see our lighting" "4393": "Enable ExtractReflectorsFromQuads() to use the LightIndex" "4522": "Run the game to see that the light isn't stable" "4631": "Step in to ExtractReflectorsFromQuads() and inspect the Solution" "4817": "Add LastEmit and LastDirection to the lighting_solution so ExtractReflectorsFromQuads() can mix in those values at the end of the routine" "5137": "Run the game to see that we have four frames of lag on the lighting" "5149": "Enable ComputeLightPropagation() to use our tracked LastEmit and LastDirection" "5250": "Run the game to see that the walls didn't get any lighting" "5325": "Run the game to see less flicker" "5356": "Make ComputeLightPropagation() interpolate the lighting across 10 frames" "5360": "Run the game to see the lighting" "5376": "Make ComputeLightPropagation() interpolate the lighting across 20 frames" "5378": "Run the game to see the lighting" "5386": "Make ComputeLightPropagation() interpolate the lighting across 100 frames" "5389": "Run the game to see the lighting" "5426": "Make ComputeLightPropagation() interpolate the lighting across 10 frames, and cast more rays" "5442": "Run the game and tweak our latency and RayCount" "5520": "Step in to ComputeLightPropagation() and inspect the Solution" "5648": "Make ComputeLightPropagation() normalize or zero the AverageDirectionToLight interpolation" "5681": "Run the game to see that that fixed it" "5706": "Reinsert the snake" "5735": "Run the game to see the lighting with the snake, and the more noticeable lag" "5792": "Q&A" "5820": "Note in ComputeLightPropagation() to finish implementing and debugging lighting" "5916": "Q: Yesterday someone asked if it will be beneficial to have more test scenes for lighting tests. And this was never answered" "5928": "Q: Don't you use the todo.txt in the code directory to make notes?" "5949": "Q: Found this video, seems related to what we are talking about (render denoising). What is your take on the use of machine learning to approach problems like these?" "5978": "Wrap up early" --- name: "day419" title: "Debugging Missing Lighting" markers: "1": "Recap and set the stage for the day, with a few words about lighting" "186": "Run the game with the intention of showing the lighting" "301": "Read through the lighting code" "525": "Run the game to show that bitmaps aren't lit" "568": "Continue to read through the lighting code" "937": "Run the game, note that we're not getting any emission and step through the code to determine why" "1208": "Press F4 and see the light" "1352": "Make PlayWorld() set UpdatingLighting to true on startup" "1420": "Run the game and note the long lighting trails" "1443": "Make ComputeLightPropagation() interpolate the lighting across 10 frames" "1464": "Run the game to see more flickery light, yet with a shorter trail" "1498": "Consider what could be happening with the snake's light at corners" "1719": "Remove all PushLight() calls except for those performed by AddSnakeSegment() for the snake's head" "1783": "Run the game to see that the bug persists with our single light source" "1800": "Admire the UI of Microsoft Visual Studio" "1840": "Step through PushCube() to inspect the lighting values" "1996": "Step through ExtractReflectorsFromQuads() to follow the light data down the pipe" "2333": "Step through OutputLightingTextures() to see if we correctly output all the lights" "2479": "Enable CompileZBiasProgram() to colour the light by its assigned index" "2619": "Run the game to see that the light indices and positions are coherent" "2707": "Make CompileZBiasProgram() colour the light <= 1033 green and > 1033 red" "2748": "Run the game to see a suspicious pattern" "2827": "Read through ComputeLightPropagation() looking for any biasing" "3014": "Mention the problem inherent in graphics programming to do with misalignment of disparate arrays" "3114": "Provide a specific break point in ComputeLightPropagation()" "3269": "Run the game, successfully break on our point and step through the code from there" "3461": "Realise that ComputeLightPropagation() is incorrectly setting DestEmit[EmitIndex]" "3509": "Make ComputeLightPropagation() correctly set the DestEmit[EmitIndex]" "3554": "Run the game to see that the lighting transmission now works" "3571": "Revert everything to semi-normal" "3596": "Run the game to see the light looking pretty clean" "3855": "Make PlayWorld() create two rooms" "3916": "Run the game to see the slowdown caused by lighting recalculation" "4006": "Make PlayWorld() create four rooms" "4024": "Run the game to see that slowdown" "4055": "Make PlayWorld() create bigger rooms" "4071": "Run the game to see the slowly recalculating lighting" "4284": "Make PlayWorld() generate rooms in all directions" "4342": "Run the game and crash" "4368": "Double the LIGHT_DATA_WIDTH" "4384": "Run the game and consider the frame rate at different zoom levels, at least initially" "4635": "Run it again and see that PeekMessage starts taking more time later" "4748": "Read through Win32ProcessPendingMessages()" "4793": "Run the game, check our memory usage and provide a ton of input to the game to get PeekMessage up to the top of the profiler" "5009": "Step into Win32ProcessPendingMessages() to see how often it gets hit, and realise that Alt-Tabbing away removes PeekMessage from the top spot in the profiler" "5175": "Read through Win32ProcessPendingMessages()" "5210": "Run the game and spam PeekMessage with mouse movement" "5396": "Put our "PeekMessage" TIMED_BLOCK in Win32ProcessPendingMessages() inside the message loop" "5421": "Run the game and again spam PeekMessage with mouse movement" "5515": "Return our "PeekMessage" TIMED_BLOCK to where it was and allow Win32ProcessPendingMessages() to handle all messages" "5633": "Run the game, try to spam PeekMessage again and find it not rising to the top of the profiler" "5699": "Determine to try and narrow down the problem in Win32ProcessPendingMessages()" "5736": "Run the game and successfully produce that bad case" "5837": "Prevent Win32ProcessPendingMessages() from skipping WM_PAINT messages" "5851": "Run the game and again trigger the bad case" "5869": "Prevent Win32ProcessPendingMessages() from skipping WM_MOUSEMOVE messages" "5888": "Run the game and fail to produce the bad case, determining that WM_MOUSEMOVE cannot be skipped" "5938": "Note our PeekMessage observations" "6004": "A few words on the utility of our always-on profiler from the debug system" "6073": "Wonder why this is happening" "6124": "Run the game and try to trigger lots of WM_PAINT messages" "6269": "Prevent Win32ProcessPendingMessages() from skipping WM_PAINT messages" "6294": "Run the game and experience no bad behaviour" "6316": "Try to prevent Win32ProcessPendingMessages() from skipping 0x738 messages" "6344": "Run the game to see that PeekMessage no longer takes the top spot in the profiler" "6368": "Re-enable Win32ProcessPendingMessages() to skip 0x738 messages" "6432": "Q&A" "6436": "Casey, did you notice that the annotation search doesn't seem to be working anymore?" "6571": "Why do you call PeekMessage once for each element in the skip list instead of retrieving the message once (if any) and comparing it against the messages you want to skip?" "6627": "Q: You got that messages while debugging with the NVidia GPU devy thingy" "6634": "Note the situation in which the 0x738 message is problematic" "6658": "Prevent Win32ProcessPendingMessages() from skipping 0x738 messages" "6696": "Run the game and find that our fonts are gone" "6744": "Try to give us a break point in Win32ProcessPendingMessages()" "6820": "Add an assertion in Win32ProcessPendingMessages()" "6842": "Run and hit that assertion" "6859": "Re-enable Win32ProcessPendingMessages() to skip 0x738" "6869": "Run the game to see that we freeze" "6883": "Fix our PeekMessage note" "6934": "Q: I heard you have talked about it already, but do you have any comments you would like to make about Meltdown and Spectre on record? I missed the pre-stream" "7099": "Q: What in your opinion is the biggest lie / myth most programmers follow / believe in?" "7264": "Hey Casey do you know SFML? If so, what is your opinion about it?" "7276": "Q: What do you mean when you mentioned "browser security" is a concern these days? Should the OS be secure instead of the browser or something like that?" "7611": "Q: Alright. Do you think code reviews and / or writing tests helps with that?" "8065": "Q: I watched the first 50 or so episodes of Handmade Hero. Quick question about the current state of things: is the GPU / OpenGL / shaders part of the project now?" "8080": "Q: When do you plan on showing / adding in the new art" "8089": "Q: Opinion of the .net framework platform?" "8092": "Q: One argument I get from people that use "advanced C++ features" is that the resulting code is more secure and more robust. Do you agree with that? Why?" "8176": "Close this down" --- name: "day420" title: "Pushing Lighting Information Directly" markers: "5": "Recap and set the stage for the day streaming on YouTube for the first time" "103": "Run the game to see our current, slow lighting solution" "147": "Make PlayWorld() generate only one room" "163": "Run the game to see the lighting at a more playable rate" "186": "A few initial words on algorithmic optimisation" "292": "ComputeLightPropagation() TODO(casey): Before moving on, be sure to index allocation management in the renderer" "423": "Lighting Work" "639": "Reducing emitters × surface O(n²)" "970": "Spatial partitioning" "1149": "Multiresolution approach" "1264": "Multigrid approach" "1309": "Comparing and combining these approaches" "1553": "Cubes - or, rather, axis-aligned bounding boxes (AABB) - as lighting elements" "1686": "The steps to produce this AABB-based lighting solution" "1985": "The difficulty in handling the transfer of light between tightly bound ground cubes" "2291": "Check the time" "2307": "38 minutes into the main stream. 82 until Q&A. (based on NOTE)" "2314": "Consider our proposed approach" "2499": "Run the game to inspect the lighting" "2528": "Determine to modify our lighting to use AABBs" "2604": "Introduce (a commented out) lighting_box, and add SurfaceCount and Surfaces to game_render_commands" "2981": "Add LightPointCount and Lights to game_render_commands" "3151": "Determine to pare down ExtractReflectorsFromQuads() and consider how to enable lighting points and surfaces to correspond" "3375": "Run the game to illustrate the notion of sharing lighting information across boundaries" "3460": "Enable PushCube() to push onto a lighting_surface array" "3680": "Positioning the surface at the most negative corner of an axis-aligned cube" "3723": "Continue to enable PushCube() to push onto a lighting_surface array" "3797": "Generating the surface normals" "3821": "Make PushCube() push all six surfaces" "3943": "Understanding XAxis and YAxis in a right-handed coordinate system" "3962": "Make PushCube() set the XAxis and YAxis" "4144": "Make PushCube() set the LightIndex and LightCount" "4219": "Understanding Width and Height" "4256": "Make PushCube() set the Width and Height" "4397": "Make PushCube() generate the lighting points on the surfaces" "4539": "Discover a potential bug with PushCube() erroneously resetting the AverageDirectionToLight" "4614": "Temporarily comment out our recent changes to try" "4661": "Run the game to see the old lighting" "4672": "Try to prevent PushCube() from clearing the AverageDirectionToLight" "4750": "Continue with our new PushCube() solution, adding EmitC0 to the lighting_point" "5220": "Allocate these lighting points per surface" "5668": "Run the game to see our lighting solution" "5713": "Toggle off most of ExtractReflectorsFromQuads() to start to use the lighting surfaces and points instead" "5943": "Run the game to see that we are slower, but working" "5996": "Replace ExtractReflectorsFromQuads() with inline operations in LightingTest()" "6180": "Replace static arrays in lighting_solution with pointers" "6215": "Run the game to see that it works" "6245": "Add a TIMED_FUNCTION in OutputLightingTextures(), OutputLightingPoints(), LightingTest() and ComputeLightPropagation()" "6281": "Run the game and inspect the profiler" "6330": "Add a DEBUG_VALUE to LightingTest()" "6382": "Run the game and inspect the SurfaceCount and PointCount in the profiler" "6485": "Note that we could propagate light across frames" "6534": "Glimpse into the future of passing AABBs down directly" "6563": "Q&A" "6611": "Q: How come Bink2 isn't used, prevalently at that, in video playback across all of the video-playbacking use cases? Why is it the incumbent sovereign only in video games?" "6766": "Q: Was there a bug with light leaking behind the walls that was newly added?" "6776": "Run the game to look for light leaking" "6870": "Q: Maybe not, I thought I saw the light leak through the bottom wall" "6924": "Q: I'm getting pretty frequent audio popping. Other people noticed it as well. I recorded a sample" "6963": "Q: When you write code in an exploratory fashion, and you end up with something that works well but is too large and complex to fit in your head at once, how do you simplify it back into something manageable?" "7041": "Q: Will you continue (dual) streaming to YouTube?" "7085": "Q: Are you concerned with compile times at all so far? I saw CTIME reporting 2.7 seconds. Time to pop in a threadripper?" "7162": "End the stream for today" --- name: "day421" title: "Passing Lighting as Boxes" markers: "0": "Welcome to the stream, power outage edition" "124": "Recap and set the stage for the day" "223": "Fix the P, N and XAxis for the fifth and sixth surfaces in PushCube()" "461": "Run the game to see our hopefully corrected lighting" "507": "Flip back to the old settings in PushCube()" "522": "Run the game to see that bug exhibiting" "535": "Redo the correction in PushCube()" "557": "Run the game and check out the newly corrected lighting" "575": "Close that bug" "629": "Determine to compress PushCube()" "829": "Compress what we can of PushCube()" "2198": "Specify the lighting_box struct and begin to fix up compile errors in PushCube()" "2410": "Light Box Face Interpolation" "2542": "Make PushCube() procedurally interpolate the lighting surfaces for each axis" "2755": "Min and max corners of a cube vs its faces" "2800": "Continue to make PushCube() interpolate the lighting surfaces" "3619": "Switch DefaultRenderCommands() from lighting_surface to lighting_box" "3736": "Introduce GetBoxSurface() to perform some of the work of PushCube() for LightingTest() to call" "4152": "Compress LightingTest() using GetBoxSurface()" "4692": "Change OutputLightingPoints() to display the actually used axes" "4938": "Run the game and crash in LightingTest()" "4999": "Step in to LightingTest() and inspect the Surface" "5051": "Fix LightingTest() to correctly iterate over the box surfaces" "5091": "Run the game to see that we are completely wrong" "5132": "Step in to LightingTest() and inspect the data" "5186": "Make GetBoxSurface() correctly set the YAxis" "5217": "Run the game to see our lighting surfaces" "5292": "Check the time" "5301": "87 minutes into the main stream. 33 until Q&A. (based on NOTE)" "5328": "Run it in release mode" "5357": "Step through PushCube() and inspect the LightBox data" "5514": "Make GetBoxSurface() set the Span after setting the Max and Min corners" "5564": "Step through GetBoxSurface() and LightingTest() and inspect their data" "5857": "Run the game and consider whether the debug and main views do not correspond" "5992": "Step through LightingTest() to see that a Surface.Width is negative" "6168": "Note that Min in light_box_surface is not necessarily the minimum relative to the axes, and respecify light_box_surface" "6521": "Run the game to view the debug visualisation" "6658": "Step in to PushCube() to verify if the surfaces were pushed on in the expected order" "6799": "Reorder the PushQuad() calls in PushCube()" "6973": "Run the game to see that we're closer" "7051": "Flip the Y PushQuad() calls in PushCube" "7066": "Run the game to see that we're better" "7138": "Q&A" "7203": "Q: Is there any way to put a break point outside Visual Studio?" "7282": "Pull up the profiler and note the cycle usage of ComputeLightPropagation" "7352": "Q: What do you think about the blockchain future? I have no idea if questions outside of the game are allowed" "7590": "Q: Shouldn't we go back to do more stuff in assembler like on the Amiga" "7599": "Q: How do you jump to a function during debugging? Usually there's a lot of functions and not easy to find them" "7657": "Q: Jon tweeted once again about how X-Forward, Right Handed coordinate systems should be standard. Do you know details on why is that important?" "8185": "Q: What kind of memory allocations do you use? Are there any custom stack allocations, pools etc. or are you using standard malloc / new? If custom, how do you define memory chunk size?" "8225": "Q: Did you manually build all of the menus currently on the screen, or get it from somewhere?" "8252": "Q: Is ComputeLightPropagation 92% seems too high at the moment?" "8266": "Q: Hi Casey, would you be able to recommend good resources to learn / practise efficient programming habits (e.g. efficient algorithms, code, etc.)?" "8303": "Q: Can metaprogramming do everything and solve all the world's problems?" "8313": "Close this up" --- name: "day422" title: "Raycasting AABBs Directly" markers: "1": "Recap and set the stage for the day" "53": "Run the game with the determination to raycast lighting boxes directly" "187": "Move the Surface computations from LightingTest() into RayCast()" "390": "Replace HitSurface in AccumulateSample() and RayCast() with a lighting_box" "970": "Run the game to see our slow lighting solution, and determine to investigate the slowness" "1081": "Add a TIMED_FUNCTION in RayCast()" "1102": "Run the game and consult the profiler to see that RayCast() is our most costly function" "1188": "Check the day" "1230": "Raycasting Against AABB" "1454": "Relieve RayCast() of testing RaySourceN for every surface" "1757": "Run the game to see that we halved the cost of RayCast()" "1796": "Relieve RayCast() of using redundant data" "1946": "Run the game to see that that didn't speed it up" "1954": "Make RayCast() perform inline the functionality of GetBoxSurface()" "2065": "Run the game to see that that halved the cost of RayCast()" "2100": "Relieve RayCast() of performing redundant work originally necessitated by GetBoxSurface()" "2332": "Run the game to see that the lighting is busted" "2362": "Reenable RayCast() to actually compute all the lighting" "2525": "Run the game to see that our lighting is back" "2558": "Optimise the Normal value out of RayCast() and introduce a Sign value" "3030": "Run the game to see that we're a little faster" "3034": "Optimise the SignX value out of RayCast()" "3202": "Optimise the HalfWidth and HalfHeight values out of RayCast()" "3261": "Optimise the Width and Height inner product computations out of RayCast()" "3519": "Run the game to see that we are down below 60ms" "3535": "Change RelOrigin to be relative to the MinCorner in RayCast()" "3796": "Run the game to see that the lighting is different and investigate why" "3879": "Revert that RelOrigin change" "3911": "Determining the ray intersection point more efficiently" "4013": "Try again to make RayCast() use the HalfWidth and HalfHeight instead of Width and Height" "4045": "Run the game to see that the lighting is wrong again" "4089": "Make RayCast() correctly compute the Width and Height" "4120": "Run the game to see that the lighting remains correct" "4123": "Consider storing the Span and P in the Box" "4157": "Run the game to see that we are at 52ms" "4177": "Toggle off the snake in PlayWorld()" "4194": "Run the game to see that we are at 26ms" "4207": "Relieve RayCast() of doing an extra comparison of XCheck and YCheck with Width and Height respectively" "4230": "Run the game to see that we are about the same" "4246": "Add P and Radius to lighting_box for RayCast(), GetBoxSurface() and PushCube() to use" "4914": "Run the game to see black lighting" "4996": "Step in to GetBoxSurface() and inspect its values" "5134": "Make PushCube() correctly set the P and Radius" "5184": "Run the game to see that the lighting is better" "5233": "Toggle back on the snake in PlayWorld()" "5244": "Run the game to see that we're at 47ms" "5323": "Toggle off the TIMED_FUNCTION in RayCast()" "5332": "Run the game to see that we are below 40ms" "5354": "Try to unroll the Axis loop in RayCast()" "5588": "Run the game to see that we are below 30ms" "5630": "Further compress the Axis "cases" in RayCast()" "5848": "Run the game to see that we remain below 30ms" "5858": "Relieve RayCast() of multiplying the Sign in to RaySourceN and d" "5933": "Run the game to see that we remain below 30ms" "5961": "Consider removing the Sign computation from RayCast()" "6073": "Switch back to the looped version of RayCast() and relive that of multiplying the Sign in to the RaySourceN and d" "6124": "Run the game" "6136": "Q&A" "6212": "Q: Is the lighting done after this?" "6228": "Q: You may now sort the episode guide entries from "new to old"" "6252": "Q: Which headers do you include for working with OpenGL?" "6271": "Q: How long until you'll move all of this to the GPU?" "6372": "Q: Why did inlining GetBoxSurface() in RayCast() result in such an improvement?" "6474": "Q: Will the lighting boxes remain sort of separate from the rest of the render commands flow?" "6489": "Q: Great stream by the way and the lighting looks great" "6523": "Q: In my engine I have 3D models that contain a buffer of uint8 which is cast to a struct which contains OpenGL handles for the model. My instinct is to hide the OpenGL stuff from the game engine itself - is this a good idea or should I just give in to the OpenGL overlords and put #include in my game code? Maybe I'm just being dogmatic" "6614": "Q: When the Jai programming language stabilizes, will you be considering using it for future handmade projects?" "6652": "Q: Is there an episode that explains some generalities about what OpenGL shaders are?" "6714": "Wrap it up" --- name: "day423" title: "Modifying Lighting to Use a Spatial Hierarchy" markers: "7": "Recap and set the stage for the day, optimising the lighting" "157": "Consider the intractability of O(n²) algorithms" "430": "Consider the kinds of numbers at play in our lighting system, and possible ways to optimise it as it is" "650": "Standard raycasting acceleration structure, bucketing up lighting elements" "878": "Ordered traversal of this acceleration structure" "1049": "k-d tree" "1242": "Multiresolution tree, aggregating lighting elements to produce a plausible, approximate solution" "1530": "Consider unifying the spatial partitioning for use by all systems" "1801": "Create handmade_lighting.h and handmade_lighting.cpp" "2019": "A few words on separating code into files" "2124": "Continue to populate handmade_lighting.h and #include our new files" "2291": "Run the game to see our lighting solution running not multiresolution, and consider how to split it into pieces" "2671": "Augment lighting_box and lighting_solution to support child nodes, and propagate this to LightingTest() and RayCast()" "3387": "Run the game and consult the lighting solution data in the profiler" "3537": "Begin to enable RayCast() to operate on a spatial partition" "3840": "Simplify raycast_result and reorganise RayCast() to handle this" "4118": "Run the game to see that that didn't much affect our speed" "4137": "Introduce a new RayCast(), rename the existing one to RayCastRecurse() and continue to enable it to operate on a spatial partition, calling itself recursively" "4450": "A few words on ray intersection of a convex vs concave solid" "4490": "Finish implementing RayCastRecurse()" "4582": "Introduce BuildSpatialPartitionForLighting()" "4950": "Run the game to see that we're doing okay" "4985": "Checking against the backface, to handle the case when a ray originates inside a cube" "5148": "Run the game to confirm that it seems to be working okay" "5212": "86 minutes into the main stream. 34 until Q&A. (based on NOTE)" "5228": "Consider how to build a basic spatial partition" "5373": "Run the game to see that ComputeLightPropagation takes 148,634,510 cycles" "5404": "Add BoxTable indirection to lighting_solution, and introduce GetBox()" "5563": "Enable BuildSpatialPartitionForLighting() to loop over our BoxTable" "5623": "Run the game to see black" "5634": "Fix BuildSpatialPartitionForLighting() to loop over the BoxTable after BoxCount has been incremented" "5661": "Run the game to see that that's fine and did not appreciably affect our performance" "5684": "Note that our indirection table allows a single child node to be placed in multiple places" "5739": "Introduce AddOverlappingBoxes() and SplitBox()" "6194": "Run the game and note that we are testing against a spatial hierarchy" "6223": "Make PlayWorld() generate 32 screens" "6253": "Run the game to see our slowdown" "6606": "Q&A" "6643": "Q: Can you try lighting as it is in a release build?" "6656": "Try to build in release mode" "6677": "Run the game to see that the O(n²) is too slow" "6699": "Make PlayWorld() produce fewer rooms" "6711": "Run the game to see the fine framerate" "6764": "Q: You mentioned something about the need to handle concave and convex solids differently when raycasting, due to (I believe) the possibility of entering and leaving a single face of a concave solid multiple times. Any chance you could explain a little more how this could affect us if we had concave solids?" "6781": "Optimally raycasting a split convex solid, based on its front face" "7078": "Raycasting a split concave solid" "7355": "Raycasting against back faces of concave solids may work the same" "7576": "Q: Why did we skip the part with placing cubes over entities such as trees and the hero? And also they should receive light in some way, right?" "7603": "Q: We just noticed your 4coder and Milton are colour coordinated. What are the values?" "7665": "That's it for today" --- name: "day424" title: "Modifying Lighting to Use a Spatial Hierarchy" markers: "0": "Recap and set the stage for the day, creating a hierarchy of lighting nodes" "45": "Run the game to see our current lighting solution running at ~30 fps" "268": "Determine to make SplitBox() do something intelligent" "307": "Introduce AddBoxStorage() and AddBoxReference()" "544": "A few words on box storage vs box referencing" "567": "Implement AddBoxReference() and AddBoxStorage()" "756": "Consider how to store our partitioned boxes" "903": "Begin to enable BuildSpatialPartitionForLighting() to build the spatial hierarchy" "1328": "Introduce a rectangle3 version of Union()" "1376": "Continue to enable BuildSpatialPartitionForLighting() to build the spatial hierarchy" "1494": "Introduce InvertedInfinityRectangle3() and GetRadius()" "1640": "Finish setting up BuildSpatialPartitionForLighting() to call SplitBox()" "1988": "Spatial Partition "In Place"" "2178": "Add ScratchA and ScratchB arrays to lighting_solution and enable BuildSpatialPartitionForLighting() to use them" "2306": "Begin to enable SplitBox() to split a box along each axis" "2696": "Consult our MergeSort() to see how it stores the data" "2768": "Try to enable SplitBox() to ping-pong between the buffers" "3868": "Introduce AddBoxReferences()" "4074": "Step through BuildSpatialPartitionForLighting() and SplitBox() to inspect their values" "4415": "Make SplitBox() break after splitting" "4434": "Continue to step through SplitBox()" "4476": "Run the game to see our resulting lighting" "4595": "Determine to debug the splitting" "4658": "Delete AddOverlappingBoxes() and read closely through RayCastRecurse()" "4767": "Note that RayCastRecurse() is not checking to see if we are inside a bounding box" "4847": "Introduce IsInRectangleCenterHalfDim() to enable RayCastRecurse() to check if we are inside a box" "5166": "Run the game to see that that sort of fixed us" "5213": "Make PlayWorld() create 32 rooms" "5232": "Run the game to see our more realistic lighting situation" "5330": "Q&A" "5361": "Q: Do you even like sushi?" "5400": "89 minutes into the main stream. 31 until Q&A. (based on NOTE)" "5462": "Q: This is a generic question, but for an example AddBoxStorage demonstrates this. I see Asserts are used to find exceptions in debug mode. What would be the way to handle a failed Assert in release mode, assuming in release Assert is just stubbed. Is it a case where most if not all problems would be found during testing and not needed to make changes for release?" "5583": "Add a TIMED_FUNCTION() in BuildSpatialPartitionForLighting()" "5612": "Run the game to see the performance of BuildSpatialPartitionForLighting()" "5652": "Q: Couldn't you have just used a stack or a queue to do a depth first search or breadth first search? You init the stack with the root box, and then splitting just adds to it, if the stack is empty you're done?" "5689": "Q: Will we need to go through each Assert call and eventually add ways to handle failure cases? Or only when we run into an issue down the line and fix those specific failures? I ask because I add Asserts to my code but then wonder what is the proper way to handle failures when I am not building release" "5766": "Q: I noticed how you barely have any code / keyword highlighting in your editor. Do you not like that?" "5792": "Q: Do you wish you never started the Sushi game thing to begin with or do you feel like you didn't waste your time and you actually got something out of it?" "5865": "Q: Like I have here for example" "5900": "Q: Have you thought of making a stream be a recap of your code, kind of looking over it and explaining it to catch people up who can't watch it all?" "5944": "Q: Started slightly late and the pre-stream went on for longer than usual" "5980": "Q: Can you add partition box visualization? Or is that not valuable?" "6028": "How close are you to finishing?" "6058": "Q: That frame profiler UI, is that custom made on stream? Looks good" "6066": "Show off the profiler" "6193": "Q: What do you think of functional programming" "6222": "Wrap up" --- name: "day425" title: "Entity-based Lighting Storage" markers: "7": "Recap and set the stage for the day, improving the runtime performance of the lighting" "56": "Run the game to show our whole world, only excepting the trees, lit" "283": "Consider the two ways of optimising the lighting solution to only process the necessary elements" "371": "Prevent PushCube() from pushing on elements outside the bounds of the lighting solution, using a new LightBounds in render_group" "658": "Run the game and hit the assert in GetHashFromID()" "678": "Make PushCube() clear the first LightIndexStore" "693": "Run the game to see no lighting on anything" "726": "Make EnableLighting() take a rectangle3 LightingBounds, and UpdateAndRenderWorld() pass the entire SimBounds to it" "804": "Run the game to see the whole world lit" "829": "Introduce smaller LightBounds in UpdateAndRenderWorld() to pass to EnableLighting()" "900": "Run the game to see a speed increase because some of the world is not participating in the lighting solution" "926": "Further shrink the LightBounds in UpdateAndRenderWorld()" "938": "Run the game to see yet more speedup, but buggy behaviour with the light apparently wrapping" "1201": "Consider how to visualise the lighting solution" "1421": "Potential bugs - correctness and performance - in the lighting solution" "1928": "Run the game and note the impossibility of diagnosing our lighting bug without visualising lighting elements" "2098": "Read carefully through PushCube() for potential bugs" "2174": "Determine to allocate lighting elements responsibly" "2282": "Introduce a free list for the lighting solution, replacing LightPointCount in game_render_commands with a u16 FirstFreeLightingChunk, adding NextFree to lighting_point and making PushCube() free and reuse light chunks" "3216": "Consider how to determine when an entity holding light indices no longer needs them" "3264": "Add a LightPointUsed array to game_render_commands for PushCube() to store light point usage" "3353": "Implement FreeLightChunk() and LightChunkFrameSweep()" "3617": "Make WinMain() clear the lighting memory every frame before rendering, and fix compile errors" "3838": "Encounter the problem of handling lights scattered about the array, and avoiding processing stuff that doesn't exist" "4237": "Replace Solution->PointCount with LIGHT_POINTS_PER_CHUNK in OutputLightingPoints() and OutputLightingTextures()" "4425": "Prevent LightingTest() from setting the PointCount, and make it copy the whole set of lighting indices" "4528": "Note that we are doing everything on an allocation basis" "4565": "Make DefaultRenderCommands() take and initialise LightChunkUsed" "4645": "Note that LightChunkFrameSweep() skips Chunk 0 and builds the free list backwards" "4784": "Replace Solution->PointCount with LIGHT_POINTS_PER_CHUNK in ComputeLightPropagation()" "5063": "Add u8 *LightChunkUsed to lighting_solution" "5103": "Run the game and hit the assert in FreeLightChunk()" "5188": "Consider how to confirm which entity occupied a light chunk" "5328": "Temporarily make PushCube() take a u32 EntityID" "5420": "Consider making entities store their previous lighting information, and use a hot list of regions rather than a free list" "5521": "Make PushCube() instead take a lighting_point *LightStore and u32 LightCount" "5669": "Add an array of lighting_point Points to the entity struct" "5860": "The problem of sharing lighting points between entities" "6103": "Large sets of lighting points" "6355": "Spatially merging lighting points" "6475": "Prevent PushCube() from taking LightCount and managing a free list" "6532": "Replace EmitC0 from game_render_commands with Emission in lighting_box, and add lighting_point *Storage to lighting_box" "6922": "Remove FreeLightChunk() and LightChunkFrameSweep()" "6955": "Restore PointCount to lighting_solution and move the light point generation code from PushCube() into LightingTest()" "7158": "Store full arrays rather than pointers in lighting_solution, and introduce lighting_point_state for lighting_box to store" "7307": "Make LightingTest() copy out the lighting solution per element" "7394": "Replace LastIsValid in lighting_solution with StorageContentsAreValid in lighting_box and propagate this change to LightingTest()" "7897": "Move the finalisation code from ComputeLightPropagation() to LightingTest()" "7988": "Consider a better way to solve the lighting across frames" "8178": "Begin to enable LightingTest() to handle both cases of storage contents validity" "8319": "Consider packing the lighting data tighter" "8557": "Make LightingTest() use alternate storage if the storage contents are not valid, and prevent OutputLightingTextures() from looping over the chunks" "8765": "Finish enabling LightingTest() to blend the lighting if the storage contents are valid, and fix compile errors" "9445": "Remove StorageContentsAreValid from lighting_box and instead make LightingTest() check if the normal of the first lighting point is valid" "9574": "Run the game and crash in LightingTest()" "9597": "Try to make LightingTest() correctly set the FirstPoint" "9629": "Run the game, crash in LightingTest() and inspect the values to find that Box->Storage is not valid" "9696": "Assert in LightingTest() that LightPointIndex <= LIGHT_DATA_WIDTH, and temporarily try hard setting the LightStore->Direction to 1, 1, 1" "9734": "Run the game to determine that the pulling out, rather than pushing on, of boxes is the problem" "9775": "Step in to LightingTest() and inspect the Solution->Boxes to find that they are all garbage" "9809": "Make UpdateAndRenderWorld() run the lighting solution before EndSim()" "9859": "Run the game to see that the Boxes look valid, but that the LightBoxCount is greater than expected, and investigate why" "9969": "Step in to LightingTest() and realise that it is erroneously operating on the new set of boxes" "10006": "Make LightingTest() store and iterate over the OriginalBoxCount" "10024": "Run the game to see that we're at least running but totally wrong" "10096": "Q&A" "10198": "Q: The 148 Mil was the number of cycles the lighting took" "10218": "Q: Is this your usual design process, a bit ad hoc?" "10334": "Wrap it up" --- name: "day426" title: "Debugging Lighting Persistence" markers: "1": "Recap and set the stage for the day debugging the lighting from last stream" "50": "Run the game to show our current lighting situation" "123": "Lighting Storage" "311": "Storing lighting data in entities" "431": "Describe the entity and lighting structures, donning the Pig Hat in the process" "661": "Describe PushCube() assigning light indices" "1070": "Determine to ensure that the LightStore round-trips successfully, and read through LightingTest()" "1322": "Assert in LightingTest() that we have extracted the final surface of the lighting box, and that the EmitC starts off cleared" "1572": "Continue to read through LightingTest()" "1682": "Note in LightingTest() to initialise directions to x = 1000, and pull out LocalCount into a variable to aid debugging" "1960": "Read through OutputLightingTextures()" "2106": "Read through ComputeLightPropagation()" "2224": "Assert in PushCube() that LightIndex != 0" "2239": "Run the game and unexpectedly fail to hit that assertion, before realising that we set LightPointIndex to 1 after all" "2307": "Continue to read through ComputeLightPropagation()" "2400": "Run the game and determine to get F1 toggling the lighting points debug visualisation again" "2425": "Read through OutputLightingPoints()" "2547": "Step in to OutputLightingPoints() and inspect its values" "2671": "Unify the lighting commands in UpdateAndRenderWorld(), and introduce the notion of discarding old commands" "2955": "Begin to introduce DiscardAllPreviousRenderCommands(), before deciding to let UpdateAndRenderWorld() instead render the old stuff before calling Clear()" "3109": "Run the game and view our lighting points debug visualisation to see that the Clear() does not work" "3137": "Make UpdateAndRenderWorld() call EndDepthPeel() before EndSim() and the lighting functions" "3162": "Run the game to see that the Clear() still fails" "3196": "Introduce render_entry_full_clear in OpenGLRenderCommands()" "3530": "Run the game to see nothing" "3547": "Make UpdateAndRenderWorld() call Clear() before BeginDepthPeel()" "3602": "Run the game to see that we are rendering again but that the lighting does not correspond across frames" "3625": "Make OpenGLRenderCommands() call OpenGLBindFramebuffer() at the end of the render_entry_full_clear case" "3642": "Run the game to see that our state is still not resetting correctly" "3657": "Investigate why our clearing is failing to produce correct lighting" "3898": "Make OpenGLRenderCommands() call glClearColor() and glClear() at the end of the render_entry_full_clear case" "3928": "Run the game to see no difference" "3979": "OpenGLRenderCommands()" "4118": "Run the game to see no difference" "4143": "Reorganise OpenGLRenderCommands() with a view to correctly clearing the render buffers" "4514": "Rename Clear() to PushFullClear() and introduce render_entry_begin_peels struct for BeginDepthPeel() to take" "4708": "Run the game to see similar behaviour" "4727": "Scrutinise OpenGLRenderCommands() to see how the render buffers are being bound and the peel indices are being used" "4941": "Make OpenGLRenderCommands() test OnPeelIndex against MaxRenderTargetIndex in the render_entry_begin_peels case" "5055": "Read through ResolveMultisample() and how it is used" "5142": "Set glClearDepth before all the render_entry cases in OpenGLRenderCommands()" "5212": "Run the game to see that the lighting points debug visualisation actually looks about right, noting that the we seem to have a correspondence problem" "5287": "Determine that OpenGLRenderCommands() may now be correct" "5331": "Run the game in -O2 and switch between the real and debug visualisation lighting" "5404": "Read through OutputLightingTextures() and then PushCube() to see if our lighting indices are corresponding correctly" "5746": "Step through OutputLightingTextures() and inspect the Solution, P, C and D" "5869": "Step through OutputLightingPoints() to compare its values with OutputLightingTextures()" "5937": "Try to hard set Valid = false in LightingTest()" "5954": "Run the game and determine that our problem is unrelated to storage" "6050": "Step through LightingTest() and watch its PointIndex and Solution values" "6399": "PlayWorld() only generate 1 screen" "6419": "Run the game and watch the behaviour of the lighting" "6458": "Stop hard setting Valid = false in LightingTest()" "6470": "Run the game to see that the lighting still doesn't correspond" "6503": "Try hard setting the normals and colour in OutputLightingTextures()" "6594": "Run the game to see that it looks as expected" "6603": "Let OutputLightingTextures() use the computed normals" "6613": "Run the game to see a tremendous amount of noise in the normals" "6692": "Hard set Valid = false and the colour values and directions in LightingTest()" "6776": "Run the game and note that the noise must be coming from somewhere up stream" "6852": "Prevent LightingTest() from hard setting the colours" "6875": "Run the game to see complete garbage" "6916": "Make LightingTest() smooth the lighting over 100 frames" "6947": "Run the game to still see noise even in the debug visualisation" "6985": "Hard set Valid = true in LightingTest() to force it to blend" "6995": "Run the game to see that this removes the noise from the lighting points debug visualisation" "7023": "Hard set the directions in the blending case in LightingTest()" "7074": "Run the game to see that the (computed) colours are garbage" "7080": "Step through PushQuad() watching the vertices' LightIndex and LightCount, and then on through the rest of the lighting code" "7719": "Temporarily make OutputLightingTextures() clamp the colours" "7767": "Run the game to see that this doesn't affect it" "7783": "Temporarily try to make OutputLightingTextures() loop over the boxes in the same manner as OutputLightingPoints()" "7883": "Run the game to see that the lighting still doesn't correspond" "7944": "Temporarily prevent UpdateAndRenderWorld() from calling PushFullClear() before OutputLightingPoints()" "7960": "Run the game to see that the lighting is still wrong" "7989": "Temporarily try to make OutputLightingPoints() perform the very code from OutputLightingTextures()" "8099": "Run the game and toggle between the two views to see that they perform identically" "8189": "Read carefully through the lighting code, following the textures down the pipeline, and note that there is one frame lag in them" "8376": "Make UpdateAndRenderWorld() call PushLighting() immediately after EnableLighting()" "8460": "Run the game to see that that totally fixes the problem" "8549": "Remove the test code" "8572": "Run the game to see that it doesn't work quite right" "8591": "Hard set Valid = true in LightingTest()" "8598": "Run the game to see that it's correct" "8695": "Owl of Shame Moment: The removed frame of lag exposed the fact that our lighting indices were not lining up across frames" "8884": "Q&A" "8960": "Q: Perhaps the perspective of the game would make this a bit awkward to do but are you planning to have water in the game with reflections, sine waves, and shaders and all that cool stuff?" "9035": "Q: Blackboard please" "9045": "Lighting Index Correspondence, Old vs New Way" "9462": "Q: What time will the pre-stream will start tomorrow? Got some off-topic burning questions" "9480": "Q: So we have to call the PushLighting() twice for a solution? Or there is another way to solve the bug?" "9570": "Q: I know you said it's a common class of bug, but do you have any thoughts on how you might avoid a bug like this in the future?" "9704": "Q: So this frame latency is bad if we would made this a multithread system?" "9723": "Q: Are you allowed to elaborate more on how Moustache works exactly?" "9742": "Q: So you cant use the 4th lines of light and on the 6th line the light stops? There is no other way to make the light stop?" "9775": "Allow UpdateAndRenderWorld() to call PushFullClear()" "9801": "Run the game to see that the debug visualisation is as expected" "9871": "Q: What is the performance on the big level now?" "9895": "Make PlayWorld() generate 32 screens" "9905": "Run the game to see our lighting performance" "10002": "Q: Will you add tone mapping at some point?" "10015": "Q: Can you implement more light sources later? Like holding a torch, or such or other sources of light?" "10021": "Run the game to show all of the light sources" "10094": "Q: Not exactly on topic but you don't use your attempt in the for loop in SplitBox()" "10148": "Set DimIndex = NextDimIndex at the end of SplitBox()" "10179": "Run the game to see that everything seems fine, and note that the lighting bounds should be based on the camera" "10222": "Q: What's the differences between the game without OpenGL and with OpenGL?" "10245": "Q: Yep, otherwise it was a useless loop" "10264": "Q: Have you tried the Clang compiler (on windows, the versions of the last few months)? I have been loving the error messages, e.g. it rolls out scopes of macros. (I have it on F3 for when VisualStudio messages fail me.) Just wondering about your opinion if you have used it" "10448": "Close it down with a few words on updating the Molly Rocket website" --- name: "day427" title: "Debugging Lighting Flicker" markers: "1": "Recap and set the stage for the day doing lighting optimisation" "157": "Run the game to see our current lighting situation" "250": "Determine to enable OpenGLRenderCommands() to correctly clear the backbuffer" "376": "Step in to OpenGLRenderCommands() to see that it may be clearing the wrong render target" "422": "Read through OpenGLRenderCommands(), to see if we are indeed clearing the wrong target" "485": "Step through OpenGLRenderCommands() watching the OnPeelIndex" "517": "Make OpenGLRenderCommands() increment the HeaderAt pointer inside the commands loop" "649": "Run the game to see that the clear is back to the correct behaviour" "751": "Read through the lighting code with a view to optimising it" "933": "Run the game and point out that we are not leveraging our previously computed lighting" "987": "Enable LightingTest() to use the previously computed lighting emission" "1236": "Run the game to see flickering lighting" "1267": "Make LightingTest() save the new lighting emission back" "1350": "Run the game to see that we're a lot slower" "1371": "Reduce the RayCount in ComputeLightPropagation()" "1396": "Run the game to see that the lighting is still very flickery" "1443": "Increase the RetainedEmissionCoefficient in LightingTest()" "1456": "Run the game to see the light spreading" "1524": "Change ComputeLightPropagation() to use a power-decaying scheme" "1670": "Run the game to see more reasonable lighting" "1681": "Tweak the BlendAmount, RayCount and IterationCount in ComputeLightPropagation()" "1772": "Run the game and consider that a single pass on the lighting may be usable" "1839": "Determine to rework ComputeLightPropagation() to compute the lighting in a single pass" "2032": "Rework ComputeLightPropagation() to compute the lighting using a single-pass point collection-style scheme" "2851": "Resolving discontinuities caused by snapping the lighting samples to spatial partitions" "3189": "Enable ComputeLightPropagation() to blend the lighting emission by the DistanceSq" "3343": "Describe the InvDistanceSq computation – (1 / (1 + x²)) – via a graph" "3486": "Continue to enable ComputeLightPropagation() to accumulate, blend and attenuate the light" "4607": "Run the game to see that we get a little grey lighting, and step through ComputeLightPropagation()" "4683": "Remove NextFree from lighting_point" "4710": "Continue to step through ComputeLightPropagation() inspecting the lighting values" "4926": "Increase the Power value in ComputeLightPropagation()" "4968": "Run the game to see that the lighting is still flickering" "5064": "Make ComputeLightPropagation() propagate forwards the previously computed lighting" "5130": "Run the game and still see flicker, due to the unpredictable moonlight sampling" "5289": "Enable the BlendAmount in ComputeLightPropagation() to work as expected" "5470": "Run the game without the skylight, to find that BlendAmount works as expected" "5515": "Reconsider the problem in light of the fact that a lower BlendAmount does not reduce the flicker" "5798": "Make ComputeLightPropagation() and AccumulateSample() sum the lighting identically" "5917": "Run the game to see that it is exactly as it was, and step through ComputeLightPropagation()" "6050": "Enable ComputeLightPropagation() to measure the total light removed and distributed" "6150": "Step through ComputeLightPropagation() to see that TotalAdded is less than TotalRemoved, and that a very low BlendAmount still fails to prevent the flicker" "6544": "Read carefully through LightingTest() to double-check our assumptions" "6623": "Make ComputeLightPropagation() sum in (and not clear) the AverageDirectionToLight" "6707": "Run the game to see the flicker-free lighting" "6740": "Work on the transmission amount in ComputeLightPropagation()" "7152": "Run the game and consider that we have a bug in the light removal" "7290": "Q&A" "7384": "Q: I don't think your lighting approach (it's kinda like photon mapping but in weird) will work. I think it's worth to rethink your whole idea" "7413": "Q: Doesn't a surface need a hit to have its light reduced? If nothing hits the surface, the light will remain constant" "7487": "Q: EmitC += Weight*ContribC, isn't that wrong? It should be RemovedC I think. I may be wrong of course" "7521": "Q: What editor are you using?" "7528": "Q: Is the RPI still a thing?" "7541": "Consider the bidirectional nature of the lighting" "7634": "Q: I study game engineering, so I had some courses about rendering and lighting. What you try is kinda over the top for a live game. I would advise to look into radiosity" "7726": "Q: Raspberry Pi" "7800": "Determine to make ComputeLightPropagation() bidirectional, using one array, tomorrow" "8006": "Q: I thought radiosity approximates the light for one area and not trace single rays to the areas" "8067": "Q: McGuire's 2016 paper "Deep G Buffer for Stable Global Illumination" has a very good implementation of radiosity and his implementation of a deep g buffer is analogous to the depth peeling you are using in Handmade Hero" "8211": "Are you implementing transparency?" "8253": "Reenable the particles and run the game to show the transparency" "8298": "Q: When you remove the light of the current frame RemoveC after, say, 5 frames, you have to in some way clear DestC and add only SourceC and restart the blend, otherwise it will add forever? Very small portions will get added constantly. Did I misunderstand something?" "8407": "Try to make ComputeLightPropagation() accumulate to a constant amount of light" "8671": "Run the game to see that this doesn't seem to be working, and step through it to see why" "8785": "Try hard-setting SourceSum" "8860": "Run the game to see the effects of this" "9113": "Double-check in ComputeLightPropagation() that the light is being clamped" "9169": "Run the game to determine that we still have issues" "9293": "Consider that we are close to this working reliably" "9382": "Q: What comes after lighting? Any ideas?" "9430": "Q: How big is the current codebase, loc wise?" "9563": "cmuratori Can you work Yakety Sax into this program somehow?" "9625": "cmuratori Change one note, like Vanilla Ice did" "9661": "Shut it down" --- name: "day428" title: "Tracking Light Proportional to Photons per Second" markers: "1": "Recap and set the stage for the day continuing debugging the lighting" "203": "Lighting transport with fewer sample points than in nature, and the need to record light over time" "491": "Introducing 1. Formulation for stored light that means something" "571": "Introducing 2. Understanding of emission and extinguishing" "763": "Introducing 3. Difference between render colour and the emission" "1063": "Unidirectional vs Bidirectional Transport" "1325": "1. Formulation for stored light that means something" "1674": "Photons / sec, with separate arrays for the emitters and collectors" "1934": "Using photons / sec to update the collectors" "2342": "2. Understanding of emission and extinguishing" "2392": "3. Difference between render colour and the emission" "2420": "Consider the sanity of this way of looking at the problem" "2572": "Consider how to move ComputeLightPropagation() towards a scheme in which emitters emit light at a constant photons / sec rate" "2742": "Emitter-Reflectors" "2913": "Introduce the notion of photons / sec and AccumulatedWeight in lighting_solution for LightingTest() to use to average the light over time" "4039": "Simplify ComputeLightPropagation() and AccumulateSample(), enabling the latter to use our new notion of AccumulatedWeight" "4459": "Finish simplifying and enable ComputeLightPropagation() to use our new notion of photons / sec" "4831": "Run the game to see some flickering" "4891": "Step through LightingTest() to inspect the lighting Solution" "5417": "Try to fix the if(Valid) test in LightingTest() and make CompileZBiasProgram() clamp the surface reflectance" "5658": "Continue to step through LightingTest()" "5710": "Correctly fix the if(Valid) test in LightingTest()" "5774": "Continue to step through LightingTest()" "5802": "Fix the AccumulatedPPS computation in LightingTest()" "5944": "Continue to step through LightingTest()" "6001": "Darken the MoonColor in ComputeLightPropagation()" "6029": "Run the game to see our current lighting solution" "6153": "Try preventing OutputLightingTextures() from updating the AverageDirectionToLight" "6195": "Run the game to observe the difference in just the emission values" "6326": "Try forcing LightingTest() to always accumulate the lighting from the previous frame and reduce the tUpdate" "6405": "Run the game to barely see flicker" "6461": "Try increasing the RayCount in ComputeLightPropagation()" "6475": "Run the game to see greatly reduced flicker" "6513": "Increase the MAX_LIGHT_EMISSION and reduce the RayCount" "6570": "Consider stabilising our samples" "6657": "Q&A" "6760": "Q: Is that... color banding I see? I hope that's just from being on-stream" "6880": "Q: What do you think of game development frameworks like unity? Do you think an AAA game can be made using it?" "6962": "Q: Why can't sampling rays be evenly distributed to eliminate the flickering? Wouldn't it be fine with enough rays?" "6978": "Distribution of Rays" "7052": "Q: I've been watching a fair bit of the backlog, and you seem to return values from functions via parameter pointers, even when you're not returning anything else (i.e. `void Func(int Arg, int *Return)` instead of `int Func(int Arg`)). Is there any particular reason behind this? I can imagine it maybe stops the API changing too much over time?" "7110": "Q: Are there any light effects that you can think of where assuming bidirectional ray sampling would give janky results? Maybe subsurface scattering?" "7213": "Q: But if the rays are the same across frames, the flickering would only happen around moving objects? Would that be less offensive during gameplay?" "7270": "Stratified sampling" "7365": "Q: Would it be possible to cast cones instead of rays?" "7441": "Q: Do you currently do any form of ambient occlusion?" "7495": "Q: So you could use a blue noise-like source to select possible "cones" and shoot random rays inside each of these cones?" "7523": "Q: What do you think about buying an IP that is practically abandoned by the publisher / developer? For a game that has about 100 players online at maximum? This is an online game" "7534": "Q: How much does each new light in the scene reduce performance?" "7561": "Q: (Off-topic) Do you feel like you still have the same passion for this project as you did back when you first began, or do some days feel more like it's a chore?" "7634": "Q: I'm sure it's been asked before, and maybe to some extent like reflections AAA games do this, but are ray casters / tracers really such a performance hit that they aren't used on more complex set of geometry in games like Call of Dooters or just in general games with lots of geometry?" "7838": "Q: Do you have any good sources for learning about making lighting solutions?" "7859": "Q: Our light is not getting, at least on the light propagation, more close to PBR schema? How would we implement fog in this system? Can we simulate different media through which the light propagates?" "7990": "That's about it" --- name: "day429" title: "Multiresolution Light Sampling" markers: "0": "Recap and set the stage for the day working on the lighting" "97": "Run the game to show our current lighting situation whose stability is dependent on the rays" "254": "Wax lyrical on serge_rgb's wonderful work on milton" "349": "Lighting mods" "430": "1. Stratified Sampling, including white noise" "832": "White vs Blue noise" "1053": "Light perception" "1167": "Blue noise, with a mention of the Witness Wednesday glass-planting system" "1307": "Performing stratified sampling" "1518": "2. "Multires sampling"" "1726": "3. "Bidirectional sampling"" "1912": "Make PlayWorld() generate 16 screens" "1943": "Run the game and inspect the profiler, with the determination to get multiresolution sampling working" "2051": "Read through the current lighting code with a view to implementing multiresolution sampling, with synthetic light indices for neighbouring spatial partitions to use" "2326": "Introduce the notion of an ExtendedPointCount in lighting_solution, to store synthetic lighting data" "2727": "Producing the data for the synthetic lighting elements" "2988": "Make SplitBox() produce the extended lighting points from the average of all points in their box" "3735": "Run the game to see the total lighting solution, and determine to produce some debug visualisation of the spatial hierarchy" "3860": "Introduce OutputLightingPointsRecurse() to produce debug visualisation for the lighting system's entire spatial hierarchy" "4247": "Step in to OutputLightingPoints() to realise that we are indirected" "4413": "Make OutputLightingPoints() and SplitBox() use GetBox()" "4511": "Run the game to see our lighting debug visualisation" "4566": "Make OutputLightingPointsRecurse() size the debug visualisation lighting boxes proportionally to their depth in the hierarchy" "4806": "Run the game to see our proportionally-sized lighting debug visualisation" "4861": "Provide the ability in UpdateAndRenderWorld() to adjust the depth hierarchy" "4935": "Run the game and inspect our entire lighting hierarchy" "5043": "Make SplitBox() set the AccumulatedPPS to the InitialPPS" "5131": "Run the game and inspect our entire lighting hierarchy" "5226": "Prevent OutputLightingPointsRecurse() from including the emission of a childless light source" "5257": "Run the game to see that that doesn't fix our problem" "5534": "Enable RayCastRecurse() to recurse to a given depth" "5615": "Run the game and watch the RayCastBoxCount while adjusting the depth in RayCastRecurse()" "5701": "Make PlayWorld() create larger rooms" "5733": "Run the game and again watch the RayCastBoxCount while adjusting the depth in RayCastRecurse()" "5909": "Step in to LightingTest() to inspect the PointCount" "6008": "Make LightingTest() use a temporary variable for the PointCount before giving it to the DEBUG_VALUE" "6031": "Run the game to determine that we have a bug in how we output u16s" "6037": "Add padding in lighting_solution after PointCount" "6106": "Run the game to see that that fixes it" "6157": "Add a u16 handler in DEBUGValueSetEventData" "6348": "Run the game to see that our PointCount is displayed correctly, but that our RayCastBoxCount seems to be too high" "6582": "Augment lighting_solution with some more meaningful counters" "7004": "Run the game and inspect lighting data in the profiler" "7093": "Force RayCastRecurse() never to recurse" "7110": "Run the game to see that TotalPartitionsTested did not go down much" "7224": "Read carefully through RayCastRecurse()" "7296": "Run the game and watch the TotalLeavesTested when recursing or not" "7372": "Try making PlayWorld() create more layers" "7486": "Run the game and now watch TotalLeavesTested() when recursing or not, to see that, when it doesn't recurse, it goes down much more now that there is a layer of geometry above use" "7648": "Q&A" "7743": "Q: Can you explain why was the debug output behaving odd with u16s?" "7967": "Q: How likely is a lighting system GPU port still?" "7999": "Q: (Off-topic) Did you ever find out if it's necessary for CPUs to have named registers?" "8138": "Look at Mill CPU. It has no registers, but it is also a vaporware as far as physical implementations go" "8241": "Q: Do you think arranging pixels on LCD monitors in a blue noise pattern would be an improvement visually, I assume the costs to manufacture would sky rocket, or are we just better off making the pixels smaller?" "8300": "Q: Memory is slow" "8315": "Close down" --- name: "day430" title: "Stratifying and Multithreading the Lighting" markers: "2": "Recap and set the stage for the day continuing with lighting mods" "18": "Lighting mods" "64": ""Stratified sampling" with a few words on random number generation and debug visualisation" "290": "Run the game to see what we see, i.e. no debug visualisation of our ray casting" "453": "Introduce PushDebugLine() and a debug_line struct to draw the lighting rays" "1030": "Run the game to see our wild rays" "1071": "Reduce the line thickness in OutputLightingPoints(), and fix the location of their origin in LightingTest()" "1237": "Run the game to see our stably located rays" "1307": "Reduce the near clip plane distance in UpdateAndRenderWorld() if in debug mode" "1333": "Run the game to see our debug visualisation" "1364": "Raise the ray's origin in LightingTest()" "1381": "Run the game and see our lighting ray debug visualisation" "1393": "Add a keybinding to pause the lighting ray debug visualisation" "1584": "Run the game, and pause and inspect our lighting ray debug visualisation" "1830": "Stratified Hemisphere Sampling" "2146": "Add XAxis and YAxis to lighting_point for SampleHemisphere() to take and distribute the samples into two halves" "2463": "Run the game to see our distributed lighting samples" "2643": "Add a SampleTable to lighting_solution for LightingTest() to fill with customised locations" "3167": "Run the game to see no flicker because the rays are not random" "3212": "Flatten down the midrange rays in LightingTest()" "3236": "Run the game to see our distributed rays" "3296": "Add some randomness into SampleHemisphere()" "3389": "Run the game to see our perturbed rays, with flicker" "3440": "Add a tweakable Ratio in SampleHemisphere()" "3469": "Run the game and tweak the Ratio, watching the effect on the flicker" "3581": "Increase the tUpdate in LightingTest(), to smooth the lighting over a longer time" "3610": "Run the game to inspect the lighting, and consider using predictable sampling, smoothed over time" "3727": "Replace the random Series with EntropyCounter in lighting_solution, to predictably seed the random number generator per lighting sample" "3916": "Run the game to see the effects of this" "3973": "Make ComputeLightPropagation() correctly pin the EntropyCounter to the lighting sample" "4024": "Run the game to see a repetitive pattern in the rays" "4107": "Make LightingTest() blend the lighting slower than it takes samples" "4209": "Run the game to see that this doesn't help us much" "4254": "Enable OutputLightingTextures() to factor in the direction to light" "4285": "Run the game to see how this affects the lighting solution" "4347": "Prevent LightingTest() from blending the light over time" "4388": "Run the game to see that this is incredibly noisy" "4510": "Tweak the EntropyCount and tUpdate in LightingTest(), and increase the RayCount" "4618": "Run the game to see our coverage" "4656": "Increase the Ratio in SampleHemisphere() and set the RayCount to 16 in ComputeLightPropagation()" "4681": "Run the game to see our more evenly distributed rays, and consider how to proceed" "4821": "Introduce a DoLightingWork() callback to thread the ray casting" "5327": "Run the game to see how this works" "5362": "Add a single-thread toggle to ComputeLightPropagation()" "5417": "Run the game to see that the threaded path has slowed us" "5429": "Try making ComputeLightPropagation() loop over fewer samples" "5500": "Run the game to see that we are still slow" "5557": "Try toggling SampleHemisphere() back to how it was" "5598": "Run the game to determine that this has nothing to do with it" "5640": "Distribute the work across multiple threads again" "5683": "Run the game to see that we do get a little bit faster, but not as much as expected" "5851": "Increase the RayCount to 64 and run the game comparing it in the single- and multithreaded paths" "5961": "Add a TIMED_FUNCTION() to LightingTest()" "5998": "Run the game to see that the heavy load is entirely in ComputeLightPropagation()" "6040": "Comment out all instances of values changing in the solution" "6131": "Run the game to see that this speeds us up, and add back in some of those value changes, noting that we were thrashing the cache" "6352": "Make ComputeLightPropagation() set PointsPerWork to a multiple of 16, for cache-line alignment" "6607": "Run the game to see that we are still speedy" "6728": "Q&A" "6752": "Q: Can we temporarily turn off / turn down the frame-to-frame color interpolation to see how much the increased sample count stabilizes the solution on its own?" "6764": "Temporarily disable smoothing and tweak the RayCount, sample randomisation and EntropyFrameCount" "6999": "Q: Can someone explain why to store and pass around OnePastLastSamplePointIndex instead of calculating at the loop part?" "7169": "Q: Why we not using the atomics when we modify data on the multithread pass?" "7205": "Q: Given the restricted number of rays should they be biased towards directions which are "interesting" to us, i.e. not vertically? Just wondering as are we interested in the light values gained from the ceiling compared to that from surfaces which the player can visually see on screen" "7263": "Q: Can the raycasts be optimized more?" "7300": "Q: Would increasing the size of the SampleTable make sense if we are going to 64 rays?" "7321": "Q: Since you only use cubes, depending on the height of the light you may know exactly where to cast since there can be, say, only 4x4 square over you at a certain height? I think it could work even if the light is placed as a "wall" the generated table based on height would be flipped towards the normal?" "7358": "Q: Less technical question: how are you today?" "7400": "Q: Normal of the wall" "7543": "Q: Now the threading is working well, how does it scale with more threads?" "7814": "Q: What's the status of using LLVM?" "7837": "Q: How is the light source stored?" "7856": "Q: No more wrist supports?" "7859": "Q: Use the new calculator!" "7939": "Q: Are there any ways to make it clear in your profiler that you are having these cache issues (concerning threads, and shared memory) or is this just something you have to look for with trial and error, experience etc?" "8070": "Q: In menu, View -> History might help" "8105": "Time to shut down, with a glimpse into the future optimising the lighting and reducing its variance more intelligently" --- name: "day431" title: "SIMD Raycasting" markers: "2": "Recap and set the stage for the day with a few words on the pace of the project" "249": "Run the game to see our current software-rendered lighting, with the determination to see how much performance we can get out of the CPU" "407": "Prevent RayCast() from summing the TotalCastsInitiated" "423": "Run the game to see that that does not appreciably affect our performance" "485": "Augment lighting_work with some of the lighting_solution, to avoid bouncing cache lines around" "968": "Run the game and inspect the profiler" "1012": "Make lighting_work and lighting_solution cache-aligned" "1193": "Cache-alignment and false sharing considerations when threading" "1455": "Introduce InitLighting() to align our lighting data" "1881": "Run the game and determine to double check that everything is aligned and figure out why the tests are slow" "1942": "Assert in ComputeLightPropagation() that the lighting_work is aligned" "1997": "Run the game and hit that assertion" "2041": "Pad the lighting_work to 64 bytes" "2080": "Run the game to see that we are running at full speed again" "2153": "Profile PartitionsPerCast and LeavesPerCast in ComputeLightPropagation()" "2274": "Run the game and consult the profiler to see that our PartitionsPerCast is high, and consider how to reduce them" "2510": "Add a TIMED_FUNCTION() in RayCast()" "2548": "Run the game and consult the profiler to see that our RayCast() is not too bad" "2724": "Remove the recursion in RayCastRecurse()" "2965": "Run the game to see that that greatly improved our performance" "3035": "Just make RayCast() perform our new code from RayCastRecurse()" "3126": "Run the game to see that that doesn't change our runtime" "3133": "Prevent RayCast() from taking Solution and add a TIMED_FUNCTION() in it" "3189": "Add a TIMED_FUNCTION() in RayCast()" "3205": "Run the game and see the performance of RayCast(), disable HANDMADE_SLOW and consider what to tackle next" "3345": "Consider performing RayCast() in SIMD" "3621": "Reduce RayCount from 64 to 16 in ComputeLightPropagation()" "3636": "Run the game to see what kind of a speedup SIMD could provide" "3702": "Enable ComputeLightPropagation() to call SampleHemisphere() in SIMD, introducing V3_4x()" "4219": "Update RayCast() to work with our SIMD data, introducing GetComponent()" "4972": "Run the game, crash in RayCast() and investigate why" "5070": "Temporarily disable threading in ComputeLightPropagation()" "5174": "Step through RayCast() to try and see what's going wrong" "5532": "Assert in RayCast() that the Depth is < BoxStack" "5584": "Step back into RayCast(), and eventually hit that assertion" "5705": "Increase BoxStack from 32 to 64 in RayCast()" "5730": "Run the game and see nothing" "5756": "Prevent RayCast() from pushing on the boxes four times" "5862": "Run the game to see that our performance has decreased" "5898": "Enable RayCast() to call IsInRectangleCenterHalfDim() in SIMD" "6335": "Introduce Any3TrueInAtLeastOneLane(), All3TrueInAtLeastOneLane(), AbsoluteValue() and v3_4x versions of <=, −, | and &" "7196": "Step in to RayCast() and inspect our SIMD data" "7319": "Prevent AbsoluteValue() from converting the Mask to a float" "7395": "Step back in to AbsoluteValue() and through our other new SIMD functions in RayCast()" "7573": "Run the game to see that our lighting is a little bit messed up" "7639": "Make RayCast() perform the old scalar code after our SIMD code, to verify the SIMD" "7888": "Run the game and fail to hit our verification assertion" "7990": "Prevent RayCast() from erroneously breaking out of the child box loop" "8028": "Run the game to see that we are correct" "8047": "Streamline and switch RayCast() almost entirely over to SIMD, introducing ZeroV34x(), versions of V3_4x() that load four scalars, and one wide set, into lanes, v3_4x versions of − for full 4-wide negation, < and *, a f32_4x struct and versions of −, * and / that use this type" "11958": "Step in to RayCast() to inspect its values" "12093": "Make RayCast() subtract only one element of the FaceRelOrigin, introducing a f32_4x version of -=" "12495": "Step in to RayCast() and inspect the FaceRelOrigin" "12559": "Run the game to see that we are producing the correct lighting a little faster" "12590": "Enable RayCast() to perform the bounds checking in SIMD" "13271": "Organise handmade_simd.h and introduce f32_4x versions of every operator and function we need" "14550": "Run the game to see that it's totally fine" "14581": "Read through RayCast() with the determination to finish doing it all in SIMD" "14662": "Start to enable RayCast() to update and load out the boxes in SIMD, before saving it for tomorrow" "15061": "Q&A" "15121": "Clarify the video capture card situation mentioned in the pre-stream" "15178": "Q: I think you call AnyTrue() from within AllTrue(). Can you check that's intended?" "15269": ""And" and "All" in a matrix" "15359": "Call it there" --- name: "day432" title: "Finishing the Main SIMD Raycasting Loop" markers: "1": "Recap and set the stage for the day finishing SIMD optimising the lighting" "47": "Toggle on the threading and add a b32 Hit to raycast_result for RayCast() to encode that a ray did not hit" "357": "Run the game to find that we're running at 32ms" "389": "Toggle off the threading" "409": "Run the game to see that we're running at 128ms per frame" "438": "Toggle on the threading" "446": "Run the game and consider our 32ms per frame rate" "583": "Excise from RayCast() the non-SIMD tRay code, and start to consider how to retire rays hits" "702": "Preserving ray hits vs traversing the spatial hierarchy, when threading" "957": "Enable RayCast() to record ray hits for each SIMD component before traversing the spatial hierarchy" "1202": "Run the game to see that we're running at the same 32ms" "1237": "Revert RayCast() to traverse the spatial hierarchy, applying the ray hit mask for each component, and streamline how this works, introducing f32_4x versions of &= and |=" "1618": "Run the game to see that that's fine" "1626": "Start to streamline the tRay setting code" "1736": "Fix the CloseEnough check in RayCast()" "1805": "Run the game to see not much difference" "1820": "Introduce Select() to streamline the tRay setting code" "2055": "Run the game to see that we are at ~28ms per frame" "2084": "Make RayCast() set the BoxIndex and BoxSurface in SIMD using Select()" "2550": "Run the game and crash in ComputeLightPropagation()" "2685": "Step in to GetBox() to see that our BoxIndex is busted" "2793": "Step through RayCast() to see what's happening" "2986": "Make RayCast() actually set the BoxIndex and BoxSurfaceIndex" "3055": "Run the game with the selection happening" "3069": "Make RayCast() set the RayP in SIMD using a v3_4x version of Select()" "3218": "Run the game to see that we are down to ~26ms" "3262": "Add a TIMED_FUNCTION() in RayCast()" "3281": "Run the game to consult the profiler" "3295": "Add a TIMED_BLOCK() around the startup code in RayCast()" "3335": "Run the game and consult the profiler to see that the startup cost is not high" "3360": "Perform SampleHemisphere() in SIMD" "3682": "Run the game to see that we're down to 22ms per frame" "3724": "Temporarily make SampleHemisphere() use complete randomisation" "3740": "Run the game to see that this would put us back up to 30ms per frame, and note why" "3848": "Drop the RayCount down to 4 in ComputeLightPropagation()" "3865": "Run the game and unexpectedly see no speed improvement" "3945": "Remove variable suffixes in RayCast()" "4135": "Consider removing the Depth loop in RayCast() and reposition the AnyTrue(Mask) test" "4231": "Run the game and consider where to go from here" "4285": "Inspect the assembly of RayCast()" "4472": "Remove the Mask tests from RayCast() entirely" "4516": "Run the game to see no real difference" "4540": "Try removing the AnyTrue(tCheck)" "4555": "Run the game to see that that would put us up to ~25ms per frame" "4611": "Compute RayP at the very end of RayCast()" "4710": "Run the game to see no difference" "4721": "Replace RayP with tRay in RayCast()" "4840": "Run the game to see no difference" "4861": "Let RayCast() break if(AllTrue(Mask))" "4872": "Run the game to see no difference" "4897": "Toggle off the snake" "4907": "Run the game with our consistently lit scene" "4948": "Inline AccumulateSample() in ComputeLightPropagation()" "5137": "Run the game to see no difference, and consider further improvements" "5226": "Make SampleHemisphere() operate entirely SIMD, introducing RandomBilateral_4x() and versions of Inner(), LengthSq() and NOZ() that take v3_4x" "6095": "A few words on _mm_rsqrt_ps and _mm_sqrt_ps" "6260": "Rename our new NOZ() to ApproxNOZ() for SampleHemisphere() to call, and introduce ApproxInvSquareRoot() using _mm_rsqrt_ps" "6564": "Run the game to see no difference" "6592": "Inline SampleHemisphere() in ComputeLightPropagation()" "6711": "Run the game at ~22ms per frame, and consider that this CPU rendered lighting is performant enough for us" "6772": "Q&A" "6802": "How much % of the CPU does it drain?" "6967": "Q: What version control system do you use?" "7010": "Q: Can you look at the thread profile view when you lower the samples from 16 to 4 and don’t improve frame rate?" "7068": "Temporarily Toggle off VSync" "7126": "Run the game and consult the profiler to determine that the pixel shader is too slow" "7337": "Q: You cast the input value in the U32_4x loader to a float. Why is that?" "7532": "Q: How does the mask replace an if in the SIMD instructions?" "7546": "Masking in SIMD" "8378": "Read about PBLENDVB - 'Variable Blend Packed Bytes' in the Intel 64 and IA-32 Architectures Software Developer Manuals and consult the Steam Hardware Survey for instruction set use" "8723": "Q: Why does the light flicker even when the cube is not moving?" "8742": "Q: Could we ship with SSE4, so we have _m256 and get more performance improvement?" "8752": "Q: What can you see in TaskManager's GPU tab?" "8845": "Q: Do you have any tips on talking with non programmers about programming related concepts?" "8854": "Q: How does your profiler work? Does it hook into the compiler or something?" "8871": "Q: Could we compile one exe with SSE4 that falls back to SSE2 if it's not present on the CPU, or would we need to compile into several exe's?" "8930": "Close up shop" --- name: "day433" title: "Optimizing Ray vs. AABB Intersections" markers: "2": "Recap and set the stage for the day refining the lighting" "31": "Take Visual Studio's quick feedback survey" "495": "Run the game to see our current lighting situation" "719": "Consider the performance of ComputeLightPropagation()" "858": "Track TotalPartitionLeavesUsed in ComputeLightPropagation()" "1077": "Consult the TotalPartitionLeavesUsed performance figures" "1102": "Determine to change SplitBox() from doing k-d to quad tree partitioning" "1215": "k-d tree vs Quad tree" "1260": "Allow SplitBox() to have 8 leaves per child, increased from 4" "1292": "Run the game to see that that doesn't appreciably change our runtime" "1304": "Track PartitionsPerLeaf in ComputeLightPropagation()" "1357": "Run the game and compare the PartitionsPerLeaf with 8 and 4 leaves per child" "1389": "Toggle off ComputeLightPropagation()" "1421": "Run the game to determine that our shader is the bottleneck" "1560": "Toggle off wglSwapIntervalExt in Win32InitOpenGL()" "1585": "Run the game and watch the threads view with the determination to investigate the time delay" "1709": "There's a knock at the door" "1730": "afk" "1748": "Return and consider the threads view to be misleading" "1893": "Introduce HUD_TIMED_FUNCTION() called in LightingTest() to enable more direct textual profiling of the lighting rendering" "2213": "Run the game to see that it does nothing different" "2241": "Enable DEBUGEnd() and DEBUGInit() to handle HUD_TIMED_FUNCTION(), renaming AddTooltip() to AddLine() and DrawTooltips() to DrawLineBuffer()" "3473": "Crash in DEBUGDrawElement() and inspect what's going on" "3759": "Enable DrawTreeLink() to handle the case when a tree has no element and no children, and change HasChildren() to CanHaveChildren()" "3892": "Run the game to see that we do not crash, and see our new HUD element" "3984": "Make DEBUGEnd() display only the function name of our HUD_TIMED_FUNCTION(), expandable to contain textual profiling information for its child functions" "4647": "Step in to DEBUGEnd() and inspect the HUD element" "4961": "Enable DEBUGEnd() to gather profiling information for our HUD element" "5468": "Run the game and consult our LightingTest() HUD to see that our average value is busted" "5544": "Fix DEBUGEnd() to correctly compute the average cycle count" "5635": "Run the game and consult the performance of LightingTest() in the new HUD" "5737": "Tweak the leaves per child value in SplitBox(), comparing their performance in the HUD, and consider that our spatial partitioning is not effective enough" "5975": "Consider making the RayCast() more performant with AABB testing" "6109": "Read 'Fast, Branchless Ray / Bounding Box Intersections' and 'Fast Ray / Axis-Aligned Bounding Box Overlap Tests using Ray Slopes'" "6336": "Ray AABB testing" "6438": "Continue to read these papers on ray AABB testing" "6983": "Change RayCast() to perform AABB testing" "7155": "Computing X, Y and Z intersections in T" "7581": "Doing this without caring which direction the normal is facing" "7771": "Continue to enable RayCast() to perform fast AABB testing" "7985": "Determining the tMin and tMax intersection points" "8052": "Enable RayCast() to compute those tMin and tMax" "8150": "The Maximum-Minimum and Minimum-Maximum" "8189": "Set tMin and tMax and continue enabling RayCast() to perform fast AABB testing" "8851": "Consider how to determine which side of the box we hit" "9024": "Enable RayCast() to select the correct BoxSurfaceIndex" "9327": "Introduce f32_4x and v3_4x versions of Min() and Max(), and the v3_4x / operator" "9483": "Run the game to see that it looks pretty similar, and is faster" "9591": "Introduce v3_4x * operator and make RayCast() precompute the RayD" "9653": "Compare the performance of this with the previous way" "9689": "Consider breaking down our profiling of LightingTest()" "9805": "Consult the threads view to see that the performance is more reasonable" "9832": "Try to stress the system" "9917": "Q&A" "9961": "SurfaceIndexLookupTable[movemask(tmin == tBoxMin)], and just choose the first set bit in the return from the movemask for which index" "10035": "Q: Would we get an improvement if we switch all the v3 to a v3_4x so we have not to load the value into the __m128 each frame?" "10060": "It would only be 256 entries" "10085": "Q: Could you recap how we retain the state of the debug UI between frames?" "10111": "Consider the movemask instruction" "10186": "You can collapse the 4 bytes into 2 bytes" "10339": "Q: tMin3 will always be the closest in distance to RayOrigin, since RayD that hits BoxMax will result in tBoxMax < tBoxMin, no?" "10380": "Determining the closest hit when rays can be cast in all directions" "10413": "Sketch out RayCast() computing the RayPosition from the ray direction" "10568": "Glimpse into the future optimising the spatial hierarchy stuff" "10620": "Consult the profiler in terms of multithreading" "10661": "Try quadrupling PointsPerWork in ComputeLightPropagation()" "10674": "Consult the threads view to see that there is more empty space now" "10780": "Optimising lane usage when threading" "10914": "Note that we are not measuring dead computation time, and just enjoy our lighting" "10985": "Close down, with one last look at 'Fast, Branchless Ray / Bounding Box Intersections'" "11048": "Glimpse into the future, either continuing with optimisation or investigating the lighting flicker" --- name: "day434" title: "Replacing the Pseudo-random Number Generator" markers: "1": "Recap and set the stage for the day investigating the variance (flicker) in the lighting" "255": "Read through and describe our usage of photons per second in the lighting code" "508": "Make ComputeLightPropagation() consider the approximate location of the moon (i.e. directly up in Z) when applying its colour" "567": "Run the game to see that underside surfaces are black" "610": "Temporarily increase the MoonColor brightness in ComputeLightPropagation()" "619": "See that brighter moon and admire the character of the scene" "762": "Remove the SkyColor, GroundColor and SunDirection from ComputeLightPropagation()" "786": "Transferring light as photons per second" "962": "Complete sample, if sampling every single photon hit by an infinite number of rays" "1179": "Our actual sample, casting 64 rays with temporal antialiasing filtering, and questions to consider" "1831": "Consider explicitly accumulating all lighting points and only averaging at the end" "1992": "Rename Emit to LastPPS and Direction to LastDirection, and add SampleCount in lighting_point_state, to enable ComputeLightPropagation() to accumulate all lighting points directly without doing temporal blending?" "2342": "Run the game to see a totally stable lighting solution" "2442": "Introduce the notion of a fixed LIGHT_TEST_ACCUMULATION_COUNT, to make the light converge over this many iterations of the lighting routine" "2918": "Add a key to toggle the converging lighting accumulation in UpdateAndRenderWorld()" "2967": "Run the game and try toggling the lighting accumulation" "2985": "Enable LightingTest() to map the lighting points back" "3097": "Run the game to try toggling the lighting convergence" "3146": "Make LightingTest() cap the AccumulationCount" "3183": "Run the game to see our "converged" lighting getting brighter, and investigate why" "3323": "Correctly make LightingTest() cap the AccumulationCount" "3336": "Run the game and admire our converged lighting solution" "3397": "56 minutes into the main stream. 50 until Q&A. (based on NOTE)" "3402": "Toggle the lighting accumulation and consider how to address the oscillation" "3592": "Increase LIGHT_TEST_ACCUMULATION_COUNT from 256 to 1024" "3603": "Consider working on the hemisphere sampling" "3735": "Add debug visualisation of the rays in LightingTest()" "4003": "Run the game and check out the debug visualisation of our rays, to see that there is some clumping" "4062": "Determine to improve the random number generation" "4353": "Recommend Melissa O'Neill's PCG" "4619": "Consider the difficulty of performing PCG in SIMD, due to the absence of lane shifting until AVX-512" "4899": "Switch RandomNextUInt32() to perform xorshift" "4999": "Run the game to see an unexpected distribution" "5027": "Make RandomUnilateral() produce up to U32Max points of randomness" "5085": "Run the game to see a more expected, if still slightly clumpy, distribution" "5206": "Excise the old random number table in favour of xorshift" "5235": "Take another look at the random distribution" "5263": "LightingTest()" "5347": "Weighted sampling" "5436": "Start to make LightingTest() perform an inverse square-root mapping" "5499": "Run the game to see a more upward-facing distribution" "5519": "Continue to work on the upward-facing sampling equation in LightingTest()" "5638": "Upward-biased sampling equation" "5666": "Fix the sampling equation in LightingTest()" "5682": "Run the game to see a more fully distributed upward-facing distribution" "5739": "Enable the rays to be randomly cast over time" "5818": "Run the game to see our randomly cast rays" "5842": "Switch our random number generator to operate in SIMD by default, introducing f32_4x versions of << and >>" "6191": "Arithmetic vs logical shifting" "6343": "Introduce ShiftRight4X() and ShiftLeft4X() in lieu of f32_4x shift operators" "6839": "Step through RandomNextU324X() to watch what it does" "7098": "Make RandomNextU324X() perform ShiftLeft4X() inline" "7207": "Step in to RandomNextU324X() and inspect its values" "7247": "Owl of Shame Moment: It wasn't doing a lane-based shift" "7310": "Make ShiftRight4X() and ShiftLeft4X() use _mm_srli_epi32 and _mm_slli_epi32 respectively" "7357": "Step back through RandomNextU324X() to see that its values look reasonable" "7415": "Run the game to see our ray distribution, with unexpectedly flicker-free lighting" "7571": "Make U32_4x() pick the correct slice for RandomSeed()" "7631": "Run the game to see our flicker back" "7723": "Switch all our _mm_set*() calls to be _mm_setr*()" "7759": "Run the game and note the ordering of the _mm_set*() intrinsics" "7856": "Enable RandomBilateral_4x() to operate directly in SIMD, and introduce RandomUnilateral_4x() and U32ToF32()" "8363": "Consider negative and positive numbers in twos complement" "8507": "Continue to implement RandomBilateral_4x()" "8566": "Run the game and consider stopping here for today" "8612": "Q&A" "8640": "Q: Is there a drawback to implementing your f32_4x type as an union between __m18 and __m128i?" "8712": "Q: There is not windows functions for random number generation?" "8751": "Q: You can still try my idea, keep one subray fixed, make 3 random" "8772": "Q: So what does bilaterial vs. unilaterial mean?" "8792": "Q: Doesn't relying on biased sampling instead of angular fall-off means that you could oversample if you use bilateral sampling?" "8814": "Sample distribution" "8938": "Q: Would it be reasonable to seed your PRNG with RNG provided by OS?" "8984": "handmade_hero I'm trying to start from the beginning of Handmade Hero including the Intro to C videos, but you use visual studio 2013 express in it. Is it okay to use visual studio 2017 express windows instead, or are there too many differences and I should use the 2013 version?" "9038": "Q: Can your current implementation of lighting turn a surface into a mirror? Are the sample points too sparse to do that effectively, or does it not really work like that at all? I'm trying to wrap my mind around how it all works" "9087": "Using the "eye" vector to estimate perceived reflectance of surfaces" "9381": "Q: You mentioned a few times that later on during world generation we will do a better job of adding sample points. Are theses sample points limited to static terrain or do you have ideas about how to handle terrain that can be in motion or altered in some other way?" "9437": "Q: What I meant with the question is that if a surface B is nearly above surface A but perpendicular to it, there is a risk of a lot of rays originating from A could hit B and thus contribute a lot even though the angular falloff would prevent that" "9461": "Angular falloff" "9523": "Q: I'm talking about bilateral sampling" "9583": "Actually you're not 100% true in terms of the diagram, but your concept is true. The geometric concept of rays actually breaks down for caves or any cone (it's the infinite reflection problem). Conceptually though you are right. Normal objects are not mirrors. You actually have to use nonlinear optics and a geometric diagram to fully describe the lightening going into a cave" "9658": "Computing reflected light sources around corners" "9796": "You can google The Illumination Problem - Numberphile for a full video on the topic" "10087": "We are good to go" --- name: "day435" title: "Removing the CRT from the Win32 Loader" markers: "6": "Recap and set the stage for the day removing the C Runtime Library" "52": "Read our linker flags in build.bat" "182": "Inspect our executable in depends to see what we're linking with" "474": "Replace the -MTd switch with -MD in our CommonCompilerFlags" "654": "Inspect this executable in depends to see VCRUNTIME140.DLL in there" "840": "NODEFAULTLIB" "912": "Add /NODEFAULTLIB to our 64-bit win32_handmade.cpp compilation line and move -MTd down to there" "1048": "On the trend of compilers to essentially try and force the use of the CRT, and how to get around this" "1160": "Determine which functions from the CRT we need to replace" "1316": "Read 'How to avoid C/C++ runtime on Windows' by mmozeiko on allocating large arrays / structures on stack (>4KB)" "1864": "Add -STACK:0x100000,0x100000, -GS- and -Gs9999999 to our CommonCompilerFlags" "2155": "Grab the function signature of memset() from vcruntime_string.h, and write our own implementation in a new file using #pragma intrinsic" "2796": "Change our memset() to use #pragma function" "2895": "Hunt for _fltused in the CRT" "3057": "Grab the int _fltused from fltused.cpp" "3134": "Find WinMainCRTStartup" "3532": "Pull in the declaration of WinMainCRTStartup" "3722": "Read about the /ENTRY and /SUBSYSTEM flags" "3871": "Add /SUBSYSTEM:windows to our win32_handmade.cpp compilation line" "4075": "Run the game to see that we're running just fine without the CRT" "4105": "Add /NODEFAULTLIB to our handmade.cpp compilation line and compile to see that we are only missing the transcendental mathematics functions, sinf(), cosf() and atan2f()" "4417": "Inspect the asm of cosf() with the determination to write our own" "4554": "Why we did all of this: for sampling the hemisphere" "4613": "Remove /NODEFAULTLIB from our handmade.cpp compilation line for now" "4644": "Read through our hemisphere sampling code in ComputeLightPropagation()" "4708": "Run the game to show our sampling debug visualisation" "4733": "Remove cruft – including EntropyCounter from lighting_solution – from the lighting code" "4856": "Run the game, hit Alt-F4 and note that the game is still running" "4906": "Make WinMainCRTStartup() call ExitProcess()" "4949": "Run the game, hit Alt-F4 and successfully exit out" "4965": "Investigate ceilf() and floorf() from our debug build" "5173": "Crash in ComputeLightPropagation() and consult the asm to try and determine why" "5510": "Realise that threads initialised by us, subsequent to the first one initialised by Windows, were overflowing the stack" "5778": "Make Win32MakeQueue() pass 1 megabyte as dwStackSize to CreateThread()" "5803": "Run the game and try to determine how much stack space ComputeLightPropagation() could need" "6428": "Note that our HitPointIndex is out of bounds, and investigate how" "6628": "Run the game until we crash in ComputeLightPropagation() and try to recover the HitBox and BoxSurfaceIndex information with help from the asm" "7052": "Investigate how BoxSurfaceIndex could get set to 6" "7229": "Assert (unfortunately in the #if 0 code) in RayCast() that Positive == 1 or 0, and that BoxSurfaceIndex is less than 6" "7270": "Run the game until we crash" "7363": "Assert in the correct part of RayCast() that BoxSurfaceIndex is less that 6" "7546": "Run the game, hit the assertion on our third lane, and note that a BoxSurfaceIndex > 5 could be produced if a box has no size" "8170": "Make RayCast() keep a running total of box surface hits in a RunningMask in order to correctly determine the BoxSurfaceIndex()" "9013": "Run the game and try unsuccessfully to trigger our BoxSurfaceIndex assertions" "9152": "Q&A" "9197": "Q: Can we use six separate bits to represent hits with each box wall, then take the highest bit to determine which individual box hit we'll use? (see: _mm_lzcnt_epi32)" "9420": "cmuratori, RETURN THE ORIGINAL DESTINATION!!!!!" "9442": "Make memset() return _Dst" "9501": "Q: Would it be better to make hemisphere sampling visualization as an actual hemisphere with dots rendered on it?" "9526": "Reduce the length of the debug lines in LightingTest()" "9566": "Run the game to see this debug visualisation" "9601": "Make LightingTest() use PushCube() instead" "9726": "Run the game to see the cubes" "9751": "Enable LightingTest() to display a stationary sampling pattern" "9789": "Run the game to see the static debug visualisation" "9846": "Q: Why do you do *(unsigned char*)&_Val instead of (unsigned char)_Val in memset?" "9971": "Q: Off-topic: What harm do you think could happen if you click on that yellow flag to upgrade MSVC? No breaking change has been introduce since this new machine, just lots of compiler upgrades" "10075": "Q: Is the stack size set on the command line for the entire stack or for each stack frame?" "10115": "Q: Another thing to mention when using /stack to get 1MB stack vs 4kb probing, is that all threads also will have this stack size by default. It could be an issue if somebody is creating and keeping hundreds of threads live" "10139": "Q: Also you once said that in your projects you don't include windows.h and other windows-related h-files. How would we go about doing that?" "10189": "Q: I hope this is not too far off-topic. Recently I have thought about a hook-based execution / memory management system. Where when you allocate memory you can tell in the next line when it should be freed. There would be as many hooks as you like, for example: afterFrameHook or levelLoadHook or stuff like this. The hooks internally would be a collection of lambdas so they can capture the address that" "10290": "Q: What are your thoughts on using macro's in C to make writing certain repeated patterns shorter? For example, encapsulating extremely common patterns like: #define DO(f,n) = for(int i = 0;i= 0.01f (i.e. not pointing backwards)" "5808": "Run the game and hit that assert" "5895": "Make ComputeLightPropagation() test for tMin > ZeroF32_4x() when setting tValid" "5923": "See that it looks much better, noting that we got a lot brighter when turning off angular falloff" "6159": "Enable GenerateLightingPattern() to produce an additional unweighted sampling pattern for comparison" "6790": "Introduce TestFunc() for GenerateLightingPattern() to call" "6896": "Step through to GenerateLightingPattern() and inspect our MinTestAvg and MaxTestAvg to see that they differ a lot" "6932": "Fix GenerateLightingPattern() to use F32Min rather than 0.0f" "6947": "Step back through to GenerateLightingPattern() and inspect our MinTestAvg and MaxTestAvg to see that they still differ a lot" "6989": "Enable GenerateWhiteNoiseSamples to produce a biased sampling pattern" "7119": "Step through to GenerateLightingPattern() and inspect our averages to see that they differ differently" "7224": "Q&A" "7295": "Blow's avatar looks exactly like him!" "7345": "Q: Hi, not really an on-topic question, but you said you'd talk about some tidbits concerning the SIMD union type" "7382": "Q: How are you feeling on the progress of the lighting so far?" "7391": "Q: Are there any libraries available that would help with just the lighting stuff you're working on right now? It seems fairly involved and require some R&D from the developer's part" "7403": "Q: Why are you not sure about GPU'ing light? Do you think that it might not increase FPS?" "7489": "Q: What are your dislike on Windows 10? Some people complain about it because of their hatred against Microsoft regardless how good to product is but I feel like they mixed a lot of messy stuff after 8 and 8.1. What are the things you'd like them to fix?" "7641": "Q: How many hours / day are you programming?" "7658": "Q: Do you think we will be able to keep the lighting, at least to this complexity or even method, on the Raspberry Pi?" "7672": "Q: What level are intrinsics defined, are intrinsic CPU vendor specific or architecture specific? Will we/you need to make AMD/Intel specific Intrinsics or x86/x64 ? (or is it defined on a different level?)" "7710": "Q: I understand you switched from AMD to NVIDIA. Any specific reason?" "7729": "Q: how much longer do you expect to spend on lighting?" "7733": "Q: Sorry for an off-topic question, I'm pretty far behind. I'm curious if you have already implemented the swapping function or macro. How would you avoid using templates for this?" "7755": "Using the SIMD union type to issue instructions to particular units" "8245": "Q: What are the specs of your current dev machine?" "8278": "Q: In your opinion, what are low hanging fruits the UNIX / Linux world could or should tackle to become more competitive with Windows, from a usability perspective?" "8462": "Q: Can you explain why you use f32 instead of f64 (double)?" "8516": "Q: Is this something that could cause a stack overflow? Or related to it?" "8544": "Q: Would what you are talking about unions be related to overflow of variables (or "stack overflow") if you did things wrong? I was asking because I was curious what error codes you could look for for this problem" "8642": "Close it down" --- name: "day439" title: "Testing Better Entropy" markers: "1": "Recap and set the stage for the day" "49": "Hemisphere Integration" "758": "Our light reception function" "1029": "Weighted sampling, as a way to optimise out the multiplication of a weighting coefficient" "1758": "Writing the bias into the sampling equation" "1990": "Review GenerateLightingPattern() from last stream" "2039": "Make GenerateLightingPattern() take a much greater number of samples, to try and see if it converges" "2090": "Run the game to see that it takes too long to compute" "2156": "Make GenerateLightingPattern() take not quite that many samples" "2170": "Step in to GenerateLightingPattern() and inspect the test averages" "2209": "Make GenerateLightingPattern() perform fewer tests and take more samples" "2232": "Step in to GenerateLightingPattern() and inspect the test averages" "2243": "Further increase the sample count and lower the test count in GenerateLightingPattern()" "2268": "Step in to GenerateLightingPattern() and inspect the test averages" "2280": "Increase the test count in GenerateLightingPattern()" "2296": "Step in to GenerateLightingPattern() and inspect the test averages, to find that we are starting to converge" "2329": "Consider replacing xorshift with PCG, specifically its notion of k-Dimensional Equidistribution" "2686": "Determine to plot our random sampling points" "2780": "Run the game to see our sample points" "2797": "Enable LightingTest() to draw a random set of sampling points" "2981": "Run the game to see our random sample points" "3033": "Research sphere point picking" "3190": "Implement Marsaglia's method for uniform point picking on a sphere" "3398": "Run the game to check out Marsaglia's sampling" "3432": "Toggle between Marsaglia's method and our full random sampling in LightingTest()" "3484": "Run the game to check out the two sampling patterns" "3527": "Modify Marsaglia's method in LightingTest() to sample only the upper hemisphere" "3592": "Run the game to check out the two hemisphere sampling patterns" "3652": "Introduce random_series_pcg and versions of RandomNextU32(), RandomUnilateral() and RandomBilateral() that take this struct" "4240": "Praise the compiler for figuring out that we'd never pass the check in Marsaglia's sampling routine, thus raising the "unreachable code" warning" "4285": "Determine to enable the random_series_pcg version of RandomNextU32() to perform xorshift" "4776": "Try to check out the example PCG code, but encounter a hang in File Explorer when clicking "New"" "4966": "Read through pcg_basic.c in conjunction with Melissa E. O'Neill's PCG paper and Pierre L'Ecuyer's 'Tables of linear congruential generators' with a view to understanding why the example code uses rng->inc or'd with 1 in the LCG update step" "5408": "Consult Wikipedia's article 'Linear congruential generator' to discover that O'Neill must be using Knuth's LCG style" "5548": "Enable the random_series_pcg version of RandomNextU32() to perform the LCG update step, augmenting random_series_pcg to contain a Selector" "5702": "Introduce RandomSeedPCG() for LightingTest() to use" "5821": "Run the game to see if we get any better random results" "5885": "Fix RandomNextU32() to correctly cast the entire PreRotate computation" "5911": "Run the game to compare the PCG and Xorshift random sampling patterns" "5963": "Make LightingTest() use a different random series for each axis" "6082": "Run the game to determine that the non-PCG random sampling looks fine" "6141": "Q&A" "6182": "Q: You can't have an even number as the Selector because then the 1s-bit would never flip and your period would get cut down a few orders of magnitude. The paper goes over that at some point if I recall correctly" "6210": "Q: In the random series when you write the state part there is a bug: it should be (incr << 1) | 1" "6216": "Fix RandomSeedPCG() to correctly shift the Selector" "6236": "Run the game to see no significant difference" "6315": "Q: The basic PCG32 you're using will only be k-dimensionally equidistributed for simple (u32,u32) tuples. Each u32 will appear 2^32 times within the 2^64 period. You'll need PCG64 or an extension array if you want k-d equi for v3 or more. However, it probably doesn't actually matter for your v3 generation case here, because you're unlikely to actually see the generator loop around. Even at one v3 generated per nanosecond (extremely generous), it'd take ~195 years to see a loop" "6351": "Q: What is your opinion on event systems? And how would you implement one?" "6403": "Q: Is there a way that a slack channel can be set up that way us newbies can catch up and have a place to ask questions as I am finding it hard to keep up with the earlier videos without a lot of side researching" "6441": "Q: What are sampling and for what? Missed out on that part" "6473": "Q: So why opt for a PCG or LCG generator rather than just hashing the time for a random number?" "6557": "handmade_hero An event system for communication between interacting systems" "6590": "Q: In Monte Carlo estimates usually error scales like 1/sqrt(samples). For 1024 samples one expects error of order 0.03 and for 65k one expects error of order 0.003. It therefore seems like the error you're seeing is pretty reasonable, or am I misunderstanding?" "6622": "Q: What would you consider the most performant RNG despite the accuracy?" "6671": "Q: What will you work on tomorrow?" "6735": "Generating blue noise cos(𝜃) distributed sampling points on a disc, for projection up to its hemisphere" "7050": "Q: Can I see the current state of the lighting / game?" "7057": "Show the lighting in the game" "7144": "Q: Is there an intention to support shadows from the point lights?" "7196": "Q: Will there be any raymarching / volumetric fluid stuff?" "7221": "We are out of questions" --- name: "day440" title: "Introduction to Function Approximation with Andrew Bromage" markers: "0": "Welcome to a special episode with Andrew Bromage" "162": "How floating point numbers are represented by a computer" "276": "Scientific notation, and how IEEE 754 represents numbers in binary" "434": "Get Andrew back" "567": "Return" "636": "Continuing IEEE 754's representation of floating point numbers" "980": "Subnormal numbers, the special-case numbers infinity, quiet NaN and signaling NaN, and the quality of being "algebraically closed"" "1450": "Any questions?" "1475": "Is it just a peculiarity of binary as a number system, that you can skip encoding the leading digit?" "1566": "Q: Is there a representation for underflowing numbers?" "1648": "Note the binary and decimal representations of floating point numbers in the IEEE 754 standard" "1671": "Constants definitions in handmade_numerics.h" "1822": "Constants definitions in C's float.h as compared with those in handmade_numerics.h, with a special mention of machine epsilon" "2012": "Describe the IEEEBinary32 union, ieee754_number_category enum and the special-case number functions" "2208": "Describe Real32_Abs(), Real32_SetSign() and CategoryOfReal32()" "2347": "Describe ExtractExponent() as similar to the CRT's frexp() with an example of its use in a sqrt() function" "2856": "When multiplying a subnormal number by a power of two, does the floating point unit first shift the numbers into the normal range before incrementing the exponent?" "3038": "Describe ScaleByExponent()" "3238": "Note the differing range of absolute values of the mantissa in text books (as used in handmade_numerics.h) and the CRT's frexp()" "3421": "Quote James H. Wilkinson on the state of computer arithmetic in 1971" "3510": "Describe SlowDivision(), with emphasis on the sheer amount of specification compliance it contains" "3989": "Walk through an example of SlowDivision(), noting why it uses 11 bits of precision in its application of Horner's rule (IA-32's RCPSS instruction)" "4453": "How SlowDivision() finishes up its computation to the highest precision it can" "4614": "Note the difference between SlowDivision() and how our FPU performs division" "4753": "Calculating those polynomial approximations from SlowDivision(), with range illustrations in Mathematica" "5112": "Relative vs absolute error" "5203": "Plot the error function in Mathematica, with a mention of Chebyshev's Equioscillation theorem and Chebyshev nodes" "5495": "Plot the eighth order Chebyshev polynomial in the range -1 to 1 in Mathematica" "5627": "Using the Remez exchange algorithm to find approximations to Chebyshev's set of polynomials" "5901": "On the initial guesses in the Remez exchange algorithm" "5955": "Plot the ninth order Chebyshev polynomial, for comparison with the eighth order, to explain extrema" "6020": "Struggle with the communication link" "6109": "As the Remez exchange algorithm proceeds, what values does it use as its new guesses?" "6144": "Searching for the extremum, perhaps using golden-section search, as the Remez exchange algorithm proceeds" "6410": "Plot sine in Mathematica, and introduce the computation of sine in the range 0 to 2π" "7003": "Can you set video / audio bit rate on hangouts? If he could lower the bit rate of the video the audio might work better" "7017": "Describe SinCos_TableVersion()" "7111": "Deriving trigonometric identities" "7348": "Calculating cosine around "a", branch-free" "7440": "Point out the experimental SinCos_QuadrantVersion() for SIMD sines and cosines" "7554": "Describe the XSinCosX table look up" "7676": "Counting has always started at zero" "7727": "Continued description of the XSinCosX table look up" "7838": "Run calculate_sincos_tables and explain the result for .5" "7930": "Describe how FindSinCosAround() searches adjacent floating point numbers" "8155": "Could you explain why part of the table version looks up into XSinCosX while the polynomial part is the same no matter where you are in the table?" "8230": "Further explain the table lookups of cos(a) and sin(a) and the sin(e) and cos(e) polynomial approximations" "8386": "Since table lookups are hard in SIMD, what sort of stuff would you end up doing if you couldn't use a table?" "8409": "Describe the experimental SinCos_QuadrantVersion()" "8905": "Q: Why do C0, C2, C4, C6, etc. have more precision than can fit in a float?" "8972": "Describe ATan() and ATan2(), noting the current use of atan2 in Handmade Hero" "9301": "Determine to remove atan2 from Handmade Hero with thanks to Andrew" "9331": "Q&A" "9384": "If the values are denormal, they will run way slower" "9406": "Q: What was the reason we couldn't do two's complement in the exponent?" "9452": "sin and cos" "9692": "Unless you explicitly flush them to zero, they will run super slow" "9764": "Q: Is there a version of this maths source code anywhere, or will it be included in the Handmade Hero project eventually?" "9797": "Note the educational nature of this sine and cosine implementation, with a mention of Cody-Waite reduction" "9943": "Q: Will you go through acos as well in a later stream?" "9970": "What is the guy speaking's username?" "10011": "SSE denormal flushing" "10093": "I can show you some versions that are completely branchless without tables if you are interested" "10145": "Q: Have you done a speed comparison vs the C versions?" "10234": "Re-emphasise the slowness of SlowDivision()" "10375": "Not industrial strength?! Why am I here??" "10395": "Q: To be sure, it means the SIMD intrinsics are not standards-compliant?" "10582": "Quote the Intel 64 and IA-32 Architectures Optimization Reference Manual: "Although x87 supports transcendental instructions, software library implementation of transcendental function can be faster in many cases"" "10624": "Thank you to Andrew for walking us through sine and cosine, with closing thoughts on numerical approximations" --- name: "day441" title: "Never, Ever Update Your Development Tools. Ever." markers: "0": "Welcome to the stream with a brief mention of Visual Studio's installation experience, recalling the time we completed their survey" "271": "Try to install NVIDIA Nsight Graphics" "575": "Try to login to NVIDIA Developer on the dev machine, and debug what's going on with their website" "1173": "Determine that it's a cross-site access problem, and try to run chrome with the --disable-web-security" "1344": "Try to login to NVIDIA Developer with web security disabled, again with no luck" "2314": "Try to login at the URL of the script that handles NVIDIA Developer's login dialog" "2564": "Explain how to successfully log in to NVIDIA Developer" "2624": "Install NVIDIA Nsight Graphics and NVIDIA Display Driver" "3066": "Q: You're blocking cookies!" "3203": "Restart the computer to complete the driver installation, losing the mic audio in the process" "3290": "Re-enable the audio" "3352": "handmade_hero Do you want shader debugging? I think that's only in the Nsight Visual Studio edition, not Nsight Graphics" "3398": "Launch NVIDIA Nsight Graphics, and try to run our program" "3465": "Try to send a crash report to NVIDIA, and encounter a "Connection Error" in the crash reporter" "3538": "Try to make a project in Visual Studio 2017" "3783": "Look at the NVIDIA Nsight Graphics welcome page for a while" "3840": "Q: As far as I know, not have the CRT make it to crash" "3876": "Q: I think you're getting the NVIDIA experience after all" "3884": "Q: Maybe run the profile as an admin?" "3909": "Try to run the game under Nsight Graphics as admin, unsuccessfully" "3946": "Try to compile with the CRT by removing /NODEFAULTLIB from and adding -MTd to our CommonCompilerFlags in build.bat" "4366": "Remove the #include of stdio.h and malloc.h" "4398": "Q&A" "4443": "Q: Try removing handmade_msvc.c from the build as well" "4464": "Try using the WinMain() entry point" "4545": "Try to run the game compiled with the CRT under Nsight Graphics, unsuccessfully" "4566": "Try to send a crash report to NVIDIA, successfully!" "4644": "Q: Do you use anything like metaprogramming to make modern OpenGL more tolerable?" "4656": "Q: What is the editor you use? The simplicity of it appeals to me as someone who used to work on a UNIX terminal back in the day" "4728": "Q: Does it still work with the Visual Studio plugin of Nsight?" "4752": "Try to run the game with the Visual Studio plugin of Nsight" "4940": "Install Nsight Visual Studio Edition" "5236": "Try to run the game with the Visual Studio plugin of Nsight, still unsuccessfully" "5272": "A few words on never updating your development environment" "5312": "There's nothing else to say" --- name: "day442" title: "Getting NSight Working" markers: "1": "Recap and set the stage for the day" "25": "Note that NVIDIA replied to our crash report from the previous stream to let us know that the crash occurred in wglGetProcAddress() inside the old Graphics Driver" "138": "Gather further information for NVIDIA, to affirm that it crashes on Graphics Driver 391.01" "310": "Perform a clean install of the NVIDIA Graphics Driver 391.01" "413": "A few words on the beauty of coffee as a psychoactive drug" "512": "Reboot and lose audio" "619": "afk" "637": "Return to write: "The NVIDIA installer just popped up and said it "couldn't continue" because "other installers were running"??" and wait, apparently in vain, for the installation to proceed" "782": "Try to uninstall everything NVIDIA related: Nsight / Driver / VS Plugin, and reinstall with palpable excitement" "1047": "Request a reminder as to how we got ourselves to a place where "installation" doesn't just mean copying a file onto a drive" "1058": "Confirm our NVIDIA Graphics Driver version and enable the mic" "1076": "Install NVIDIA Nsight Graphics v1.0" "1269": "Launch the game successfully inside Nsight" "1399": "Explore Nsight, noting the plentiful glDraw*() and glBind*() calls reported in the Events View" "1914": "handmade_hero You have to close it in Nsight" "1944": "Can someone summarize how the issue was fixed?" "1966": "Load up the code, run the game and consider how to wrap up the lighting" "2551": "Reacquaint ourselves with our OpenGL code, and specify our goal to recombine a scattered set of lighting samples to shade our scene" "2834": "See if there's any liquid" "2846": "afk" "2854": "Return with liquid and set up our Day number" "2941": "Q: It's 442" "2949": "Interpolating lighting samples across continuous walls" "3148": "Lighting entities like the trees and hero appropriately" "3313": "Distributing a fixed network of lighting points" "3737": "Consider changing SumLight() to operate on a fixed network on lighting points" "3794": "Conceptualising cube lighting vertices vs points for interpolation purposes" "4062": "Run the game to see that we run at ~28ms per frame" "4122": "Prevent LightingTest() from drawing the hemisphere sampling debug visualisation" "4177": "Run the game to see our expected performance difference at different zoom levels" "4224": "Make CompileZBiasProgram hard set the LightCount to 4" "4280": "Run the game to see a little performance improvement" "4304": "Consider regularising CompileZBiasProgram()" "4357": "Packing sampling points in a square chunk of memory" "4438": "Consider how to interpolate square-packed lighting points in CompileZBiasProgram()" "4547": "Sketch out a version of lighting_textures packed as a pair of v3 values" "4862": "Change textured_vertex removing LightCount and Emission and adding UV and LightUV, and propagate the removals" "5311": "Run the game to see nothing different" "5327": "Introduce FetchAndSum() for SumLight() to call with a view to performing UV-based interpolation" "5630": "Run to see no performance problems" "5646": "Consider how to change FetchAndSum() to operate on square-packed lighting points" "5760": "Run the game to double-check that we're okay so far" "5861": "Temporarily pack the lighting_textures in a square chunk of memory for ready fetching" "6006": "Add PackIndex to lighting_point to specify where lighting samples should be packed" "6191": "Run the game to see the same performance" "6214": "Pack the lighting_textures in a square chunk of memory for ready fetching, and propagate this more prescriptive change to OutputLightingTextures() and SplitBox(), considering lofting out the notion of a BaseLightIndex to higher level" "6555": "Revert our recent changes with the determination to figure out how to generate the information as to how lighting sampling points go together" "6616": "Sampling the lighting as faces" "6679": "Q&A" "6719": "Q: Hi Casey! Can you please remind the good people on the stream 1) why templates are bad, 2) what use cases templates can be considered for, which they are good and bad for 3) and what can they be replaced with even then? (I'm gonna take a gander it's METAPROGRAMMING)" "6760": "Q: Has getting Nsight working boosted your morale back and recovered some hope?" "6901": "Q: or are you still moving to Montana" "6903": "Q: Do you have any plans for doing shadows in the game?" "6912": "Run the game to show the shadows" "6961": "Show shadowing irrelevance in the good-looking Horizon: Zero Dawn, and photos of the real world" "7236": "Q: Is the cause over brightness merely a change in the algorithm makes the light brightness value different or is there an actual bug?" "7281": "Q: Will sprites be simply flat-lighted, or do you plan to implement something to give them some kind of fake 3D lighting?" "7296": "Q: How similar is this lighting model to something you would find in other game engines?" "7475": "Q: Why use Nsight in the application for graphics debugging when you already use Visual Studio for CPU code debugging? Why not just use Nsight in Visual Studio?" "7557": "Q: Have you considered baking shadows?" "7586": "Q: Do you think that the number of small draw calls might be causing GPU occupancy issues? Can't remember if we saw occupancy statistics in Nsight" "7628": "Can you show what game looks like now?" "7638": "Show the game" "7800": "Q: Do you plan on having 3D objects for things like gates or doors?" "7829": "Wrap it up with a glimpse into the future of world generation" --- name: "day443" title: "Updating the Player Movement Code" markers: "7": "Recap and set the stage for a few weeks of bouncing around" "196": "Determine to lock down the movement code and make tools to build rooms" "439": "Re-enable the hero in AddPlayer()" "489": "Run the game and traverse our hero around the world a little" "649": "Determine to move from a continuous movement style to a tile-based one" "899": "Re-enable doors in all directions in PlayWorld()" "917": "Run the game to see those bigger rooms" "967": "Introduce ExecuteBrainHero() to handle the Type_brain_hero case from ExecuteBrain()" "1220": "Try out the gamepad controller to see that it happily still works" "1298": "Reacquaint ourselves with the gamepad controller code in ExecuteBrainHero(), encountering the Atan2() call mentioned by Pseudonym73" "1524": "Only permit movement in ExecuteBrainHero() if we have a head and a body" "1804": "Run the game to see the same movement" "1871": "Body Motion" "2127": "Replace the current movement code in ExecuteBrainHero() with the beginnings of a tile-wise, tapped hopping scheme" "2752": "Run the game to see the head's analogue movement" "2796": "Enable ExecuteBrainHero() to initiate hops, with a few words on feel in terms of non-laggy but forgiving input handling" "3050": "Run the game and try hopping, noting the nicety of holding down the key for continuous movement, and consider using a clutch to control dodging" "3428": "A few words on games that proliferate the number of buttons" "3556": "Add ClutchAverage to game_controller_input and enable WinMainCRTStartup() to process the triggers, change the "Add Player" key to VK_RETURN, and use VK_SPACE for the clutch" "4272": "Run the game with the determination to handle dodging using our clutch" "4303": "Enable ExecuteBrainHero() to handle the notion of dodging" "4385": "Run the game and try dodging" "4450": "Enable WinMainCRTStartup() to correctly persist the clutch-key state" "4612": "Run the game and try out clutching with Space, noting that this dodging doesn't feel great on the keyboard" "4812": "Add the Shift keys as clutches in Win32ProcessPendingMessages()" "4931": "Try out the Space and Shift clutching" "4961": "Re-enable stretchy leaning in ExecuteBrainHero()" "5094": "Try out the stretchy leaning" "5203": "Delete extraneous code from ExecuteBrainHero()" "5332": "Traverse the world with Body->dP disabled" "5347": "Toggle on the Body->ddtBob calculation in ExecuteBrainHero()" "5401": "Traverse the world and consider the bounce animation to be fine" "5478": "Introduce the notion of crouch while dodging in ExecuteBrainHero()" "5642": "Run the game and try dodging" "5679": "Enable ExecuteBrainHero() to correctly crouch the head" "5726": "Run the game to see the head crouching while dodging" "5736": "Enable ExecuteBrainHero() to also crouch the body" "5771": "Run the game to see the crouching" "5814": "Reintroduce the springiness if dodging in ExecuteBrainHero()" "5917": "Traverse the world to try out the springiness while dodging" "5973": "Prevent diagonal movement in ExecuteBrainHero()" "6065": "Run the game to try out the cardinal (non-diagonal) movement" "6108": "Q&A" "6162": "Q: Celeron ftw. FailFish?" "6177": "Q: Are you planning on having a jump command?" "6200": "Don't even remember what a Celeron is" "6272": "Q: There were some questions around b32x vs. b32 at some point" "6304": "Q: How about a dive and slide command?" "6321": "Q: Are you planning on implementing a control remapping interface?" "6338": "Q: I know your view on comments but I often see you asking yourself "what was all that about?" when looking at old code. Wouldn't it be beneficial to comment non-obvious stuff?" "6375": "Q: What is the reason of pure C? I think C++'s oop and procedural coverage much better" "6390": "Q: If you don't care how much space a bool is, why not use b8x?" "6434": "Q: Will you eventually make these input commands event driven rather, now that multiple sources of input are being accounted for?" "6465": "handmade_hero What do you think are the disadvantages of C++ compared to C? Isn't C basically a subset of C++?" "6621": "Q: Something I thought of, of coarse it is a gameplay thing totally up to you. You could have the dodge double as an attack or have it push enemies away (or something) in the direction of the dodge" "6649": "Q: Since you interviewed Pat Wyatt in 2015 HandmadeCon, have you ever thought about copying the Guild Wars faux Z-axis configuration?" "6710": "Q: What is happening with C++ templates that shouldn't be? Isn't it just generating code based on the template parameters?" "6826": "Q: What do you think about entity component systems as the engine architecture? How would you implement this if you don't use inheritance?" "6865": "Q: I recently learned about Imperfect Shadow Maps, I wonder if that could be a substitute for raycasting in the current lighting system (at least on the GPU)?" "6954": "400 viewers today. That's a lot more than usual!" "6976": "Q: Even if you don't do network for the game, will you do some lecture about it?" "7162": "Q: What are your current thoughts on jai?" "7209": "Q: With the capabilities of mobile games exponentially increasing, what are the decision factors that result in games being ported to mobile?" "7398": "Q: What are your thoughts on Rust?" "7405": "Q: What was it C was missing that makes you compile using C++?" "7477": "handmade_hero stb doesn't do hinting, is there another lib that supports small text?" "7535": "Q: How many types of enemies are you planning on having?" "7542": "handmade_hero How long have you been coding?" "7559": "handmade_hero Kind of off-topic question but here it goes: I've been in the gamedev industry working with studios, but now I decided to make an independent game of my own, and I kinda want to make a Kickstarter. Do you have any recommendations on that?" "7576": "Wrap it up for today" --- name: "day444" title: "Stubbing Out the World Generator" markers: "6": "Recap and set the stage for the day" "78": "Run the game with a few words on the art, camera and world construction" "482": "Explain the existing world struct" "645": "Introduce world_room stuct" "871": "Camera Behavior per Room" "1036": "Run the game and consider co-op camera behaviour" "1244": "Introduce world_room_camera enum for world_room to contain, and add an array of world_room in world" "1413": "Run the game, noting that a debug visualisation of all generated rooms could be helpful" "1509": "Setup AddStandardRoom() to initialise a WorldRoom" "1910": "Introduce AddWorldRoom(), with a few words on Asserting even on things that we expect to replace before shipping" "2062": "Run the game with the determination to draw debug visualisation for every generated room" "2157": "Make UpdateAndRenderWorld() draw debug visualisation lines around all our generated rooms" "2533": "Run the game to see that we're nearly correct" "2553": "Fix typo in the AddWorldRoom() call in AddStandardRoom()" "2583": "Run the game to see all our room debug visualisation lines, considering switching to infinite far clip-plane" "2702": "Determine to make our current camera code zoom to rooms better" "2823": "Create handmade_world_gen.h for all of our existing world generation code" "3048": "Run the game and crash immediately because there's no world" "3097": "Introduce CreateWorld() for PlayWorld() to call" "3202": "Run the game to see our existing world" "3215": "Determine to build up our world generation code from the usage code backwards" "3358": "Introduce CreateOrphanage()" "3492": "Room" "3663": "Continue to implement CreateOrphanage() calling our fictitious GenRoom() function" "3903": "Room Connectedness, and cycles" "4097": "Add BackDoorPath and SideAlley in CreateOrphanage(), and connect them up in such a way as to create a cycle" "4262": "Introduce the notion of a gen_room_spec for CreateOrphanage() to use" "4567": "Introduce CreateWorld() to call CreateOrphanage() and the currently fictitious Layout(), GenerateWorld() and EndWorldgen(), and gen_orphanage that specifies room connections" "4798": "Reflect on having constructed our API from the usage code backwards" "4951": "Implement our world generation types and functions, with an eye on later differentiating between the world's specification and its generation from that spec" "5305": "Check out our current memory arena allocation code" "5441": "Consider the sheer amount of memory available these days" "5580": "Stub out GenSpec(), GenRoom(), Connect(), BeginWorldGen() and EndWorldgen() with memory management and return values, fixing Clear() to correctly skip the last remaining block" "5948": "Make CreateWorld() call our new CreateWorld() routine" "5988": "Run the game and step through our new CreateWorld(), CreateOrphanage(), etc. routine" "6141": "Close "Bug in Clear(memory_arena *)"" "6177": "Q&A" "6194": "Q: Any thoughts on Mike Acton joining the Unity dev team?" "6375": "Q: Is the parenthesis around the returned value used for debugging or just a habit?" "6488": "Q: Is it a good idea to use events?" "6562": "Q: Are we going to see the new art assets soon now? Today was exciting. I can’t wait for worldgen. Should be interesting" "6573": "Q: Off-topic if you run out of other questions. In C, is there a way to make something similar to function overloading?" "6615": "handmade_hero I read somewhere you can #define return and log all your returns that happen" "6629": "Q: What do you think of Golang?" "6646": "Q: Just as side note on that Nvidia fiasco you had. I found out that in my case I can get Nsight graphics to crash in the same way if I use raw input to get PS4 controller data. As soon as I remove the call that registers raw controllers, Nsight work. Any idea on why that could happen? Maybe Nsight is using something to intercept user input?" "6726": "Q: I know you did a video on interpolation. Do you know of any good resources for cubic B-splines?" "6960": "Bezier curves, and B-spline orders" "7241": "Daisy-chaining Bezier curves to produce more complex curves" "7443": "Orders of discontinuity" "7565": "Cubic B-spline curves" "7686": "Q: I really like the look of the lighting you have implemented. Will the system be working with many light points?" "7721": "Q: So if I am on the same page, if we wanted to make sure that two rooms never touch each other we would still use Connect() plus passing a flag of some kind. Or would you do something else?" "7776": "Q: Are there any plans to write tools to author rooms or will everything be done in code?" "7813": "Wrap it up for today" --- name: "day445" title: "Cleaning Up Entity Creation" markers: "1": "Recap and set the stage for the day, laying out rooms in a constraint- or evaluation-based manner" "432": "Toggle off superfluous test code in GenerateLightingPattern()" "566": "Run the game to see that we load up faster" "589": "Toggle off the existing test world generation code in CreateWorld()" "670": "Begin to implement gen_connection" "796": "The distinction between Database and Winged-Edge Data Structure, with a recommendation to read 'Transaction Processing' by Jim Gray" "1064": "Spec out gen_room_connection as a linked list of connections to a single room" "1204": "Spec out gen_connection itself as a linked list of its two connected rooms, with gen_room_connection as a linked list of these connections" "1330": "Implement this more verbose version, introducing AddConnection() for Connect() to call, and making GenRoom() link up the rooms" "1726": "Implement GenerateWorld(), and GenerateRoom() to do the old work of AddStandardRoom()" "2491": "Make GenerateRoom() call BeginWorldChange() and EndWorldChange(), and begin to systematise the entity system inside the world generator working off a sim_region, respecifying BeginEntity() and EndEntity() as AddEntity() and PlaceEntity()" "3532": "Relieve EndSim() and EndWorldChange() of taking the World, and create handmade_room_gen.cpp" "3736": "Disable transparency compositing in GNOME 3" "3814": "Pull the entity creation code from handmade_world_gen.cpp into handmade_room_gen.cpp" "3984": "Add TempMemory to the world_generator struct for GenerateRoom() to use, and setup the room's position and dimensions for entity simulation purposes" "4545": "Enable AddPlayer() to create a player entity, calling AddEntity() directly on the SimRegion" "4750": "Implement Layout(), initially stamping down rooms in a row" "5143": "Make CreateWorld() initialise the camera position, introducing gen_result struct" "5455": "Run the game to see nothing" "5505": "Step through CreateWorld() into GenerateRoom() and beyond to see what happens" "5779": "Make GenerateRoom() place its camera entity" "6061": "Run the game to see that we're getting further, but have no entities" "6217": "Make UpdateAndRenderWorld() outline the screen, sim region and world sim bounds" "6239": "Run the game to see that the sim region is not in our starting area" "6254": "Enable CreateWorld() to set the StandardRoomDimension" "6337": "Run the game to see our world" "6444": "Introduce gen_volume for gen_room and gen_connection to contain, and specify the geographical location of connections, introducing IsInVolume()" "6811": "Hardcode Layout() to knock out connection holes in the rooms" "6985": "Run the game to see a partial knockout" "7006": "Enable GenerateRoom() to colour the connections" "7141": "Run the game to see the colour" "7162": "Fix GenerateRoom() to enable IsInVolume() to test the correct tiles" "7181": "Run the game to see our full knockouts with working camera" "7260": "Q&A" "7283": "Q: Can you please fix EndWorldgen?" "7296": "Make EndWorldgen() clear the TempMemoryClear()" "7326": "Q: The capitalisation" "7327": "Rename EndWorldgen() to EndWorldGen()" "7341": "handmade_hero What is "internal" used for in C? Is it like the opposite of "extern" in C++?" "7417": "Q: Should the light calculation always be stuck to the camera or something else?" "7490": "Q: By the way in some C++ header there is a definition of internal so your code would not work if any C++ file get included. I'm happy with that, it prevent us from get mad" "7520": "Q: What function is camera using to interpolate between two positions right now? Bezier curve? expf?" "7633": "Q: How much of the world gen can be done in this pass and how much would depend on more gameplay exploration stuff?" "7778": "Q: Why does the color of the room go as it does without lighting, rather than going black?" "7810": "Compare the lighting with and without the moonlight" "7870": "Q: Just want to randomly suggest transactional processing as a topic for some future off-topic stream" "7878": "Q: Will there be specific locations in the world - I saw you mention an orphanage yesterday - and if so how will they be handled in a generated world?" "7905": "Q: How long would it take me to get up to speed on 4coder if I decide to, like, switch off the hell that is emacs?" "8226": "Q: Is there a reason you don't use __forceinline?" "8278": "Q: Can you go over the architecture of how to generate the rooms (like with this generic config) briefly again?" "8324": "cmuratori Streaming Today would be Very Doubtful" "8340": "Q: I think they meant the unlit part. The plain diffuse / albedo bit" "8381": "handmade_hero Can you start optimizing your code as you go or when you reach major milestones, or do you need to wait for near-completion to optimize your code, and make sure you don't have useless coding lines bulking up?" "8601": "Q: Maybe something for next week, but can you make the boundary wall heights equal?" "8613": "Close out" --- name: "day446" title: "Generating Possible Room Volumes" markers: "2": "Recap and set the stage for the day generating possible room volumes" "112": "Describe our current world layout code in CreateOrphanage() with a note that we are using an undirected graph" "255": "Run the game to show our current world" "303": "A few words on starting to devise solutions and to open black boxes" "445": "Inter-room Layout" "569": "Dynamically resizable rooms" "759": "Recall dad's work at DEC around the time of the DEC Alpha, chip layout, and "rip up and replace"" "1127": "Speculative layout, and the notion of starting off with a totally brute force solution, before trying to reduce the search space of that solution" "1590": "Setup to tackle our layout problem with an eye toward impermanence" "1741": "Specify our world generation rules for Layout() to follow" "1907": "Introduce gen_room_stack for Layout() to use, with a few words on the use of the compiler's vs our own stack management by recursive functions" "2730": "Introduce GetOtherRoom() for Layout() to call" "2992": "Determine to enable Layout() to figure out where to place and connect rooms in a trial-and-error fashion, with four connections per room, connecting two rooms after both are placed" "3250": "Continue enabling Layout() to place and connect rooms in separate passes, introducing PushConnectedRooms()" "3628": "Enumerating shapes of rooms that satisfy connections" "4226": "Union and intersection" "4568": "Determining the largest rectangle that touches other rectangles in our union" "4782": "Metropolis–Hastings algorithm" "5128": "The problem of stably iterating over multiple, changeable brute force possibilities" "5202": "Enable Layout() to unionise our rooms, clipping that union to the largest spaces to accommodate a connecting room and placing a room there using PlaceRoom()" "5314": "“I also kind of want to do a grow operation on this here, and not the kind where the feds come because you're using U.V. lights”" "5326": "Enable Layout() to expand the volume by an apron" "5962": "Minimum / maximum bounding rectangle room requirements to satisfy connections" "6203": "Remove the union gathering phase from Layout(), in favour of room clipping based on the dimensions stored in gen_volume, introducing IsMinimumDimensionsForRoom()" "7064": "Constraining our possible room placements" "7160": "Enable PlaceRoom() to clip our rooms in all dimensions" "7729": "Introduce InfinityVolume() containing the whole world for Layout() to call before PlaceRoom() clips out our desired region" "8077": "Introduce GetMaximumVolumeFor(), and consider using a room spec to constrain our dimensions" "8285": "Min / Max Intervals for Reasonable Length Picking" "8525": "Enable PlaceRoom() to pick reasonable room dimensions" "8929": "#if 0 most of today's code, with a view to getting the existing code to work with our newly formulated notion of parameterised room volumes" "9246": "Run the game to see that all is okay" "9274": "Q&A" "9320": "Q: I think one of your >= should be <=, also some < to >, around line 180, 190-ish, I think..." "9520": "Fix PlaceRoom() to correctly clip our new room" "9702": "Q: Why you did not place important rooms randomly, then generate more rooms to join them? This seems more efficient than generating all the rooms upfront before placing them" "9885": "Wrap it up" --- name: "day447" title: "Placing Adjacent Rooms" markers: "0": "Recap and set the stage for the day continuing on procedural generation of level layout" "107": "#if 1 our half-written layout code from yesterday, and implement PushRoom() and PopRoom()" "756": "Fix up typos in PlaceRoom() and implement CanBeDirection() and HasEntries()" "992": "Create handmade_box.h to contain a new box_surface_mask as a generalised box directional mask based on the existing GetBoxSurface() from the lighting system, for CanBeDirection() also to use" "2109": "Enable Connect() and CanBeDirection() to use the box_surface_mask to connect rooms" "2377": "Introduce GetBoxMaskComplement()" "2644": "Rename CanBeDirection() to CouldGoDirection(), and make it flip the incoming mask using GetBoxMaskComplement() if it isn't the mask of Connection->B" "2810": "Introduce PlaceRoomInVolume() for Layout() to call, in order to special-case the placement of the first room" "3130": "Augment gen_room with a RoomName string to aid debugging, and #define two versions of GenRoom() for release and debug builds" "3364": "Step through Layout() to see that the Stack wasn't correctly built" "3442": "Fix PushConnectedRooms() to push the correct room" "3468": "Step back into Layout() to see what happens" "3745": "Introduce GetSurfaceMask() for CouldGoDirection() to call" "3825": "Jump back into CouldGoDirection() and through PlaceRoom()" "3891": "Fix PlaceRoom() to clip the rooms to the correct dimensions" "4009": "Continue to step through PlaceRoom() to see how it works" "4128": "Make Layout() set the FirstRoom to one unit high" "4156": "Continue to step through PlaceRoom() into IsMinimumDimensionsForRoom(), to see that it may overflow" "4266": "Make InfinityVolume() produce a smaller volume to avoid overflowing signed int, and IsMinimumDimensionsForRoom() compute the dimensions individually for ease of inspection" "4345": "Step in to IsMinimumDimensionsForRoom() and inspect its values to consider that PlaceRoom() may be clipping the room incorrectly" "4583": "Make InfinityVolume() cast its computed min dimensions to signed integers" "4620": "Step into InfinityVolume() to see that the Min dimensions now correctly remain negative" "4625": "Force S32Min and S32Max to be signed integers" "4661": "Continue to step through PlaceRoom()" "4696": "Enable PlaceRoom() to keep chaining up rooms for every room connection" "4820": "Continue to step through PlaceRoom() to see that the room clipping is incorrect" "4949": "Make PlaceRoom() more correctly clip and handle rooms that cannot be placed, introducing InvertedInfinityVolume()" "5367": "Step into PlaceRoom() to see that MinVol.MaxZ may be off by 1" "5816": "Make PlaceRoom() consistently clip the new room's Min and Max dimensions such that it exactly abuts the other room or the interior apron, introducing ClipMin() and ClipMax()" "7333": "Overlapping rooms" "7528": "Continue to make PlaceRoom() correctly clip to the interior apron" "7691": "Step into PlaceRoom() to see what it produces" "7743": "Prevent PlaceRoom() from expanding the InteriorApron in Z" "7755": "Step back into PlaceRoom() to see that the dimensions are looking more sane" "7834": "Make PlaceRoom() offset both the other dimensions only by the interior apron (i.e. without a further +/- 1 offset)" "8075": "Step in to PlaceRoom() to determine that the clipping should actually be asymmetric" "8099": "Make PlaceRoom() offset the other max dimension by 1" "8110": "Step in to PlaceRoom() to determine that this room is correctly placed" "8143": "Take a look at our world" "8172": "Simplify CreateOrphanage() to only create two adjoining rooms" "8276": "Step through Layout() to see how it places our two rooms" "8418": "Make PlaceRoom() leave the loops" "8502": "Run the game to see our two placed rooms" "8557": "Fix PlaceRoom() to exactly abut the rooms" "8675": "Run the game to see that the rooms abut" "8687": "Increase the InteriorApron in PlaceRoom()" "8694": "Check out our room abutment with more space" "8705": "Reduce the maximum room size" "8717": "Check out the smaller rooms" "8798": "Enable PlaceRoom() to knock out the entire abutment of adjoining rooms, introducing Union() and Intersect()" "9293": "Run the game to see that we knocked it out backwards" "9314": "Fix PlaceRoom() to correctly position the door" "9345": "Run the game and traverse between the rooms" "9404": "Q&A" "9497": "Q: Would nomenclature like: Low / High / Width be helpful?" "9516": "Q: Would using a range of low values and a range of high values for dimensions be easier than having two volumes?" "9534": "Q: Why are you appending 'x' to some of the types?" "9615": "Q: Didn't you want to avoid recursion?" "9706": "Q: Could the hero walk outside the rooms in this setup (in the gray / void zone)?" "9770": "Q: Low can be between -30 and 5, and high can be between -4 and 20. As opposed to a min volume of -4 and 5 and a max volume of -30 and 20. (In one dimension). Makes it easier to fit in my brain, at least" "9828": "Q: Do you think that languages that interact with the GPU directly (like Nvidia's CUDA or AMD HIP) would be useful for game programming?" "9904": "Q: (Off-topic) Do you miss some features that exist in C but are absent in C++?" "9991": "Q: Thoughts on DXR?" "9998": "Q: will you ever get back to the nicely aligned grass / rocks bitmaps, map them over the current tiles maybe?" "10051": "Q: Sorry, I could not exactly follow, but can you guess at what makes the interval computations tiresome?" "10289": "Q: Do you feel it'd be worth it to abstract away subsystems (input, audio, lifecycle) with an Event system?" "10318": "Q: Can we try all the rooms now?" "10328": "Let CreateOrphanage() try and create the whole building" "10362": "Run the game to show that it's always connecting rooms at the further side, and will inevitably fail when it would need to connect along another side" "10477": "Q: Have you ever made a visualization tool for working stuff like this out? (I'm thinking of something like live-code-editing combined with showing values on screen and lerping between previous and new values showing how the changes affect the scene when the code reloads.)" "10502": "Q: Also, after all of this code on rendering and this, is code reloading still working?" "10542": "Demonstrate the hot code reloading by making LightingTest() return immediately" "10619": "Q: Are you doing custom memory management?" "10688": "Wrap it up" --- name: "day448" title: "Explicitly Placed Room Connections" markers: "5": "Recap and set the stage for the day manually laying out rooms to nail down the room placement API" "149": "Describe our conceptualisation of min / max in gen_volume" "257": "Fill Rules for Tile Maps" "693": "Correctly picking our fill rules" "886": "Consider the clipping asymmetry in PlaceRoom()" "1064": "Compare our room placement with and without the +1 minimum apron clipping" "1096": "Redefine Min and Max from gen_volume to include their bounds, introducing gen_point struct and GetDim() for IsMinimumDimensionsForRoom() to call" "1961": "Make GenerateRoom() and IsInVolume() obey the new fill rule, pulling the room generation code out into handmade_gen_math.h and .cpp" "2355": "Fix up PlaceRoom() to obey our new fill rule" "2567": "Step in to PlaceRoomInVolume() to see what it produces" "2625": "Make Layout() obey the fill rule for the initial room placement" "2677": "Step in to GenerateRoom(), then see that the world is correctly created" "2771": "Orphanage Architecture" "3059": "Setup CreateOrphanage() to explicitly connect rooms" "3186": "Articulating connections around a room" "3258": "Determine to introduce an extended version of Connect()" "3340": "Refined Orphanage Architecture" "3451": "Make CreateOrphanage() connect our rooms as per the diagram" "3617": "Rearticulating connections as Y-low to Y-high (not counterclockwise)" "3757": "Continue to make CreateOrphanage() connect our rooms" "3885": "Consider prescribing the size of our rooms" "3984": "Introduce SetSize() for CreateOrphanage() to call explicitly on all our rooms" "4257": "Implement a version of Connect() that connects A explicitly to B" "4427": "Implement SetSize(), augmenting gen_room to contain a gen_v3 RequiredDim" "4766": "Determine to rewrite Layout() such that we can place adjoining rooms" "4944": "Enable Layout() to place all unplaced neighbouring rooms, introducing PlaceRoomsAlongEdge() and GetDirectionForRoom()" "5573": "Implement GetDirectionForRoom() for CouldGoDirection() to call" "5723": "Implement PlaceRoomsAlongEdge(), introducing GetBoxIndexFromDirMask() and a version of CouldGoDirection() that takes a TestMask instead of Dim and Side" "6517": "Aligning rooms to the min and max edges" "6578": "Enable PlaceRoomsAlongEdge() to align rooms to the min and max edges" "7004": "Run the game and hit an assertion in GetOtherRoom()" "7104": "Fix up a Connect() call in CreateOrphanage()" "7116": "Run the game and hit our assertion in PlaceRoomsAlongEdge()" "7183": "Remove that invalid assertion from PlaceRoomsAlongEdge()" "7200": "Run the game to see that it does run properly" "7227": "Q&A" "7253": "Q: Your edge axis is wrong. It gives the direction of the connection, not the axis the connected rooms should align to" "7325": "Fix PlaceRoomsAlongEdge() to correctly set the EdgeAxis and AxisA" "7409": "Q: Can the connection be fashion in such a way it forms a long empty corridor / stair up or down to connect two rooms?" "7434": "Q: You mentioned a few streams ago that the xbox 360 controller has a crap potentiometer. Do you have an example of a controller with a good one?" "7464": "Q: Have you thought to use a constraint solver algo for room layout?" "7481": "Q: Can the Hero have the ability to "Dig" the ground and fall through the floor to the room below it?" "7526": "Wrap it up" --- name: "day449" title: "Preventing Overlapping Rooms" markers: "0": "Recap and set the stage for the day continuing with room layout" "45": "Run the game to show our strange situation with the camera placement" "99": "Enable CreateWorld() to set a sane initial camera position" "264": "Run the game to see the camera oddly positioned" "313": "Step in to CreateWorld() to inspect the camera and room data" "469": "Step in to GenerateRoom() to inspect its values" "546": "Fix Layout() to not include the bounding edges in the volume dimensions" "641": "Run the game to see that our camera is now correctly initialised" "669": "TODO(casey): Fix 2-high room bug - camera seems to get confused" "705": "Check out our orphanage, and determine to implement the doors" "806": "Make PlaceRoomsAlongEdge() knock out the entire wall between connecting rooms" "954": "Run the game to see that we actually don't overlap our rooms in this placement scheme" "1002": "Determine to make PlaceRoomsAlongEdge() expand the door dimensions into each room" "1177": "Step in to PlaceRoomsAlongEdge() and inspect MinDoor and MaxDoor" "1299": "Make PlaceRoomsAlongEdge() flip the door's Min and Max dimensions along the axis pointing to the adjoining room" "1321": "Run the game to see that the door placement is almost there" "1340": "Fix typo in PlaceRoomsAlongEdge()" "1379": "Hop around the world and consider fixing the camera and lighting once the world generation is done enough" "1494": "Make PlaceRoomsAlongEdge() constrain the door width to 1 unit wide" "1617": "Run the game and consider tweaking the eccentricity of the perspective projection" "1684": "Adjust the camera focal length and zoom in UpdateAndRenderWorld() and UpdateCameraForEntityMovement()" "1887": "Run the game and note the reduced eccentricity of the perspective projection, with a few thoughts on the camera in The Binding of Isaac and Hotline Miami" "2012": "Determine to get things up to a playable state, generating more stuff, and making a separately moveable debug camera" "2160": "Make CreateWorld() create multiple orphanages, and Layout() to take an initial room" "2302": "Run the game to see some Z-fighting, and determine to make the layout code check for overlap" "2438": "Make CreateWorld() call Connect() on the orphanages" "2484": "Run the game and walk between our two orphanages" "2559": "Make CreateOrphanage() create smaller rooms" "2599": "Run the game to see that the camera correctly handles traversal between the orphanages" "2656": "Make CreateWorld() create 64 orphanages all chained together" "2745": "Run the game to see that our debug system runs out of space for the timings" "2776": "Remove TIMED_FUNCTION() calls pertaining to simulation regions" "2840": "Traverse the world, with a few words on structuring our code to ease procedural generation" "2961": "Note the low loading time of our game considering its anticipated length" "3066": "Remove TIMED_FUNCTION() from BeginTicketMutex()" "3084": "Note that our high entity count does not affect our performance" "3214": "Step in to the game and inspect the LastUsedEntityStorageIndex" "3281": "Make CreateWorld() create 1024 orphanages" "3329": "Disable HANDMADE_INTERNAL and redefine DEBUG_STRING and HUD_TIMED_FUNCTION to do nothing in this mode" "3370": "Run the game in release mode and inspect the LastUsedEntityStorageIndex, noting that it is computationally free to have many entities" "3519": "Increase the world_room array size in the world struct by × 4" "3549": "Run the game one last time with this large world" "3606": "Restrict CreateWorld() to create a single orphanage" "3625": "Determine to address the room overlapping bug" "3849": "Consider augmenting the world struct with a two-tiered representation of the world at both entity- and room-granularity" "4097": "Setup PlaceRoomsAlongEdge() for overlap testing before room placement" "4237": "Highly recommend Milton" "4329": "Edge Subscription" "4544": "Directed Search vs Blind Search" "4761": "Introduce a TestVol in PlaceRoomsAlongEdge()" "4972": "Consider that we may have hit a 4coder bug" "5116": "Continue setting up PlaceRoomsAlongEdge() for overlap testing" "5198": "Overlap testing each room from the start of the placement edge" "5283": "Coffee at Molly Rocket and in indie development in general" "5416": "Finish setting up PlaceRoomsAlongEdge() for overlap testing, introducing GetDeltaAlongAxisForCleanPlacement()" "5665": "Run the game to see all connected rooms placed on top of each other" "5679": "Don the pig hat with a few words on working on one thing at a time" "5797": "Enable GetDeltaAlongAxisForCleanPlacement() to perform overlap testing and clean room placement" "6035": "Run the game and crash in PlaceRoomsAlongEdge()" "6085": "Prevent GetDeltaAlongAxisForCleanPlacement() from considering unplaced rooms" "6115": "Step through PlaceRoomsAlongEdge()" "6138": "Fix PlaceRoomsAlongEdge() to correctly loop over the edges" "6159": "Run it to see that the room placement is all totally correct" "6233": "Q&A" "6265": "Q: Do you plan on making an in-game editor similar to the one in The Witness?" "6319": "Q: The "4coder bug" was not a bug, it was a missing ']'" "6327": "Insert a ']' in PlaceRoomsAlongEdge() (not a 4coder bug)" "6346": "Q: How can I earn a piggy hat for myself?" "6403": "Q: I think I know the answer to this question, but do you know of some simple preprocessor library that has iteration as a feature? I really don't want to write my own at the moment" "6623": "Q: Hello sir. I just started creating my first game using SDL in C++. Can you give me some advice? Am I going the right way or I should change my tools? Plus, I'm looking for a game programming book. Do you know a good one to start with? (I worked a little with Unity3D)" "6897": "Q: The current generator always creates two-tile wide walls when rooms are adjacent. Will you leave it like this because it's easier to include the walls inside the room volume? Would you take the same approach if the tile size were not tied to the traversable size, which would allow for thinner walls, for example?" "6986": "Q: libclang can parse your code and give you the AST. It's a simple C interface" "6998": "Q: Can you show the game? Just fell asleep and missed all of the coding" "7004": "Run the game to show the orphanage layout" "7031": "Q: What to do if CS course enforces OOP?" "7348": "Q: What do you think about Lua and Love2D?" "7355": "handmade_hero What paradigm do you use instead of OOP?" "7369": "Q: The problem is that understanding why OOP is really bad probably requires 5+ years of experience, because it takes that long to be able to build sufficiently complex programs such that you know what "should" be easy, or which complications are unnecessary" "7418": "On the problem with languages whose design philosophy is divorced from the computer" "7662": "Close down" --- name: "day450" title: "Supporting All Room Connection Directions" markers: "0": "Recap and set the stage for the day" "38": "Demo the limitations of a) the current simulation code affecting the lighting, and b) the camera code" "156": "Determine to exercise the world generation code and add a more manoeuvrable debug camera" "332": "Consider the functional nature of our code, and thoughtful randomisation" "643": "Introduce CreateDungeon() and CreateForest()" "1304": "Enable CreateDungeon() to create each floor's random batch of rooms" "1866": "Consider encoding connections between families of rooms for the layout code to deal with" "2131": "Enable CreateDungeon() to create all the paths between rooms and special Shop and Item rooms" "2700": "Stub out CreateForest(), move RequiredDim from gen_room to gen_room_spec, and propagate this change" "3028": "Run the game to see our orphanage" "3034": "Make CreateDungeon() set the dungeon size, and CreateWorld() to call it" "3218": "Run the game and hit our assertion in GetBoxIndexFromDirMask()" "3251": "Rename PlaceRoomsAlongEdge() to PlaceRoomAlongEdge() and make it explicitly take a Connection and SurfaceIndex" "3488": "Run the game to see our same orphanage" "3497": "Make PlaceRoomAlongEdge() return whether or not it placed a room, for Layout() to call it multiple times on different surface indices" "3754": "Rip up and replace, having backed ourselves into a corner while picking rooms" "3866": "Enable Layout() to call PlaceRoomAlongEdge() multiple times on all directions, introducing GetRandomDirectionFromMask()" "4229": "Run the game to see that our existing orphanage gets generated" "4266": "Make CreateWorld() call CreateDungeon()" "4278": "Run the game and hit the assertion in PlaceRoomAlongEdge() because the GenerationIndex was erroneously set" "4303": "Fix Layout() to only set the GenerationIndex if the room was indeed placed" "4361": "Run the game and hit the assertion in PlaceRoomAlongEdge() because we don't support up / down connections" "4381": "Temporarily restrict CreateDungeon() to only create one floor" "4410": "Run the game and hop around our dungeon" "4450": "Consider how to handle up / down connections" "4700": "Enable PlaceRoomAlongEdge() to handle up / down connections, allowing them to occur anywhere on a floor" "5857": "Switch CreateDungeon() back to only create one floor, and CreateWorld() to call CreateOrphanage()" "5934": "Run the game, crash in Layout() and step through PlaceRoomAlongEdge() to see what it does" "6071": "Make PlaceRoomAlongEdge() test the TestVol in Y up to and including the MaxRelY" "6113": "Continue to step through PlaceRoomAlongEdge()" "6164": "Switch back to -O2 and see that the orphanage is correctly generated" "6184": "Switch CreateWorld() to call CreateDungeon() and determine that it works for up to four floors" "6310": "Make UpdateAndRenderWorld() set the far clip plane proportional to the target distance" "6388": "Run the game to see our whole dungeon" "6406": "Make CreateWorld() create both the Dungeon and Orphanage" "6499": "Further increase the FarClipPlane in UpdateAndRenderWorld()" "6523": "Run the game to see our whole world, and consider labelling the rooms" "6730": "Q&A" "6797": "Q: How do you decide whether to include a library in your project or not?" "6809": "Q: Who builds a dungeon under an orphanage?!" "6841": "Q: What are you listening to?" "6862": "Q: What's the InvalidDefault thing in your switch statement?" "6927": "Q: Are you wearing headphones because you want to hear the visual studio error sounds?" "6947": "Q: How do you keep the motivation to continue working on Handmade Hero?" "7082": "Q: So I'm guessing the layout system still will not handle cyclical connections nicely, or do you think it could now?" "7104": "Q: Can you do a brief overview of all the parts that are involved in generating the world? I lost the thread" "7348": "handmade_hero Are you working on other stuff parallel to Handmade Hero?" "7365": "Q: Just caught up and watched the stream for the first time live today. Wanted to say thanks for the amazing learning resource. You've made me a better programmer than college or university ever could" "7383": "Q: Have you decided how many levels the world will have in the end?" "7537": "Q: The current system doesn't handle adding a rotated or mirrored orphanage, right?" "7647": "Q: At the moment the gen_rooms are all created by hand, correct? Are you going to use some sort of logic to generate them? If yes, what do you have in mind?" "7732": "Q: Have you worked on procedurally generated worlds similar to this before?" "7807": "Wrap it up, with a glimpse into the future cleaning up the camera code" --- name: "day451" title: "Updating Unproject" markers: "0": "Recap and set the stage for the day" "63": "A few words on art, originally produced remotely by Yangtian Li, and then produced in-house by Anna Rettberg" "275": "Run the game to see what on-demand, in-house art production would entail" "427": "Determine to focus on the camera for starters, then the lighting bounds" "574": "Consider the current LightBounds code" "629": "Increase the LightBounds, running the game to illustrate the need to move to a camera-centric lighting bounds" "724": "Make UpdateAndRenderWorld() draw the LightBounds" "900": "Run the game to see the light bounds" "918": "Make UpdateAndRenderWorld() draw the WorldCameraRect" "1004": "Run the game to see that WorldCameraRect, and determine to fix its computation to encompass the screen" "1064": "Determine to validate Unproject() for GetCameraRectangleAtDistance() to produce a correct WorldCameraRect" "1213": "Make GetCameraRectangleAtTarget() take a Z, and try dynamically changing the TargetOffsetZ in UpdateCameraForEntityMovement()" "1539": "Run the game to see that camera move" "1549": "Make UpdateAndRenderWorld() pass Camera.OffsetZ to GetCameraRectangleAtTarget()" "1609": "Run the game and determine to fix WorldCameraRect to encompass the screen" "1624": "Work towards making the WorldCameraRect encompass the screen, considering how Unproject() works" "2046": "Step in to GetCameraRectangleAtTarget() to see our camera projection" "2377": "Closely consider Unproject()" "2810": "Step in to Unproject() to see that the Proj combines the world camera transform and the projection matrix" "2933": "Continue to nail down our understanding of Unproject()" "3005": "Step in to Unproject() and consider that its ClipZ computation may be erroneous, thus throwing off the Clip" "3327": "Fix the computation of ClipZ and ClipSpaceXY in Unproject()" "3399": "Run the game and fail to see our WorldCameraRect debug visualisation, but that the ScreenBounds is now correct" "3606": "Step in to GetCameraRectangleAtDistance() to investigate the camera's dramatic Z offset" "3760": "Let Unproject() divide the ProbeZ.w in to ClipZ again" "3818": "Run the game to see that the WorldCameraRect now matches the ScreenBounds" "3844": "Read PerspectiveProjection() to confirm that the Z was multiplied in to the W" "4001": "Run the game to see the WorldCameraRect move with the hero, and determine to make it slide with the camera" "4043": "Consider how UpdateAndRenderWorld() is using the camera transform, with a view to making the WorldCameraRect slide rather than jump" "4418": "Step in to UpdateAndRenderWorld() to see exactly how the debug visualisation is being drawn" "4561": "Hit a crash in DEBUGEnd()" "4582": "Make DEBUGEnd() use SafeRatio0() in the AvgKilocycles computation" "4632": "Note that the WorldCameraRect is sliding subtly, but not actually with the camera" "4727": "Continue to investigate why the WorldCameraRect seems to be tied to the sim center, and not sliding with the camera" "5221": "Consider that our camera's identity matrix may not have its offset set correctly" "5309": "Step in to SetCameraTransform() to see that the camera's identity matrix actually does look good" "5454": "Break on SetCameraTransform() when moving between rooms to see that the camera's identity matrix remains looking good" "5521": "Break on SetCameraTransform() during a big camera move to see that the DeltaFromSim displacement is initially lower that expected" "5785": "Display the DeltaFromSim" "5817": "Run the game and watch that DeltaFromSim value to see that it looks fine" "5882": "Consider if Unproject() is not correctly applying the camera displacement" "6006": "Realise that Transform() is multiplying the w in to the displacement, and make Unproject() use the ProbeZ.w in the Clip computation" "6124": "Run the game to see that we're not quite out of the woods yet" "6141": "Make Unproject() use ProbeZ.z directly (not divided by ProbeZ.w) in the Clip computation" "6207": "Run the game to see the WorldCameraRect properly slides with the camera" "6244": "Make UpdateAndRenderWorld() set the LightBounds from our WorldCameraRect, adjusted by the SimBounds Z" "6261": "Run the game to see that our lighting is never wrong" "6301": "Q&A" "6360": "Q: How would you obfuscate what's outside of the view of the character?" "6506": "Q: Do you plan to close the orphanage's rooms or do you want them to have the skylight as some sort of ambient light?" "6527": "Q: Does the UpdateAndRender() function do any rendering right now? Or was it offloaded to some other place?" "6562": "Q: Would you for example cast rays to see if something is visible to the character (e.g. if something is on the screen but the character should be blind to it)?" "6659": "Q: Would Handmade Hero's chunk->offset world work in 3D? Would there be any problems there that I'm not seeing?" "6680": "Q: Is there already new artwork to be put in the game in the next couple of episodes?" "6717": "Consider the problem of dealing with perspective in the art" "6819": "Q: Is it currently possible to easily customize rooms, e.g. with non-random tile-z, etc?" "6845": "Q: Sorry, I mean, say we wanted to make a universe-scale game, i.e. space sim. Would that scale well?" "7266": "Q: Would these massive distances even be needed if you don't need to be accurate to, say, the nearest centimetre? Or do you always need to be that accurate?" "7525": "Q: Would separating chunks into chunks in this case be overkill?" "7631": "Q: In this hypothetical situation, I suppose you could also change the physics / realism of the universe so that planets and galaxies are closer than they would normally be so flying to them is more feasible" "7721": "Q: Do you have to always take float precision into account or is it more like an "it will come up" type of thing (like the rock that didn't move on The Witness editor)?" "7751": "Q: Does the rather nice state of the anti-aliasing in Handmade Hero have to do with the use of depth peeling or is it just standard MSAA?" "7784": "Q: How do you tackle this issue in a large open world then? Do you use some sort of grid system?" "7932": "Q: Follow-up: What benefit does depth peeling bring to the anti-aliasing table? (Not that you're doing depth peeling for that purpose, obviously)" "8026": "Close it up, with a glimpse into the future of working on the camera motion and introducing the new art" --- name: "day452" title: "Improving Camera Placement and Room Alignment" markers: "0": "Recap and set the stage for the day" "90": "Run the game with the determination to position and zoom the camera to focus on a given rectangle, and retain the simulation region until the camera transitions are complete" "459": "Make UpdateAndRenderWorld() merge the camera bounds into the simulation region" "522": "Run the game to still see entities drop out of the simulation region" "545": "Enlarge the SimBounds in UpdateAndRenderWorld()" "600": "Run the game and no longer see entities drop out of the simulation region" "649": "Note the risks to allowing the simulation region to be determined by the camera" "973": "Run the game and set up to implement our dynamically zooming camera" "1312": "Determine to hand-code camera zoom levels per room" "1404": "Work towards enabling UpdateCameraForEntityMovement() to set the TargetOffsetZ from the stored CameraOffset.z" "1581": "Run the game to see nothing" "1606": "Make GenerateRoom() initialise the CameraOffset.z to 16" "1641": "Run the game to see our usual camera view" "1657": "Introduce GetCameraOffsetZForDim() to dynamically zoom the camera" "2083": "Make UpdateAndRenderWorld() write out the Camera.OffsetZ" "2123": "Run the game and watch that Camera.OffsetZ change while traversing the orphanage" "2290": "Determine to fix the camera's room selection bug" "2409": "Make UpdateAndRenderEntities() draw the room boundaries" "2468": "Run the game to see those room boundaries" "2503": "Fix GenerateRoom() to correctly align the collision volumes of both even- and odd-sized rooms, removing the world_room_camera struct and making ChunkPositionFromTilePosition() take a world_generator that contains the TileDim" "3303": "Run the game to see that the room alignment is off-by-one" "3331": "Fix GenerateRoom() to correctly align the room collision volumes" "3346": "Run the game to see that the rooms are correctly aligned in X and Y, and consider how to align them in Z" "3432": "Temporarily prevent ChunkPositionFromTilePosition() from offsetting the room collision volumes in Z" "3481": "Run the game to see how this change aligns the rooms" "3541": "Make GenerateRoom() compute the RoomCenter along all axes" "3711": "Step in to GenerateRoom() to see that MakeSimpleGroundedCollision() may be busted" "3808": "Change GenerateRoom() to align the room collision volumes using MapIntoSimSpace() renamed from GetSimRelativePosition()" "4077": "Run the game to see how our rooms are now aligned, and consider peeking into rooms" "4340": "Introduce AddLamp() for GenerateRoom() to call and add a lamp to every room" "4564": "Run the game to see the bright lights" "4603": "Prevent UpdateAndRenderWorld() from adding a light at the hero's location" "4621": "Run the game to see our unlit hero" "4651": "Reduce the lamp brightness in GenerateRoom()" "4666": "Run the game to see our dimmer lights" "4693": "Make AddLamp() reposition the lamps, and GenerateRoom() generate them in the four corners of the rooms" "5006": "Run the game to see our lights in the corners of rooms" "5076": "Enable GenerateRoom() to randomise the light colours" "5194": "Run the game to see our differently coloured lights" "5240": "4 minutes into the Q&A, 11 until end. (based on NOTE)" "5290": "Make PushCube() take a v3 Radius to uniformly size cubes, and propagate this change" "5770": "Run the game to find that the walls are suddenly taller" "5854": "Make GenerateRoom() align the rooms in Z as they were before" "5937": "Run the game to see the room alignment" "6034": "Prevent GenerateRoom() from offsetting the HalfTileDim.z" "6120": "Run the game to see the room alignment" "6204": "Consider our alignment scheme" "6330": "Draw the chunk locations in UpdateAndRenderWorld()" "6510": "Run the game to see our chunk boundary" "6527": "Prevent ChunkPositionFromTilePosition() from adjusting the Offset.z" "6543": "Run the game to see that the chunk boundary lines up with the floor" "6554": "Disable most of the debug visualisation and take a walk about the orphanage" "6634": "Disable the room boundary debug visualisation" "6659": "Run the game and consider our dynamic camera" "6705": "Q&A" "6722": "Q: Is there a particular reason why the sim region and / or lighting region are based on "world space" rather than connected rooms? I know that's how it was originally put together but are there any benefits / disadvantages either way? Also, if you place the lighting boundary right before a lamp and then move so it enters the light region, doesn't it kind of pop-in a little? (It's more of a fade but hopefully you know what I mean, entering the big square room does what I mean with the lamps at the top)" "6881": "Q: I think there were two typos: 1. GetCameraOffsetZForDim() had XCount; typo 2. PushLight() PushCube() had x, x, z" "6915": "Fix typo in GetCameraOffsetZForDim()" "7006": "Q: Haven't really followed much, but are those static lights simulated? If yes, would it be a good idea to make their lighting pre-calculated to improve performance?" "7050": "Q: Will the up-facing sprite cards be affected by the lighting in the future?" "7085": "Q: Will we do shadow maps?" "7105": "Consider how shadow maps could work with sprite cards, and making stairwells" "7211": "Q: It looks like rooms below you can be outside of the lighting volume" "7343": "Q: I'm cleaning up the color handling to track down rendering differences between my OpenGL and Metal backends. Is there a generally accepted way to pass / store colors in the pipeline, i.e. pre-convert everything in the asset packer to linear or widest color space? The world generation code is currently linearizing the sRGB color inputs so that they can then be reconverted to sRGB by OpenGL during blending. This seems inefficient?" "7539": "Q: Should we change the color of the hero sprite depending on the surrounding light? He looks too bright in the darker areas" "7642": "Q: Shouldn't lights behave as other entities in regards to the sim region?" "7686": "Q: I thought they are visible when outside?" "7696": "Understanding the simulation region in terms of the lighting" "7847": "Q: Will you be adding fire-flies and will you call them lighting-bugs?" "7855": "That's all, folks" --- name: "day453" title: "Parsing PNG Headers" markers: "0": "Recap and set the stage for the day" "16": "Run the game to show the current camera and lighting situation, and consider our next steps" "142": "Determine to support hot-loadable art assets in a readily usable format by Anna, i.e. PNG" "293": "Consider our current BMP-loading code, with a view to implementing minimal PNG-loading" "564": "Install GIMP" "703": "Bring up the PNG specification" "776": "Create a piece of structured art as a 1024×1024 8bpp RGBA PNG called gimp_test.png" "1173": "Embark on a PNG parser, creating handmade_png.cpp" "1319": "Run it to see our printf" "1329": "Grab ReadEntireFile() from test_asset_builder.cpp" "1398": "Run it to see it in action" "1414": "Introduce ParsePNG(), noting that it is not meant to be fault tolerant" "1544": "Setup the handmade_png.cpp project in MSVC" "1622": "Step through ReadEntireFile() and inspect its Result" "1665": "Create handmade_png.h" "1713": "Consult the PNG spec with an explanation of the RIFF generic file container format" "1902": "Introduce png_header, png_chunk_header and png_chunk_footer structs, using #pragma pack" "2154": "Begin to implement ParsePNG(), introducing ConsumeSize() to extract desired data from our file contents" "2629": "Run it and hit a file underflow error" "2665": "Step through ParsePNG() to realise that the ContentsSize doesn't decrease" "2683": "Fix ConsumeSize() to decrement the ContentsSize" "2703": "Step through ParsePNG()" "2783": "Consult the PNG spec for information on the Length field" "2827": "Change Type in png_chunk_header to be an array of four chars" "2850": "Step in to ParsePNG() to see our Type more easily" "2889": "Consult the PNG spec about for information on the Length field" "3020": "Inspect the FileContents as raw memory to determine that PNG may be big-endian" "3092": "Consult the PNG spec to see that it is indeed big-endian" "3161": "Introduce EndianSwap()" "3695": "Add a test value and assertion in EndianSwap()" "3725": "Step in to EndianSwap() to see what it produces" "3757": "Step in to ParsePNG() to inspect our endian-swapped PNG data" "3821": "Enable ParsePNG() to print out the chunk types" "3874": "Run it to see our chunks" "3889": "Start to enable ParsePNG() to not bother parsing certain chunk types, introducing FOURCC() to turn a string into a 32-bit identifier" "4106": "Run it to see that our FOURCC() works" "4140": "Check the web to show other FOURCC() approaches" "4186": "Try to make FOURCC() straight up cast the string to a u32 pointer" "4221": "Run it to see that this works" "4233": "Enable ParsePNG() to switch on our chunk types for conditional parsing" "4273": "Hit a compile error and revert FOURCC() to our bit-shifting approach" "4310": "Trim down ParsePNG() to only handle IHDR and IDAT, introducing png_ihdr struct" "4890": "Run it to see our IHDR data" "4952": "Condense ParsePNG() down to only support 8bpp RBGA, deflate / inflate, and the International Standard-defined adaptive filtering and not interlaced PNGs" "5159": "Jump into the IDAT chunk" "5403": "Consult the DEFLATE spec" "5516": "Huffman Tree" "5824": "Consult DEFLATE's use of Huffman coding with a note that Huffman excels with integral numbers of bits" "6043": "“I'm gonna have to take a mulligan on that one.”" "6050": "Continue to consult the DEFLATE spec" "6641": "Setup ParsePNG() to decompress our images, introducing AllocatePixels()" "7070": "Introduce png_idat_header and png_idat_footer for ParsePNG() to parse out of our file" "7503": "Run it to see our IDAT chunk data" "7604": "Q&A" "7648": "Q: Instead of using the FOURCC() macro why not just use a single-quoted literal? For example, if ((ChunkHeader->TypeU32) == 'IHDR') {}" "7675": "Q: What is wrong about using ImageMagick from the build system to convert all the images?" "7702": "Q: Don't think so. I used it 20 years ago at least" "7754": "handmade_hero Q: What math subject do I need to know to follow along? Should I learn linear algebra?" "7796": "Q: Just little bit brainstorming, can somehow Zipf's law be used for benefit on Huffman?" "7811": "handmade_hero It would work if you bswap the type" "7821": "Change ParsePNG() to EndianSwap() the chunk type, and replace FOURCC() with direct equality checks on 'IHDR' and 'IDAT'" "7867": "Q: Zipf's law" "8008": "Q: How could someone abuse the PNG loader? You brought up malformed code" "8068": "handmade_hero The png_idat_footer should be 4 bytes. I think you just have it as a single u8 right now" "8075": "Fix png_idat_footer" "8080": "Q: Why are there several IDAT chunks and not one single one?" "8133": "handmade_hero Not using _bswap() intrinsic instead?" "8220": "Try to change EndianSwap() to use the _bswap intrinsic" "8312": "Try to find the definition of _bswap" "8423": "Make EndianSwap() use the _byteswap_ulong intrinsic" "8460": "Step in to EndianSwap() and check out the asm" "8494": "Make EndianSwap() use our original approach, and compile in -O2" "8513": "Step in to EndianSwap() to see that the compiler output a bswap anyway" "8566": "Q: Is the PNG loader to support allow live art iteration on stream? Art stream soon?" "8581": "Q: Sorry if I missed it, but was there any reason the chunk types have the weird mixed case, like tEXt and pHYs etc?" "8652": "Q: What's the 32-bit crc for?" "8702": "We're all done" --- name: "day454" title: "Parsing ZLIB Headers" markers: "0": "Welcome to the stream" "21": "Recap and set the stage for parsing PNG IDAT data" "78": "Run the program to look at our IDAT chunks" "238": "Set up to parse IDAT chunks" "404": "Prepare ReadEntireFile() and ConsumeSize() to read the .png file into a linked list of streaming_chunks" "818": "Run it to see that it works" "819": "Enable ParsePNG() to build up a linked list of IDAT chunks, introducing AllocateChunk()" "1149": "Describe this obtuse, single-expression singly linked list append" "1211": "Enable ParsePNG() to parse the IDATHeader" "1279": "Run it to see our decompressed IDAT chunks" "1290": "Make ParsePNG() print the IDAT chunk sizes" "1305": "Run it see the sizes of the IDAT chunks and determine that GIMP is outputting in 8192-byte chunks" "1410": "Consult the PNG and ZLIB specs to understand what we need to support" "1519": "Further condense ParsePNG() to support compression method 8 (DEFLATE) and no preset dictionary" "1581": "Run it to see our "Supported" message" "1587": "Begin to make ParsePNG() decompress the IDAT data using DEFLATE" "2119": "LZ-Style Compressors" "2455": "Run-Length Encoding as LZ Mode 2" "2685": "Enable ParsePNG() to LZ-decompress the IDAT data" "2977": "Read about non-compressed and compressed blocks, including Huffman codes, in the DEFLATE spec" "3476": "Implement ConsumeBits() and FlushByte() and enable ParsePNG() to parse BTYPE 00 chunks" "4153": "Step through ParsePNG() to see our consumed bits" "4236": "Read about dynamic Huffman codes (BTYPE 10)" "4393": "Enable ParsePNG() to handle dynamic Huffman coded (BTYPE 10) chunks" "5564": "Step through ParsePNG() to inspect our HLIT, HDIST and HCLEN, and realise that the code lengths are swizzled from most to least likely" "5785": "Set up ParsePNG() to build up our Huffman table, introducing stubs for ComputeHuffman() and HuffmanDecode()" "6760": "Q&A" "6821": "Q: I'm happy you're doing this. I've had problems making my inflate decoder (for fun) working, and you being a spec decoder works out perfectly" "6837": "Q: I believe the length for the LZ should be interpreted like u32 copy_length = length_table_base[LitLen-257] + ConsumeBits(length_table_extra_bits[LitLen - 257]); And the distance is similar with the other table(s)" "6887": "Q: How have you found the png and zlib specification, compared to other specifications you have read and implemented?" "6951": "Q: Any way to fix the pink flashing? It was fairly persistent today" "6969": "Q: Will Yangtian iterate over the art live?" "7006": "Q: What do you do when you have an incomplete specification? Is it then more just trial and error, or are there techniques on how to continue?" "7152": "Q: What 4coder version are you using on stream?" "7196": "Q: Just caught up with the stream, but I have had a question for a while: When you come up with a reusable data structure and want to share it between projects / other people, how do you deal with custom allocation? I have been writing some hybrid data structures, and I want to add custom allocation, but adding a template parameter seems like a bad solution to the problem" "7219": "Q: I see it in the *Message* window that you don't get at start up apparently" "7230": "Custom memory allocation in Granny" "7443": "Q: Why does no one spec the simplest solution possible, so people can easily implement the parsers and exporters they need (in cases when space / speed does not matter)?" "7621": "Q: Are you going to do audio formats next?" "7667": "We're all done" --- name: "day455" title: "Decoding PNG Huffman Tables" markers: "0": "Recap and set the stage for the day decoding Huffman" "48": "Bring us up to speed with ParsePNG()" "129": "Return to the PNG and DEFLATE specifications with a few words on compressor creation" "377": "Set up to handle DEFLATE's use of Huffman coding" "624": "Slightly organise handmade_png.h and let ComputeHuffman() process the entire HCLENSwizzle table" "937": "Stupid Huffman Decoder" "1269": "LUT+Shift Algorithm, Patent Pending 2018®™" "1381": "Consult the DEFLATE spec for the maximum code length" "1690": "Consider the feasibility of building a 32k lookup table" "1786": "Introduce AllocateHuffman() and png_huffman_entry struct" "2200": "Determine to implement HuffmanDecode()" "2276": "Encoding symbols: "Numerical" vs "Bit"" "2362": "Relieve png_huffman_entry of containing SymbolLength" "2408": "Introduce PeekBits(), the same as ConsumeBits() just without shifting the bits, and DiscardBits()" "2773": "Implement HuffmanDecode(), augmenting png_huffman with MaxCodeLengthInBits" "2970": "Dive into implementing ComputeHuffman()" "3205": "Determining symbol code locations" "3316": "Enable ComputeHuffman() to correctly place symbol codes in the table" "3560": "Start to enable ComputeHuffman() to build those Huffman codes, in conjunction with the DEFLATE specification" "3792": "Come to understand DEFLATE's use of Huffman coding specifications with a few words on compressor creation" "4107": "Enable ComputeHuffman() to find the numerical value of the smallest code for each code length, and assign numerical values to all the codes" "4513": "Consider ourselves done with that part of it" "4546": "Make ParsePNG() allocate our Huffman tables" "4734": "Determine to go over the LitLenDistTable construction routine and implement the filters" "4798": "Step through ParsePNG() and inspect our data, in conjunction with the DEFLATE specification" "5115": "Fix AllocateHuffman() to set the MaxCodeLengthInBits" "5140": "Continue to step through ComputeHuffman() and consider the use of MaxCodeLengthInBits in the ArbitraryBits computation" "5375": "Change AllocateHuffman() to set the MaxCodeLengthInBits according to the length of that length it was passed in, i.e. 2^Length" "5490": "Run it and hit our assertion in AllocateHuffman()" "5504": "Revert AllocateHuffman() and instead make ParsePNG() pass 8 to it for the DictHuffman allocation" "5536": "Continue to step through ComputeHuffman() and inspect our data" "5618": "Assert in HuffmanDecode() that BitsUsed != 0" "5660": "Continue to step through ParsePNG(), hit our assertion in HuffmanDecode() and investigate why" "5726": "Carefully read 3.1.1 Packing into bytes to discover that Huffman codes are packed in the opposite direction to everything else" "6330": "Make ComputeHuffman() flip the bits of Huffman codes" "6492": "Step through ComputeHuffman() to watch our bits flip" "6547": "Fix ComputeHuffman() to flip all our bits correctly" "6613": "Step through ComputeHuffman() to see our correctly flipping bits" "6677": "Consider packing the Huffman codes backwards" "6792": "Step through HuffmanDecode() until we assert" "6957": "Make ParsePNG() increment LitLenCount in the LitLenDistTable construction routine" "7010": "Run until we crash in HuffmanDecode()" "7029": "Temporarily prevent ComputeHuffman() from flipping the Huffman bits" "7046": "Run it and crash earlier" "7085": "Q&A" "7097": "Fix typo in the LitLenDistTable construction in ParsePNG()" "7170": "Close that issue" "7215": "Q: Don't the bits when reading the table need to be reversed as well?" "7253": "Q: How many hours long is this series now? I've dabbled in the first dozen or so episodes, but trying to catch up on so much content is discouraging" "7272": "Q: You said multiple times that PNG spec does not allow fixed Huffman codes, but this is not true: PNG spec explicitly says that both fixed and dynamic Huffmans are allowed (section 10.1)" "7288": "Q: In AllocateHuffman() you use the sizeof the huffman table not the entries to malloc data" "7298": "Fix typo in AllocateHuffman()" "7331": "Read 10.1 Compression method 0" "7384": "Q: When reading the 3 bit lengths you'd read, e.g. 0b011, but I believe it should be 0b110" "7551": "Q: Yeah, you are correct" "7709": "Q: Only Huffman codes are bit-reversed when looking at the bit from first byte to last, and most significant bit to least significant" "7777": "Close down the stream" --- name: "day456" title: "Decoding PNG Length and Distance Extra Bits" markers: "6": "Recap and set the stage debugging our PNG reader, with a few words on implementing from a specification" "132": "Step through ParsePNG() and consider our current situation" "401": "A few thoughts on compressor scheme quality in terms of its possibility for erroneous output" "523": "Continue to step through ParsePNG()" "644": "Change ParsePNG() to allocate 7 bits for the DictHuffman" "701": "Step through ComputeHuffman()" "854": "Q: I think there is a typo in the code you copied from the standard. You have a < instead of <=" "919": "Continue to step through ComputeHuffman() where it bit-flips the Huffman codes" "1040": "Carefully read the DEFLATE spec on the endianness of Huffman codes" "1187": "Continue to step through ComputeHuffman() where it enters the Huffman codes into the symbol table" "1428": "LSB vs MSB Huffman" "1749": "Change ComputeHuffman() to put the bit-flipped Huffman code before its entry index, before bit-flipping that whole thing" "1802": "Step through ComputeHuffman() to see that it decompresses all our symbols" "1957": "Let ParsePNG() read to the end of the file, run it and crash on the second time through the loop" "2040": "Consult the Huffman decode part of the DEFLATE specification" "2105": "Make ParsePNG() copy the data to output, renaming ConsumeBits() to ConsumeSize() and introducing a u16 version of EndianSwap()" "2346": "Inspect the disassembly for EndianSwap(LEN) to see that it was optimised out" "2371": "Prevent the compiler from optimising out the EndianSwap(LEN)" "2434": "Inspect the disassembly for EndianSwap(LEN) to see that it it didn't do the expected byte-swap" "2479": "Fix the u16 version of EndianSwap()" "2502": "Inspect the disassembly for EndianSwap(LEN) to see that it it did a rol" "2525": "Begin to enable ParsePNG() to perform the Huffman decompress using a LengthExtra table of pre-subtracted lengths, in conjunction with the DEFLATE specification" "3717": "Bit reversal" "4085": "Research bit reversal" "4249": "Introduce ReverseBits() for ComputeHuffman() and ParsePNG() to call" "4479": "Create a DistExtra table to enable ParsePNG() to interpret the extra bits" "4974": "Enable ParsePNG() to decode the symbols using our lookup tables" "5559": "Step through ParsePNG() to see what it does" "5635": "Fix ParsePNG() to use the PNGDistExtra table when setting the DistTab" "5652": "Continue to step through ParsePNG() to see that it's working" "5687": "Consult the PNG spec in preparation for implementing the filter" "5768": "Let AllocatePixels() allocate space for the filter" "5934": "Hit an assertion in ParsePNG()" "5976": "Q&A" "6005": "Q: LitLen-256 should be LitLen-257" "6015": "Fix the LenTabIndex initialisation in ParsePNG() to LitLen - 257" "6030": "Step through ParsePNG()" "6076": "Q: Once this works, do you think it could be SIMDied?" "6106": "Q: That LitLen bug came from me. It'll also be clearer if you write "LitLen >= 257" instead of "LitLen > 256"" "6115": "Change "LitLen > 256" to "LitLen >= 257" in ParsePNG()" "6148": "Q: When you are making a PNG reader, I assume you want game textures to be in PNG format. For my projects I create uncompressed image data, and then archive all of them with some compressor. Is my approach a bad one? (I ask because you have decided to use PNGs)" "6196": "Q: Should ReverseBits table be u16 and not u32?" "6201": "Reduce the ReverseBits table size from u32 to u16" "6245": "Q: No bit reversal is needed. See Deflate spec 3.1.1 first two bullet points" "6344": "Q: By the way the <= I was referring to at the begin is in the loop in the Huffman decode function, the one with BitIndex in the spec. That loop has <= whereas you have <" "6427": "Q: BTYPE==0 should read from CompData I think, instead of At?" "6441": "Fix ParsePNG() to read from CompData rather than At in the BTYPE==0 case" "6488": "Q: "the extra bits, after being unpacked as described in 3.1.1, should be interpreted as a machine integer stored...", I guess is what they meant" "6505": "Prevent ParsePNG() from reversing the extra bits" "6533": "Step through ParsePNG() to see that we're sort of okay, but not quite right" "6645": "Q: Yes, that loop" "6778": "Stop now with a glimpse into the future" --- name: "day457" title: "Implementing PNG Reconstruction Filters" markers: "0": "Recap and set the stage for the day continuing with our PNG reader" "164": "Our understanding of the DEFLATE encoding" "360": "Pull up our piece of structured art" "463": "Create a simpler piece of structured art" "693": "A few thoughts on structured art" "753": "Add a BYTE == 1 case in ParsePNG() by advice of mmozeiko" "831": "Run our PNG reader on gimp_8x8_compression0.png to see which compression case we hit in ParsePNG()" "979": "Prevent ParsePNG() from performing integral promotion on the LEN != NLEN comparison" "1003": "Continue to step through ParsePNG()" "1112": "Prevent ParsePNG() from calling EndianSwap() on the LEN" "1133": "Continue to step through ParsePNG() to completion, and inspect the DecompressedPixels" "1497": "Deduce that the DecompressedPixels contain row transform filter indicators that we have not yet learnt" "1616": "Rename DecompressedPixels to FinalPixels, initialising it before the parsing loop in ParsePNG()" "1679": "Crash 4coder and step into it to see what's going on" "1810": "Continue setting up ParsePNG() to apply the filters to the FinalPixels" "2007": "4.3 Reference image to PNG image transformation" "2427": "9 Filtering (PNG)" "2945": "Finish setting up ParsePNG() to apply the filters to our parsed pixels, noting that it seems tailor-made for SIMD" "4090": "Introduce our PNGFilter*() functions" "4936": "Introduce PNGFilterReconstruct() to perform the filtering part of ParsePNG()" "5163": "Step through PNGFilterReconstruct() to see what we end up with" "5372": "Add assertions in the untested Average and Paeth filter cases in PNGFilterReconstruct()" "5455": "Run the program on the compressed gimp_8x8.png to see that it looks right" "5956": "Draw a more complicated image" "6060": "Run it on our more complicated, uncompressed image and hit the Paeth filter" "6160": "Remove that assertion from the Paeth filter case in PNGFilterReconstruct()" "6173": "Step through PNGFilterReconstruct() into PNGFilter4() (Paeth) to see that it looks reasonable" "6381": "Run it on our compressed complex image, to see that it look good too" "6417": "Run it on our fully complex gimp_test.png and crash in ParsePNG()" "6521": "Step through ConsumeSize() to realise that the crash occurs even in the first IDAT chunk, so the bug must be in the Huffman decode" "6833": "Perform coverage checking on every EncodedLen case in ParsePNG() to find that the 16-long (0x10) case is never used in the successfully parsed file" "7136": "3.2.7 Compression with dynamic Huffman codes BTYE=10" "7304": "Step through the BTYPE=10 case in ParsePNG() to see that the LitLenDistTable seems to be built correctly" "7360": "Consider our current situation and ways to proceed" "7398": "Q&A" "7418": "Q: The LEN, NLEN is so the decompressor can resync with a compressor if a block got corrupted (and the compressor emitted an empty block) by looking for the bytes 0000FFFF, mostly handy for byte streams" "7449": "Q: C is up and left" "7526": "Fix PNGFilterReconstruct() to correctly filter Paeth" "7584": "Q: Did I see for(;;) in your code? What's that for / how does it work?" "7676": "Q: In the memory window when you were writing the "decoded" pixel (non-compressed 8x8) you were writing to some memory that you have not allocated, accordingly to the ASCII representation, there were some strings about a path in windows" "7756": "Q: In Day 055 when you create the hash table, you added your TODO on getting a better hash. Other than for educational purposes investigating better hashes, what kinds of problems would you start to see if the hash was not good enough? Like would it pop-up when you are profiling or something? Would you get any errors?" "7869": "Q: There is a VS plugin that lets you see images in memory. It's called Image Watch. Was pretty useful when I did the PNG decoding" "7898": "Q: Oh okay, it's that it looked strange. Usually it's filled with 0xDD of 0xCD if I remember correctly, or maybe it's just for stack memory?" "8002": "Q: Try a big empty image which compresses very well" "8089": "Q: So on Linux, would you have to use calloc() instead of VirtualAlloc() or is there an alternative?" "8132": "Q: Will you integrate the decoder directly into the game or into the simple_preprocessor?" "8164": "Close it up with a glimpse into the future" --- name: "day458" title: "Debugging the PNG Reader" markers: "1": "Recap and set the stage for the day debugging our PNG reader" "61": "On starting by making our decompressor produce the correct number of bytes from our input stream" "254": "Approaching problems either by working from a spec, or comparing our implementation with a working version" "360": "Run the program on gimp_test.png until a crash caused by the Dest pointer's attempt to write into memory" "805": "Let ParsePNG() proceed to the next iteration of the loop, to see another length code 258" "938": "Compare our PNGLengthExtra and PNGDistExtra tables with the DEFLATE spec to ensure they look right" "1270": "3.2.5 Compressed blocks (length and distance codes)" "1390": "Scrutinise the length table building code in ParsePNG()" "1514": "Assert in ParsePNG() that the LenCount <= number of items in the LitLenDistTable" "1533": "Continue to scrutinise the Huffman decoding code in ParsePNG()" "1704": "Assert in ParsePNG() that the DecompressedPixelsEnd does not get exceeded" "1761": "Run it and hit our Source + Len assertion" "1813": "Consider investigating the Huffman table calculation, before determining to nail down the literal length stuff" "1884": "Produce a smaller image that exhibits the bug" "2367": "Note that our bug exhibiting image contains multiple IDAT chunks" "2520": "Produce a 64×64 pixel image that probably can't be PNG compressed" "2692": "Run it on gimp_64x64.png to see that the image contains two IDAT chunks and exhibits the crash" "2720": "5.3 "Chunk layout" and 11.2.4 "IDAT Image data"" "2935": "10.2 Compression of the sequence of filtered scanlines" "3017": "Run it and hit an assertion in HuffmanDecode() due to an invalid symbol" "3208": "Step through ConsumeSize() to realise that PeekBits() doesn't correctly operate across multiple IDAT chunks" "3249": "Fix PeekBits() and ConsumeSize() to correctly operate across multiple IDAT chunks" "3450": "Run it and again crash in HuffmanDecode() on an invalid symbol, although we did process more bits" "3545": "Crash ScriptedSandbox64.exe" "3592": "Continue to investigate our bug exhibited by gimp_64x64.png" "3771": "Assert at the end of ParsePNG() that the Dest == DecompressedPixels" "3796": "Run it and do not hit that assertion" "3814": "Determine that gimp_64x64.png crashes 9 bytes from the end, and investigate why" "3930": "Make PeekBits() print out BitBufferBeforeAdvance if it needs to advance the buffer" "4025": "Run it to see that there are 12 bits in the buffer but, more pressingly, that we do not handle fixed Huffman compressed chunks" "4086": "Enable ParsePNG() to handle fixed Huffman compressed chunks" "4671": "Step into ParsePNG() and inspect the LitLenDistTable comparing it with the PNG spec" "4757": "Determine to perform some difference tests" "4863": "Grab a screenshot of the stream" "4963": "Run okay on our captured screenshot" "4986": "Q&A" "5018": "Q: Yeah, same bug" "5032": "Q: You could use the ray casting code for save image files so we can see what happens. It should be a quick thing to do!" "5052": "Run the PNG reader successfully on our ray tracing image" "5149": "Credit rooctag for clarifying our understanding of the Paeth filter" "5193": "Q: Did you purposely screenshot my message saying you are handsome?" "5202": "Q: I think he meant save out the decoded PNGs out as a raw BMP so we can see the result?" "5244": "Pull WriteImage() in from ray.cpp and make ParsePNG() return an image_u32 for us to write out" "5547": "Inspect our written image to see that it is upside-down and incorrectly coloured" "5595": "Rename WriteImage() to WriteImageTopDownRGBA() and enable it to swap the rows, introducing SwapRAndB() to swap those colour channels" "5987": "Compare our written image with the original, to see that it is off-by-1 pixel vertically" "6185": "Fix typo in WriteImageTopDownRGBA()" "6200": "Compare our written image with the original to see that they match" "6249": "Q: Isn't it true that the compiler's optimizations of your code and the way the CPU works can sometimes cause instructions to happen in a different order than you wrote them? If so, won't that screw up profiling measurements?" "6283": "Q: Can you quantify how fast you type?" "6299": "Q: Would you say that 4coder is the ideal text editor?" "6332": "Q: Also, how often do you work out? You're buff" "6340": "Q: In the BMP write routine, I think you have a bug. You advance Row0 too soon" "6344": "Q: Double-check the shifting is not a GIMP paster error" "6357": "Q: Just joined a week ago and haven't had time to go through all the series. Can you say in overall what have you done on the project and what is left to do?" "6430": "Q: Do you have any project recommendations for beginner-intermediate C programmers?" "6466": "Q: Seems a bit casual today, what's your favorite album?" "6594": "Q: What is the craziest file format to parse, in your opinion?" "6654": "Q: What is the most difficult file format to read? Have you ever try to read ttf files? And try doing a vector renderer for those in OpenGL?" "6668": "Q: What's your favourite pasta dish?" "6701": "Q: How come no one has made a solid debugger? Is it difficult?" "6754": "Q: Will the game be only room based?" "6763": "Q: Bit off topic, but are you a musician? Didn't you write some music for Handmade Hero yourself?" "6774": "Q: This may be too in-depth of a question, but: how can I send data over the internet for a game that can be picked up in a code that I write" "6798": "Q: Will we be parsing compiler debug output (DWARF?) for cool in-game debug stuff?" "6807": "Q: 3ds is worse than psd?" "6827": "Q: We've had a Handmade Ray bonus series, what about Handmade Asteroids?" "6832": "Call it a day" --- name: "day459" title: "Partitioning the PNG Reader for Integration" markers: "0": "Recap and set the stage for the day working towards putting art into Handmade Hero" "188": "Is anyone else mesmerised by the bobbing orphan on the web page" "293": "Unpack the new art into a dedicated directory where the artist may dump art" "433": "Show off item_template.png and character_template.png" "560": "Discover how to switch the default image viewer back to the one that used to be the default" "788": "Switch the default image viewer back to Windows Photo viewer" "868": "Show off our new art" "1046": "Set up to read our new PNGs" "1142": "Run our PNG reader on character_hero.png and crash in ConsumeSize()" "1258": "Note in ParsePNG() the need to handle BTYPE0 blocks that straddle IDAT chunk boundaries" "1372": "Step through ParsePNG() to see that BFINAL does not get set" "1708": "Let it run to completion, writing out our image" "1735": "View character_hero.bmp to see that it looks correct but for the alpha channel" "1870": "Inspect the Width and Height values, to see that they are as expected" "1945": "Consult the DEFLATE, ZLIB and PNG specifications for information on BFINAL and chunk processing" "2512": "Enable ParsePNG() to break out of its consumption loop once all the expected pixels have been consumed" "2599": "Run it successfully to see that the output looks correct" "2632": "Run it successfully on hand_skeleton.png" "2657": "Inspect the output image to see that it looks correct, and wonder if Photoshop's PNG encoder is busted" "2815": "Remove stale code from WriteImageTopDownRGBA() and note in ParsePNG() to figure out why we can't rely on BFINAL being set to 1 on the last chunk of Photoshop-exported PNG files" "2987": "Consult stb_image.h for insight into its consumption loop" "3231": "Set up to test our PNG image with stb_image.h" "3417": "Run stb_png_test successfully on character_hero.png" "3637": "Step through stbi__parse_zlib() and into stbi__parse_uncompressed_block() to see that it processes 0-length blocks" "3929": "Investigate the handling of 0-length blocks by FlushByte() in ParsePNG(), reverting the latter to break out of its consumption loop only if BFINAL is 1" "4044": "Set up to test our PNG reader on character_hero.png" "4139": "Break on the FlushByte() call in ParsePNG() and realise that it may be flushing more than a byte" "4202": "Change ParsePNG() to consume 16-bits for the LEN and NLEN, and FlushByte() to only flush the remainder of the byte" "4301": "Run it to see that we correctly parse character_hero.png" "4339": "Enable ParsePNG() to parse blocks that straddle IDAT chunk boundaries, introducing RefillIfNecessary()" "4567": "Run it to see that it still works" "4595": "Remove the ReversedBits table" "4639": "Determine to split up the PNG reader for integration into the game, while retaining the small test app" "4703": "Create test_png.cpp to contain everything except the decoding code" "4927": "Consider supporting buffered error handling in the PNG decoder" "5041": "Create handmade_stream.cpp to contain all the stream consumption code for our PNG reader" "5523": "Introduce Outf() to write errors into our stream, augmenting the stream struct with Errors and stream_chunk with File and LineNumber" "5929": "Make test_png.cpp initialise an Info and Error stream, pass them to ReadEntireFile() and WriteImageTopDownRGBA(), and write those stream to file using a new DumpStreamToCRT()" "6256": "Introduce OnDemandMemoryStream()" "6302": "Compile and run and get no output, with a view to addressing that later" "6316": "Q&A" "6389": "Q: So what is the focus now? This logging / error system?" "6498": "Q: I haven't been following the PNG streams closely, but how satisfied are you with the code for the reader?" "6553": "Q: Could you explain the bug that was solved again?" "6682": "Q: Is TODO comment still in the code?" "6717": "Q: Any plans to switch to LLVM anytime in the series?" "6761": "Q: If Visual Studio can load PNG files, maybe it can display BMP files with alpha?" "6822": "Enable WriteImageTopDownRGBA() to conditionally replace the alpha pixels with all black, and the program to output this as an extra BMP file" "7118": "Run it and inspect our two output BMP files" "7140": "Introduce MulAlpha() to composite the alpha and non-alpha pixels" "7386": "Run it to see our premultiplied output" "7429": "Q: This is off-topic, but will there be any blog posts on Molly Rocket for any of the projects anytime? Kind of miss those" "7445": "Q: I am confused why you shift the multiply down by 8 bits. Wouldn't you want to mask with 0xFF?" "7484": "Basis in Fixed Point Multiply" "7865": "Q: Can you briefly explain how the binary reverse works you implemented last week?" "7870": "Bit Reversal" "8005": "We're all done" --- name: "day460" title: "Providing Platform File Information to the Game" markers: "0": "Recap and set the stage for the day" "78": "Determine to enable the PNG loader to use memory from an arena" "316": "Switch the PNG loader over to use a memory_arena" "1020": "Note the need to emulate a platform layer in test_png.cpp" "1126": "Initialise a platform_api and introduce CRTAllocateMemory and CRTDeallocateMemory callbacks in test_png.cpp" "1416": "Run it to see that it still works" "1448": "Begin to implement Outf_() based on our existing FormatString()" "1631": "A few thoughts on null-terminated strings" "1761": "Proceed with Outf_() pushing non null-terminated strings into the error stream" "1961": "Run it to see no errors, but busted info printout" "2004": "Change AppendChunk() to return a stream_chunk for Outf_() to print the File and LineNumber" "2069": "Run it to see our complete info printout" "2166": "#include "handmade_png.h" and "handmade_stream.h" in the game" "2278": "Determine to augment the asset storage format with the concept of on-demand asset addition" "2502": "Check out the current asset system with a view to enabling it to load PNG spritesheets into permanent storage, and expanding the platform_api with information on when that PNG loading needs to happen" "2681": "Determine to watch a directory for changes to PNG files" "2869": "Add a PlatformFileType_PNG and PlatformFileType_WAV for Win32GetAllFilesOfTypeBegin to understand" "2925": "Check out what file information the asset loading system currently contains" "3070": "Introduce platform_file_info struct containing the FileDate and BaseName" "3250": "Consider the need for additional information not included in the PNG files" "3442": "Augment platform_file_group with an array of platform_file_info, and make PLATFORM_OPEN_FILE take an Index to open a particular file" "3583": "Consider how the file info will be gathered and used in the asset loading system, and the directory structure of our assets" "3771": "Establish the directory structure from where Win32GetAllFilesOfTypeBegin gets files" "3980": "Remove win32_platform_file_handle and change win32_platform_file_group to only contain a memory_arena for Win32GetAllFilesOfTypeBegin to store a linked list of platform_file_info" "4607": "Consult MSDN for a filename parsing function" "4915": "Enable Win32GetAllFilesOfTypeBegin to pull out the BaseName from the file path and Win32GetAllFilesOfTypeEnd to Clear the memory" "5199": "Trim down Win32OpenFile, preventing it from allocating memory for the Win32Handle" "5472": "Change Win32GetAllFilesOfTypeEnd and Win32GetAllFilesOfTypeBegin to use wchar_t characters" "5683": "Search MSDN for a UTF-16 to ASCII converter" "5773": "Read MSDN on the WideCharToMultiByte function" "5801": "Enable Win32GetAllFilesOfTypeBegin to pass ASCII base filenames to the game using WideCharToMultiByte()" "6077": "Enable Win32OpenFile to open our file handle, and implement Win32CloseFile" "6309": "Enable Win32GetAllFilesOfTypeBegin to fill out all the platform_file_info and fix up compile errors" "6547": "Step through Win32GetAllFilesOfTypeBegin to watch it fill out the Info" "6798": "Begin to enable Win32GetAllFilesOfTypeBegin to include the file path stem and extension in the info" "7009": "“If wishes were horses... we'd all be at the airport”" "7017": "Continue enabling Win32GetAllFilesOfTypeBegin to fill out the file path stem and extension, introducing CopyArray()" "7277": "Jump into Win32GetAllFilesOfTypeBegin and through Win32OpenFile until hitting the InvalidCodePath in BeginWorldChange()" "7498": "Run the game in -O2 to determine that that part of the system is ready to do dynamic loading" "7537": "Q&A" "7570": "Q: Where will the assets be stored when they're not reloaded from the PNGs, WAVs etc?" "7648": "Q: I thought asset system allocates based on headers read from asset files. That means you can replace resources with dynamic reload but not add new ones. And you can't add tags. Or am I missing something?" "7681": "Q: How will we handle the switch between .hha and loose asset files?" "7707": "Q: For future reference, since you might be looking at it in the next few episodes - GetFileAttributesEx() with a GetFileExInfoStandard flag comes out the fastest out of all the ways to get the file size from the win32 API; vs GetFileSize and FindFirstFile etc." "7739": "Q: Will you do my comp sci homework for me?" "7745": "Q: Sorry, meant file mod time" "7794": "Q: Do you intend to allow hot reload of things like metadata (hotspots, etc.). You sort of mentioned it but I didn't follow what you were thinking" "7820": "Q: Which language is better in game industry? C, C++, or even C#? So much way to programming, it's confusing" "7895": "Q: In my system I have a thing that you can register a file name and when it changes a callback function is invoked, then for every file I have to load I add an entry in that table. What do you think of add callbacks?" "7948": "Q: If the artist changes the art, then the hotspot might change, so it could be tricky" "7968": "Q: How often people in chat suggest you to Rewrite In Rust?" "8089": "Q: IO completion ports vs asset loading thread?" "8205": "Q: A little off-topic: There's been a lot of talk about the deprecation of OpenGL and using a lower level API to talk to the GPU. My question is, does Nvidia's CUDA satisfy this lower level API requirements for games, in your opinion?" "8308": "Ask Miblo how you ban people from HexChat" "8352": "Use .b " "8394": "Q: Forgive me for I did not watch the entire episode, but instead of iterating over the entire directory, could you not use functions like ReadDirectoryChangesW and FindFirstChangeNotificationW? Or will the number of files be so small and this is for debug only that not worth it?" "8743": "Q: Would it be good idea to abstract render push buffer? That way you can use Vulkan command buffers or whatever Metal has with less memory copying" "8786": "Q: More hardware related: Will your code have to be different when coding for different video cards (i.e. AMD vs Nvidia)?" "8874": "Q: Why sometimes do the MSDN functions require buffers to be aligned?" "8994": "That's it, with a mention of the Watch page and a glimpse into the future moving PNG files through a runtime pipeline into the .hha files" --- name: "day461" title: "Checking for File Date Changes" markers: "0": "Recap and set the stage for the day integrating our PNG reader into the game" "173": "Consult our current asset loading code with a view to storing assets more smartly" "484": "Walk through our asset struct, and consider removing asset_memory_header" "611": "Walk through our hha_asset and game_assets structs, with a few words on tagging and tag array expandability" "999": "Dive into watching files for changes, introducing watched_file" "1145": "Consider the structure of character_template.png and take a look at character_mummy.png in Paint 3D" "1325": "Add AssetIndices structural information to watched_file" "1658": "Set up watched_file for hashing into a list, consider moving to fixed sized blocks for performant texture memory use, and store the source location in assets" "1993": "Determine to reload assets on a key-press, with a few words on dedicating a core of a developer's machine to reloading" "2140": "Introduce CheckForArtChanges(), renaming watched_file to asset_source_file" "2346": "Open character_skeleton.png in Paint 3D, and try and paint in 3D" "2566": "Check out character_orphan_09.png in GIMP and consider annotating it with additional information" "2708": "Set up to store our additional information in the hha file" "2879": "Enable CheckForArtChanges() to hash file names using a newly introduced UpdateStringHash()" "3284": "Null-termination vs Length + Pointer" "3513": "Parsing regions of strings" "3858": "Introduce buffer struct and Advance()" "4156": "Ask after Mr4thDimention, noting that 4coder sometimes jumps to the second error in the stream" "4206": "Continue to propagate our buffer struct to all interested parties" "4331": "Run the PNG reader to make sure nothing broke" "4371": "Fix WriteImageTopDownRGBA() to output the alpha layer the right way up" "4451": "Run it to see that the alpha is the right way up" "4496": "Enable CheckForArtChanges() to parse out pieces of our file names" "4818": "Set up CheckForArtChanges() to match loaded files against known files, making the platform layer lowercase file names using a newly introduced ToLowercase()" "5388": "Enable CheckForArtChanges() to initialise unknown files" "5599": "Set up CheckForArtChanges() to process individual assets, calling a stubbed out UpdateAssetPackageFromPNG()" "6123": "Enable CheckForArtChanges() to (de)allocate memory for each block" "6252": "Change CheckForArtChanges() to use a temporary memory arena with a view to implementing UpdateAssetPackageFromPNG() tomorrow" "6393": "Q&A" "6439": "Q: Thoughts on the use of persistent memory, e.g. Intel Optane, in game programming?" "6532": "Q: Are you sure always lowering filename to lowercase is a good solution? Because case-sensitivity is a feature of filesystem, not whole OS. On NTFS you can enable case-sensitivity individually per folder. You can mount NTFS disk on Linux / Mac. And on Apple HFS+ or APFS can be both - case sensitive or case insensitive, depends on how you format it" "6599": "Q: I can't remember, are the bitmap assets stored next to the audio and font glyph assets in memory? May be relevant if those are not the same size as the bitmaps?" "6684": "Q: What's the mnemonic device used in "umm"? I get that it's a size_t, but what does umm stand for? Quite a few people on the stream ask" "6773": "Q: Thoughts on use of Vulkan for a 2.5D game like this? Is it an overkill or is there a benefit?" "7022": "Q: I think you meant to add to String->Count when Scan[0] != '_', just below the code on screen (CheckForArtChanges)" "7057": "Fix typo in CheckForArtChanges()" "7107": "Q: I've been listening to early episodes of Jeff and Casey podcast and want to ask if you feel guilty for giving EA all the advice which they definitely follow?" "7150": "Q: Thanks a lot for all these great educational materials. They are very inspiring! Could you explain why OpenGL is a state machine?" "7183": "Q: Why Scan[1] == 0 and not Scan[0] == 0?" "7382": "Q: Is the answer still no to doing my Comp Sci homework for me?" "7391": "Q: Ah, okay. Sorry, I missed the *Scan check first, which of course would mean that Scan[0] == 0 would never happen" "7397": "Q: A bit off-topic, but are there any intrinsics for bit-interleaving? I can't find on the Intel intrinsics webpage, but was thinking that they might not have named it "interleave" or some such" "7433": "Q: Once the game is completed (and I know it may take a long while to get there) are there any plans to do similar educational series? If so, what would it be?" "7441": "Q: Should those pieces also be passed to UpdateAssetPackagrFromPNG()? As far as I can tell you're parsing them out but not using them" "7493": "Q: Yes, every other bit" "7945": "Q: I seemed to have missed a lot of the memory arena work, but when you create a temp memory arena, where do you pass in the original memory that you've allocated? Normally I would think global variable, but if in the game layer, that would get reset when you reloaded, correct?" "7973": "Q: I don't know if this has been asked before, but would you consider having your VODs do reruns on days you aren't going to stream?" "8000": "Q: On my day to day I find myself using std::string very often. Should I write my own string library or what other options would you recommend? If so how do I handle allocations (a single huge allocation doesn't seem to be the right choice since I'm not writing a game)" "8111": "Q: On the topic of VODs, i was curious why you don't have your past broadcasts saved on twitch. Say someone misses something you said / wrote and wants to go back and listen / watch quickly there's no way to do that until the VOD is uploaded on YouTube" "8129": "Q: In a semi-related thought to GG_Nate , have you ever considered using a program that overlays the twitch chat into OBS? I see entertainment focused streamers using them and it's really nice for when they reference something from chat and you're watching the YouTube upload of the stream" "8149": "Q: Months ago when you were implementing intrinsics, you added one that uses an SSE4.2 instruction. This isn't supported by most older AMD chips (like mine). Will you consider a work-around for this?" "8184": "Wind it down with a plug of the new Watch page and its integrated Annotated Guide and hotlinks" --- name: "day462" title: "Extracting Asset Tiles from Gridded PNGs" markers: "4": "Recap and set the stage for the day" "117": "Dive into implementing UpdateAssetPackageFromPNG(), adding an Errors stream to asset_source_file" "592": "Introduce MakeReadStream()" "669": "Note the flexibility of having the first Contents buffer within the stream struct, rather than making everything go through a stream_chunk" "762": "Fix compile errors" "857": "A few words on memory arenas" "953": "Set up to enable UpdateAssetPackageFromPNG() to break assets up into tiles" "1097": "Note the need to handle non-tiled assets, with a mention of mom's misremembrance of Krampus as "Krumpus"" "1183": "Introduce ProcessTiledImport() to split up assets into 1024×1024 tiles, for UpdateAssetPackageFromPNG() to call" "1870": "Note the need to invalidate the texture memory, determining first to load the stuff in before switching to fixed size blocks" "2024": "Consider resizing our title_screen.png down to fit into one of our fixed blocks, with some general thoughts on texture memory" "2423": "Consult the Steam Hardware and & Software Survey for VRAM availability statistics" "2656": "Enable ProcessTiledImport() to load the asset-tile into a provisional bitmap" "2845": "Texture Borders, for sub-pixel rendering" "3093": "Where the 1-pixel border approach falls down: Mipmapping" "3254": "Border thickening" "3554": "Make ProcessTiledImport() enforce an 8-pixel border, and warn about encroachments into this border" "4081": "Set up to store our tiles in the pack file" "4215": "Make ProcessTiledImport() write our tiles into Bitmap->Memory" "4389": "Consider writing our tiles into a backing store before compacting down into the .hha file" "4683": "Introduce WriteAssetBitmap()" "5025": "Change ProcessTiledImport() to load our tiles into a provisional bitmap before writing out to the .hha file" "6183": "Fix compile errors and stub out ReserveAsset(), ReserveData(), WriteAssetData() and WriteAsset()" "6453": "Q&A" "6491": "Q: Will you rewrite the software rasterizer with SSE4?" "6605": "I don't have AVX512" "6651": "Q: You still haven't bounded HashValue in CheckForAssetChanges(). Thought I’d mention" "6666": "Make CheckForAssetChanges() bound the HashValue" "6757": "Q: How long until Microsoft tries to force win32 to become obsolete, and what comes after win32 for games?" "6807": "Trying to play PUBG with Anna and Matt" "7317": "Q: If I remember correctly, stb_lib was used in one of the episodes. Was it for loading PNG assets?" "7461": "Q: Since you already have deflate decoder implemented in PNG reader, will you implement deflate compressor for asset files?" "7473": "Q: Speaking of stupid driver distribution, Sony only have DualShock 3 drivers for PC packaged with their PS Now software. Ridiculous" "7503": "Q: Spent ages struggling with getting that damned controller to work" "7507": "Q: My poor friend said when Windows last updated for her it took four hours" "7514": "Q: Do you think Linux will take over? Seems unlikely. Also remember when the PlayStation 3 had Linux support?" "7575": "Q: What would it take to make it more designer friendly to develop on an Ubuntu or Fedora platform first?" "7717": "Q: MSVC does a terrible job with mod, clang seems to do better" "7759": "Q: Are you going to support more complex languages. Coding your own HarfBuzz text shaping equivalent?" "7794": "Q: Sixaxis / PS3 controller" "7821": "Q: So is our plan to infiltrate Microsoft and make Handmade Windows?" "7892": "Q: Yeah they need a handshake thingy. You get past that with the driver though. That's exactly why I struggled with it. Writing a rawinput thingy for controllers" "7907": "Q: Cant enable the controller through userland win32, sadly" "7958": "Brief continuation of the PUBG story" "7990": "Q: Isn't a big part of the issue that the operating system would need a lot of traction. If Jonathan or someone like you build an OS it would need a very significant amount of traction to incentivize game developers to build for that platform" "8108": "That's it, with a mention of the new site and a glimpse into the future" --- name: "day463" title: "Preparing HHAs for Rewriting" markers: "4": "Recap and set the stage for the day continuing with asset loading" "169": "Review CheckForArtChanges() with a few words on obtaining tagging information from filenames" "390": "Considering file deletion" "569": "File system capabilities" "871": "Finish walking through CheckForArtChanges() and ProcessTiledImport()" "1083": "Asset tagging" "1255": "Change the Assets in game_assets to be expandable, implementing ReserveAsset()" "2123": "Implement WriteAssetData(), introducing WriteDataToFile()" "2262": "Set up to implement WriteAsset() considering our .hha file format" "2434": "Enable AllocateGameAssets() to track asset locations in .hha files" "2576": "Consider either enabling .hha files to reference each other, or rewriting the header of a given .hha file on every asset edit" "2816": "Propose rewriting the entire header, and storing with each asset their type" "3009": "Introduce Win32WriteDataToFile()" "3202": "Remove WriteAsset() in favour of RewriteHHAHeader()" "3271": "Run the game to make sure it's fine" "3322": "Consider possibly changes to our .hha file to pair up assets with their types" "3571": "Temporarily change GetBestMatchAssetFrom() and AllocateGameAssets() to chain up assets of whatever type as a linked list" "4222": "Run the game to see that we didn't mess anything up" "4244": "Note our newfound ability to rewrite our .hha files at will and interleave our asset types, with a view to future improvements" "4362": "Consider establishing the concept of editable .hha files" "4506": "Add EditingHHAIndex to game_assets, fixing AllocateGameAssets() to assert FileIndex < Assets->FileCount" "4730": "Run the game to see that all is okay" "4740": "Make CheckForArtChanges() honour our EditingHHAIndex, and introduce RewriteHHADirectory()" "4909": "Rename EditingHHAIndex to DefaultAppendHHAIndex for ProcessTiledImport() to set for the first .hha file" "5202": "Add FileSize to asset_file" "5266": "Growable Data Storage" "5534": "“An artist's machine can write 2.5 MB before Photoshop can even select the lasso tool, not counting if you accidentally, heaven forfend, accidentally hit the "Open In Bridge" button, at which point you could rewrite all of the world's knowledge many times over to optical media and you would be done before Photoshop could even open its dialog box”" "5558": "Overwriting tiny data with large data before rewriting the tiny data back out to the file" "5607": "Add HighWaterMark to asset_file for AllocateGameAssets() to set using a newly introduced RetractWarterMark()" "6388": "Implement ReserveData() and WriteModificationsToHHA()" "7015": "Q&A" "7048": "Q: Will you be making an editor for the engine?" "7061": "Q: Did you mean to type it "retractwaRtermark"?" "7082": "Fix name of RetractWaterMark()" "7100": "Q: I may have missed this, but where are you handling the growth of an existing asset. Presumably you'd still need to memcpy a huge portion of the bitmaps to insert new data or remove from the middle?" "7203": "Q: I've probably missed this but why do we want to contiguously pack the bitmaps and the header?" "7341": "Q: Is asset_file (or forgive me, whatever you've named the file) actually a file?" "7396": "Q: Thanks, separate question, again from much earlier stuff I may have missed: What is the likelihood of a hash collision with the asset source names and do you handle that?" "7440": "Q: Wouldn't keeping different files for different assets, and keeping another file just for the index be better for source control?" "7562": "Q: Are I/O puns off limits, cause I hope this question doesn't block! If you wouldn't mind, as you've often hailed it, what makes IOCP such a great API? How does it work better than other APIs?" "7737": "Q: I was thinking on the direction of always having a running build on source control" "7785": "Q: When / where are you doing that Witness development presentation?" "7800": "Q: Quick follow up: Is that just a matter of using the one message queue for more than I/O or when you need to use multiple message queues?" "8128": "Close it down with a glimpse into the future tackling the tagging problem" --- name: "day464" title: "Applying Asset Types and Tags to Imported PNGs" markers: "0": "Recap and set the stage for the day plumbing in the asset loading" "65": "Review CheckForArtChanges() in terms of over-imported asset avoidance" "212": "Review WriteModificationsToHHA() with the determination to extract information from, and tag, assets" "276": "Enable WriteModificationsToHHA() to insert assets into the .hha files" "740": "Make WriteModificationsToHHA() tag assets with their existing tags" "1070": "Provide the option for the Win32OpenFile callback to conditionally open files with read or write access" "1521": "Consider consolidating down the platform_api" "1702": "Make all necessary functions use our new Win32OpenFile options" "1783": "Run the game and determine to embark on the new tagging scheme" "1836": "Set up to assign tags to assets, introducing ReserveTag()" "1994": "Consider using the old school tags for now, with thoughts for the new tagging scheme" "2114": "Introduce the notion of an Asset_Hand, and begin by enabling CheckForArtChanges() to import just hands and append them to a dummy file" "2624": "Break in to CheckForArtChanges() to see that it skips because there's nowhere to append data" "2665": "Step in to GameUpdateAndRender() and note that the dtForFrame being a whopping 14 seconds is the cause of our camera bug" "2739": "Make GameUpdateAndRender() clamp the dtForFrame to relieve it of doing an excessive amount of updating after stalls" "2849": "Run the game to see that the simulation updates tractably after having been "stalled" by CheckForArtChanges()" "2908": "Consider the .hha file naming and creation scheme for newly imported assets" "3357": "Setup to conditionally create local.hha if we're in a HANDMADE_INTERNAL build" "3663": "Create hhaedit.cpp as a dedicated asset creation utility" "4016": "Note the ability to do magic values as strings enclosed in single-quotes" "4078": "Run hhaedit to see how it all works" "4116": "Run the game and hit the AssetCount mismatch assertion in AllocateGameAssets()" "4432": "Enable AllocateGameAssets() to handle TagCount and AssetCount of 0" "4496": "Step into CheckForArtChanges() and follow hand_skeleton.png down the import pipeline" "4849": "Step back through CheckForArtChanges() to see that we already have errors on entering Win32WriteDataToFile" "5027": "Make AllocateGameAssets() only read in an .hha file if the TagCount != 0" "5069": "Step through AllocateGameAssets() to the success of WriteAssetData()" "5271": "Introduce SetAssetType()" "5522": "Embark on the tagging problem, introducing import_grid_tags for ProcessTiledImport() and CheckForArtChanges() to use" "6387": "Try making AddPlayer() add an Asset_Hand" "6421": "Run the game to see that it doesn't find our Asset_Hand" "6449": "Test the entire asset import process, to see that it works, but we have RGB flipped" "6502": "Try reloading the game to hit our AssetCount mismatch assertion in AllocateGameAssets()" "6526": "Delete local.hha and successfully run the game" "6556": "Q&A" "6595": "Q: I've been looking into existing approaches to assign items to cells for clustered shading. I've already implemented two of them, but now I'd like to try iD's approach. They mention in their SIGGRAPH slides that an item shape can be an OBB or a frustum and they test its planes against the cells in clip space since a cell will simply be an AABB there. I should really improve my math knowledge / skills but I currently don't know how to do this. Can you point me in the right direction?" "6791": "Understanding perspective projection and clip coordinates" "7103": "Performing operations in clip space" "7281": "Describe PerspectiveProjection()" "7374": "Q: Is the warning in the ctime code supposed to be taken lightly? How would it delete files, format my hard drive, etc? Has there been any instance of any of that thus far?" "7413": "Q: I see that transient_state has only four task_with_memory, and game uses much more threads. So the threads may sit there without work because you can only submit at most four such tasks per frame to queue. Isn't four tasks a bit low, or am I missing something here?" "7443": "Show the profiler's thread view" "7492": "Q: Thanks for answering. The way I understand their slides is they have a convex shape defined by its boundary planes (either a 6-plane OBB or a 5-plane frustum) and they test it against an AABB in clip space. The AABB is already in clip space and the planes come from world space. I have no idea how to test for intersection in clip space. What even happens to the planes when they are transformed?" "7672": "Plane transformation" "7827": "Close down with a plug of the site and glimpse into the future" --- name: "day465" title: "Updating HHAs from V0 to V1" markers: "1": "Recap and set the stage for the day" "107": "Take a look at the .hha files in our data directory" "186": "Demo hhaedit creating a new local.hha file" "240": "Run the game, hit our AssetCount mismatch assertion in AllocateGameAssets(), and plan out the day" "328": "Dive into debugging the asset updating bug" "443": "Make WriteModificationsToHHA() account for the initial null asset" "553": "Create a new .hha file, run the game twice and again hit our AssetCount mismatch assertion in AllocateGameAssets()" "581": "Separate the AssetTypeCount from AssetCount in WriteModificationsToHHA()" "739": "Perform our .hha creation / game running cycle, and again hit the AssetCount mismatch assertion in AllocateGameAssets()" "811": "Create a debug directory containing only the data and our created local.hha" "895": "Step through AllocateGameAssets() and inspect our local.hha to see that the OnePastLastAssetIndex is wrong" "1037": "Make WriteModificationsToHHA() correctly set OnePastLastAssetIndex" "1079": "Note the F8 command-completion shortcut in Command Prompt" "1112": "Create a new local.hha and ensure that we're all good" "1308": "Determine to write out our metadata and nail down the tag situation, and consider the possibility of enabling hhaedit to upgrade our .hha file format" "1451": "Dive into tagging, possibly storing tags for entire sprite sheets rather than individual sprites" "1712": "A few words on trying different solutions to problems" "1888": "Consider importing assets as named by the artist" "1981": "Art Space" "2329": "Integer-based IDs, that may later be associated with picking" "2357": "Merging of asset packs, and hierarchical tags" "2553": "Asset annotations" "2701": "Introduce hha_asset_markup struct for asset annotations, and add a Tag_Primacy asset_tag_id" "3040": "Augment our hha_header with Annotations (renaming hha_asset_markup to hha_annotation) setting us up for HHA file format upgrading" "3220": "Consider whether we need TypeIDs on our assets at all" "3409": "Consider using TypeIDs to partition the assets" "3470": "Add Tag_DataType asset_tag_id and an asset_data_type_id enum" "3614": "Set up to perform .hha file format upgrading, creating handmade_file_formats.h and separating the .hha struct version into their own files" "3751": "Introduce ReadHHA(), WriteHHA() and FileExists()" "3972": "Research file existence checking in the CRT" "4150": "Implement FileExists() and set up to dump the .hha file contents to stdout" "4620": "Augment loaded_hha with TagCount and AssetCount, and hha_annotation with SourceFileBaseName, AssetName, AssetDescription and Author, and their counts" "4778": "Implement ReadHHA() and dump the MagicValue and Version to stdout" "5198": "Run hhaedit -info to see our info dump" "5221": "Create a fresh dummy.hha and check out its mini info dump" "5271": "Make ReadHHA() read in the file using ReadEntireFile() before extracting the MagicValue and SourceVersion and conditionally calling ReadHHA_V0() or ReadHHA_V1()" "5586": "Enable ReadHHA_V0() to read in and upgrade the .hha file to version 1, and augment loaded_hha with a Valid boolean" "6664": "Implement WriteHHA()" "6946": "Consider our need to copy data from the data store forward" "7108": "Introduce loaded_hha_annotation for ReadHHA_V0() to use" "7246": "Define our hha structs as the old ones" "7382": "Run it and hit our InvalidCodePath in AllocateGameAssets()" "7509": "Step through AllocateGameAssets() and inspect the File to see that it's using the wrong sizes" "7567": "Correctly pragma pack the hha structs everywhere and redefine HHA_VERSION 0" "7626": "Run it to see that we're loading correctly" "7683": "Augment hha_annotation with FileDate, SpriteSheetX and SpriteSheetY" "7777": "Q&A" "7796": "Q: So, instead of tags, why not relegate the logic of picking a range, or random bunch, of specific assets to the part that pulls assets in - e.g. when making a new entity or what have you, have a way to specify hey pick one from these specific assets here (by path / name or some other identifier). Obviously comes with its own issues, might not be what you want, and all but is it an idea you've entertained?" "7944": "handmade_hero Do you have any plans about adding scripting? Which language you going to use for scripting in case if you have such plans (or will everything be C / C++ only)?" "7955": "Q: Are we going to use typedef for the enums? Also, is an unnamed union inside a struct legal in terms of ANSI C?" "8028": "Q: Will HHA contain hashes / checksums for original input files? This might allow a nice way to only update the changed assets, even if file timestamps are off" "8042": "Augement hha_annotation with SourceFileChecksum" "8114": "Q: If the entity holds a reference into a table that looks up the asset then that would work with hotloading, no?" "8126": "Art Space" "8148": "Also, what I meant was go away with the specific code-side defined tags and leave picking down to reference specifically by path or asset name that's based on the source asset file" "8169": "Q: I implemented an animation system based on your tag system where every animation frame is tagged with a number between 0-tau and as the t value loop goes up it says "hey go get the next sprite" but not sure if this is a good idea? Do you see any problems with this, and / or how do 2D animation system normally know which sprite to grab?" "8306": "Close it down" --- name: "day466" title: "Loading and Displaying HHA Files as Text" markers: "1": "Recap and set the stage for the day continuing with our modder-friendly asset file format" "143": "Dive into the code with a few words on the asset annotations, and the determination to augment the hha_asset struct with data conducive to moving assets between packs" "423": "Augment hha_asset with DataSize and DataType" "673": "Introduce CTAssert() (compile-time assertion)" "995": "Provide the ability to use CTAssert() multiple times, by appending __LINE__ to its test struct" "1476": "Use CTAssert() on our hha_asset, hha_annotation, hha_tag and hha_header structs" "1561": "Introduce flag32() and enum32() for hha_asset, hha_sound and hha_tag to use, for documentation purposes" "1781": "Set up to finish the asset importer" "1973": "Include the necessary data from hha_annotation in loaded_hha_annotation" "2115": "Introduce WrapZ() and ConstZ() as a way to turn a null-terminated string into a count-string, for ReadHHA_V0() to use when setting the DefaultAnnotation" "2419": "Set up to dump our HHA info" "2487": "Enable hhaedit to print the TagCount, AssetCount and presence of Annotations" "2558": "Check out our HHA printout" "2566": "Introduce PrintHeaderInfo() and a -dump flag" "2683": "Check out our -info and -dump" "2703": "Demo TabView from the Handmade Fund's bonus pack" "2809": "Introduce PrintContents() to print our HHA data indented for viewing in TabView" "3091": "Enable ReadHHA_V0() to read in all the asset types" "4175": "Dump our HHA info and take a look at it in TabView" "4207": "Enable PrintContents() to print the Tags" "4383": "Check out our dump in TabView" "4420": "Enable ReadHHA_V0() to read in the tags" "4461": "Check out our dump in TabView to see some UNKNOWN tags" "4492": "Fix the TagCount in ReadHHA_V0()" "4502": "Check out our dump in TabView to see that our tags are correct" "4507": "Try dumping test2.hha to see that it has no tags" "4580": "Try dumping intro_art.hha to see that it looks like we're working properly" "4625": "Enable PrintContents() to print out all the information, introducing PrintTag()" "5531": "Check out our more detailed dump in TabView" "5574": "Make PrintContents() flip the x and y when printing "Tags: x at y"" "5634": "Check out the dump of testfonts.hha" "5679": "Prevent PrintContents() from printing the tag field if there are no tags" "5715": "Check out the dump of testfonts.hha" "5817": "Q&A (not quite)" "5847": "Enable PrintContents() to print the Annotations" "5893": "Check out the dump of testfonts.hha with its annotations" "5927": "Enable PrintContents() to print the AssetDescription and Author, wondering whether %llu is the correct identifier, with a meta-comment on metaprogramming" "6124": "Check out our further annotated dump of testfonts.hha" "6132": "Q&A" "6146": "Q: I would suggest using static_assert(bool_condition, "message"); instead of CTAssert. It is a C++11 feature and it is supported by MSVC2013 (you are using other C++11 features already now anyways)" "6181": "Change CTAssert() to be a static_assert" "6309": "Q: Regarding CTAssert: Do you have a trick for getting a number for __FILE__ to use in the struct name (assuming you don't have a trick for using that in the struct name)?" "6402": "Q: You have "one past alst" in your output" "6408": "Fix typo in PrintContents()" "6421": "Q: In an earlier episode of Handmade Hero (around day 160), you answered a question regarding your plan on splitting Handmade Hero into two parts – first, writing the engine; second, writing the game – and there was a clear divide. Do you still see you moving towards that goal, or do you feel it is better, when you move to game code, to still work on the engine to add features?" "6480": "Q: How to deal with concurrency in C++?" "6644": "Q: Why is hha version 1 still important? Is it only to convert the (few) existing assets?" "6677": "Q: How do you feel about the progress of Handmade Hero so far?" "6711": "Q: Should I learn C or C++ first? Is there any good advantage that C++ offers?" "6811": "Q: Given that static_assert is a language feature and you can't really implement it yourself, why not just use it?" "6820": "Q: Remember to lookup printf() stuff" "6871": "Q: I know we haven't done much with in-game text in this series yet, but could the asset system be used as is for storing story text, etc., tagged with language tag for translation and other relevant data tags? Maybe we would want custom tags for storing language codes? Or do you think it better to make a different system specifically for this purpose? Also, TabView is looking cool. All it needs now is the iconic Handmade Hero dark theme" "6932": "Q: Out of curiosity, why OnePassedLastAssetsIndex. Would not, e.g. AssetCount or NumberOfAssets be more readable?" "6954": "Q: Maybe you could add the line to the message? Or did it print line numbers" "6969": "Q: Does the CTAssert fail if we have two asserts in two files at the same line?" "7001": "Q: I'm interested in knowing how downloading a patch or DLC is getting installed and changes how existing code works. Would that be covered at the end?" "7035": "Q: How did you recompile / reload a dll when LoadLibrary seems to keep a lock on the file? Any tricks or just copy the dll?" "7054": "Q: Why not use -1 instead of 0 as an array length to get harder error in assert?" "7066": "Make CTAssert3() use array length of -1" "7107": "Q: long long is not the same as int64_t type (it is 64-bit but gcc / clang will still complain that %llu does not match uint64_t). The "proper" way is to include which provides compiler specific PRIu64 string literal (as define), so you need to do printf("%" PRIu64, value);" "7156": "Q: Doeo the preprocessor parse before #include directive and then resolve the __LINE__ after the include is parsed? I still do not get why the preprocessor, that can be powerful, is so bad" "7191": "Demo line number resolution" "7317": "Compile it to see our error reported to be on line 278" "7338": "Demo use of the #line directive" "7423": "Q: The good news is that starting with C99 printf() supports u modifier for size_t - so "%zu" or "%zx" would work" "7457": "Replace %llu with %zu in hhaedit.cpp" "7477": "Check out the dump of testfonts.hha to see that %zu works" "7517": "Q: Have you ever changed the line number / file name in that way in an actual project?" "7541": "Oops, "z" modifier. What was changed? I missed it..." "7564": ""%zu" will work only for size_t type, not uint64_t type" "7575": "Change PrintContents() to cast some values to size_t" "7647": "Close it down in the hopes that that's okay" --- name: "day467" title: "Updating the Game to HHA Version 1" markers: "1": "Recap and set the stage for the day" "33": "Check out our testfonts.hha in TabView" "133": "Introduce WriteHHA_V1()" "379": "Make WriteHHA_V1() clear the Header, with a few words on maintaining an updatable binary file format" "501": "Continue to implement WriteHHA_V1()" "1542": "Introduce WriteBlock() and WriteString()" "1727": "Implement ReadHHA_V1(), introducing RefString()" "2240": "Try to check out test1.hha in TabView" "2374": "Document -dump and handle unsupported program invocations" "2420": "Check out test1.hha in TabView" "2441": "Test rewriting test1.hha into test1_v1.hha" "2487": "Check out our dump of test1_v1.hha in TabView to see that it looks right, but for the absence of the asset name" "2688": "Fix WriteHHA_V1() to correctly write the asset name" "2706": "Rewrite test1.hha as test1_v1.hha and check out its dump in TabView, to see that it all looks right" "2746": "Enable querying assets by their type for full backwards compatibility" "2981": "Introduce TruncateBeforeExtension() for ReadHHA_V0() to omit ".hha" from the asset name" "3131": "Rewrite test1.hha as test1_v1.hha and check out its dump in TabView, to see that it all looks right" "3161": "Remove TruncateBeforeExtension() to RemoveExtension() and introduce RemovePath()" "3265": "Rewrite ..\data\test1.hha as test1_v1.hha and check out its dump to see our asset names without the full path" "3316": "Enable ReadHHA_V0() to load in all the old tags" "3544": "Rewrite test1.hha as test1_v1.hha and check out its dump to see some UNKNOWN tag names" "3575": "Add "BasicCategory" to TagNameFromID" "3596": "Rewrite test1.hha as test1_v1.hha and check out its dump to see fewer UNKNOWN tag names" "3604": "Prevent ReadHHA_V0() from processing the tag of the zero asset" "3638": "Rewrite test1.hha as test1_v1.hha and check out its dump to see all of our information" "3651": "Organise our dump files, wondering why 4coder is not a drop target" "3741": "Rewrite all of our .hha assets to v1 versions, and check out their dumps to see that everything seems kosher" "3853": "Run the game to see that it breaks failing to load our v1 .hha assets" "3897": "Enable WriteModificationsToHHA() and everyone else in the game to handle v1 .hha files" "4367": "Make AllocateGameAssets() straight up set FontBitmapIDOffset" "4545": "Investigate why AllocateGameAssets() checked each asset to see if it is a font glyph before setting FontBitmapIDOffset" "4706": "Replace FontBitmapIDOffset with AssetBase in asset_file, and propagate this change" "4944": "Continue to enable AllocateGameAssets() to handle v1 .hha files" "5290": "Step in to AllocateGameAssets() and inspect our Assets to see that everything seems pretty good" "5498": "Run through to the game to see that everything imported correctly, except that the fonts are messed up" "5645": "Make AllocateGameAssets() offset the AssetBase by -1 to account for the initial null asset" "5692": "Run the game to see that the fonts are now good" "5784": "Consider the next step: populating our asset source file information directly out of the .hha file" "6043": "Q&A" "6063": "Q: Have you tried lldb? I use that at work and it seems to be stable" "6140": "Q: How come the shaded debug window with the graphs makes transparent pixels around the main character white?" "6165": "Q: Why is the "there is no file" there if it's in the way all the time?" "6180": "handmade_hero If you need to run a bunch of regexp substitutions on huge chunks of your codebase, how you go about it?" "6355": "JimerinoRustlerino you need Q:" "6393": "Q: There was this issue with the glyph count printed the wrong way around" "6416": "Fix the font printout in PrintContents()" "6438": "Q: Not really a question, but why EFI? What problem did they make up to have EFI solve?" "6476": "Q: Yes, the BIOS standard" "6499": "BIOS, EFI (Extensible Firmware Interface) and UEFI (Unified EFI)" "6803": "Q: Bit of an off-topic question: I found your talk about GJK (which was really great!) and implemented it for my project but now I don't know what to do to "resolve" collisions when I detect them. What should I do?" "6894": "Q: Can you give advice for someone who wants to drop out of college (CS undergrad) and just finally get a programming job? Or is it a big no-no nowadays to do so?" "7397": "Q: I am a bit confused by your answer, because I have booted from USB on pre UEFI systems. Am I missing something?" "7512": "Q: Can you give an overview of how you have structured your web programming in C? I've heard you mention it in some stream on how you made certain components behind the Handmade Hero website in C or at least more-sanely programmed than most web frameworks. It really interests me, could you give some more info?" "7839": "handmade_hero How about learning some online courses at python or something, and contributing to open source at GitHub (documentation fixes)?" "7846": "Q: You talked about people needing to know C++ to be hired for programming jobs these days. Did you mean OOP C++ with compile times linked to lunch-breaks? Do you think you would need to bone-up on newer C++ to do such a job?" "8042": "handmade_hero How can you create a interesting portfolio for backend developers? I can't make fancy sites because I know nothing about design" "8053": "Gauge the performance of Mailjet's newsletter sign-up form" "8465": "Compare the performance of Molly Rocket's mailing list sign-up form" "8562": "Portfolio creation tips" "8702": "handmade_hero Have you read "Out of the Tar Pit"? It seems to resurface lately for some reason" "8709": "Q: Have you checked out kore.io (web server written in C)?" "8742": "handmade_hero: libmicrohttpd is pretty good, as far as I can tell" "8749": "Q: Do you have any advice for a programmer having trouble to adjust to a OOP way of thinking on the job and how to cope with or handle patterns. Thank you" "8788": "Q: Follow-up question: What kind of projects would be interesting for recruiters to look at? For example, at the moment I am working on a 3D rasterizer in x86 assembly using mode 13h with a DOS emulator. I don't know if that is interesting, because it is so legacy-like but I like doing it and reading the Michael Abrash stuff about it" "8899": "handmade_hero They can't tell you because then you could just try mails and see if they are subscribed, leading to data breach" "8976": "Q: Your subscribe form is not GDPR compliant. You need to add an unchecked-by-default checkbox with "I want to subscribe" text and add double verification emails" "9180": "GDPR has a section dedicated to it" "9417": ""If you have not previously unsubscribed, a confirmation email will be sent"" "9465": "Q: If he unsubscribes, he has to accept the terms again (a checkbox) when he enters the email address and wants to subscribe again" "9543": "Q: Why not just have an FAQ with the fact that if you don't receive the subscription mail and have unsubscribed before, you have to send a mail?" "9566": "Propose responding identically to email addresses which have already been put on the mailing list or unsubscribed" "9671": "Close it up" --- name: "day468" title: "Handling Annotation Data During Import" markers: "0": "Recap and set the stage for the day cleaning up the asset importing" "175": "Continuing thoughts on asset tagging" "386": "Run the game and consider hhaedit's ability to upgrade .hha files" "496": "Note our desire to get art into the game" "597": "Determine to persist hha_annotation information across runs of the game" "871": "Two solutions to the problem of storing and sharing .hha file information: 1) In a separate file; 2) Directly in the .hha file" "1001": "Determine to make the asset loader care about annotations" "1067": "Augment the asset struct with an hha_annotation and enable AllocateGameAssets() to read these in from file" "1451": "Consider how to build the asset_source_file information" "1826": "Make AllocateGameAssets() read in our needed annotation information when an .hha file is open for editing, handling the error in which two assets occupy the same slot in a spritesheet" "2656": "Augment asset_source_file with a FileCheckSum and prepare AllocateGameAssets() to set the lowest FileDate" "2816": "Introduce GetOrCreateAssetSourceFile() and StringHashOf()" "3265": "Make AllocateGameAssets() call GetOrCreateAssetSourceFile(), and fix up compile errors" "3395": "Consider annotation loading done, and set up to write that information back out" "3442": "Enable WriteModificationsToHHA() to write our annotations to file" "3980": "Enable ProcessTiledImport() to set the relevant annotation information, augmenting import_grid_tags to contain Name, Description and Author strings" "4751": "Introduce WriteAssetString()" "5002": "Rename PushString() to PushStringZ() and introduce a new PushString() that pushes an entire null-terminated string" "5222": "Checksums" "5517": "Introduce CheckSumOf() for CheckForArtChanges() to call and set the FileCheckSum" "5649": "Introduce a version of StringHashOf() that takes a string" "5686": "Point out the checksum algorithms BLAKE and SHA-2" "5828": "Note in CheckSumOf() to put a full hash function" "5850": "Run the game fine" "5897": "Q&A" "5914": "Q: How often are assets updated? What are the performance characteristics you're aiming at?" "6038": "Q: Would you suggest any resources that cover modern C++ memory management very well? I tend to overuse unique_ptr" "6091": "Q: You already have an adler32 function written out in the PNG parser, why not use that?" "6139": "Q: If I wanted to run the game locally, is the steps I need to run the test_asset_build first? And then we could run the hhaedit to update to v1 if we wanted?" "6154": "Q: Looking at struct hha_annotation could we append the authors of assets into the credits for the assets in the current run of the game?" "6166": "Q: Pre-stream off-topic: GL swizzling with GL_TEXTURE_SWIZZLE_R/G/B/A works fine with GL v3.3 and higher. Even for core profile. Before v3.3 it works only if extension is present. So you get whatever channel (R/G/B/A or 0/1 constant) into any channel you want" "6238": "Q: What are your thoughts on the Rust programming language?" "6247": "Q: I thought you added it along with the Huffman compression? They go hand in hand" "6285": "Q: This is in GL core spec" "6310": "Q: Is C++ memory management bad "for games" or "just bad"? If the latter, what's a good general purpose memory management strategy for C++?" "6603": "Q: Do you use any of the Handmade code on your 1935 project?" "6728": "Q: Will you be changing your fonts to be packed bitmaps rather than a bitmap per glyph? If not, how would you store the UVs for the glyphs in the HHA file?" "6770": "Q: Have you tried the Opus codec, by the way? Though it might be even more complex than Vorbis" "6807": "Q: Is it necessary to use pragma pack (push) and pop for the hha structs? Is it okay to use 0 instead of '\0' for the string null terminator?" "6882": "Why does Vorbis suck? (Not being skeptical, I just don't know)" "7024": "Here's a comparison if somebody is interested" "7051": "Thoughts on code complexity of audio decoders" "7288": "Q: 47024 lines and counting" "7409": "We are done for today" --- name: "day469" title: "Downsampling Imported Assets" markers: "1": "Recap and set the stage for the day" "122": "Research fast, good file hash: xxHash" "321": "Check out MurmurHash" "786": "Introduce MurmurHashUpdate() as a MurmurHash3 and a 64-bit version of RotateLeft()" "1213": "Introduce MurmurHashFinalize()" "1314": "Consult the MurmurHash3 repo for the constant values suitable for 64-bit hashing" "1782": "Enable MurmurHashUpdate() to perform the mixing step from the 128-bit MurmurHash3" "1864": "Reflect on our chosen hash function and our unfortunate inability to gauge its strength" "2046": "Implement CheckSumOf() as a MurmurHash3, permissively unaligned and for little-endian machines" "2516": "“I'm just going to leave it like this, and everyone who has a big-endian machine can eat on it”" "2521": "Finish implementing CheckSumOf()" "2562": "Decide against making ReadHHA_V0() produce the file's checksum" "2656": "Set up to test our importing" "2687": "Create and inspect a new local.hha" "2747": "Step in to AllocateGameAssets() and follow the asset importing process" "2891": "Address the failed TagIndexInFile == TagCount assertion in WriteModificationsToHHA()" "2963": "Create a new local.hha and step through WriteModificationsToHHA()" "3086": "Fix WriteModificationsToHHA() to skip the null asset entry, and copy out the source tags" "3150": "Continue to step through WriteModificationsToHHA() into the game" "3183": "Check out our local.hha dump in TabView to see UNKNOWN types" "3326": "Make ProcessTiledImport() set the Type" "3408": "Run the game, check out our local.hha dump and see that the bitmap types are now set" "3471": "Step through AllocateGameAssets() to see if we correctly check for changes" "3566": "Make AllocateGameAssets() set the asset BasicCategory" "3684": "Recreate local.hha" "3725": "“Oh, Blue Angels again today”" "3731": "Check the local.hha dump in TabView to see our BasicCategory settings" "3769": "Determine to swizzle the R and G channels, and downsample our assets" "3839": "Downsampling of Art Assets" "4021": "Streaming in assets from disk" "4203": "Solving the streaming-from-disk problem by downsampling or compressing" "4419": "Oversampling art as a future-proofing measure" "4502": "Set up to downsample our assets" "4729": "Enable ProcessTiledImport() to downsample our assets and swizzle their R and B channels" "5556": "Run the game without downsampling to see our asset" "5602": "Run the game downsampling by 2, to not see our asset" "5631": "Check the local.hha dump in TabView to see nothing obvious wrong" "5690": "Make ProcessTiledImport() stride through the pixels differently, and delinearize their colour" "5803": "Run the game to see parts of our asset" "5842": "Fix ProcessTiledImport() to correctly stride through all the rows" "5910": "Run the game to see our asset, and consider that they do not have premultiplied alpha" "5965": "Insert some investigative code in ProcessTiledImport() to determine whether or not the assets have premultiplied alpha" "6086": "Break in to ProcessTiledImport() and watch the MaxBlueAlphaDiffC, to deduce that the alpha is not premultiplied" "6170": "Make ProcessTiledImport() multiply each pixel's alpha into its colour" "6320": "Run the game and hit a long delay" "6388": "Check out the nice clean edges on our asset" "6421": "Run the game a second time, and test it all in -O2" "6558": "Q&A" "6591": "Q: At the end of the y loop of the downsample, shouldn't it be SourceBuffer0 = SourceBuffer1 + PrevDim; SourceBuffer1 = SourceBuffer0 + PrevDim; and x and y advancing by 2?" "6661": "Q: You added a comment for handling big-endianness for residual value when calculating hash, but I feel it is important to mention that the same comment should apply also for *At dereferencing in the loop. Loading u64 from byte array will also be affected by endianness and hash value will be different" "6710": "Make the big-endian comment apply to the whole of CheckSumOf()" "6759": "Q: (Off-topic) Are you the founder of Molly? How long ago did you start working there?" "6782": "Q: Does Anna draw Vector graphics initially and would you consider rasterising vector graphics in the asset system or at startup for a game like this?" "6863": "Q: What sort of precision would we be losing by doing the downsamples from each other and doing srgb->linear->srgb, rather than, say, doing the linear conversion at the start and keeping it in linear, and doing the linear->srgb only when writing out each file?" "6988": "Q: (Off-topic) Any suggestion / resource about how to implement a networking layer from scratch for massive multiplayer games?" "7006": "Q: I guess that’s a fun thing for me to test out" "7146": "Q: (Off-topic) Just curious, are there any games that require more accurate or complex digital filters on the image than those of bilinear or other approximations? Like any sort of sharp low pass filter, etc?" "7249": "Q: Could you explain again the rotation to the left in the bit pattern you used?" "7321": "Q: I was thinking about a shooter. But let's think that we want to support multiplayer (over network) for Handmade Hero" "7381": "Q: (Off-topic, a bit) Can you give a quick description of the filter you designed? I'm fine with heavy DSP jargon" "7421": "Q: There are no rotate left / right SSE / AVX intrinsics?" "7500": "Q: My girlfriend appreciates how much you hate on Microsoft and Windows (since I scream about it day in and out), but she said your keyboard sounds like someone's peeing in the next room and it has ruined my life" "7538": "Q: But when client updates using server's incoming updates, assuming client simulates locally, it can create discontinuation if simulation diverged. Maybe in Handmade Hero it cannot diverge that much, though" "7658": "You can just lerp between the client state and the server update" "7691": "Q: Would you need the brush strokes or would vector graphics from a conversion tool work? In Adobe Illustrator there is a quick and dirty conversion tool that I found works nicely for high-res cartoony graphics to vector graphics" "7732": "Shut it on down" --- name: "day470" title: "Separating the Renderer Completely (Part 1)" markers: "0": "“Welcome to Handmade Hero, the game where we code a complete show on stream”" "12": "Set up for the special two-stream day separating out and finalising the renderer for use in a new project" "284": "Determine to perform Snuffleupagus-Oriented Programming, creating our dream sample program to drive API development" "386": "Add a renderer test bed compilation line to build.bat" "514": "Create win32_renderer_test.cpp as a trimmed down version of Handmade Hero's Windows platform layer" "1183": "Create handmade_types.h, replacing global_variable with global" "1450": "Run the game just as normal" "1458": "Set up new win32_renderer_test project" "1671": "Run Handmade Hero Renderer Test to see nothing happen, as expected" "1684": "Incorporate a trimmed down Win32ProcessPendingMessages() in to win32_renderer_test.cpp" "1762": "Run the Renderer Test and successfully resize and close the window" "1776": "Create win32_handmade_opengl.cpp to consolidate all our OpenGL code" "2351": "Temporarily make win32_renderer_test.cpp use stdio.h string functions in place of the game's custom ones" "2596": "Continue to consolidate our types and OpenGL code" "2898": "Include handmade_math.h and handmade_intrinsics.h in win32_renderer_test.cpp" "3185": "Create handmade_software_renderer.cpp to contain all the software renderer code" "3393": "Rename our render files in a more organised fashion" "3516": "Merge handmade_render.{cpp,h} and handmade_render_group.{cpp,h} into handmade_renderer.{cpp,h}" "3909": "Run the game okay" "3926": "Pull out the parts of the renderer that are wedded to the platform layer" "4311": "Temporarily make win32_renderer_test.cpp use further stdio.h string functions in place of the game's custom ones" "4599": "Consider cleaning up the lighting box data" "4912": "Return from OBS crash" "4929": "Move the LightBoxes from game_render_commands to render_group and relieve the operating system of allocating them for us" "5503": "Prevent PushLighting() from being called twice, also moving handmade_render.{cpp,h} and handmade_render_group.{cpp,h} into the "retired" directory" "5712": "Run the game to see the lighting working just fine" "5748": "Determine to generalise texture management" "5849": "Change win32_renderer_test.cpp to be OpenGL only" "6064": "Set up to test the OpenGL memory allocation" "6152": "Enable win32_renderer_test.cpp to allocate OpenGL buffers" "6376": "Step through win32_renderer_test.cpp to see that all is okay" "6585": "Make win32_renderer_test.cpp call PushFullClear() and hit the situation where we need to talk to the renderer" "6762": "Q&A" "6804": "Q: Are you going to check the recording that ended in an app crash?" "6857": "Q: Is Vulkan worthwhile for the performance gain over OpenGL?" "6932": "Q: Will you take this opportunity to implement the d3d backend?" "6966": "How long is lunch break?" "6983": "Q: Are there practical solutions to reducing the fill rate in the software renderer?" "7019": "Q: Isn't every graphics API just a middleman?" "7144": "Q: How do you recommend a beginner get better at writing platform layers? Is the only way to just write a bunch of them to figure out the common patterns?" "7164": "Q: I'm one of the Linux people. Please don't give us Vulkan" "7253": "Close it down for a timezone-appropriate meal" --- name: "day471" title: "Separating the Renderer Completely (Part 2)" markers: "1": "Set the stage for the day making the texture system optional" "134": "A few words on ping-ponging between the renderer test bed and the full game, to gradually work the code away from the game, like in cookery" "256": "Pull out non-generic parts of handmade_renderer.h into handmade_math.h and handmade_renderer_software.h" "798": "Work towards the removal of loaded_bitmap from handmade_renderer.h in favour of a unified texture API" "1135": "Introduce renderer_texture to replace loaded_bitmap, propagating this replacement" "1796": "Run the game to see textured rendering" "1808": "Move loaded_bitmap out of handmade_renderer.h to guide our replacement of it" "2290": "Create handmade_asset_rendering.cpp to contain the Handmade Hero-specific functions from handmade_renderer.cpp" "2457": "Replace loaded_bitmap with software_texture" "2660": "Change the hardware renderer to use renderer_texture directly" "3018": "Run the game and encounter a "GL_INVALID_OPERATION" OpenGL Error" "3069": "Fix RendererTextureFrom() to use the TextureHandle" "3097": "Run the game successfully" "3122": "Remove RendererTextureFrom() in favour of passing Bitmap->TextureHandle to PushQuad() and PushCube()" "3146": "Try to include handmade_renderer.cpp in win32_renderer_test.cpp, and set up to push our lighting solution into the renderer" "3268": "Move lighting_point_state, lighting_box and LIGHT_POINTS_PER_CHUNK into handmade_renderer.h" "3334": "Try to let win32_renderer_test.cpp call PushFullClear()" "3359": "Run the renderer test, see no clear colour and investigate why" "3392": "Make win32_renderer_test.cpp use PushFullClear() as the game uses it, performing the depth peel" "3495": "Run the renderer test to see our clear colour" "3514": "Add a camera in win32_renderer_test.cpp" "3774": "Call PushCube() in win32_renderer_test.cpp" "3833": "Run the game and see no cube" "3884": "Set CameraDolly to 10.0f" "3892": "Run the game, see the cube and tweak the camera parameters" "4011": "Consider how to proceed, tackling texturing" "4221": "Set up win32_renderer_test.cpp to load a bitmap for passing to a texturing system" "4672": "Make cube_test.bmp and sprite_test.bmp" "4923": "Step through LoadBMP() in win32_renderer_test.cpp to see our bitmap loaded successfully" "4948": "Set up to submit our textures to the renderer as two types: odd-sized (slower) and 512×512 (faster)" "5263": "Consider how to structure the two-tiered textured quads" "5470": "Pull AddOp() and related structs into handmade_renderer.{cpp,h}" "6309": "Run the game and crash in AtomicAddU64()" "6342": "Fix WinMainCRTStartup() to set the GameMemory.TextureQueue" "6361": "Run the game successfully" "6368": "Determine to make the renderer use a fixed number of textures, to remove notion of allocating / deallocating textures, in favour of only updating them" "6568": "Introduce renderer_texture_group and renderer_memory_layout" "6966": "Q&A" "6991": "Q: How would you approach front-to-back rendering?" "7044": "handmade_hero Yes" "7086": "Q: Is including a cpp file generally a bad idea?" "7163": "Q: Is it possible to make variadic functions in C, when compiling without a LIBC?" "7474": "handmade_hero Including varargs.h doesnt pull in libc" "7505": "Q: Why would the person you are helping not want to use a game engine if they are not too experienced with 3D programming?" "7636": "Q: Kinda new to the stream, but did you do any sort of batch rendering (like rendering once by storing into a texture)?" "7688": "Q: Does the current renderer support arbitrary meshes or shaders?" "7727": "Q: When the texture is sent to the GPU is it a 1:1 size ratio or does it get compressed" "7751": "Q: Did you noticed that the stream went down for a minute at around minute 45 of this stream?" "7806": "Q: Thoughts on a simple handmade OBS?" "7882": "Q: Would this texture system solve our binding texture timing?" "7899": "Q: Where do you buy your cool hats?" "7918": "Q: Stupid question, but would there ever be a need to use compute shaders in the game, or are we staying away from this side of the API?" "7940": "Q: I mean the time spent in glBindTexture()" "7989": "Q: Can we get another Lemongrab impersonation for my compilation?" "8163": "Q: Why did you change to Visual Studio editor? You were using something else before, I think" "8177": "Q: Any idea on how to handle different textures when using instancing rendering? Pack all the textures in an array and write a custom sampler?" "8240": "Q: Sorry to ask a noob question, but why do your function signatures use the internal keyword?" "8262": "Q: Do you know if DX12 is going to be needed for making use of the new hardware ray tracing stuff? What alternatives exists, and is it going to be worth it?" "8351": "Q: And there is a reason for that, Casey: if you include any cpp it will break as they define their version of internal somewhere in the STL" "8401": "Q: What's wrong with STL?" "8619": "Invasive list?" "8742": "Close down shop" --- name: "day472" title: "Making a Simple Scene with the Separated Renderer" markers: "0": "Recap and set the stage for the day cleaning up the renderer's API" "50": "Texture handling" "218": "Texture atlases and mipmapping" "390": "Our potential to lean on the streaming system for texture handling" "543": "Keep Reminder.txt open" "585": "Run the Renderer Test with the determination to render textured cubes and sprites" "641": "Consult a screenshot of Hartacon Tactics" "916": "Introduce PushSimpleScene()" "1214": "Run the Renderer Test to see our world of cubes" "1221": "Make PushSimpleScene() push blue cubes" "1257": "Run it to see our blue world" "1280": "Make our camera orbit the world" "1329": "Run it to see our orbiting perspective of the world" "1352": "Apply a texture to our cubes" "1723": "Enable OpenGLManageTextures() in handmade_renderer_opengl.cpp to fully manage the textures, introducing DequeuePending() and EnqueueFree() in handmade_renderer.h" "2105": "Wait-free vs ticketed mutex" "2157": "Finish implementing EnqueueFree() and OpenGLManageTextures()" "2481": "Run the game to see that we're not running okay" "2500": "Introduce InitTextureQueue() in handmade_renderer.h" "2736": "Run the game okay, with scepticism on this texture initialisation code" "2833": "Call OpenGLManageTextures() in win32_renderer_test.cpp" "2862": "Run the Renderer Test to see our textured cubes" "2916": "Select a tree and forest asset" "3161": "Change LoadBMP() to take a renderer_texture and load our forest tile into the test" "3315": "Run the test to see our textured ground" "3356": "Load our tree sprite into the test and enable PushSimpleScene() to sprinkle them around the scene" "3461": "Consider making PushBitmap() part of the renderer proper" "3550": "Introduce PushBitmap() in handmade_renderer.cpp" "3581": "Consider relieving PushBitmap() of the need to shrink bitmap borders in favour of making the software renderer upload textures into a bordered region" "3801": "Rename PushBitmap() to PushSprite() and clean it up" "4212": "Try making PushSimpleScene() call PushSprite() for our trees" "4294": "Run the Renderer Test, see no trees and step into PushSprite() to see what it's computing" "4373": "Prevent PushSimpleScene() from pushing cubes" "4386": "Run it to see our trees" "4392": "Enable PushSimpleScene() to elevate sprites above the cubes" "4448": "Run it to see our trees above the ground cubes" "4477": "Make PushSprite() centre the sprites on the cubes" "4544": "Run it to see our centred trees" "4555": "Grow the trees in PushSimpleScene() and scatter them randomly" "4583": "Run it to see our scattered trees" "4610": "Make the camera pan rather than orbit" "4903": "Run it to see our panning camera" "4951": "Widen the scene and shrink the trees in PushSimpleScene()" "4971": "Run it to see our scene, feeling like the trees aren't quite pegged to the centre" "5042": "Enable PushCube() to map our texture to the faces of the cube" "5331": "Run it to see our textured cubes, and reconsider the sprite centring" "5441": "Enable PushSimpleScene() to push Krampus' head and walls" "5655": "Check out our scene" "5673": "Make PushSimpleScene() position Krampus unit forwards and apply the correct texture to the walls" "5714": "Run it to see Z-fighting" "5730": "Make PushSimpleScene() elevate the walls above the ground by their radius" "5759": "Run it to see trees intersecting wall geometry" "5864": "Make PushSprite() bias the Z of upright sprites by their entire vertical size" "5876": "Run it to see how that looks" "5895": "Reduce the WallRadius in PushSimpleScene()" "5932": "Run it to see the trees more correctly occluding the walls" "6006": "Make PushSprite() render the sprites without modifying their axes" "6067": "Run it to see the trees standing perfectly upright, but looking like cardboard cutouts" "6107": "Enable PushSprite() to lerp between modified axes" "6131": "Run it to see that it looks quite nice from this perspective" "6220": "Increase the camera pitch and bias the lerp towards the correct axes" "6348": "Check out how that looks" "6467": "Play with the camera focal length, pitch and position" "6733": "Run it to see everything stacking nicely" "6800": "Create win32_renderer_test.h and introduce test_scene struct, InitTestScene() and PlaceRandom()" "7460": "Run it to see our well-spaced scene" "7508": "Fix PlaceRandom() to space elements out more" "7523": "Run it to see our even better-spaced scene" "7602": "Q&A" "7612": "Q: Are we going to do anything special on Day 500?" "7660": "Q: The right side of the walls seems to be flipped vertically, I guess it's because of the UV ordering" "7673": "Q: Not a question, but I think you changed the meaning of the code in the EnqueueFree() function. The pending list is put back on the queue instead of on the free list (Queue->FirstFree)" "7690": "Fix EnqueueFree() to set the Queue->FirstFree" "7779": "Fix PushCube() to map our texture to the correct faces of the cube" "7968": "Run it to see that our wall textures look good" "8045": "Q: So I missed the stream today. What have we done with the texture generation today?" "8099": "Q: Are we done with the renderer or will we maintain both versions?" "8143": "Q: Handmade Hero will be using this decoupled renderer, right?" "8171": "Q: Would it be helpful in this situation to use the old school billboards that are two or three sprites in a + or X shape?" "8240": "Q: I assumed we weren't going to use the decoupled version, but that makes sense" "8327": "Build the game in -O2" "8344": "Run the renderer test" "8364": "Q: Would it be too much to attach the profiling stuff to just see the FPS etc?" "8376": "Enable win32_renderer_test.cpp to print the milliseconds per frame" "8660": "Run it to see our milliseconds per frame" "8695": "Reduce the TEST_SCENE_DIM_Y" "8727": "Run it to see our still-variable frame rate" "8762": "Increase the TEST_SCENE_DIM_Y" "8776": "Run it to see our just-as-variable frame rate" "8808": "Q: Did you update 4coder yesterday (if necessary)?" "8812": "Check our rendering performance" "8893": "Q: Why do the frames drop so badly when moving the window? Does Windows spam the process with messages or something?" "9004": "Enable win32_renderer_test.cpp to create a thread for the rendering separate from Windows' message processing" "9265": "Run it and reconsider our rendering performance" "9391": "Q: What is volatile?" "9561": "Q: Now the main thread should use GetMessage(), not PeekMessage(), to save on CPU" "9581": "Change win32_renderer_test.cpp to use GetMessage()" "9774": "Q: Could you go over the extra render thread thing briefly again, please? I thought the DC is thread-specific and so the OpenGL RC has to reside within the same thread" "9854": "Q: GetMessage should be GetMessageA" "9880": "Remove all the "A" function-name suffixes" "10007": "Q: Without A or W you'll depend on "project settings" whether Unicode is set or not, and people had a lot of issues on forums, when they used Handmade Hero code in Visual Studio projects" "10036": "Embark on Windows Unicode string handling" "10286": "Q: Try to #define UNICODE at top of file, to see if the compiler is happy" "10292": "Try to #define UNICODE and continue down the Windows Unicode rat-hole" "10825": "“So, great, good, fantastic, nice work. Great job, Microsoft, as always crushing it”" "10845": "Run it successfully" "10870": "Q: I think you need to also #define _UNICODE 1" "10919": "Reflect on the progress of our standalone renderer" "10993": "Make our camera orbit the world" "11079": "Run it to see our 2D sprites rotating erroneously" "11194": "Wind it down" --- name: "day473" title: "Removing Screen Coordinates from the Render Group" markers: "8": "Recap and set the stage for the day continuing our renderer API cleanup and addressing texture arrays" "222": "Run the Renderer Test and consider addressing the API call for rotation" "358": "Consider organising our source files into directories" "537": "Move the #include of handmade_memory.h out of handmade_shared.h" "857": "Move the #include of handmade_simd.h out of handmade_shared.h" "997": "Move the #include of handmade_intrinsics.h and handmade_math.h out of handmade_shared.h" "1102": "Migrate all our #include directives in win32_renderer_test.h to the top to clearly indicate all the files needed to use our renderer" "1315": "Further organise and document win32_renderer_test.cpp and win32_renderer.test.h for clarity" "1584": "Pull out some of PlaceRandom() into CountOccupantsIn3x3(), renaming the former to PlaceRandomInOccupied()" "1747": "Enable InitTestScene() to place trees in a quantity proportional to the available area" "1856": "Introduce PlaceRectangularWall() and IsEmpty(), for InitTestScene() to call" "2384": "Run it to see our rectangular walls" "2415": "Make InitTestScene() clamp our rectangular wall to a minimum of 2×2" "2431": "Run it and consider throwing more sprites into the scene" "2478": "Create test_cover_grass.bmp" "2598": "Enable InitTestScene() to load and PushSimpleScene() to push our test_cover_grass.bmp everywhere, one per tile" "2766": "Run it to see our grass, and shrink it down" "2812": "Enable PushSimpleScene() to randomly displace multiple grass sprites in each tile" "2945": "Run it to see our randomly displaced grass" "2948": "Crank up our sprite-count per tile" "2979": "Run it to see our scene looking bad, and begin to investigate why this is permitted" "3055": "Assert in PushQuad() that VertexCount <= MaxVertexCount" "3146": "Run it and do not hit that assertion" "3156": "Add an InvalidCodePath assertion in GetCurrentQuads(), unfortunately in the case that we don't blow out the vertex buffer" "3217": "Run it and hit that assertion, failing loudly" "3281": "Bump up the MaxVertexCount in RenderLoop()" "3290": "Run it and unexpectedly hit our new InvalidCodePath in GetCurrentQuads()" "3359": "Step in to GetCurrentQuads() and inspect the Commands" "3402": "Fix the location of our InvalidCodePath in GetCurrentQuads(), in the case that we do blow out the vertex buffer" "3430": "Run it to see our lower rendering performance" "3454": "Crank up our sprite-count per tile to really slow down our test program" "3499": "Set up to test whether the slowdown is in the renderer or our push calls" "3750": "Make RenderLoop() only call PushSimpleScene() once" "3837": "Run it to see that the OpenGL dispatch and rendering takes at least 89.91ms per frame" "3898": "Let RenderLoop() call PushSimpleScene() every loop" "3915": "Run it to see that our push buffer calls slow us down to 102.56ms per frame, noting that a fair test would omit camera rotation" "4002": "Revert our performance testing code with the determination to work on the API" "4052": "Document RenderLoop(), and change the profiling to only occur if we have a valid frame" "4222": "Run it to see that our performance ranges from 20.6 to 36.9ms per frame" "4264": "Introduce Win32SetVSync() to support conditionally setting VSync" "4337": "Run it to see that our performance still ranges widely" "4370": "Consult the NVidia Control Panel for VSync information" "4470": "Continue to document RenderLoop()" "4973": "Pull out the profiling code in RenderLoop() to InitFrameStats() and UpdateFrameStats()" "5318": "Run it successfully" "5344": "Document the profiling and camera in RenderLoop()" "5541": "Enable RenderLoop() to test the scene while orbiting and panning the camera" "5612": "Run it to see our camera orbiting and panning" "5701": "Make PushSimpleScene() confine sprites to their tile" "5728": "Run it to see our grass sprites confined to their tiles" "5738": "Document our twofold camera test in RenderLoop()" "5806": "Consider how to package up the camera and render group code from RenderLoop()" "6083": "Consider relieving the renderer of using pixel coordinates, in favour of specifying clip rects in −1 to 1 screen space coordinates" "6391": "Run the game and note the reason why the debug overlay breaks the alpha compositing" "6459": "Set up to switch the renderer from pixel coordinates to −1 to 1 screen space coordinates, for the debug system clip rect and the lighting unproject to work in" "6497": "Switch the renderer from pixel coordinates to −1 to 1 screen space coordinates, introducing S32BinormalLerp() and respecifying GetScreenPoint() as GetClipSpacePoint()" "7131": "Run it to see that the lighting works, but the debug overlay does not" "7199": "Introduce ClipSpaceFromScreenSpace() to re-enable the debug system clicking" "7437": "Run it with clicking and clipping back online, and reflect on our improved API" "7541": "Q&A" "7590": "Q: Do you think you will ever get back to 60fps in the debug build, or at least a useable frame rate?" "7665": "Q: Do you want the renderer API to have a UI mode, basically a polished version of what the debug display is using now? So no interaction with the lighting system, perhaps using screen space coordinate system, etc. Or is this something that will always be for debug, and 2D stuff will need to be handled by some other means?" "7749": "Q: I mean for the other person who is using your render engine" "7808": "Q: I might have misunderstood but, in the renderer test/demo code I believe you created a function that checked for unoccupied spots but the name said Occupied? PlaceInOccupied I think you called it." "7815": "Rename PlaceRandomInOccupied() to PlaceRandomInUnoccupied()" "7859": "Q: On twitter, you said "All user interface design is an adaptive compression problem." What did you mean by that?" "7977": "Q: Going along with getting rid of unnecessary params, do the camera FOV, aspect ratio and near / far clip need to be passed every frame, or are you going to move them out to a one-time setup call?" "8044": "Q: Minor, but one of your comments had a grammatical error (is → it) around L620?" "8074": "Fix typo in RenderLoop() documentation" "8087": "Q: Hey Casey, how can I start with C++?" "8154": "Q: On comments: "use later with to figure out" is a few comments above. The "with" is obsolete" "8159": "Fix typo in RenderLoop() documentation" "8212": "Q: How you manage your dependencies in a C++ project?" "8245": "Q: Would you consider doing this sort of overhaul on any other parts of the code, like what you've been doing to the renderer?" "8335": "Q: Libraries" "8675": "Call it a day" --- name: "day474" title: "Removing the Transient State Concept" markers: "1": "Recap and set the stage for the day continuing our renderer API cleanup, with a few general words on API design" "183": "Walk through RenderLoop()" "307": "On offering user-controllable granularity in an API, including both low-level control of data and high-level utility functions" "442": "Consider enforcing a maximum of one depth peel per render group, and making depth peeling a toggle" "561": "Set up to make depth peeling a toggle, and consider removing the redundant notion of GenerationID which was previously used to prevent asset eviction during a frame they're being used" "750": "Change OpenGLRenderCommands() to call OpenGLManageTextures() at its end, and remove GenerationID from asset_memory_header and DEBUGGetMainGenerationID()" "1208": "Run the Renderer Test and the game successfully" "1253": "A few words on multithreaded texture transfer in OpenGL" "1298": "Make BeginRenderGroup() and EndRenderGroup() directly call BeginDepthPeel() and EndDepthPeel() respectively, introducing render_group_flags and eliminating DrawBuffer entirely" "2489": "Change the UpdateAndRender*() functions to take RenderCommands rather than RenderGroup and themselves open a RenderGroup using the passed RenderCommands" "2934": "Run the Renderer Test successfully, and the game unsuccessfully, crashing in BuildSpatialPartitionForLighting()" "3029": "Fix UpdateAndRenderWorld() to call LightingTest() before EndRenderGroup()" "3163": "Run the game successfully, but crash somewhere after OpenGLRenderCommands()" "3209": "Subsume transient_state into game_state, cleaning out the MainGenerationID and TranArena in favour of a general FrameArena" "4898": "Run the game successfully with the transient arena merged into the frame" "5064": "Run the game and successfully perform hot reloading" "5146": "Crash in StringLength() upon trying to open the profiler, and consider not unloading DLLs" "5194": "Return to debugging the cutscene rendering" "5339": "Remove lighting_textures TestTextures from game_mode_world in favour of making PushLighting() allocate and return lighting_textures" "5547": "Run the game, crash with the lighting_textures having been freed before the renderer is invoked" "5600": "Change GameUpdateAndRender() to clear the FrameArenaTemp only right before using it" "5696": "Continue to debug our cutscene" "5776": "Change UpdateAndRenderTitleScreen() and UpdateAndRenderCutScene() to instantiate a Render_Default RenderGroup" "5796": "Run our cutscene successfully, deducing that we do not currently support a lack of depth peels" "5883": "Q&A" "5897": "handmade_hero Hi, do you use some wrist support while typing and using mouse? Does it help?" "5930": "Q: Can you go through the rendering pipeline briefly, again? What are the RenderCommands and RenderGroups are used for and where do they get initialized? Then, what exactly is OpenGL doing with them?" "6109": "Q: Hidden triforces on the orphanage still the best" "6131": "Q: How can I start in game development, without knowing much about C++? How did you do it?" "6508": "Q: Can you recommend any game / engine source code that would be helpful to look over for general architecture, e.g. the Doom engine, etc?" "6572": "Q: As a reference, can you disclose how much you paid the artist for Handmade Hero (a general idea of it)?" "6765": "Q: Quake 2 is pretty interesting to go through. Does it matter that much that it is not multithreaded, because at least it is only around 120k lines of code and with Fabien's overview it is a good starting point, I guess?" "6871": "Q: Super off-topic, but as someone who is older and perhaps a lot more experienced than someone like me who is younger: do you have anything to say regarding interpersonal issues? Ever encounter people giving you issues, being rude? Even absolute bullies? Do you have any advice for that if one encounters that even as an adult in university or at their job?" "7017": "Q: I'll go ahead and recommend Doom 3 as a learning engine since, from what I can tell, it meets all the criteria you just suggested: on a modern API, has multithreading" "7116": "Q: Do you think the performance of the game would be fine on the Intel iGPU or in general the integrated GPU?" "7329": "Shut it down" --- name: "day475" title: "Abstracting the Renderer Interface" markers: "2": "Recap and set the stage for the day" "49": "Walk through our test RenderLoop() with a view to streamlining the camera and fog code, and cleaning up the drawing calls in PushSimpleScene()" "214": "Our framerate problems incurred by the lighting" "372": "Crank up the grass sprite count in PushSimpleScene()" "473": "Run the game and step in the RenderLoop() to see that we are using 184 bytes of our 64 megabyte-capacity PushBuffer" "555": "Reduce the PushBuffer size to 1 megabyte" "609": "Consider simplifying the PushBuffer out of the renderer API" "986": "Change open_gl to no longer be initialised as a global variable, but locally by Win32InitOpenGL()" "1729": "Introduce platform_renderer to generalise our renderer and decouple it from the OpenGL API" "2104": "Introduce GetWhiteBitmap(), and continue the API decoupling, renaming DefaultRenderCommands() to BeginFrame() and OpenGLRenderCommands() to EndFrame()" "2498": "Set up implement platform_renderer dispatching" "2569": "Change LoadBMP() to call AddOp() and take a renderer_texture_queue and renderer_texture rather than call QueueTextureOp() and take a platform_renderer" "2810": "Introduce AllocateTextureQueue() and ProcessTextureQueue() for RenderLoop() to call" "3017": "Implement AllocateTextureQueue(), setting it up to use the platform memory allocation call" "3143": "Remove AllocateTextureQueue() in favour of making RenderLoop() call InitTextureQueue(), allocating memory in that call using Win32AllocateMemory()" "3319": "Respecify InitTextureQueue() to take MemorySize, and itself compute the possible TextureOpCount to fit in that memory" "3489": "Rename MaxVertexCount to MaxQuadCountPerFrame in RenderLoop(), leaving the possibility open for the platform to specially allocate the memory" "3615": "Reorder RenderLoop() slightly" "3671": "Make Win32InitOpenGL() allocate our open_gl, adding PushBufferMemory and textured_vertex and renderer_texture arrays to this struct" "4089": "Demo C++ inheritance to abstract the renderer" "4298": "Abstract out the renderer dispatch with an enum in platform_renderer, for newly introduced Win32AllocateRenderer(), ProcessTextureQueue(), BeginFrame() and EndFrame() to switch on" "5253": "Introduce OpenGLBeginFrame(), adding WindowWidth and WindowHeight to game_render_commands, and stubbing out the various API-specific functions" "5934": "Run the Renderer Test and check out our memory usage, to see that we have reserved 1.5 gigabytes" "6080": "Step through RenderLoop() to determine that EndFrame() allocates this memory" "6259": "Step through OpenGLEndFrame() into OpenGLChangeToSetting() to see that the first CreateFramebuffer() call reserves 300 megabytes" "6393": "Step in to CreateFramebuffer() to see that the glFramebufferTexture2D() call reserves 200 megabytes, and investigate whether this is reasonable" "6677": "Run the game and consider our high memory usage" "6809": "Temporarily disable multisampling in OpenGLInit()" "6829": "Run the game to see that it now only reserves 312 megabytes" "6849": "Re-enable multisampling in OpenGLInit() and reduce the grass sprite count in PushSimpleScene()" "6891": "Run the game, and compare the edge rendering with and without multisampling" "7083": "Disable pixelisation in OpenGLInit()" "7112": "Run the game and consider that enabled pixelisation to be a bug" "7133": "Switch Handmade Hero over to our abstracted renderer interface" "7971": "Run both the Renderer Test and game successfully" "8008": "Refresh our memories as to how the mouse position is handled" "8124": "Prevent DEBUGEnd() from calling ClipSpaceFromPixelSpace() to map the mouse coordinates" "8161": "Run the game to find that the clicking doesn't work" "8180": "Introduce ClampBinormalMapToRange() for WinMainCRTStartup() to clamp the mouse coordinates to -1 to 1 space" "8343": "Run the game to find that the mouse works again, but that the rotation and scaling controls are broken" "8371": "Tweak the camera rotation and zooming multipliers in UpdateAndRenderWorld()" "8482": "Change the Mouse coordinates in game_input to be one v3 called ClipSpaceMouseP" "8601": "Run the game to see that all is working, except for the positions of the debug system menus" "8674": "Reflect on our renderer API" "8747": "Make OpenGLChangeToSettings() responsible for setting VSync using a newly introduced PlatformOpenGLSetVSync()" "8998": "Run the game and the Renderer Test to gauge the VSync" "9094": "Run the Renderer Test in -Od to see that we do request that VSync is disabled" "9140": "Q&A" "9167": "Reflect again on our cleaner renderer API" "9225": "Q: Don't know if you've answered this before, but why do you make all of your functions internal? Some in chat were saying that doesn't seem to make sense in a unity build, but I'm just wondering for your general case" "9411": "Q: Not important, but I think that in your LoadBMP() function you're still declaring a renderer_texture result" "9449": "Q: Is there something about your render passes that prohibits hybrid AA techniques, like MSAA 4X plus conservative FXAA? MSAA 16X is way overkill" "9633": "Reduce MaxMultiSampleCount in OpenGLInit()" "9660": "Run the game to gauge our multisampling quality" "9830": "Q: Could you take a look at 'Typo in win32_render_test.cpp'" "9846": "Fix typo in PushSimpleScene()" "9916": "Q: The plants look worse with 8-bit" "9963": "Q: Have we used the malloc from CRT or have we always used Windows alloc? Is it okay to use the malloc in the game?" "10059": "Q: On "internal": sorry, I was just wondering on a more fundamental level. I only knew it makes that function only accessible from that translation unit (I may have this wrong), and I wanted to know what it did for you in general, not just in response to the unity build part. Or is that really all it does?" "10294": "We're all good" --- name: "day476" title: "Providing Convenient Camera Controls" markers: "0": "Recap and set the stage for the day continuing the renderer API cleanup" "85": "Determine to switch platform_renderer to use a table of function pointers, to enable loading of renderers from DLLs" "221": "Switch platform_renderer to use function pointers" "597": "Demo C++ virtual function calls" "798": "Enable RenderLoop() to use the functions pointed to in platform_renderer, introducing Win32LoadOpenGLRenderer()" "1044": "Run the Renderer Test to see everything working fine" "1058": "Switch Handmade Hero to use our function pointers in platform_renderer" "1091": "Run the game" "1134": "Export Win32LoadRenderer() – renamed from Win32LoadOpenGLRenderer() – to a DLL" "1543": "C++ name mangling" "1612": "Try to enable the compiler to export Win32LoadRenderer() by applying extern "C"" "1695": "Investigate why the compiler could not find Win32LoadRenderer(), using dumpbin" "1798": "Stop marking Win32LoadRenderer() as internal (static), to enable the compiler to find it" "1912": "Link all the necessary libraries to our DLL" "2015": "Check our newly generated win32_handmade_opengl.dll in dumpbin and depends, to see Win32LoadRenderer in there" "2130": "Enable RenderLoop() to load in our renderer DLL, introducing Win32LoadRendererDLL()" "2686": "Remove opengl32.lib from our CommonLinkerFlags" "2714": "Step through RenderLoop() and into the Renderer Test running in our external .dll" "2777": "Enable RenderLoop() to pop up a dialog box if we failed to find a renderer" "2926": "Delete win32_handmade_opengl.dll and run the Renderer Test to see our dialog box" "2968": "Introduce Win32InitDefaultRenderer() to wrap up the renderer DLL loading" "3114": "Switch Handmade Hero over to use our external renderer DLL" "3199": "Run the game using the external DLL, with a few words on the potential to create other renderers" "3256": "Determine to clean up the camera and sprite pushing API, and general code organisation" "3308": "Dive into cleaning up the camera API" "3745": "Introduce Translation() for our camera setup code to initialise the matrix" "3834": "Run the Renderer Test with the camera working just as before" "3866": "Fold the CameraOffset into the camera matrix initialisation" "4017": "Run the Renderer Test using our single camera matrix operation" "4045": "Simplify the camera setup code out into BuildCameraObjectMatrix() and GetStandardCameraParams()" "4445": "Run the Renderer Test to see the exact same result" "4469": "Continue to simplify the camera code out into ViewFromCamera()" "4604": "Run the Renderer Test, noting the simplicity of our camera API while retaining all the power" "4660": "Make SetCameraTransform() take fog_params and alpha_clip_params" "5263": "Run the Renderer Test to verify that we work with the fog and alpha defaults" "5277": "Try setting some fog_params in ViewFromCamera()" "5437": "Run the Renderer Test to see our fog, and play with the params, encountering some bugs with the sprite outlines" "5678": "Augment the camera struct with FogStart and FogEnd" "5927": "Run our fogged Renderer Test" "5944": "Augment the camera struct with ClipAlphaStart and ClipAlphaEnd for ViewFromCamera() to use" "6127": "Run the Renderer Test to see our alpha clipping" "6171": "Reflect on our newly simplified camera API, and consider getting rid of the render_group" "6383": "Q: 1:30pm" "6430": "Consider the reason for render_group" "6556": "Switch Handmade Hero over to our new camera API" "6597": "Run the game, noting that we've lost our fog and alpha clip" "6651": "Make UpdateAndRenderWorld() set the fog and alpha clip" "6768": "Run the game with our fog and alpha clip working" "6779": "Document our window setup" "6899": "Run the Renderer Test preserving the 16:9 aspect ratio" "6909": "Try setting the draw region to fill the entire window" "6924": "Run the Renderer Test to see that we correctly draw to the entire window" "6953": "Document the camera testing and texture downloading" "7217": "Q&A" "7272": "Q: How can I program a really good Windows Update system like Windows has that makes sure you update all the time especially if you are not home or are watching a movie right now?" "7471": "Q: (Off-topic) You mentioned in the pre-stream fetching the cache misses. Do you mind explaining how it's done?" "7490": "Q: Why do you want to remove the render group? What is the alternative? My following is a bit spotty so I am sorry if this is obvious from watching previous streams" "7531": "Q: What is your opinion on the Vulkan API? Is it overkill to use it for a little indie game or is it worth the thousands of setup code lines?" "7749": "Q: I mean memory cache misses" "7778": "Q: What steps are you going to do to optimize the renderer?" "7821": "Q: I'm making DOS games for fun. Have you had experience making games during the DOS era?" "7871": "Q: Sorry, I'll rephrase it. Is there a function that lets you know how many L1, L2, etc. cache misses happened since, for example, the last time you called the function?" "8093": "Q: After ending up with the renderer part, which do you thing is the next macro-step on Handmade Hero?" "8111": "Q: Do you ever see Linux as a consumer machine? I'd personally rather use Linux to play games than Windows or Mac, but in your Vulkan rant Linux was not mentioned at all" "8158": "Q: On Linux you can do that with "perf" utility. It does not require anything extra, kernel already provides this information" "8223": "Wrap it up" --- name: "day477" title: "Changing to Single Dispatch Per Pass (Part 1)" markers: "0": "Recap and set the stage for the day" "65": "Reacquaint ourselves with the separated renderer" "127": "Review win32_renderer_test.cpp" "268": "Determine to update the API of our primitive pushing functions, and accelerate texture processing using texture arrays" "530": "Set up to support camera-matched quads" "626": "Camera-matched quads" "680": "Temporarily change PushSimpleScene() to push trees as non-upright sprites, and run the Renderer Test to see the trees Z-fighting with the ground" "740": "Respecify and simplify PushSprite() as a non-upright sprite pushing function" "1069": "Run the Renderer Test to see all our non-upright sprites" "1072": "Introduce PushUpright() as a dedicated function that handles upright sprites" "1143": "Run it to see the grass as upright sprites" "1156": "Give PushUpright() default values for MinUV and MaxUV" "1272": "Camera-matched quads, placing 2D sprites in a 3D world" "1599": "Make PushUpright() interpolate the sprite axes between the world axes and camera-relative axes, running it to see the grass sprites rotating to follow the camera" "1698": "Attenuating the sprite's Y-axis for lay-down, while preserving the camera's X-axis" "1834": "Make PushUpright() use the camera's X-axis" "1876": "Run it to see the grass following the camera" "1886": "Change PushSimpleScene() to call PushUpright() for the tree sprites" "1909": "Run it to see the trees following the camera, until we crash when panning" "1982": "Add Shift to the camera struct so that the panning code can cold-set the Offset" "2101": "Run it to try and see if the panning is working correctly" "2140": "Change PushSimpleScene() to use the (rectangular) wall sprite instead of the tree, to help debug the sprite lay-down attenuation" "2168": "Run it to see that the wall sprites are not slanted" "2174": "Make PushUpright() use 0.25 × the world axes for the sprite's Y-axis" "2188": "Run it to see our correctly tilting sprites, but their insufficient camera-facing rotation" "2225": "Temporarily make PushSimpleScene() skew the wall sprites" "2320": "Run it to see our skewed walls sprites erroneously collapsing under rotation" "2400": "Enable PushUpright() to correctly attenuate the Y-axis of skewed sprites" "2842": "Subtracting the camera Z-axis to push the Y-axis into the screen" "2894": "Make PushUpright() normalise our hybrid Y-axis" "2913": "Run it to see the skewed sprites rotating to face the camera without collapsing" "2943": "Let PushSimpleScene() push the upright wall sprites using the default axes" "2963": "Run it to see the lay-down of the wall sprites not looking quite right" "3079": "Change PushUpright() to attenuate the sprite Y-axis towards the world's Z-axis" "3130": "Run it to see the lay-down looking better, and consider making the attenuation tunable by the artist" "3245": "Make PushSimpleScene() skew the wall sprites" "3264": "Run it to see that the wall sprites rotate without collapsing" "3303": "Make PushSimpleScene() use our tree sprites again" "3317": "Run it to see our rotating tree sprites" "3330": "Make PushUpright() attenuate the sprite's Y-axis 50/50 between the world and camera Y-axis" "3352": "Run it to see our 50/50 tree sprites" "3387": "Make PushUpright() attenuate the sprite's ZBias with the lay-down" "3658": "Run it to see our upright sprites without any Z-fighting" "3738": "Make PushUpright() take a tCameraUp and add a WorldUp to the render_group struct" "3912": "Run it to see it all working nicely" "3939": "Introduce cube_uv_layout struct to permit custom layouts to be passed to PushCube()" "4592": "Run it to see it all working fine" "4632": "Test custom cube texture layouts" "4917": "Run it to see our custom cube textures for the start and end of walls" "4963": "Change WallUV to use the mid-wall texture" "5003": "Run it to see our textured walls" "5020": "Prevent PushSimpleScene() from randomising the Z of wall elements" "5087": "Run it to see our textured and aligned walls" "5097": "Prevent PushSimpleScene() from varying the wall colour" "5132": "Run it to see our aligned, segmented wall" "5355": "Stress test the texture changing" "5385": "Run it to see our slowdown with the determination to figure out who is at fault" "5429": "Set up an Nsight project" "5562": "Run our Renderer Test in Nsight and trigger it to capture a frame" "5826": "Set up to fake sprite dispatch aggregation" "6112": "Switch OpenGLEndFrame() from using glDrawArrays() to sending down tri-strips using glDrawElements" "6282": "Tri-strip" "6315": "Finish switching OpenGLEndFrame() over to use tri-strips, guided by the OpenGL spec" "6769": "Run it to see our triangles wound backwards" "6790": "Fix our triangle winding in OpenGLEndFrame()" "6815": "Run it to see our correctly drawn scene" "6844": "Q&A" "6865": "Q: Primitive restart index is in GL Core since version 3.1: glPrimitiveRestartIndex() function" "6877": "Q: I thought you had to bind a GL_ELEMENT_ARRAY_BUFFER to do indexing, is this not true if no buffer is bound?" "6938": "Q: Using indices seems to take a lot more memory if the vertex data contains texture coordinates, normals, etc. How do you know when it's a good idea to render by indices?" "7036": "Q: I have one regarding vaualbus' pre-stream question if that's alright: Why were the next steps of investigations into the MessageBox call not working to try doing it with the indirect call, then next to do it on another thread? What was the line of thinking?" "7090": "Q: What is your opinion on texture arrays vs texture atlases? Why did you choose to do texture arrays?" "7222": "Q: Does the window size have anything to do with the tuning of the t value in the renderer, e.g. if we use the full screen window?" "7258": "Q: Texture arrays require all textures to be the same size and have the same number of mipmaps, though. Isn't that a significant limitation? Atlases require manual handling in the shader, but I feel like they're more general" "7311": "Q: What are we going to mipmap in Handmade Hero?" "7320": "Q: Off-topic: How long is fall break going to be?" "7331": "Q: There's a rewrite of Dependencies Walker for Windows 10. The old depends.exe is not up to date for Windows 10 dlls. You might find it useful for Handmade Hero" "7475": "Q: Do you know if texture sampling is implemented in hardware? If it's not, then I don't think manually handling atlases would be slower" "7617": "Q: This is just about paradigms: What sets apart the functions you have made to construct structs certain ways (like GetStandardCamera) from the methodology around constructors in C++ that I presume you dislike? Or are they actually similar?" "7666": "Demo C++ constructors, with an example of a better constructor" "8356": "API Granularity" "8503": "Q: You were selecting .NET executables in dependency walker, for which it won't show anything" "8512": "Q: Back to the message box pre-stream answer, removing the filtering of message 0x738 make the window appear" "8533": "Q: Are you testing the renderer with the PNG asset? Do you think the renderer would have a better performance with bitmap because the decoding of that is easier than the PNG one?" "8562": "Q: I'm not sure, but doesn't camera Camera = {} in C++ call the constructor? (I know it zeroes if it's a normal structure, but I think if it's a thing with a constructor it calls it)" "8598": "Q: Also, placement new returns a new "object" (in terms of C / C++ object lifetimes), so you technically need to access it through the pointer returned, so it is disgusting" "8615": "Q: Do you think you could submit a constructor like that to the C++ committee?" "8659": "“Working with the C++ committee would probably be more like rearranging the ice in the lemonade of someone who's holding a glass of lemonade on a deckchair on the Titanic. Like, you're not even gonna move the chairs. You're gonna be able to get, like, an ice cube moved around”" "8698": "Thoughts on proprietary software companies offloading QA to their users" "8919": "Time for lunch" --- name: "day478" title: "Changing to Single Dispatch Per Pass (Part 2)" markers: "0": "Recap our switch to texture vertex indices" "96": "Augment game_render_commands with an IndexArray, with a few words on the GPU's ability to cache vertex shader transforms" "449": "Remove renderer_texture_group and renderer_memory_layout, and pass our new IndexArray down the pipe, also augmenting open_gl with IndexArray and MaxIndexCount" "840": "Run the Renderer Test successfully" "852": "Reduce the MaxQuadCountPerFrame in RenderTest() and the (grass) CoverIndex in PushSimpleScene(), with a few words on breaking the problem into steps" "990": "Run the Renderer Test with our single vertex buffer working" "1011": "Augment render_entry_textured_quads with IndexArrayOffset for OpenGLEndFrame() to use the index buffer passed in" "1219": "Change OpenGLEndFrame() to call glBufferData() once, instead of while processing every render command" "1337": "Run it to see problems with the depth peeling" "1364": "Make OpenGLInit() generate a separate CompositeVertexBuffer and ScreenFillVertexBuffer" "1732": "Run it with the depth peel working correctly" "1743": "Revert the MaxQuadCountPerFrame in RenderTest() and the (grass) CoverIndex in PushSimpleScene() to their original high values" "1795": "Run it to see that it is much zippier" "1834": "Temporarily disable the lighting" "1875": "Run it to see that it didn't affect it much" "1911": "Make RenderLoop() disable the lighting" "1997": "Run it and gauge the performance with the lighting disabled" "2140": "Turn off all the grass and augment open_gl with an IndexBuffer for OpenGLEndFrame() to use, rather than initialising Indices itself" "2731": "Make PushQuad() fill our new IndexBuffer with the VertIndex" "2948": "Run it without crashing, but also without seeing anything" "2977": "Fix OpenGLEndFrame() to pass GL_UNSIGNED_SHORT to glDrawElements()" "3036": "Run it to see that our triangle must be wound wrong" "3046": "Triangle winding" "3085": "Fix the vertex winding in PushQuad()" "3089": "Run it to see that it looks about right" "3098": "Let OpenGLEndFrame() texture our quads with their bitmaps" "3118": "Run it to see that it looks about right" "3125": "Switch OpenGLEndFrame() to perform one draw call per scene, using the white bitmap for each sprite" "3201": "Run it to see that our performance has improved" "3296": "Re-enable all the grass with a view to overcoming the unsigned short vertex buffer index limit" "3340": "Run it and hit our VI == VertIndex assertion" "3383": "Enable GetCurrentQuads() and PushQuad() to handle more than 65535 / 4 quads using glDrawElementsBaseVertex()" "3881": "Run it to see that it looks good" "3929": "Let OpenGLEndFrame() texture our quads with the grass bitmap" "3966": "Run it to see that we now don't have any performance spikes" "4110": "Begin to switch the renderer over to use texture arrays, first enabling the vertex shader to understand the notion of a vertex index" "4724": "Run it successfully" "4731": "Switch OpenGLAllocateTexture() to specify a feed-forward texture array, calling glTexSubImage3D()" "5889": "Switch Handmade Hero over to use the renderer's new texture array" "6301": "Run it and hit an OpenGL error: "Texture name does not refer to a texture object generated by OpenGL"" "6368": "Temporarily add a TextureHandles array to the open_gl struct" "6522": "Run it to see our tree-texture scene" "6540": "Remove the TextureHandles in favour of sampling slices into the lone texture array" "7325": "Run it and hit an OpenGL error: "Invalid texture format"" "7418": "Prevent OpenGLInit() from allocating the WhiteBitmap, and make it specify a texture level of 1 when calling glTexStorage2D()" "7469": "Run it to see it all working with the correct textures, just that they are not always correctly sized" "7646": "Run Handmade Hero to see that it has issues" "7689": "Remove the WhiteBitmap from the renderer in favour of allowing the game itself to specify it if needed" "7916": "Enable AllocateGameAssets() in Handmade Hero to create its needed WhiteBitmap" "8124": "Augment the renderer_texture with Width and Height for PushQuad() to use and so fix the texture sizing, renaming TextureHandle() to ReferToTexture()" "8833": "Make PushQuad() scale the texture UVs based on their sizes" "8954": "Run the Renderer Test and Handmade Hero to see that the textures are correctly sized" "8977": "Define TEXTURE_ARRAY_DIM" "9042": "Run it, doing texture arrays" "9082": "Q&A" "9106": "Q: Are there any benefits to using PBOs for async texture transfers these days? I've heard that drivers copy texture data into their internal memory anyway, so the call returns immediately and behaves as if it were asynchronous" "9267": "Q: In GL Core Profile you need to generate all "names" (textures, buffers, FBO, ...). Only in Compatibility Profile you are allowed to provide your own "name" values" "9289": "Q: Unrelated: What's the recommended way to deal with Windows doing an infinite WindowProc loop while moving or resizing a window? My current approach is to jump in and out of the event processing loop with fibers. Is there something less hacky?" "9374": "Q: You probably would want to replace glTexStorage3D() call with glTexImage3D(). TexStorage is from OpenGL 4.2 version (or ARB_texture_storage extension). TexStorage differs from TexImage in a way that its texture properties (size / format) are immutable – it cannot be changed once texture is created. It may help performance but often it does not change" "9418": "Replace glTexStorage3D() with glTexImage3D()" "9604": "Q: Do you still multiply the offset in the glDrawElementsBaseVertex() call? Because I never do it and never had any problem, so I don't understand what's going on" "9859": "Q: Please show glTexSubImage3D() call that fails" "10058": "Q: It needs to be GL_RGBA or whatever (value does not matter, because it is for last argument pixel data, which is NULL, so no data specified)" "10108": "Q: "does not matter", as long as it is valid, nonzero" "10189": "Q: I think glTexImage3D() is the failing call. Can you please check the call stack again at crash time?" "10305": "Wrap it up with the determination to find out why we can't use glTexImage3D() here in OpenGLInit(), and a plug of Casey and Chris Hecker's upcoming talks at Busan Indie Connect Festival 2018" --- name: "day479" title: "Large Texture Support" markers: "0": "Recap and set the stage for the day" "131": "Plug Meow Hash" "239": "Try to run the game but crash in OpenGLManageTextures()" "297": "“Forget the recap, we've got work to do, folks.”" "309": "Investigate the crash in OpenGLManageTextures(), to find that a fresh rebuild does not crash" "648": "Run the Renderer Test noting that we have adequate throughput" "738": "Run the game and note our new absence of support for large textures in our texture array" "865": "Approaching the problem of handling large textures now that we have a fixed-size texture array" "1023": "Consider mipmapping our sprites" "1173": "Run the Renderer Test and try to see scaling artifacts that could be fixed by mipmaps" "1401": "Set out our strategy for handling large textures" "1609": "Add a renderer_texture array to render_entry_textured_quads to special-case our rendering of large textures" "2138": "Enable GetCurrentQuads() to handle large textures, adding a stretchy renderer_texture *QuadTextures buffer to game_render_commands, introducing IsSpecialTexture() and stubbing out GetSpecialTextureHandleFor()" "3269": "Run the Renderer Test and the game successfully" "3315": "Enable LoadBitmap() to handle special large textures, introducing DimensionsRequireSpecialTexture() and SpecialTextureIndexFrom()" "3901": "Add SpecialTextureHandleCount and NextSpecialTextureHandle to game_assets and enable AllocateGameAssets() to handle special large textures" "4158": "Enable OpenGLAllocateTexture() to handle special large textures, introducing TextureIndexFrom()" "4357": "XOR vs AND NOT" "4562": "A few words on demythologising programming and the truth of making mistakes" "4770": "Continue to enable OpenGLAllocateTexture(), Win32InitOpenGL() and OpenGLBeginFrame() to handle special large textures" "6174": "Run the game and crash in OpenGLInit()" "6248": "Fix Win32InitOpenGL() to allocate the asset and texture handle arrays before calling OpenGLInit()" "6281": "Run the game nominally correctly, before switching to the cutscene and crashing in OpenGLAllocateTexture()" "6353": "Step through LoadBitmap() to see what happens with the large textures" "6541": "Fix DimensionsRequireSpecialTexture() to correctly handle textures that are larger than standard on either axis (rather than both)" "6557": "Run the game, switch to the cutscene and hit our Assert(TextureIndex == Texture.Index) in PushQuad()" "6633": "Fix PushQuad() to peel off the handle from the texture in stages, first as a u32, then cast down to a u16" "6672": "Run the game and crash in OpenGLEndFrame()" "6823": "Fix GetCurrentQuads() to set the IndexArrayOffset, and change OpenGLEndFrame() to use this offset accordingly" "7064": "Run the game without crashing, but see no cutscene textures" "7243": "Step in to OpenGLEndFrame() and inspect the Texture" "7261": "Fix PushQuad() to actually push on special textures" "7350": "Run the game, see that the Texture at this point in OpenGLEndFrame() looks a lot better, but that we don't see the cutscene textures in-game" "7426": "Q&A" "7456": "Q: Commands-> should be Entry-> on the line where it breaks. Commands was leftover and not updated to Entry" "7487": "Fix OpenGLEndFrame() to set the special Texture from the Entry, rather than from the Commands" "7495": "Run the game and still see no cutscene textures" "7597": "Q: How do you handle attributes and varyings for your GLSL?" "7674": "A few words on the need for a language that offers the ability to read in material written in another language (e.g. GLSL), and use the types defined in that material directly, noting that Jon Blow's JAI has this ability" "7798": "“Did insobot just say "Domo arigato, Mr. Compiler"? Because if so, then that is the new high watermark for artificial intelligence”" "7812": "Q: Casey my man, what are the stats on your glasses?" "7873": "Wrap it up" --- name: "day480" title: "Debugging Large Texture Support" markers: "0": "Recap and set the stage for the day debugging our large texture implementation" "87": "Refresh our memories on the additional multiple-dispatch slow path for arbitrary sized textures" "197": "Continue to investigate the incorrectness in the multiple-dispatch path" "400": "Try making OpenGLInit() and OpenGLAllocateTexture() use GL_TEXTURE_2D_ARRAY for special textures" "529": "Run the game and crash in OpenGLAllocateTexture()" "548": "Fix OpenGLAllocateTexture() to allocate one slice" "567": "Run the game and crash in OpenGLEndFrame()" "594": "Make OpenGLEndFrame() use a GL_TEXTURE_2D_ARRAY for special textures" "619": "Run the game without crashing, but also without seeing any cutscene textures" "708": "Change GameUpdateAndRender() to boot directly into the cutscene" "820": "Capture a frame with Nsight and inspect the events" "1137": "Praise NVIDIA for Nsight's event filter" "1175": "Continue to check out our glBindTexture events" "1264": "Break in the special texture path in OpenGLEndFrame() successfully" "1310": "Correctly set the working directory" "1360": "Check out the glBindTexture event for our GL_TEXTURE_2D_ARRAY" "1558": "Consult the documentation on glTexImage3D" "1574": "Make OpenGLAllocateTexture() pass 0 as the level to glTexImage3D()" "1649": "Run the game and see imagery" "1706": "Make PushQuad() correctly compute the UV coordinates for special textures" "1792": "Run the game and see our cutscene texture more correctly, but without animation or alpha blending" "1908": "Begin to investigate the bug in the alpha blending of large textures" "2133": "Step into PushQuad() and inspect the vertices" "2350": "Try making PushQuad() set the TextureIndex of special textures to 0" "2402": "Run the game to see that that doesn't solve the transparency problem" "2474": "Make OpenGLEndFrame() unbind the GL_TEXTURE_2D_ARRAY" "2678": "Run the game, see no difference and consider capturing a frame" "2712": "Try skipping the depth peeling altogether when rendering the cutscene" "2835": "Run the game to see that the cutscene layers do get composited, but still without alpha blending" "2928": "Try making RenderLayeredScene() draw the cutscene layers in the opposite order" "3000": "Run the game to see that this changed the zoom speed, but had no effect on the transparency" "3053": "Revert RenderLayeredScene() to draw the cutscene in the original order" "3099": "Capture a frame of the cutscene, scrub through the events and inspect the shaders" "3554": "Toggle on ALLOW_GPU_SRGB" "3690": "Run the game to see that that still works okay, but the cutscene also remains unaffected" "3863": "Capture a frame and scrutinise the fragment and vertex shaders" "4248": "Try making CompileZBiasProgram() hard set the FogAmount and AlphaAmount to known values" "4274": "Run it to see no effect" "4285": "Try making CompileZBiasProgram() hard set the SurfaceReflect.a to 0.5" "4302": "Run it to see no alpha blending" "4452": "Capture a frame and inspect the draw buffer settings" "4960": "Remove CompileDepthPeelToLighting() and other cruft from the OpenGL code" "5281": "Run the game and Renderer Test to see that we didn't bust anything" "5390": "Refrain from binding the OpenGLColor_Emit and OpenGLColor_NPL handle types" "5510": "Run the game to see that the background colour is now incorrect" "5577": "Remove the NPL samplers from CompilePeelComposite()" "5690": "Run the game to see that the background colour is correct again, and capture a frame to see our intended single colour target" "5782": "Determine to investigate the positional corruption as exhibited by the draw order of the cutscene layers" "5985": "Make OpenGLEndFrame() call glDrawElementsBaseVertex() directly in the special texture path" "6145": "Run it to see that it's looking a little better" "6161": "Make RenderLayeredScene() draw the layers in the original order" "6172": "Run it to see that the cutscene plates are now correct, but the alpha blending is still not happening" "6249": "Capture a frame and take a closer look at the pixel operations to see that alpha blending was turned off the whole time" "6457": "Make OpenGLEndFrame() call glEnable() at the end of a depth peel" "6507": "Run the game to see that the cutscene alpha blending works beautifully" "6761": "Greatest Handmade Hero Episode! A real hands on example of an ordinary day of a graphics programmer" "6812": "Q&A" "6858": "Q: Missed what was preventing the parallax movement; could you point that out again real quick? Also is it just me or is the gamma off a little on the cutscenes? It looks a bit washed out to me" "6914": "Toggle off ALLOW_GPU_SRGB" "6963": "Q: In the OpenGLAllocateTexture(), in the non-special texture case, you're calling the GetTextureIndexFrom() to mask off the special texture bit, but at this point you know that this bit isn't set, or am I reading this incorrectly?" "6986": "Q: Do you have the story for the game all written / thought out or are you still working on it?" "7023": "Wrap it up" --- name: "day481" title: "Encoding Cube UVs" markers: "2": "Recap and set the stage for the day focusing on the asset system" "264": "Determine to decorate the world and bind assets to entities" "680": "Open "Fog is broken!" issue" "771": "A few words on learning GitHub for Meow hash" "829": "Determine to work on asset binding, using Snuffleupagus-Oriented Programming" "1065": "Snuffleupagus-Oriented Programming (SOP)" "1182": "Set up to bind assets to entities" "1499": "Change the multi-dimensional version of AddPiece() to take a v3 Dim" "1825": "Run the game to see that all is well and good" "1939": "Introduce EncodeCubeUVLayout()" "2786": "Consider the visibility of our art, with an eye to the possible future existence of floor tiles that reflect the undersides of tiles above them" "2961": "Make EncodeCubeUVLayout() encode the BottomIndex and BottomFacingIndex in the final two bits of our UV layout, and PushCube() decode UV layouts" "3878": "Enable PushCube() to directly decrypt coordinates without a table lookup" "4438": "Switch the Renderer Test over to use our new UV layout" "4575": "Run the Renderer Test to see that we may have got our bottom and top reversed" "4596": "Fix PushCube() to offset the top faces by 0.75" "4622": "Run the Renderer Test to see that everything looks correct" "4629": "Test our UV encoding by making PushSimpleScene() rotate the WallEndUV by 90°" "4663": "Run the Renderer Test to see the wall end top-facing texture rotated 90°" "4673": "Further test the UV encoding by rotating the full WallUV by 270°" "4796": "Enable PushCube() to correctly decode negative offsets for the bottom and top faces" "4866": "Orientation of Textures" "5013": "Fix CubeDecodeX() and CubeDecodeY() to rotate textures 90° anticlockwise from 0 to 3" "5112": "Run the Renderer Test to see that the rotation is good" "5141": "Reflect on the bandwidth saving of our layout encoding" "5207": "Augment entity_visible_piece with a CubeUVLayout for AddPiece() to set" "5488": "Consider supporting mirroring" "5592": "Move on to asset tagging, possibly using a two-tier system: 1) select asset set; 2) use entity information to pick asset from set" "6080": "Introduce the notion of an asset_basic_category" "6721": "Run the game with a view to building import tables to bind textures to our scene" "6803": "Q&A" "6831": "Q: In the Renderer Test, the corner blocks that are on the side of the building have their diagonal beams reversed, due to sharing their texture with the front blocks. Do you have a plan for handling that?" "6877": "Change the cube_uv_layout struct to just be a u16 to future-proof the renderer, and enable the Renderer Test to set UV layouts for elements" "7484": "Run the Renderer Test to see the current texture layout" "7508": "Enable PlaceRectangularWall() to explicitly lay out the lower-left corner texture" "7647": "Run the Renderer Test to see the lower-left corner texture correctly rotated" "7708": "Enable PlaceRectangularWall() to explicitly lay out the lower-right corner texture" "7778": "Run the Renderer Test to see the lower-right corner texture correctly rotated" "7792": "Enable PlaceRectangularWall() to explicitly lay out the far corner textures" "7860": "Run the Renderer Test to see all our exterior wall textures correctly rotated" "7967": "Enable PlaceRectangularWall() to decorate the horizontal interior walls" "8109": "Run the Renderer Test to see no interior beaming" "8170": "Fix typo in PlaceRectangularWall()" "8231": "Run the Renderer Test to see interior beaming" "8270": "Enable PlaceRectangularWall() to decorate the vertical interior walls" "8580": "Run the Renderer Test to see beaming everywhere" "8639": "Q: When will you use the new 4coder update?" "8659": "That's it for today" --- name: "day482" title: "Associating Tags with PNGs" markers: "0": "Recap and set the stage for the day improving our asset system" "134": "Run the game with the determination to texture our world" "223": "Set up to associate asset file contents with tags" "636": "Introduce ProcessSingleTileImport() performing functionality pulled out of ProcessTiledImport() into WriteImageToHHA() and DownsampleToFits()" "2272": "Change ProcessMultiTileImport() to include the border when extracting a tile, and introduce import_source_info" "3047": "Run the game and crash in ProcessMultiTileImport()" "3117": "Step in to ProcessMultiTileImport() and inspect the TileImage" "3181": "Fix ProcessMultiTileImport() to loop over the TileImage" "3200": "Run the game to see that it's close to working" "3243": "Investigate the possibility that we have an offset problem" "3592": "Introduce GetDownsampleCountForFit() and introduce Downsample() that takes a DownsampleCount, to make sure all tiles get downsampled the same amount" "4074": "Run the game to see that it still works as before" "4089": "Set up CheckForArtChanges() to import orphanage wall textures" "4831": "Introduce ParsePieces() and ProcessPlateImport()" "5591": "Specify that an asset's filename determines its tags" "6275": "Introduce BeginTags() and EndTags() for ParsePieces() to call" "6819": "Make ParsePieces() perform multiple parsing passes, each pulling out particular pieces of information, and introduce PopToken()" "7286": "Implement BeginTags(), introducing TagIDFrom()" "7603": "“There's gotta be a "none", said the priest”" "7609": "Add a Tag_None asset_tag_id, and continue implementing BeginTags()" "8004": "Introduce AddTag() and fix up compile errors" "8249": "Implement AddTag()" "8860": "Step through ParsePieces() to see what happens" "9110": "Step through EndTags() into PopToken() to discover that our bug occurs in the final item" "9200": "Fix PopToken() to correctly parse out the full set" "9310": "Step through EndTags() and into the game with the skeleton hand mostly imported" "9385": "Fix AddTag() to correctly increment the TagCount and prevent tags from overwriting each other" "9539": "Run the game to see all facing directions of our skeleton hand imported correctly" "9587": "Try making UpdateAndRenderEntities() set the glove's MatchVector and WeightVector to 1 and 0.5 respectively, to see that it doesn't fix up our scaling issue" "9699": "Enable ParsePieces() to parse (wall) block textures" "9795": "Run the game to see that we may not have imported the block texture" "9826": "Step through ParsePieces() to see what it does with the block textures" "9893": "Make UpdateAndRenderEntities() pass the BitmapID to PushCube(), updating PushCube() itself to handle bitmaps" "10037": "Run the game to see no wall textures" "10117": "Try to break in to UpdateAndRenderEntities(), and find that our block texture has not been correctly categorised" "10343": "Fix ParsePieces() to set the import type for a block" "10368": "Run the game and see textured walls" "10437": "Rename the non-orphanage block textures out of the equation" "10486": "Run the game to see our orphanage texture, possibly upside-down" "10510": "Change GenerateRoom() to hard set the Color to all 1s" "10532": "Run the game to see deep blue textures" "10740": "Take a cursory look at ProcessMultiTileImport() for what could be wrong" "10829": "Call it" --- name: "day483" title: "Debugging Tagged PNG Imports" markers: "0": "Recap and set the stage for the day" "40": "Run the game to see our upside-down and blue-toned textures" "227": "The steps in the asset creation, packing, rendering process" "304": "Run hhaedit on our local.hha to see that we have some UNKNOWN tagging information, and consider adding dumpbmp functionality" "472": "Unify the NameTags and TagNameFromID tables in a newly created handmade_file_formats.cpp" "1026": "Introduce TagNameFromID() and TagIDFromName()" "1361": "Run hhaedit -dump on our local.hha to see all the tags filled in" "1395": "Rename the block* asset files back into the system and run the game to see them in there" "1543": "View our full local.hha in TabView, to see that these block* assets are not being fully tagged" "1676": "Add asset_tag_id and NameTags for the blocks, and rename their files using these tags" "2163": "Regenerate the asset pack and check it out in TabView" "2270": "Add asset_tag_id Tags to the entity struct for UpdateAndRenderEntities() to match on" "2746": "Run the game with no special tagging of entities" "2757": "Enable GenerateRoom() to tag entities, introducing AddTag()" "2978": "Run the game to see that we're not picking the desired textures" "3023": "Step in to UpdateAndRenderEntities() and inspect the asset matches" "3269": "Switch GetBestMatchAssetFrom() to a positive-matching scheme" "3480": "Run the game to see exactly the textures we wanted to see" "3524": "Dive into our investigation of the blue-shifted texture issue" "3914": "Capture a frame in Nsight and inspect the downloaded textures, to see that the R and B channels are swapped" "4112": "Scrutinise the texture submission code to see what's happening with the colour channels" "4451": "Regularise the texture row flipping and colour channel swapping in ExtractImage() for ProcessPlateImport(), ProcessSingleTileImport() and ProcessMultiTileImport() to call" "5109": "Run the game, importing assets afresh to see everything looking correct" "5241": "Add StoneFloor boolean in gen_room_spec for CreateOrphanage() to set and test asset picking" "5387": "Run the game to see stone-floored bedrooms" "5429": "Make GenerateRoom() randomise the texture UV layout" "5603": "Run the game to see variation on the walls" "5630": "Change GenerateRoom() to randomise floor tiles" "5642": "Run the game to see randomised floor tile textures and colours" "5714": "Temporarily make GenerateRoom() use the Color not of the textures but our cube geometry" "5728": "Run the game to see the red and green cube colours coming through" "5743": "Make GenerateRoom() reduce the texture colour application" "5786": "Run the game to see that we're looking pretty respectable" "5849": "Q&A" "5890": "Q: Will you update the test_asset_builder to version 1?" "5923": "Q: So was the reason for the blue that the PNG parser was swapping B and R when we did not need to?" "5978": "Q: Will you write any unit tests to QA yourself?" "6160": "Q: I've never streamed, so I'm not sure what's going on, but why are Jon's streams left in the videos tab, and yours aren't? I ask because I wanted to see yesterday's stream, but it isn't on YouTube yet" "6175": "Q: Will you tile the fonts as well then?" "6236": "Wrap it up with a glimpse into the future of game design" --- name: "day484" title: "Debugging Multi-tile Import" markers: "1": "Welcome and set the stage for the day" "17": "Set up to try cdbg and codeclap debuggers" "103": "A few words on the need for better ways to fund open-source tool development" "371": "On charging for your work, and possible ways to do this" "486": "A few preliminary words on cdbg and codeclap" "667": "Launch cdbg, with initial thoughts on its user interface" "809": "Step through optimised win32_handmade.exe, noting that we don't expect parsing of this binary to work" "901": "Step through debug win32_handmade.exe, noting that we're missing disassembly, but that it feels way snappier than the debugger we're used to" "1139": "Scour cdbg's list of keys for "set breakpoint by name"" "1308": "Set up to take a look at advanced features of cdbg, including linked list viewing" "1370": "Try out cdbg's fbreak "set breakpoint by function name" command on AcquireAssetMemory()" "1557": "List breakpoints in cdbg, to see that our AcquireAssetMemory() breakpoint is absent" "1605": "Continue to step through AcquireAssetMemory(), and try out cdbg's advanced lta "linked-list to array" command" "1751": "Try out cdbg's advance image "display image" command" "1876": "Final notes on our desired functionality of cdbg so we can switch: working break point list, F9 to toggle breakpoints, and disassembly" "1957": "Launch codeclap, with initial thoughts on its user interface, admiring the inline display of variable values" "2110": "Step in to Win32LoadXInput() in codeclap, triggering the appearance of the floating "Output" pane, and admiring the Expressions pane's command completion" "2236": "Continue to step lines in codeclap, finding that it's started to struggle with something" "2319": "Note nice features of codeclap, and our desired increase of usability and reliability" "2356": "Try to check out codeclap's "Mixed" source and assembly view, which unfortunately crashes" "2446": "Final optimistic thoughts and thanks to the developers of both cdbg (by Nick Slivca) and codeclap (by spx)" "2589": "Run the game and set up for today's work on the asset system" "2770": "Rename our art asset files using a new set of tags" "3441": "Consider splitting the character heads and bodies into separate files" "3683": "Organise our orphan character asset files into a "pending" directory, and continue to tag our remaining art asset files" "3883": "Enable ParsePieces() to parse out and tag both the body and head tiles of character asset files" "4320": "Add our new tags to the asset_tag_id enum and NameTags array" "4724": "Run the game to find that we are a large, misaligned cat, and that our multi-tile import is a bit buggy" "4865": "Check out our local.hha in TabView to see that all looks fine" "5000": "Refamiliarise ourselves with ProcessMultiTileImport()" "5342": "Scrutinise ExtractImage() for any obvious bugs" "5486": "Scrutinise Downsample() for any obvious bugs" "5668": "Fix Downsample() to correctly handle images with an odd number of rows" "5783": "“Don't forget to like and subscribe”" "5786": "Run the game to find that we have fixed the striding bug, but that we remain to be a large, misaligned cat" "5991": "Q&A" "6054": "Q: I don't really understand the size bug. Don't you ask for a specific size when you push the hero's sprites?" "6166": "Q: I am having trouble understanding the difference between tag and basic type" "6238": "Q: Just wanted to thank you for the link to the "Pseudo band-limited pixel art filter". It was exactly what I needed" "6251": "Q: When I issue an OpenGL / DirectX call (creating a vertex-buffer, for example) that takes a while to complete, will the CPU be busy while the GPU makes it happen, or will the thread be suspended, so that Windows can schedule something else?" "6341": "Q: If I understand correctly, since the sprites are clamped depending on the space that is actually occupied, doesn't it mean you'll need to adapt the sprite dimensions to the sprite that is being drawn?" "6361": "Q: Can you pet the cats?" "6369": "Q: Why not make the hha file generator also load the files and generate the tags?" "6398": "Q: OpenGL or Vulkan, for a complete beginner?" "6413": "Q: So what would it look like if you activated the snake code now, and made them cats? (Just seeing cats walk around randomly in the rooms will be so cool, just adding random stop_and_lick_your_paw calls and you basically have created life). ((Or I should just deal with having to wait for tomorrow.))" "6445": "Q: Advice on logging events or core dumping in case game crashes on a customer's machine? I guess the question is how to prepare for helping customers who had the game crashed" "6485": "Q: I mean that the idle body sprite will be smaller (in pixels) than the dodge left, for example, so if the sprite dimensions you send to the graphics card are the same, won't the dodge left sprite be squashed?" "6553": "Q: What's wrong with Vulkan?" "6562": "Q: Thank you, Casey, for giving both debuggers a try even though codeclap failed really bad this time. I will give my best to improve windows support, but I don't know about the "VS as a standard" thing"" "6605": "Q: How would you approach a bitmap that needs to be generated frequently on-the-fly? Would you add it to your asset system and reference it through your asset system? Or would you skip the asset system in that case?" "6638": "Q: And between DirectX and OpenGL, which one would you recommend for a beginner?" "6647": "Q: (Super off-topic) Can you offer me an explanation as to why there have never been PS/2 based PC controllers since it's a specific input port that sends CPU interrupts?" "6727": "Q: How long does the VoD of an episode usually take to come up online?" "6775": "Q: How do you like the progress of Handmade Hero so far?" "6893": "Wrap up the stream" --- name: "day485" title: "Adding Entity Placement to the World Generator" markers: "4": "Recap and set the stage for the day" "40": "Run the game as a giant, misaligned cat, with a view to implementing the ability to place cats in the world" "480": "Separating the world generation into room-generation and character-placement phases" "812": "Consider how to approach character-placement" "1040": "Change the gen_orphanage struct to contain a single array of pointers to gen_room structs, and introduce PlaceCat()" "1544": "Thoughts on randomly picking a room from a list" "1690": "Introduce gen_option struct as a store of character-placement criteria in rooms" "2067": "Introduce PushOption(), IterateOptions() and related functions for PlaceCat() to locate a room to place a cat" "2995": "Revert gen_orphanage to its original state, and introduce gen_entity, AddEntity(), PlaceEntity() and AddTag()" "3514": "Rename PushOption() and AddOption() and make CreateOrphanage() call it on various rooms we'd like cats to reside" "3705": "Run the game and crash on the AddTag() call in CreateWorld()" "3752": "Fix AddOption() to put the option in the array" "3802": "Run the game with our cats requested, but unplaced" "3824": "Introduce AddCat() based on AddMonstar() for GenerateRoom() to place requested cats" "4620": "Run the game to see that cats are getting placed" "4713": "Make CreateWorld() place and tag each cat, Hannah, Fred and Molly" "4832": "Run the game to see all three cats" "4845": "Add to the gen_entity struct a gen_create_entity function pointer for the Creator function" "5040": "Create handmade_entity_gen.cpp and .h to contain the entity generation code" "5139": "Run the game with the placement phase in place" "5166": "Pop over to the entity construction phase, making AddCat() resize and elevate the cats" "5247": "Run the game to see the more reasonably sized and positioned cats" "5301": "Make AddCat() elevate and shrink the head in comparison to the body" "5400": "Run the game to see the more correctly placed cat" "5485": "Enable UpdateAndRenderEntities() to render ghosts with some transparency" "5601": "Run the game to see translucent cats" "5644": "Set up to correlate incoming asset sizes with their resultant rendering" "5987": "Q&A" "6021": "Q: Would / could you add the values of the cat pieces into the debug-data-list and from there drag the values to live edit the cats? (I think you already made those features long ago)" "6037": "Q: Do you have a video where you talk in depth about the construction of Meow hash? I didn't find anything on YouTube" "6061": "Q: Are you offended that we named our cat Muratori?" "6105": "Q: Could you talk about some of your plans on the AI of entities and what options you're considering?" "6186": "Q: Are you offended that they missed the opportunity to name the cat Purratori?" "6203": "Catsey Purratori is a great name" "6230": "General thoughts on AI vs arcade-style patterning in games" "6421": "Q: I'm watching from the beginning, and you're fairly optimistic in your expectations for the series saying you don't expect to be done for two years. What are some of the topics that have taken longer than you expected?" "6525": "Q: Sorry if I'm repeating the question from the pre-stream, but how would you approach redrawing of small parts of the screen, without having to redraw the whole thing in a non-immediate-mode GUI application?" "6629": "Q: Follow up, the goals you state are trying to inspire the next generation of game engine programmers. How successful do you feel the series has been on this front?" "6708": "Q: Could you please explain again what does volatile do?" "7030": "Q: With the explaining Meow hash question, I aimed less at the implementation, but the thought process that goes on behind: Do you know a good resource to read up on how hashes are generally constructed, how you design them so they produce low collision rates, how you quality-check them, and so on?" "7627": "Q: Do you happen to know how different is embedded C programming compared to "simple" C programming?" "7706": "Q: Would adding a fund section on Handmade Network be a viable short-term solution? I for one would really really like to see CDbg get funded" "7755": "Q: I understand, thanks. I just wasn't sure because the wiki says: Do not use [volatile] for inter-thread communication" "7843": "Q: So a really good lossy compressor could be a decent hash function?" "7864": "Q: You mention many times that you are not a game designer and that it would be ideal if Jon Blow would design the game. Do you plan on having him on in an episode or two to talk about gameplay related stuff, specifically related to the design of Handmade Hero? If he has time, that is. He seems to be a very busy person and I imagine proper game design does not just happen in a day or two" "7979": "Q: There are attackers for non-crypto hashes: Hash table lookups can lead to denial-of-service attacks when the attacker can control data coming into the system (think web server)" "8064": "Q: Meow hash is based on AES, right? So in a way it uses crypto-tech" "8154": "Q: The smhasher GitHub repo talks about percentages of bias and distribution for a hash. What do those mean?" "8325": "Q: Jonathan Blow made an offhand remark that one should never use the stdio IO functions, but always use OS-specific IO functions. I do not know why, and I can't stop thinking about why it could be. Do you know what he could be talking about? Thanks" "8469": "Thank you, everyone" --- name: "day486" title: "Adding Multiple Alignment Points" markers: "3": "Recap and set the stage for the day" "45": "Thoughts on augmenting artwork with information not intrinsic to the artwork itself, e.g. positional relationships of different assets" "569": "Authoritative vs non-authoritative resources" "725": "Storing metadata in a separate file as a secondary authoritative resource" "1055": "Text vs binary format" "1136": "Set up to manually write a text file augmentation and work backwards through the code making this all happen" "1254": "View character_cat_gray_tabby.png in Windows Photo Viewer, and discover why the alpha handling is broken" "1382": "Check out character_cat_gray_tabby.png, the hats and character_template.png in preparation for writing our augmentation" "1509": "Spec out a text file augmentation in character_cat_gray_tabby.txt" "2216": "Consider how to represent these augmentations in the .hha files" "2510": "Augment hha_bitmap with the new data from our text file augmentation, introducing hha_align_point" "3697": "Enable PrintContents() to handle our new hha_align_point, introducing GetPPercent() and GetSize()" "4115": "Introduce AlignPointNameFromType() and related code for PrintContents() to decode alignment points" "4670": "Enable FormatStringList() to handle length-strings, with a note on JAI's support for defining our own format specifiers with type-checking" "5026": "Finish enabling PrintContents() to handle alignment points, using fprintf()" "5108": "Make ReadHHA_V0() handle our new hha_bitmap structure" "5457": "Introduce SetAlignPoint() and related code for encoding alignment points" "5966": "Set up LoadBitmap() to handle our new alignment points" "6060": "Enable WriteImageToHHA() to write out default alignment points" "6186": "Bump HHA_VERSION to 2, and rename ReadHHA_V1() to ReadHHA_V2()" "6303": "Try to view a newly unsupported v1 .hha file, and scrap backwards compatibility until we have shipped and people start trading .hha files" "6358": "Rewrite intro_art_v2.hha and check it out in TabView to see that the alignment is a little off" "6505": "Finish implementing SetAlignPoint() and GetType()" "6604": "Rewrite intro_art_v2.hha and check it out in TabView to see that the alignment is better, but unfortunately never exactly 1.0f" "6678": "Enable GetSize() to produce 1.0f" "6925": "Rewrite intro_art_v2.hha and check it out in TabView to see that the alignment now reaches 1.0f" "6980": "Make SetAlignPoint() round the alignment percentages, in an effort to produce 0.5f" "7093": "Rewrite intro_art_v2.hha and check it out in TabView to see that the alignment still doesn't come out at 0.5f" "7118": "Make SetAlignPoint() and GetPPercent() use the even-numbered U16Max − 1 in their computations" "7220": "Rewrite intro_art_v2.hha and check it out in TabView to see that the alignment may now come out at 0.5f" "7252": "Run the game successfully with these new v2 .hha files" "7384": "Q&A" "7451": "Q: Now the 85.0 is wrong again. Since 85 isn't a factor of 65534" "7486": "Q: Could you use U16MAX + 1 and a size modifier of 128?" "7521": "Q: Colour seems like it would make a nice addition to the bitmap parenting system: a ghost wearing a hat should have a hat with a lower alpha value, right?" "7566": "Q: Last week you were mulling over whether or not to separate the head from the body in the sprite sheets. Since then has this idea become more solidified? Also, do you plan on giving some of the faces more articulate animation? An example I thought of at the start of the stream today was blinking eyes on the cats or other characters, perhaps as overlays of eyelids with versions for each head angle. A separate face spritesheet might be nice, more space for such things" "7604": "Q: Totally random question, very off-topic: Do you like that the C++ preprocessor has no special syntax for invoking a macro? Are there merits to that in your mind, or not? Would you prefer a special syntax for invoking macros?" "7741": "Close it up, with a note about switching the debug system left–right camera movement to be more congruent with up–down" --- name: "day487" title: "Hit-Testing Boxes in 3D" markers: "1": "Recap and set the stage for the day" "30": "Run the game and point out the discombobulation of the cat artwork" "93": "View the intro_art_v2.hha file in TabView" "154": "The three things to do: 1. Use the alignment points; 2a. Get alignment data into our metadata file; 2b. Edit results in real time" "342": "Set up to provide a way to edit placement points" "447": "Consider reconceptualising the debug system as an integral part of the shipped game" "559": "Set up to integrate the entity picking code into the game" "767": "Begin to enable UpdateAndRenderEntities() to handle picking of all sprites" "859": "Run the game to see our sprite debug visualisation" "888": "Change UpdateAndRenderEntities() to use PushRectOutline() for the sprite debug visualisation" "987": "Run the game to see the more sensible, if incorrectly scaled sprite debug visualisation" "1020": "Remove the EntityTransform.OffsetP addition from the WorldP computation in UpdateAndRenderEntities()" "1106": "Run the game to see the better positioned sprite debug visualisation" "1129": "Adjust the dimensions of the sprite debug visualisation" "1212": "Run the game to see the cat's sprites correctly visualised" "1247": "Create a sprite-picking mouse cursor in UpdateAndRenderEntities()" "1950": "Run the game to find that the sprite-picking mouse cursor sort of works" "1985": "Decouple the use of WorldP and Piece->Offset in UpdateAndRenderEntities() to correctly locate entities and render their debug visualisation" "2122": "Run the game to find that the sprite-picking is pretty close, but that the Y is wrong" "2202": "Enable UpdateAndRenderEntities() to draw a line connecting the cursor and the picked entity" "2410": "Run the game to see our cursor–entity connection, but with incorrect projection to the entity" "2523": "Create a picking ray in UpdateAndRenderEntities()" "2999": "Run the game to find that the picking ray is pegged to the correct location" "3022": "Enable UpdateAndRenderEntities() to draw and highlight the outline of picking boxes using PushVolumeOutline()" "3274": "Run the game to see outlines around all volumes" "3288": "Introduce RayIntersectsBox() based on RayCast()" "3777": "Run the game to find that the picking is working" "3800": "Enable RayIntersectsBox() and UpdateAndRenderEntities() to highlight only the nearest intersection" "4053": "Run the game to find that it only picks the closest hit" "4074": "Enable UpdateAndRenderEntities() to support sprite picking" "4178": "Run the game to find that sprites may be picked, and consider how to proceed, including the problem of disambiguating layered (transparent) sprites" "4483": "16 minutes into the Q&A, -1 until end. (based on NOTE)" "4557": "Look forward to further improving the lighting" "4629": "Consider displaying errors recorded for a picked bitmap" "4942": "Augment hha_annotation with an error stream and propagate this addition to WriteHHA_V2() and PrintContents()" "5532": "Check out local.hha in TabView to see no mention of error streams" "5584": "Consider where to write asset import error messages" "5811": "Enable WriteImageToHHA() to write out asset and file errors, introducing WriteAssetStream()" "6360": "Trigger an asset reimport and check out local.hha in TabView to see the Errors field, but with no content" "6441": "Fix typo in PrintContents()" "6453": "Trigger another asset import and see errors, with slightly incorrect printout" "6497": "Fix PrintContents() to correctly parse out the errors" "6602": "Reimport and check out local.hha in TabView to see that all is correct" "6623": "Add newlines to the asset and file error messages" "6679": "Reimport and check out local.hha in TabView to cleanly see our errors" "6745": "Q&A" "6792": "Q: Is it possible to account for sprite opacity when selecting items, for the selection to be more intuitive? Is it useful to generate a more slim triangulation for sprites?" "6936": "Q: Instead of fussing with selecting the individual sprite parts, wouldn't it be handier to list them in a picked entity HUD" "6950": "Q: Is the .Count inclusive with strings? In other words, do you really need the nested ifs in the line printer?" "6968": "Q: You spent a lot of time optimizing the hash function, but is it worth it? Most of the time you calculate hashes when doing I/O, which will always be significantly slower, so you'll save more time if you calculate the hash in parallel with I/O. This way MeowHash and SHA512 would have the same impact on runtime, despite MeowHash being 80 times faster" "7226": "Q: You check for At == Count, but I should think that by then you would already be past the last character in the stream" "7280": "Simplify the error printing in PrintContents()" "7312": "Check out local.hha in TabView to find that the error printing remains correct" "7377": "Hashing performance, in terms of (not) being memory or I/O bound" "7754": "Wrap it up" --- name: "day488" title: "Adding an In-Game Editor" markers: "2": "Recap and set the stage for the day implementing asset editing features" "120": "Run the game to see our currently misaligned and scaled cat" "213": "Set up to implement asset editing, comparing our procedurally generated situation with the hand-designed situation of a game like Braid" "493": "Set up to make our asset editing capabilities at the level above our game's modes – title screen, cutscene, world – also available in the shipping game as was the editor in Braid's PC release" "675": "Introduce in_game_editor and related structs in a newly created handmade_in_game_editor.cpp" "1101": "A few words on passing to a function its minimum necessary set of parameters" "1215": "Change UpdateAndRenderEntities() to take a new editable_hit_test instead of the entire game_input" "1868": "Introduce AddHit()" "2306": "Introduce BeginHitTest(), EndHitTest() and ShouldHitTest()" "2723": "Make GameUpdateAndRender(), UpdateAndRenderWorld() and DoWorldSim() use our new asset editing functionality" "2998": "Run the game to find that entities with asset index 0 (white bitmap) are already highlit" "3028": "Make UpdateAndRenderEntities() only highlight entities whose BitmapID equals the HighlightAssetIndex" "3057": "Run the game to see that the white bitmaps are no longer highlit" "3065": "Finish implementing AddHit() to append hits" "3168": "Run the game to find that our highlighting works, and consider printing asset information in-game" "3326": "Introduce the notion of an in_game_editor_mode" "3497": "Run the game to find that our editor does not pick entities" "3511": "Enable BeginHitTest() to toggle the editor mode" "3612": "Run the game and toggle our editor mode" "3636": "Flesh out our editor modes, introducing UpdateAndRenderEditor() to print asset information" "3891": "Refresh our memories on PushFont() and consider rolling the fonts into the main asset system" "4081": "Continue to implement UpdateAndRenderEditor()" "4294": "Run the game to find that the picking still works" "4311": "Consider separating out the layout code from the debug system for use in a non-debug (i.e. profiling) context" "4712": "Introduce AssetEditor() based on PrintContents()" "6784": "See how AssetEditor() would shake out if it was FormatString()-centric" "7096": "Decide on the original, function-heavy approach for AssetEditor(), to write tomorrow" "7165": "Q&A" "7212": "Q: Off-topic: How do you index large meshes (index needs more than 16-bit)? Would you divide into multiple chunks (and have more draw calls) or increase bandwidth by using 32-bit for indices? Which approach is better for large meshes?" "7258": "Q: SIMPalaxy asked earlier if you have changed your 4coder custom since you handed it over to Allen, so now I'm wondering the same" "7293": "Q: Not really on-topic, but how would you go about implementing a generic resizable array, as you said you don't like to use templates?" "7335": "Example of C++'s offering for implementing generic resizable arrays" "7982": "Q: Off-topic (pre-multiplied alpha): I watched the episodes in which you presented it and I remember you mentioned that you prefer to defer multiplying by alpha "at the end". Can you explain what this means? Also, what's the benefit of pre-multiplied alpha, other than the fact that it's now a linear operation (if that's the case)? I can only see the value if you're compositing multiple transparent / translucent layers" "8138": "Are you forced to use templates? I don't code in C++ but the language does not force you to do it, right?" "8195": "Q: Is the asset tool fixed? From Day 470 I wasn't able to build some of the tools (commented out in build.bat) for asset file creation" "8247": "That's it for today" --- name: "day489" title: "Implementing Undo and Redo" markers: "0": "Recap and set the stage for the day implementing our asset editor UI" "36": "Run the game to see the current UI capabilities of our profiling debug system" "256": "Review the purpose of AssetEditor(), editing Alignment Points" "365": "Dive straight into undo / redo functionality for UpdateAndRenderEditor(), introducing in_game_edit struct, IsEmpty(), UndoAvailable() and RedoAvailable()" "1017": "Introduce align_point_edit as one of the types for in_game_edit to contain" "1191": "Introduce EditAlignPoint() and AlignPointFromAssetAndIndex() for AssetEditor() to call" "1524": "Introduce ApplyEditChange() as a dual-purpose undo / redo function for UpdateAndRenderEditor() to call" "1868": "Introduce IsDirty(), and separate Undo() and Redo() functions for UpdateAndRenderEditor() to use in the "REVERT" case" "2299": "Create handmade_dev_ui.cpp and .h to separate the game, editor and debug system's UI" "3246": "Confirm that the debug system still draws" "3282": "Get the whole in-game editor compiling with the reorganised code" "3459": "Introduce AllocateEditorEdit() using an interesting macro trick" "3700": "Continue to get the in-game editor compiling" "3980": "Stub out all the UI functions called by AssetEditor()" "4339": "Introduce PopFirst(), PushFirst(), Link() and Unlink()" "4570": "Finish cleaning up compile errors, making UpdateAndRenderEditor() initialise a Layout" "4725": "Run the game to see that we're working as before" "4781": "Consider merging almost the entire debug system layout code into the general UI code" "4958": "Trim away unused parts of the debug system" "5120": "Try tearing off UI elements unsuccessfully" "5173": "Change DEBUGEnd() to initiate tear on Alt-Click" "5226": "Successfully tear off UI elements" "5276": "Continue to trim away unused parts of the debug system and switch it over from debug_id to a unified dev_id" "5464": "Spot that our font baselines are wrong" "5531": "Replace debug_interaction_type with a unified dev_ui_interaction_type" "5730": "Run the game to find it working as before" "5780": "Q&A" "5804": "Q: (For after stream) Do you want the viewer to be able to edit things or just view things?" "6006": "Q: Hey Casey, I know this is kind of off-topic but do you have any advice / resources to read on shadow mapping implementations?" "6173": "Q: Are you still planning on removing the CRT in the game layer?" "6191": "Q: Following up on the pre-stream discussion on executable size. I nuked out the CRT in my project and it reduced its size from 150K to 35K. I did not think it insert so much crud" "6237": "Q: Do you think programming books are worth the effort to read? Or is there a better way to learn?" "6261": "Q: Are we still planning to port to Linux and bare-metal Raspberry Pi?" "6269": "Q: How useful would it be to get additional performance information from the CPU? I know Intel provides some stuff for things like branch prediction and cache misses" "6370": "Q: Will you be avoiding the CRT on Linux in the future. Sorry it's the same topic, but I'm curious!" "6418": "Q: How can you determine the validity of the book and its usefulness?" "6481": "Q: As a Linux supportr I want my $15 back (to buy a spellchecker, apparently)" "6519": "Q: What's that empty space in the thread debug view?" "6533": "The debug system's Threads view" "6769": "Q: Are you already testing some JAI?" "6789": "Q: When updating the anchor points, does this mean the .hha file has to be recompiled each time that happens?" "6806": "Q: How would you change this work scheme for a mobile platform where we are concerned about battery usage?" "6910": "Q: Can new lighting propagation be computed while the GPU is doing its stuff? Seems like a lot of waiting" "6954": "Traverse the world and look forward to the completed asset editing" "7029": "Q: We can only start to render if the lighting is done, no?" "7193": "Q: I read your article on the manipulation tool work you did on The Witness and it helped me debug my problems. Do you have a good way to manipulate rotation? Is it to ray-test on a sphere and then take the dMouse hit and then see how long the delta arc is on a specific axis?" "7253": "Q: Could you get NSight to work and did it help you with anything?" "7299": "That's all, folks" --- name: "day490" title: "Merging Debug and Developer UI" markers: "0": "Recap and set the stage for the day and December's surprise streams in celebration of Krampuslauf" "106": "Run the game and set up to edit asset annotations" "298": "Review AssetEditor() and the beginnings of our UI functionality" "440": "Set up to merge the debug system's layout code into our multipurpose UI system" "531": "Begin to merge the debug system's UI code into handmade_dev_ui.h, for use by both the debug and asset systems" "1138": "Move UI data from debug_state to dev_ui_context and propagate this change to all functions" "1777": "Rename dev_ui_context to dev_ui, and continue our UI code merge" "2049": "Organise the debug_state struct into data that will remain and be merged out" "2163": "Remind ourselves how we use the SelectedID" "2373": "Switch the debug system over to use our new general UI layout code" "3437": "Introduce InitializeUI() and BeginUIFrame() to perform the UI layout functionality of DEBUGStart()" "4342": "Switch UpdateAndRenderEditor() over to use our new general UI system, and introduce InitializeEditor()" "4821": "Make GameUpdateAndRender() call BeginUIFrame() and EndUIFrame()" "4993": "Implement EndUIFrame() based on the UI layout code of DEBUGEnd(), and make BeginUIFrame() perform the mouse handling from DEBUGInteract()" "5754": "Clean up compile errors in the UI merge across the asset and debug systems" "6166": "Run the game to find that all of that just worked" "6223": "Delete BeginLine() and EndLine() in favour of BeginRow() and EndRow()" "6304": "Implement Button(), calling ActionButton() and Label()" "6450": "Run the game to see our asset UI" "6477": "Implement Labelf()" "6688": "Run the game to see our UI labels" "6697": "Implement fake versions of EditableBoolean(), EditableType(), EditableSize() and EditablePxy()" "6738": "Run the game to see even more UI" "6749": "Q&A" "6855": "Wrap it up" --- name: "day491" title: "Debugging the Basic Editor UI" markers: "1": "Recap and set the stage for the day wiring up our asset editor" "63": "Run the game to show our current asset editor UI" "156": "A few words on our immediate-mode user interface" "522": "Introduce the notion of an Immediate Button" "922": "See if there's anything of DEBUGInteract() that could be shared between the asset and debug systems" "1104": "Introduce EditorInteract() for GameUpdateAndRender() to call, guided by DEBUGInteract()" "1790": "Enable EditorInteract() to handle mouse input" "2560": "Run the game and crash in Undo()" "2585": "Introduce IsValid() for Button() to call" "2699": "Run the game to see all our UI buttons lighting up because they share the same ID" "2736": "Try making Button() set the ID from the passed LabelText" "2801": "Run the game to see that buttons with the same label light up, due to our compiler doing string pooling" "2834": "String pooling" "2891": "Make Button() take a dev_id ID which AssetEditor() is responsible for constructing" "2997": "Introduce DevIDFromPointer() calling a newly introduced FILE_AND_LINE(), and rename UniqueFileCounterString() to DEBUG_NAME()" "3462": "Make AssetEditor() and UpdateAndRenderEditor() call DevIDFromPointer()" "3521": "Run the game to find that our UI buttons light up individually, and that Undo() crashes" "3574": "Introduce Sentinelize() to initialise the Undo and Redo lists" "3707": "Run the game to find that Undo and Redo are unavailable" "3727": "Make AllocateEditorEdit() call PushFirst()" "3872": "Run the game and crash in Undo()" "3895": "Make EndUIFrame() clear the UI->IDToExecute to prevent Undo from operating forever" "3933": "Run the game to find that our button clicks do not perform an edit" "3946": "Augment dev_ui with a NextIDToExecute so that EndUIFrame() may set an IDToExecute that is valid for the current frame only" "4069": "Run the game to find that edits, Undo and Redo all work, but Revert crashes" "4091": "Make InitializeEditor() initialise the CleanUndoSentinalNext" "4142": "Run the game to find that Revert now works, but Delete does not" "4200": "Fix AssetEditor() to correctly delete edits" "4315": "Run the game to find that deletion works, and prioritise our next steps: 1) Asset selection; 2) UI positioning; 3) UI edit interaction" "4435": "Enable EditorInteract() to handle asset picking on click" "4888": "Run the game to find that asset picking works" "4967": "Dive into making UpdateAndRenderEntities() only highlight the selected entity" "5314": "Introduce DevIDFromU32s() and a dev_id_value union to enable even 32-bit systems to use 64-bit IDs" "5678": "Replace the u32 HighlightAssetIndex in editable_hit_test with a dev_id HighlightID, and make AssetEditor() set this HighlightID" "5828": "Run the game to find that the highlighting still occurs on hover" "5841": "Make UpdateAndRenderEntities() only call PushVolumeOutline() to highlight the entity whose DevID matches the HighlightID" "5923": "Run the game to find that everyone highlights" "5961": "Fix typo in DevIDFromU32s()" "5984": "Run the game to find that selection / highlighting works" "6001": "Enable EditorInteract() to clear highlighting when clicking on no asset" "6060": "Run the game to find that highlight clearing works, but certain entities are tough to pick" "6131": "Investigate the sorting in RayInterectsBox()" "6247": "Run the game to find that our currently picked entity seems to affect which entity we may pick next" "6339": "Make EditorInteract() straight up set the HighlightID to the first asset in the hot group" "6377": "Run the game and move the cursor around the scene to see which entity gets highlighted" "6460": "Make UpdateAndRenderEditor() set the HighlightID on every update" "6476": "Run the game to still see stickiness on some entities" "6618": "Make UpdateAndRenderEntities() highlight whichever entity our ray cast hits" "6662": "Run the game to find that our cursor does not get stuck, which suggests that either our hit sorting routine or ID setting may be incorrect" "6735": "Make UpdateAndRenderEntities() highlight both our ray hits and the entity the asset system told us to highlight" "6763": "Run the game to see these different highlights" "6857": "Fix AddHit() to set the ID" "6882": "Run the game to find that our asset picking works perfectly" "6891": "Revert UpdateAndRenderEditor() to only set the HighlightID on click" "6912": "Run the game to find that all is good, and consider our next steps" "6979": "Q&A" "7048": "Q: How long do you think it would have taken you to get to this level in the project if you were working on it 8 hours a day?" "7147": "Q: Is there a reason for making two lists for undo / redo rather than one?" "7222": "Q: Big engines support multiple render paths (D3D, OpenGL), but why do these engines not use only OpenGL instead of D3D?" "7354": "Q: Which parts of C++ do you use?" "7401": "Q: Follow-up question regarding OpenGL: Can you name some of the stuff of the subset they should have marked as OpenGL v5?" "7450": "Q: Then do you think Vulkan would not have this type of problem with bugs because it's more low level?" "7573": "Q: So will we switch to D3D before shipping this game, or for simplicity will we stay with OpenGL?" "7673": "Q: Can you program shaders in asm on Vulkan, or any of the other graphics APIs?" "7857": "Q: Doesn't that same problem – APIs growing old and unsuitable for current graphics cards – also apply to DX12?" "8159": "Q: In Handmade Hero I saw this concept of BeginRender / EndRender (I believe it is called) which reminds me of fixed function OpenGL glBegin, glEnd. Can you say how these functions in Handmade Hero roughly work or what is the concept behind it?" "8209": "Q: Shouldn't these graphics APIs be made by GPU vendors, or can they not do that?" "8289": "Q: I mean current APIs. I know DX9 supports it up to 3.x or 4.0" "8301": "Q: What do you expect people to learn with this series, other than how to make a game?" "8378": "Q: Do you think next generation consoles will adopt raytracing extensions, even if just to avoid using shadow maps?" "8469": "Q: Why are most AAA games still running on DX11? Is DX12 too new and still not well supported?" "8505": "Q: What would make a graphics API great?" "8524": "Q: How often do you read other people's code bases? Do you have any recommendations of good examples of well architected code bases to learn from?" "8595": "Q: Was OpenGL 2.1 a great API?" "8605": "Q: Is there a good API for GUI applications on Windows that you would suggest?" "8627": "Wrap it up" --- name: "day492" title: "Adding More Editor Interactions" markers: "1": "Recap and set the stage for the day continuing with our asset editing UI" "82": "Run the game to show our asset editing UI and consider positioning and styling it, and aggregate continuous interactions (e.g. drags)" "480": "Set up to enable the undo / redo system to aggregate continuous interactions, introducing the notion of an InProgressSentinel in the in_game_editor" "922": "Implement EditableBoolean(), with a few words on functional decomposition" "1172": "Run the game to see that our boolean button doesn't toggle" "1176": "Augment dev_ui_layout with EditOccurred and dev_ui_edit_block with PrevEditOccurred, for EndEditBlock() and BeginEndBlock() to set" "1410": "Run the game to find that our boolean button toggles" "1462": "Implement EditableType(), introducing a version of Button() that takes an additional Classifier" "1809": "Run the game to see our editable type button" "1836": "Make EditableType() print out the value" "1892": "Run the game to find that our editable type button does not cycle through the types" "1937": "Enable AssetEditor() to wrap the values of the editable type button" "2175": "Break in to EditableType() and watch what happens upon clicking the button" "2224": "Fix EditableType() to correctly increment and decrement the Value" "2271": "Run the game to find that that doesn't fix our problem" "2341": "Change ToExecute and NextToExecute in dev_ui to be of the type dev_ui_interaction, and propagate this change" "2425": "Run the game to find that our EditableType button works fine" "2487": "Enable EditableSize() and EditablePxy() to print out the Value" "2593": "Check out the Size and Percent values in our UI" "2608": "Enable EditableSize to draw a special widget with BasicTextElement()" "2743": "Check out the Size button widget in our UI" "2753": "Give the Size widget some border" "2800": "Check out the bordered Size widget in our UI" "2831": "Enable EditablePxy() to draw a widget like the Size button, and this function and EditableSize() to handle draggable interactions" "3386": "Try dragging our Percent widget, without success" "3419": "Peruse the code for the possible cause of our dragging bug" "3539": "Step in to EditablePxy() to see what's happening" "3575": "Make EditableBoolean(), EditableType(), EditableSize(), EditablePxy() to all set EditOccured to true" "3618": "Try dragging our Percent and Size widgets, successfully" "3676": "Make EditablePxy() clamp the values to the passed in Min and Max" "3724": "Try out our clamped Percent widget, and demonstrate the need for edit aggregation" "3824": "Introduce GetOrCreateEditInProgress() to aggregate edits, replacing AllocateEditorEdit()" "4523": "Enable EditorInteract() to handle the notion of EndInteraction" "4813": "Run the game and crash in EditorInteract()" "4826": "Fix InitializeEditor() to initialise the InProgresSentinel" "4862": "Try out our aggregated undo, and consider prettying it up" "4951": "Consider how to handle coexistence of the debug and developer UI" "5046": "Investigate the font baseline issue" "5230": "Change TextOp() to factor in the AscenderHeight to the glyph's offset" "5508": "Check out the font drawing in our UI" "5531": "Refresh our memories on our font encoding" "5806": "Check out testfonts_v2.hha in TabView" "6005": "The mathematics of the font alignment percentage" "6522": "Make SetAlignPoint() and GetPPercent() clamp alignment percentages to the range -2 to 2" "6634": "Run the game and get nutso stuff on the font alignment" "6642": "Regenerate our .hha files to get our newly aligned fonts" "6737": "Run the game to find that our font baselines are now correct" "6788": "Q&A" "6818": "Q: What does ## mean? I looked it up but I don't think I understand what its use is. Is it supposed to link different variables into one variable?" "7056": "Q: I've been trying to implement the walk system from your recent talk. In the talk you make the point that "shrinking" the walk edge is trivial. I've made it that far in my own code but I haven't been able to figure how to do the shrinking without testing all edges against all segments of the walk edge. That approach doesn't scale well. So I was wondering if you could say a few words about how you did it - assuming you had another approach. I am using a half-edge structure for the manifold" "7134": "Efficiently shrinking the walk edge as per the walk system from The Witness" "7267": "Q: Do you know how to rotate a font? Do you use stb_truetype.h for font rendering?" "7537": "Wrap it up" --- name: "day493" title: "Cleaning Up the Editor UI Layout" markers: "1": "Recap and set the stage for the day beautifying the asset editing UI" "92": "Showcase the current asset editing UI" "217": "Introduce the notion of tabbed UI sections, and try to make UpdateAndRenderEditor() peg the UI to the left side of the screen" "472": "See that the UI remains at the screen's centre" "485": "Augment dev_ui with a rectangle2 UISpace for UpdateAndRenderEditor() and BeginUIFrame() to use" "706": "See that our UI is now pegged to the left side of the screen" "792": "Make UpdateAndRenderEditor() organise the buttons into sections" "916": "Check out our separated button sections" "933": "Enable BeginSection() to handle tabbed UI sections, augmenting the in_game_editor with a dev_ui_section_picker" "1867": "Introduce SectionPicker()" "2078": "Check out our tabbed UI, which doesn't cycle through sections" "2098": "Investigate the reason why our UI section cycling didn't do anything" "2183": "Check out our working tabbed UI, after having selected an asset" "2238": "Beautify the UI, augmenting dev_ui_layout with a Thickness parameter" "2444": "Check out our more thickly bordered UI" "2599": "Augment dev_ui_section_picker with CurrentSectionExists and make the UI revert to an existing section if the user's interactions result in the current section no longer existing" "2837": "Check out our UI's full section picker" "2857": "Make Button() style enabled and disabled buttons differently" "3008": "Check out our enabled and disabled button styles, finding that the state didn't always get set correctly" "3052": "Restyle the buttons a bit in Button()" "3075": "Again find that the Undo button doesn't get styled correctly" "3113": "Try to fix the enabled / disabled styling in Button()" "3141": "Find that this didn't fix the enabled / disabled button styling" "3194": "Investigate the issue with the enabled / disabled button state setting" "3361": "Try making Button() clear the Interaction.ID" "3387": "Find that this doesn't fix our button state issue" "3440": "Break in to UpdateAndRenderEditor() to figure out why the Undo button does not get restyled when undo edits should be available" "3675": "Realise that EditorInteract() pushes edits onto the undo stack one frame late" "3754": "Make UpdateAndRenderEditor() responsible for pushing edits onto the undo stack" "4168": "Find that the Undo and Redo buttons get styled correctly" "4313": "Change Button() to set the Interaction.Type of disabled buttons to NOP" "4368": "Find that disabled buttons now work by preventing click-through to the space behind" "4404": "Introduce BeginLayoutBox() to give the UI a rectangular click-consuming background" "4970": "Check out our backgrounded UI" "4994": "Make BeginLayoutBox() darken the UI's background and increase its top-left margin" "5048": "Check out our darkened and inset asset editing UI" "5082": "Reduce the number of characters in our UI labels" "5157": "Check out our more compressed UI" "5189": "Further reduce the number of characters in our UI labels" "5430": "Check out our yet more compressed UI, with some of the fields unfortunately missing" "5474": "Enable EditableType() to handle 0 LabelText" "5509": "Check out our fully working, compressed UI" "5538": "Make EditableBoolean() style On and Off values differently" "5644": "Check out our differently styled boolean button" "5657": "Increase the brightness of our button text in Button()" "5679": "Crash in OutChar()" "5686": "Prevent Win32UnloadGameCode() from calling FreeLibrary()" "5740": "Check out the brightened UI button text" "5761": "Try to darken the default BackdropColor of Button(), but find that it won't hot reload" "5834": "Investigate our hot reloading issue and realise that Win32LoadGameCode() can't reload while it uses a single TempDLLName" "6034": "Enable Win32BuildEXEPathFilename() to produce file names with an optional unique substring" "6600": "Run the game, make a change to trigger hot reloading, and find that we produced a uniquely named .dll" "6706": "Move the variably-sized Type button to the far right of our UI" "6772": "Check out our full asset editing UI" "6795": "Rename the "unused" button to "ADD", and make UpdateAndRenderEditor() draw our UI at a fixed sized" "6856": "Check out our fixed-size asset editing UI" "6904": "Q&A" "6958": "Q: Recently you said that Qt is not that good. What do you dislike about it?" "7085": "Critique Qt's QCalendarWidget (and parent widgets) offering" "7435": "Critique Qt's Application Example focusing on its application of the retained-mode paradigm" "8106": "Critique Qt's Animated Tiles Example" "8507": "Q: Just made a new version for dumpview. Feel free to come back to this after Q&A has ended" "8519": "Q: Regarding the Qt slider example. So if I get this correctly, in an IMGUI one just goes through the UI elements and just draws them depending on whatever the slider-value says?" "8532": "Immediate-mode vs retained-mode GUI" "8585": "Critique retained-mode GUI as exemplified by Qt's ListView" "8866": "Q: Regarding keeping audio and video synced. When you did the audio system you were very strict about playing without losing 1 frame. That was before we moved to OpenGL. Now there's a latency between when we're issuing a frame until it is actually rendered (CPU / GPU latency). How are we going to keep them in sync? I guess for Handmade Hero it's not a huge deal, but I'm curious to hear your opinion on how to keep them in sync in case I need to do character lip-sync animations" "9003": "Q: Thanks for the list view example. That made it pretty clear. Where do you think it comes from that people build those verbose APIs that don't even give you much flexibility?" "9114": "Q: If retained-mode is so bad, why haven't immediate GUIs taken over the desktop / mobile market yet? Spoilers, not every application is a game" "9212": "Q: Suppose you have an array of some struct type and each item has a name which is what you want to represent as an item in the list for the end user to choose from. Would it be a good idea to hand the UI some pointer to the first name and specify some stride to the next, or how would you do it?" "9245": "Q: This is why websites are slow. They are trying to impose the IMGUI paradigm onto retained style and suffer with performance, like they compare data graphs and find differences and apply changes to retained model" "9285": "Sad day when JavaScript frameworks are given as good examples" "9335": "Q: What do you think of annotation based programming a la spring?" "9448": "Q: Profiling huge websites it's pretty common to see 100-500ms spent on things like "Relayouting" or "Recalculating CSS styles" or just purely inside the JavaScript. I've made a purely dear imgui (heavily styled and customized) / WebGL / WebAsm website and it takes 0.5ms per frame to compute the layout" "9579": "handmade_hero, please make games for Linux" "9784": "Wrap it up" --- name: "day494" title: "Preparing Entity Pieces for Alignment Points" markers: "1": "Recap and set the stage for the day" "302": "Demo the asset editor UI" "488": "Reacquaint ourselves with the bitmap alignment and sizing code" "658": "Trim down loaded_bitmap with a view to aligning and sizing bitmaps using the hha data directly" "1341": "Check the performance of _mm_div_ps, _mm_rcp_ps and _mm_mul_ps in the Intel Intrinsics Guide" "1453": "Replace WidthOverHeight from loaded_bitmap with localised computations" "1757": "Make sure that our bitmaps are still there" "1770": "Remove AlignPercentage from loaded_bitmap, making callers of PushBitmap() responsible for computing this value, and introducing GetFirstAlign()" "2497": "Run the game to find that everything looks fine" "2558": "Try making UpdateAndRenderEntities() set the AlignP using GetFirstAlign()" "2610": "Try out real-time editing of our asset alignment for the first time" "2667": "Set up to implement alignment point connections" "2860": "Introduce bitmap_piece to specify parent–child connections" "3163": "Introduce ConnectPiece() for AddCat() to call" "3862": "Make ConnectPiece() enforce the rule that the target parent piece must exist" "3950": "Run the game and pass this ConnectPiece() test" "3958": "Make AddCat() try and add the cat's Head before the Body" "3985": "Run the game and (correctly) fail that ConnectPiece() test" "3990": "Introduce a version of PushBitmap() that takes a used_bitmap_dim for UpdateAndRenderEntities() to call" "4540": "Run the game with everything being drawn" "4549": "Consider how to use our alignment points" "5000": "Move towards the total removal of the object_transform struct from the renderer, first removing Upright" "5367": "Check that our bitmaps are all in tact" "5393": "Remove object_transform entirely" "6554": "Run the game to see that the only breakage was in one cat's bitmap offset" "6590": "Fix one GetBitmapDim() call in UpdateAndRenderEntities()" "6623": "Run the game to see that everything is fine" "6657": "Q&A" "6689": "Q: Any news about meowhash?" "6722": "Q: Not extremely important, (but Krampus related), just for your information, the word "lauf" in "Krampuslauf" is pronounced more like "ou" in the words "ouch" or "couch". Even less of an issue, in German the "a" in "Krampus" is more of an "ah", more like "Krahmpus". So... "Krahmpuslouf"" "6783": "Q: I forgot why sorting was necessary, couldn't we just send it all to the GPU and have the depth buffer sort it out?" "6833": "Q: Can you put the shadow offset in the shadow transform now?" "6873": "Q: When do you plan on shipping the game? I'm really looking forward to play it" "6904": "Q: Are there any particular reasons you use Windows over Linux?" "7063": "Q: Hey, just stopped in for the first time, this is really cool. Question is: How much time do you think game devs should spend refactoring code compared to writing new features? I often find it discouraging when I spend too much time refactoring spaghetti code without adding anything new for a while" "7181": "Q: You're dropping the "f"" "7206": "Q: Off-topic: Do you have any tips on parsing academic math papers?" "7254": "Q: Are we going to save the changes to the scale and alignment point back to the file they are coming from?" "7264": "handmade_hero In the TextOp() it still offsets the text" "7314": "Off-topic Q: I've heard you mention other memory management techniques than the arenas as used on Handmade Hero" "7350": "Q: Should you try and use multi-threading as much as possible, or the other way around? Or does it just depend a lot?" "7511": "Q: Can you show Jon Blow how to compile from Emacs with a keyboard shortcut?" "7521": "Q: Can you go into a bit of detail about what these memory allocators / management techniques are?" "7537": "Q: So you would never refactor code just for code readability?" "7605": "Q: Do you plan to add scripts support, i.e: lua scripts (for modding)? If you do, how would you protect the user?" "7618": "Q: Also polijn in twitch chat is right: "pus" in "Krampus" is like "puss" in pussy cat" "7641": "Q: Unrelated: I just discovered dual quaternions. Are they used in game programming?" "7662": "handmade_hero It's not bad at all, the question was: Could this be in the ShadowTransform?" "7700": "Q: What are your thoughts on ISPC for multithreading / SIMD?" "7765": "Shut down the stream" --- name: "day495" title: "Improving the Alignment Editing UI" markers: "1": "Recap and set the stage for the day doing, essentially, skeletal animation" "314": "Set up to snap heads onto bodies and visualise snapping points, considering flexible scaling" "651": "A few preliminary words on immediate-mode GUI" "753": "Make UpdateAndRenderEntities() draw asset alignment points, introducing GetDebugColor3() and GetDebugColor4()" "1619": "Check out our alignment points in-game" "1649": "Make UpdateAndRenderEntities() negate the AlignmentPercentage of the alignment points" "1777": "Find that that doesn't peg the alignment point to the asset" "1854": "Make UpdateAndRenderEntities() offset the alignment point by the asset's dimensions rather than its ground position" "1886": "Find that our alignment point is correctly located" "1913": "Make UpdateAndRenderEntities() draw the alignment points closed to the camera" "2001": "Check out our pegged alignment points in-game, tweaking their size" "2129": "Enable toggling of coloured alignment points, introducing Buttonf() and EditableBooleanf() for AssetEditor() to call" "2608": "Try out our alignment point toggling, noting the scarcity of code required for this feature" "2736": "Change AssetEditor() to only permit existing alignment points to be toggled and coloured" "2770": "Check out our correct alignment point toggling" "2808": "Introduce ShouldDrawAlignPoint() to enable UpdateAndRenderEntities() to draw all existing alignment points" "3002": "Check out all our alignment points in-game, noting the need to fix the way we're drawing them closer to the camera" "3167": "Make PushCube() take a ZBias which UpdateAndRenderEntities() may use to elevate alignment points above entities" "3271": "Find that this didn't elevate our alignment points as expected" "3406": "See how CompileZBiasProgram() uses the ZBias" "3604": "Make UpdateAndRenderEntities() pass a ZBias of 5.0f for alignment points" "3634": "Find that alignment point elevation works fine in debug camera mode, but not in regular camera mode" "3719": "Figure out how the clip planes differ in the different camera modes" "3793": "Make UpdateAndRenderEntities() pass a ZBias of 3.0f for alignment points" "3812": "Find that our alignment points are now always elevated above assets, and visible" "3887": "Enable UpdateAndRenderEditor() and EditorInteract() to support asset piece picking, introducing SetActiveAsset()" "4384": "Try out our asset picking functionality" "4498": "Make UpdateAndRenderEditor() display bitmaps in our asset picker, introducing BitmapButton()" "5253": "Check out the new bitmap buttons in our UI" "5341": "Make BitmapButton() outline the selected bitmap" "5475": "Check out the outlined bitmaps in our UI" "5536": "Try out our asset alignment editor UI" "5615": "Q&A" "5681": "Q: How come the near clip plane is at 5, and not closer?" "5718": "Q: Would we be showing linkages between alignment points?" "5790": "Q: What would you say is crappy in your current implementation of the IMGUI?" "5880": "Q: Do you think it would be useful to add mouse wrapping (like in Blender) so you can drag past the end of the screen when editing values?" "5940": "Q: Isn't it an overhead when checking for "if(Button(...))" when doing that every frame?" "6035": "Q: Will you ever make an emote, or just steal one of Jon's?" "6093": "Q: What is the reason the UI loses state when you hot-reload?" "6192": "Q: Can you play around with it a little more?" "6207": "Play around with the UI a little more" "6290": "Q: With software rendering you can do hot regions that are redrawn when the user fiddles with the UI elements. Can anything similar be done with hardware rendering?" "6381": "Q: Will the finished game ship with almond milk?" "6390": "Q: You get Anna to draw something cute, like a cat, and then upload the kitty image to twitch" "6478": "Q: You can upload emotes from a page in the twitch dashboard" "6497": "Q: What is the best way to add to an atlas map? Is it costly to "re-update" the image to the GPU (OpenGL)?" "6544": "Q: What do you think about a tree-based undo system (where you do not lose the redo state when changing after undo, but create branches)?" "6606": "Q: Thoughts on ML, will your game use it?" "6629": "Q: You said you wouldn't use the internet at work. I'd like to do that but then I am missing MSDN and the OpenGL documentation. What do you do when you don't have this info locally available? Asking because I'd prefer not to have the internet around when coding" "6707": "Q: You talked about threading being hard yesterday. Would you use OpenMP if MSVC upgraded, or would you prefer something else?" "6949": "We're all done" --- name: "day496" title: "Debugging Attachment Point Transforms" markers: "0": "Recap and set the stage for the day snapping cat heads onto bodies" "50": "Showcase the asset editing UI, with thoughts on scaling asset pieces" "324": "Storing and transforming alignment points of entities on-demand" "506": "Make UpdateAndRenderEntities() store PieceX, PieceY and PieceP as the basis in which we interpret alignment points" "583": "Set up to break out PushBitmap() into utility functions that provide alignment information for our snapping procedure to use" "671": "Note the imprecision of our 2D sprite vs 3D geometry picking" "756": "Prepare to split up PushBitmap() and PushQuad()" "1189": "Create handmade_renderer_geometry.cpp and .h, introducing WriteQuad() based on PushQuad()" "1709": "Introduce sprite_values and accompanying functions" "2115": "Implement PFromAlignP() and SpriteValuesForUpright() based on GetBitmapDim() and PushBitmap(), introducing SpriteDimFromWorldHeight()" "2566": "Introduce SpriteDimFromWorldHeight(), with a few words on extracting pieces of code into their own functions to be called in whatever combination necessary" "2704": "Reimplement SpriteValuesForUpright() based on PushUpright()" "2917": "Consider the problem of computing the Z-Bias of rotating sprites" "3024": "Add a fourth dimension to the sprite_values axes" "3138": "Z-Bias of Rotated Sprites" "3252": "Z-biasing sprites, respecting their suggested depth (i.e. ones whose lowermost point in Z is some way in from their bottom edge)" "3662": "The mathematics of correct 2D sprite Z-biasing along the camera vector" "4289": "Consider rolling the Z-bias projection from CompileZBiasProgram() into the vertex shader" "4361": "Constructing the Z-bias projection inside the vertex shader" "4591": "Simply sliding sprites forwards along the tile to simulate Z-alignment" "4770": "Continue to implement SpriteValuesForUpright(), postponing our Z-bias story for now" "5378": "Make UpdateAndRenderEntities() use our new geometric rendering functions" "5562": "Run the game to see everything rendering as before" "5575": "Prevent PushSprite() from taking a Size and instead take scaled axes" "6023": "See that the UI all looks fine" "6043": "Change UpdateAndRenderEntities() to use PushSprite() rather than PushBitmap()" "6144": "Find that our sprites are misplaced" "6181": "Investigate our sprite alignment bug" "6396": "Fix the MinP computation in SpriteValuesForUpright()" "6418": "Find that our sprite placement is much better, pointing out our Z-bias problem" "6468": "Decrease the pitch of our camera in UpdateAndRenderWorld()" "6568": "Traverse the world with our lower pitched camera, to find that it doesn't correctly interpolate between rooms" "6691": "Increase our camera's Z-offset from the room in GetCameraOffsetZForDim()" "6831": "Speed up our build by commenting out some compilation lines" "6878": "Traverse the world, with our room interpolation working again, but not the lighting region" "7017": "Set up to implement sprite snapping" "7096": "Make UpdateAndRenderEntities() snap sprites together based on alignment points set in the UI, introducing FindAlign()" "7746": "Run the game to find that our cat hero's body oscillates between two locations" "7770": "Enable UpdateAndRenderEntities() to handle snapping of pieces with no parent alignment point" "7947": "Find that our cat hero's body now correctly stays still" "7963": "Investigate our alignment issue in UpdateAndRenderEntities()" "8111": "Make AddCat() connect the Body piece to the world, introducing ConnectPieceToWorld()" "8448": "Step through UpdateAndRenderEntities() and inspect the bitmap pieces of our cat" "8640": "Realise that the cat (not the cat hero) is showing up" "8738": "Try snapping the regular cat's head to its body successfully, again noting our Z-bias problem" "8897": "Q&A" "9005": "Q: Do you know anything about the state of the series Bitwise? We haven't heard anything from Per in the last two months" "9039": "Q: Why not render with the projection matrix + WM matrices to position?" "9102": "Q: Is wait-free multithreading as difficult as lock-free multithreading?" "9461": "Q: Why not render sprites with the projection matrix resetting its rotation (facing) towards camera?" "9525": "Demo the sprite Z-biasing" "9685": "Q: Can you explain again briefly how you might want to solve the problem of sprites penetrating the ground? Maybe the sprites have to be at a lower angle to the floor so they won't intersect that easily and distort the texture so it looks correct again?" "9731": "Q: Have you read Communicating Sequential Processes by Tony Hoare?" "9735": "Q: Would you mind posting that multithreading paper in chat?" "9770": "Q: Are you planning on allowing camera rotation in the final game? You could reface after certain angles so it still gives you some of what you want" "9829": "Close it up" --- name: "day497" title: "Starting on Asset System Cleanup" markers: "1": "Recap and set the stage for the day cleaning up the asset system" "58": "Showcase our asset editing UI with snapping functionality, setting up to implement scaling and saving" "322": "Plans for after the asset system, making the game look more professional" "434": "Hunt the orphanage for more cats and set Fred's alignment points" "636": "Asset editor: Scaling" "925": "Specify that entities contain their real-world size, and that the scaling information is used to adjust that size, augmenting hha_bitmap with an OrigDim" "1646": "Make UpdateAndRenderEntities() scale sprites using our OrigDim" "1743": "See nothing in-game, because our imported bitmaps all have OrigDim set to 0" "1802": "Reimport our assets" "1850": "See that our fist is now smaller, and the same size in all orientations" "1971": "Make UpdateAndRenderEntities() scale our sprites relative to the world dimensions" "2112": "Find that our cat is larger than hoped" "2128": "Fix UpdateAndRenderEntities() to unpack the sprite piece sizes" "2149": "Try out asset piece scaling" "2323": "Cascading scaling down to children?" "2442": "Storing Z-bias in the asset piece information?" "2630": "Asset editor: Save" "2857": "Saving scheme: "Save" and "Import & Save"" "3053": "Add an "Import & Save" button to our asset editor" "3232": "Test out our new "Import & Save" button, finding that we don't flush our textures" "3423": "Force-flushing textures on import, and generating their mipmaps in temporary buffers before uploading to the GPU" "3976": "Improving our texture loading" "4288": "Prevent LoadBitmap() from taking "Immediate" calls" "4398": "Continued thoughts on texture load improvements" "4491": "Make LoadBitmap() early-out if it cannot get a texture_op handle from the GPU, and allocate no memory itself" "5140": "Improving our texture eviction" "5435": "Introduce the notion of a dirtiness level (UsedGeneration) and consider purging stale textures in bulk" "5817": "Improving asset handles, keeping font glyphs loaded, and putting audio in its own pool" "6076": "Delete asset_memory_header and introduce an asset_audio_buffer" "6303": "Round-robin, continuous audio streaming" "6396": "Round-robin audio streaming, overwriting and marking assets as unloaded" "6498": "Removing asset_audio_buffer in favour of a LoadedAtSampleIndex in asset" "6537": "Streaming audio from a sliding window of an imaginary infinite buffer" "6732": "Augment game_assets with a SampleBuffer and sample indices, in preparation for our sliding window audio streaming scheme" "6832": "Make LoadFont() load the font glyphs directly, for permanent residence" "7596": "Replace LoadAssetWorkDirectly() with LoadAssetWork(), remove the asset_memory_header from asset, and make the bitmap functions use renderer_texture handles" "8144": "Q&A" "8172": "Make the bitmap functions in the entity system, asset editing UI and debug system use renderer_texture handles" "8339": "Q: Sooo maybe extra stream today? And by today you mean in approximately 20h?" "8343": "Q: Could you elaborate more on what you were talking about with more intermediate data structures in object-orientation" "8430": "Q: Near the start of the stream, I think you mentioned focusing on making the game "look more professional". Can you recap what that entails? And does that mean making some artistic decisions on-stream?" "8549": "Q: Oh, and Happy Krampuslauf, Casey! So, is it a specific day or ongoing? How do we celebrate it, besides trying to catch the next episode of Handmade Hero?" "8567": "Q: (A bit off-topic) If I recall correctly, you said that during the Krampuslauf streams you may do some other things like Handmade Ray. What would be the next thing to do with Handmade Ray?" "8604": "Wrap it up" --- name: "day498" title: "Finishing Asset System Cleanup" markers: "0": "Recap and set the stage for the day finishing our asset system cleanup" "49": "Reacquaint ourselves with the renderer_texture queueing / dequeuing code" "300": "Split AddOp() into newly introduced functions CompleteTextureOp() and BeginTextureOp()" "756": "Texture transfer buffer size and circularity" "965": "Implement the texture transfer buffer as an in-order circular buffer, augmenting texture_op_list with TransferMemory and related data" "2008": "Determining the available space in a circular buffer, in both the wrapped and unwrapped cases" "2080": "Make BeginTextureOp() compute the SizeAvailable in both cases" "2403": "Switch InitTextureQueue() to our new TransferMemory circular buffer scheme" "2607": "Tie the game's platform layer and OpenGL renderer in to our TransferMemory" "3082": "Switch the Renderer Test to use our TransferMemory" "3217": "Switch OpenGLAllocateTextures() to our TransferMemory" "4216": "Introduce platform_renderer_limits" "4417": "Make the Renderer Test use our TransferMemory everywhere necessary" "4812": "Step in to LoadBMP() in the Renderer Test to see what we're getting" "5046": "Fix BeginTextureOp() to increase the TransferMemoryUsedCount" "5131": "Step through LoadBMP() in the Renderer Test into BeginTextureOp() to see what it does" "5259": "Fix BeginTextureOp() to enqueue an op when there is enough space available" "5279": "Continue to step through BeginTextureOp() into OpenGLManageTextures() to find that it all works" "5484": "Run the Renderer Test in release mode, and consider stress testing our TransferMemory wrapping" "5553": "Switch the game's asset system over to our TransferMemory" "5741": "Break" "5795": "Make LoadFont() acquire its own memory specially, introducing KeepTemporaryMemory()" "6139": "Switch OutputPlayingSounds() over to use its special sliding window sample buffer" "6548": "Switch the whole game to use our new platform_renderer_limits, and AllocateGameAssets() to use our TransferMemory" "6831": "Hit an assertion in OpenGLManageTextures()" "6870": "Fix that assertion in OpenGLManageTextures()" "6885": "Hit the assertion in GetBitmap()" "6950": "Permit GetBitmap(), GetSoundSamples() and GetFont() to handle any asset with ID 0" "6994": "Run the game okay, see only grey, and step through LoadBitmap() and LoadAssetWork() to see what's going on" "7238": "Make LoadAssetWork() clear the work memory up front" "7364": "Step through LoadAssetWork() and then on to OpenGLManageTextures() to see what happens with our bitmaps" "7538": "Fix LoadBMP() to set the Asset->TextureHandle" "7615": "Find that everything except the white texture loaded correctly" "7649": "Fix AllocateGameAssets() to set the Op->Texture for our white texture" "7688": "Find that everything works fine" "7759": "Implement texture flushing for our "Import & Save" button, introducing UnloadBitmap()" "8072": "Try out our "Import & Save" button, totally successfully" "8154": "Q&A" "8204": "Q: What is going on in your optimized build?" "8243": "Q: Are you optimizing assets or something? I just wanted to know what it looks like" "8389": "Q: Why don't you have any moderators for twitch chat?" "8430": "Q: So MSVC just doesn't do all the inlining stuff by default? Sorry, I'm more of a web dev and don't get this low-level stuff" "8463": "Walk through ComputeLightPropagation() and its disassembly in a debug build" "8637": "Compare the ComputeLightPropagation() assembly in optimised build" "8751": "Q: Newbie question: Wouldn't inlining every function call speed things up? Does the compiler do that when you turn optimizations on?" "9221": "Understanding the "inline" keyword as an advisory to the compiler" "9369": "Close it down" --- name: "day499" title: "Unifying Debug and Editor Modes" markers: "0": "Recap and set the stage for the day" "52": "Set up to unify the debug and asset editing interfaces" "342": "Introduce the notion of a global dev_mode, of which asset editing and profiling are modes" "676": "The categories in our current debug system" "738": "Add keybindings for our modes in GameUpdateAndRender(), making each mode monopolise the keyboard" "1418": "Try out our UI mode-switching keys" "1438": "Set up to split the debug system's UI across modes" "1745": "Make DEBUGDrawElements() draw only the elements associated with the current mode" "2628": "Flesh out GetName() to produce fuller information appropriate to the element's type" "3701": "See no immediate change in the debug UI" "3722": "Change debug variable links to use their linked element's info directly, introducing CreateNameElement()" "4694": "Try out the debug UI and crash in DEBUGBeginInteract()" "4742": "Enable DrawTreeLink() to add child elements to trees" "4828": "Check out our debug UI to find our Root text appearing in the "Profile" section" "4850": "Fix CanHaveChildren() to correctly handle our circular linked list" "4915": "Check out our functional debug UI" "4985": "Make DEBUGEnd() draw only the tree of debug elements associated with the current mode, introducing DrawTree()" "5707": "Try out mode-switching to find our asset editor unexpectedly appearing when pressing F5" "5844": "Fix UpdateAndRenderEditor() to only operate in its own mode" "5876": "Try out our Profile mode, and crash in StringLength()" "5906": "Introduce DEBUG_UI_HUD() for GameUpdateAndRender() to initialise a HUD to house our Profile mode" "6289": "Find that our Profile mode now works" "6296": "Make GameUpdateAndRender() initialise HUDs for all our debug modes" "6330": "Try out all of our debug modes" "6352": "Make DEBUGEnd() snap our UI to the screen corners" "6495": "Try out our debug UI snapped to the corner, noting some inconsistent scaling / positioning" "6590": "Make UpdateAndRenderEditor() draw the UI in UISpace" "6807": "Check out our asset editor sidebar" "6841": "Make DEBUGEnd() also draw the UI in UISpace" "6906": "Check out our debug modes sidebar" "6941": "Q: How would you go about exposing a very object-oriented API to C without ending up in the disaster that DX12 did (with their C API)? Especially if the API has something like a device for its central access point like this gives you queues and surfaces and buffers" "7222": "Q: (Off-topic) Best way of moving data from disk to GPU: What I think I really want is to get a GPU mapped memory chunk and map my asset file right over there (assuming I prepared the data to be GPU friendly). What I have right now is loading from disk into memory and then either doing glBufferSubData or glBufferMapView and copying the data. How can I avoid this copy?" "7953": "Q: Updated the dumpview "spec" a little. Is this a little clearer about things? Also added some elements with a determined length" "8026": "Q: So OOP's fallacy is basically overusing inheritance?" "8368": "Q: Great answer. So is it possible to memory map a file to GPU pinned memory for non texture data then? I think about a complex 3D model. Sounds like you can't avoid this memory copy. I agree that textures are trickier, especially if they are compressed already" "8637": "Q: The main thing I'm concerned with is, since I've never really programmed in OOP (got to know about Handmade Hero early enough), I can't be sure if I'm sometimes transitioning into OOP accidentally. And it really bugs me, since you could say that "device" or "texture" structs are "objects" or something like that" "9260": "Q: In the OOP example that you gave, you assume that you have access to the source code. That might be the case in Handmade Hero but if you're using a library you sometimes don't have access to the cpp sources. Another reason to use unity build without libraries" "9286": "Q: You are right that OOP is bad when every single field of a class has a getter / setter, however in general it is better to only have getters for most fields, making sure they can only be changed by the class itself. It's the same reason globals are generally to be avoided, state changing randomly makes code hard to follow" "9452": "Wrap it up with a recommendation of Krampuslauf" --- name: "day500" title: "Saving HHAs Modified by the In-Game Editor" markers: "1": "Recap and set the stage for the day saving our in-game asset edits" "307": "Dive into saving asset modifications, introducing SaveAllChanges() and WriteAllHHAModifications()" "635": "Fixing "redo"" "794": "Respecify CleanUndoSentinelNext from in_game_editor as a CleanEdit, introducing FindCleanEditList() and EditExistsIn()" "1257": "Fix our "Revert" implementation in UpdateAndRenderEditor()" "1439": "Enable SaveAllChanges() to mark asset files as modified, introducing GetAssetForEdit()" "1950": "Try out our asset editing and saving" "2163": "Relaunch the game to find that our asset information was saved" "2201": "Prevent AddCat() from offsetting the pieces' positions" "2286": "Find that our cat is stuck underground" "2357": "Make UpdateAndRenderEntities() offset asset piece positions after they've been snapped to their parent" "2584": "Find that our cat is not standing on the ground" "2700": "Check how entities get placed" "2919": "Enable drawing of traversable points in UpdateAndRenderEntities()" "3021": "Find that the traversable points are in the right place" "3056": "Make AddCat() call GetSimSpaceTraversable() as per AddPlayer()" "3236": "Find that our cat has moved, but not onto a traversable point" "3259": "Delete GetEntityGroundPoint(), and make UpdateAndRenderEntities() draw entity locations" "3433": "Find that our entity's actual position is wrong" "3473": "Make GenerateRoom() place the floor tiles before placing the entities" "3562": "Find that the cat is now correctly placed on the floor, with only its Z-bias remaining incorrect" "3674": "Offsetting entity pieces in Z" "3762": "Make AddCat() offset the head position 0.1f in Z" "3777": "See the head's displacement, and position our other cats" "4180": "Consider filling out the area around the edges of scenes, and fixing camera interpolation and lighting" "4294": "Check out our art" "4612": "Consider getting our characters in there and making an outdoors area" "4654": "Create an outdoors area in GenerateRoom()" "4805": "Explore the world outside the orphanage, and consider fixing the camera and lighting" "5090": "Camera placement and interpolation" "5176": "Toggle on the hero's light in UpdateAndRenderWorld()" "5235": "Traverse the world, to find that we can leap over single-tile thick walls" "5378": "Reduce the hop search radius in ExecuteBrainHero() to 1.25f" "5402": "Find that we can no longer leap over walls, and consider camera improvements" "5607": "Remove all the lights from the world" "5623": "Traverse our darkened orphanage" "5652": "Camera fixes" "6130": "Make UpdateCameraForEntityMovement() set the camera position relative to the Region->Origin" "6358": "Find that the camera height changes discontinuously" "6402": "Make UpdateCameraForEntityMovement() offset the TargetP.z straight off the bat, and remove OffsetZ from game_camera" "6610": "Find that our camera interpolation remains discontinuous" "6678": "Continue to investigate our camera discontinuity" "6897": "Remove CameraOffset and CameraDolly from UpdateAndRenderWorld()" "7026": "Animation interpolation between absolute positions" "7067": "Make UpdateAndRenderWorld() interpolate the camera between its unmodified positions" "7096": "Find that the camera interpolates correctly" "7150": "Make UpdateCameraForEntityMovement() take a CameraZ from UpdateAndRenderWorld() to offset the camera's actual position" "7210": "Find that the camera interpolation is now buttery smooth" "7285": "Q&A" "7300": "Q: Have you ever found yourself angry with something in the game? Maybe the progress or a certain part? If so, how did you get past it?" "7346": "Q: Are you planning to switch up the interpolation with a smoothdamp function?" "7401": "Q: Do you ever feel like everything needs work to the point it's demotivating / you're not even sure where to start?" "7528": "Q: So we've been debating the merits of using a garbage-collected language like go in a network situation where you have absolutely no prediction of what data loads will be coming in. Do you think a language like go would be a good choice? (I feel like you've answered a question like this, but I honestly don't remember your response)" "7826": "Q: Is it better to work on a fun task or a task that is more important if you have limited time?" "7887": "Understanding the decision to use a technically suboptimal solution, e.g. garbage collection, as a trade-off" "8092": "Wrap it up" --- name: "day501" title: "Importing Orphans" markers: "0": "Welcome to the stream" "19": "Show our correct camera interpolation, and plan to get our hero back in" "126": "Showcase Anna's new art pack, with heads and bodies in different files" "413": "Tag Anna's new body art" "1178": "Name Anna's orphans" "1901": "Add our new tags to the asset_tag_id enum and NameTags array" "2269": "Introduce ImportBody() and ImportHead() for ParsePieces() to call" "2730": "Try to import our new assets" "2781": "Make AddPlayer() use our newly imported hero assets" "3181": "See our hero art in-game, noting that our orientations are backwards" "3245": "Decrease the HeroSizeC in AddPlayer()" "3288": "Check out our smaller hero in-game" "3309": "Make PushLight() draw our light cube fully transparent" "3352": "See our hero more clearly and move towards fixing our facing direction and body picking" "3469": "Change AddPlayer() to add a cat" "3524": "Find that the cat hero is correctly oriented" "3580": "Investigate our facing direction issue" "3757": "Try marking AddPlayer() add Laird" "3811": "Find that Laird is totally correctly oriented" "3841": "Try marking AddPlayer() add the baby" "3856": "Find that the baby is also correctly oriented" "3890": "Turn off the fire particles in UpdateAndRenderEntities()" "3917": "Spot some garbage above the baby's head" "3934": "Check out the baby's source art in GIMP, to determine that it must be an asset-import bug" "4036": "Increase the HeroSizeC in AddPlayer()" "4048": "Check out our baby hero's appearance in-game, noting that the garbage is no longer above the head" "4164": "Make AddPlayer() connect the head to the body" "4222": "Align the baby hero's assets in all orientations" "4457": "Increase the head's Z offset in AddPlayer() to prevent Z-fighting" "4498": "Find that our baby hero's head and body no longer Z-fight" "4585": "Make AddPlayer() add Viva" "4668": "Align Viva's assets, but find that we've been given the baby's head again" "4721": "Make AddPlayer() tag the Body (even for the head)" "4760": "Align Viva's assets" "5009": "Take a walk as Viva" "5097": "Note the incongruous scaling of the orphans in comparison with the walls" "5161": "Decrease the HeroSizeC to 1.25f in AddPlayer()" "5173": "Consider this better because we're not taller than the wall" "5246": "Check out Viva's art in GIMP to find that it is wrong" "5341": "Introduce ReadAssetString() to display annotations in our in-game editor" "5644": "Check out our new "Info" tab in the asset editor" "5667": "Enable AssetEditor() to print asset annotations in the "Info" tab" "5915": "See a blank Name in our annotation printout" "5940": "Introduce AnnotationLabel() for AssetEditor() to call and print out various annotations that we expect to be populated" "6219": "Switch to the "Info" tab and hit our assertion in GetBitmapInfo()" "6336": "Fix GetBitmapInfo() and GetSoundInfo() to handle assets with ID 0" "6365": "Check out the annotated errors in our Info tab" "6427": "Investigate our apparent texture transfer bug" "6573": "Try making BeginTextureOp() fill our required TransferMemory with all white" "6747": "Try in vain to trigger our bug" "6842": "Q&A" "6896": "Introduce AddOrphan() and PlaceOrphan()" "7238": "Visit the orphans in the orphanage" "7309": "Q: So are you going to create a Level Editor as well?" "7329": "Temporarily expand the lighting bounds in UpdateAndRenderWorld()" "7409": "Find that the lighting now covers the screen" "7429": "Q: Any thoughts of using dlopen et al to do some hot reloading shenanigans to help with the "feedback" loop?" "7490": "Q: How does the back buffer work when you resize the window? Do you create a new back buffer matching the window size when the window is resized?" "7557": "Contract the lighting bounds a little in UpdateAndRenderWorld()" "7613": "Q: Quick question, what exactly is the difference between a temp arena and a frame arena? Does the temp arena get collected at a sub-frame interval?" "7790": "Q: Is each character going to have an animation sequence as NPCs, or are they all playable?" "7879": "Q: Petition to rename the baby Judas" "7923": "Stream has ended" --- name: "day502" title: "Adding Stairs to the Generator" markers: "0": "Recap and set the stage for the day" "55": "Set up to continue working on the camera, scrolling and zooming" "225": "Camera: Scrolling in large rooms" "435": "Enable GetCameraOffsetZForDim() to follow the player in large rooms (17×13 tiles and up)" "546": "Try out our scrolling camera" "602": "Treat X and Y separately in UpdateCameraForEntityMovement() to make the camera scroll in long, thin corridors" "686": "Gauge the width of our first corridor" "705": "Adjust the camera distances in GetCameraOffsetZForDim()" "815": "Try out our freely scrolling and room-focused camera" "900": "Adjust the camera distances in GetCameraOffsetZForDim()" "935": "Try out our freely scrolling and room-focused camera" "955": "Prevent CreateOrphanage() from sticking a person in the main room" "978": "Traverse the orphanage into the large main room and out to the forest" "1206": "Reduce the ray count to 1 in ComputeLightPropagation()" "1222": "Traverse the orphanage discotheque" "1246": "Increase the ray count to 8 in ComputeLightPropagation()" "1250": "Traverse the orphanage, noting that we'll need a further-reaching lighting solution" "1291": "World generation: Stairwells" "1494": "Allow GenerateRoom() to colour-code our entities" "1518": "Check out our room connections and stairwell locations" "1610": "Make PlaceRoomAlongEdge() expand the area of stairwells, introducing AddRadiusTo()" "1896": "Check out our expanded stairwell" "1957": "Articulating the direction of stairwells" "2150": "Augment gen_room_connection with PlacedDirection for PlaceRoom() to set, introducing GetOtherSide()" "2426": "Introduce GetRoomConnectionTo()" "2864": "Set up GenerateRoom() to handle stairwells" "2920": "Traverse the orphanage to see that our stairwell generation didn't work" "2952": "Add Save / Load Startup Location buttons to our UI, introducing CameraEditor()" "3218": "Reorganise the asset editor UI" "3430": "Check out our camera UI" "3476": "Scan through our stairwell generation code" "3565": "Step in to PlaceRoomAlongEdge() in the stairwell placement cases" "3695": "Move the stairwell connection code from PlaceRoom() to PlaceRoomAlongEdge()" "3878": "Investigate the Intersect() call in PlaceRoomAlongEdge()" "4035": "Make PlaceRoomAlongEdge() generate room connections" "4166": "Traverse the world to our successfully generated stairwell hole" "4210": "Make GenerateRoom() create traversable stairs in their stairwells" "4819": "Try out our new stairwell" "4846": "Adjust our stairwell in GenerateRoom()" "4937": "Try out our new stairwell" "4978": "Make GenerateRoom() compute the depth of the stairs based on the tile depth" "5034": "Step in to GenerateRoom() to see what's going on with the stairs" "5115": "Check out our deeper stairwell in-game" "5183": "Investigate our inability to traverse deep stairs" "5354": "Allow GetClosestTraversable() to pick locations further below us" "5472": "Try to get a handle on our stairwell traversal" "5531": "Toggle on the traversable debug visualisation in UpdateAndRenderEntities()" "5621": "Make GetClosestTraversable() consider traversable tiles 0.5f below and above us" "5714": "Make CreateWorld() place the hero at the forest entrance" "5790": "Try to launch the game with the hero placed at the forest entrance, and crash in GetHashFromID()" "6013": "Add a ClippedZ traversable_search_flag for CheckForJoiningPlayer() to pass to GetClosestTraversable()" "6092": "Find that we now start at the forest entrance" "6102": "Make ExecuteBrainHero() pass TraversableSearch_ClippedZ to GetClosestTraversable()" "6131": "Find that we still cannot hop down the stairs" "6150": "Increase the Z search area of GetClosestTraversable()" "6173": "Try to perform looped live code editing to debug our stairwell traversal" "6240": "Set the FrameArena to PlatformMemory_NotRestored to fix looped live code editing" "6352": "Try looped live code editing" "6373": "Change the FrameArena to be cleared rather than ended" "6456": "Try looped live code editing and crash when clearing the FrameArena" "6476": "Refrain from setting FrameArena to PlatformMemory_NotRestored" "6503": "Try looped live code editing and again crash when clearing the FrameArena" "6639": "Investigate our looped live code editing bug" "7145": "Make Win32AllocateMemory() and Win32DeallocateMemory() respect the PlatformMemory_NotRestored flag" "7249": "Find that looped live code editing works, but that we are leaking memory" "7311": "Change the FrameArena to be allocated separately" "7806": "Find that looped live code editing works without leaking memory" "7856": "Record a loop trying to traverse the stairs, and break into GetClosestTraversable()" "8343": "Consider simplifying the problem" "8383": "Try adjusting the stair depth in GenerateRoom()" "8516": "Find that a stair height of 0.75f combined with our Z randomisation can prevent us from traversing them" "8587": "Find out what TileDim.z gets set to" "8799": "Make GenerateRoom() and GetClosestTraversable() handle stairs with our understanding of the typical floor height" "8830": "Traverse down our stairs successfully" "8858": "Increase the NearClipPlane in UpdateAndRenderWorld()" "9055": "Change UpdateAndRenderWorld() to set the Fog and AlphaClip based on the world Z" "9103": "Check out our fogging and alpha clipping" "9205": "Adjust the camera in GetCameraOffsetZForDim()" "9258": "Try out our adjusted camera" "9287": "Adjust the AlphaClip in UpdateAndRenderWorld() and toggle off the traversable points debug visualisation" "9355": "Consider that to be pretty good" "9413": "Q&A" "9445": "Disable the moonlight in ComputeLightPropagation()" "9458": "Traverse the orphanage without the moonlight" "9497": "Q: Hey Casey, I'm trying to load the "Complete set of V0 HHAs" data set with the latest GitHub Handmade Hero code, but it doesn't work. It runs in an access violation in Assets->Tags[AssetTagIndex].ID == Tag_BasicCategory. What I'm doing wrong?" "9563": "Q: What's the status on the RAD debugger?" "9574": "Q: The head just clipped into the wall, if I saw correctly. Do you plan on doing Z-buffer tricks to keep sprites from being hidden by 3D geometry?" "9622": "Temporarily make PushSprite() apply some Z-bias" "9634": "Show our Z-bias situation in-game" "9698": "Crash in BeginWorldChange()" "9723": "Increase the size of our entity_hash array" "9774": "Q: Can you explain the difference between HeapAlloc and VirtualAlloc and for what scenario they are appropriate?" "9986": "Q: What kind of allocation do you use for assets (stack, heap, etc)?" "10020": "Q: What does the "OnLamp" variable represent?" "10040": "Temporarily enable the corner lamps" "10109": "Close it down" --- name: "day503" title: "Constructing a Camera Easing Function" markers: "0": "Set up to work on camera functionality" "327": "Meaningful Fog and AlphaClip parameters" "558": "Fading floors and moving the camera" "712": "Return from OBS crash" "795": "Defining our camera clipping boundaries" "842": "Reacquaint ourselves with the fogging and alpha clipping code in CompileZBiasProgram()" "1108": "Parameterising our fogging and alpha clipping" "1153": "Augment game_camera with ExpectedFloorAtZ on which to base our fog and alpha clip parameters" "1547": "Check out our heavily fogged orphanage" "1615": "Augment game_state with Alpha and Fog parameters for our in-game camera editor to use" "2120": "Try out our new fog and alpha controls" "2147": "Move the Alpha and Fog from game_state into game_mode_world, and add ExpectedFloorZ to our UI" "2509": "Try out our camera editor UI" "2621": "Swap AlphaMax and AlphaMin in UpdateAndRenderWorld()" "2650": "See that the alpha fade is being applied in camera space, not world space" "2682": "Rename FogMax and AlphaMax to FogSpan and AlphaSpan respectively" "2776": "Find that FogMin is not working as expected" "2837": "See how the Fog is computed in CompileZBiasProgram()" "2966": "Remove the NearClipPlane from the Alpha computation in SetCameraTransform()" "3006": "Continue to investigate our Fog computation in CompileZBiasProgram()" "3071": "Fog premultiplied alpha in CompileZBiasProgram()" "3277": "Make CompileZBiasProgram() correctly blend the fog using premultipled alpha" "3308": "“That seems like the best plan to me; don't quote me on it.”" "3316": "Hit our "Shader validation failed" assertion in OpenGLCreateProgram()" "3326": "Fix CompileZBiasProgram() to only multiply in the alpha in the Lerp() call" "3341": "Adjust our fogging parameters to try and make sense of them" "3546": "Bracketing the alpha clip and fogging to contain the player" "3584": "Expand our notion of camera focus in game_camera to represent a range, for UpdateCameraForEntityMovement() to set" "3968": "Find that our ExpectedFloorMinZ is not as expected" "4090": "Fix the EntityFocusZ computation in UpdateCameraForEntityMovement()" "4117": "Find that the bracket is set correctly, but the alpha is wrong" "4152": "Fix the FocusMinZ and FocusMaxZ computations in UpdateAndRenderWorld()" "4163": "Find that our AlphaClip and Fog bracket works beautifully" "4191": "Proactive camera interpolation" "4382": "Interpolation functions" "4516": "Position our hero in her bedroom" "4597": "Traverse the orphanage between rooms" "4619": "Change the camera only to interpolate positions when we change rooms" "4708": "Traverse the orphanage to trigger camera interpolation" "4772": "Make UpdateCameraForEntityMovement() trigger camera interpolation, keeping track of the FromP and TargetP, and using a tInterpolation value" "4942": "Find that our camera interpolation is linear" "4961": "Make UpdateCameraForEntityMovement() use the Square function to interpolate the camera" "5023": "Check out our Squared camera interpolation" "5033": "Make UpdateCameraForEntityMovement() use the SquareRoot function to interpolate the camera" "5042": "Check out our Square rooted camera interpolation" "5077": "Interpolation functions" "5400": "Understanding rates of change, and polynomials" "5859": "Shaping our desired interpolation curve" "6002": "Bézier curves" "6677": "Plug our derivatives into Desmos" "6875": "Make UpdateCameraForEntityMovement() interpolate the camera using our ease-in-ease-out function" "6943": "Check out our camera interpolation" "6992": "Q&A" "7033": "Q: The site actually had support for variables. It was giving you a slider to edit the values" "7050": "Try to use variables in a Desmos function" "7269": "Q: Could we also describe the easy-in / -out via a sine function?" "7306": "Q: I noticed that you used t*t*t for t cubed. Does C have support for something like t**3 for exponents?" "7383": "Q: Have you tested the new transition going up and down the stairs?" "7461": "Q: By setting the u and v values to negative, you can get things like "overshoot" where the camera goes over and then corrects back. I don't think it will be a good feel in Handmade Hero's case, but for some cases that is really good" "7469": "Try making UpdateCameraForEntityMovement() interpolate the camera using an overshooting function" "7670": "Check out our overshooting camera" "7718": "Revert UpdateCameraForEntityMovement() to perform an ease-in-ease-out camera interpolation" "7757": "Save our Desmos curve" "7898": "It's been a pleasure" --- name: "day504" title: "Exploring Camera Interpolation Alternatives" markers: "0": "Recap and set the stage for the day" "48": "Show our camera transitions, noting our desire to follow a moving target" "184": "Moving Camera Target" "406": "Interpolating camera between unknown start and end locations" "872": "Respecifying camera room transitions as taking a constant time" "982": "Change UpdateCameraForEntityMovement() to follow the player, but interpolate the camera on room changes" "1010": "Show the player-locked camera behaviour" "1093": "Change UpdateCameraForEntityMovement() to interpolate the camera between "large" distances, removing InRoom from game_camera" "1308": "Try out our new distance-based (as opposed to room-based) camera, finding weird behaviour on the stairs" "1342": "Investigate that weird camera behaviour on the stairs" "1462": "Make UpdateCameraForEntityMovement() interpolate all camera movements" "1538": "Try out our interpolated camera to again see the positional hiccough on the stairs" "1578": "Investigate our camera's positional hiccough" "1710": "Enable UpdateCameraForEntityMovement() to restart camera interpolation when the target changes" "1952": "Try out our newly restarting camera interpolation, to still see a positional hiccough" "2019": "Reduce the MaxDistancePerFrame() in UpdateCameraForEntityMovement(), and initialise the hero at the forest stairs" "2053": "Take a closer look at our camera's positional hiccough on the stairs" "2074": "Continue to investigate our camera's positional hiccough" "2160": "Fix UpdateCameraForEntityMovement() to restart camera interpolation if either the starting or ending positions move" "2182": "See a camera glitch on chunk boundaries" "2205": "Continue to investigate our camera's positional hiccough" "2267": "Assert in UpdateCameraForEntityMovement() if we are not in a room" "2286": "Happily fail to hit that assertion" "2296": "Continue to investigate our camera's positional hiccough" "2357": "Make UpdateCameraForEntityMovement() restart camera interpolation more smoothly" "2652": "Find that we've fixed the camera's positional hiccough" "2685": "Camera phases: Acceleration, Max Speed and Deceleration" "2819": "Figuring out our options for getting the target velocity" "2940": "Initialise the hero in her bedroom" "2975": "Show our current camera easing" "2983": "Change UpdateCameraForEntityMovement() to base camera interpolation on accelerations, rather than start and end positions" "3621": "Differentiating between the acceleration and deceleration regions" "3714": "Make UpdateCameraForEntityMovement() compute the velocity in addition to the acceleration" "3962": "Solving for our position along a three-phased camera interpolation curve" "4190": "Solving for our position along a parabolic curve" "4598": "Parameterising our camera interpolation on the "total curve length" and our "t along the curve"" "5622": "Change game_camera to contain our position, velocity and acceleration along the interpolation curve" "5772": "Solving for our velocity and acceleration along an interpolation curve, knowing our position" "5997": "Plug our equations into WolframAlpha" "6261": "Solving for our acceleration along a uniform curve based on our current velocity" "6433": "Remove dt and ddt from game_camera" "6634": "Storing and heuristically adjusting our length and t value from last frame" "6717": "Begin to make UpdateCameraForEntityMovement() step along our camera interpolation curve using the t and DeltaP from the last frame" "7200": "Consider other options for camera interpolation" "7326": "Make UpdateCameraForEntityMovement() update our velocity based on a curve rule" "7698": "Check out our camera interpolation" "7729": "Make UpdateCameraForEntityMovement() compute our camera's velocity by mapping onto specified acceleration / deceleration curves" "8550": "Find that our camera interpolation sort of works" "8579": "Change game_camera to store the ddP, and UpdateCameraForEntityMovement() to compute this as well as the dP" "8759": "See a hitch in our camera" "8823": "Fix UpdateCameraForEntityMovement() to use the AccelRange to compute the ddP along the acceleration curve, and to lerp along the deceleration curve" "9177": "Try out our camera" "9198": "Increase our acceleration and deceleration curve ranges in UpdateCameraForEntityMovement()" "9268": "Try out our camera" "9283": "Make UpdateCameraForEntityMovement() update the camera's P in the deceleration curve case" "9691": "Consider solving for the deceleration curve from our current velocity to 0" "9867": "Temporarily make UpdateCameraForEntityMovement() interpolate the camera using a proportional derivative controller" "10511": "Try out our proportional derivative controlled camera" "10654": "Blending the camera focus range, for alpha clip and fogging purposes" "10954": "Synchronising that camera focus" "11007": "Make UpdateCameraForEntityMovement() include the camera focus range in our proportional derivative controller" "11317": "Try out our fully proportional derivative controlled camera" "11481": "Q&A" "11512": "Q: In episode 392 you thought about moving Molly Rocket to Linux. Are you still thinking about that? What about the lack of proper debuggers?" "11674": "Q: Is the plan to change the character facing direction when they move in a direction, or will that be mapped to a different key?" "11762": "Q: If there were a truly good (better than VS's) debugger for Linux, would that make Linux viable for gamedev?" "11793": "Q: It looks like the "average" sized room is currently too big to be seen without scrolling. Is that what we want in the end, or is it just that average room size is still undecided?" "11819": "Q: I started watching at the beginning, and I'm up to episode 024. Did any code get released? Is any code public domain?" "11829": "Q: Did the updated speed get applied into the camera for the fog / alpha interpolation?" "11834": "Wrap it up" --- name: "day505" title: "Placing Multiple Entities at a Time" markers: "0": "Recap and set the stage for the first day in the new office, only possible today thanks to Jon and Anna" "240": "Show our proportional derivative controlled camera behaviour" "377": "Plan to clean out the camera wobble in Z, cap the speed at which the camera considers changes and re-enable the debug camera" "601": "Hit the InvalidCodePath in BeginWorldChange()" "681": "Restart to get the correct font size in 4coder, and reset the timer" "886": "Increase the MaxEntityCount and MaxBrainCount in BeginWorldChange()" "959": "Consider introducing a special camera for NPC interactions" "998": "Special camera" "1360": "Enable UpdateCameraForEntityMovement() to handle special camera regions inside rooms more specifically" "1489": "Change UpdateCameraForEntityMovement() to offset special cameras relative to the enclosure, rather than the simulation centre" "1732": "Special camera triggers" "1947": "Set up to enable GenerateRoom() to query entity placement, introducing gen_room_grid" "3274": "Introduce gen_entity_group for GenerateRoom() to place and tag grouped entities" "3896": "Grouping entities, introducing AddEntityGroup() and a version of PlaceEntity() that chains entities onto a group" "4879": "Introduce FindPlaceToPutEntityGroup()" "5224": "Find that we placed our entities correctly" "5243": "Plausible placement of entity group members" "5300": "Remove P from gen_room_tile_query" "5451": "Dual-entity and special camera placement" "5521": "Introduce RecursiveOpenTileSearch() to place an entire entity group" "6745": "Introduce a version of + for gen_v3" "6807": "Find that the game works" "6853": "Try making PlaceOrphan() place a cat to the south of each orphan, to test our entity grouping" "7132": "Fix RecursiveOpenTileSearch() to set Tile->Open to true if it couldn't place an entity" "7229": "Find cats positioned to the south of orphans" "7242": "Try making PlaceOrphan() place a cat to the north of each orphan" "7256": "Find cats positioned to the north of orphans" "7271": "Q&A" "7359": "Q: Haven't done much on dumpview lately as it's pending a rewrite in Odin. But I did just get to use dumpview for the first time today. Here is some usage code. And for those asking this is not Jai, it's Odin" "7373": "Q: Could you make an elevator in the game?" "7404": "Q: Hey Casey! Off-topic: Is it beneficial performance-wise to use switch statements instead of if-else blocks? As far as I could understand from disassembly, using switch statement allows to compute where to jump to directly, without invoking the cmp instruction for each case. Is that correct?" "7500": "Off-topic, but I watched your 30 Million Lines of Code, and was wondering whether you think that Intel and other hardware manufacturers would be more likely to adopt an ISA as a response to consumer-unfriendly policies from Microsoft (if they're scared of consumer PC markets collapsing)?" "7710": "Q: Are all rooms going to be procedurally generated or are they gonna be hand-cranked and then just populated with certain entities procedurally?" "7714": "Q: Have you played any of the Souls games? What do you think of them? (I don't know if I asked this question before)" "7730": "Is the game going to contain both 2D and 3D assets? Or are the cubes only for testing purposes?" "7764": "Q: Regarding Intel shipping their own "platform that just runs": How would that look? Would there be a minimalistic OS boot up once you power on the machine? Sorry, if this is obvious but I don't quite get it" "7958": "Q: Favourite cheese?" "7986": "Q: Any more office moving drama / insanity to share? Has the reason for the move been talked about?" "8028": "Wrap it up" --- name: "day506" title: "Improving Camera Motion" markers: "0": "Recap our new entity grouping functionality and set the stage for the day" "119": "Show off our orphan–cat groups" "182": "Create a special camera-triggering entity region, introducing AddConversation() and GetCameraOffsetZForCloseup()" "789": "Toggle on the entity bounds debug visualisation in UpdateAndRenderEntities()" "848": "Check out our entity bounds debug visualisation" "938": "Make PlaceOrphan() position the orphan facing downwards" "979": "Announce the upcoming Tau vs Pi rant" "1022": "Change PlaceOrphan() to add a conversation rather than a cat" "1050": "Find that the conversation boxes are misplaced" "1068": "Fix AddConversation() to correctly position the entity" "1090": "Find that the conversations are correctly positioned" "1119": "Recompile in debug mode" "1155": "Step in to UpdateCameraForEntityMovement() to find that we never get to the special camera case" "1272": "Make AddConversation() create a larger collision box" "1301": "Step in to UpdateCameraForEntityMovement() to find that we now trigger the special camera case" "1459": "Make GetCameraOffsetZForCloseup() zoom in closer" "1505": "Try out our conversation zoom" "1574": "Make AddConversation() offset the camera northwards" "1604": "Try out our offset conversation zoom" "1657": "Plan to improve the camera code: damping hopping motion; alpha clipping interpolation; reintroducing debug camera; computing lighting for the entire visible area" "1828": "Harmonising the alpha clip and camera movement interpolation" "2051": "Mathematically tie together the alpha clip and camera position interpolation in UpdateCameraForEntityMovement()" "2621": "Try out our newly harmonised camera" "2711": "Fix UpdateCameraForEntityMovement() to use the target camera position directly if it's close enough" "2860": "Try out our harmonised camera" "2930": "Try out smaller values for the AlphaMin and AlphaSpan" "3170": "Reduce the AlphaMin and AlphaSpan in PlayWorld()" "3184": "Plan to damp the camera Z motion" "3392": "Only moving the camera when the player has moved far enough, on each axis separately" "3522": "Augment game_camera with a MovementMask for UpdateCameraForEntityMovement() to modify the camera's position" "3620": "See that our camera is unexpectedly working" "3648": "Use the computed TotalDeltaP in UpdateCameraForEntityMovement()" "3799": "See nothing, as expected" "3810": "Use Camera->MovementMask in UpdateCameraForEntityMovement() to move the camera above a threshold" "3995": "Try out our camera movement threshold" "4028": "Increase the camera movement threshold in UpdateCameraForEntityMovement()" "4057": "Try out our camera movement threshold" "4106": "Investigate our threshold and camera movement masking" "4469": "Add camera data to the debug system" "4591": "Find that the camera's Y values are already wrong at startup" "4614": "Print the TotalDeltaP after doing the Hadamard product with the MovementMask" "4735": "Traverse the orphanage, watching the camera data printout" "4940": "Interpolate the camera when the target position is below 0.01f in UpdateCameraForEntityMovement()" "5001": "Find that the camera position interpolates forever" "5157": "Fix UpdateCameraForEntityMovement() to only interpolate the camera when the target position is above 0.01f" "5196": "Find that the camera interpolation is discontinuous" "5204": "Increase that target distance threshold in UpdateCameraForEntityMovement()" "5250": "Try out our stabilising camera, still with slight wonkiness" "5281": "Remove that target threshold, and reduce the deceleration of our proportional derivative controller from 6 to 2" "5311": "Try out our camera to find it overshoots" "5316": "Increase the deceleration of our proportional derivative controller from 2 to 3" "5318": "Traverse the orphanage to still find overshoot in the camera, increasing the deceleration value to 5.5" "5465": "Reduce that deceleration value to 5.25" "5479": "Try out our camera, and consider making the MovementMask signed" "5594": "Let the camera smoothly change direction in UpdateCameraForEntityMovement()" "5748": "Try out camera direction changing" "5773": "Reduce the camera speed threshold in UpdateCameraForEntityMovement()" "5782": "Try out camera direction changing" "5829": "Cold set the camera's velocity when it is close enough to the target" "5844": "Try out the camera to find that the special camera gets positioned incorrectly" "5875": "Make the special camera set the Camera->MovementMask to 1, 1, 1" "5903": "Try out the special camera" "5990": "Q&A" "6027": "Make ExecuteBrainHero() position the glove with the hero" "6169": "Find that the glove stays with the hero" "6265": "Q: I'm still not sure I understand the reason why you don't store the "actual" position and smoothly scrolling between tiles, and the "animation" position doing the bouncing? The bouncing should only have to be dealt with during render and can be derived from the "actual" position, and so you don't have to store it anywhere. Am I wrong about that?" "6417": "Q: What was the plan for lighting on the sprites?" "6473": "Q: Is the variance in lighting just a side effect of the random sample?" "6497": "Q: Off-topic but how do you stay motivated on long projects like this? I usually would lose interest much earlier, and am wondering if there are techniques to want to keep working for on the same game for many years" "6720": "Q: How big is Handmade Hero?" "6816": "Q: Do you ever get burnt out? What does it take for that? Have you noticed a change in your mental stamina as you've gotten older?" "6954": "Q: How long does a full rebuild take?" "7010": "Q: Motivation: I can recommend your chat about the imposter syndrome.It helped me a lot. I used to have way too high expectations of what I can do in a day. I reduced that expectation and set myself smaller goals for each day. Way easier to even start then and I was surprised how quickly I got way more done than I initially wanted to do" "7217": "Q: Do you ever experience having no idea on how to approach a specific problem and have that negatively impact how productive you are? Any tip on how to deal with it?" "7436": "Roll it up for 2018" --- name: "day507" title: "LRU Texture Handle Reuse" markers: "0": "Set the stage for an unannounced day mopping up issues" "107": "Watch the cutscene for incorrect rendering" "351": "Watch the cutscene for a second time, considering that we have a texture transfer problem" "417": "Refamiliarise ourselves with the texture transfer code" "890": "Consult docs.GL on glTexImage3D and glPixelStore" "1124": "Consider instrumenting OpenGLManageTextures() and watch the cutscene to see our rendering artifacts at different places" "1314": "Watch the cutscene under NSight" "1476": "Capture a frame during our glitch and inspect the textures" "1728": "Investigate whether or not we are properly reserving our texture transfer memory" "2265": "Circular buffer usage cases" "2525": "Fix our circular buffer usage in BeginTextureOp(), replacing TransferMemoryUsedCount with TransferMemoryLastUsed in renderer_texture_queue" "3064": "Watch the cutscene to see no texture transfer errors first time round" "3292": "Find that the cutscene is busted second time round" "3400": "Address the "Check z coordinates of cutscene" issue" "3549": "Make RenderCutsceneAtTime() start the cutscene at scene 6" "3617": "Increase the Z of scene 6's fourth layer from -3.0 to -2.9" "3633": "See fearful tears appear, and close that issue" "3689": "Texture handle recycling" "3989": "Implement least-recently-used (LRU) texture handle recycling in GetBitmap()" "5074": "Initialise our LRU texture handle lists in AllocateGameAssets(), and introduce AcquireTextureHandle()" "5996": "Watch the cutscene to find that our new LRU texture handle recycling has solved our problem" "6386": "Close the "Add texture handle recycling to asset system" issue" "6420": "Fix S32FromZ() to use the Ignored pointer" "6491": "Close the "S32FromZ unused variable by mistake (minor)" issue" "6522": ""Sign extension bug" issue" "6745": "Step in to Win32ProcessPendingMessages() to see the sign extension occurring in the disassembly" "6780": "Prevent IsDown in Win32ProcessPendingMessages() from being sign extended" "6800": "Step in to Win32ProcessPendingMessages() to see that sign extension no longer occurs" "6983": "Close the "Sign extension bug" issue" "7018": ""Can still call OpenGL.DebugLightBufferTexIndex / OpenGL.DebugLightBufferIndex in release mode" issue" "7072": "Remove DebugLightBufferIndex and DebugLightBufferTexIndex from the open_gl struct" "7097": "Close that issue" "7134": ""Avoid hard dependency on OpenGL 4.2 (glTexStorage3D)" issue" "7174": "Make OpenGLInit() pass 0 as the level to the glTexImage3D() call" "7208": "Find that that works" "7248": "Close that issue" "7322": "Q&A" "7374": "Q: Does 4coder support indenting of shader code yet?" "7459": "Q: Personally I've only ever used LRU caches. Have you ever used LFU, and has it worked well?" "7503": "(least frequently used)" "7865": "LFU has more overhead than LRU. More accounting, but statistically it supposedly converges to the same expected values" "7946": "Custom emotes" "8047": "Q: Owl of Shame emote, Pig Hat emote for starters" "8098": "Q: Go look at the Handmade Network discord's emotes" "8102": "Q: Jon Blow's face" "8117": "Lemongrab" "8157": "Wrap it up" --- name: "day508" title: "Fixing the Remaining GitHub Issues" markers: "0": "Recap and set the stage for the bonus stream" "118": "Close "Segfault in handmade_brain.cpp:277" issue" "220": "Addressing the "Trouble with NVIDIA Optimus" issue, with a few words on power efficiency" "723": "Check out win32_handmade.exe in Dependencies" "837": "Check out the export table of win32_handmade_opengl.dll in Dependencies" "959": "Export the NvOptimusEnablement and AmdPowerXpressRequestHighPerformance symbols" "1018": "Check out the new export table of win32_handmade.exe in Dependencies" "1097": "Close that issue" "1154": "Addressing the "Linux updates" issue" "1199": "Rename various struct members so they don't clash with system definitions of Linux" "1291": "Understanding Linux's mmap() in contrast to Windows' VirtualFree()" "1562": "Delete the file io function pointers from platform_api and remove Win32ResizeDIBSection()" "1991": "Try to run the game, crash in OpenGLEndFrame() and investigate why" "2099": "Temporarily disable the window-moving case in Win32MainWindowCallback()" "2118": "Find that the game runs, but cannot be resized" "2136": "Investigate why we cannot resize our window" "2252": "Find that we can resize after all, but that our cursor remains as the regular pointer" "2311": "Make Win32MainWindowCallback() use the "resize" cursor" "2345": "Find that we now get the resizing cursor" "2509": "Enable aspect-ratio preserving resize in Win32MainWindowCallback()" "2622": "Find that our aspect-ratio preserving resize works fine" "2647": "Replace win32_window_dimension with a v2u, and delete win32_offscreen_buffer" "2723": "Ensure that platform_memory_block contains a Size" "2824": "Close that issue" "2885": "Addressing the "Window fullscreen bug" issue" "2903": "Try out window movement keys to find that "minimise" breaks CreatFramebuffer()" "2993": "Try unsuccessfully to reproduce the bug from the issue" "3065": "Check out our window management code" "3224": "Enable Win32MainWindowCallback() to handle resizing to encompass the entire screen" "3578": "Find that fullscreening does not work" "3622": "Step in to Win32MainWindowCallback() in the BecomingFullscreen case" "3803": "Make ToggleFullscreen() disable WS_OVERLAPPEDWINDOW in the window's style" "4006": "Try to snoop our window messages in Spy++" "4136": "Add Spy++ 64-bit to MSVC" "4207": "Snoop our window messages in Spy++" "4476": "Enable Win32MainWindowCallback() handle WM_WINDOWPOSCHANGED messages" "4602": "Find that our window management works better" "4644": "Prevent ToggleFullscreen() from disabling WS_OVERLAPPEDWINDOW in the window's style" "4671": "Find that the window management magically works" "4814": "Prepare to close that issue" "4890": "Investigate why our window width and height are getting zeroed out" "5105": "Make BeginUIFrame() only use the DrawRegion, renaming WindowWidth and WindowHeight in game_render_commands to OSWindowWidth and OSWindowHeight" "5393": "Find that our UI is now correctly aligned" "5420": "Trigger our "minimise" bug to find that we are rendering directly to the window resolution requested of us" "5575": "Make BeginUIFrame() and OpenGLBeginFrame() use the renderer's width and height, renaming DrawRegion in game_render_commands to OSDrawRegion" "6101": "Find that we have fixed our "minimise" bug" "6312": "Close that issue" "6324": "Check the "Fog is broken" issue in-game" "6450": "Introduce AddSnake() and related functions for CreateDungeon() to call" "6838": "Hit our assertion in RecursiveOpenTileSearch()" "7094": "Try placing the snake in the hero's bedroom" "7112": "See the snake just fine" "7156": "Make AddSnake() elevate the body and brighten the light" "7194": "Check out our snake" "7267": "Fix AddEntity() to use non-temporary memory, and make CreateDungeon() call AddSnake() again" "7459": "Find our snake in the dungeon, but see that the lighting down there is not correctly fogged" "7541": "Investigate the fog's alpha computation in CompileZBiasProgram()" "7826": "Make CompileZBiasProgram() compute the lighting before the fogging" "8049": "Find that the fogging now fogs to black" "8090": "Scrutinise the fogging in CompileZBiasProgram()" "8237": "Make CompileZBiasProgram() compute SurfaceReflect at the end" "8316": "Find that the fogging now works correctly" "8431": "Close that issue" "8474": "Q&A" "8486": "Investigate twitching" "8648": "Call it a day" --- name: "day509" title: "Creating Tags Files" markers: "0": "Briefly recap our 4coder upgrade and set the stage for the day" "67": "Set up to try out George Menhorn's RemedyBG debugger" "212": "Admire the concision of RemedyBG's distribution" "324": "Create remedybg.bat, making it run RemedyBG in its own directory to keep imgui.ini files in one place" "549": "Take a first look at RemedyBG" "724": "RemedyBG feedback: Need threads function / library name" "855": "RemedyBG feedback: Breakpoints in release vs debug build" "1093": "Praise RemedyBG's separate source and assembly windows" "1258": "Organise our RemedyBG windows" "1372": "RemedyBG feedback: Watch window, out-of-scope variable resolution, keyboard-expandable compound types and editable names" "1793": "RemedyBG feedback: Call stack window, need for a more concise view" "1856": "RemedyBG feedback: Breakpoints window" "1964": "RemedyBG feedback: Watch window, casting" "2108": "RemedyBG feedback: Memory window, HexII and needing easier ways to set the address" "2340": "Final optimistic thoughts on RemedyBG with thanks to George" "2619": "Consult our open issues" "2701": "Update the README to discuss new downloads" "3480": "Consider our need to simplify and speed up the lighting and finish our asset system" "3664": "Separate the asset markup and source files" "4034": "Revert our asset source file names back to their originals, and make a markup file responsible for tagging" "4315": "Single vs multiple markup files" "4479": "Create base_game.txt and intro_cutscene.txt and tag all our assets" "6287": "Organise our base_game.txt and intro_cutscene.txt files into a tags directory for ease of distribution" "6570": "Consider our next steps in terms of maintaining the tags files" "6868": "Introduce a default block in base_game.hht" "6973": "Q&A" "7002": "Q: When utilizing the entity scheme, you mentioned in the pre-stream the single inheritance scheme. How would you implement functionality to allow modding of the game’s existing entities, and the code handling them (such as a physics overhaul mod which replaces the physics system in the game)." "7234": "Q: So what did WinDBG do better than VS' debugger? Have you thought about using it in the interim between now and when RemedyBG is ready?" "7381": "Q: Getting a bit fancy here, but do you think it'd be handy to have "scoped defaults" in the .hht? So you could have multiple defaults in a file, each of which has its own scope full of assets" "7450": "Q: Did you know you can use the /d1reportTime flag for cl to see where the compiler spends its time?" "7668": "Wrap it up" --- name: "day510" title: "Making a Parser for HHTs" markers: "3": "Welcome to the stream" "33": "Announce a job opening on the game Sub Rosa by Alex Austin" "371": "Fix typos in base_game.hht" "524": "Note the need to search for asset files" "704": "Consider allowing for placeholder stubs of nonexistent assets" "937": "Set up to make our existing parsing code usable by multiple routines" "1150": "Get the simple_preprocessor building" "1470": "Save off handmade_generated.h as handmade_generated_original.h and diff them with Meld" "1598": "Intentionally break the tokenizer and see the diff in Meld" "1679": "Pull out the tokenizing code from the simple_preprocessor into handmade_tokenizer.cpp and .h" "1817": "Convert the token struct to contain a length-string" "2171": "Organise the string manipulation code into handmade_shared.h" "2554": "Convert the whole tokenizer over to use length-strings, introducing Tokenizer()" "2858": "Update EatAllWhitespace() and GetToken() to use length-strings, noting that hand-coded token checking is the one thing made harder by length-strings vs null-terminated ones" "3369": "Introduce AdvanceChars() and Refill()" "3637": "Find that our generated files are identical" "3721": "Introduce ParseHHT() in a newly created handmade_hht.cpp, augmenting the tokenizer to handle all the single-character tokens in our .hht file format" "4580": "Make ParseTopLevelBlock() use RequireToken() and add systemic error handling in the tokenizer" "5197": "Verify that our generated files are identical" "5214": "Enable ParseTopLevelBlock() to parse all the fields of a block, introducing ParseTagList()" "5618": "Include handmade_hht.cpp everywhere necessary, and clean up compile errors" "5983": "Make hhaedit call ParseHHT() on intro_cutscene.hht, changing ReadEntireFile() to return a string" "6481": "Step through ParseHHT() to see what it does" "6553": "Add the "plate" keyword to ParseTopLevelBlock()" "6569": "Continue to step through ParseHHT()" "6608": "Encounter an apparent 4coder bug in which some contents of intro_cutscene.hht is missing" "6746": "Continue to step through ParseHHT() to completion" "6796": "Run the parser on base_game.hht and hit a (correctly handled) error" "6830": "Enable ParseTopLevelBlock() to handle the "default" block specially" "6898": "Run the parser to completion" "6912": "Q&A" "6946": "Q: Could the 4coder bug be at all related to your in-comment calculator?" "6956": "Q: Now that we are using this method to assign tags, does this change how you plan to organize lots of little items on a sheet that may have differing, non sheet-wide tags, and in cases where using significance of positioning in the sprite sheet is too limiting? For example, maybe a collection of different fauna, each plant may have different tags for attributes, but can not be easily put into categories" "7015": "Q: What are some advanced parsing features that are interesting to you but may be too much work / not necessary for Handmade Hero?" "7179": "Q: Wnat" "7196": "Q: Are there things that recursive descent is not good for, or does it cut it for most of the parsing stuff?" "7299": "Q: What is your opinion of the Vulkan API, and its future?" "7319": "Q: I wasn't here for all of today's stream, but is RequireToken() what you'd use for lookahead (or a peektoken), ensuring you have an upcoming series of tokens to be of a specific form before you process those tokens?" "7617": "Bow out gracefully" --- name: "day511" title: "Merging HHT Parsing into the Asset System" markers: "1": "Recap and set the stage for the day" "138": "Show our tag file format and the separation of .hht files from the source assets" "277": "Organise our uncompressed cutscene layer images for all eleven shots into a single directory" "686": "“Oh DOS, so precious... "Oh, little lemon sweets. So precious. Have you enjoyed renaming your little files? What would you like to do now? Rename something"”" "709": "Continue to organise our cutscene images" "1052": "Tag our cutscene image assets in intro_cutscene.hht" "1592": "Enable ParseTagList() and GetToken() to parse numbers" "2350": "Move the parsing code into handmade_asset.cpp, and remove handmade_hht.h and .cpp" "2585": "Finding vs specifying parent-directories of files" "2797": "Enable Win32GetAllFilesOfTypeBegin() to handle .hht files" "2982": "Introduce PLATFORM_GET_FILE_BY_PATH() and Win32GetFileInfoFromWildCard()" "3993": "Replace PNG and WAV platform_file_type with a general HHT" "4187": "Introduce UTF8FromUTF16() and UTF16FromUTF8()" "4740": "Remove Win32GetFileInfoFromWildCard(), implement Win32GetFileByPath() and introduce Win32AllocateFileInfo()" "5563": "Disable ImportChangedAssets()" "5591": "Find that the .hha files still get found" "5620": "Add a "HHA" field to the parser and handle merging of the "default" block" "6040": "Tying in our .hht parser with the asset parser" "6282": "Make ParseTopLevelBlock() (in the .hht parser) call the asset parser's BeginTags(), ParsePieces() and EndTags(), introducing SetCategory()" "7003": "Duplicated tag parsing" "7105": "Revert our changes in the asset parser, and make EndTags() copy previously parsed tags" "7370": "Add a version of Error() in the tokeniser that doesn't take a token, and one of Outf_() that takes a va_list" "7690": "Add a FileName, LineNumber and ErrorStream to the tokenizer, and clean up compile errors" "8519": "Reflect on our .hht parser and glimpse into the future loading in asset source files" "8582": "Q&A" "8650": "Q: What are the flaws of converting a decimal floating point number to a binary equivalent by first parsing the number, and converting it to a regular integer, ignoring the decimal point. Then using the parsed number as the mantissa, and an accumulated value for the exponent, for the floating point number?" "8883": "Q: What do you think about WebAssembly as a platform for cross-platform applications and games?" "9063": "WebAssembly has always had a binary format, which is the default, and a text format to be able to read it" "9098": "handmade_hero: That's asm.js" "9129": "Q: How would you convince a seasoned OO-programmer of the merits of not using it? What is your best statement?" "9165": "Q: Have you ever read any of The Art of Computer Programming?" "9188": "Q: Why you don't use switch in our while(Parsing(Tokenizer)) loop?" "9246": "Q: Can you explain a bit more of what Windows considers UTF-16? I see it mentioned plenty of times on MSDN but usually it just means wchar_t, not actual utf16 with surrogates" "9363": "Q: Has the intentionally deliberate pace for Handmade Hero helped you in your day job at all (as say a reminder / refresher), or is it always just tedious to program in this fashion after all these years?" "9486": "Q: Hey, just saw your talk on "Papers I Love" or whatever they call it. Super impressed, has brought me back to Handmade Hero" "9528": "Q: If Jon can't come tomorrow, can Molly at least be here to celebrate episode 512 with a party hat? And cake (not for Molly)?" "9556": "We're done with questions" --- name: "day512" title: "Updating Assets via HHT Files" markers: "1": "Recap and set the stage for the day" "92": "Set up to use the traditional announcer voice in honour of Day 512, as per ivereadthesequel's request" "184": "And we're off, summarising our .hht parsing in the announcer voice" "414": "Flowing import_source_info / hht_fields through the parser" "487": "Enable ParseTopLevelBlock() to handle a "Name" field" "635": "Set up to merge the import_source_info with the assets' tile-based tags" "785": "Make ParseTopLevelBlock() responsible for parsing the asset tile info, and merging in default tags" "1306": "Note the need to make ParseTopLevelBlock() associate errors with the asset files" "1452": "Determining the freshness of .hht files using timestamps and checksumming" "1688": "Augment hha_annotation and loaded_hha_annotation with HHTBlockChecksum" "1853": "The perils of using a file's timestamp to determine its freshness" "2280": "Change ImportChangedAssets() to process .hht rather than .png files directly, calling ParseHHT()" "2908": "Make ParseTopLevelBlock() construct the full (enough) path of our .hha files, and get their info" "3345": "Make ParseTagList() build and return an import_tag_array" "3649": "Clean up compile errors" "3914": "Make ImportChangedAssets() read in the file to pass to Tokenize()" "4178": "Make WriteImageToHHA() write out to the locations parsed in from .hht files" "4579": "Drink concoction: 25% Newman's Own Lemonade, 75% Water, filled with 1/8th cup chia seeds per gallon" "4645": "Creating a .hha from whole cloth" "4802": "Someone is rage horning" "4871": "Add Stem to asset_file for AllocateGameAssets() to set, making RemoveExtension() and RemovePath() composable, and introducing GetOrCreatHHAByStem()" "5857": "Find that the game runs just fine, but without editor mode" "5909": "Q&A" "5953": "Q: I actually thought you were gonna just vary your pitch a lot more, in terms of inflection, not go fast! Everyone on stream was in awe of how fast you were going. Did we get more done today as a result? That's a killer way to celebrate episode 2^9!" "5977": "Q: What sort of pre-release checks / actions do you do? How do you make your programs "industrial strength"? For example, do you turn all of your asserts into fatal errors? Do you add verbose logging, crash reporters, etc?" "6211": "Q: I think I spotted a typo in that final print string: %S, not %s" "6250": "Q: Third from the bottom" "6260": "Fix up other typos" "6322": "Q: Oh, you handle %S?" "6328": "Q: How do you keep your mind fresh at your age? You talk really fast" "6373": "LeTambourinRoyal Exercise. It helps your brain a lot" "6392": "Close this out" --- name: "day513" title: "Adding Raw Tokens and Alignment Point Parsing" markers: "1": "Recap and set the stage for the day getting our asset tagging file parsing working" "144": "Demo our asset selection and alignment point editing UI" "341": "On the need to generate .hht files corresponding to .hha files" "548": "Rebuilding .hht files" "906": "Parsing and rewriting out a consistently merged file" "1048": "Writing out a new file while parsing in the original" "1186": "Custom emoticons" "1344": "Respecify GetToken() as GetTokenRaw(), preserving the ordinarily omitted whitespace and comments" "2077": "Newline" "2388": "Enable GetTokenRaw() to handle all end-of-line variants" "2590": "Introduce a new GetToken() which ignores spacing, end-of-line and comments, and make GetTokenRaw() preserve quotation marks around strings" "3048": "Add line and column numbers to the tokenizer's error messages, introducing PeekTokenRaw()" "3990": "Set up to copy already-tokenized input to a new file" "4238": "Add an "Align" identifier to the .hht format" "5031": "Distinguish between rewriting .hht files and importing them for merging into an .hha files" "5498": "Augment the "Align" identifier definition syntax, and make ParseTopLevelBlock() store up alignment points" "6154": "Improve the error handling of ParseTopLevelBlock(), introducing RequireIntegerRange()" "6494": "Fix compile errors" "6830": "Q&A" "6892": "Q: How would you print an enum tag as a string in C?" "7020": "Q: Is there a reason you don't (as far as I've seen) write bail out style functions to avoid too much nesting of if-else blocks?" "7121": "Q: Would you be willing to use metaprogramming and templates to do that job? Just because you absolutely have to" "7147": "Q: Can the difference between the pointers have undefined behavior? I guess we use it for the count variable" "7364": "Q: How do you feel about guidelines encouraging coupling enums with guards and label arrays (e.g. static assertions on min and max enum values and macros to establish enums creating corresponding label arrays)" "7392": "Q: If I understand right, insobot only really echos stuff from HMN IRC to twitch IRC. However, the mapping between HMN/#hero and twitch/#handmade_hero is, I believe, hardcoded, so maybe it could readily be mapped the other way" "7406": "Q: Regarding enum strings, would you be happy if you could write procedural macros to solve this problem?" "7452": "Q: As a student who is being taught C++ in college, can you explain to me why you think it is a terrible language?" "7638": "Q: Off-topic, but what is your stance on compile-time code generation like in D?" "7654": "Q: About label arrays: arrays of the same size of the enum with strings corresponding to the label of each enum item (for contiguous enums) or couples of label and offset (for sparse valued enums)" "7714": "Wrap it up" --- name: "day514" title: "Separating Image and Metadata Imports" markers: "0": "Recap and set the stage for the day communicating asset data between the .hht and .hha files" "251": "Merging alignment points into .hht" "438": "Our options for merging in alignment points" "589": "Pair up the .hht and .hha files by removing the "HHA" identifier, and make ParseTopLevelBlock() parse in alignment points from .hha up front for rebuilding while parsing the .hht" "1356": "Enable ParseTopLevelBlock() to perform our full and metadata rebuilds" "2574": "Introduce #hha and #include preprocessor directives to re-allow decoupling of .hht and .hha files" "2796": "About Molly's feeder" "2859": "Make ParseHHT() handle the #hha directive" "3075": "Make ParseHHT() and ImportChangedAssets() handle the #include directive" "3479": "Relieve ParsePieces() of appending tags and WriteImageToHHA() of writing out annotations" "4842": "Introduce StampAssets() to merge tags and write out annotations" "5913": "Run the parser for the first time" "5958": "Fix the sense of the Asset->Type assertion in SetAssetType()" "6106": "Trigger an asset reimport and step through the .hht parser" "6271": "Trigger another asset reimport and step through GetTokenRaw() to find that we fail to tokenize multi-line comments" "6326": "Fix GetTokenRaw() to account for its character advancement" "6463": "Step through GetTokenRaw() to find that we correctly tokenize the whole intro_cutscene.hht and base_game.hht" "6726": "Enable GetOrCreateHHAByStem() to create a .hha if it doesn't exist, introducing InitSourceHHA()" "8206": "Trigger an import and step through GetOrCreateHHAByStem() until InitSourceHHA() fails to open our newly created file" "8356": "Fix GetOrCreateHHAByStem() to close the file before calling InitSourceHHA()" "8414": "Q&A" "8458": "Q: You still parse At[1] in one of the newline cases instead of At[0]" "8470": "Fix typo in GetTokenRaw()" "8489": "Q: You had a NOTE you changed to a TODO, but what if by "with the right data!" indicated the code wasn't or isn't using the right data (yet)?" "8568": "Q: You using a KVM in that setup? Do you like it?" "8671": "Q: Do you have an idea as to what the gameplay of Handmade Hero will be, or are you just doing more of that design exploration?" "8754": "Q: (Repeating my question) What makes asset importing special the way you're doing it, compared to other ways in other game libs?" "8932": "Q: Is CheckSumOf() based on murmur hash?" "8943": "Q: When you import assets, do they go into some kind of target? Like a texture atlas? I'm new at this game stuff" "9004": "Spritesheets and texture atlases" "9228": "Wrap it up with an announcement of next weekend's 4coder Jam with Allen" --- name: "day515" title: "Debugging HHT to HHA Packing" markers: "1": "Meow the Infinite" "112": "Recap and set the stage for the day debugging HHT to HHA packing" "374": "Plan to delete and rebuild our current .hha file" "468": "Continue to plan our .hha deletion and rebuild" "648": "Create handmade_import.cpp and .h to house the non-runtime asset system code" "977": "Make AllocateGameAsssets() call ImportChangedAssets() just before returning" "1162": "Delete base_game.hha and step in to ImportChangedAssets()" "1203": "On Visual Studio's incorrect display of #if blocks" "1256": "Step through ImportChangedAssets()" "1325": "Fix the Author settings in cutscene.hht" "1442": "Continue to step through ImportChangedAssets() to ParseHHT() until we detect an error" "1533": "Change cutscene.hht to use our #hha directive" "1562": "Continue to step through ParseHHT(), until we spot a bug exhibited in InitSourceHHA()" "1734": "Make GetOrCreateHHAByStem() refresh the file info after creating a new .hha, to get its correct file size" "1797": "Delete intro_cutscene.hha and successfully step through ImportChangedAssets() to CopyAllInputUpToAndIncluding()" "1957": "Comment out the unimplemented CopyAllInputUpToAndIncluding()" "1969": "Continue to step through ImportChangedAssets() after the CopyAllInputUpToAndIncluding() call" "2110": "Fix the .hha directory Path in ParseTopLevelBlock()" "2144": "Continue to step through ParseTopLevelBlock()" "2381": "Fix ParseTagList() to check the next token after pulling off the closing parenthesis" "2435": "Continue to step through ParseTagList()" "2515": "Make StampAssets() pass the Tags.TypeID to EndTags() and prevent the latter from calling AddTag() if passed an Asset_None" "2631": "Continue to step through ParseTagList() to find that we parsed the correct number of tags" "2703": "Just insert the missing semicolons in intro_cutscene.hht" "2806": "Continue to step carefully through ParseTopLevelBlock()" "2908": "Make PeekToken() pass the duplicated Temp tokenizer to GetToken()" "2942": "Continue to step through ParseTopLevelBlock()" "3008": "Fix ParseTagList() to use PeekToken() rather than GetToken() wherever we operate conditionally on tokens" "3104": "Continue to step through ParseTopLevelBlock()" "3243": "Respecify StampAssets() as UpdateAssetMetadata() which itself determines if the metadata tags differ, changing ParseTopLevelBlock() to call it always" "4013": "Introduce GetTagCount() and TagsAreEqual(), and fix compile errors" "4451": "Delete intro_cutscene.hha and step through UpdateAssetMetadata()" "4564": "Make ParsePieces() tag plates as Asset_Plate" "4644": "Continue to step through UpdateAssetMetadata() until the image extraction phase" "4907": "Make UpdateAssetMetadata() mark the file as Modified if the tags differ" "5040": "Hit an error while importing base_game.hht" "5152": "Comment out the item and obstacles and cover settings in base_game.hht" "5200": "Find that our generated intro_cutscene.hha file is empty" "5256": "Introduce WriteModificationsToAllHHAs() for ImportChangedAssets() to call" "5445": "Delete and regenerate base_game.hha and intro_cutscene.hha" "5536": "Find that the hero's head is missing, but the intro cutscene displays okay" "5649": "Move intro_art_v2.hha to a new directory, and find that the intro cutscene now fails to display" "5722": "Check out our intro_cutscene.hha in TabView" "5896": "Add an -extract command to hhaedit" "6304": "Copy WriteImageTopDownRGBA() and bitmap_header into hhaedit.cpp and introduce ExtractBitmapAsset()" "6787": "Try to extract test1_v2.hha with partial success" "6853": "Comb through WriteImageTopDownRGBA() for any clear bugs" "7003": "Step through an extract of test1_v2.hha" "7140": "Remove the colour Mask values from hhaedit's bitmap_header" "7186": "Try again to extract test1_v2.hha with full success" "7218": "Extract intro_cutscene.hha to see that all is correct" "7271": "Q&A" "7339": "Q: What's your first major gameplay programming topic going to be?" "7372": "Q: Do you use string library from CRT? I though we wrote our own version?" "7407": "Q: Have you every programmed non-blocking TCP sockets? I wonder what is the cost of directly calling recv() / send() vs select()" "7514": "Q: Could you improve the assert macro such that it prints the stringized expression which failed? On Linux the debugger does not always show which assert failed where" "7580": "Q: What is your thought on the structure of config files in Windows (.ini files) that have sections in the close brackets? Do you think it is a good structure for the game config file?" "7610": "Q: How would you implement immediate mode-esque functionality for rendering anti-aliased polygons? I am currently rendering n-gons with a geometry shader, but I am unable to implement anti-aliasing" "7834": "Q: When trying to manage entities in my own game engine / game (just me on my own), do you think the Entity-Component structure is worth considering, or am I just giving myself too much work when it's just my own code?" "8049": "I am here as the ambassador of DON'T BOTHER WITH COMPONENT SYSTEMS" "8085": "Q: What should I choose: Xlib or XCB?" "8108": "handmade_hero Yeah, I haven't thought in a while to explain the "walling yourself in" thing, but that is 100% true. It's like playing Go... when you build a strategic structure, you are also filling the board and ruling out possibilities for yourself" "8227": "Q: I've been writing my own game / render loop but I've been having trouble getting the loop timing to be constant. I seem to get a stutter or skip in motion, but it's not because the render procedure takes too long. Any ideas on what could be the issue? Sorry, I know it's not much to go on, but any ideas would be helpful" "8527": "lada-vatz" "8555": "Call it a day with a plug of Meow the Infinite" --- name: "day516" title: "Rewriting HHTs" markers: "2": "Recap and set the stage for the day" "113": "The workings of our .hht and .hha files, and hhaedit" "203": "Look at our exported .bmp files in GIMP" "256": "Check out intro_cutscene.hha in TabView" "419": "Check out the original intro_art_v2.hha in TabView, to find that the BasicCategory differs" "488": "Replace Asset_OpeningCutscene with Asset_Plate" "539": "Find that the intro cutscene now displays correctly" "681": "Make UpdateAndRenderTitleScreen() draw our pre-cutscene title screen image" "1187": "Check out our title screen, and increase its size" "1352": "Extract base_game.hha to see that the bitmaps look correct" "1466": "Check out our base_game.hha dump in TabView" "1575": "Change AddPlayer() to apply the Tag_Hero (rather than character-specific tags)" "1659": "Find that all the assets except heads seem correct" "1743": "Temporarily change AddPlayer() to connect the HeadPiece to the world" "1825": "Find that the hero's head is present, and align it" "1913": "Replace Tag_DodgeLeft and Tag_DodgeRight with a bidirectional Tag_Dodge, and make the NameTags matching case-insensitive, introducing StringsAreEqualLowercase()" "2302": "Trigger a successful base_game.hha rebuild" "2346": "Enable UpdateAndRenderEntities() to consider an asset's dodge value when picking" "2380": "Find that we have not picked the hero's non-dodge asset" "2452": "Reacquaint ourselves with GetBestMatchAssetFrom()" "2624": "Possible problems: 1) Import incorrectly setting tags; 2) Improperly matching; 3) Accidental preference for dodging" "2781": "Remove all except the font test .hha files and find that the game runs just the same, with only the dodge asset bug" "2880": "Enable UpdateAndRenderEntities() to consider an asset's idle value when picking" "2986": "Find that we now pick the correct character asset" "3015": "Rewriting .hht files to contain in-game edited alignment points" "3208": "Respecify ImportChangedAssets() as SynchronizeAssetFileChanges(), which merges asset edits into an existing .hht file" "4233": "Atomic file operations" "4357": "Continue to implement .hht synchronization, making ParseHHT() responsible for the file write" "4961": "Implement CopyAllInputUpToAndIncluding(), noting our intention to diff .hha files the same way as .hht" "5322": "Fix compile errors in our .hht synchronization code" "5517": "Introduce CopyStreamToBuffer()" "5689": "Continue to fix compile errors in our .hht synchronization code" "5870": "Introduce a stubbed out Win32AtomicReplaceFileContents()" "6046": "Find that everything seems fine" "6191": "Break in to CopyStreamToBuffer() to see that it did not produce the expected result" "6245": "Make ParseHHT() initialise the HHTCopyPoint" "6377": "Step through ParseHHT() and watch the copy process play out" "6642": "Make the rebuild routine within ParseTopLevelBlock() responsible for its own memory" "6702": "Find that our .hht diffing / copying succeeds" "6750": "Q&A" "6842": "Q: Do you ever write unit tests for testing these low-level functions instead of running through the game?" "6992": "Q: Now that you've done a C++ game engine series, do you plan to do a C game engine series?" "7016": "Q: Any thoughts or hopes for c2x scheduled for 2022?" "7026": "Q: When you transform a mesh, do you do that on the GPU? If so, do you load it back if you e.g. want to raycast against it?" "7211": "Q: How do you toggle between debug and release builds? Modify build.bat each time?" "7218": "Q: How do you conceptualize and tackle large projects and prevent from getting overwhelmed and lost in the weeds of minute details? I tend to suffer from analysis paralysis" "7265": "Q: Let's say a AAA studio bought quite a bit into OOP, any steps to show that that's not the answer / easiest way to go forward? If they have a codebase that "works" but changing anything is a pain, it's hard to make them see that this is one of the big problems. Any advice? It's for a friend" "7445": "Q: Watched your talk about lines of code problem. Have you ever seen anything from Ian Piumarta?" "7463": "handmade_hero Do twitch subs count towards source code access?" "7545": "Q: Do you use any graphics libraries like SDL, SFML?" "7553": "Q: What are your thoughts on the use of C++ lambda functions? Seems like one of the better additions to the C++ spec and doesn't break procedural style" "7676": "Wrap it up with a plug of Meow the Infinite and a glimpse into the future" --- name: "day517" title: "Inserting and Rewriting HHT Alignment Points" markers: "2": "Recap and set the stage for the day" "75": "Demo our asset alignment point editor" "332": "Synchronising our asset alignment points between .hha and .hht files" "612": "Enable ParseTopLevelBlock() to insert new alignment points in an .hht and clear them from an .hha file" "2303": "Enable ParseTopLevelBlock() to retain matching alignment points and replace changed ones in an .hht file" "3121": "Enable ParseTopLevelBlock() to apply our asset alignment point changes to the .hha file" "3642": "Consider a more generic diffing system" "3783": "Atomic file replace" "4053": "Implement Win32AtomicReplaceFileContents()" "5322": "Hit an assert in ParseTopLevelBlock()" "5400": "Fix the assert in ParseTopLevelBlock() to test on the Asset->HHA.Type" "5488": "Run the import, but do not see our assets" "5619": "Make ParseTopLevelBlock() apply default alignment points to assets" "5800": "Find that our assets now appear, and step through the "Import & Save" routine" "5908": "Make FindAlign() rather than ParseTopLevelBlock() apply default alignment points, to permit assets that lack alignment points" "6167": "Find that that didn't work" "6180": "Fix FindAlign() to apply default alignment points for an asset's ToParent connection" "6407": "Find that we see our assets just right, and step through our "Import & Save" routine again with full success" "6583": "Enable Win32AtomicReplaceFileContents() to delete the temporary file if the move failed" "6649": "Compare our original and updated base_game.hht with Meld" "6723": "Find the alignment points reload correctly" "6761": "Make ParseTopLevelBlock() output tabbing and newline" "6816": "Q&A" "6901": "Q: Will you make file formats for how the worlds are generated as well in the future?" "6948": "Q: Do you think it is better to design for the top 10% of programmers, or the majority, in language / API design?" "7104": "Q: Off-topic, but in an old stream you mentioned that you liked having all allocators (like PushSize) go through macros instead of direct function calls. What was your reasoning behind this?" "7163": "Q: Since there aren't a lot of questions: Do you think I could interest you in a pair of zircon-encrusted tweezers?" "7230": "Q: Would you move to clang and implement custom build tooling" "7264": "handmade_hero May I ask a larger sort of off-topic question, or should I save that for tomorrow's pre stream?" "7293": "Q: Is there anything like operating system garbage collection nowadays? My professor talked about not needing to free calls to malloc() due to something like that. I would imagine he has no idea what he is talking about, but I'm not sure either" "7495": "handmade_hero So I talked to one of the handmade debug teams and they made it sound like it would be doable to expose all debug symbols on an API level. This seems like a very powerful thing since people could build custom luggins [sic] on top of the debugger itself. This seems very powerful and very leveragable. Is there anything wrong with that? Is there some reason you know of Visual Studio does not expose debug information to an API? Some security vulnerability or something?" "7656": "DBGHELP.DLL" "7700": "Close it down with a glimpse into the future and a plug of Meow the Infinite" --- name: "day518" title: "Displaying Import Errors" markers: "0": "Recap and set the stage for the day" "137": "Fix ParseTopLevelBlock() to correctly consume a semicolon only once, and remove the redundant check for Context->HHTOut, as per frostyninja's suggestion" "394": "Loading alignment points from .hht and applying them to the live assets" "451": "Rename the "IMPORT" and "IMPORT & SAVE" asset editor buttons to "RELOAD HHTs" and "SAVE HHTs"" "654": "Fix compile errors, introducing a version of IsValid() that takes a buffer" "821": "Try out our "RELOAD HHTs" button to see that nothing happens" "889": "Delete base_game.hha and intro_cutscene.hha, and let the game regenerate them to find that we must have a bug, but do not know where" "1008": "Displaying import errors in our asset editor panel" "1217": "Add an ErrorStream to the htt_context for ParseHHT() to write into" "1538": "Set up AssetEditor() to print out our ErrorStream" "1810": "Upgrade TextOp() to operate on a length-string rather than a char *" "2271": "Find that everything remains intact" "2310": "Further set up AssetEditor() to print out our ErrorStream, upgrading our text printing functions to work on a length-string" "3308": "Find that everything remains working" "3334": "Enable AssetEditor() to print the actual error stream contents" "3353": "Check out our asset import errors in-game" "3410": "Make Error() colourise its printout" "3451": "Check out our colourised errors in-game" "3469": "Try to address our syntax errors in base_game.hht" "3586": "Enable GetTokenRaw() to track newlines within block comments" "3781": "Find that our line numbers are now correct" "3793": "Enable RequireToken() to report its expected token" "4054": "Check out our more informative errors in-game" "4071": "Fix ParseTopLevelBlock() to output alignment points using the correct syntax" "4142": "Find that the asset importer now runs, and loads our .hht alignment points correctly" "4224": "Backup our .hht files, trigger our asset editor to save out new files, and find that the original and new ones match" "4284": "Edit alignment points in-game" "4485": "Find that our hero's head art asset is incorrect" "4643": "Try to save our edited alignment points, and find that we did not save the file" "4694": "Enable SynchronizeAssetFileChanges() to report "Load" or "Save" to our UI" "4897": "See our "Load" / "Save" report in-game, and again try to save" "4992": "Enable ParseTopLevelBlock() to correctly merge alignment point changes, introducing OutPoint()" "5298": "Edit and re-save alignment points, to find that our new .hht now (correctly) differs" "5349": "Make the caller of OutPoint() responsible for aligning the output" "5440": "Try again to edit and re-save alignment points, to find that the .hht does not change" "5558": "Fix the compile error in the calls to Outf()" "5601": "Find that the .hht now (correctly) differs after saving" "5623": "Try again to edit and re-save alignment points, to find that the .hht correctly changes" "5753": "Manually modify our base_game.hht, edit alignment points and re-save them in-game, and find that the .hht file does not get updated reliably" "5844": "Enable ParseHHT() to report atomic replace failure or success" "5960": "Reproduce our save bug" "6017": "Make ParseHHT() report the .hht filename" "6151": "Try to reproduce our save bug, crash in StringLength() and investigate why" "6379": "Rebuild in -Od, reproduce the StringLength() bug and step through it to see that we unexpectedly get to the va_list version of Outf()" "6556": "Verify the fact that a va_list is defined as a char *, which can throw off function overloading" "6688": "Rename the va_list overload of Outf() to OutfArgList()" "6728": "Find that we have fixed our va_list induced bug, and that the .hht files now appear to reliably get saved" "6844": "Q&A" "6879": "And this is why I don't use overloading functions..." "6895": "Q: Wouldn't it be nice to move the old file to a .bak in the atomic file replace?" "6970": "Q: How awesome would it be if windbg preview had trace diffs?" "6993": "Q: Read this in Game Engine Architecture by Naughty Dog's guy I can't remember the name of, but they use C++11 user-defined literals to do compile-time hashes on strings. "At Naughty Dog, we permit runtime hashing of strings, but we also use C++11’s user-defined literals feature to transform the syntax "any_string"_sid directly into a hashed integer value at compile time."" "7180": "Q: What happens when RequireToken fails? I realize it appends an error, but what does it return? An empty / invalid token? I ask because near the top of the while(Parsing(Tokens)) (or something) where you get the filename and require strings, you did not check the result. So curious if something went wrong, would it just be null?" "7220": "Q: Off-topic, just an idea: In 4coder, you could do the block re-indentation after exiting the insert mode, instead of live. Then there would be no "jumpy" code while typing" "7295": "Q: What are your thoughts on persistent structures like used in Clojure?" "7317": "Q: Off-topic: This probably isn't relevant to you working in a small / solo company but as you get "older" any thoughts on aging as a programmer? In a large company it seems many become "managers" but irrespective of large organizations / teams anything you find noteworthy / interesting about your day-to-day as you get older?" "7580": "Q: I asked on the pre-stream yesterday about aspects of programming you didn't enjoy and you mentioned no spec or under spec'd problem domains often being annoying. I was thinking that may well be a young man's game, at least doing it multiple projects in a row" "7713": "Q: The structures are like lists in lisp where old versions are kept around because new ones reference the old with only sub-parts containing the new data appended on" "7769": "Q: It's building up diffs" "7792": "Q: Hey Casey, I just started working on a super OOP open-source project in C++, and one thing I'm noticing is that it's so hard to find the code that actually does the thing I'm looking for. Can I expect this with modern C++, because it blows? Literally all I'm trying to do is add a menu option, but my exploration is so far looking at eight different files, none of which actually contains the thing that I want, which is, from what I understand, literally just adding a boolean flag in the metadata" "7950": "I am working on codegen because LLVM has too many issues: It is slow, it has numerous bugs, it's weirdly / badly designed" "8016": "Q: About splitting code into microscopic files: My coworkers love it because it makes the code "easier to read" for them. It seems like they get lost if a file has > 200 lines" "8034": "Q: Will moving away from modal in 4coder affect your wrists? Or have you found that it won't?" "8129": "Q: The other day I heard someone make the claim that programming without syntax highlighting is more error prone. What would you say?" "8520": "Wrap it up" --- name: "day519" title: "Brainstorming about Z Bias" markers: "2": "Recap and set the stage for the day" "95": "Fix typos in EditableBoolean(), EditableSize() and Error() as per KimJorgensen's bug report" "641": "Close issue 90" "702": "Investigate gingerBill's bug report 'Bug in `PushSize_` that could cause buffer overflow'" "1174": "Insert assertions in PushSize_()" "1399": "Introduce IsPow2()" "1754": "Test Power of 2" "2158": "Carefully scrutinise PushSize_() as per gingerBill's bug report" "2232": "Explicitly parenthesise the (Used + Size > Size) comparison in PushSize_()" "2276": "Conclude that the bug report is wrong" "2482": "Check out C's operator precedence rules" "2554": "Continue to investigate gingerBill's bug report" "2729": "Construct PushSize_() failure cases to address gingerBill's bug report" "3136": "Step through our PushSize_() test to see that it behaves well" "3244": "Construct a PushSize_() test in which our request is right on the boundary" "3347": "Step through our PushSize_() test to see that it behaves well" "3481": "Try allocating 4 MiB as the second, expansion-triggering allocation" "3538": "Step through our PushSize_() test to see that it behaves well" "3579": "Try allocating 4 MiB as the first allocation" "3605": "Step through our PushSize_() test to see that it behaves well" "3690": "Close issue 88 with a few words on the helpfulness of concrete repro-cases in bug reports" "3857": "A few words on judicious unit testing" "4367": "A final glance at the open issues" "4415": "Consider hiding the assets of disabled alignment points" "4586": "Consider solving our 2D billboard asset Z-bias problem" "4843": "Set up to express our Z-bias in CompileZBiasProgram()" "5019": "Sprite Z-bias encoding" "5304": "How CompileZBiasProgram() is currently working" "5417": "Adjusting sprite position in Y" "5612": "Imaginary encodings of sprite position and orientation" "6234": "Don the tennis headband" "6295": "Understanding ZBias in the case that sprites are drawn exactly upright" "6611": "Understanding ZBias in the case that sprites are drawn lying down a little" "6804": "Projecting in the vertex shader the sprite's Z positions to the passed in Z heights of the world plane" "7103": "Q&A" "7147": "Q: What kind of testing (unit, replays, etc.) do you use on 1935 / have you used over the years? Is automated testing even really a thing at game studios?" "7360": "Q: Any news on 1935?" "7363": "Q: For people who don't want to fuss with platform specific code, would you say SDL is a good solution?" "7455": "We're all done" --- name: "day520" title: "Solving for Debug Camera Parameters" markers: "0": "Recap and set the stage for the day" "154": "Demo our world level / elevation fogging, and our need for a rigorous Z-bias solution" "352": "Z Occlusion" "607": "Keeping Z, sliding forward in Y and tilting backwards" "786": "Set up to get our debug camera in good shape to develop our Z occlusion solution" "884": "Demo the garbage debug camera" "957": "Show off the title screen" "989": "Reacquaint ourselves with the debug camera code in UpdateAndRenderWorld()" "1157": "Set up UpdateAndRenderWorld() to handle debug camera panning, and more clearly set the Debug and Regular clip planes" "1284": "Continue to reacquaint ourselves with the debug camera code in UpdateAndRenderWorld()" "1427": "Temporarily make PlayWorld() set the DebugCameraDolly" "1487": "Find that the debug camera is now restored" "1503": "Set up UpdateAndRenderWorld() to position the debug camera to match the regular camera" "1792": "Reconstructing a camera's dolly, orbit and pitch from a point" "2234": "Make UpdateAndRenderWorld() reconstruct the debug camera's dolly from the regular camera's position" "2493": "Using the inner product to isolate the position of a point on only one axis" "2569": "Add CameraPan to game_mode_world for UpdateAndRenderWorld() to compute" "2716": "Make UpdateAndRenderWorld() reconstruct the debug camera's orbit and pitch using ATan2()" "2840": "atan2 assumes that our starting vector points along x" "2997": "Change UpdateAndRenderWorld() to feed an x-pointing vector to atan2" "3157": "Crash in FindAlign() with an "Access violation" error" "3224": "Find that the debug camera is wrong" "3243": "Scrutinise our debug camera construction in UpdateAndRenderWorld()" "3435": "Make UpdateAndRenderWorld() compute separate debug camera values to aid debugging" "3551": "Step in to UpdateAndRenderWorld() and inspect our debug camera values" "3946": "Fix the winding of the DebugCameraPitch computation in UpdateAndRenderWorld()" "4180": "Step back in to UpdateAndRenderWorld() and inspect our DebugCameraPitch" "4220": "Fix the DebugCamera0 computation to use an XRotation(), and negate the PlanarArm length in the DebugCameraPitch computation" "4268": "Step back in to UpdateAndRenderWorld() and inspect our DebugCameraPitch" "4331": "Refrain from negating the PlanarArm length in the DebugCameraPitch computation" "4343": "Step back in to UpdateAndRenderWorld() and inspect our DebugCameraPitch" "4378": "Find that our orbit is −90° off" "4394": "Fix the DebugCameraOrbit computation" "4472": "Find that our debug camera is now correct" "4528": "Invert the mouse's X-axis in UpdateAndRenderWorld()" "4547": "Try out our perfect debug camera" "4588": "Naively make UpdateAndRenderWorld() to handle debug camera panning" "4646": "Try our newly panning debug camera" "4666": "Invert the panning axes in UpdateAndRenderWorld()" "4679": "Try our newly panning debug camera, noting that it breaks when the orbits of our debug and regular cameras are not aligned" "4726": "Enable UpdateAndRenderWorld() to pan the camera in camera-space" "4845": "Show our camera panning in camera-space" "4873": "Find that we are inverting the mouse's Y axis" "4937": "Note the correctness of our panning" "4965": "Make UpdateAndRenderWorld() invert our panning and scale its speed by the camera's distance from the subject" "5020": "Try out our distance-proportional panning camera" "5128": "Take a close look at our sprites in preparation to try our Z occlusion solution" "5279": "Reacquaint ourselves with SpriteValuesForUpright()" "5421": "Remove ZBias from SpriteValuesForUpright()" "5432": "Find that we draw just fine without the ZBias" "5444": "Temporarily make SpriteValuesForUpright() displace the sprites in Y" "5553": "Check out our displaced entities and adjust the alignment points to find that we are displacing in the wrong direction" "5597": "Change SpriteValuesForUpright() to use the (not inverted) WorldDim.y in the sprite displacement" "5624": "Align the hero's body and head, and find that we now sort beautifully (i.e. no penetration with walls), except during hopping which we are erroneously performing in Y" "5845": "Make UpdateAndRenderEntities() hop the entities in Z" "5947": "Check out our Z-hopping entities, to find that our hero never penetrates walls" "6026": "Q&A" "6095": "Q: You uploaded the last episode as episode 520, instead of 519" "6137": "Q: Are we gonna switch to remedybg for Handmade Hero soon?" "6221": "Q: So one of the reasons I became briefly enthusiastic about WinDBG Preview is the ability to record a trace of a running program and then send that trace to someone else and they can look at the exact debug session you were looking at, rather than having to reproduce a bug spending possibly a long period of time. To me that sounds like a silver bullet way to reproduce a bug. Can you think of any reason why I would be wrong to conclude that the feature is a silver bullet for reproducing bugs?" "6387": "Q: So far it seems all the animation is done programatically, moving static sprites. Is there any plan to include pre-set or artist-created animations?" "6450": "Q: I studied the rendering code for a bit and it seems that the vertices and indices for the cubes (and quads) are generated each frame on the CPU and put into a big VBO which is set to stream_draw. Is this correct and, if yes, what was the decision to do it that way and not even using VAOs? For big models with a lot of polygons would you go a different route?" "6571": "Q: What's your take on profilers vs. DIY in-game profiling? What are some decent profilers that you know of or have used?" "6665": "Q: What you think about python?" "6736": "Q: Do you think there is any value in keeping the concept of registers in the higher level language?" "6759": "Q: How do you feel about dynamically-typed languages?" "6788": "Q: I may have asked this before, but have you looked at ponylang? If so, what are your thoughts on it?" "6826": "Q: Does the game load levels from files, and do you plan to include a level editor with the final game?" "6920": "Deep thoughts on modern languages like PLISK, StopLang and ZnO, and their cutting edge provision for memory composting" "7294": "Wrap it up for the day" --- name: "day521" title: "Debugging Missing Parent Pointers" markers: "1": "Recap and set the stage for the day" "33": "Show off our sprite Y-displacement solution (replacing Z bias)" "186": "Make UpdateAndRenderWorld() pan the debug camera along its own axes (rather than those of the regular game camera)" "587": "Try out our debug camera panning, and determine to finalise our asset alignment for accurate sorting and axis-correct snapping" "1054": "Set up to snap assets together by their alignment points" "1548": "Ensure that the alignment points slide along the tilted pane" "1621": "Snapping children to their parent" "1728": "Demonstrate that we are not snapping sprites together in Z" "1832": "Define sprite alignment and snapping: Sprite stacks snap together naturally when at the centre of the scene, and tilt when at the edges" "2156": "Aligning the sprite stack for the scene centre before snapping according the stack's actual position" "2371": "Remove ZBias and BaseP offset from SpriteValuesForUpright(), and instead make its caller UpdateAndRenderEntities() perform the offset" "2507": "See that the sprite stack is aligned as before" "2518": "Temporarily prevent UpdateAndRenderEntities() from applying the sprite offset" "2661": "Find that we unexpectedly do not snap sprites directly" "2679": "Investigate why our sprites are not snapped directly" "2849": "Aligning sprites to 0, 0, 0 in world-space" "3084": "Temporarily make SpriteValuesForUpright() snap sprite directly" "3117": "Find that our sprites are snapped directly, and Z-fighting" "3178": "Enable UpdateAndRenderEntities() to offset sprites in Y as SpriteValuesForUpright() used to" "3289": "Crash in FindAlign() with an "Access violation" error, and investigate it" "3491": "Reverse engineer the optimised assembly code generated for FindAlign()" "4025": "Find that UpdateAndRenderEntities() evaluates a non-zero ParentAlignType before going on to pass the bitmap with a ParentAlignType of 0 to FindAlign()" "4305": "Reverse engineer the optimised assembly code surrounding that ParentAlignType check in UpdateAndRenderEntities()" "4755": "TEST - Logical Compare" "4885": "Continue to reverse engineer the ParentAlignType check in UpdateAndRenderEntities(), to see that ecx gets overwritten after the check" "5007": "Investigate why ParentAlignType is evaluated to 259" "5559": "Consult our source of ConnectPiece() where ParentAlignType is set, and note that this entity's first piece should not have a non-zero, but valid ParentAlignType" "5775": "Possible causes for our non-zero ParentAlignType" "6220": "Reverse engineer the optimised assembly code generated for AddCat()" "6857": "Consider the nastiness of our bug" "6925": "Add an assertion in UpdateAndRenderEntities() to guard against our first piece, non-zero ParentAlignType bug" "7010": "Q&A" "7102": "Q: How do you like the progress of Handmade Hero so far?" "7283": "Q: Will you add 3D primitives as collision proxies or something like that?" "7290": "Q: You've mentioned in the past you climb as a form of exercise. Have you seen Free Solo yet?" "7297": "Q: Not related to the problem at hand, but on the subject of assembly, did you have a chance to look at the burst compiler demo from Unity's GDC 2019 keynote and, if so, what's your take on it? I thought it looked cool but don't know enough to be able to really have an informed opinion on it" "7453": "Q: Couple of days late, but now that we're hopping in Z, how about adding water so the hero can go swimming?" "7572": "Q: (Not a question). Hi Casey. On Monday I am starting my first day of work at a medium sized game studio after working for Microsoft for a few years. Just wanted to say thanks to you (among others) for the inspiration and education that made this career change possible for me" "7608": "Q: It was a good demo about how a bug can mess up the schedule and get you two hours of info, but sadly nothing..." "7762": "Q: Hey Casey, the way you think / teach how to think about matrices has helped me understand the transformation pipeline a lot better. There is just one thing that I think I am missing. At one point you put the camera's coordinates into clip space [-1, 1] so I was wondering how you scale world units to make sure things aren't huge on screen?" "8167": "Projecting a 3D world onto a 2D screen" "8534": "Understanding scaling in terms of the film-back's distance from the aperture" "9078": "Q: I think in a pinhole camera, the focal length is 0 and the focal point is the actual pinhole itself" "9101": "Document the FocalLength in PerspectiveProjection()" "9166": "Q: Going to the perspective question: So mathematically, you are recreating the space bounded by the near and far clip frame in the space "defined" by the lens and the focal length? So if you could imagine one pixel as being a vector from the lens to some point, you are literally just doing a magnitude scale. If that's the case, then how do you handle the fact that you're mapping a curved surface onto a plane?" "9269": "Q: What you said made sense and I think I get it. Thank you very much! I'm going to mess around with it to get things scaled the way I like it" "9301": "Q: How much do curved monitors complicate this?" "9356": "Projecting onto a curved monitor" "9529": "Recommend '3D Rasterization: A Bridge between Rasterization and Ray Casting'" "9696": "Q: I'm imagining the "true" surface as being an arc with radius=focal length but you're mapping that arc onto a flat rectangular screen (assuming it's not a curved monitor)" "9720": "Projecting onto a flat surface" "9903": "Q: If I wanted to create seamless terrains, starting from a cube-like tile map, what algorithm should I look into? Is Marching Cubes a viable approach?" "9922": "Q: I was thinking that you'd want to solve the problem that you'd get a differential zooming, but it seems like that's not too much of an issue" "10080": "Close things down" --- name: "day522" title: "Solving for Sorting Displacement" markers: "2": "Recap yesterday's post-stream suggestion from binjimin, that our erroneous ParentAlignType may be caused by an unset parent TextureHandle" "85": "Change UpdateAndRenderEntities() to acquire the TextureHandle after having set all the BitmapInfo" "287": "Separating streaming and non-streaming information" "429": "Change WorldDimFromWorldHeight() to take a hha_bitmap *" "506": "Find that the game runs, trusting that we've solved the ParentAlignType bug" "558": "Snapping sprite stacks to be fully aligned when at the center of the scene" "628": "Demonstrate our sprite alignment requirements" "813": "Offsetting pieces, e.g. head bobbing, after aligning the sprite stack" "1062": "Align for Default Camera" "1449": "Solving our child−parent sprite alignment" "1808": "Make UpdateAndRenderEntities() align child sprites to their parent as per our diagram" "2245": "Find that our child−parent sprite snapping works just great" "2396": "Make UpdateAndRenderEntities() apply the Piece->Offset" "2427": "Find that our child and parent sprites' alignment points are not aligned" "2601": "Make AddPlayer() elevate the hero's head higher" "2665": "Check out our perspective shifting, and determine to handle rotating sprites" "2773": "Aligning rotating sprites" "3224": "Replacing entity pieces with sprite snapping" "3296": "Temporarily make UpdateAndRenderEntities() spin the hero's head and glove" "3411": "Note the pulsing of rotating sprites caused by MinP no longer always representing the lowest point on the sprite" "3450": "Make SpriteValuesForUpright() compute a ZDisplacement to provide a stable lowest point" "3675": "Find that our rotating sprites now remain at a stable elevation" "3776": "Remove the test spinning code from UpdateAndRenderEntities()" "3827": "Make UpdateAndRenderEntities() hide sprites when their alignment point is disabled, changing FindAlign() to return a find_align_result" "4265": "Try toggling alignment points / sprites" "4294": "Begin to change UpdateAndRenderEntities() to hide the child sprites of parents" "4552": "Delete the lot of the sprite hiding code" "4597": "Add a "Show Children" button in our asset editor, introducing ShouldDrawChildren() for UpdateAndRenderEntities() to call" "5064": "Try out our "Show Children" button, without success" "5110": "Make InitializeEditor() enable ShouldDrawChildren and proofread our new children hiding code" "5307": "Note that our entity selection does not record which specific asset we clicked" "5356": "Scour our child sprite hiding code" "5556": "Find that the hero's "head" child sprite never gets hidden" "5664": "Step in to ShouldDrawChildren() and compare the ParentID and HitTest->Editor->HighlightID" "5916": "Find that DevIDFromU32s() differentiates one dev_id from another by their file and line number" "5949": "Introduce CopyType() to harmonise two separate dev_id settings" "6059": "Find that our "Show Children" button remains busted" "6134": "Step in to ShouldDrawChildren() and again compare our values to find that they differ" "6271": "Fix CopyType() to persist its work" "6301": "Try out our "Show Children" button with success" "6340": "Prevent EditorInteract() from deselecting assets when moving the camera" "6409": "Try out our asset editor" "6500": "Condense the asset editor, introducing HHAEditor()" "6769": "Check out our condensed asset editor" "6811": "Fix F4 to display the HHA page, and remove SectionPicker()" "6848": "Try out our slicker asset editor, aligning the hero" "7266": "Reload the game to find the our alignment points persist, and align Molly and Orphan #4" "7566": "Q&A" "7588": "Q: Shouldn't body pieces' displacement be a function of camera distance (and maybe angle)?" "7668": "Q: If nobody jumps in with another Q, maybe can you do the gloves?" "7711": "Q: Suggestion: Maybe turn down lighting quality in debug mode so debug can run with higher FPS again" "7718": "Q: What graphics API(s) does Handmade Hero use?" "7753": "Q: Speaking of lighting, I assume this isn't what the final lighting will look like, right? What do you have planned for that?" "7809": "Q: Dear Mr Muratori, I followed like 15 of your videos and now I'm in a game dev studio. Are you proud of me, Sensei?" "7835": "Q: Have you tried out Vulkan on any project yet?" "7863": "Q: What causes the flickering in the lighting?" "7884": "Q: The skewing when moving on Y is only applied on the body. Should the head also be modified?" "7930": "Q: Is light estimated using Monte Carlo integration?" "7994": "Q: Is there any good article on camera in the computer graphic field or video games? I am ready to learn in detail about the camera. Thanks!" "8398": "Q: Regarding Vulkan, I really wonder why you think it's not relevant these days. Or are you talking about your current project? Thanks" "8565": "Q: Are you going to to compose specific particle effects with the editor, or are they all going to be composed at runtime?" "8635": "Nintendo Switch is kinda pushing Vulkan, isn't it? Which I guess is kind of similar to mobile programming" "8767": "Structname membername =" "8803": "id announced they're going Vulkan-only for the next engine, for whatever it's worth" "8879": "Does OS support really matter that much? Seems like it's really the GPU / driver vendors who you have to care about" "8949": "Q: Hasn't this "have to use the platform specific API" thing always been the case for multiplatform console games?" "9006": "Linux people care a lot about Vulkan, though, if that means anything" "9082": "Even macOS is not worth it for most" "9119": "Close it up" --- name: "day523" title: "Introduction to Git" markers: "1": "Welcome with introductory thoughts on professional-grade source code control" "135": "Introducing git" "193": "`git help -a`" "383": "`git clone`, followed by preparation using `git bless`" "640": "Understanding and addressing git's ERROR G0099 "unrevertmail would overwrite previous degettree" using `git unrevertmail`" "966": "Addressing git's ERROR G0102 "unsetup-graph over graph 4f7b4e1a failed" using `git reset --no-hermeneutics --force`" "1131": "Addressing git's ERROR G0103 "Can't trihash-scribe-index", understanding mail servers and hashing, using `git retract` (and flags)" "1375": "Addressing git's ERROR G0097 "trirevert-index / mail 436dbcfa conflicted with quadreadporcelainmsg", using `git retract` with the --no-porcelain and --unprint-errors flags" "1496": "Addressing git's ERROR G0103 "quadverify-quote over format 315c4d46 failed" using `git retract` with the --ignore-quilt-errors and --requilt-unquilted-formats flags" "1584": "Reflect on the simple and rewarding nature of the aforementioned process" "1765": "Q: Could you go over the git-soil-archive command? I've had a really hard time understanding the docs on it" "1796": "`git git-soil-archive` and the notion of gardening" "2039": "Q: What if the atomization fails?" "2091": "Q: I heard Knuth recently proved gardening had a probabilistic polynomial time algorithm? It just has huge coefficients" "2118": "Q: I am still skeptical. Will this affect the arrangement of my garden gnomes? Rearranging them is not really something that I am able to do as they are permanently fixed in place" "2174": "`git bless --by-gnome --assume-mutable-gnomes`" "2214": "Understanding git's ERROR G0104 "Can't procpinsta-column after uncheckmultiimap with map 27ac3787"" "2257": "Q: Can you explain the --tricycleentropy option?" "2365": "Addressing Microsoft Visual Studio's Error '$Loader is undefined' by using x13pixels' remedybg" "2595": "Launch and add our project to remedybg" "2740": "Organise our remedybg layout" "2966": "Set up to fix the clipping of our hero's body with the floor during shearing" "3196": "Walk through the ZDisplacement code" "3426": "Change SpriteValuesForUpright() to use the sheared YAxis in the ZDisplacement computation" "3438": "Find that that doesn't improve our clipping situation" "3448": "Prevent SpriteValuesForUpright() from factoring the WorldDim into the ZDisplacement computation" "3472": "Find that that does solve our clipping problem, except on stairs where our hopping arc is too shallow" "3620": "Note that the top stairs sometimes flash in and out of our fog range" "3746": "Determine to finish up the asset packing for sounds, admiring our realistic lighting" "3864": "Note our need to assess the ZDisplacement calculation for spinning entities" "3903": "Listen to and organise our audio assets" "4113": "Set up to parse audio assets" "4212": "Add a "music" block to intro_cutscene.hht, introducing IntroCutscene and TitleScreen tags" "4472": "Add "sound" blocks to base_game.hht, introducing tags for our audio assets, including the concept of a Variant" "4695": "Enable ParseTopLevelBlock() to handle "music" and "sound" blocks" "5275": "Introduce ProcessAudioImport() and ParseWAV(), guided by the PNG equivalents" "5812": "Copy in our WAVE code from test_asset_builder.c" "6051": "The Resource Interchange File Format" "6134": "Reacquaint ourselves with LoadWAV()" "6354": "Change ParseWAV() to process the entire stream, delegating any chunking to users of LoadWAV()" "6629": "Audio sample rate and bit depth" "6932": "#if 0 out ParseWAV() with the determination to do it tomorrow" "6964": "Q&A" "7011": "Q: Will C++ add CSP type concurrency in the next edition?" "7115": "Q: Have you seen Bret Victor's talk Inventing on Principle?" "7121": "Q: On the pre-stream I'd asked about finding the filter kernels and you asked whether I meant the integer one or the floating point. Do you mind explaining how you found each? Thanks!" "7247": "Q: Have you tried Oni?" "7335": "Q: Don't we want 32-bit floating samples for high quality audio streams? Additionally, are we planning to support surround sound later?" "7481": "Q: What do you think about procedural audio? Will we explore something about this during future streams?" "7490": "Q: Thanks! Also, why was the windowed sinc worse than the one you found, if sincs are ideal? Does the kernel need slight changes from the ideal's values once it is windowed?" "7556": "Q: Is it possible to write a graphics card debugger like NSight, or is it something that has to be done by graphics card vendors?" "7647": "handmade_hero Hello, I'm a computer science student but recently started following your series on YouTube. They helped me a lot because you explain really good in depth. I just want to say thanks for all the work you do for us and I hope that I never catch up with the series because you will never stop doing them" "7711": "Q: I'm still wondering why we should choose git over TRAVELMAN? Despite its simplicity, I'm just not convinced it's better" "7764": "Add the -diagnostics:column flag to our cl line in build.bat, for columnar errors" "7914": "Q: You made an off-hand comment on a source control tool you made yourself. I take it few have seen it other than yourself?" "7935": "Q: They intentionally didn't make reporting columns the default behavior in order to not break backwards compatibility" "7971": "Q: Have you seen V-lang? Is it vaporware?" "8000": "handmade_hero Since there are so few questions, can I just comment that your coding style is super pleasing? Just popping out structs left and right, so procedural, no weird modern C++-isms, verbose variable and function names so there's no ambiguity. It's nice and has had a huge influence on my style for the better!" "8166": "Q: Hit a wall, every company I lookup demands OOP, and not a healthy balance of OO and procedural, but the ultra radical OO and nothing but OO" "8184": "Q:At work, I started rewriting a python package in C since its performance is so bad that nobody wants it anymore. I was wondering why people do not write in native code that often anymore and choose the scripting languages that causes lots of problems further down the road. Do you have any comment on that?" "8292": "End it there" --- name: "day524" title: "Integrating WAV Importing" markers: "1": "Welcome with a plug of Handmade Seattle, noting that the HandmadeCon site now mentions this conference" "369": "Recap and set the stage for the day merging in our WAV processing code" "453": "Navigate handmade_wav.cpp, eliciting a green flash in 4coder – denoting a render buffer overflow – at 7:43" "466": "Request a note of the green flash from Miblo" "524": "Q: Gotcha! I'll email you the link to it" "530": "Set up to implement ParseWAV()" "689": "Replace the assertions in ParseWAV() with error handling" "1208": "Consider enabling ParseWAV() to support an arbitrary number of audio channels" "1615": "Consider enabling ParseWAV() to deinterleave audio sources, for mixing down to 8 channels" "1740": "Enable ParseWAV() to deinterleave audio sources into separate buffers, introducing GetChannelSamples()" "2146": "Remove the stale code from ParseWAV()" "2214": "Iterating over RIFF chunks" "2327": "Create handmade_riff.cpp to contain our existing RIFF iteration code" "2912": "Set up ParseWAV() to parse any RIFF file, calling IterateRIFF()" "3156": "Introduce IterateRIFF() and GetHeaderChunk()" "3632": "Fix compile errors in the RIFF parsing code" "3802": "Set up to import our parsed audio data from .hha files" "3950": "Implement ProcessAudioImport(), streaming in our audio assets in chunks, and introduce UnloadAudio()" "4876": "Enable ProcessAudioImport() to tag audio assets with IDs" "5223": "Let ProcessAudioImport() instead not tag audio streaming chunks, but only reserve enough contiguously indexed asset chunks for the sample chain" "5811": "Set up ParseTopLevelBlock() to stamp out the audio channel tags" "6043": "Q&A" "6069": "Q: Not related, but do you have any thoughts on Pony lang?" "6120": "Q: How are you feeling about the way the asset system's working out so far?" "6189": "Q: What does good documentation look like? I think I've heard about you and Jon talk about documentation being really bad and soul sucking when it's auto generated. So, what does "good" human made documentation look like for programmers, and for users?" "6395": "Q: So like, Unix man pages, because they lean closer to conceptual documentation (as far as I can tell), would be more preferable to you?" "6428": "Q: Does the C code run faster, in general, if we replace something like width /=2 and height /=2 by the left bit shift <<1?" "6455": "Q: About Meow hash, do you have any resources on how you came up with it or where I could learn more about designing such?" "6542": "Q: Do modern game engines have their own sound synthesizer, or do they just import sounds from other software / libraries?" "6744": "Q: Could you demonstrate in one episode how you implemented cmirror version control? It seems very interesting. Thanks a lot" "6902": "Q: How many times have people given you the old "why reinvent the wheel?" line? I've never seen a discussion about building code from scratch not have at least someone smugly break that one out" "7116": "Q: Speaking about MSDN, I had an issue where an old version of docs had a remark that was important for a certain call, that some value should be set a certain way in a struct. Not there in the new version. ACKK!! Anyway, doesn't the "remarks" section usually have information on things like "CloseFile" for the "CreateFile" call and so on?" "7227": "Q: Why is Functional Programming not dominating corporate programming? It's much better for business apps" "7280": "Q: You changed debugger yesterday… To what again?" "7500": "Q: Anyway to get 4coder for free?" "7528": "Q: Do you know why functional programming languages tend to be so closely tied to formal verification and more theoretical work, by any chance?" "7631": "Q: Is it license-based?" "7655": "Q: Greetings Casey. How do you find balancing duplicating code versus trying to generalize a function? As an exercise, I took FormatString() – from Handmade Hero – and wrote a FormatWideString() version. In the end I chose to simply take the format, call UTF8FromUTF16(), call FormatString() on a temp buffer, then UTF16FromUTF8(). But now I sacrifice performance for maintenance. Other than if it becomes a bottleneck when profiling, what other things do you look for choosing to duplicate code and making it more a pain to maintain, than the benefits of having specific versions?" "7764": "Wrap it up with a plug of Handmade Seattle" --- name: "day525" title: "Cleaning Up Import Tag Grids" markers: "0": "Recap and set the stage for the day finishing up our WAV file importing" "263": "“Entropy is the mother of invention”" "303": "Set up to upgrade remedybg" "373": "Unpack the backpack from the back room" "648": "Fetch a thumb drive from the other room" "670": "Upgrade to remedybg 0.2.0.1" "892": "Set up to tag our audio assets" "1218": "Make SynchronizeAssetFileChanges() call a new CreateAudioChannelTagGrid()" "1260": "Determine to replace the tag grid building in ParsePieces() with the Context containing import_grid_tags directly" "1358": "Distinguishing between TagGrid and Hagrid" "1425": "Augment hht_context with import_grid_tags for ParseTopLevelBlock() to set" "2336": "Make SynchronizeAssetFileChanges() initialise all of our Context's import_grid_tags, catching an out-of-memory error early" "2879": "Relieve ImportBody() and ImportHead() of taking the tokenizer, and split ParsePieces() out into various CreateArt*TagGrid() functions" "3115": "Introduce CreateAudioChannelTagGrid()" "3342": "Fix compile errors" "3533": "Move the import_grid_tags from hht_context to game_assets, for AllocateGameAssets() to initialise once at startup" "3969": "Step through AllocateGameAssets() to see how it all behaves" "4079": "remedybg bug: Tree expansion IDs" "4137": "Step through CreateAudioChannelTagGrid()" "4154": "remedybg love: Resolution of enum item names" "4178": "Continue to step through CreateAudioChannelTagGrid()" "4209": "remedybg love: Locking of out-of-scope variables, and sheer responsiveness" "4349": "Step on through SynchronizeAssetFileChanges() to ParseHHT()" "4442": "Fix typos in ParseTopLevelBlock()" "4466": "Step through ParseTopLevelBlock()" "4499": "remedybg bug: Disassembly stepping with F10 switches focus back to the source view after stepping" "4560": "Continue to step through ParseTopLevelBlock()" "4813": "Step through the parsing of our "music" and "sound" blocks" "4870": "remedybg feature request: Display of long strings in the Watch window, potentially in a manner flexible enough to allow for displaying of images, waveforms, etc., and even the contents of other windows like Threads" "5158": "Organise music_test.wav into the correct directory" "5210": "Step back in to the parsing of a "music" block" "5369": "remedybg bug: Incorrect cursor position" "5380": "Continue to step through ParseWAV()" "5469": "remedybg love: Expression parsing, casting and relative scope variable resolution" "5761": "Continue to step through ParseWAV()" "5806": "Prevent ParseWAV() from iterating past the already departed initial chunk" "5874": "Step back through ParseWAV() to ProcessAudioImport()" "6197": "Fix ProcessAudioImport() to write the correct AssetIndex into our AssetIndexSlot" "6408": "Step back through ProcessAudioImport()" "6570": "Hit assertion in SetAssetType()" "6580": "remedybg feature request: Status line colourisation" "6628": "Investigate our !Asset->NextOfType assertion" "6812": "Make AllocateGameAssets() check for a TypeID before calling SetAssetType()" "6946": "Break into our !TypeID test path in AllocateGameAssets() to find that we follow it often" "7098": "Check out the existing "plate" processing code in ParsePieces()" "7264": "Dump base_game.hha and intro_cutscene.hha" "7421": "Check out our dumps of base_game.hha and intro_cutscene.hha in TabView" "7438": "Make PrintContents() print each asset's basic type tag at a higher, more visible level" "7591": "Introduce CategoryTags[] and CategoryNameFromID()" "7979": "Finish enabling PrintContents() to print each asset's basic type tag" "8130": "Check out the new .hha dumps in TabView to determine that intro_cutscene.hha is our culprit" "8255": "Reimport intro_cutscene.hha (in our debug build)" "8480": "Check out the new intro_cutscene.hha dump in TabView to see many chained audio assets (correctly) tagged basic type "None"" "8587": "Re-run the game and no longer hit our plate export conflict" "8622": "Consider how to tag chained audio assets" "8791": "Document hha_sound" "8865": "Re-run in an optimised build" "8899": "Q&A" "8923": "Q: Have you tried running TabVew with the --no-hermeneutics flag?" "8969": "90 / 125 sub points" "9150": "Q: You never went to university yet you seem to be very literate in mathematics. How did you get to this level?" "9372": "Q: I got a call from Gary Walsh – Selina Meyer's bag man – while you were unpacking the backpack. He said he's jealous and wants to compare bag layouts..." "9391": "Q: What are your thoughts on code introspection or adding metadata to things like structs? Useful, or yet another bad object-oriented idea?" "9470": "Q: Favorite code design learning resources?" "9475": "Q: Would you use your "from scratch / low level" approach for machine learning? Or just use a library like TensorFlow?" "9667": "QuickShift_ asked in the pre-stream: "I guess Dear ImGui is a good example of a properly used global state?"" "9692": "Q: Do you have any book recommendations for programming or mathematics?" "9733": "Q: Are you exclusively a C++ guy or have you worked with other languages over the years?" "9840": "Q: What's your favorite fairly-new language? Like the last 10 years" "9871": "Q: What's your impression of Seattle after living there for as long as you have? Where did you live before then?" "9955": "Q: Come back to Boston" "10009": "Q: If given a virtually infinite budget, what would you dedicate your time to?" "10032": "It's still valve" "10094": "Oh wow, Casey is not using Visual Studio debugger anymore! So just the compiler is being used on Handmade Hero?" "10148": "That's all, folks" --- name: "day526" title: "Single-Buffer Sound Streaming" markers: "5": "Note the upgrade to remedybg 0.2.2.0 with thanks to x13pixels" "78": "Set up to get our audio streaming into the game, checking out intro_cutscene.hha in TabView" "246": "Streaming audio into 256KiB fixed-size chunks, with thoughts on audio-visual budgetary considerations" "526": "Streaming audio into a crazy sound buffer" "752": "Crazy Sound Buffer" "1065": "Crazy sound buffer vs fixed-chunk scheme" "1222": "Implement our crazy sound buffer in LoadSound()" "1698": "Note a subtlety that could cause an incorrect sound to be played back" "1824": "Continue to implement our crazy sound buffer in LoadSound(), independent of sample bit-depth" "2036": "Introduce Agner Fog's instruction tables" "2299": "Consult Agner Fog's Skylake instruction table for the performance of DIV instructions" "2419": "Add a SampleBufferMappingMask to the game_assets with which LoadSound() may set the SampleBufferIndex using bitwise AND, rather than the less performant modulus" "2543": "Check the L2 cache latency of an Intel Skylake CPU" "2619": "Continue to implement our crazy sound buffer in LoadSound()" "2882": "Reflect on the simplicity of our crazy sound buffer" "2904": "Introduce ReserveSoundMemory() for LoadSound() (and the playback function) to know about the area of the crazy sound buffer that should not get evicted" "3093": "Enable GetSoundSamples() to play back from our crazy sound buffer, introducing GetSoundBufferMemory()" "3708": "Awareness of overlap in a circular buffer" "3829": "Make ReserveSoundMemory() return a more informative sound_buffer_memory for LoadSound() and GetSoundSamples() to use" "4299": "Implement GetSoundBufferRanges()" "4373": "Introduce InitSoundMemory() for AllocateGameAssets() to call" "4693": "Reacquaint ourselves with the audio playing code" "4893": "Enable GameUpdateAndRender() to call ChangeVolume() and PlaySound() on our piano music_test.wav" "5259": "Listen to our piano music_test.wav in-game, to find that only the first chunk plays" "5344": "Make PrefetchSound() call GetSoundSamples() to pull samples into the non-eviction region of our crazy sound buffer" "5504": "Continue to reacquaint ourselves with OutputPlayingSounds()" "5704": "Make OutputPlayingSounds() correctly compute the SampleCount and retrieve a full hha_asset * from GetSoundInfo()" "5980": "Listen to our piano music_test.wav in-game, to find that we get choppy playback when we miss our framerate" "6103": "Reacquaint ourselves with the single-play audio code" "6302": "Make ExecuteBrainHero() call PlaySound() on the Glove" "6379": "Find that we cannot hear the glove" "6462": "Step through ExecuteBrain() to PlaySound() to find that we passed a bogus SoundID" "6503": "Fix ExecuteBrainHero() to only call PlaySound() on attack, rebuild and crash remedybg" "6613": "Step in to ExecuteBrainHero()" "6649": "Make ExecuteBrainHero() set the Weight for our bloop sound asset, rebuild and crash remedybg" "6676": "Try to figure out the repro case for this remedybg crash" "6783": "Step in to ExecuteBrainHero() to determine that GetBestMatchSoundFrom() fails to find a sound" "6836": "remedybg feature request: Casting to an enum" "6920": "Step through GetBestMatchAssetFrom() to see how it's handling our request for the bloop asset" "7076": "Check out base_game.hha in TabView to find that our bloop audio assets are absent" "7244": "Check out our import errors" "7271": "Fix typos in base_game.hht" "7290": "Reimport our assets, step through ExecuteBrainHero() and successfully hear our glove bloop" "7349": "Investigate why we hear the glove bloop on repeat" "7440": "Listen to the repeated audio" "7480": "Temporarily reduce the Entity->tMovement of our glove swipe in UpdateAndRenderEntities()" "7485": "Find that the bloop audio continues to repeat" "7540": "Fix ExecuteBrainHero() to correctly perform a single attack" "7627": "See and hear our non-repeated glove attack bloop" "7634": "Revert the Entity->tMovement of our glove swipe in UpdateAndRenderEntities()" "7647": "Find that our glove is absent" "7662": "Fix ExecuteBrainHero() to float our glove when we're not attacking, rebuild and crash remedybg" "7690": "See and hear our glove in-game, and hear some clicking" "7741": "Q&A" "7780": "Q: In the LRU copy path you might have forgotten to set Result?" "7825": "Fix GetSoundSamples() to set the correct Result" "7855": "Q: Just started at a new job that has a gargantuan codebase (in the millions of lines of code) and it's very hard to follow what's going on. Do you have any general advice or approach to gaining an understanding of what's going on in files that are part of very large codebases? Also thanks! It's in a large part thanks to Handmade Hero that I managed to land the job!" "8105": "Is there a name for that type of buffer?" "8194": "Q: John Carmack likes Rust, is Rust > C++?" "8321": "Q: On an interview I was given a debugging task on a new piece of code (it was a web scraper written in Python). This company was actually generous enough to provide feedback on performance and said I would have done better if I had "debugged more systematically". Do you have any tips on better debugging practices?" "8373": "Q: Why can't we use the GF2P8AFFINEINVQB instruction all the time?" "8700": "Q: After reading your "About" on your website, Casey, what does it mean to be in gaming research and development? What's your company's bread and butter? Are you basically a consultant for other game companies?" "8997": "Q: Regarding story engines: what sort of advancements are in yours, if you can mention anything? What does it achieve?" "9043": "Close it down with an exercise for the reader: preventing the sound from skipping when we miss our frame rate" --- name: "day527" title: "Making a Stand-Alone Font Extractor" markers: "1": "Note our capability to rebuild all of our assets except fonts" "124": "Cross-platform font processing" "308": "Reacquaint ourselves with our current .hha representation of fonts" "485": "Exporting fonts to .png format for packing into .hha" "608": "Spec out a directory structure for developer resources such as fonts" "698": "Set up to write fonts out to .png and then into .hht" "923": "General thoughts on complexity in asset processing systems deriving from complex inter-relationships and structure, as we will find in fonts" "1098": "Create hha_font.cpp based on test_asset_builder.cpp" "1511": "Handle command-line arguments and respecify WriteFonts() as ExtractFont()" "2382": "Introduce the notion of a CHAR_SET_CREATOR to facilitate the creation of various character-set extraction procedures, for localisation" "3083": "Enable ExtractFont() to call LoadGlyphBitmap() on all the glyphs, making the latter operate on passed in dimensions retrieved from a GetTextMetrics() system call, and return a glyph_result" "4841": "Clean up compile errors" "5357": "Introduce Include() and IncludeRange() for CHAR_SET_CREATOR functions to call, and a codepoint_mask for ExtractFont() to take" "6063": "Run hhfont for the first time" "6175": "Print out some font extraction information" "6262": "Run hhafont on some real input, and crash beautifully" "6306": "Add hhfont to remedybg and step through it to a crash on fprintf()" "6530": "Clear the Mask.CodepointFromGlyph, and prevent Include() from doubly-incrementing through its loop" "6602": "Run hhafont successfully" "6624": "Fix Include() to only add glyphs whose code point is not 0" "6670": "Run hhafont to see a more likely glyph count" "6685": "Q&A" "6711": "Q: Are you going to implement the PNG writer?" "6792": "Q: Does the Windows API use Hungarian notation?" "6844": "Q: We had a yellow 4coder flash today. Did we know about that color of flash already?" "6893": "Q: Do you think you still improve a lot as a programmer (as opposed to when you first started)? I'd be curious to know if there are specific things you work on to keep improving" "7170": "Q: Is it hard to write a level editor? What are the steps? I just want to set positions via mouse, save them so that they're used once exited" "7210": "Demo the game's asset editing UI" "7354": "Q: What do you mean by better language?" "7496": "Q: I really like your programming style of returning a struct from a function and I have been using it a lot. Is it true that it was not possible to return a struct from a function in the early days of C?" "7612": "Q: If you were making a game with a lot of text on-screen, what text rendering technique do you think you'd go for?" "7723": "Q: How do you visualize your logic so easily? Sometimes I'll write a complicated function and it will take me, potentially, hours to debug (or fully understand); but that never seems to be a problem for you" "7882": "Q: I keep running into problems that I cannot figure out, but if I drop it and come back to it at a later date (weeks / months), I can sometimes figure out what's going wrong within 10 minutes. Any suggestions on how to improve my problem solving in this regard?" "8099": "Q: What font do you recommend for a native desktop app? A font that looks pleasant to the eye. I have a hard time finding one. Thanks for your help!" "8143": "Q: What's the hardest programming problem you've found yourself dealing with?" "8163": "Q: Do you ever use Valgrind? Would you recommend it for C (or maybe C++) code? Is there a decent Windows alternative?" "8262": "Q: What language / environment do you recommend for introducing young kids to programming?" "8483": "Q: Do you think learning to program with C is a bad idea?" "8520": "Q: How often do you work on random small projects that aren't work-related (i.e. not Handmade Hero, Molly Rocket stuff, etc)?" "8560": "Close it down" --- name: "day528" title: "Writing HHTs from HHFont" markers: "0": "Recap and set the stage for the day processing fonts" "106": "Demo hhfont with thoughts on localisation" "436": "Walk through the hhfont utility" "548": "Run hhfont with a full complement of arguments" "655": "Set up ExtractFont() to write out our font metadata to .hht and rendered glyphs to directory" "965": "Introduce Sanitize()" "1151": "Enable ExtractFont() to export our font metadata to .hht" "1692": "Hello Molly" "1746": "Continue to enable ExtractFont() to export our font metadata to .hht" "1898": "No scratching, Molly" "1957": "Fix up compile errors" "1985": "Run hhfont and check out the glyph and HorizontalAdvance data in our .hht to find that the latter is always an integer" "2126": "Change ExtractFont() to output the HorizontalAdvance as an unsigned int, and typeset the block in rows of 16" "2317": "Run hhfont and check out the block of HorizontalAdvance data" "2331": "Prettify the HorizontalAdvance output in ExtractFont()" "2356": "Check out our HorizontalAdvance block" "2378": "Set up ExtractFont() and LoadGlyphBitmap() to call our soon-to-write WritePNG()" "2776": "Introduce WritePNG() to export our rendered font glyphs (initially to .bmp)" "2968": "Try it out and check out our .bmp rendered glyphs" "3027": "Reacquaint ourselves with ParsePNG() and the PNG spec" "3445": "Implement WritePNG() guided by ParsePNG()" "4930": "Enable WritePNG() to write out an IEND chunk and temporarily blank four-byte CRC" "5160": "Try out hhfont to find that our rendered .png files are sized correctly" "5273": "Add test_png to remedybg" "5427": "Run test_png on a newly exported .png and step through ParsePNG() to see what it processes" "5560": "Make WritePNG() write out the BTYPE" "5640": "Step through test_png's ParsePNG() to find our correctly set BTYPE" "5675": "Fix WritePNG() to write out the BTYPE as part of the BFinalType byte" "5724": "Step through test_png's ParsePNG() to find that the while(LEN) loop cannot be correct" "5959": "Fix ParsePNG() to consume the correct length of pixels" "5993": "Step on through test_png's ParsePNG() to find that we do not fill all our expected pixels" "6078": "Make WritePNG() output the pixels in rows, prepending each one with a filter value" "6245": "Step through ParsePNG() to find that we still underflow" "6262": "Fix the Len computation in WritePNG()" "6289": "Step on through test_png's ParsePNG() to completion" "6358": "Fix WritePNG() to correctly offset the pixels of each row" "6382": "Export our .png glyphs to find that they remain incorrect" "6473": "Q&A" "6520": "Q: The IEND footer is missing some swaps" "6523": "Fix WritePNG() to endian-swap the IEND chunk" "6543": "Q: I love that "vertical header peek" in your 4coder editor. Is it a default feature? How can I get it?" "6614": "Q: Is the RGBA the same for bitmaps and PNGs?" "6683": "Q: Do you think machine learning can be useful in games? If yes, in what way?" "6817": "handmade_hero Will we be able to get your current 4coder? With the new version coming out and maybe the sources for yours on the Handmade Hero files? I keep doing things that you seem to have done already and, damn man, I'd love to have it" "6935": "Q: I see quite a lot of people moving into more programming / software engineering related jobs after doing some academical research, not at all focussed on CE related things (physics, chemistry, etc). Do you have any experience working with people that didn't focus on coding for a long time, possibly not having any real training in it? What's the biggest difference with people that have a degree in CE or focused on programming from a young age?" "7012": "Q: Do you feel like explicit languages make people more productive compared to expressive languages? I think functional programmers program just for masturbatory purposes" "7177": "Q: You've talked in the past about understanding the trade-offs in software development such as: optimizing increasing complexity; time constraint in the context of readability vs features implemented. Are there other things you keep in mind when deciding how to spend your time?" "7325": "Yak Shaving. New term learned" "7471": "Q: Why not use stb_image to save PNGs instead of writing your own?" "7778": "handmade_hero That's why you need to get on the writing-robots bandwagon!" "8046": "Q: Do you have a std::vector / dynamic array replacement, or are you also not using std::?" "8087": "Q: Hello, probably answered before, but I wish to use C99 with MSVC, but heard it is not so well supported by Microsoft. Could it be an issue for programming in C with Windows?" "8133": "Stack Overflow-oriented AI" "8234": "Some guy on twitch was writing a vim plugin that you ask questions to and it would look on Google or in a database for code, and paste it on your cursor" "8510": "Call it quits" --- name: "day529" title: "Debugging the PNG Writer" markers: "1": "Recap and set the stage for the day debugging our font glyph PNG writer" "299": "Reacquaint ourselves with PNGFilterReconstruct()" "431": "Try running test_png on the known-valid shot4_2.png" "506": "Craft a line that exports our font glyphs and extracts liberation_mono_0089.png to .bmp" "692": "Invoke our test line to see that our .bmp output works, but for being upside-down" "799": "Reacquaint ourselves with the pre-multiplication of alpha in our PNG loader and .hha font extractor" "927": "Prevent LoadGlyphBitmap() from pre-multiplying alpha, and instead produce a monochrome bitmap" "1014": "Run our exporter–extractor to see our monochrome .bmp" "1036": "Make LoadGlyphBitmap() flip the bitmap's rows" "1089": "Run our exporter–extractor to see that our .bmp is off-by-one row" "1118": "Fix LoadGlyphBitmap() to pad the image equally top and bottom" "1153": "Run our exporter–extractor to see our 1 pixel border" "1163": "Determine to make our PNG writer comply with the PNG spec" "1240": "Combine the PNG writer and reader, switching WritePNG() to write to a stream and introducing OutCopy(), OutStruct() and OutStructCopy()" "1642": "Switch WritePNG() to use our new OutCopy() and OutStructCopy()" "1986": "Initialise a stream for WritePNG() to use" "2267": "Delete our .png glyphs, run and crash png_test" "2420": "remedybg bug: Run-to-cursor switches focus from source to disassembly (if the latter was not open, opening it)" "2477": "Step through WritePNG()" "2718": "remedybg bug: Opening a recent session creates a breakpoint" "2760": "Step through ParsePNG() in test_png to see that the Signature is wrong" "2839": "Investigate our incorrect Signature" "2951": "Run hhfont and fail to see the printout" "2982": "Respecify DumpStreamToCRT() as DataStreamToFILE()" "3042": "Run our exporter–extractor to see that we're producing the .bmp again" "3071": "Run test_png on the known-valid shot4_2.png and compare its ZLIB header with one we produced for liberation_mono_0089.png" "3120": "Consult the ZLIB spec" "3372": "Make WritePNG() write out a valid FCHECK value" "3615": "Consult the PNG spec for the suggested CRC algorithm" "3773": "Temporarily implement the ability to write out the CRC table" "3997": "Generate our CRC table" "4005": "Enable WritePNG() to write out our CRC" "4794": "Run our exporter–extractor to see that we are producing .png files that Paint 3D can read" "4871": "Consult the ZLIB spec for the ADLER32 algorithm" "4927": "Enable WritePNG() to ADLER32 hash the data" "5318": "Run our exporter–extractor, crash png_test and investigate why" "5486": "Fix WritePNG() to include the checksum size in the ChunkHeader" "5508": "Run our exporter–extractor successfully" "5515": "Hunt for a PNG validator and find pngcheck" "5746": "Try pngcheck on liberation_mono_0089.png to see that we have a CRC error in chunk IHDR" "5813": "Carefully consult the PNG spec for the CRC information" "5970": "Fix WritePNG() to exclude the length field from the CRC" "6128": "Run our exporter–extractor and crash test_png, but find that pngcheck and GIMP recognise our .png as valid" "6263": "Run our exporter–extractor on the correct directories, and determine that we're in the clear" "6308": "Q&A" "6395": "Q: I thought there should be an error because the type was endian swapped before the CRC was calculated, but apparently that is how it works" "6434": "Q: Hi Casey, I think you would enjoy Revision demopary. There are plenty of people yelling "Amiga" frequently. And some of the Amiga demos and intros are very, very good" "6464": "Q: What do you think are other fields to look into to get hired as a systems programmer other than the game industry?" "6573": "Q: What does the align point for fonts stand for? The offset of a rectangle of size by size?" "6595": "Q: Do you use any standard software development process while creating this game?" "6621": "Q: I missed it during stream, could you show what an .hht font file looks like?" "6741": "Q: Are sampling profilers always strictly worse than adding counting points directly to the binary? I have trouble wrapping my head around the accuracy / quality of sampling" "6943": "How do sampling profilers work? Do they need to pause every thread, or can they take a snapshot somehow and then figure out where the program was?" "7676": "Q: How many game developers are there who actually care about performance / optimisation? Isn't most game development just simple things, e.g. made with Unity? Are these game devs that work in Unity as valuable as you said, that they can apply to web-scale companies and get an easy job with high salary?" "7765": "300k at Google is no joke" "7786": "Wrap it up" --- name: "day530" title: "Writing Large PNGs and Supersampling Fonts" markers: "0": "Recap and set the stage for the day with a few words on asset metadata" "259": "Determine to address the "Support writing "large" PNGs" issue" "421": "Run our font exporter–extractor for 20px high glyphs" "524": "Run our font exporter–extractor for 512px high glyphs to exhibit our bug" "634": "Set up to enable WritePNG() write out large images in multiple chunks" "771": "Enable WritePNG() to write out multiple chunks" "1526": "Consult the ZLIB spec to see where the ADLER32 checksum is supposed to go" "1702": "Continue to enable WritePNG() to handle multiple chunks, prepending rows with the filter value" "2219": "Thoughts on a more succinct and maintainable specification of the ability to modify rarely modified values, e.g. PNG filter per row" "2311": "Continue to enable WritePNG() to process rows for multiple chunks" "2483": "Enable WritePNG() to handle the ADLER32 checksum for multiple chunks, introducing BeginAdler32() and Adler32Append()" "2881": "Step through WritePNG() to find that our B and Width fail to line up" "3011": "Fix WritePNG() to correctly detect the end of row" "3041": "Run hhfont to completion, and check out a glyph in GIMP to see no antialiasing" "3135": "Consult the documentation on CreateFontA() for its ANTIALIASED_QUALITY parameter" "3326": "Enable ExtractFont() and LoadGlyphBitmap() to oversample our output glyphs" "4287": "Run our exporter–extractor to find that we produced corrupted .png files" "4352": "Prevent LoadGlyphBitmap() and ExtractFont() from scaling" "4391": "Run our exporter–extractor successfully on both 512px and 800px high glyphs" "4440": "Make ExtractFont() oversample by 2" "4448": "Run our exporter–extractor to find that we produced corrupted .png files" "4460": "Step in to WritePNG() to see that the Width and Height are 0, and then on through LoadGlyphBitmap() to see what it does" "4582": "Change LoadGlyphBitmap() to increment the SampleInner" "4614": "Step back in to WritePNG() to still see a Width and Height of 0" "4636": "Fix LoadGlyphBitmap() to increment the Sample" "4653": "Step back in to WritePNG() to find more plausible Width and Height values" "4657": "View our glyphs to find that they appear squished horizontally, but antialiased" "4691": "Fix LoadGlyphBitmap() to increment the Sample by the Scale" "4703": "Rerun our exporter–extractor and check the antialiasing of our correctly scaled glyphs" "4821": "Increase the scaling to 4 in ExtractFont()" "4839": "Rerun our exporter–extractor and check the antialiasing of these ×4 oversampled glyphs" "4906": "Prevent ExtractFont() from scaling" "4920": "Rerun our exporter–extractor and compare the antialiasing of our unscaled and oversampled glyphs" "4952": "Increase the scaling to 8 in ExtractFont()" "4965": "Rerun our exporter–extractor and compare the antialiasing of our variously oversampled glyphs" "5039": "Set our Scale amount to 4 in ExtractFont(), and briefly check the CreateFontA() documentation for the switch-over point of antialising" "5168": "Prevent ExtractFont() from scaling, to allow Windows to perform antialiasing" "5189": "Start to binary search the switch-over point of Windows' font antialiasing" "5257": "Make ExtractFont() pass the negative SamplePixelHeight to CreateFontA()" "5270": "Find that our glyphs are now larger, and explain the reason for this negative cHeight value" "5334": "Continue to binary search the switch-over point of Windows' font antialiasing" "5533": "Note that 354 is the magic value at which Windows stops antialiasing font glyphs" "5748": "Make ExtractFont() oversample if the pixel height is greater than 4" "5802": "Run our exporter–extractor on various glyph heights and check their antialiasing" "5859": "Q&A" "5895": "Q: Perhaps your certificate for large font antialiasing died" "5915": "Q: In ExtractFont(), MaxGlyphDim's x value is set using TextMetric.tmOverhang. It seems like tmOverhang should only apply to MaxGlyphDim's y-value?" "5967": "Q: Would this only work for monospace fonts?" "5974": "Q: What is the difference between the FreeType and TrueType fonts? Do both do the sub-pixel rasterization?" "6008": "handmade_hero You wrote in the note 543->544 instead of 353->354. Glasses!" "6019": "Fix the antialiasing magic value note in ExtractFont()" "6036": "Q: Did you try the Kakoune editor? Could its behavior be achieved in 4coder?" "6108": "Q: Didn't MSN say something about small fonts too?" "6171": "Q: But did you not check 500 and it worked?" "6235": "Q: GitHub bug report?" "6257": "Close the "Support writing "large" PNGs" issue" "6282": "Address the "Should we advance a character here?" issue" "6382": "Fix GetTokenRaw() to skip past the '.' of decimal numbers" "6400": "Close the "Should we advance a character here?" issue" "6456": "Q: Are there any plans for a new HandmadeCon?" "6540": "Q: I followed your suggestions and used Roboto and Droid Sans fonts for my desktop app. They look good! Thanks for that. Do you have any other suggestions for a good looking font?" "6643": "Close it down" --- name: "day531" title: "Parsing and Updating Font Metadata" markers: "1": "Recap and set the stage for the day, assuming that our certificates are not about to expire" "154": "Recall Windows' rule for antialiasing fonts (up to 353px high), and set up to parse and update font metadata" "273": "Address the "hhfont creates corrupt PNG for "space" glyph" issue" "459": "Check out test.hht with the determination to augment it with richer font metadata" "558": "Determine to break up ParseTopLevelBlock() into bundles of uniform operations, and permit such things as calling UpdateAssetMetadata() for many individual glyphs" "727": "Introduce HandleCommonFields() for ParseTopLevelBlock() to call for many block types" "965": "Extract the "default" block parsing out of ParseTopLevelBlock() for its caller ParseHHT() to perform, introducing ParseDefaultBlock()" "1445": "Extract the "font" block parsing out of ParseTopLevelBlock(), introducing ParseFontBlock() and RequireIdentifier()" "1725": "Introduce RequireField() to compress out the field parsing code" "1807": "Continue to implement ParseFontBlock() calling RequireField() and setting the Font header" "2064": "Enable ParseFontBlock() to handle the Glyph and HorizontalAdvance arrays" "2419": "Consult Molly" "2678": "Continue to enable ParseFontBlock() to handle Glyph metadata, introducing ImportGlyph()" "3100": "Enable ParseFontBlock() to handle the HorizontalAdvance metadata for every Glyph" "3256": "Enable ParseFontBlock() to handle the rest of the Glyph metadata, including code point and alignment points" "3827": "Introduce UpdateSingleAssetMetadata() for ParseFontBlock() to call" "4340": "Change UpdateSingleAssetMetadata() to take an asset_file rather than asset_source_file, and additionally take an Errors stream and FileBaseName, for ParseFontBlock() to pass" "4672": "Consider how to import glyphs specially, since they lack an asset index" "4907": "Introduce a synthetic asset file in ParseFontBlock() to denote our font assets" "5366": "Set up ParseFontBlock() to rebuild differing glyph arrays, introducing BlockDiffers()" "6259": "Implement BlockDiffers()" "6530": "Fix compile errors" "6832": "Stub out ImportGlyph() and a version of GetOrCreateAssetSourceFile() that takes the BaseName as a string" "7071": "Q&A" "7089": "Q: In NeedsFullRebuild shouldn't DataSize not be equal?" "7100": "Fix typo in the NeedsFullRebuild setting in ParseFontBlock()" "7201": "Wrap it up" --- name: "day532" title: "Finishing HHT-Based Font Importing" markers: "2": "Recap and set the stage for the day" "92": "Check out our NotImplemented routines" "154": "Implement the overloaded GetOrCreateAssetSourceFile() that takes a string, making the char * version call it" "267": "Set up to implement ImportGlyph(), reacquainting ourselves with ParseTopLevelBlock() with a view to compressing it" "510": "Enable ImportGlyph() to open source PNG file based on code copied from ParseTopLevelBlock()" "723": "Compress out the asset data updating code from ParseTopLevelBlock() into UpdateAssetDataFromFile()" "1384": "Remove ImportGlyph() in favour of making ParseFontBlock() perform that work itself" "1505": "Merge ProcesPlateImport() into ProcessSingleTileImport(), making the latter take a MaximumDim value" "1654": "Continue to implement ParseFontBlock(), calling UpdateAssetDataFromFile() and setting the BitmapID for each glyph" "2052": "Compress out the file matching code from ParseFontBlock() into FindMatchingFileFor(), for ParseTopLevelBlock() also to call" "2981": "Reflect on the state of our asset system with a view to testing the font importing" "3068": "Move the base_game.* and intro_cutscene.* files out of the way, and trigger a non-font asset rebuild" "3337": "handmade_hero Are you having any issues with the debugger or is it okay even if it's an early version?" "3484": "Find that everything imported correctly" "3518": "Run in release mode to find that the sound is fine, with the determination to finish up dynamic loading of fonts" "3599": "Make ExtractFont() write out all our glyph information and set their alignment points" "4130": "Consider getting updated alignment points to flow to ParseFontBlock()" "4338": "Enable UpdateAssetDataFromFile() to update alignment points" "4462": "Understanding C's rightward-then-leftward parsing behaviour, and our ability to control it using parentheses" "4661": "Make ParseFontBlock() pass an hha_align_point array to UpdateAssetDataFromFile()" "4920": "Trigger a full .hha rebuild" "4993": "Find that the full rebuild succeeded" "5004": "Move testfonts_v2.* out of the way, trigger a font asset rebuild, and hit a remedybg crash" "5042": "Set up WinDBG as our just-in-time debugger" "5582": "Click "Debug" and hit a "Visual Studio Just-In-Time Debugger" error" "5625": "Fix the path of WinDBG so that the root user can find it" "5683": "Trigger a font asset rebuild, reliably crash remedybg and save our mini-dump to send to George" "5954": "Run win32_handmade in remedybg okay" "5996": "Step through SynchronizeAssetFileChanges() to see files being erroneously marked as modified" "6058": "Regenerate our glyph PNGs using hhafont and organise them into our directory structure" "6304": "#include LiberationMono.hht in base_game.hht" "6414": "Step through ParseHHT() on the included LiberationMono.hht" "6504": "Add a ParseFontBlock() call to ParseHHT()" "6533": "Step through ParseFontBlock(), to find that we encounter a parsing error" "6602": "Fix ParseFontBlock() to treat the FontName syntactically as a string" "6748": "Continue to step through ParseFontBlock() to find that the Glyph syntax is parsed incorrectly" "6930": "Enable ParseFontBlock() to handle more correctly our desired Glyph syntax" "6980": "Continue to step through ParseFontBlock() to find that the Glyph syntax parsing is a little incorrect" "7021": "Fix ParseFontBlock() to fully handle our desired Glyph syntax" "7086": "Continue to step through ParseFontBlock() to ParsePNG(), to find that the latter fails due to the PNG being zero-sized" "7270": "Force WritePNG() to enter the chunk writing loop" "7345": "Regenerate our glyph PNGs using hhafont" "7404": "Step through ParseFontBlock() and past a zero-sized ParsePNG() call, until finally failing in GetFontInfo()" "7560": "Reacquaint ourselves with the Asset->HHA.Type setting code" "7770": "Make ParseFontBlock() set the Asset->HHA.Type" "7804": "Again hit our assertion in GetFontInfo()" "7830": "Tag the liberation_mono font with Tag_FontType(10)" "7892": "Crash in StringLength(), and investigate why" "8052": "Try to watch the Format variable of OutfArgList() and crash remedybg" "8110": "Continue to investigate our crash in StringLength()" "8313": "Rename to ErrorArgList() the overloaded version of Error() that takes a va_list, to work around the treatment of va_list as a char *" "8365": "Find that the StringLength() crash is fixed, and that we are back to addressing the assertion in GetFontInfo()" "8380": "Set the GlyphCount before the Tags in LiberationMono.hht" "8386": "Find that we still hit that assertion in GetFontInfo()" "8434": "Make ParseFontBlock() set the font's basic category" "8676": "Find that GetBestMatchAssetFrom() still fails to find our font" "8687": "Change ParseFontBlock() to set the font's basic category in the ExtraTags" "8734": "Find that GetBestMatchAssetFrom() still fails to find our font" "8754": "Step through ParseFontBlock(), to find that we have a parsing error" "8835": "Fix the FontType tag in LiberationMono.hht" "8841": "Step through ParseFontBlock() to completion, but sadly not success" "8914": "Fix ParseFontBlock() to set the glyph's BitmapID whether or not the font was updated" "9029": "Step through ParseFontBlock() to find that our glyphs' BitmapID values do not align as expected" "9421": "Using one integer to refer to an asset, by offsetting indices by those of other assets, as opposed to pre-allocating all the indices (as in The Witness)" "9507": "Fix ParseFontBlock() to offset the glyph BitmapID values by the AssetBase of their containing .hha file" "9688": "Find that our font importing works, but that the spacing may be a little off" "9743": "Run in release mode to see no obvious font bugs" "9798": "Q&A" "9845": "Q: If you had to support ligatures (for instance "ffi" can optionally become a single glyph when using some fonts), how would you store that information in an asset file? (I think Arabic works in a similar way...?) What about substitutions, like in some fonts the uppercase 'Q' can have a longer tail when in front of 'u' like in 'Quest'?" "9951": "Make CameraEditor() append "\\5c0f" to the "SAVE STARTUP LOCATION" button" "9992": "Find that the "\\5c0f" codepoint did not get parsed as expected" "10049": "Change IsHex() to be case-insensitive" "10078": "Find that the "\\5c0f" codepoint did not display as expected" "10090": "Change GetHex() to be case-insensitive" "10108": "Find our glyph displaying in the button" "10112": "Add the U+FB00 to U+FB05 ligatures to the Test charset in hhafont" "10326": "Make CameraEditor() use the "\\FB03" codepoint in our button" "10367": "Find that our font must lack the U+FB03 (ffi) ligature" "10408": "Try to determine the existence of "ffi" in Liberation Mono using LibreOffice Writer" "10606": "Temporarily change our font to Segoe UI Regular" "10787": "Regenerate our assets, triggering a remedybg crash" "10972": "Check out the exported ligatures of Segoe UI Regular and Liberation Mono" "11103": "This wasn't the kanji for owl..." "11247": "handmade_hero 小 is not owl, it means small" "11323": "Q: I was going through the platform code and noticed that you declare the platform struct with all the function pointers as extern in handmade_platform.h. How does the linker resolve that? Isn't the platform in a different executable?" "11375": "Q: How do we render text and do you have any thoughts on dealing with a large number of glyphs such as in Chinese" "11435": "Q: Casey, do you think most of the optimizations you use are domain specific, i.e. game development related? And if so, do you think it's possible to decouple optimizations and algorithms in the context of games? And if so, to what extent?" "11507": "Q: How was your experience of CygnusEd text editor on Amiga? How do you compare it to emacs?" "11577": "Okay, the selection happened right here" "11648": "Kanji owl research" "11800": "Q: Sadly the site you found it on seems be deceased (or at least changed). But yeah, "short eared owl" is indeed what the site said!" "11818": "Wrap it up" --- name: "day533" title: "Importing Particles, Scenery, and Items" markers: "1": "Recap and set the stage for the day sprucing up the asset system" "398": "Crash on the GetFontInfo() call in InitializeUI()" "432": "Determine to investigate the problem with segoeui.hht" "559": "Step in to GetFontInfo() to see that it could not find our font" "640": "Reacquaint ourselves with the tagging of font assets from ParseFontBlock()" "858": "Check out the base_game.hha dump in TabView, to find no font" "1042": "Step in to ParseFontBlock() to find that parsing fails on encountering a negative floating point kerning value" "1196": "Investigate why we are putting negative values into the HorizontalAdvance table" "1557": "Fix LoadGlyphBitmap() to compute the AlignPercentage and KerningChange in (signed) 32-bit floating point space" "1643": "Regenerate our Segoe UI assets, to find that SegoeUI.hht contains purely positive Kerning values" "1794": "Successfully find the font, and take a close look at its alpha blending and tight kerning" "2044": "Swap our font back to Liberation Mono" "2068": "Find that Liberation Mono is loaded okay" "2094": "Prevent GAME_UPDATE_AND_RENDER() from playing the music" "2127": "Determine to address asset tagging, noting that our floors are erroneously stone" "2210": "Investigate why our stone texture is never getting selected" "2438": "Add a breakable place in UpdateAndRenderEntities() when matching Tag_Grass" "2494": "Break in to UpdateAndRenderEntities() to see how the Grass tag gets matched" "2656": "Fix GenerateRoom() to only apply the Manmade tag if the room is not outdoors" "2723": "Find that our grass texture is correctly applied, and determine to furnish the world" "2831": "Peruse our art and consider respecifying obstacles, splitting them into their own files" "3112": "Start to add our obstacles to base_game.hht" "3181": "Split out the red armchair into its own file, including a new green variant" "3750": "Split out the table lamp into its own file" "3843": "Consider how to categorise the forestry" "4032": "Split out and arrange the ground cover foliage into separate files" "4532": "Delete our obsolete art files, and add our new packs to base_game.hht" "5014": "Enable ParseTopLevelBlock() to handle "particle" and "scenery" blocks, introducing CreateArtParticleTagGrid(), CreateArtItemTagGrid() and CreateArtSceneryTagGrid()" "5835": "Encounter an "unrecognised tag name" parsing error" "5866": "Add a Hat tag" "5889": "Successfully import our assets" "5903": "Check out the base_game.hha dump in TabView" "6011": "Make AddPlayer() add a hat" "6108": "Find that our hero's head sadly lacks a hat" "6123": "Make AddPlayer() connect the hat to the head" "6201": "Find that our hero's head still sadly lacks a hat" "6215": "Add an alignment point for TopOfHead and see the hat appear" "6358": "View the hats to see that their orientations do not match the template" "6399": "Investigate why the hat is absent when we are facing downwards" "6491": "Note that the FacingDirection is being set the same and that we imported too many assets from item_hat_03.png" "6589": "Take a close look at item_hat_03.png" "6809": "Make AddPlayer() add the Cook tag" "6834": "Check out our cook's appearance and set the alignment points" "7072": "Q&A" "7103": "Q: Was Michael Abrash around during your time at RAD?" "7121": "Q: Copy pasta snafu with the variant using YIndex instead of XIndex in the scenery tag grid" "7137": "Fix typo in CreateArtSceneryTagGrid()" "7145": "Q: How about "ornaments" for the oriented furniture instead of "scenery"?" "7158": "Q: I'm creating an OpenGL engine in C#. I really enjoy the language and I'm enjoying the process, but should I just go move to C++?" "7260": "Q: What's your learning method when faced with a new topic? How do you juggle figuring things out yourself vs reading a textbook. My problem is wanting to move quickly but also wanting to learn deeply" "7420": "Q: Do you have an official code style guide anywhere?" "7436": "Q: Hi from Hungary! I took your advice you gave me last week and started a blog to get involved in the game industry. It contains a few posts already, and some description of my earlier projects. Maybe worth reading sometime" "7710": "Q: Hi from Bulgaria (er UK now)! I’m starting an internship in July at a game studio and I’m super excited and I feel I owe you a lot of gratitude for keeping me excited about game dev!" "7767": "Q: Greetings Casey! You have a distinct coding style and though I realize you may have evolved into it over the years, I was wondering if there was there something specific that directed you? It could even have been you did not like other styles. I know you appreciate good typography too so I wonder if some of your decisions were based on what you like" "7940": "Q: You deleted an X" "7942": "Re-fix typo in CreateArtSceneryTagGrid()" "7948": "Q: Are u32, f32, etc. aliases or supported by the language?" "7979": "Thank George for fixing our reported remedybg bugs" "8117": "Q: When porting to other platforms, do you have to rewrite all your shaders in HLSL and Metal SL? Is there a way to transpile GLSL?" "8235": "Plug Jon's talk 'Preventing the Collapse of Civilization' from DevGAMM Moscow 2019" "8567": "Wrap it up" --- name: "day534" title: "Heuristic Alpha Testing for Multi-Tile Import" markers: "0": "Recap and set the stage for the day, having updated the GitHub issues for Anna" "95": "Show item_hat_03.png with a view to investigating why we are extracting six tiles from this four-tile asset" "314": "Determine to enable test_png to output alpha pixels full white" "414": "Enable WriteImageTopDownRGBA() to output any alpha pixels full white, introducing ThreshAlpha()" "592": "Run test_png on item_hat_03.png and see some spurious data in the output" "700": "Reacquaint ourselves with ProcessMultiTileImport() to see that it only processes tiles containing alpha pixels" "899": "Compare our RGB output in GIMP with the dump of base_game.hha in TabView" "1135": "Implement TestMultiTileImport() based on the game's ProcessMultiTileImport()" "1319": "Run test_png on item_hat_03.png to see that it does indeed extract six tiles" "1352": "Make TestMultiTileImport() output the extracted tile indices" "1384": "Check out our extracted tile indices" "1394": "Make TestMultiTileImport() output the dimensions of the extracted image" "1496": "Check out the dimensions of our extractions" "1566": "Make TestMultiTileImport() output our extractions to files using ExtractImage() and WriteImageTopDownRGBA()" "1949": "Check out the dumps of our extractions" "2055": "Make ProcessMultiTileImport() only import tiles containing enough valid, solid pixels" "2653": "Reimport all the assets successfully" "2757": "Revert AddPlayer() to not apply the Cook tag" "2783": "Find that our downward facing hat has made it into the game" "2880": "Prevent UpdateAndRenderEntities() from drawing the collision volume debug visualisation" "2895": "Traverse and consider furnishing the orphanage" "2983": "Make ExecuteBrain() correctly set the facing direction of entities" "3021": "Find our monstar facing in the correct directions" "3033": "Make ExecuteBrain() prevent entities from hopping diagonally" "3079": "Find our monstar unable to hop diagonally" "3181": "Consider furnishing the orphanage and making the tagging of people more flexible" "3236": "Reacquaint ourselves with the procedural generation code" "3385": "Make CreateOrphanage() place a chair in the MainRoom" "3582": "Check out our chair in the doorway of the main room" "3608": "Make CreateOrphanage() orient our chair as per its originally drawn asset" "3649": "Consider how to place and size furniture sensibly" "3786": "Fix UpdateAndRenderTitleScreen() to query the correct asset" "3846": "Check out our correct title screen and consider starting the furniture layout stuff" "4007": "Split out some trees into their own files" "4469": "Add those pieces of tree scenery to base_game.hht" "4514": "And tags for Snow, Tree and Evergreen, and enable GenerateRoom() to plant trees along outdoor boundaries" "4888": "Crash on the GetSimSpaceTraversable() call in GenerateRoom()" "4979": "Change GenerateRoom() to only place trees on open tiles" "4991": "Find that our trees are absent" "5013": "Temporarily prevent GenerateRoom() from trying to place trees" "5052": "Find that our outdoor perimeter remains absent" "5084": "Enable GenerateRoom() to generate the perimeter of outdoor rooms, placing trees anywhere other than at a connection" "5210": "Check out our forest of trees" "5221": "Fix GenerateRoom() to only place trees around the edge of outdoor areas" "5251": "Check out our tree perimeter" "5466": "Enable GenerateRoom() to randomise our trees" "5648": "Check out our forest of damaged trees" "5686": "Investigate our failure to match tree assets" "5757": "Add the snow tag and apply the same alignment to all three tree varieties" "5790": "Check out our varied forest of snow and damaged trees" "5829": "Consider how best to match absent tags" "5923": "Explicitly apply damaged and snow tags to all three tress, in varying degrees" "5955": "Check out our fully varied forest" "5993": "Q&A" "6014": "Enable GenerateRoom() to add lamps" "6024": "Check out our brightly lit orphanage" "6042": "Make GenerateRoom() place only one lamp per room" "6235": "Check out our lamps" "6286": "Prevent GenerateRoom() from placing lamps outdoors" "6318": "Q: When will you be fixing the lighting?" "6322": "Q: What's your all time favourite game?" "6330": "Q: Is there going to be lighting affecting the shading of the entities? If so, would that lighting strength be uniform along the height of the entity within a square? Is it possible to make the lighting of a 2D entity in a 3D space look "right"?" "6369": "Q: Is there a bug now that the guy is pointing left constantly?" "6417": "Q: Thoughts on creating some sort of weather system and / or sun noon, dusk, etc system?" "6482": "Q: It seems the tree graphics are for different seasons. I don't think the evergreen one is supposed to be damaged. Also you already have tags for seasons like Tag_Winter, so the Snow tag is kinda pointless?" "6505": "Q: How will we do shadows? In the past we had a bitmap for that" "6534": "Replace the "snow" tag with "winter"" "6645": "Take a turn through the forest" "6689": "We're good" --- name: "day535" title: "Minor Art Update, Reenabling Particles, Glove Fixes" markers: "2": "Recap and set the stage for the day incorporating Anna's art updates" "214": "Start to merge in Anna's art updates using Meld" "294": "Plug Beyond Compare" "344": "Use Meld to merge in Anna's art updates without diffing the .png files" "451": "A few words on permissive conformance" "548": "Continue to merge in Anna's art updates, using her filenames" "647": "Tag our updated art files in base_game.hht" "1210": "Add tags for Stars, Smoke, Cover, Particle and Fire" "1327": "Tag our updated scenery art in base_game.hht" "1481": "Add tags for Table, Rug and Sofa, and deprecate Evergreen" "1593": "Oh hello, Molly!" "1802": "Tag our updated tree art in base_game.hht" "1951": "Enable GenerateRoom() to plant more tree variants" "2033": "Import our new art, close the "hero body has left/right directions reversed" issue and note that the tree variants are not being picked fairly" "2155": "Close fixed art issues" "2197": "Fair picking of asset variants" "2485": "Close the "Re-enable sound data loading / caching" issue" "2515": "Auto-spreading of asset variants" "2573": "Open "Need to automatically assign variant values" issue" "2618": "Set up to re-enable particles" "2688": "Get UpdateAndRenderFire() working again" "2965": "Check out our particles in-game" "2976": "Make InitParticleCache() pick smoke particles" "3033": "See no smoke particles" "3062": "Make InitParticleCache() pick from particle assets" "3072": "Check out our smoke particles, noting their inconsistent displacement during camera transitions" "3147": "Trim down particle_4x and add a Size for SpawnFire() to set()" "3339": "Try changing the M() macro to use the _mm_extract_ps() instruction, before reverting it because this instruction must take an immediate" "3477": "Make SpawnFire() shrink our particles, and again note their inconsistent displacement" "3542": "Set up to consistently displace particles as the camera transitions" "3674": "Prevent UpdateAndRenderWorld() from lighting the hero" "3692": "Check out our unlit hero" "3705": "Enable UpdateAndRenderWorld() to displace the particles more correctly during camera transition" "3933": "See that the particles are almost correctly displaced, only wrong on the first frame of a camera transition" "3965": "Fix UpdateAndRenderFire() to apply particle displacement after rendering it for this frame" "4050": "See that the particles are stably displaced" "4072": "Tweak SpawnFire() to fade the particles faster" "4090": "Check out our faster fading particles" "4169": "Try making UpdateAndRenderFire() square the alpha to try and make particles fade perceptually linearly" "4212": "Check out the squared alpha fading" "4229": "Try making UpdateAndRenderFire() square-root the alpha" "4244": "Check out the square-rooted fading" "4255": "Try making UpdateAndRenderFire() cube the alpha" "4264": "Check out the cubed fading" "4271": "Settle of making UpdateAndRenderFire() square the alpha" "4277": "Admire our squared alpha fade" "4288": "Make SpawnFire() disperse the smoke a little wider" "4322": "Check out the weakly dispersed smoke" "4334": "Make SpawnFire() disperse the smoke wider still" "4346": "Check out the more dispersed smoke" "4351": "Change SpawnFire() to use the same XDir and YDir when both positioning and moving the particles" "4419": "Find that we're spawning four identical particles" "4433": "Fix SpawnFire() to produce four different particles per instruction" "4542": "Check out our dispersed particles" "4565": "Slow down the particles in SpawnFire()" "4575": "Admire our particles and art and consider tackling the variant problem" "4627": "Prevent GenerateRoom() from sticking that errant chair in the doorway" "4672": "Successfully traverse the orphanage down to the dungeons" "4746": "Consider what small thing we could do next" "4865": "Slow down the punch speed in UpdateAndRenderEntities()" "4949": "Try punching, and note that the glove drops down to the floor" "4992": "Make ExecuteBrainHero() elevate the glove to its regular Z position while punching" "5092": "Check out the more correct punching height" "5119": "Make ExecuteBrainHero() predicate the glove's hover position on the hero's facing direction" "5175": "Find that the glove is directly in front of the hero" "5212": "Make ExecuteBrainHero() position the glove beside the hero's head" "5231": "Check out the glove's sideways position" "5250": "Make ExecuteBrainHero() lower the glove's hover height" "5281": "Check out the glove's lower position" "5316": "Make ExecuteBrainHero() preserve the glove's position at the end of its swing" "5370": "Check out the glove's preserved position" "5428": "Try slowing down the punch speed in UpdateAndRenderEntities()" "5456": "Give the snake some hit points" "5551": "Hunt down the snake to see its three hit points" "5597": "Toggle on the collision volume debug visualisation in UpdateAndRenderEntities()" "5622": "Check out the hero's collision volume" "5668": "Make AddPlayer() create a collision volume for the glove" "5742": "Check out the glove's collision volume" "5762": "Make AddSnake() create a collision volume" "5811": "Check out the snake's collision volume, and try to herd him up the stairs" "5911": "Determine to make our punch damage the snake, preventing UpdateAndRenderEntities() from calling MoveEntity()" "6162": "Find that everything remains fine" "6178": "Set up UpdateAndRenderEntities() to perform overlap testing of entities" "6290": "Q&A" "6316": "Q: The AmigaOS used vblank interrupt (irq 3) for the scheduler, and the DEFAULT_QUANTUM was 4" "6482": "Q: 4 frames then changed to next task using prioritized round-robin" "6553": "Q: Will collisions be solved in a physically-based way, or in a "hacky" way?" "6694": "NTSC is ~30FPS, not 60, no?" "6880": "Close the "Hat 3 (flower) seems to be out-of-order" issue" "6922": "Wrap it up" --- name: "day536" title: "Proper Variant Distributions and Issue Cleanup" markers: "1": "Recap and set the stage for the day addressing cvaucher's pre-stream question about Handmade Hero halting under clang's address sanitizer" "33": "Address sanitizer" "150": "Q: The equivalent area in the win32 layer would be accessing Info->Platform in PLATFORM_OPEN_FILE" "168": "Reacquaint ourselves with Win32OpenFile() and related functions with a view to addressing cvaucher's BootstrapPushStruct() issue" "536": "Q: That helps. I'll check it out again and add some more detail in the forums if I need to" "621": "Our problem with fair picking of asset variants" "911": "Displaying tags in the asset editor UI, and regularising the asset sizing" "1019": "Determine to implement fair picking of asset variants" "1094": "Variants" "1359": "Creating the systemic flow to produce fairly picked variants" "1411": "Begin to fairly redistribute asset variants, introducing the notion of a VariantGroup in import_grid_tag" "1876": "Introduce UpdateAssetVariants() to perform the entire fair distribution of asset variants in a group, for UpdateAssetDataFromFile() to call" "2723": "Enable AssetEditor() to display asset tags, introducing GetTag()" "3086": "View the asset tags in the editor, with UpdateAssetVariants() not happening" "3233": "Toggle on UpdateAssetVariants()" "3243": "View the asset tags, to find that the variant code is working" "3362": "Make GenerateRoom() add a Variant tag to trees" "3434": "Check out our fairly distributed tree variants, and resize the trees" "3730": "Close the "Need to automatically assign variant values" issue and open the "Pink line in scenery_tree_03.png" issue" "3833": "Consider changing how to the asset editor UI" "4329": "Address the "Update README to discuss new downloads" issue" "4384": "Hi, Molly" "4407": "Update the README to mention tags and asset importing" "4934": "Test the documentation by building and running afresh" "5134": "Close the "Update README to discuss new downloads" issue" "5171": "Fix everything in the "Some minor issues (naming and returns)" issue" "5624": "Close the "Some minor issues (naming and returns)" and "Easier asset download so there are less steps to building current source" issues" "5775": "Let OpenGLGetInfo() enable OpenGL_ARB_framebuffer_object if we're on OpenGL 3 or higher" "5925": "Close the "Support for ARB_framebuffer_object" issue" "6009": "Change the conditional logic in BeginTextureOp() such that the MemoryAt will not get reset if the buffer is either entirely full or empty" "6102": "Hit the Result->TransferMemoryLastUsed <= Queue->TransferMemoryCount assertion in BeginTextureOp()" "6136": "Investigate that assertion hit in BeginTextureOp()" "6270": "Fix BeginTextureOp() to reset the MemoryAt if none of the buffer has been used" "6315": "Find that BeginTextureOp() is now fine" "6337": "Close the "SizeAvailable is not optimal in BeginTextureOp when there are no ops" issue and address the "win32_renderer_test.exe asserts because it can't create framebuffer" issue" "6413": "Assert in CreateFramebuffer() that the Width and Height are > 0" "6442": "Try to provoke that assertion" "6463": "Successfully provoke the assertion in the Renderer Test" "6664": "Make OpenGLBeginFrame() take and set the Commands->RenderDim" "7087": "Hit assertions in the Renderer Test and Handmade Hero, and investigate why" "7208": "Fix OpenGLBeginFrame() to set the Commands->Setting.RenderDim" "7311": "Find that all is now good with Handmade Hero but not with the Renderer Test" "7356": "Close the "win32_renderer_test.exe asserts because it can't create framebuffer" issue" "7375": "Copy the renderer_test assets back into place" "7511": "Find that the Renderer Test is now good" "7552": "Assess our issues" "7580": "Q&A" "7605": "Q: Will you do all the platform layers or leave that to the community support?" "7631": "Q: Will you add some randomness to the sizes (and maybe shape - skewing, height / width) of the trees?" "7686": "Q: What do you think about using the mouse wheel in order to drag values in the editor? In this way it wouldn't be limited by the screen space. Also, you could use something like Alt + mouse wheel for doubling the increase / decrease rate" "7715": "Q: Are you doing more Meow Hash later tonight?" "7775": "Q: Having just dealt with weighted distributions and cumulative sum draw, will you add weighted selection to the tree selection, i.e. some trees may show up more or less common?" "7934": "Q: Left-click normal speed, right-click double speed dragging? Or some modifier key that the pen also has" "7963": "Depression-oriented programming is the future" "8015": "Q: I have watched an older episode where you were coding player movement related to a moving translation point. Will there be any in-game elements using this mechanic?" "8037": "Q: Is the idea that the monsters from Anna Draws It going to be in Handmade Hero? Or at least potentially?" "8046": "Will there be any in-game elements using this mechanic?" "8087": "Q: Moving translation points (the points where the body moves to)" "8139": "Q: What is your go-to method to hide a string in a project?" "8300": "That's all, folks" --- name: "day537" title: "Filling Areas Around Rooms" markers: "1": "Set up to start something new: tag system clean-up, ground cover, lighting and world fill generation" "182": "Demonstrate the need to surround the world with an apron of non-dead space" "516": "Reacquaint ourselves with the world generation code" "702": "Introduce gen_apron and gen_apron_spec structs, for the world_generator to contain" "887": "Reacquaint ourselves with the GenRoom() function" "1033": "Introduce GenApron() based on GenRoom(), for GenerateRoom() to call" "1111": "Consider associating aprons with rooms" "1232": "Augment get_room_spec with a gen_apron_spec, for GenerateRoom() to set" "1497": "Run the game with no adverse effects" "1515": "Introduce GenerateApron() loosely based on GenerateRoom()" "1727": "Determine to perform a spacial query of entities, to prevent GenerateApron() from clashing with existing entities" "1870": "Set up GenerateApron() to generate a piece of apron where OverlappingEntitiesExist() returns false" "2665": "Implement OverlappingEntitiesExist()" "2891": "Consider removing all the world_position nonsense" "3015": "Finish implementing GenerateApron(), and make CreateOrphanage() initialise an ApronSpec, introducing GenApronSpec()" "3278": "Check out our world's above-ground apron, to find that it is being over-generated" "3433": "Make GenerateApron() set collision volumes to facilitate the prevention of collisions" "3579": "Find that the apron is being less over-generated, but that we are not seeing its collision volume outlines" "3706": "Temporarily toggle of PushCube() in UpdateAndRenderEntities()" "3732": "Check out our apron's collision volumes" "3770": "Enable GenerateApron() to expand the Z-depth of its query regions, relative to the collision volumes" "3831": "Find that our expanded query region failed to prevent over-generation" "3866": "Toggle on PushCube() in UpdateAndRenderEntities()" "3910": "Temporarily make GenerateApron() use the expanded QueryRegion as the CollisionVolume" "3922": "Find that our expanded collision volume seems to prevent over-generation" "3992": "Let GenerateApron() set the CollisionVolume as normal and expand the QueryRegion's Z-depth in both directions" "4064": "Find that the apron is no longer being over-generated, but that we are colliding with the room volumes" "4226": "Prevent OverlappingEntitiesExist() from considering the room volumes, introducing IsRoom()" "4314": "Find that GenerateApron() is now generating pieces within rooms" "4358": "Let OverlappingEntitiesExist() consider the room volumes" "4395": "Hit and investigate the VI == BaseIndex assertion in PushQuad()" "4533": "Step in to PushQuad() in a debug build" "4613": "Fix PushVolumeOutline() to reserve enough space for the twelve line segments" "4634": "Find that we no longer hit that assertion" "4664": "Make GenerateApron() produce a flat, i.e. non-varying, apron" "4729": "Find that our apron resides just below floor level, where it should have collided with the floor" "4764": "Try to make GenerateApron() elevate the apron pieces upwards by half the wall height" "4806": "Find that our apron still resides below floor level" "4825": "Investigate our room-relative placement of the apron" "4967": "Determine to respecify Z == 0 as the lowermost part of the room volume" "5041": "Make GenerateRoom() set the MinRoomP.Z to 0" "5085": "Find that the world still seems to be generated plausibly" "5139": "Change GenerateRoom() to position the rooms' min corner at 0, 0, 0" "5699": "Find that the walls remain centred" "5723": "Replace the MinRoomWP and MaxRoomWP in GenerateRoom()" "5846": "Find that all is fine" "5852": "Make GenerateRoom() factor in the -HalfTileDim to the ChangeBaseP" "5880": "Find that our rooms are tightly bounded" "5889": "Simplify the positioning of entities in GenerateRoom(), removing and replacing all calls to PlaceEntity()" "6366": "Find that we have reintroduced the half-tile offset for the walls" "6405": "Change GenerateRoom() to offset the room boundaries, and not the entities, by the HalfTileDim" "6661": "Find that our rooms and entities are positioned as desired" "6671": "Further simplify GenerateRoom(), removing variables and introducing GetTotalVolume() for it to call" "7018": "Find that we are still okay" "7038": "Simplify GenerateRoom() further still, introducing a version of ChunkPositionFromTilePosition() that takes a gen_v3" "7229": "Traverse the world with the determination to continue with the apron tomorrow" "7300": "Q&A" "7324": "Q: Why have a separate "apron" concept instead of just generating "rooms" on the sides?" "7438": "Q: Will aprons be underground and ground level only, or will you also have sky aprons for upper levels like in the case of a tall tower? You could have clouds, or birds or something. Might look neat with multiple layers, thicker clouds as you climb, etc." "7491": "Q: How to link a third party library like glfw3.lib, any suggestions on where to read about it?" "7623": "Q: Environment is very sterile because all placed static entities seem to be snapped to grid. Maybe vary the offset randomly from the tile center? Also the random height difference between floor tile could be severely reduced (who made that flooring, it's a hazard)" "7674": "Q: Will you also replace XCount with Dim.x in the GenerateApron() function as you did with Tilecount.x and y?" "7702": "Q: Have you ever used Sony's (SN Systems) debugger for PS3? Someone on Handmade Network called it the best debugger they'd ever used, but didn't really go into detail about what it did right" "7787": "Q: Have you had any unpleasant experience with the debugging on Linux?" "7803": "Q: Was the old Dune 2 game made using GDI or OpenGL?" "8265": "Peruse the code for FLIER.CPP and PARTICLE.C from the Bonus Pack, drilling down into double buffering in DOS Mode 13h from XMAIN.ASM" "8976": "Q: You are surprisingly correct on those DOS VGA programming topics. "Vanilla" mode 13h was not double buffered" "9012": "Wrap it up" --- name: "day538" title: "Making a Grid-based Layout Helper" markers: "0": "Recap and set the stage for the day" "34": "Demo the current state of our world apron, with the determination to semantically codify our world tiles to help produce that apron" "390": "Codifying world tiles such that they may be queried in a more semantic fashion" "594": "Begin to semantically codify world tiles, tentatively introducing gen_tile_volume" "973": "Work on the semantic codification of world tiles, backwards from the usage code in GenerateApron(), introducing an edit_grid struct, BeginGridEdit() and EndGridEdit()" "1866": "Create handmade_edit_grid.h, and introduce MakeRelative(), GetMinZCenterP(), and stubbed out GetVolumeFromMinZ(), IterateTiles(), IsValid() and Advance() for edit grids and tiles" "2157": "Implement BeginGridEdit(), augmenting edit_grid as required" "2791": "Respecify IterateTiles() as IterateAsPlanarTiles()" "2960": "Implement the edit_tile version of IsValid(), introducing a version of IsInVolume() that takes a gen_v3, and IsInArrayBounds()" "3240": "Implement the edit_tile version of Advance(), IterateAsPlanarTiles() and GetMinZCenterP()" "3400": "Consider our options for codifying the offsetting of room volumes vs their entities" "3530": "Specify that room volumes are not offset from 0, 0, 0, introducing GetTotalVolume()" "3771": "#include handmade_edit_grid.cpp and handmade_edit_grid.h, finish up the edit_grid struct and fix compile errors in the new edit_grid code" "4139": "Port the existing GenerateRoom() code over to the new codified tile edit_grid scheme, introducing a version of GetTile() that takes an edit_tile, IsOnEdge() and GetAbsoluteTileIndex()" "4840": "Introduce GetRoomVolume(), GetRoomMinWorldP() and GetRoomMaxWorldP() for GenerateRoom() to call" "5070": "Find that our tile grid codification enables our world apron generation to work perfectly first time, but that rooms are failing to be paged in" "5185": "Change GenerateRoom() to position the camera in the center of rooms, to enable correct paging in of rooms as we traverse the world" "5216": "Find that our camera is now fixed" "5256": "Disable the collision box debug visualisation" "5276": "Traverse the world, and see gaps in our world's apron" "5434": "Make GenerateApron() shrink the test tile when checking for overlapping entities, to try and avoid floating-point precision issues" "5472": "Find that those gaps in our apron are now filled" "5565": "Relieve GenerateRoom(), GenerateApron() and Layout() of taking a world" "5665": "Make sure that we run okay, and glimpse into the future implementing ground cover, finishing lighting and cleaning up the tag system" "5734": "Q&A" "5763": "Q: Do you plan to implement any fancy 3D audio stuff?" "5806": "Q: When you code in pure C do you have our own string library or do you always use a subset of C++ and their std string library?" "5828": "Q: Will you at any point remove the double walls between rooms?" "5881": "Q: See jeffrey's comment" "5888": "cmuratori your AddWorldRoom() call contains two Mins, not Min and Max!" "5895": "Fix typo in the call to AddWorldRoom() in GenerateRoom()" "5930": "Q: Handmade sin / cos?" "5955": "Q: I have a feeling you will find more engine work to do once you start the gameplay stuff" "6001": "Q: What about implementing a tiny animation tool in the editor? It would delay the part of gameplay programming, at least" "6026": "Q: Would you recommend any books for learning C++?" "6049": "Q: Does the apron cover everything we need now? I'm just wondering if there may be any point in using our elevation and camera angle to figure out the necessary extents of the apron for floors far below us" "6106": "Q: The world apron is meant to make the outside of the world not look so empty. Could there be entities inside the world apron as ambient entities, to make it look like there is life outside of the playing area? They could just wander around" "6162": "Q: Is the particle system complete?" "6245": "Q: Have you used git, svn or other VCS's for actual collaboration? What did you think about them?" "6500": "Q: What about simple ambience, like birds flying from tree to tree?" "6530": "Q: And in theory you could have the composition of elements / theme of the apron be visibly different yet still complimentary so that it is clear that it is in fact an apron" "6596": "Q: Do you consider any AI-related code as gameplay programming? Is there anything you could implement, engine-wise, in order to ease the coding process of these topics? For example, I could see pathfinding and world generation as a possible candidate" "6651": "Q: What about rolling fog cloud entities out there? Just a bunch of trees in a large grid sounds kinda weird" "6664": "Q: How do you write thread safe code in C or do you use C++ std::atomic in that case?" "6704": "Q: But what if the birds don't fly in a straight line, as the crow flies?" "6715": "Q: How would you implement a game like Diggles? Like in terms of the structure for the landscape?" "6845": "Close it down" --- name: "day539" title: "Capturing Source Information for Memory Allocations" markers: "1": "Recap our new world apron and the tiled nature of our game, and set the stage for the day" "203": "Demo our world apron, and set up to tackle our world solidity issues: lighting and ground cover" "491": "Transient vs persistent state in the context of lighting entities and placing ground cover" "935": "Plant trees in the apron, introducing AddTreeTags() for GenerateApron() to call" "1278": "See no trees in the apron" "1291": "Systematise entity generation for both traversable and non-traversable locations, introducing GenEntityAtP(), GenEntityAtTraversable() and AddInanimate()" "2051": "See our forest of trees in the apron" "2063": "Change GenerateApron() to plant a tree on one random tile out of three" "2088": "See our randomly distributed forest" "2104": "Prevent AddTreeTags() from picking DarkEnergy, Fall and Damaged trees" "2161": "Check out our less variable forest" "2176": "Consider preventing GenerateApron() from placing trees right next to rooms" "2254": "Note our need to light the sprites, and to prevent trees from penetrating walls by placing them carefully" "2334": "Make GenerateRoom() use our new AddTreeTags()" "2376": "Find that we're still generating all types of trees in our (non-apron) rooms" "2411": "Fix GenerateRoom() to pass the correct argument to AddTreeTags()" "2439": "Check out our winter trees, and see one tree in each room placed underground" "2596": "Try preventing GenerateApron() from placing trees" "2640": "See our sunken trees" "2647": "Try preventing GenerateRoom() from placing trees" "2688": "Still see our sunken trees" "2707": "Try preventing GenerateRoom() from placing lamps" "2724": "See no sunken trees, but still an errant entity in one room" "2742": "Try preventing GenerateRoom() from adding tags to pending entities" "2765": "Find that our sunken entity has disappeared" "2802": "Fix GenEntityAtTraversable() to only call Creator() once, and let everyone place their entities again" "2844": "Find that we have fixed our errant entity placement" "2863": "Caching ground cover in addition to lighting" "2996": "Begin to cache ground cover, augmenting the entity struct with a newly introduced ground_cover" "3272": "Gauge the performance of copying our larger entity" "3439": "Consider adding finer grained memory usage information to the debug system" "3598": "Illustrate where memory statistics may reside" "3689": "Reacquaint ourselves with the debug system" "3842": "Add a debug UI hud for the memory data block" "3857": "Check out our sketched out memory viewer" "3881": "Add the AssetArena to our memory data block" "4069": "Consider adding "total space" to our memory viewer" "4094": "Toggle on DrawArenaOccupancy() and reacquaint ourselves with it" "4391": "Criticise the overly generic nature of our debug system" "4478": "Add to the debug system purpose-built support for memory tracking, including HANDMADE_INTERNAL versions of our Push*() functions" "5776": "Find that we've broken nothing" "5782": "Toggle off HANDMADE_INTERNAL and fix compile errors" "5868": "Crash 4coder upon writing "#endif HANDMADE_INTERNAL" in handmade_import.cpp" "5889": "Continue to fix compile errors" "5960": "Crash on the call to GetFontInfo() in InitializeUI()" "6060": "Investigate the assertion hit in GetFontInfo()" "6581": "Step through AllocateGameAssets() in HANDMADE_INTERNAL" "6792": "Step through AllocateGameAssets() in not HANDMADE_INTERNAL, to see that we do not load all the asset files" "7030": "Fix AllocateGameAssets() to loop over all our allocated asset files" "7089": "Find that the non-internal build now works" "7177": "Q&A" "7262": "Q: Why do you delete the pdb's before each build? Have you found the compiler having issues or leaving junk if you just let the compiler deal with it?" "7433": "Q: In that system, do you have to transform all Push*() functions into macros?" "7450": "Q: What are some better alternatives to things like #ifdef's that a language could provide?" "7474": "Q: So all functions that allocate any memory need to become macros if you want to keep track of where the memory was allocated?" "7484": "Q: How much more stable has remedybg gotten since you started using it on stream? Were there any particularly big issues that caused you trouble that have been fixed in that time?" "7522": "Q: Do you think using tests would have made it easier to find the code paths that were broken with this refactor?" "7596": "Q: Is that why you put all Push*() functions in the same file?" "7626": "Q: If you didn't do code-reloading, like say for release, would you still have the platform exe, and a separate dll for the game code?" "7735": "Q: The caller location is a many-to-one mapping which is why languages generally don't do it. You could, but it means complications for the runtime / code-generation" "7843": "We're done with questions" --- name: "day540" title: "Adding Memory Usage Visualization" markers: "3": "Welcome to the stream" "55": "Q: There is a small compile error with Clang: "extra tokens at end of #endif" in handmade_import.cpp (#endif HANDMADE_INTERNAL). Could you fix this?" "109": "Remove HANDMADE_INTERNAL from the #endif" "131": "Q. Yes" "157": "Recap our new debug-ready Push*() functions and set the stage for the day using their file and line number information and tracking memory" "508": "Embark on memory tracking, introducing DEBUG_RECORD_ALLOCATION(), DEBUG_RECORD_BLOCK_FREE(), DEBUG_RECORD_BLOCK_TRUNCATE() and DEBUG_ARENA_NAME()" "1000": "Introduce debug_arena_allocation, debug_arena_block and debug_arena as a mirror of the real memory arenas" "1255": "Consider cleaning up our debug system in a more purpose-built way" "1284": "The importance of thread-awareness in a debug system" "1401": "#define internal and non-internal versions of DEBUG_RECORD_ALLOCATION(), DEBUG_RECORD_BLOCK_FREE(), DEBUG_RECORD_BLOCK_TRUNCATE() and DEBUG_ARENA_NAME()" "1605": "Implement our memory DEBUG*() macros, recording operations into the debug events stream, from which the debug system may pull them" "2513": "Change the Push*() functions to get their __FILE__ and __LINE__ from a DEBUG_NAME(), noting the differing treatment of string concatenation by GCC and Visual Studio" "2696": "Fix up macro-related compile errors, and remove DebugType_memory_arena_p" "3211": "Set up CollateDebugRecords() to handle our new memory debug types" "3296": "Find that the game continues to play fine" "3317": "Introduce DEBUGArenaSetName(), DEBUGArenaBlockFree(), DEBUGArenaBlockTruncate() and DEBUGArenaAllocate() for CollateDebugRecords() to call" "4165": "Implement DEBUGArenaBlockTruncate(), introducing DEBUGMoveToFreeList()" "4830": "Implement DEBUGArenaAllocate() and introduce DEBUG_RECORD_BLOCK_ALLOCATION()" "5711": "Fix up compile errors" "5994": "Implement DEBUGGetArenaByPointer()" "6178": "Hit our Block->MemoryAddress == UMMFromPointer(Op->Block) assertion in DEBUGArenaAllocate() and investigate why" "6345": "Try out remedybg's value locking functionality" "6469": "remedybg feature request: Savable variable values" "6568": "Continue to investigate our debug memory arena assertion hit" "7100": "Realise that memory arenas move around upon growing, and consider how to handle such moves" "7308": "Tentatively introduce MoveArena() and DEBUG_MEMORY_MOVE_ARENA()" "7436": "Enable the debug system to handle memory reallocations by respecifying DEBUGGetArenaByPointer() as DEBUGGetArenaByLookupBlock(), and augmenting the debug_memory_op with an ArenaLookupBlock" "8328": "Fix compile errors" "8549": "Introduce DEBUGRemoveArena()" "8765": "Hit our assertion in DEBUGMoveToFreeList() and investigate why" "8857": "Fix typo in DEBUGArenaAllocate()" "8874": "Hit our Block->MemoryAddress == UMMFromPointer(Op->Block) assertion in DEBUGArenaAllocate() due to the arena containing no blocks" "8927": "Disallow creation of memory blocks by all functions except DEBUGArenaBlockAllocate()" "8995": "Hit our new AllowCreation assertion in DEBUGGetArenaByLookupBlock() and investigate why" "9687": "Fix DEBUGGetArenaByLookupBlock() to correctly set the state of a reused arena" "9708": "Find that the game may be leaking memory" "9776": "Scour the code for our apparent memory leak" "10319": "Realise that, since the debug system uses memory arenas, it's just recording its own arena allocations" "10420": "Prevent the debug system from recording its own allocations, introducing DEBUG_ARENA_SUPPRESS()" "10917": "Hit our AllowCreation assertion in DEBUGGetArenaByLookupBlock() and investigate why" "10987": "Let the debug system only track memory blocks, just not its own suppressed allocations" "11071": "Find that the game now has more stable memory usage" "11178": "Add a memory group in DEBUGInit()" "11492": "Check out our blank memory viewer" "11585": "Set up the UI to display our memory arenas, frames and sizes" "12152": "Add a "Top Memory" list to the UI, introducing DrawTopMemList()" "12965": "Find that we display nothing" "12981": "Make DEBUGDrawElement() call DrawTopMemList()" "13056": "Hit our "Unrecognized format specifier" assertion from DrawTopMemList()" "13089": "Fix format string in DrawTopMemList()" "13100": "Check out our memory sizes viewer" "13232": "Change DEBUG_ARENA_SUPPRESS() to take a Name" "13307": "Check out our named debug system arena in the UI" "13334": "Add a memory occupancy viewer to the UI, introducing DrawArenaInterval()" "14443": "Crash 4coder after switching to the left-hand pane and typing something" "14505": "Retype and continue to implement DrawArenaInterval()" "15135": "Fail to see our memory arena visualisation" "15225": "Fix DrawArenaInterval() to increment the BlockIndex and draw the block rectangles" "15299": "See our block rectangle" "15310": "Briefly scour DrawArenaInterval() for bugs" "15392": "Step in to DrawArenaInterval() and inspect its values" "15564": "Prevent DrawArenaInterval() from drawing suppressed blocks, and make it offset the BlockRect by the ProfileRect" "15610": "Find that we're properly sizing the block rectangle, but not moving it along" "15661": "Make DrawArenaInterval() apply an outline to the BlockRect" "15759": "Check out our two, outlined block rects, and step through DrawArenaInterval()" "15848": "Make DrawArenaInterval() compute the correct dimensions of the RegionRect" "15979": "Continue to step through DrawArenaInterval() to see that we Suppress memory allocations for the Game Mode" "16068": "Make DEBUG_ARENA_NAME() set the AllocatedSize to 0" "16082": "Check out our memory Arenas viewer" "16192": "Comment out the ground_cover from the entity struct" "16233": "Check out our memory Arenas viewer, absent the ground_cover" "16260": "Uncomment the ground_cover in the entity struct" "16266": "Check out our memory Arenas viewer, including the ground_cover" "16335": "Q&A" "16378": "Q: Not on-topic at all but could you just say hi to my friend Thomas Grim who is a fervent follower of yours?" "16434": "Close it down" --- name: "day541" title: "Adding Call Sites to the Arena Display" markers: "1": "Recap and set the stage for the day" "68": "Update remedybg and show off its new Save Layout functionality" "205": "Demo our memory profiler, with the determination to draw blocks at sizes proportional to their allocation size" "1019": "Look into why the memory Sizes viewer does not show all the allocations mentioned in the Arenas viewer" "1133": "Let DrawArenaInterval() record suppressed blocks" "1259": "Find that the memory Sizes viewer still does not show all our expected allocations" "1303": "Continue to investigate the discrepancy between the Sizes and Arenas viewers" "1473": "Step through DrawArenaInterval() to see what it draws" "1669": "Fix DrawArenaInterval() to offset the BlockY when drawing suppressed blocks" "1698": "Check out our suppressed allocations in the Arenas viewer" "1841": "Add a toggle to the debug UI for drawing suppressed blocks" "2141": "Crash in DrawTopMemList()" "2172": "Fix DrawTopMemList() to sort the correct number of arenas" "2223": "Try out our Debug toggle UI button" "2331": "Investigate why the Sizes viewer does not display all Asset Storage allocations mentioned by the Arenas viewer" "2414": "Make DrawTopMemList() write out "blocks" and "allocs"" "2443": "Check out our not pretty printout" "2451": "Change DrawTopMemList() to title the list" "2592": "Check out our prettier, if slightly off, printout" "2611": "Fix up our titling in DrawTopMemList()" "2618": "Check out our prettier printout()" "2633": "Tweak the titling in DrawTopMemList()" "2649": "Consider merging allocation statistics by call-site" "2836": "Set up DrawTopMemList() to display arena usage amounts per call-site, introducing debug_memory_callsite" "3365": "See nothing different in the Sizes viewer" "3397": "Enable DrawTopMemList() to print out the arena usage per call-site, adding a "Show Callsites" toggle" "3725": "Check out our allocations per call-site Sizes viewer" "3789": "Fix up the formatting of the call-sites" "3805": "Check out our allocations per call-site, to see a high number in handmade_asset.cpp and handmade_stream.cpp" "3916": "Investigate our allocations in handmade_asset.cpp, and determine that we don't care about them" "3980": "Investigate our allocations in handmade_stream.cpp" "4068": "Enable the Sizes viewer to more specifically locate the call-sites of string allocations, augmenting stream_chunk with a GUID for Outf() and OutfArgList() to use" "4398": "Hi Molly Bean!" "4549": "Check out our more detailed string allocations in the Sizes viewer" "4623": "Investigate our allocations by the call to Outf() in UpdateSingleAssetMetadata() in handmade_import.cpp" "4694": "Fix ParseFontBlock() to apply the FontGlyph tag" "5045": "Rebuild the assets and find that handmade_import.cpp no longer shows up in the Sizes viewer" "5150": "Investigate our string allocations in handmade_asset.cpp" "5316": "Dump base_game.hha and check it out in TabView, to see that multiple chained portions of an audio asset occupy the same "spritesheet" slot" "5641": "Change AllocateGameAssets() to let all chained audio portions use the same index" "5726": "Find that this change did not remove our string allocations in handmade_asset.cpp" "5839": "Step in to an erroring Outf() call in AllocateGameAssets()" "5911": "Fix AllocateGameAssets() to correctly identify HHAAsset_Sound assets" "5924": "Step in to an erroring font Outf() call in AllocateGameAssets()" "6058": "Consult our Call Sites Sizes viewer" "6122": "Investigate our one allocation in handmade_memory.h" "6158": "Enable the Sizes viewer to more specifically locate the call-sites of BootstrapPushSize()" "6411": "Consult our Call Sites Sizes viewer" "6453": "Label the GameState->TotalArena and Assets->ErrorStream" "6623": "Rerun the game, but see that the Assets->ErrorStream remains unnamed" "6672": "Fix typo in labelling of the Assets->ErrorStream" "6679": "Find that our Assets->ErrorStream remains unnamed" "6704": "Change SynchronizeAssetFileChanges() to label the Assets->ErrorStream after allocating a block" "6733": "Consult our completely labelled Call Sites Sizes viewer" "6789": "Set up to draw memory blocks at sizes proportional to their allocation size, introducing DrawMemoryRange()" "7136": "Q&A" "7199": "Q: Do you code C++ for your day job?" "7211": "Q: All these with / without comma macros is a complete nonsense… Is there any better way to deal with it?" "7282": "Introduce DEBUG_MEMORY_NAME to compress the debug macros" "7663": "Q: I'm a Web developer by trade and my day-to-day code seems to abstract away more logic than you do in your engine. Could you explain why that is?" "7712": "Q: What would you do differently if you had to work with other developers on this project?" "7912": "Q: Yes, this is a lot better. We would have a problem when dealing with a function with 0 parameters, though (I mean, the DEBUG_MEMORY_NAME is the only parameter) because of the trailing comma" "7954": "Q: I'm wondering what language feature would make what you have done with memory tracking easier. Would it be possible to make the entire call stack available for every function at compile time at all times so you don't have to do all this macro nonsense. I'm asking in the abstract sense, not whether C++ supports it" "8038": "Q: If someone were looking to get into game programming today, would you recommend starting with using an engine like Unity, or would you recommend doing this lower level programming?" "8243": "Q: (Off-topic) A question about RenderGroup, which was introduced many days ago (when we were still working on the software renderer). What is the purpose of this entity / object / API in few words nowadays? Is it essentially a command buffer for a specific FBO with for a specific glState?" "8383": "Q: Why are games unable to saturate storage bandwidth when loading? With modern SSDs it seems like loads should never take longer than 2-3 seconds?" "8503": "Q: You've mentioned that with the engine you are writing for 1935 you are spending a lot more time documenting your process and decisions when tackling a problem. Do you have any tips or examples of what you find useful to keep track of? And what you find is just noise? I find documenting well difficult and it's easy to write too much and, ironically, not enough" "8596": "Q: Is there a good rule of thumb when it comes to guarding against errors in your code? Is there such a thing as too much handling? I could imagine having many if-statements to check conditions could cause a performance hit" "8768": "Q: So does it mean that you have augmented this caller information in your metaprogramming scheme so you can always query who called you? I hope that Jon integrated these features in JAI already…" "8801": "Q: For more specifics on where you log, do you have a file for each function? Do you have one / few giant document that you just keep adding to? Do you just add it directly to the code itself?" "8817": "Q: RenderGroup: Thanks for answering. Sounds like an abstraction of the gl API + the notion of a renderpass?" "8893": "Q: What are your thoughts on visual programming languages? Do you imagine good use cases for them and, if so, in what contexts do you think they work? My understanding is that it's challenging to make a good visual language and that usually the special-purpose ones work better than attempts at general-use ones" "9047": "Q: To touch on the over-error checking, what about the case where you're making an API that is to be accessed by other developers? Right now I'm making a library for the TwitchAPI that will be constantly interfaced by users, but I feel like I'm holding their hand too much with errors instead of assuming they have any idea what they're doing, to the point where a significant amount of the library is just error checking" "9226": "Q: Going back to a question near the beginning about "abstracting logic", I think the heart of the questions is due to a discussion about what is "clean code". Some higher level languages seem to make things "look good" but "clean code" is, at least to me, isn't very well defined. Maybe they were looking for why does this look complex vs something that's a few lines of code (but contained in a bunch of little files, in my opinion). My thoughts are due to performance, fine tuning, and knowing exactly what's going on rather than guessing. I do that a lot using python" "9841": "Q: Have you tried Odin? Any thoughts?" "9853": "Q: Casey, what you're saying is really good, but opposite to what devs are being told in schools…" "10015": "Q: Java is still Intro to CS and oftentimes C / C++ is barely covered. Why do you think that is? I think it's because a lot of old "corporate" financial companies in the old guard were stuck in OOP server land. It's frustrating" "10101": "We're all good here" --- name: "day542" title: "Drawing Memory Occupancy Accurately" markers: "0": "Plug Handmade Seattle" "81": "Recap and set the stage..." "86": "I'm surprised that Casey likes Chrono Trigger" "143": "Recap and set the stage for the day" "194": "Demo the current state of our memory viewers, with the determination to draw our blocks at sizes proportional to their usage amount, and track peak usage" "488": "Set up DrawArenaInterval() to draw proportionally sized ranges of memory" "1012": "Implement DrawMemoryRange()" "1830": "Check out our incorrect memory Arenas viewer" "1856": "Fix DrawArenaInterval() to advance the BlockStartAddress" "1886": "Check out our less incorrect memory Arenas viewer" "2017": "Fix DrawMemoryRange() to correctly draw sub-regions of rows" "2094": "Check out our proportionally-sized memory Arenas viewer" "2451": "Add colours to the DebugColorTable, requesting a .h file containing the 64 most easily differentiated colours" "2588": "Enable DrawTopMemList() and DrawArenaInterval() to track and colour allocations the same per call-site" "3805": "Hit our "too many call sites" assertion in GetCallSiteFrom()" "3924": "Change GetCallSiteFrom() to compare GUIDs as strings, rather than by pointer, and increase the ArenaCallSites size" "3958": "Check out our memory Sizes viewer to see call-sites currently responsible for 0 allocations, but the Arenas viewer not colouring call-sites consistently" "4062": "Fix DrawArenaInterval() to use the CallSiteIndex in the lookup to the DebugColorTable" "4071": "Check out our consistently coloured memory Arenas call-site viewer" "4250": "Change DEBUGInit() to expand all the debug views by default" "4860": "Find that the debug views are not expanded by default" "4894": "Change DEBUGInit() to call SetExpand() after the AddTree() calls" "4907": "Find that the debug views remain not expanded by default" "4909": "Scour the code for the reason why the debug views are not expanded by default" "5082": "Step through DEBUGInit() to see how view collapsibility figures in to it" "5205": "Consult the code to see if it matters if the View.Type is unset" "5291": "Continue to step through SetExpand(), to find that we correctly match the Tree but not the Link of our views" "5491": "Discover that we create dummy view groups, to later replace them in CollateDebugRecords()" "5598": "Make CollateDebugRecords() expand HUD groups" "5686": "Find that our debug views are now expanded by default" "5770": "Add per-arena peak memory usage tracking to DEBUGArenaBlockAllocate() and DrawTopMemList()" "6041": "Check out our peak usage in the memory Sizes viewer" "6141": "Add per-call-site peak memory usage tracking to DEBUGArenaBlockAllocate() and DrawTopMemList()" "6362": "Check out our per-call-site peak usage in the memory Sizes viewer" "6446": "Add a %m conversion specifier for FormatStringList() to convert byte-amounts to sensible, non-zero multiples of bytes, i.e. b, kb, mb, gb" "6986": "Find that our byte-amounts are incorrectly displayed" "7006": "Prevent DrawTopMemList() from casting memory amounts to u32 in its calls to FormatString()" "7078": "Check out our correctly converted byte-amounts" "7130": "Tweak FormatStringList() to display 1 kb, mb and gb as such, rather than 1024 of their smaller multiple" "7145": "Check out our perfectly converted byte-amounts" "7162": "Q&A" "7182": "Q: Do you think that having a way to visualize the memory as an image could be useful? How you would implement that?" "7354": "Q: Admittedly I have not been watching all the streams or reviewed the code, but if this tracks memory, and the transient memory could reset itself throughout the frame, is what is only tracked what is left at the end of the frame? And if you have collected peak information? Is the reason the memory appears static because you are not doing anything new / different between frames?" "7461": "Q: Are you planning to add more features to this?" "7469": "Q: Started watching you awhile back, is the earlier episodes still relevant / worth it, or should I start somewhere more up-to-date so to speak?" "7539": "Q: Are you going to add an edit box to filter / reduce the visible lines for memory?" "7544": "Q: Thanks for the image scaling explanation in the pre-stream. Could you explain about zoom towards the mouse position? Thanks!" "7801": "Q: The timing part of the profiler, you had it so you could click on a section and zoom into that section to see more details about a section. Do you see value for it here? Almost like an embedded tab-view that could show the allocations of each object if you wanted to see it? Or what about an option to print to a file the current allocations?" "7874": "Q: In the threading tutorial you used a pointer to a function. I know that you want to keep it C-style, but wasn't that cleaner to just use a method inside a struct? It'd remove every "pointer = func"" "7972": "C-style function pointer in struct vs C++-style virtual function in class" "8623": "Q: What about C++ lambdas in that case?" "8714": "handmade_hero I meant "GameMemory.PlatformAddEntry = Win32AddEntry" and "GameMemory.PlatformCompleteAllWark = Win32CompleteAllWork" platform_add_entry is a void and it points to Win32AddEntry instead of just a single method in a class / struct without jumping through the files and "=" every function pointer" "8792": "Q: My nephew started computer science a year ago and when I saw the educational materials they are not good and professors mostly teach the toy examples. I think there is a problem with computer science education. Do you know how it can be improved? Maybe the production programmers should teach the programming courses" "9028": "Q: Would there also be an issue in C++ if you wanted to have it be in a queue and some other thing, perhaps, would need to inherit from two or more things?" "9073": "Q: Is the C++ way – a lot of hoop jumping just to avoid the cast from the void* to the data type (that you need to do in the C function pointer method) – did the C++ committee reason that it's more type safe?" "9104": "Wrap it up" --- name: "day543" title: "Moving Unpacked Entities from the Sim Region to World" markers: "1": "Recap and set the stage for the day" "70": "Demo our new memory viewer, with a view to working on the storage of our world's entity data" "365": "Our entity system, not pre-designed" "490": "Compare the memory requirements of our entity system, with and without the ground_cover" "535": "Our concrete problem: visual effects only need to be stored while they are visible" "856": "Alternative, lossy representations of entities" "1051": "BeginSim() and the (un)packing of entities" "1310": "Changing the sim_region to contain a reference table of entity pointers contained in the world's cache" "1462": "Start to reacquaint ourselves with all uses of the sim_region's Entities" "1600": "Reacquaint ourselves with the sim_region's EntityHashOccupancy" "1700": "Continue to reacquaint ourselves with all uses of the sim_region's Entities" "1769": "Augment the world struct with UnpackedEntities, into which the sim_region may point" "2224": "The problem of determining which entities to pack" "2432": "Change all instances of entity array iteration in the sim region to operate as if on a reference table of pointers, introducing entity_iterator and IterateAllEntities()" "2745": "Begin to move all the existing entity storage, packing and unpacking code from the sim region to the world, introducing EnsureRegionIsUnpacked()" "3411": "Consider how to correctly set the origin of entities during unpacking" "3762": "Augment the world with a world_position UnpackOrigin, for EnsureRegionIsUnpacked() to use, and introduce RegisterEntity()" "4255": "Introduce a version in the world of CreateEntity() that takes a world *" "4511": "Introduce RepackEntitiesAsNecessary() in the world, for the sim region's EndWorldChange() to call" "5097": "Implement IterateAllEntities() and the entity_iterator version of Advance(), introducing FindNextEntity()" "5458": "Hit our assertion in GetHashFromID()" "5490": "Fix BeginWorldChange() to call EnsureRegionIsUnpacked()" "5541": "Hit our InvalidCodePath in EnsureRegionIsUnpacked()" "5562": "Remove Entities_ from the sim_region, and fix EnsureRegionIsUnpacked() to operate on the entities in the world" "5608": "Hit our InvalidCodePath in EnsureRegionIsUnpacked(), and investigate why" "5775": "Augment the world with an UnpackIsOpen to prevent multiple concurrent unpacks of the same sim region" "5870": "Hit our InvalidCodePath in EnsureRegionIsUnpacked(), noting that entity (un)packing succeeds during world generation, but not during simulation" "6069": "Enable EnsureRegionIsUnpacked() to detect infinite looping" "6411": "Hit our InvalidCodePath in EnsureRegionIsUnpacked(), assuming that it is not infinite looping" "6437": "Investigate why we are hitting the InvalidCodePath in EnsureRegionIsUnpacked()" "6717": "Step through many calls to RepackEntitiesAsNecessary(), watching the EntityP values" "7008": "Step through IterateAllEntities() to see that we do find stuff" "7116": "Step through EnsureRegionIsUnpacked(), watching which chunk is responsible for the majority of blocks" "7293": "Track our number of packs minus unpacks" "7468": "Find that the LastUsedEntityStorageIndex is 31 higher than our TotalEntityPacksMinusUnpacks" "7592": "Temporarily set a huge MAX_SIM_REGION_ENTITY_COUNT" "7721": "Step over BeginWorldChange() to find that we are trying to unpack 15383 entities, fewer than the LastUsedEntityStorageIndex of 21523" "7762": "Disable lighting" "8288": "Crash in LoadEntityReference()" "8354": "Make RepackEntitiesAsNecessary() take a SimRegion to pass to PackTraversableRefernce()" "8408": "Still crash in LoadEntityReference()" "8443": "Fix FindNextEntity() to only find an entity if its occupancy slot is not empty" "8628": "Run without crashing, but see that RepackEntitiesAsNecessary() is happening too often" "8723": "Step through BeginSim() to see a huge discrepancy between our TotalEntityPacksMinusUnpacks of 6109 and LastUsedEntityStorageIndex of 21523" "8796": "Scrutinise EnsureRegionIsUnpacked()" "8878": "Fix EnsureRegionIsUnpacked() to offset the Dest->P after actually setting the Dest" "8893": "Find that everything now works, noting the performance of the game in debug mode without lighting" "8969": "Re-enable lighting" "9001": "Find that we are fully back to normal" "9056": "Q&A" "9120": "Q: Will the packed entity be a separate struct, and what is the plan of adding / removing data?" "9247": "Q: I had a question regarding the Arena graph in the profiler, though it may have changed this episode, and you may not be able to display it in its current state. It was about why there were separations between the ground chunks (the first group, all were "green", but every X amount, there was a gray value that separated them). What was this separation?" "9461": "Remove the cruft from world_entity_block" "9555": "Check out our more closely packed entity blocks" "9691": "Change CreateWorld() to put the world in its own memory arena, noting that GetWorldChunk() allocates space for the headers" "9843": "See that our entity blocks are packed the same" "9864": "Revert CreateWorld() to put the world in the GameState->ModeArena" "9887": "Note the utility of memory usage visualisation" "9905": "Change GetWorldChunk() to allocate space for chunks in bulk" "10169": "Check out our perfectly packed entity blocks" "10280": "Q: Did you ever figure out MEM_LARGE_PAGES for VirtualAlloc? Is that what you're talking about?" "10295": "Q: How did people do memory management in the era of Commodore 64 for writing games? It is so luxurious nowadays with all these amounts of memory we have on our machines" "10419": "Close this down for today" --- name: "day544" title: "Caching Unpacked Entities Across Frames" markers: "1": "Recap and set the stage for the day, judiciously packing and unpacking entities" "245": "Show the game running" "252": "Remove entity_reference in favour of making the traversable_reference and entity structs identify entities by entity_id" "1131": "Hit our assertion in GetHashFromID()" "1151": "Change GetEntityByID() to only call GetHashFromID() if the ID.Value is valid" "1215": "Find that we're back to good" "1319": "Set up to cache our entities, likening our plan to L1 and L2 caches in CPUs" "1729": "Make RepackEntitiesAsNecessary() repack entities that do not fall within a given chunk volume, introducing IsContainedInChunkVolume() and respecifying the world's version of CreateEntity() as AcquireUnpackedEntitySlot()" "2731": "Clean up the entity slot stuff, introducing a free_entity for the world to contain and CreateWorld() to chain up" "3863": "See nothing in-game" "3889": "Walk through our new entity caching code" "4173": "Consult the profiler" "4234": "Temporarily make RegisterEntity() operate on every Entity it is passed, even if it resides outside our sim region" "4266": "Crash on a call to END_BLOCK()" "4514": "Consider performing heap compaction on our entities" "4659": "Remove free_entity in favour of making RepackEntitiesAsNecessary() perform heap compaction on our entities" "5053": "Crash again on a call to END_BLOCK()" "5429": "Revert RegisterEntity() to only operate on an Entity if in resides outside our sim region" "5492": "Step through many calls to RegisterEntity(), watching the Entity->P values" "5690": "Step through AddPlayer() and through the camera initialisation code to see no obvious incorrectness" "6060": "Carefully read through EnsureRegionIsUnpacked() and RepackEntitiesAsNecessary()" "6190": "Try to break in to RepackEntitiesAsNecessary() to find that we never actually repack entities" "6294": "Consider our bug to be in EnsureRegionIsUnpacked() and RegisterEntity()" "6464": "See our world off in the distance, with our camera and entities misplaced" "6544": "Scour the code in the knowledge that we're tackling a positional bug" "6703": "Offsetting the sim region origin across frames" "6896": "Fix the order of arguments passed to Subtract() by EnsureRegionIsUnpacked()" "6920": "Find that we've solved the problem" "6966": "Start to enable RepackEntitiesAsNecessary() to repack entities that are some distance outside our sim region" "7111": "Make EnsureRegionIsUnpacked() responsible for packing entities" "7685": "Hit our assertion in EnsureRegionIsUnpacked()" "7726": "Fix EnsureRegionIsUnpacked() to square our MaxAllowedDistance" "7748": "Find that we're fine" "7765": "Q&A" "7829": "Q: Would you do Linux programming if you had a RemedyBG on Linux?" "7878": "Q: Will there be any memory difference with TooFarFromPrecision vs no TooFarFromPrecision? (If so, can we see in the memory viewer?)" "7930": "Q: I'm working on a project where "the client" has written some prototyped mathematics code in Matlab. I've translated most of it, however, I have some discrepancies with the output, and I can't figure out if there's a better way to debug the problem than a whole bunch of printf debugging. Thoughts?" "8040": "Q: When you are hopping around in a large room, it appears when you are hopping up, it seems that the outer area is lighter than that around around the player. Is this on purpose? Or used temporarily to demonstrate something?" "8126": "Q: How large a world does the float precision allow in this case? (I remember it being a problem in some games with large maps where the edges lose precision)" "8168": "Step in to EnsureRegionIsUnpacked() and inspect our ChunkDimInMeters to see the sheer size of our world" "8294": "Q: The assertion that we didn't find was a debugtable assertion: assert macro inside record event macro inside destructor of the timed function. Can we put a MessageBox into the assert macro to find these kinds of asserts more easily?" "8306": "Q: Heard about posits? Better precision and faster than normal floats (not in hardware yet obviously)" "8410": "Q: Do you have time to explain on the zooming towards the mouse position and how it can be implemented (not coding just the concept and algorithm)? Thanks a million" "8441": "Q: Do you have any advice on how to ensure the uniqueness of UI element ids in an immediate mode UI in a setting in which the number of elements changes from frame to frame (so using monotonically increasing counter won't work)?" "8654": "handmade_hero What's the most effective way of testing code? I come from a web development background and there's a very heavy focus on unit testing and test driven development. I'm not sold on the dogma of that and I don't think it's really used in game development, which makes me curious as to how you do test effectively in game development" "8971": "Q: You said last week you will explain the zooming towards the mouse pointer on the white board. If it is not too much bother, otherwise I try to find something on google. Thanks a lot again" "9021": "Zooming towards mouse pointer, using a Stretch() function" "11077": "End" --- name: "day545" title: "Adding Ground Cover" markers: "1": "Recap and set the stage for the day" "146": "Consider the need to speed up our lighting solution, determining to generate ground cover to exercise the entity system's new caching" "433": "Temporarily reduce the MaxUnpackedEntityCount in CreateWorld()" "467": "Take a look at the smaller memory footprint of our entity system" "520": "Revert our MaxUnpackedEntityCount in CreateWorld()" "574": "Determine to produce ground cover to page in and out from the cache" "597": "Organise the entity struct with the disposable Lighting and Cover at the bottom, after a DiscardEverythingAfter value" "830": "Set up to discard the Lighting and Cover when packing" "866": "Set up to enable EnsureRegionIsUnpacked() to stream our minimally-stored entities into packed storage, based on the PNG reader" "1090": "Enable EnsureRegionIsUnpacked() to stream our minimally-stored entities into packed storage" "1727": "Check out the smaller memory footprint of our packed entities" "1819": "Introduce FillUnpackedEntity()" "1935": "Plug the grass distribution solution for The Witness" "2025": "Implement FillUnpackedEntity(), introducing a ground_cover_spec struct for entity to contain" "2837": "A few words on white and blue noise" "2944": "Enable FillUnpackedEntity() to distribute grass in a white noise "pattern", introducing RandomSeedOffset() and PointFromUVW()" "3931": "A few words on API design and delivering assets to the game in a way it wants to use them" "3996": "Fix compile errors, passing the GameState->Assets through to FillUnpackedEntity(), and augmenting the world_generator with Assets" "4420": "Pack all entities for dispersal on initialisation, introducing ClearUnpackedEntityCache() and PackEntity()" "4995": "Crash on EndWorldGen()" "5037": "Investigate our crash on the ClearUnpackedEntityCache() call in EndWorldGen()" "5083": "Fix EndWorldGen() to call ClearUnpackedEntityCache() before clearing our memory" "5094": "Check out our profiler to see that everything is as expected" "5176": "Enable GenerateRoom() to request ground cover for outdoor areas" "5247": "See 0 calls to FillUnpackedEntity()" "5297": "Introduce DrawGroundCover() for UpdateAndRenderEntities() to call, fixing FillUnpackedEntity() to keep ground cover affixed to entities, e.g. moving platforms" "5886": "See no ground cover" "5914": "Break in to FillUnpackedEntity()" "5965": "Fix FillUnpackedEntity() to set the Entity->GroundCoverCount" "6004": "Break in to FillUnpackedEntity() to see that our ground cover's P and the CollisionVolume of its containing entity are unset" "6121": "Enable GenerateRoom() to produce collision volumes for all floor entities" "6270": "Break in to FillUnpackedEntity() to see that our ground cover's P is now set" "6304": "Fix DrawGroundCover() to offset the sprite by the entity's position" "6389": "Step in to DrawGroundCover() to see pretty reasonable values for our Sprite" "6562": "Enable GenerateApron() to request ground cover" "6594": "See grass on our apron" "6610": "Fix DrawGroundCover() to offset the sprite by the ground cover's position" "6668": "See our lush ground cover" "6706": "Scale down the ground cover to 0.25f in UpdateAndRenderEntities() and make GenerateRoom() produce collision volumes the same way GenerateApron() does it" "6858": "Note that we are not offsetting the ground cover's collision volume by the floor tile's stagger" "6875": "Fix GenerateRoom() to offset the ground cover's collision volume by the floor tile's stagger" "6999": "Find that we are sunken into the ground" "7015": "Fix GenerateRoom() to correctly set the traversable position" "7264": "Traverse the orphanage and surrounding areas" "7300": "Scale up the ground cover to 0.5f in UpdateAndRenderEntities() and increase their density in GenerateRoom()" "7341": "Admire our (unlit) ground cover" "7403": "Scale down the ground cover to 0.3f in UpdateAndRenderEntities()" "7422": "Admire our correctly sized ground cover" "7459": "Max out the density of our ground cover in GenerateApron()" "7471": "Q&A" "7485": "Gauge the performance of our ground cover rendering" "7561": "Q: Do you intend cover to be used for things like footprints, and do you want cover to be interacted with? Like grass shifting as you walk through it to show a path where someone has walked" "7600": "Plant flowers everywhere we hop, augmenting the ground_cover_spec with two Reserved values and introducing StompOnEntity() for UpdateAndRenderEntities() to call" "8040": "Plant flowers" "8061": "Increase the ENTITY_MAX_GROUND_COVER to provide more space for our planted flowers" "8081": "Plant flowers outdoors and in the dungeon" "8164": "Q: Will there be a sort of transition from the doors to the outside? I suspect yes but curious of how?" "8214": "Q: Of the grass?" "8261": "Q: If you step on a tile more than once do the flowers stack?" "8277": "Enable StompOnEntity() to plant more flowers on each stomp" "8299": "Plant flowers until we wrap the 8-bit density count" "8493": "Toggle off the flower planting in StompOnEntity()" "8520": "We're done" --- name: "day546" title: "GPU MIP Mapping" markers: "2": "Recap and set the stage for the day" "40": "Demo our new ground cover, with the need to light our sprites" "109": "MIP mapping our sprites" "494": "Distributing our grass more naturally" "595": "Plan to work on our rendering quality" "668": "MIP (Multum In Parvo) maps" "840": "Texture sampling" "1085": "MIP map pre-filtering" "1395": "Anisotropic filtering" "1831": "MIP map memory bandwidth savings and efficiency" "1975": "Understanding glTexSubImage3D()" "2109": "Understanding the "level" parameter of glCompressedTexSubImage3D()" "2198": "Set up OpenGLManageTextures() to specify the texture subimage of multiple MIP map levels" "2258": "Understanding glGenerateMipmap()" "2340": "Experimentally revert OpenGLManageTextures() and instead call glGenerateMipmap() to do all the MIP mapping" "2463": "Better understanding glGenerateMipmap()" "2639": "Abandon glGenerateMipmap() and make LoadAssetWork() to generate the MIP maps ourselves" "3349": "Make OpenGLManageTextures() specify the texture subimage of multiple MIP map levels" "3488": "Introduce Downsample2x() for LoadAssetWork() and our original Downsample() to call" "3783": "Create handmade_image.cpp and .h" "4157": "Introduce GenerateSequentialMIPs() for LoadAssetWork() to call, IterateMIPs() and the mip_iterator versions of IsValid() and Advance()" "4523": "Consider how best to indicate special textures to BeginTextureOp()" "4787": "Change BeginTextureOp() to take a SizeRequested for LoadBitmap() to pass, introducing GetTotalSizeForMIPs()" "5075": "Implement GetTotalSizeForMIPs(), IterateMIPs() and the mip_iterator versions of IsValid() and Advance()" "5469": "Step through BeginTextureOp() to debug our new MIP mapping work" "5594": "Fix GetTotalSizeForMIPs() to correctly accumulate the size, and the mip_iterator version of Advance() to operate the opposite way round" "5629": "Step through GetTotalSizeForMIPs() and out to LoadBitmap()" "5793": "Hit a GL_INVALID_VALUE OpenGL error in OpenGLDebugCallback()" "5955": "Fix LoadBitmap() to set the TextureOp->GenMipMaps" "5990": "Step through GenerateSequentialMIPs() to see that we're not dealing with powers of 2 sizes" "6122": "Enable the mip_iterator version of Advance and Downsample2x() to handle non-powers of 2 sizes" "6520": "Step through GenerateSequentialMIPs() successfully" "6572": "Investigate the GL_INVALID_VALUE OpenGL error in OpenGLDebugCallback()" "6679": "Make OpenGLInit() announce all of our MIP levels" "6783": "Find that OpenGL is accepting our textures, but we have glitches" "6905": "Understanding the GL_TEXTURE_MIN_FILTER value for glTexParameteri()" "6985": "Temporarily prevent LoadAssetWork() from calling GenerateSequentialMIPs()" "7004": "See that our rendering glitches are gone, and consider our possible bugs" "7035": "Scour Downsample2x() and GenerateSequentialMIPs() for bugs" "7125": "Slightly simplify GenerateSequentialMIPs()" "7190": "Step through GenerateSequentialMIPs()" "7422": "remedygb bug: Clicking values of entered variables" "7480": "Just fixed that about 20 minutes ago" "7501": "Step through Downsample2x()" "7628": "Add a space-checking assertion in GenerateSequentialMIPs()" "7737": "Fail to hit that assertion in GenerateSequentialMIPs()" "7758": "Investigate our rendering glitches, scouring LoadBitmap()" "7800": "Slightly simplify LoadBitmap()" "7881": "Continue to investigate our rendering glitches" "8036": "Slightly simplify OpenGLManageTextures()" "8049": "Continue to investigate our rendering glitches" "8102": "See our rendering glitches" "8122": "Temporarily prevent Downsample2x() from writing the pixels" "8141": "See that our glitches are gone" "8144": "Let Downsample2x() write the pixels" "8177": "Assert in GenerateSequentialMIPs() that the end of one bitmap is the start of the next" "8258": "Fail to hit that assertion but still see the glitches" "8303": "Change GenerateSequentialMIPs() to fill the MIP map with a different colour per level, introducing FillImage()" "8512": "See no rendering glitches" "8525": "Scour Downsample2x() for bugs" "8555": "Fix Downsample2x() to output the correct sized image" "8610": "See that our glitches are gone, and we are not using our MIP maps" "8628": "Enable MIP maps in OpenGLInit()" "8732": "Admire our smoother, MIP mapped textures" "8854": "Q&A" "8884": "Q: Would you want to add shaders to the asset system?" "8941": "Q: Which textures are considered "special textures", and why do they not want MIP mapping?" "9037": "Q: (Off-topic) Can you explain these light blue kind of selection bars in 4coder?" "9059": "Q: Request to change the name of mip_iterator to mipterator" "9066": "Q: Through stream is difficult to notice. Can we please see an image sent through chat difference between before and after MIP maps?" "9110": "Enable OpenGLChangeToSettings() to toggle MIP maps and nearest texel filtering" "9706": "Try toggling nearest texel filtering and MIP maps" "9787": "Q: Is there an easy way to view the MIP maps sent to the GPU and, if so, why didn't you use that feature for debugging purposes before?" "9872": "Q: Some file formats like DDS have MIP maps already baked in. Is generating them better nowadays or does it actually matter any longer?" "9977": "Q: If we add some packing, would MIP maps interfere with that?" "10059": "I don't watch you much but I was wondering: Are those settings you toggle, can / do you have a GUI so users can interact, or is that different?" "10162": "Close up shop" --- name: "day547" title: "Starting the Move to Light Probes" markers: "0": "Recap and set the stage for the day cleaning up the lighting" "57": "Demo the state of our lighting solution" "217": "Why is our lighting slow?" "217": "Lighting performance: 1. Threading" "300": "Lighting performance: 2. GPU vs CPU" "486": "Lighting performance: 3. Algorithmic approach" "707": "Light Probes" "781": "Light Probes: Ours" "984": "Light Probes: Theirs, with "separation of reflectors and collectors"" "1317": "Light Probes: Why not separate the reflectors and collectors to begin with?" "1657": "Light Probes: Moving from our "fused" to their "separated" scheme" "1868": "Picking which probes to sample" "2081": "Naive probe sampling: 1. Grid lookup" "2156": "Naive probe sampling: 2. Linear search" "2340": "Plausible per-pixel probe sampling" "2720": "Eyeball our probe sampling requirements" "2844": "Closest probe, voxel lookup" "2947": "Disable lighting" "3097": "View our unlit world" "3249": "Make ComputeLightPropagation() build up lighting statistics" "3391": "Check out our lighting statistics" "3451": "Collect all lighting statistics in ComputeLightPropagation()" "3539": "Check out our lighting statistics, and estimate our improvements" "3679": "Introduce a light probe brain_type for GenerateRoom() to place on all non-wall tiles" "4195": "Introduce AddLightProbe()" "4358": "Do not see our light probes" "4371": "Enable UpdateAndRenderEntities() to draw our light probes, introducing IsLightProbe()" "4676": "Check out our light probes" "4698": "Make GenerateRoom() place the upper light probes slightly lower" "4714": "Check out our light probes" "4735": "Let UpdateAndRenderEntities() ignore Z-biasing for the light probes" "4752": "Check out our light probes down stairs" "4801": "Fix GenerateRoom() to place light probes correctly on stairwells" "4822": "Check out our light probes down stairs" "4874": "Make UpdateAndRenderEntities() count up the light probes" "5004": "Check out our LightProbeCount, compared with the PointCount of our existing solution" "5190": "Determine to build up our light probe voxel grid" "5475": "Create our voxel grid, introducing light_probe_spatial_index for the lighting_solution to contain" "5883": "Introduce AddProbeToSpatialIndex()" "5988": "Voxel sampling resolution" "6141": "Continue to sketch out AddProbeToSpatialIndex()" "6505": "Hierarchical sampling" "6614": "Q&A" "6644": "Q: How far along in the game are we? What percentage would you say?" "6742": "Q: Concerning picking lighting probes, could you use some sort of proximity hash (for lack of a better term), if there is such a thing? Something like where the key would be the location you want to select from. Ideally collisions would be physically close to each other in space? Or is there a reason why doing something like this would not be feasible? Although now that I think about it, what I'm describing sounds a lot like a 2D array" "6855": "Q: Have you thought about fully voxelizing the world and tracing rays in voxel space? Alternatively, what about selecting the probes using frustrum voxels like in Doom 2016?" "7000": "Q: Is it possible for you to share your theme color hex codes? I would like to use them on VSC" "7065": "Q: Will light probes only collect from hits to closest surfaces and as such would a three level setup per tile always leave the middle one never collecting any light? So now the two level is only for floor and ceiling?" "7084": "Q: Would you then consider handing the project over to a game designer to continue teaching the next parts?" "7197": "Q: Have you read the recent Morgan Mcguire Diffuse GI probe paper? Could come in handy for this!" "7220": "Q: Are entity component systems really a good way for an entity system? Jon has said that they are not really nice, but I wanted to know what you think about them, from an engine programmer's view. For me it looks like lots of wasted time" "7376": "Q: Can we do some AI programming for the NPCs, since you say we're almost done?" "7402": "Q: Do you use 4coder outside Handmade Hero?" "7528": "Q: Could you share the paper you mentioned about light probes?" "7603": "Q: Did you talk about Harvey Potter during pre-stream? Jon asked us to ask you about it…" "7615": "Q: You said that at a hit you will store the result in the closest probe. Would this not leave any probe that has no surface close completely black. Like a 3x3 probe grid per tile, the middle probe would never get picked. And in your two level system, the upper probes will only be picked for the ceiling and the lower ones for the floor (without considering walls)" "7649": "Q: Might you need extra reflectors for the sprites to get better collection around those areas?" "7656": "Q: Are 4coder source licenses available to the general public?" "7879": "Q: More Jeff and Casey Show episodes soon?" "7915": "Why only PayPal and credit card payment methods for Handmade Hero" "7925": "Q: What do you think about a purpose built editor, as opposed to a general purpose text editor. Could work directly with a binary format similar to any other content creation tool" "7942": "Bitcoin, of course" "7988": "Apple Pay" "8057": "Q: Why are you listed as rewind evangelist in Braid?" "8341": "Q: What mailing list?" "8352": "Q: That sounds like you wouldn't been a fan of the current Souls-like trend" "8523": "Wrap it up" --- name: "day548" title: "Voxelizing Light Probes" markers: "0": "Welcome to the show" "6": "handmade_hero What's a high-level language you find bit interesting?" "30": "Language Graph: Performance vs Speed of Development" "483": "Q: What place on this graph takes Jon's Jai?" "533": "Q: Where is lisp on that graph? Because you said it was interesting" "588": "Plug Guga Foods" "794": "Recap our switch to light probes and set the stage for the day" "1202": "Walk through our sketched out AddProbeToSpatialIndex()" "1289": "Sampling discontinuities across multiple voxels" "1517": "One light probe per voxel cell" "1686": "Smoothly sampling a moving light probe in 2D" "2024": "Fixing light probes at the centre of voxel cells" "2238": "Continue to implement AddProbeToSpatialIndex() with light probes positioned at the centre of voxel cells, introducing light_probe struct" "2669": "Introduce GetProbeLightingFor(), accumulating the lighting contribution of all eight corners of the voxel cell" "3423": "Introduce GetLightFromProbe()" "3569": "Blending two colour values using a normal" "3763": "Norms, or Normalised Values" "3930": "Blending two colour values using a 1-norm" "4113": "Implement GetLightFromProbe(), linearly blending the colours of voxel cell faces" "4233": "Sampling out of a cube" "4328": "Continue to implement GetLightFromProbe()" "4464": "Ways to optimise GetLightFromProbe()" "4617": "Introduce AccumulateProbe()" "4718": "Introduce GetCenterOf(), GetSpatialIndexAddress(), GetCornerLightIndex() and MapIntoGrid()" "5232": "Shifting and Powers" "5339": "Change GetCornerLightIndex() and GetSpatialIndexAddress() to use efficient shifting" "5523": "Implement MapIntoGrid(), introducing light_probe_spatial_index_mapping" "5820": "Switch gen_v3 over to be a v3s, introducing conversion functions" "6132": "Introduce GetProbeFromCell() and GetProbe(), and clean up compile errors" "6406": "Q&A" "6448": "Q: Concerning moving light probes, could you have special purpose light probes that only affect the lighting of certain things that move? So you would end up with things that move, and things that don't and most other probes in the lighting system would be unmoving. (And perhaps the moving probes could use some of the unmoving information, and the unmoving could could gradually sample from the moving.)" "6616": "Q: When and how often do we plan to compute the light probes?" "6693": "Q: How are square roots computed and how fast are they?" "7216": "Q: Is CRT dependency a Visual Studio feature only or do other compilers such as GCC and Clang have it too? Also, does the dependency include C++ or just C?" "7348": "Q: I didn't really see this pop up before, so: Do you think using Direct2D for a 2D game is a good idea if I want to implement it from scratch or would you rather use DX11/12 today?" "7383": "Q: You probably went over this last week, but how do you plan to make this faster than what we had before then?" "7433": "Q: Hey, I love the trick with the hot loading but having a hard time grasping the general idea. Could you make a kind of generic overlooking explanation, and would it work with a 3rd party library like SFMl?" "7565": "Targeting DX11, rather than DX12" "7777": "Q: Do you have an opinion on C callbacks and void* userdata? Do you know any alternatives? Do you have an opinion on GCC's "nested functions"?" "7815": "Q: I'm pretty early on in the stream, like 028, and the sound on my machine was scratchy. Do you end up making it use a separate thread to help clean it up, or did DirectSound get replaced?" "7959": "Q: About hot loading game code, is it a common thing between game programmers?" "8029": "Q: Hey, I'm way behind on Day 027, and for some reason StretchDIBits() has started failing after changing resolution to 960x540. I reverted to 1280x720 and now it still fails... Any quick ideas?" "8068": "Q: Would you recommend any free Windows debuggers?" "8250": "Q: Have you ever used Telemetry debugger?" "8276": "Q: When I look for ways of looking up the position of objects in a game, e.g. for raycasting, some sort of graph or tree is always presented as essential. Are there other ways of doing such lookups efficiently? It seems like an array sorted by the distance from the origin, and doing lookups in ranges" "8385": "Data breakpoints just got finished up today" "8432": "Q: How do you run the .bat compile code on other platforms?" "8448": "handmade_hero The other thing you can do in VS is have your debugger not work properly" "8467": "Q: About mip map generation, I was wondering why you decided to compute on CPU and not GPU. In addition, why did you decide to go with a simple box filter and not something smoother like a tent filter?" "8586": "Wrap it up" --- name: "day549" title: "Removing Old Lighting Lookups" markers: "1": "Recap our ongoing switch to light probes and set the stage for the day" "497": "Demo the currently unlit game" "546": "Disable ComputeLightPropagation()" "605": "Consult the profiler, to see that RenderGroundCover is our expensive routine" "694": "Gauge the expense of DrawGroundCover(), and note the potential for caching it" "883": "Note that we are not quite hitting 60FPS" "927": "Add a VSync toggle" "997": "Find that VSync toggling seems not to affect the frame rate" "1043": "Consult our VSync toggling code" "1076": "Break in to PlatformOpenGLSetVSync(), toggle VSync, but conclude that we always get VSync" "1262": "Consult the documentation on OpenGL's Swap Interval" "1329": "Create issue "Are we actually able to turn off VSync?"" "1393": "Determine to feed our new light probes through to the renderer" "1581": "Remove lighting_point_state from the entity struct, and TextureIndex from textured_vertex" "2356": "Remove LightIndex and FragLightIndex from CompileZBiasProgram()" "2462": "See that our textures are absent" "2510": "Reinstate TextureIndex in textured_vertex" "2722": "See that our textures are still absent" "2746": "Remove VertLightIndex from CompileZBiasProgram()" "2784": "See that our textures are still absent" "2786": "Remove VertLightIndex from opengl_program_common" "2845": "See that our textures are still absent" "2862": "Scan through the hardware renderer for texture index" "2940": "Let WriteQuad() and PushQuad() set the TextureIndex again" "3120": "See that our textures are back" "3244": "Plan to push light probes through to the renderer" "3488": "Remove LightIndex and Transparency from lighting_box" "4025": "Find that the game runs fine" "4087": "Enable PushCube() to push a lighting_box onto the lighting system, augmenting that structure with a TextureIndex" "4479": "Consider building into the ray tracing process the idea that every ray has a set destination to write to" "4606": "Consider blending the colours of each face of the lighting_box into one colour" "4781": "Toggle off all the surface colour computation in RayCast()" "5037": "Consider the necessity of breaking out early of the surface colour computation in RayCast()" "5443": "Toggle off the early-out code in RayCast()" "5631": "Set up to accelerate RayCast(), replacing BoxIndex and BoxSurfaceIndex with Normal in raycast_result" "6858": "Q&A" "6910": "Q: Do you have any tips for how someone would go about moving an existing codebase from OOP, assuming you're in control of it? By the way, thank you very much for the series. I'm learning so much, that $15 doesn't even begin to compare with the value you're providing. The fact the series is free is even more awesome" "7139": "Q: I'm only on episode 81 so excuse the noobiness: I've created different "modules" in my code that store different data for my entities (physics, render, AI, etc). Would it be silly to create an "anonymous" module type that union's these different modules into one generic struct? Meaning I can put them all into one array to pass around etc." "7341": "Q: It seems that tracing rays to collect light is a heavy operation. If ray tracing supported GPU hardware was common these days, would it be fair to say that you would prefer to move the lighting computation to the GPU entirely?" "7392": "Q: (Off-topic) Talking to graphics folks, it seems that shader permutation management is a real pain point. On the other hand, you have titles like Doom that use a significant small number of permutations and pipeline states. In a more complex 3D title, what’s your take on GPU complexity management? How will you design a solution that scales?" "7597": "Q: (Off-topic) Real production related question. In Handmade Hero, we have a general idea of how the game should look and feel like (mechanics, art direction, etc.). We’re tackling engine problems because they are interesting, and I’m very grateful for you doing it. How will the process of tackling things and “exploring” the engine design look like in a real production environment based on your experience? Say, maybe, based on your experience working on The Witness with Jon Blow?" "7700": "Q: Tips on reading academic papers about graphics and stuff? I always seem to get lost in their technical jargon and don’t really get anything out of them. A good example is your video about GJK vs the actual paper" "7757": "Wrap it up" --- name: "day550" title: "SIMD Raycast Point and Normal Computations" markers: "0": "Recap and set the stage for the day" "134": "Putting six-rayed light probes into the lighting system" "196": "Our old box-intersection testing in RayCast()" "294": "Our box lighting primitives" "420": "Our old box-intersection testing and reporting in RayCast(), continued" "631": "Ways of Getting Intersection Normals for AABB" "871": "Consider storing the BoxMin and BoxMax in lighting_box" "939": "Getting an Approximate Normal from an Ellipsoid-like AABB" "1130": "Getting Accurate AABB Intersection Normals" "1492": "Set up RayCast() to compute the intersection normal for a unit cube lighting_box" "1779": "Could we compute our intersection normal more efficiently?" "1946": "Consider the cost of our intersection normal computation in RayCast()" "2071": "Computing the intersection normal only of box hits, saving the box scale and centre" "2253": "Let RayCast() only set the box centre and scale, making ComputeLightPropagation() compute the intersection normal" "2417": "The cost and availability of _mm_blend_ps" "2665": "Make RayCast() select the RefColor and at the end compute the Result, augmenting raycast_result with P, Normal and RefColor" "3457": "Introduce SignBitFrom()" "3577": "Finish making RayCast() set the HitNormal from Masks" "4069": "Clean up compile errors, making RayCast() compute BoxRadius and its approximate inverse, introducing ApproxOneOver()" "4953": "Consider the potential speed improvement of RayCast()" "5019": "Determine to make ComputeLightPropagation() operate wide" "5092": "Lament SIMD's lack of fetching instructions" "5169": "Consider how to make our lighting operate wide" "5408": "Q&A" "5472": "Q: Origin, BoxCenter, and HitP are on the same line. Why do we use HitP – Center for the normal computation, and not Origin – Center? The direction should be the same. Problems could arise if origin is within the box (esp if origin = center), but I don't think that's a use case. I understand the HitP is useful for other purposes, just wondering if it's actually necessary for the normals computation" "5557": "Q: I've just added the C++ standard reference to the issue type-name member-name, issue. I agree it's a stupid warning, but there seems to be no way to disable it in GCC" "5586": "Ahh, thanks for explaining it once more. I get it now" "5722": "Q: Why are the light probes cubes and not spheres?" "5789": "Q: GCC is following the standard. It's just that the standard is stupid" "6333": "The good idea in C++ was "Let's start with C"" "6372": "Q: Should I work on a game engine in C / C++ or just put out games in Unity / Unreal until Jai comes out?" "6554": "Q: Is there any reading material you recommend for more serious real-time lighting like this (Papers, books, even blog posts etc.)? I've done simple diffuse lighting before but nothing beyond that" "6660": "The PBR book is good book" "6803": "What do you think is a good idea in games? I feel like I tune into so many programmer streams telling me this and that is terrible, but not really giving me another option. I don't want the answer to be "wait for Jai"! What is good today?" "6921": "Jai demo on Macros is in an hour and a half. Just a reminder for chat" "7013": "But it's pretty difficult to listen to you or Jon's stream when it's all just "this is bad, that is bad". But hey, maybe it's true?" "7082": "Shut down, with a plug of Jon's stream and Handmade Seattle" --- name: "day551" title: "Computing Probe to Probe Transmission" markers: "0": "Recap and set the stage for the day" "113": "Walk through the current state of our light probe implementation" "525": "Determine to perform probe to probe transmission" "674": "Switch ComputeLightPropagation() over from geometry-locked to probe-to-probe lighting propagation, with an eye on threading this routine" "1900": "Note the expense of ray casting and transference" "1986": "Implement probe-to-probe transference in ComputeLightPropagation(), initially in scalar" "3472": "Fix compile errors" "3928": "Consider how to store the AccumulatedPPS in lighting_solution, in a cache-friendly way" "4126": "Enable InitLighting() to reserve six times the space for each AccumulatedPPS" "4192": "Find that the game runs" "4241": "Delete stale data from lighting_solution" "4310": "Consider storing light boxes in a free-list" "4679": "Consider storing the light probes stably" "4722": "Augment raycast_result with an Emission for RayCast() and ComputeLightPropagation() to use" "4969": "Continue to delete stale data from lighting_solution" "5041": "Find that the game runs" "5076": "Q&A" "5085": "Rename some struct members to satisfy the C++ standard" "5387": "Close the "Linux Problems" issue" "5415": "Let me guess, this is about undefined behaviour?" "5619": "Q: How do you know if you wrote undefined behaviour code?" "5716": "Q: There is Clang's ub sanitizer" "5835": "Q: Which is the weirdest macro you had to make for some application? Have you ever gone to macro madness?" "5883": "Q: What's the full screen purple flash that happens in your editor sometimes?" "5917": "Q: Have you seen "The Grand C++ Error Explosion Competition"?" "5955": "Q: Did you enjoy it?" "6008": "Q: Did you enjoy Jon's macro video" "6027": "Q: Imagine a light probe that has no direct visibility to a red wall but it could reach it via one indirect bounce. I don't think the light probe will ever get any red contribution from that wall no matter how long you iterate, unless you cast secondary rays from surfaces" "6066": "Secondary Bounces" "6609": "Q: Yes" "6835": "I just checked Wikipedia, and apparently signed overflows are still undefined behaviour" "7010": "Thank you, everyone" "7151": "Edit the schedule, adding an episode on 24th August 2019 at 12:00PM PDT" "7298": "Until we next meet" --- name: "day552" title: "Generating Sampling Spheres into an INL" markers: "0": "Recap and set the stage for the day, with a plug of Daily MOBA Hero" "141": "Demo the presence of lighting probes in the world, with a view to colouring them" "375": "Set up to: 1) Plug together the light probes from the entity system and lighting system; 2) Insert the light probes into the spacial index; and 3) Build our directional sampling support structures" "492": "Check how light probes are stored in the 'Dynamic Diffuse Global Illumination with Ray-Traced Irradiance Fields' paper" "729": "Note the problem of sampling the corner of a cube" "886": "Sampling Contribution" "1162": "Enable ComputeLightPropagation() to perform a blended gather from all six sides of the cube, introducing light_sampling_sphere for lighting_solution to contain" "1700": "Note the problem that our LIGHTING_PATTERN_GENERATOR() generates hemispherical patterns" "1830": "Remove LIGHTING_PATTERN_GENERATOR() in favour of the lone GeneratePoissonSamples(), and make the latter generate samples around the entire sphere" "2286": "Consider how to produce a well-distributed spherical sampling pattern, e.g. using blue noise" "2396": "Create hhsphere.cpp to generate handmade_sampling_spheres.inl for handmade_lighting.h to include" "2645": "Spec out an example handmade_sampling_spheres.inl" "3008": "See that our light probes exist as usual" "3041": "Set up LightingTest() to draw our light probe sampling directions" "3440": "See our lone sampling direction" "3464": "Embark on the generation of handmade_sampling_spheres.inl, introducing OutputBlah()" "3892": "A few thoughts on spherical harmonics" "3943": "Finish up our initial handmade_sampling_spheres.inl generator, renaming OutputBlah() to OutputSphereINL()" "4282": "Invoke hhsphere and check out our handmade_sampling_spheres.inl" "4352": "Make GenerateLightingPattern() call GeneratePoissonSamples()" "4455": "Consider sampling slices of a blue-noise covered sphere" "4580": "Make GenerateLightingPattern() generate a white noise set of samples, from which each sphere is sliced randomly, introducing cube_store and sphere_store" "5288": "Enable OutputSphereINL() to output our generated spheres and main() to call GenerateLightingPattern()" "5681": "RemedyBG feature request: Take debugee-arguments on the command line" "5870": "Step through hhsphere to see what it generates" "6012": "Check out our generated handmade_sampling_spheres.inl" "6048": "Make OutputSphereINL() suffix float values with "f"" "6136": "See nothing new in the game" "6143": "Regenerate our handmade_sampling_spheres.inl" "6170": "Investigate the compile error in handmade_sampling_spheres.inl" "6864": "Make OutputSphereINL() surround the data with extra braces" "6891": "Regenerate our handmade_sampling_spheres.inl" "6933": "Investigate the compile error in handmade_sampling_spheres.inl" "7018": "Make OutputSphereINL() surround the data with extra braces" "7035": "Regenerate our handmade_sampling_spheres.inl" "7055": "Hit a "Too many braces" error" "7178": "Change OutputSphereINL() to generate the sampling directions as one huge array of floats" "7310": "Find that our flat array compiles okay" "7338": "Make OutputSphereINL() set the LightSamplingSphereFloatTable as global and 16-byte aligned, pointed to by our actual light_sampling_sphere data structure" "7572": "Regenerate our handmade_sampling_spheres.inl" "7583": "Check out our single sampling sphere" "7611": "Enable LightingTest() to use all of our generated spheres" "7683": "Check out all our (overlapping) spheres" "7686": "Make LightingTest() elevate the sphere" "7714": "Check out our sampling sphere" "7733": "Make LightingTest() elevate the sphere higher still" "7745": "Check out our floating sampling sphere" "7789": "Q&A" "7861": "Q: Have you considered using Julia language to do any sort of game development?" "7868": "Q: I am surprised the cast works as an initializer" "7918": "Q: Why does C++ suck so badly?" "7967": "Q: Can you replace __declspec(align) with C++11 alignas? Because non-Windows people won't have declspec. See example code here" "8041": "Q: What advice would you give Bjarne Stroustrup?" "8088": "Q: If you were to make this a more full 3D game (models, animations etc.) how would you go about modifying the renderer to support submission of these? Would you keep the single vertex buffer setup etc?" "8147": "Q: Sorry, I just logged in. What happened for you to turn on C++ so harshly?" "8169": "Q: Yes, you can put it before variable, not on struct" "8178": "Make OutputSphereINL() use alignas(16) on the LightSamplingSphereTable" "8223": "Q: Since we're asking off-topic questions, is SPIR-V in the direction of getting programmable ISAs for graphics hardware, or am I incorrect? Thoughts on SPIR-V in general?" "8333": "cmuratori I've sure you've been asked, but what do you think about Rust? If anyone in chat knows something for me to look at, a link would be helpful!" "8370": "Q: What happened to Shawn McGrath?" "8417": "Q: Can you build an entire game in a data-oriented mindset? Will it be a mess?" "8425": "Q: I'm a CS student and I want to learn about rigid body physics. It seems resources I find on the internet are very basic tutorials or advanced academic papers. Is there a resource I can use with a not as steep learning curve?" "8454": "Q: light_sampling_sphere has no padding then?" "8481": "Make OutputSphereINL() add Padding to light_sampling_sphere" "8847": "Regenerate handmade_sampling_spheres.inl and calculate our new light_sampling_sphere alignment" "8936": "Fix the Padding computation in OutputSphereINL()" "9000": "Regenerate handmade_sampling_spheres.inl to see our new light_sampling_sphere alignment" "9038": "Prevent OutputSphereINL() from outputting Padding if light_sampling_sphere is already aligned" "9109": "Regenerate handmade_sampling_spheres.inl to see our unpadded light_sampling_sphere" "9175": "cmuratori The one thing Rust has that makes it better than C++: no header files. That's enough right there" "9221": "Q: That learning curve seems to be the case with most complicated programming topics such as graphics. How did you learn these topics when you started out?" "9315": "Thanks for joining us" --- name: "day553" title: "Improved Sphere Distributions" markers: "1": "Recap and set the stage for the day" "87": "Address the "Sphere generator alignment" issue" "182": "Show off our white noise sampling sphere" "354": "Blue Noise Slices" "415": "White noise" "527": "Blue noise, or Poisson distribution" "648": "Blue noise as an approximation of real-world tree distributions" "919": "Blue noise as a limiter (or sampler) of workload, computing the average colour of an intractably huge image" "1181": "Structured–Unknown But Evenly-distributed sampling continuum" "1499": "Sphere Sampling" "1914": "Sphere Sampling Tuning vs Repulsion" "2133": "Sphere Sampling Slicing" "2247": "Make GenerateLightingPattern() apply repulsion to the white noise samples" "2954": "Distance-based repulsion around a sphere" "3040": "Continue to make GenerateLightingPattern() apply distance-based repulsion to the white noise samples" "3080": "Hard clipping in purely distance-based repulsion" "3158": "Continue to make GenerateLightingPattern() apply a smooth falloff to the repulsion" "3529": "Enable GenerateLightingPattern() to track the minimum and maximum distances between samples, to provide an exit condition" "3983": "Step through hhsphere" "4096": "Praise RemedyBG: The FLT_MAX display" "4137": "Continue to step through hhsphere" "4211": "Fix GenerateLightingPattern() to initialise LastMinClosestPointDistance as 0.0f" "4245": "Step through hhsphere and watch the closest point distances slowly converge" "4288": "Increase the MaxDispPerStep in GenerateLightingPattern() to speed up the convergence" "4322": "Step through hhsphere and see the closest point distances converge quickly" "4329": "Make GenerateLightingPattern() set the MaxDispPerStep based on MaxClosestPointDistance" "4469": "Step through hhsphere and watch the closest point distances converge" "4490": "Decrease the computed MaxDispPerStep in GenerateLightingPattern()" "4504": "Step through hhsphere and watch the closest point distances converge" "4577": "RemedyBG 0.2.8.1" "4592": "Copy handmade_sampling_spheres.inl in to place" "4681": "Check out our (identical) sampling sphere" "4800": "Again copy handmade_sampling_spheres.inl in to place" "4820": "Check out our wrong-looking sampling sphere" "4882": "Scrutinise our repulsion routine in GenerateLightingPattern()" "4950": "Prevent GenerateLightingPattern() from zeroing out the Displacement" "4991": "Continue to scrutinise our repulsion routine in GenerateLightingPattern()" "5036": "Repulsion around the great arc" "5128": "Continue to scrutinise and clean-up our repulsion routine in GenerateLightingPattern()" "5268": "Invoke hhsphere overwriting the real handmade_sampling_spheres.inl" "5354": "Make GenerateLightingPattern() print out the sampling directions" "5452": "Invoke hhsphere again and watch the distances converge" "5505": "Make GenerateLightingPattern() track the MinMaxSeparation and bail if it ever increases" "5614": "Step through GenerateLightingPattern() until the MinMaxSeparation increases" "5687": "Give GenerateLightingPattern() a more distant exit condition" "5704": "Invoke hhsphere and watch the distances converge" "5729": "Fix GenerateLightingPattern() to set the LastMinMaxSeparation in the correct place" "5738": "Invoke hhsphere and watch the distances supposedly converging" "5819": "Consider how to improve our sample repulsion" "5903": "Tangential repulsion" "5975": "Make GenerateLightingPattern() tangentially repulse the samples" "6017": "Invoke hhsphere and watch the distances converge" "6060": "Check out our (identical) sampling sphere" "6141": "Give GenerateLightingPattern() a yet further distant exit condition" "6160": "Invoke hhsphere and watch the distances converge" "6176": "Give GenerateLightingPattern() a yet further distant exit condition" "6183": "Invoke hhsphere and watch the distances converge" "6252": "Check out our sampling sphere to see that samples are clearly not equidistant" "6323": "Fix GenerateLightingPattern() to compute the ForceLineLength before the tangent" "6433": "Invoke hhsphere to see that it struggles to converge" "6502": "Decrease the MaxDispPerStep multiplier to 0.01f in GenerateLightingPattern()" "6512": "Invoke hhsphere to see that it seems to be converging more cleanly" "6624": "Increase the MaxDispPerStep multiplier to 0.025f in GenerateLightingPattern()" "6636": "Invoke hhsphere and watch the distances converge" "6719": "Increase the MaxDispPerStep multiplier to 0.05f in GenerateLightingPattern()" "6729": "Invoke hhsphere to see the distances start to oscillate" "6846": "Make GenerateLightingPattern() exit once the MinMaxSeparation is 0.02f" "6865": "Invoke hhsphere until the distances converge" "6898": "Check out our (still identical) sampling sphere, to determine that we are possibly measuring or writing out something incorrectly" "7110": "Q&A" "7134": "Q: You use two times the Min" "7141": "Fix typo in the MaxClosestPointDistance computation in GenerateLightingPattern()" "7154": "Invoke hhsphere to see the distances oscillate more wildly" "7194": "Decrease the MaxDispPerStep multiplier to 0.01f in GenerateLightingPattern()" "7211": "Invoke hhsphere and leave it hopefully converging" "7241": "Q: When will you start reading chat during the session?" "7335": "Gauge the convergence of our distances" "7363": "Q: Could you use a function like gravity and just sum up all the forces applied by all other points, where the force is proportional to the distance squared?" "7425": "Q: But it would remove the if statements, right" "7456": "Q: Is something like a golden spiral method too deterministic? I missed the beginning" "7513": "Q: Is there any save / load state of the entire game, e.g. for resume purposes? Serialization?" "7599": "Q: How do you measure stalls that happen on a particular memory load? Is it even a good metric to measure?" "7807": "Q: I only caught the end, so I may be misunderstanding. Won't the points get farther and farther from the sphere, since you only normalize at the end?" "7844": "Q: What spatial partitioning method would you use on this problem?" "7903": "Q: For a dedicated server using winsockets, how would you send the player data? Is like a JSON serialization possible or should I use other formats to send player / game state to all clients like every x ticks?" "8066": "Q: Converging to the situation where the closest point max and min distance are similar isn't something like trying to produce a regular solid polygon with N faces and than rotate it by arbitrary angles?" "8102": "Make GenerateLightingPattern() exit once the MinMaxSeparation is 0.03f" "8116": "Invoke hhsphere and leave it converging" "8216": "Q: On a shipping game you would hard-code the shaders in the game or have it in the asset file?" "8288": "handmade_hero Do you have projects that are voxel / octree-based?" "8301": "Q: So another possible implementation would be starting by a regular polygon distribution, and then apply an initial random displacement force and continue simulating, right?" "8315": "Check out our (identical) sampling sphere" "8383": "Read through our sampling sphere drawing code" "8474": "Consider whether we are seeing 1,000 points" "8508": "Invoke hhsphere to generate 1 batch of samples" "8592": "Make GenerateLightingPattern() exit once the MinMaxSeparation is 0.08f" "8623": "Check out our sparse samplingd sphere, to see 18 points (not the desired 4 × 18)" "8774": "Step in to LightingTest() to see that we have duplicated sampling points" "8856": "Force GenerateLightingPattern() to bundle up four consecutive sampling directions before incrementing past them" "8978": "Step in to LightingTest() to see that we now have non-duplicate sampling points" "9027": "Check out our more regular sampling sphere" "9043": "Add a TODO to determine what the real convergence criteria is" "9077": "Invoke hhsphere to generate our full 16 batches of samples" "9108": "Q: So maybe C++ was right" "9189": "Q: Maybe you can convince Jon to make arguments evaluate left to right in JAI" "9243": "Close the "Sphere generator alignment" issue" "9289": "handmade_hero Will you be in the JAI closed beta?" "9331": "Check out our beautiful new sampling sphere" "9473": "Q: As you decrease that magic number, does this method converge towards a uniform distribution?" "9517": "Wrap it up" --- name: "day554" title: "Reducing GPU Memory Footprint" markers: "2": "Update Milton and RemedyBG, with thanks to Ameen Sayegh for the Milton grid patch" "166": "Try out Milton's grids" "378": "Milton or tablet driver issue: Smoothing" "498": "Demo our lighting sampling sphere" "569": "Note the fast lighting computation" "755": "8-Wide Light Probes" "1335": "Plan to work on both the pixel shader and light propagation" "1446": "See stutter in our frame rate" "1555": "We've got an interloping puss" "1638": "Consider that we're using too much GPU memory" "1722": "Calculate our GPU memory requirements" "1911": "Crash Nsight upon launching Handmade Hero" "2015": "Add a new Nsight project for Handmade Hero" "2113": "Crash Nsight upon launching Handmade Hero" "2196": "Install RenderDoc and configure it for Handmade Hero" "2426": "Crash RenderDoc upon launching Handmade Hero" "2496": "cloc Handmade Hero: 32,936 lines" "2604": "Remove the light_buffer array from open_gl" "2861": "Find that there is no change" "2871": "Track the frame buffer memory usage in FreeFramebuffer() and CreateFramebuffer()" "3461": "Find that we may get a faster frame rate with V-Sync disabled" "3493": "Add a "Renderer" DEBUG_DATA_BLOCK in WinMainCRTStartup() for the framebuffer and texture memory" "3898": "Enable the debug system to handle umm type" "4077": "Find that we have a TotalFramebufferMemory of 3GB" "4102": "Add UsedMultisampleCount to the "Renderer" DEBUG_DATA_BLOCK in WinMainCRTStartup()" "4248": "Find that our UsedMultisampleCount is 16, and calculate the memory requirements as 2.47GB" "4394": "Consider memory usage improvements: Only store one depth buffer" "4739": "Consider memory usage improvements: Streamline the colour buffer" "4982": "Consider rendering solid cubes into a single multisampling buffer with depth peeling disabled, resolve and composite this with our alpha items" "5415": "Consider depth peeling in only two buffers" "5786": "Spot our DepthPeelResolveBuffer, and make OpenGLEndFrame() use a single depth peel buffer" "5961": "Find that we render just fine in one DepthPeelBuffer" "6011": "Shrink open_gl down to only contain one DepthPeelBuffer" "6135": "Find that we render correctly and have a TotalFramebufferMemory of 2GB" "6196": "Step in to CreateFramebuffer() and watch the memory usage" "6360": "Add a new Nsight project for Handmade Hero using the correct Working Directory" "6411": "Run successfully in Nsight" "6487": "Continue to step through CreateFramebuffer() and spot that we're multiplying the MaxMultiSampleCount into the GPUMemoryUsed even when multisampling is disabled" "6533": "Fix CreateFramebuffer() to multiply the correct SampleCount into the GPUMemoryUsed" "6584": "Step through CreateFramebuffer() to see that our GPUMemoryUsed is actually okay" "6955": "Find that we have a TotalFramebufferMemory of 325MB" "7066": "Nsight rendering time: 14ms / frame" "7118": "Permit NVIDIA GPU performance counters" "7269": "Capture for Live Analysis in Nsight, and look for a combined memory count" "7659": "Nsight: Range Profiler View" "8097": "Reflect on our peel buffer memory usage reduction, and plan to pseudo-simulate the light probes" "8189": "Try disabling V-Sync and multisampling, to find that the latter fails" "8237": "Plan to fix the multisampling read" --- name: "day555" title: "Looking for GPU Performance Issues" markers: "2": "Welcome to the stream" "14": "A few words on RenderDoc's crash message yesterday, with praise for their tech support, and plans to enable the game to fail gracefully when launched with incorrect parameters" "228": "Launch Handmade Hero in RenderDoc" "253": "Set the wrong Working Directory in RenderDoc" "274": "Crash RenderDoc upon launching Handmade Hero" "372": "Launch Handmade Hero in RemedyBG with the Working Directory set wrong" "435": "Hit our assertion in GetFontInfo()" "459": "Make GetFontInfo() additionally assert that the Asset's Type is HHAAsset_None" "514": "Hit our TextureIndex assertion in PushQuad()" "595": "Enable all our asset Get*() functions to handle the absence of assets" "1003": "Run successfully with our incorrect Working Directory" "1033": "Enable AllocateGameAssets() to issue a warning notification when no assets were available" "1397": "Crash RemedyBG apparently on a jump-to-zero" "1438": "Create jump_to_zero_crash.cpp" "1507": "Run jump_to_zero to find that RemedyBG is fine with it" "1548": "Run Handmade Hero successfully with our new warning code" "1598": "Introduce Win32ErrorMessage()" "1711": "Run and close cleanly" "1724": "Make Win32ErrorMessage() print out an error message" "2056": "Run and close with our warning box" "2079": "Fix the MBoxType in Win32ErrorMessage()" "2146": "Run and close with our warning box" "2151": "Temporarily try making AllocateGameAssets() produce a Fatal error" "2177": "Run and close with our error box" "2189": "Make WinMainCRTStartup() emit errors using Win32ErrorMessage()" "2338": "Run and close with our warning box" "2346": "Run unsuccessfully with the correct Working Directory" "2476": "We've got a saucy bean" "2532": "Fix GetBitmap() to correctly set the TextureHandle" "2625": "Run successfully" "2642": "Run in RenderDoc with the wrong Working Directory" "2665": "Crash RenderDoc post-exit" "2740": "Run in RenderDoc with the correct Working Directory, noting that we sometimes miss 60 FPS" "2814": "Capture a frame in RenderDoc and see that it took 35590 µs" "2928": "Look at our four Colour Passes, and plan to submit vertices economically" "3097": "Make OpenGLInit() disable RequestVSync" "3160": "Find that our frame time hovers around 14 ms per frame" "3207": "Reacquaint ourselves with our render dispatch in OpenGLEndFrame()" "3331": "Understanding glMapBuffer()" "3477": "Nsight rendering time: 14ms to 18ms / frame" "3577": "Scrub through Events to see that glDrawArrays takes 1.27ms" "3635": "Scrutinise ResolveMultisample() with a view to speeding it up" "3900": "Make CompileResolveMultisample() bake the SampleCount in to the shader, to hopefully permit the loop to be unrolled" "4083": "Find that it actually works" "4099": "Make CompileResolveMultisample() bake InvSampleCount in to the shader, and slightly reorganise it" "4355": "Find that that made no difference to the frame time, and that UpdateAndRenderEntities() takes a while" "4444": "Temporarily Disable DrawGroundCover()" "4477": "Find that Game Update takes less of the total time, but we are not hitting 60 FPS" "4631": "Disable HANDMADE_SLOW" "4703": "Find that Debug Collation takes a lot of the total time" "4726": "Compile out some of the debug system if HANDMADE_SLOW is off" "4843": "See the debug UI" "4867": "Instead compile out that part of the debug system if HANDMADE_SLOW is on, and rearrange the code to fix compile errors" "5013": "Find that lots of the debug system is absent" "5046": "Compile out timing if HANDMADE_SLOW is off" "5105": "Still see jerkiness with debug collation off" "5169": "Compile in our frame marker in all situations" "5205": "See that our frame time is well below 16ms, but we are not actually seeing 60 FPS" "5242": "Nsight rendering time: 10ms to 14ms / frame" "5347": "Capture a frame in Nsight to see that glDrawArrays remains by far the most expensive call" "5627": "Hard set SampleCount to 1 in CompileResolveMultisample()" "5684": "Nsight rendering time: 4ms / frame" "5703": "Capture a frame in Nsight to find that the resolve and draw calls take similar times" "5769": "Understanding multisampling" "5867": "See our crispy lines, without multisampling" "5911": "Research multisampling in GLSL" "6342": "Spec out our desired fast path in CompileResolveMultisample(), based on there being only one sample in a multisample" "6480": "See nothing" "6484": "Revert CompileResolveMultisample()" "6608": "See everything" "6610": "Spec out our desired fast path in CompileResolveMultisample() again" "6700": "See nothing" "6712": "Cut out the else and the if(1) in CompileResolveMultisample()" "6761": "Find that the if(1) was the problem, somehow" "6788": "Reinsert the if(1) in CompileResolveMultisample()" "6810": "Capture a frame in Nsight, but still see no error message" "6924": "Enable HANDMADE_SLOW" "6946": "Trigger a fragment shader error: implicit cast from "int" to "bool"" "6981": "Change the if(1) to if(true) in CompileResolveMultisample()" "7040": "See our standard output" "7049": "Trigger our non-multisampled fast path in CompileResolveMultisample()" "7054": "See our crispy edges" "7067": "Make a note to ask GPU people about our fast path" "7108": "Q&A" "7153": "Q: textureSamples(sampler)?" "7227": "Q: You can have Windows automatically capture crash dumps for you. Check if this key exists: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps and, if so, it will automatically capture dumps to %LOCALAPPDATA%\CrashDumps. You can read more" "7427": "Q: The Watch page has no more scheduled appearances. When will you be streaming next?" "7454": "Q: You should switch to Linux" "7541": "Q: Someone had asked whether or not that would optimize anything since the GPU has to execute both branches" "7654": "Q: I’m not sure if you were joking when you said to ask, but if you have the time and feel like it I would 100% be down to see lectures from you about the rest of the animation system like you did with skinning" "7766": "Q: I think that putting it under "Chat" made it less clickable. Also, flashy thumbnails are really important" "7880": "Q: My girlfriend watches and tells you most of the things you said about Linux are old school issues" "8173": "I have an Arch Linux machine. Its dependencies are now broken and will take weeks to get working again" "8317": "Q: Casey please dispel the myth that molly123 and I are the same person. rupan3 has a crazy conspiracy going on I can't shake" "8341": "Q: For what reason do you like Linux if it breaks all the time?" "8592": "Wrap it up" --- name: "day556" title: "Optimizing Depth Peeling and Multisample Resolves" markers: "2": "Plug Molly Rocket's Discord channel" "104": "Recap and set the stage for the day with praise for RenderDoc" "195": "Note that lots of our time is spent doing the multisample resolve" "452": "Configure our project in RenderDoc" "522": "Capture a frame in RenderDoc and consult the event timings to see that the multisample buffer took 10 times longer to resolve than to draw" "654": "The possible bandwidth cost of resolving our multisample buffer" "856": "Our best case solution: Resolve the multisample buffer independently of the depth peel" "989": "Demo Milton's new grid feature, but its smoothing bug" "1052": "Rendering requirements of Sprites vs Geometry" "1216": "Demo some undesirable alpha blending when traversing stairs" "1335": "Consider two multisample resolves to may be necessary" "1440": "Plan to render the sprites with depth peel in a separate pass, then composite in the geometry with two multisample resolves" "1817": "Segregating our sprites and geometry into separate buffers" "2008": "Hesitate to impose this separation requirement on the renderer" "2131": "Producing a separate multisample buffer of the edge information" "2212": "The edge information in question" "2333": "Using conservative rasterization to enable recovery of our edge blend from a single high- / low-coverage multisample resolve" "2628": "Using conservative rasterization just to tell us how much a pixel is covered by a primitive" "2728": "Research conservative rasterization" "2954": "Hunt for a coverage-to-alpha function, in NV_shading_rate_image, ARB_sample_locations and ARB_sample_shading" "3493": "Find that conservative rasterization is not widely available" "3550": "Consider running the multisample routine without a multisample buffer, only recording which samples were covered" "3940": "Consider attaching a multisample and non-multisample render target at the same time" "4025": "Consult glext.h for coverage-related functions" "4285": "Research NV_fragment_coverage_to_color" "4451": "Research ARB_post_depth_coverage and gl_SampleMaskIn" "4673": "NVIDIA request: When enabling conservative rasterization, let us set the SampleMask to the number of samples we want" "4748": "Lament the tremendous amount of bandwidth required to smooth out our edges" "4836": "Reflect on the need for the multisample buffer to tell if primitives are coplanar" "4900": "Consider augmenting our Colour Pass shader to skip pixels whose prior pass produced a fully opaque pixel" "5290": "Make CompileResolveMultisample() set the gl_FragDepth of opaque pixels to 1.0f, enabling CompileZBiasProgram() to discard obscured pixels" "5784": "Capture a frame to see that depth sorting is still working, and our Colour Passes are now more efficient" "5908": "Switch to the non-multisampling fast path in CompileResolveMultisample()" "5990": "Capture a frame to see that our glDrawArrays() calls have sped up" "6061": "Options for creating our fast path in CompileResolveMultisample(): 1. Read from the previous depth peel and do not resolve opaque pixels; 2. Resolve into a separate "blend" buffer" "6210": "Make CompileResolveMultisample() only blend non-opaque pixels" "6282": "Reacquaint ourselves with the final CompilePeelComposite() with a view to instead accumulating the colour as we go" "6399": "Introduce a MaskSampler in CompileResolveMultisample() to contain the opacity" "6529": "Crash the game under RenderDoc" "6551": "Hit a shader error "unable to find overloaded function texelFetch()"" "6585": "Fix CompileResolveMultisample() to fetch the Mask's texel from the 0th texture" "6624": "See that the multisampling is a little busted" "6661": "Just let CompileResolveMultisample() always blend, including some shader parser mayhem" "6796": "See that the multisampled artefacts are gone" "6822": "Make CompileResolveMultisample() initialise the samplers in the order in which they are passed to OpenGLLinkSamplers()" "7016": "Make OpenGLEndFrame() set the Mask for CompileResolveMultisample() to acquire pixel opacity, introducing a SinglePixelAllZeroesTexture" "7625": "See a few multisampling artefacts in there" "7688": "Quickly scrutinise our new Mask code" "7758": "Capture a frame to see that our second and fourth Colour Passes are not as expected" "7801": "Check the Mask test in CompileResolveMultisample()" "7860": "Take a close look at our first glDrawArrays() call, to see that our MaskSampler is 0×0 pixels" "7977": "Fix OpenGLInit() to correctly bind our SinglePixelAllZeroesTexture" "7999": "Capture a frame to see that our third Colour Pass drew much more than expected" "8129": "Make CompileResolveMultisample() set gl_FragDepth of opaque pixels" "8206": "Crash in RenderDoc" "8231": "Make CompileResolveMultisample() set BlendUnitColor of opaque pixels" "8256": "Battle with the shader parser" "8476": "Prevent CompileResolveMultisample() from setting the BlendUnitColor of opaque pixels" "8499": "Capture a frame to see that we are still busted" "8671": "Make CompileResolveMultisample() always blend" "8680": "Find that the shader parser is unhappy, and wonder if it's a problem with 4coder's virtual whitespace" "8714": "Revert CompileResolveMultisample() to a supposedly working state" "8748": "Find that the shader parser continues to be unhappy" "8808": "Change all the comments in CompileResolveMultisample() to be C-style ones" "8843": "Find that that doesn't solve the problem" "8880": "See how RemedyBG sees the code in CompileResolveMultisample()" "9006": "Trim out some possibly problematic code from CompileResolveMultisample()" "9018": "Find that the shader parser is happy now" "9035": "Make CompileResolveMultisample() set the Mask to 0.0" "9068": "Find that the shader parser remains happy, but we still see our multisampling artefact" "9083": "Make CompileResolveMultisample() always blend" "9093": "See our multisampling artefact" "9129": "Leave in our fast path in CompileResolveMultisample()" "9153": "See new artefacts" "9172": "Make CompileResolveMultisample() always blend" "9185": "See that everything looks nice and smooth" "9233": "Reinsert our fast path in CompileResolveMultisample()" "9246": "See new MIP map anisotropic filtering artefacts" "9284": "Capture a frame to see that our third and fourth Colour Passes are not as free as expected" "9311": "Fix CompileResolveMultisample() to black out the BlendUnitColor of opaque pixels" "9376": "Capture a frame to see that our Colour Passes are way more efficient" "9511": "Q&A" "9518": "Q: Are you exceeding the size of your buffer for the shader code text? The EOF error seems kind of suspicious" "9530": "Make CompileResolveMultisample() record the shader string BufferSize" "9582": "See that the shader string is 3877 characters" "9599": "Increase the FragmentCode buffer size from 4096 to 16000" "9664": "Find that the shader parser is happy, with a few words on tooling" "9813": "Q: Couldn't you just not define the dimension and let the compiler figure out the size?" "9850": "Q: Why can’t you just run the preprocessor on the shaders, though?" "10013": "Q: Do you have any concept of like a string builder that you could use with your format string function to have it pass you back a string allocated from temp memory? It's a small thing, but you won't need to think / worry about that anymore" "10086": "Q: I think that Dual Depth Peeling. This paper may be able to help you out, because I looked at their OpenGL code and it seems possible to resolve only once when you render to the screen. You can download the code and see. I am not sure. It is pure OpenGL. They have not enabled multisampling, however I think it is possible to work" "10400": "Q: Have you considered using RenderDoc directly to recompile the shaders at runtime during rapid development?" "10480": "Q: Hi Casey, some episodes ago you said you didn't understand why Jon credited you on Braid, since you didn't do any work on it. But you wrote the collision detector, right? Maybe I misunderstood and it was about the rewind only" "10748": "Q: How you would implement in debug systems the way of changing also v3 / v4, values?" "10796": "Q: I just watched the video about sub-pixel sampling for pixel art assets. Thank you for explaining it, was really good. I have two related questions, though: 1) When you viewed the sprite sheet you noticed that it’s not alpha pre-multiplied and kind of mentioned that it might be a problem. I was wondering why. 2) You mentioned that they don’t use MIP maps and that got me thinking… How should we produce MIPs for pixel art assets? Box-filtering would not work since that’s made for bilinear" "10964": "Q: 1) You're right. But I think Unity's shaders were set up for point sampling" "11027": "Q: And thank you very much for the skin mesh video. I still have to watch it" "11040": "Time for bed, with a plug of Molly Rocket's Discord channel" --- name: "day557" title: "Basic Dynamic Quad Output Optimizations" markers: "0": "Plug Molly Rocket's Discord channel" "123": "Recap our multisampling improvements" "251": "A few words on deferred rendering" "430": "Lessening the bandwidth requirements of the lighting" "518": "Determine to optimise our ground cover output" "579": "Check out our time per frame: 10ms" "676": "Reacquaint ourselves with DrawGroundCover()" "737": "Enable DrawGroundCover()" "744": "RenderGroundCover took 0.3%, and now takes 17% of our frame time" "815": "Hit our MaxVertexCount assertion" "845": "Increase MaxQuadCountPerFrame fourfold" "892": "Again consult the Frames breakdown and hit our MaxVertexCount assertion" "982": "Remove entity timing blocks" "1032": "Again consult the Frames breakdown and hit our MaxVertexCount assertion" "1130": "Investigate why we are hitting the MaxVertexCount" "1224": "Stop GetBestMatchAssetFrom() being a TIMED_FUNCTION" "1300": "Consult the Frames breakdown without hitting our MaxVertexCount assertion" "1346": "Rather than timing UpdateAndRenderEntities() entirely, just time DrawGroundCover" "1458": "DrawGroundCover takes 26% of our frame time" "1492": "Capture a frame to see that the GPU is not struggling to render our ground cover" "1593": "Plan to time DrawGroundCover(), and maybe cache PushQuad()" "1774": "Time the "Computation" code in DrawGroundCover()" "1840": "DrawGroundCover takes 4% and the Computation takes 19% of our frame time" "1891": "Endeavour to speed up our DrawGroundCover Computation, using caching" "2192": "Rework ground_cover to facilitate faster ground cover generation" "2395": "Enable DrawGroundCover() to operate on cached quads, calling OutputQuads()" "2741": "The freeness of the CPU moving a value into a destination + offset vs incrementing the destination itself" "3058": "Make DrawGroundCover() call explicitly indexed VertexOut() and IndexOut()" "3217": "Make DrawGroundCover() acquire the TextureIndex, and relieve it of getting the bitmap info" "3384": "Make FillUnpackedEntity() get the bitmap info, introducing v4 and v3 versions of FinalizeColor()" "3714": "Clean up PushSprite()" "3735": "Consider making PushSprite() work with pre-calculated values" "3911": "Make FillUnpackedEntity() compute the ground cover's P and UV values previously done by PushSprite() and PushQuad(), introducing GetUVScaleForBitmap(), GetUVScaleForRegularTexture() and GetUVScaleForSpecialTexture()" "4707": "Consider why SpriteValuesForUpright() problematically takes a RenderGroup" "4821": "Introduce a version of SpriteValuesForUpright() that takes a WorldUp, CameraUp and XAxisH, instead of a RenderGroup, for FillUnpackedEntity() to call" "5160": "Introduce indexed_vertex_output, OutputQuads(), VertexOut(), QuadIndexOut() and a version of Advance that takes an indexed_vertex_output" "6450": "Hit our assertion in the SafeTruncateToU16() call in OutputQuads()" "6489": "Let OutputQuads() early-out if the VertexCount and IndexCount are both 0" "6532": "Again hit our assertion in the SafeTruncateToU16() call in OutputQuads(), and investigate why" "6764": "Understanding the batch-fitting check in GetCurrentQuads()" "6836": "Step in to OutputQuads() to see a QuadCount of 7670, which suggests we should have sunk fewer than 65752 vertices" "6891": "Scrutinise the indexed_vertex_output versions of Advance(), and OutputQuads() and DrawGroundCover()" "7053": "Fix DrawGroundCover() to Advance() by 1 quad" "7069": "Again hit our assertion in the SafeTruncateToU16() call in OutputQuads(), and investigate why" "7169": "Step through OutputQuads() successfully for a while, concluding that it and GetCurrentQuads() may not be agreeing" "7303": "Fix OutputQuads() to increment the QuadCount" "7386": "Find that we are running okay, but not seeing the expected ground cover" "7408": "Step in to DrawGroundCover() and inspect its values" "7538": "Fix FillUnpackedEntity() to set the ground cover's correct P values" "7588": "See our ground cover, just with an incorrect camera up vector" "7612": "DrawGroundCover takes 12% of our frame time" "7676": "Step it to UpdateAndRenderWorld() to get the camera's up vector" "7746": "Fix the DEFAULT_CAMERA_UP" "7771": "See that our ground cover is sheared" "7803": "Try to fix the winding in QuadIndexOut()" "7841": "See that our ground cover remains wrong" "7851": "Scrutinise QuadIndexOut(), and wonder if a P value is wrong" "7928": "Fix FillUnpackedEntity() to set the ground cover's correct P[3]" "7936": "Admire our more performant ground cover" "8005": "Q&A" "8040": "Q: Should OutputQuads() (line ~1078) use a '&&' rather than '||' to check that both vertex / index counts are nonzero?" "8111": "Q: So next step to optimize that is to do instancing rendering for the ground cover?" "8267": "Q: Maybe it would be easier to do the upright sprite calculaiton in the vertex shader instead?" "8323": "Q: Speaking of getting the compiler to output the right instructions, I have been toying with a lower level 'language' (assembly without the friction really). Would love to hear your thoughts (super simple example)" "8613": "Q: Do you ever feel like the verbosity of passing around an often-used pointer like game_assets in Handmade Hero is too much hassle or do you find it's more beneficial in the long run over a global?" "8787": "Q: I think you might have missed pragma's question above? Or maybe I missed the answer?" "8792": "Q: How would you go about breakable surfaces, not like in a voxel style?" "9167": "Q: Early in the series, you said you wanted to try to make your own math functions. Have you gotten around to doing that yet?" "9229": "Wrap it up with a plug of Molly Rocket's Discord channel and glimpse into the future of lighting" --- name: "day558" title: "Assigning Lighting Probe Slots" markers: "0": "Plug Molly Rocket's Discord channel" "110": "Demo our more performant ground cover" "185": "Determine to send down lighting probe information, initially gauging the performance of the sampling" "412": "Plan to sample pre-fabricated lighting" "603": "Make UpdateAndRenderEntities() draw the light probes as white cubes" "614": "See our pure white probes" "628": "Wonder if lighting is enabled" "668": "Set up to send lighting information to our perfect reflectors" "756": "Modify lighting_textures for our light probe-based solution, including a voxel lookup" "1140": "Estimate the number of visible light probes" "1165": "Augment lighting_textures with a 128³ LightVoxelIndex" "1384": "Determine to switch the lighting solution away from a push-forward scheme, to a static buffer" "1545": "Augment game_render_commands with LightProbe data, subsuming lighting_textures" "1709": "Remove PushLighting() and OutputLightingPoints()" "1908": "Crash on the GetCenter() call in BuildSpatialPartitionForLighting()" "1930": "Recall what LightingTest() does with the Solution" "2010": "Crash again on the GetCenter() call in BuildSpatialPartitionForLighting()" "2020": "Recall that PushLighting() used to help set up the RootBox" "2087": "Step in to LightingTest() to see that the LightBoxes are not allocated" "2141": "Introduce BeginLightingComputation() and rename LightingTest() to EndLightingComputation() for UpdateAndRenderWorld() to call" "2486": "Keep open the possibility of making a hardware-based ray tracing solution" "2557": "Augment game_render_commands with a buffer of lighting_box LightOccluders, and remove LightBox and LightPoint data from render_group" "2788": "Switch PushCube() and EndLightingComputation() over to use our modified data structures" "3103": "Crash again on the GetCenter() call in BuildSpatialPartitionForLighting()" "3147": "Begin to make OpenGLInit() allocate our Light buffers" "3287": "Hunt in vain for a main memory allocator in the renderer" "3420": "Augment open_gl with static Light arrays" "3539": "Make OpenGLBeginFrame() initialise the Light arrays" "3733": "Our GetCenter() crash is resolved" "3759": "Make BeginLightingComputation() call EnableLighting()" "3963": "EndLightingComputation takes 14% of our 41ms frame time" "3992": "Set up to fill out our light probes" "4077": "Change UpdateAndRenderEntities() to push our real LightProbeCount onto the debug system, and perform DrawGroundCover() in the main entity loop" "4187": "Consider making the light probes persist stably across frames" "4332": "Light probe persistence 1: Locating light probe information according to its index in the entity active set" "4586": "Light probe persistence 2: Keeping a separate list for light probe indices" "4712": "Reacquaint ourselves with the entity registration code" "4804": "Augment the world with a LightProbeSlots free list" "5024": "Augment entity with a LightProbeIndex and make CreateWorld() initialise our light probe free list" "5256": "Consider where the light probe free list should live" "5395": "Introduce AssignIndices() and RemoveIndices() for EnsureRegionIsUnpacked() to call" "5666": "cmuratori You might want to ban the person spamming Twitch chat with stupid crap" "5716": "Encourage people not to use Twitch chat" "5808": "Subscriber only chat" "5839": "Finish implementing RemoveIndices() and augment entity with a LightProbeClear for FillUnpackedEntity() and UpdateAndRenderEntities() to use" "6082": "The purpose of clearing light probe slots" "6169": "Address Discord spam" "6452": "Fix up compile errors, passing the MaxLightProbeCount down to CreateWorld()" "6717": "Hit our IsLightProbe() assertion in UpdateAndRenderEntities()" "6754": "Prevent EnsureRegionIsUnpacked() from calling RemoveIndices(), deleting that function and instead making PackEntity() perform its code" "6871": "Again hit our IsLightProbe() assertion in UpdateAndRenderEntities()" "6919": "Ensure that the UnpackedEntities buffer begins cleared" "6976": "Assert in PackEntity() that LightProbeIndex is 0 for non-light probe entities" "6999": "Assert in AssignIndices() that LightProbeIndex is 0" "7034": "Hit our new assertion in AssignIndices()" "7089": "Assert in ClearUnpackedEntityCache() that LightProbeIndex is 0, after calling PackEntity()" "7115": "Hit our new assertion in AssignIndices(), to see also that LightProbeClear is 1" "7138": "Investigate why we are trying to assign an index to an entity that already has one" "7240": "Reintroduce RemoveIndices() for PackEntity() and EnsureRegionIsUnpacked() to call" "7315": "Again hit our assertion in AssignIndices()" "7486": "Q&A" "7625": "Q: Off-topic: How do you parallelize hash functions?" "7807": "Q: How is a hash function like the meowhash useful for game development?" "7849": "Q: This is sorta off-topic so if you don't think it's relevant, feel free to disregard. With member functions they're namespaced based on the type, whereas with free functions they're all in the same namespace unless you specifically namespace. (Of course what the compiler generates is identical.) Since you don't use explicit C++ namespaces, as far as I know, do you think this is a problem and, if so, how do you work around it?" "7886": "Q: Hi Casey, I've missed most of the last few streams. Could you run the game quickly so I can see where we're at?" "7912": "Why not follower only chat?" "8041": "Q: You could do a 1-day follower limit, or something large" "8082": "Q: Since we're going off-topic: I was looking at DPI-aware UI and rendering and it seems annoying in win32. I'm usually many years behind trends, so is high-DPI rendering a thing to worry about these days?" "8153": "Close things down" --- name: "day559" title: "Experimenting with Fragment Light Sampling" markers: "0": "Plug Molly Rocket's Discord channel and note that the twitch player on the Watch Page is broken" "79": "Recap and set the stage for the day, initially fixing a bug in assigning light probe indices" "307": "Hit our assertion in AssignIndices()" "585": "Add a "conditional break point" in AssignIndices() and RemoveIndices() when the LightProbeIndex is 101" "719": "Break in to AssignIndices() and RemoveIndices() for LightProbeIndex 101" "958": "Scrutinise EnsureRegionIsUnpacked()" "1019": "Add an assertion in EnsureRegionIsUnpacked() that LightProbeIndex is 0" "1033": "Break in to AssignIndices() for LightProbeIndex 101, and fail to hit our new assertion in EnsureRegionIsUnpacked()" "1114": "Add an assertion in AcquireUnpackedEntitySlot() that LightProbeIndex is 0" "1166": "Break in to AssignIndices() for LightProbeIndex 101, and successfully hit our new assertion in AcquireUnpackedEntitySlot()" "1239": "Realise that we never clear the Entity data when removing from unpacked" "1314": "Fix EnsureRegionIsUnpacked() to clear stale data when unpacking entities" "1372": "Hit our assertion in AcquireUnpackedEntitySlot()" "1392": "Remove our assertion from AcquireUnpackedEntitySlot()" "1409": "We have solved that light probe index assigning bug" "1429": "Make UpdateAndRenderEntities() colour the light probes by their index" "1469": "Our light probes remain stably indexed" "1561": "Storing light probe positions" "1684": "Augment game_render_commands with a LightProbePosition buffer, introducing SetLightProbePosition() for UpdateAndRenderEntities() to call" "1950": "Implement SetLightProbePosition()" "2280": "Wonder if we should treat light probes as points and directions, rather than cubes" "2318": "Introduce light_probe_irradiance for game_render_commands and open_gl to contain" "2411": "Consider converting the light_probe_spatial_index to use our voxel" "2473": "Crash in SetLightProbePosition()" "2490": "Augment open_gl with a LightProbePosition array for OpenGLBeginFrame() to populate" "2558": "Our SetLightProbePosition() crash is fixed" "2610": "Sampling light probes" "3106": "Enable lighting in CompileZBiasProgram()" "3200": "Calculate our light probe bandwidth requirements (22 GB/sec)" "3525": "Note that we only need to sample one face of a light probe, requiring 3 GB/sec" "3757": "Consider sampling our light probes as a 2D texture: light probe count × direction" "3833": "Consider sampling our light probes as a cube map" "4067": "Make CompileZBiasProgram() sample the light probes as a 2D texture" "5827": "Consider instead sampling our light probes as a cube map" "6143": "Begin to prepare CompileZBiasProgram() to sample our light probes as a cube map" "6201": "Continue to consider sampling our light probes as a cube map" "6505": "Lighting Atlas" "6749": "Blending the eight octants of a cube" "7035": "Disable lighting in CompileZBiasProgram()" "7052": "One last view of the game" "7061": "Q&A" "7093": "cmuratori Would you want to do a debug Milton stream?" "7170": "Q: Does this still work on XP?" "7261": "Q: If you had to draw text in Arabic, Chinese, Korean, etc in a game, how would you do text shaping?" "7332": "Q: Would it make sense to store the whole cube of voxels as six 3D textures, one for each direction, and then use hardware trilinear filtering?" "7472": "Q: Would you overestimate side F on the cube map?" "7528": "Wind it down" --- name: "day560" title: "Querying Irradiance Directly from Voxels" markers: "1": "We are working on lighting" "41": "Plug Molly Rocket's Discord channel and the Watch Page with best wishes to our friends in Japan near Typhoon Hagibis" "159": "Plug the upcoming Jon & Casey gaming stream" "235": "Experimentally getting the lighting into the fragment shader, with thoughts on specialist vs generalist programming for GPUs" "551": "Reconstituting the inbound lighting from our light probes, to light pixels" "730": "Contributing the light from only the three front faces" "845": "On the need to trilinear blend multiple light probes" "1016": "Using a 3D texture voxel representation of the lighting, to simplify things for the GPU" "1197": "Switch CompileZBiasProgram() over to represent the light probes as a 3D texture" "1952": "Hit an OpenGL shader error" "1989": "Fix typo in CompileZBiasProgram()" "2045": "See that everything is black" "2097": "Temporarily make CompileZBiasProgram() set the LightData to the WorldN" "2114": "See our colourful world" "2163": "Temporarily make CompileZBiasProgram() shift the light into the visible colour range" "2234": "See our fully colourful world" "2295": "Set up first to output voxels directly to the GPU, then send just the list of light probes" "2402": "GPU Voxelization" "2612": "Dear NVIDIA, Why does GPU Voxelization require us to use an unordered access view?" "2742": "Set up to send our entire voxel grid at 2,800 MB / sec" "2843": "Make CompileZBiasProgram() submit our six-faced light probes as 3D textures" "3946": "See a black screen with little seams" "3971": "Make EndLightingComputation() stuff red into the West face of our light probe voxels" "4258": "See our red world" "4286": "Test our spatial querying, by making EndLightingComputation() colour the voxels alternately red / blue" "4324": "See a fully blue world" "4359": "Augment zbias_program and render_setup with VoxelMinCorner and VoxelInvTotalDim for CompileZBiasProgram() to use" "4744": "Still see a fully blue world" "4764": "Introduce SetLightBounds() for UpdateAndRenderWorld() to call" "5076": "See our alternately red / blue world" "5111": "Make EndLightingComputation() stripe our lighting in all three dimensions" "5212": "Check out our tartan world" "5239": "Flip our stripes in EndLightingComputation() from RGBA to BGRA" "5255": "Check out our tartan world" "5376": "Check out our tartan world in release mode" "5447": "Nsight rendering time: 22ms / frame" "5489": "Capture a frame to see that we may be CPU-bound" "5565": "Prevent EndLightingComputation() from striping the world" "5580": "Nsight rendering time: 22ms / frame" "5623": "Q&A" "5731": "Q: In the pre-stream when you were talking about creating command buffers in your theoretical graphics API, would this be like a buffer you would dynamically assemble GPU machine code into, or is this something that the driver would need to translate for you to the GPU machine code?" "5849": "Q: Isn't SPIR-V the thing you are talking about?" "5956": "Unrelated Q: How would a highlight shader work, e.g. if you want to select a sprite you'd want to color the edges of a sprite in some color? Is this done via the stencil buffer?" "6114": "Q: What happened with the profiler? Just before you ended the stream, you mentioned you want to re-enable the profiler (I assume it's the Handmade Hero one). Was it disabled, or just not tracking for this part of the code?" "6193": "Q: Have fun gaming with Jon" "6198": "Thank you everyone, with a plug of the Jon & Casey gaming stream" --- name: "day561" title: "Sampling Light Voxels with a Reflection Vector" markers: "1": "Recap and set the stage for the day" "34": "Demo our tartan world with a view to sampling all of our voxels" "139": "Consider optimising CompileZBiasProgram() to only sample from three voxels" "216": "Toggle off BuildSpatialPartitionForLighting() and ComputeLightPropagation() in EndLightingComputation()" "248": "Nsight rendering time: 22ms / frame" "300": "Capture a frame to see that the glTexSubImage3D() call takes most of our frame time, at 15.13ms" "523": "Make OpenGLInit() rather than OpenGLEndFrame() set the texture parameters for each voxel" "579": "Ensure that that has done nothing adverse" "598": "Temporarily make OpenGLEndFrame() only submit the light probe textures ten times" "657": "Nsight rendering time: 8ms / frame" "724": "A few words on structured art, credited to Mike Biddlecombe" "812": "Make EndLightingComputation() stuff structured art into all faces of our light probe voxels, with Green in the East" "956": "See our red-striped world" "998": "Enable CompileZBiasProgram() apply the colour of our East faces" "1081": "Demo RemedyBG's new .str feature" "1187": "Fix our typo in CompileZBiasProgram()" "1198": "See our red- and green-striped world" "1213": "Make EndLightingComputation() stuff structured art into the South, North, Down and Up faces of our light probe voxels" "1337": "See that our green striping is not as expected" "1359": "Make EndLightingComputation() increase the spacing of our stripes" "1467": "See our distantly-spaced stripes" "1481": "Enable our closer-spaced stripes in EndLightingComputation()" "1488": "See our closer-spaced stripes" "1508": "Nsight rendering time: 18ms / frame" "1529": "Capture a frame to determine that we must be CPU-bound" "1570": "Toggle off the structured art code in EndLightingComputation()" "1581": "Nsight rendering time: 6 to 14ms / frame" "1642": "Check our GPU model: NVIDIA GeForce GTX 1080" "1671": "Consider how best to fill our pixels, not using GPU Voxelisation because of its unordered access view" "2124": "Disable voxel blending in OpenGLInit(), so we can see their boundaries" "2175": "Gauge the width of our voxels" "2220": "Make UpdateAndRenderWorld() set the WorldCameraRect based on the ExpectedFocus" "2399": "See that our entire viewable region is fully lit" "2467": "Consider our voxel grid to be too detailed" "2495": "Reduce our LIGHT_LOOKUP_VOXEL_DIM from 128 to 64" "2519": "Consider our voxel grid to be more reasonably detailed" "2536": "Reduce our LIGHT_LOOKUP_VOXEL_DIM from 64 to 32" "2548": "Consider our voxel grid to be roughly the right size, but the Y-band to be too thick" "2647": "Scan through CompileZBiasProgram() and EndLightingComputation() for possible bugs" "2808": "See eight narrow stripes along the X axis" "2826": "Understanding modulo operation" "2863": "Toggle off the extraneous stripes EndLightingComputation()" "2876": "See four red stripes along X" "2927": "Try to apply Green to the LightWest in EndLightingComputation()" "2966": "See no difference, to determine that our problem is in the filling / sampling of all faces of the voxels" "2987": "Disable the LightBounds resizing and positioning code in UpdateAndRenderWorld()" "3106": "Traverse the world with the determination to work on our spatial query" "3157": "Scan the code for any problems in our voxel specifications" "3233": "See no green stripes in Y, step in to UpdateAndRenderWorld() and inspect our InvLightDim" "3371": "Break in to a voxel submission in OpenGLEndFrame() and inspect the LightData" "3581": "Scrutinise our test striping code in EndLightingComputation(), and the voxel initialisation code in OpenGLBeginFrame()" "3766": "Excise stale OpenGL light values, and size the LightData in open_gl by the LIGHT_LOOKUP_VOXEL_DIM" "3913": "See our expected green stripes in Y" "3932": "Make EndLightingComputation() colour our lighting bounds" "3990": "See our four stripes in X and Y" "4041": "Consider using non-uniform voxel bounds, e.g. 64 × 64 × 32" "4145": "Make UpdateAndRenderWorld() form a square LightBounds" "4218": "See our square light bounds" "4266": "Make EndLightingComputation() stripe every other voxel" "4292": "See that our light probes tend to span two voxels" "4363": "Decrease the LIGHT_LOOKUP_VOXEL_DIM from 32 to 16" "4375": "See that we have roughly one voxel per light probe" "4458": "Increase the LIGHT_LOOKUP_VOXEL_DIM from 16 to 32" "4476": "Determine to light our world" "4485": "Nuke our striped lighting, and stuff the West face of all voxels with white" "4542": "See our uniformly lit world" "4565": "Consider our lighting equation" "4857": "Simple Fragment Lighting" "5159": "Reflection Vector" "5332": "HOWTO search "reflection" in the episode guide" "5359": "Compute our reflection vector in CompileZBiasProgram()" "5556": "Run successfully" "5558": "Make CompileZBiasProgram() sample the lighting specularly from the direction of the reflection vector, introducing GetIrradiance()" "5851": "See our west-lit world" "5866": "Check our lighting equation in CompileZBiasProgram()" "5970": "Consider our lighting to be exactly right, except for the falloff" "6058": "Try making EndLightingComputation() light from the East" "6082": "See our east-lit world" "6104": "Note that we're computing the lighting based on the debug camera" "6149": "Try making EndLightingComputation() light from the South" "6169": "See our south-lit world, and wonder if the reflection is wrong" "6247": "Scrutinise our lighting normals in CompileZBiasProgram()" "6366": "Note that our sprite normals are probably wrong" "6434": "Try making EndLightingComputation() light from the North" "6452": "See our north-lit world" "6460": "Try making EndLightingComputation() light from Below" "6475": "See our below-lit world" "6484": "Try making EndLightingComputation() light from Above" "6494": "See our above-lit world" "6507": "Make EndLightingComputation() light purple from above and yellow from below" "6545": "See our colourfully-lit world" "6613": "Q&A" "6647": "Q: Shouldn't it be R = I + 2*…, adding instead of subtracting the vectors?" "6702": "Flip the reflection vector computation in CompileZBiasProgram()" "6730": "See our (in)correctly lit world" "6832": "Q: I think subtraction is right, actually, isn't it?" "6841": "Reflection Vector Direction" "6987": "Flip back the reflection vector computation in CompileZBiasProgram()" "7002": "Reflection Vector Direction, continued" "7089": "See our purple sky reflection" "7117": "Q: So where would you put material information for the lighting? In the ray tracing part of the algorithm, that we still have not plugged in, or in the shader?" "7410": "Q: Are the AVX load instructions actually fast? Have you tested them?" "7471": "Q: Like this photo?" "7576": "Q: Were the PS3's SPUs good at texture sampling?" "7781": "Wrap it up" --- name: "day562" title: "Testing Voxel Light Sampling" markers: "0": "Recap and set the stage for the day" "35": "Demo the current test state of our lighting sampling, planning to stuff predictable values into our light probes" "305": "Split out and explain our lighting equation in CompileZBiasProgram()" "640": "Does anyone know if Milton has been fixed" "651": "Light Occlusion via Normal" "751": "Bug with light being transmitted through surfaces" "1005": "Split out the light direction coefficient of our lighting equation, used to prevent light transmission through the backs of surfaces" "1174": "Cosine falloff light collection at angles" "1353": "Radiating light at angles" "1501": "Research "Phong Lighting and Specular Highlights"" "1714": "Determine to look into light emittance at angles" "1786": "Make our lighting equation ignore light obscured by surfaces" "1898": "See our possibly more correct lighting" "1993": "The problem sampling from a light probe perpendicular to the surface" "2090": "Light Probe Spreads" "2166": "Let our lighting equation gather in some light from perpendicular sources" "2198": "See our more lit world" "2241": "Spread our light sampling by 45°" "2327": "Light Direction Coefficient Spread" "2531": "Scale our spread light to the range 0 to 1" "2553": "Consider our spread light sampling to be sane enough for now" "2583": "Factor diffuse light into our lighting equation" "2773": "Check out our diffuse and reflective lighting" "2809": "Blank out the Down light in EndLightingComputation()" "2847": "Check out our diffuse and reflective lighting" "2893": "Material reflectance" "3044": "Introduce a specular–diffuse coefficient in our lighting equation" "3123": "Check out our 50/50 reflectance" "3135": "Make our materials perfectly specular" "3147": "Check out our specular reflectance" "3161": "Make our materials pure diffuse" "3173": "Check out our diffuse reflectance" "3181": "Leave our surface materials as 50/50 specular–diffuse" "3228": "Determine to stuff predictable values into our light probes" "3255": "Make our Up light white in EndLightingComputation()" "3269": "Check out our plain lit scene" "3340": "Let OpenGLEndFrame() continue to send lighting to the GPU" "3381": "Briefly traverse our lit world" "3401": "Prepare EndLightingComputation() to handle distant light sources, of varying intensities" "3945": "See our brightly lit world" "3957": "Factor in the light intensity in EndLightingComputation()" "4045": "See our still brightly lit world" "4056": "Scrutinise our light falloff, and increase our light ratio coefficient from 0.5 to 3" "4104": "Check out our distance-based lighting, light a spotlight" "4167": "Enable OpenGLInit() to apply linear blending" "4192": "Check out our more smooth-faded lighting" "4308": "Prepare EndLightingComputation() to handle moving light sources" "4428": "See our spotlight jump between camera positions" "4467": "Make EndLightingComputation() lock the light source to player's position, augmenting lighting_solution with a DebugLightP" "4563": "Check out our moving spotlight, lamenting the hard-line artifacts where the light falls to black" "4734": "Calculating a smoother falloff function" "4881": "Produce a smoother falloff in EndLightingComputation()" "4921": "Check out our spotlight's smoother falloff" "4935": "Try to further smooth our falloff in EndLightingComputation()" "4948": "Find that our falloff is less smooth" "4968": "Try producing a harsher falloff in EndLightingComputation()" "5006": "Check out our blocky falloff" "5018": "Reduce the light intensity from 0.1 to 0.025 of the max in EndLightingComputation()" "5025": "Check out our less intense light" "5037": "Revert to linear falloff, with the lower intensity in EndLightingComputation()" "5044": "Check out our linear falloff, and lower intensity spotlight" "5091": "Consider how to proceed with our lighting" "5221": "Consider our falloff edge artifact to not need solving" "5349": "Make EndLightingComputation() collect appropriate amounts of light from the six directions" "5696": "See our unlit world" "5702": "Temporarily hard set the UpA to 1.0 in EndLightingComputation()" "5750": "See our still until world" "5753": "Fix EndLightingComputation() to multiply our light colours by 255" "5776": "Check out our brightly lit world" "5779": "Make EndLightingComputation() correctly normalise the inverse total light" "5815": "Check out our directionally lit world, with the sprites incorrectly lit" "5967": "Adjust the ground cover's normal in FillUnpackedEntity()" "6051": "Check out our directionally lit ground cover" "6077": "Further adjust the ground cover's normal in FillUnpackedEntity()" "6095": "Check out our directionally lit ground cover and monstar sprite" "6140": "Q&A" "6258": "Q: Could you give sort of a brief high-level explanation of how the lighting works?" "6280": "Q: Are the cube artifacts a result of the view vector reflection instead of the light vector reflections?" "6303": "Make our materials pure diffuse in CompileZBiasProgram()" "6327": "Continue to see our spotlight falloff edge artifact" "6340": "Consider our voxel trilinear interpolation to be the problem" "6478": "Lighting" "6537": "Lighting at Startup: 1) Light Probe Distribution" "6595": "Lighting during Run-time: 2) Light Probe Table Index Assignment" "6821": "Lighting during Run-time: 3) Light Injection" "6885": "Lighting during Run-time: 4) Light Transmission" "6921": "Lighting during Run-time: 5) Smoothing (Hysteresis)" "7020": "Lighting on the GPU: 6) Voxelisation of Light Probes" "7139": "Q: (Responding to why there's not two cosine terms) Two things: The BRDF is defined to be the derivative of the outgoing radiance with respect the irradiance, so whatever extra terms you think you need are already folded into the BRDF. Also, remember that the next bounce of light will have another cosine, so the other cosine is accounted for. Does that clear it up, or am I misunderstanding?" "7194": "Q: Regarding Milton, aren't you using an "unofficial" version that has the grid tool patched in? If so, maybe switch back to the official version" "7284": "Wrap it up, with homework to figure out better, non-trilinear light probe sampling" --- name: "day563" title: "Using the Light Probe Spatial Index" markers: "0": "Recap and set the stage for the day" "26": "Demo our current lighting sampling, with the trilinear blend artifacts" "187": "Determine to move on to light transmission" "361": "Reacquaint ourselves with BeginLightingComputation() and EndLightingComputation()" "542": "Admire our sampling sphere" "580": "Remove the SampleTable from EndLightingComputation() and lighting_solution" "633": "Walk through the rest of EndLightingComputation()" "717": "Determine to store persistent information in the light probes" "800": "Determine to specify and track light sources" "895": ""Bias" in the context of rendering vs sampling" "1019": "Summarise our determination regarding light probes and tracking of light sources" "1054": "Prepare EndLightingComputation() to implement persistent light probes" "1260": "Reacquaint ourselves with the light probe data in game_render_commands and lighting_solution" "1415": "Remove light_probe and the LightProbes buffer from lighting_solution" "1439": "Consider handling variable amounts of light from the six directions, by using a uniform sampling pattern, pre-multiplied based on the rays-per-face" "1619": "Make EndLightingComputation() accumulate light persistently across frames" "2126": "Probe Accumulation" "2398": "Make EndLightingComputation() blend the accumulated light using our equation, rather than pre-multiplying in a first pass" "2668": "Prepare to voxelise our light probes" "2739": "Consider the performance of our voxel sampling and trilinear blending" "2794": "Determine to use our voxel spatial indexing for now" "2859": "Make EndLightingComputation() call AddProbeToSpatialIndex() on all light probes, making the latter take the ProbeP and Radius to save it having to look up the light_probe" "3298": "Make EndLightingComputation() accumulate the irradiance of light probes during voxelisation, introducing IrradiancePack()" "3905": "Reacquaint ourselves with GetCornerLightIndex() and GetProbeLightingFor(), noting a positional bug" "4134": "Make EndLightingComputation() call GetCornerLightIndex()" "4219": "Make EndLightingComputation() stuff some test irradiance into our light probes" "4511": "Make InitLighting() and BeginLightingComputation() set up our light probe voxel grid, and EndLightingComputation() clear the ProbeIndexPtr (while meaning to clear the ProbeIndex)" "5567": "Switch ComputeLightPropagation() and friends to our new implementation of light probes, augmenting the lighting_solution with LightProbeP and LightProbeIrradiance pointers" "6179": "Make EndLightingComputation() set the solution's light probe data" "6254": "Crash in AddProbeToSpatialIndex()" "6297": "Fix MapIntoGrid() to clamp the light probe voxel cell coordinates" "6569": "See something totally wrong" "6612": "Q&A" "6672": "handmade_hero Why does the Handmade Hero channel not have the "game development" and "programming" tags?" "6755": "Q: The debug text still not working? I'm guessing yes for I've not seen it, but was curious if I just missed it). I did see earlier that you have begin / end lighting" "6784": "Q: Do you have any examples of good written software (open source) that you would recommend someone to study or that you yourself studied in the past?" "6878": "Q: Where's puss?" "6901": "Q: " jhucktemp: Does his color scheme have a name? It's very pleasing to the eye"" "6933": "Q: How can we improve the web?" "7094": "Q: Someone had mentioned during the stream perhaps you needed 1.0f - IrrBlendU? (You had 1 - IrrBlendU). Perhaps you have already addressed this" "7149": "Q: Is DirectX dependent on the C runtime? Can it be used without it?" "7273": "Q: I would guess so, because it might cast it to a integer. I had just read the chat" "7283": "Walk through the IrrBlendV initialisation in terms of int-to-float conversion" "7471": "Test int-to-float conversion" "7732": "Compile and see our int-to-float conversion warning" "7840": "Confirm the compiler's reluctance to warn when converting int-to-float in the IrrBlendV initialisation" "7920": "Use 1.0f in the IrrBlendV initialisation" "7934": "Step to our int-to-float test code and inspect these values" "8105": "Representing 5 as an int and a float" "8276": "Continue to describe our test int-to-float values" "8384": "Floating-point hexadecimal to binary" "8442": "Check the IEEE 754 floating-point format" "8580": "Inspect TestFloat in memory" "8647": "Convert TestFloat from hexadecimal to binary, and understand its floating-point representations" "9004": "Step through our int-to-float conversion of 5" "9057": "Increase TestVal from 5 to 1 << 26" "9078": "Step through our int-to-float conversion of 1 << 26" "9087": "Why 1 << 26 fits in a float" "9123": "Set TestVal to (1 << 26) | 1" "9166": "Step through our int-to-float conversion of (1 << 26) | 1, to see our truncation problem" "9294": "Q: What debugger is that?" "9337": "Demo the sheer speed of remedybg, and praise its installation and the productivity of its writer x13pixels" "9432": "Q: Have you tried CLion? Its debugger is awesome" "9710": "Wind it down" --- name: "day564" title: "Improving Trilinear Sampling Results" markers: "2": "Recap and set the stage for the day debugging our lighting pipeline" "177": "Demo our mostly unlit world" "300": "Scrutinise EndLightingComputation() for bugs" "392": "Expand the radius of our light falloff in EndLightingComputation()" "414": "See some visible lighting, with "watery" artifacts as we apparently get full brightness in voxels lacking a light probe" "520": "Increase the light intensity from 0.025 to 0.1 of the max" "585": "See fuller light in the center region" "639": "Fix EndLightingComputation() to omit the zero light probe from our spatial index" "835": "See that our lighting brightness artifact is fixed, but that the sampling needs improving" "1023": "Visualise the location of light probes within their voxels, using our checkerboard pattern and disabling the trilinear filtering" "1197": "Check the location of our light probes" "1248": "Make EndLightingComputation() override all the lights with our checkerboard" "1300": "Check the location of our light probes in the voxels" "1352": "Disable the checkerboard in EndLightingComputation()" "1376": "See that our non-trilinear sampled lighting looks more or less correct, and consider factoring in the light probe position to our lighting equation" "1573": "Begin to make CompileZBiasProgram() factor in the light probe position to our lighting equation" "1799": "Consider how we could adjust the light based on its position" "1957": "Consider a cleaner way to interpolate between light probe voxels, using a signed distance field" "2234": "Revert our light position code, and re-enable trilinear filtering" "2309": "Take a close look at our light falloff artifacts" "2422": "Rounded Falloff" "2675": "Distance-based Falloff" "2881": "Try to encode our lighting alpha and intensity as a signed distance field, before reverting" "3396": "Make sure that it still runs" "3399": "Make EndLightingComputation() stuff lighting values directly into the voxels" "3560": "See our test light sphere" "3576": "Encode our light values as a signed distance field in EndLightingComputation()" "3835": "Find that our trilinear interpolation is more round than it was" "3949": "Prevent EndLightingComputation() from normalising the incoming light, and only apply the West light" "4099": "Check out the high quality of our lighting falloff" "4177": "Reinstate all our light directions in EndLightingComputation()" "4316": "See light beyond our falloff boundary, and that the roundedness has gone again" "4434": "Consider if we can put our sampled lighting into a signed distance field construction at voxelisation time" "4690": "Walk through our lighting equation in EndLightingComputation(), noting the problematic interaction of multiple normalisations with a signed distance field" "4979": "Prevent EndLightingComputation() from factoring in the light direction normals" "4998": "See our non-round falloff interpolation artifact" "5028": "Reduce the light intensity in EndLightingComputation()" "5077": "Still see our falloff interpolation artifact" "5081": "Make EndLightingComputation() only apply the West light" "5131": "See that our falloff interpolation artifact has gone" "5172": "Make EndLightingComputation() also apply the South light" "5239": "See that our falloff still looks fine" "5251": "Make EndLightingComputation() also apply the Down light" "5281": "Start to see falloff interpolation artifact return" "5328": "Make EndLightingComputation() only apply the West light" "5377": "See our smooth falloff" "5384": "Make EndLightingComputation() clamp the light values from 0 to 1" "5401": "See falloff interpolation artifacts" "5440": "Reinstate the signed distance field in EndLightingComputation()" "5446": "Consider the box-directionality of our light probes to be the problem" "5795": "Prevent EndLightingComputation() from applying the light from all directions" "5851": "See some light" "5856": "Try making EndLightingComputation() set all light directions to -1" "5940": "See black, as expected" "5952": "Consider correctly handling zero light (in a signed distance field)" "6158": "Force CompileZBiasProgram() to falloff the light to zero, and let EndLightingComputation() apply the West light" "6185": "See our smooth radial falloff, to black" "6302": "Determine to factor in the light direction to our lighting equation" "6369": "Make CompileZBiasProgram() factor in the light direction to our lighting equation" "6666": "See that our light reflections look correct" "6732": "Make CompileZBiasProgram() reconstruct light directions more precisely" "6777": "Admire our light reconstruction" "6852": "Q&A" "6915": "Q: Are you ever going to upgrade the stream 4coder to the latest one you and Allen were working on?" "6972": "For us latecomers, what helped smooth the voxel-like outline of the lighting?" "7401": "Demo our smooth radial falloff" "7429": "Make EndLightingComputation() encode the light as 0 to 1 values" "7460": "Watch the falloff interpolation artifact return" "7494": "Reinstate the signed distance field in EndLightingComputation()" "7504": "Watch the falloff interpolation smooth" "7514": "Plug Chris Green's article 'Improved Alpha-Tested Magnification for Vector Textures and Special Effects'" "7638": "Consider encoding our light from -0.2 to 1" "7734": "Q: What's the reason you want to keep with the light probes approach instead of using light entities?" "7821": "Q: Light source" "7992": "Q: Could you explain about the real time fluid simulations for games. For example, how to simulate swirling smoke in the game? Have you read the paper by Jos Stam on the real time fluid solver for games? It is really interesting in my opinion. Thanks" "8078": "Q: This paper" "8446": "Backwards Integration" "9208": "Shut it down" --- name: "day565" title: "Reconstructing Multiple Lights" markers: "1": "Recap yesterday's discovery using a signed distance field for lighting falloff" "162": "Demo our voxel-based signed distance field interpolated lighting, non-computed" "244": "Make EndLightingComputation() encode the light as 0 to 1 values" "268": "Watch the falloff interpolation artifact return" "300": "Reinstate the signed distance field in EndLightingComputation() and watch the falloff smooth out" "459": "Reorganise and enable our voxel checkerboard code in EndLightingComputation()" "844": "Check out the resolution of our voxel grid" "907": "Halve our voxel resolution" "915": "Check out our lower resolution voxel grid" "923": "Toggle off our checkerboard in EndLightingComputation()" "953": "Admire the quality of our lighting reconstruction" "1006": "Disable trilinear filtering" "1036": "Check out the sparse resolution of our light" "1083": "Toggle on our checkerboard in EndLightingComputation()" "1107": "Consider our voxel resolution to suffice" "1139": "Enable trilinear filtering and embark on switching our light sampling from the box-model, to a signed distance field scheme" "1229": "Consider encoding our light field using spherical harmonics" "2287": "Change our light sampling to a signed distance field, normal plus colour scheme in CompileZBiasProgram()" "3651": "Update EndLightingComputation() to handle our separately encoded normal and colour" "3965": "Update CompileZBiasProgram() to handle our separately encoded normal and colour" "4090": "Find that that worked the first time, but the normals are not correct" "4139": "Enable GetIrradiance() in CompileZBiasProgram() to produce and EndLightingComputation() to encode a -1 to 1 normal, introducing BinormalToNormal()" "4353": "Find that our normal encoding now works correctly" "4384": "Add a secondary light source in EndLightingComputation()" "4542": "See our two light sources" "4554": "Further separate our two light sources" "4581": "See our two separated light sources" "4587": "Colour our light sources yellow and cyan" "4598": "See our two separate coloured light" "4609": "Overlap our two lights" "4617": "Check out the intersection of our lights" "4769": "Nsight rendering time: 6ms / frame" "4841": "Add two more light sources in EndLightingComputation()" "4977": "See three of our four lights" "4996": "Enable CompileZBiasProgram() to sample our fourth light" "5072": "See our four lights" "5132": "Consider how to change our light probes to work as a signed distance field" "5516": "Admire our lighting, and consider tracking colour and intensity differently" "5632": "Q&A" "5654": "Q: Have you taken anything you implemented for Handmade Hero and used it in your other work?" "5723": "Q: What are you working on during the week?" "5803": "Q: How will walls stop light, same bouncing rays as before?" "5875": "Q: I assume there is a source of income, not working on projects for pay?" "6022": "Q: You do realise you could be a very wealthy man if you accept a small project for a few weeks, right?" "6670": "Q: In terms of programming techniques, how has your style changed over the course of this project? Are there things you did at the beginning of this project that you think were steps in the wrong direction or would do differently?" "6914": "Q: Can memory fragmentation happen on GPU?" "7170": "Q: 10/10 pants, looks very comfy" "7173": "Q: How would you compare WinDBG and RemedyBG? Should I consider switching to RemedyBG if I'm using WinDBG?" "7381": "Q: Where could I learn more about out-of-order optimization?" "7394": "Q: Could you explained the stripped binary? Is it possible to optimize a binary even there is no access to the source code?" "7512": "Q: Do you have any resources on why OOP programming isn't that good?" "7558": "Q: What would be the best way to prevent overdraw in a software rasterizer, in particular with a voxel scene like Minecraft? (I asked this before but didn't specify the type of game)" "7683": "Q: I've heard you mention before that you don't like callbacks. Should they be avoided at all costs? How would you avoid them if using recursion and navigating a tree-like structure?" "7735": "Q: What’s your opinion on white board interviews in the big tech companies like Google?" "7921": "Q: If virtual memory exists, how are games still able to be hacked? Is it because offsets are constant?" "7951": "Q: Have you heard about game development workshop assembly and also assembly archive?There are lots of material there." "7959": "Q: Is there an errata page for the Jeff and Casey show that I can submit to?" "7967": "Q: How do you do design memory arenas for multiple dynamic arrays to please the cache?" "8012": "Q: Don't you think that the reason for low quality software was because people wanted to do things faster?" "8033": "Q: I would like to express my deepest disappointment in the lack of new J&C episodes" "8055": "Q: I mean for software for simulations, something like Mathematica" "8066": "Q: Do you think it's possible to turn the web around? Also PJs are pretty nice" "8122": "Q: If you are an employer, which candidate would you choose? A: 4.0 GPA with no side project; B: 2.5 GPA with lots of side projects" "8361": "Q: Hey Casey, I know you're busy and all. Can you stand up for me and reverse this linked list for me on the white board? Thanks" "8645": "Q: Random off-topic question but why does it feel like you would enjoy knitting? Just a random gut feeling" "8680": "Q: The thing is also that these people probably make the software slow and sh… on purpose to not be easily fired" "8804": "Q: What are some resources to learn graphics programming? How much math is really necessary?" "8861": "Q: If not with dynamic arrays, how do you store dynamically growing data when you can't predict how much memory you will need and need to store it, so the Handmade Hero temporary memory concept doesn't solve the problem? I figure some sort of linked list is even worse for the cache" "8880": "Q: Have you or would you ever use goto?" "9033": "Q: switches can in some cases generate indirect jumps" "9095": "Q: Will you be an early adopter of JAI?" "9100": "Q: In your experience what do you think are good ways to manage software projects? I hear lots of praise for scrum / agile but from my experience these methodologies have shown none to little results. Am I missing something with these methodologies?" "9113": "Q: The dynamic array example: 1) a list of active connections on a server; 2) an array of entities in a game" "9154": "Q: If you have several unpredictably growing dynamic arrays, say in a "math" simulation, would you separate them by a large distance in a memory arena? Or do you pile blocks on top of each other? What does the cache prefer? Is it even a concern?" "9281": "Close it down, people" --- name: "day566" title: "Moving to a Voxels-only Lighting Approach" markers: "3": "Recap and set the stage for the day streaming from a new location" "71": "Demo our new signed distance field-based lighting solution" "279": "Determine to work on our light transport, with an eye on outputting it to our signed distance field voxel grid" "434": "Light transport: 1) Sampling" "482": "Light transport: 2) Storage (in light probes) for reconstruction per voxel, e.g. spherical harmonics, k-means clustering" "931": "Determine to start with direct ray casting of one light" "1116": "Turn off all but one of the test lights in EndLightingComputation()" "1158": "See our single light source, and plan to: 0) Move to screen-space voxel for light reconstruction; then 1) Compute direct ray casting of one ray" "1310": "Update the checkerboard to handle one light source in EndLightingComputation()" "1384": "Our checkerboard still works" "1395": "Begin to update the light probes code in EndLightingComputation()" "1545": "Consider moving to a voxels-only lighting approach" "1878": "Mostly replace light probes in lighting_solution with a newly introduced light_voxel_cell" "2285": "Switch EndLightComputation() over from light probes to cells" "2538": "We got a puss" "2639": "Make EndLightingComputation() initialise our larger voxel, from where we access our small voxel cell" "3313": "Fix compile errors, making InitLighting() handle our new light_voxel_cell" "3551": "Determine to get the voxels tracking properly" "3718": "Stably position the lighting voxel grid in absolute world space, making UpdateAndRenderWorld() pass the Camera.P to BeginLightingComputation()" "4203": "Begin to make BeginLightingComputation() align the lighting voxel grid with our view" "5172": "Gather peanuts" "5191": "afk" "5207": "Return to crunch on some peanuts and consider how to align our view to a whole-number multiple of the voxel call dimension" "5401": "Day 566" "5512": "Aligned Voxels" "6201": "Research modulus distribution" "6342": "Modular multiplication, or using a light cell dimension of a power of 2 to easily align the grid with our view" "6558": "Enable BeginLightingComputation() to align the lighting voxel grid with our view" "6860": "Q&A" "6875": "Q: It's day 566" "6902": "Q: You talking about non-realism but good looking art got me thinking, do you plan on having game entities that manipulate light in extremely non-real ways? Like light absorption that sucks the light out of an area or perverts it in some way? (Inversion, RGB-swapping, messing with normals etc.) I'm thinking like dark magic kind of effect." "6955": "Q: Why not use % directly?" "7061": "Q: Couldn't you contrive it so that ChunkDim is always an even multiple of LightCellDim?" "7121": "Consider deriving our LightCellDim from the WorldChunkDimInMeters, for easy alignment" "7182": "Q: A thing that I have trouble with is what happened to you a few minutes ago. I found the math.stackexchange pages perfectly readable, and I'd have no idea that anyone wouldn't be able to read it. How do you put yourself in other people's shoes when you teach? If I'm writing things online, should I always try to state things in terms of notation that beginners would understand?" "7201": "Q: I'm missing something fundamental about spherical harmonics. I get the idea of decomposing areas into spheres, but I don't get how you could use something like that to accumulate some representation of light that you could reconstruct. Would be willing to provide an intro sometime?" "7438": "Q: Yeah, essentially, or maybe anything with lots of jargon that's kinda essential to working with the subject seriously. I find myself on the other side a lot when I'm doing, like, FPGA stuff and I have no idea what people are talking about, but once I learn all of the jargon it becomes second nature to think about things in those terms. If that makes sense" "8187": "Q: Thanks. I guess I put too much emphasis on accumulation and reconstruction. I can reason about what you just said about orthogonality and addition. My misunderstanding is more fundamental. I understand how you can use ray tracing to get light intensities and colors at probe points, which can be passed to your fragment shader, but I don't get how you can get some spherical representation of light at probe points, and what the heck your fragment shader would do with it" "8417": "That's the end of the Qs" "8443": "We are looking for generally applicable novice questions" "8616": "That's it for today" --- name: "day567" title: "Large to Small Voxel Transfer" markers: "0": "Recap and set the stage for the day" "79": "Some thoughts on experimental vs clean code" "217": "Describe our new light_voxel_cell lighting scheme" "374": "Align our lighting voxel grid to the world, augmenting game_mode_world with a FundamentalUnit, and making InitLighting() derive our VoxCellDim from that FundamentalUnit" "749": "See a black screen" "758": "Toggle off the lighting in CompileZBiasProgram()" "779": "Our world generation remains good, but our AlphaMin needs adjusting" "947": "Reduce AlphaMin from 2.75 to 2.25 in PlayWorld()" "1078": "Reacquaint ourselves with the entity hopping code" "1291": "Augment the entity struct with a GroundP for UpdateAndRenderEntities() to record, to help stabilise the camera in Z as the player hops around" "1473": "See no change to our alpha fading" "1492": "Make UpdateCameraForEntityMovement() use our new GroundP" "1525": "Find that our alpha fading remains stable during hopping" "1617": "Plan to stabilise our alpha / fog across traversables" "1769": "Admire our floor heights" "1809": "Make BeginLightingComputation() compute and draw our LargeVoxelRect and HotVoxelRect" "2598": "Check out our lighting voxels" "2638": "Halve the VoxCellDim in InitLighting()" "2658": "Check out our smaller lighting voxels" "2697": "Make BeginLightingComputation() centre our lighting voxels" "2741": "See that our HotVoxelRect does not quite cover our whole view" "2774": "Double the VoxCellDim in InitLighting()" "2793": "See that our HotVoxelRect covers our whole view" "2860": "Enable the checkerboard lighting" "2871": "Consider our lighting voxel to be too sparse" "2889": "Increase the resolution of our lighting voxel" "2940": "Consider our lighting voxel resolution to suffice" "2979": "Make EndLightingComputation() draw our checkerboard more clearly" "3020": "Admire our clearer checkerboard, and still consider our lighting voxel resolution to suffice" "3107": "Make EndLightingComputation() alternate our checkerboard colours in Z" "3131": "Find it tough to gauge the lighting voxel resolution in Z" "3175": "Make EndLightingComputation() produce a full 3D checkerboard, disabling trilinear filtering in OpenGLInit()" "3455": "See that our checkerboard encompasses our whole view and the lighting voxel is locked to the world, and consider handling offset simulation centre" "3585": "Toggle on lighting transfer in EndLightingComputation()" "3616": "See black" "3633": "Establish "Hot" / "Large" voxel nomenclature in EndLightingComputation()" "3783": "Still see black" "3791": "Begin to make EndLightingComputation() handle Large–to–Hot voxel lighting transfer" "4104": "Find that the copying of our large voxel to the graphics card is working, but our falloff is too steep and the checkerboard alternates with black" "4129": "Investigate the checkerboard blackness in IrradiancePack() and CompileZBiasProgram()" "4239": "Make EndLightingComputation() alternate our checkerboard between (7, 7, 7) and (6, 6, 6)" "4278": "See the checkerboard exhibit misalignment of our voxels" "4319": "Fix our lighting falloff in EndLightingComputation()" "4463": "See our spotlight" "4473": "Enable trilinear filtering in OpenGLInit()" "4516": "Admire our smooth lighting falloff" "4546": "Make EndLightingComputation() cast a ray from the voxel centre to the light" "5071": "Consider our ray caster to be doing something around the edges" "5113": "Reacquaint ourselves with RayCast()" "5383": "Leave the ray cast LightDF along and fix the falloff in EndLightingComputation()" "5430": "Our smooth spotlight is back" "5443": "Set the ray cast LightDF to 0" "5449": "Consider our ray casting code to never hit anything" "5500": "Make EndLightingComputation() call BuildSpatialPartitionForLighting()" "5558": "Admire the freaky answers from our ray casting" "5619": "Augment raycast_result with tRay for callers of RayCast(), such as EndLightingComputation(), to use" "5978": "Consider our RayCast() to be buggy" "6032": "Debug our RayCast(), making EndLightingComputation() draw our rays" "6111": "See no rays" "6124": "Move the debug visualisation drawing code to the end of EndLightingComputation()" "6140": "Still see no rays, noting that it almost works" "6192": "Enable UpdateDebugLines in InitLighting()" "6288": "Hit our assertion in PushDebugLine()" "6327": "Restrict our ray cast drawing in EndLightingComputation()" "6499": "See our rays" "6534": "Make EndLightingComputation() only draw rays that hit something" "6570": "See our rays which hit something" "6631": "Make EndLightingComputation() draw the rays from the light source" "6651": "See our rays emanating from the light source" "6680": "Disable the ray drawing in EndLightingComputation()" "6756": "Q&A" "6790": "Q: Shouldn't WorldChunkDimInMeters use FundamentalUnit?" "6806": "Make PlayWorld() derive the WorldChunkDimInMeters from the FundamentalUnit" "6821": "Q: How about increasing the voxel density and see if that reduces the acne?" "6860": "Q: I am your big fan, and have always been delighted with your… grouchy, in a good (very good) sense. I believe that this is a very useful quality that allows you to look at things and the world with a sober look. Just… I still can’t understand how to develop this quality in myself. Can you advise something? A book? Production OOP programming? Work as Web developer? If you do not mind the time, please give a detailed answer. Thank you!" "8004": "Q: Yo Casey, my man, since you're doing everything in C, did you make your website also in C? And if so, is it possible to build an entire website from scratch in plain C using no libraries too?" "8158": "Q: Do you ever try and measure how much of your current outlook is affected by rose tinted memories? There were great things about using computers in 1992, but I remember having to constantly do things like mess with himem.sys to try and get the most basic of things working… (Not arguing that the current state of things isn't woeful)" "8429": "handmade_hero, I feel like this was a pretty recent shift in the zeitgeist too, I remember just 5, 10 years ago everyone was much more excited about tech" "8460": "Q: Which Windows is the best version?" "8474": "Q: (About grouch) But when you do something, you do it qualitatively, because you know what quality is. It's cool from a programmer's point of view, that's all I want to say" "8590": "Q: The state of programming is pretty sad. I was doing some investigating the other day and needed to use Process Monitor to spy on devenv. Randomly looking around, I noticed a big number of events sequentially all calling ReadFile and noticed devenv, it loading a 180k byte config file in 42 calls, each reading about 4k chunks from this file, setting the offset each time" "8883": "Q: What is one thing in programming or tech that can excite you and you think is an improvement (if any)?" "9235": "Q: (Again off-topic) I think I upset you with that question, sorry" "9252": "Q: (Off-topic) Do you have any advice for applying for AAA engineering jobs? I've worked on a few indie titles, porting them to consoles (mostly Unity games). I think a lack of C++ work experience is hurting me, but it's hard to get that work experience without previous C++ experience. Any advice?" "9355": "Q: Do you do anything specific to motivate yourself in the world of awful software?" "9831": "handmade_hero Are you describing technocracy?" "9970": "handmade_hero One way to force that idea of excellence is through some form of authoritarianism, but many wouldn't like that" "10067": "Q: What are you talking about Casey, everything we do at our organization is excellent by our definition. No problems here. None at all. And if there are it's not my fault" "10432": "Arguing about capitalism vs socialism is going backwards" "10507": "It has been a pleasure" --- name: "day568" title: "Debugging the Raycaster" markers: "1": "Welcome to Handmade Coffee, roasted by Irad and presented to Casey at Handmade Seattle" "185": "Demo the current state of our raycast lighting" "493": "Cursorily reacquaint ourselves with EndLightingComputation()" "534": "Switch from TEST_LIGHT_TRANSFER to TEST_LIGHT_SPHERE in EndLightingComputation()" "545": "Admire our radial falloff lighting solution, mixing four lights" "702": "Switch from TEST_LIGHT_SPHERE to TEST_LIGHT_TRANSFER in EndLightingComputation(), and let it assume that all rays hit light sources" "764": "Admire our voxel-to-voxel interpolation" "805": "Make EndLightingComputation() draw a simple shadow if a light source is found to be occluded" "894": "See our anomalous shadows" "935": "Toggle on the ray cast debug lines in EndLightingComputation()" "956": "See our rays" "988": "Note that we are drawing a subset of 8³ out of 32³ rays" "1124": "Disable lighting in CompileZBiasProgram()" "1154": "Look at our rays in bright light, to see some which hit non-obvious objects" "1372": "Make EndLightingComputation() draw all the rays, coloured black if no hit, and yellow if hit" "1534": "Begin to reacquaint ourselves with RayCast()" "1663": "Prevent RayCast() from initialising NegativeOne" "1686": "Continue to reacquaint ourselves with RayCast()" "2216": "Consider making RayCast() base tCloseEnough on the particular box, such that boxes at the root of the hierarchy are more likely to be entered than boxes near the leaves" "2371": "Continue to reacquaint ourselves with RayCast()" "2494": "Address the old early-out condition in RayCast() when all four rays hit" "2651": "Delete the old all-hit early-out condition in RayCast(), and restrict the Box push to ones whose closest point it also closer than the current tRay" "2904": "Finish reacquainting ourselves with RayCast()" "3041": "Look at our rays, and pick a problem one to isolate" "3116": "Try to isolate our problem ray in EndLightingComputation()" "3220": "See that we picked the wrong ray" "3239": "Fix our ray isolation in EndLightingComputation()" "3251": "See that we picked our desired problem ray" "3265": "Add a BreakMePlease in EndLightingComputation()" "3303": "Break on our BreakMePlease in EndLightingComputation() and inspect our test case" "3497": "Make RayCast() initialise AnyInside and AnyCloseEnough" "3565": "Break on our BreakMePlease in EndLightingComputation() and step through to RayCast()" "3603": "Consider starting our camera at a known good location" "3665": "Break on our BreakMePlease in EndLightingComputation(), skip the first frame, step through to RayCast() and inspect our test case" "4127": "Our ray cast bug possibilities: 1) Erroneous box, correctly hit tested; 2) Correct box, erroneously hit tested" "4227": "Enable RayCast() to draw its boxes, initially one ring of each" "4593": "Launch our debug build and see no ray cast box" "4625": "Make EndLightingComputation() pass IsTestCast to RayCast()" "4659": "Check out our ray cast boxes" "4688": "Make RayCast() draw the opposite ring of the boxes" "4705": "Check out our ray cast boxes" "4744": "Make RayCast() draw the final edges of its boxes" "4787": "Check out our complete ray cast boxes" "4889": "Make RayCast() colour hit boxes cyan if they are containers, and yellow if not" "4965": "Check out our ray cast boxes, noting the erroneously placed box, and the fact that our light probes are considered colliders" "5021": "Prevent light probes from being considered colliders, introducing PushOccluder() to perform the occlusion code from PushCube()" "5341": "Check out our ray cast boxes, to see that our bad case has disappeared" "5402": "Enable lighting in CompileZBiasProgram()" "5422": "See black" "5457": "Make EndLightingComputation() draw a simple shadow if a light source is found to be occluded" "5484": "See different erroneous shadows" "5548": "Make EndLightingComputation() draw all our rays" "5592": "See some black (non-hitting) rays that apparently should be hitting something" "5647": "Disable lighting in CompileZBiasProgram()" "5684": "Try to pick a problem ray" "5848": "Make EndLightingComputation() just draw a tick mark at the casting locations" "5949": "Check out our casting locations" "5972": "Make EndLightingComputation() colour the tick marks cyan, and draw the rays themselves" "6014": "See some tick marks lacking a ray, and vice versa" "6077": "Make EndLightingComputation() draw the direction in which each ray is pointing" "6135": "Again see some tick marks lacking a ray, and vice versa" "6178": "Wonder what could be wrong with our rays" "6234": "Pick a problem ray to isolate" "6287": "Try to isolate our problem ray in EndLightingComputation()" "6297": "See that we picked our desired problem ray" "6367": "Break on our BreakMePlease in EndLightingComputation(), and inspect our Cast to see that FLT_MAX may be causing the problem" "6422": "Change EndLightingComputation() to set the CastP of non-hit rays to the light distance" "6533": "See that our problem ray's check mark is now accompanied by its actual ray, and that it remains a problem ray" "6562": "Make EndLightingComputation() pass IsTestCast to RayCast()" "6570": "See that our RayCast() failed to test the child boxes through which our ray passes" "6612": "Make RayCast() push all the child boxes into the system" "6642": "See that we do correctly detect the intersection" "6693": "Prevent RayCast() from checking from AnyCloser before pushing on a box" "6737": "See that we do not detect the intersection" "6747": "Prevent RayCast() from checking from AnyCloseEnough before pushing on a box" "6782": "See that we do not detect the intersection" "6789": "Scrutinise the AnyInside value in RayCast()" "6934": "Let RayCast() push on a box if AnyInside or AnyCloser" "6974": "See that we do not detect the intersection" "7004": "Make RayCast() extend tInside to encompass FLT_MAX" "7028": "See that we do correctly detect the intersection" "7043": "Restore our full checks in EndLightingComputation() before pushing a box" "7060": "Look at our correct ray" "7069": "Make EndLightingComputation() draw all our rays, without boxes" "7103": "Find that our rays look a little more sane" "7156": "Disable the test drawing in EndLightingComputation(), and enable lighting in CompileZBiasProgram()" "7222": "See our shadows, and determine to cast rays from light probe points" "7280": "Make EndLightingComputation() draw all our rays" "7297": "Admire our rays in the lit scene" "7351": "Q&A" "7428": "Q: Where did you learn programming, like this lighting stuff, previously?" "7613": "Q: Which parts of the CRT do you think are the most poorly designed or unnecessary? What do you feel is missing?" "7755": "Q: Did you learn new things about game programming while working on Handmade Hero? If yes, what?" "7836": "Q: Can you imagine any debug tools that would make stuff like graphics programming and lighting easier to debug (especially for beginners)?" "8135": "Q: Is it possible to get cl.exe and msbuild without installing Visual Studio?" "8167": "Q: How do you split your time between learning theory and practice?" "8197": "Q: How many hours did you expect Handmade Hero was going to be at the start?" "8310": "Q: Are you planning to do another series after you're done with Handmade Hero?" "8314": "Q: Any plans for physics?" "8329": "Wrap it up" --- name: "day569" title: "Raycasting from Light Probe Locations" markers: "2": "Recap and set the stage for the day" "44": "Demo the current state of our test ray casting from voxel centres, with the determination to cast rays from light probe locations" "268": "Prepare to switch over to raycasting from light probe locations" "452": "Introduce Frumbledygok() to contain the voxel-centre casting code from EndLightingComputation()" "527": "Begin to develop the light probe-based ray casting" "693": "A few words on programmable light falloff vs real life inverse-square falloff" "847": "Continue to develop the light probe-based ray casting, introducing TestCastFromProbes()" "1258": "Introduce GetVoxelIndex() to find which voxel a point in world space corresponds to" "1538": "Introduce GetVoxelCenterP()" "1654": "Make TestCastFromProbes() call our new GetVoxelIndex() and GetVoxelCenterP()" "1768": "Check out our initial light probe-based ray cast lighting" "1846": "Toggle on IsTestCast in TestCastFromProbes()" "1897": "See unexpected rays" "1936": "Disable lighting in CompileZBiasProgram()" "1948": "Check out our rays in a shadowless world" "1980": "Fix the HitP computation in TestCastFromProbes()" "2016": "Check out our correct rays in a shadowless world" "2084": "Consider working on our voxel fill" "2210": "Introduce PushDebugBox() for RayCast() to call" "2340": "Make TestCastFromProbes() draw the voxels hit by the rays" "2498": "Check out our hit voxels, finding that we seem to overflow our DebugLines in lighting_solution" "2599": "The puss arrives" "2639": "Hit our assertion in PushDebugLine() and investigate why" "2739": "Increase the DebugLines array in lighting_solution from 4096 to 65536" "2764": "Check out our supposed 4096 lines" "2834": "Step through TestCastFromProbes() to see multiple light probes set identically" "2925": "Replace the SetLightProbePosition() call in UpdateAndRenderEntities() with a newly introduced PushLightProbe(), to prevent multiple light probes in the same location" "3066": "Check out our hit voxels" "3146": "Shrink the voxel debug visualisation in TestCastFromProbes()" "3181": "Check out our hit voxels, and determine to fill a swathe of nine voxels" "3275": "Meow" "3401": "Introduce SpamVoxel() to flood our light computation into blocks of nine voxels, and a utility InLargeVoxel()" "3797": "Check out our flood filled voxels" "3817": "Prevent CompileZBiasProgram() from disabling the lighting" "3845": "Check out our beautiful lighting" "3892": "Make UpdateAndRenderEntities() position our light source nearer the ground" "3920": "Find that our light source still lights the area beyond a wall" "3955": "Disable lighting in CompileZBiasProgram()" "3971": "Note that our flood filling does not propagate through the wall at the starting location" "4009": "Prevent CompileZBiasProgram() from disabling the lighting" "4034": "Increase the radius of our test casting debug visualisation in TestCastFromProbes()" "4082": "See our flood filling propagate through that wall at the starting location" "4094": "Only make TestCastFromProbes() perform the flood fill if our ray did not hit" "4116": "Find that we light slightly erroneously, because we aren't clearing voxels" "4164": "Decrease the radius of our test casting debug visualisation in TestCastFromProbes()" "4185": "Make TestCastFromProbes() clear the voxels each frame" "4262": "Check out our lighting" "4305": "Make UpdateAndRenderEntities() position our light source still nearer the ground" "4353": "Admire our fog-of-war lighting" "4369": "Decrease the light falloff time (thus increasing our light radius) in SpamVoxel()" "4392": "Admire our more farsighted fog-of-war lighting" "4421": "Disable IsTestCast in TestCastFromProbes()" "4445": "Admire our fog-of-war lighting without voxel debug visualisation" "4504": "Make UpdateAndRenderWorld() position the light source relative to GroundP" "4534": "Admire our more stable light, with the determination to handle blending and convection" "4695": "Q&A" "4762": "Q: Isn't there an hour left?" "4793": "Q: would the particle system you had (heads popping out) be affected by the shadows at the moment?" "4809": "Check out the lighting on the particles" "4937": "Disable Global_Lighting_ShowProbes" "4945": "Check out our cleanly lit world" "5024": "Q: Can we enable light for the debug interface so we see the impact of the code?" "5050": "Q: Are you procrastinating on doing gameplay code and inventing problems to solve? Last time I checked (~3 months ago) you were saying you are about to start gameplay code in a couple of streams" "5096": "Admire our lighting" "5139": "Just give the game code as an assignment to Jon. Last I heard he had time to spare" "5154": "Q: Why are the debug lines a fixed sized buffer? Just 'cause it's throwaway code?" "5203": "Q: Do you have any thoughts on the trade-offs of making your data structures directly serializable versus having intermediate serialize / deserialize steps, i.e. data structures containing pointers being converted to offsets or indices" "5297": "Q: Are the bounces going to be computed also with the raytracer?" "5359": "Increase tCloseEnough in RayCast()" "5382": "Determine the tCloseEnough filtering to be garbage" "5433": "Q: Can we add for a test a second bounce or it require more work?" "5478": "Temporarily make TestCastFromProbes() bounce our rays once" "5690": "Check out our hacked secondary bouncing of the ray cast lighting" "5776": "Delete the secondary bounce code from TestCastFromProbes()" "5803": "Check we didn't screw anything up there" "5824": "Q: Do you plan on adding details on how sprites are lit? Right now they are full dark when the light is behind it. Maybe normal maps or some subsurface transport? Although I guess bounces will help with that anyway" "5865": "Q: It's my second year programming and it feels like there's endless stuff to catch up before I can be a competent games programmer. What might I do to help with that?" "5952": "Q: It should be SecCast not Cast?" "5961": "Reintroduce and fix the secondary bounce code in TestCastFromProbes()" "5985": "Check out our hacked secondary bouncing of the ray cast lighting" "6061": "Make SpamVoxel() take the LightP and LightC for secondary bounces to compute specially, dimming the light" "6222": "Check out our dimmed secondary bouncing of the ray cast lighting" "6281": "Q: How are you going to handle bouncing off of different materials?" "6329": "Q: Which type of engine programming do you think the industry needs the most? Does it need more graphics programmers, or physics, or sound programmers for example?" "6463": "So the answer is "everything everywhere yes"" "6502": "Q: Are engine programmers really as in-demand as you say? I see that most AAA games are releasing with hundreds of employees but only like 4–6 engine programmers" "6598": "Q: How much do game studios hire interns? Trying to find something for next year" "6644": "Q: Following with the theme, what would you define as the minimum requirements to be a good engine programmer?" "6837": "Q: Why aren't most studios willing to compensate appropriately in spite of the seemingly short supply of graphics programmers?" "6897": "Q: Have you heard about Valve's ACO Mesa shader compiler for AMD GPU? Apparently it is replacing LLVM and it is a great thing for Linux gaming" "6924": "Q: Relative to other positions on the team that may not require as extensive knowledge" "7043": "Q: Have you heard about Valve's ACO Mesa shader compiler for AMD GPU? Apparently it is replacing LLVM and it is a great thing for Linux gaming" "7097": "Q: Well, as a specific example, take Bethesda: They pay gameplay programmers 80–110k, but the graphics / engine programmer is 90–130k. Obviously, those numbers are from pay scale, glass door, etc, but most likely represent a decent sample size" "7288": "Wrap it up" --- name: "day570" title: "Distinguishing Between Lights and Occluders" markers: "1": "Demo the current state of our light probe-based ray cast lighting" "119": "Lighting improvements: 1. Averaging across frames" "177": "Lighting improvements: 2. Real indirect bounce and convection" "214": "Lighting improvements: 3. How best to store and update our information" "502": "Reacquaint ourselves with TestCastFromProbes()" "595": "Reacquaint ourselves with ComputeLightPropagation()" "649": "Turn the lighting_work version of ComputeLightPropagation() into a ComputeLightPropagationWork() PLATFORM_WORK_QUEUE_CALLBACK" "802": "Prepare to update ComputeLightPropagationWork() to work with voxel-based lighting" "1071": "Set up ComputeLightPropagationWork() to handle multiple light sources" "1255": "Continue to reacquaint ourselves with ComputeLightPropagationWork(), its stochastic spherical sampling and ambient light" "1433": "Consider getting ambient light from the probes" "1496": "Continue to reacquaint ourselves with ComputeLightPropagationWork(), sampling hits" "1612": "Set up ComputeLightPropagationWork() to sample from our voxel-based lighting, removing light_probe_irradiance and introducing ComputeVoxelIrradianceAt()" "1879": "Make ComputeLightPropagationWork() call SpamVoxel() renaming the existing SpamVoxel() to SpamVoxelSlice()" "2152": "Clean up compile errors" "2455": "Set up ComputeLightPropagationWork() to compute falloff based on the light source position" "2582": "Make ComputeLightPropagationWork() weight the incoming light by its intensity and location" "2771": "Consider how to average higher fidelity lighting with multiple light fields" "2903": "Make ComputeLightPropagationWork() initialise a consistent MoonP, and SpamVoxelSlice() and SpamVoxel() take a LightFalloff which may be 0.0f for the moon" "3277": "Introduce a stubbed out ComputeVoxelIrradianceAt()" "3338": "Traverse the world with the determination to put lights into the casting hierarchy" "3389": "Determine to distinguish between lights and occluders" "3479": "Spatial Partitioning of Lights" "3797": "Upgrade our lighting_box spatial hierarchy for gathering four lights and distinguish between lights and occluders, replacing its Emission and TextureIndex values with a LightBoxD array in lighting_solution" "4301": "Make PushOccluder() set IsLight to 0, and redo PushLight() based on that function instead setting IsLight to 1" "4420": "Fix compile errors in SplitBox() and UpdateAndRenderEntities()" "4576": "Make RayCast() conditionally set the HitEmission to 1.0 or 0.0f for lights and occluders respectively, with deep considerations on efficiency" "5045": "Find that all remains well" "5063": "Toggle on the PushLight() call in UpdateAndRenderWorld()" "5112": "Check out our pushed light, being occluded at the top of the hero's hop" "5150": "Set up TestCastFromProbes() to distinguish between lights and occluders" "5230": "Find that our light–occluder distinguishing does not work" "5251": "Enable IsTestCast in TestCastFromProbes() to highlight ray hits" "5406": "Find that our light–occluder distinguishing now works" "5477": "Introduce GetSpatialLeafForP() to gather light from the spatial hierarchy" "5909": "Make TestCastFromProbes() call GetSpatialLeafForP(), and rename LightBoxP to LightBoxTargetP in lighting_solution" "6064": "Slightly rewrite GetSpatialLeafForP() to return a u32 rather than a lighting_box pointer" "6159": "Fix compile error in TestCastFromProbes()" "6192": "Determine to gather our light from the spatial hierarchy" "6227": "Check out our uninitialised light" "6239": "Investigate why we saw the light move" "6283": "Consider our lighting to be buggy" "6302": "Begin to enable BuildSpatialPartitionForLighting() to insert lights into the hierarchy, introducing InsertLight()" "6741": "Consider tabling our spatial hierarchy lighting gather for tomorrow" "6835": "Make BuildSpatialPartitionForLighting() fill LightBoxTargetP with the DebugLightP" "6901": "Verify that the LightBoxTargetP filling works" "6909": "Disable IsTestCast in TestCastFromProbes()" "6934": "See our test lighting, without the spatial hierarchy lookup" "6956": "Q&A" "7043": "Q: You're returning 0 instead of Result in the function you created to find the box" "7065": "Fix GetSpatialLeafForP() to return Result" "7083": "Q: Not sure how relevant, but the problem seems related to importance sampling lights in Monte Carlo ray tracers" "7183": "Q: What lessons did you learn from implementing Handmade Hero's debug inspection system?" "7275": "Q: Yes! Follow up question incoming..." "7329": "Q: Are there any performance impacts to storing large arrays of data as static global constants?" "7450": "Q: Is a non-trivial part of the difficulty the inherent limitations of C (you originally had to implement various metaprogramming tooling) or is the ideal system you want just inherently complex?" "7492": "Q: Do you use OpenGL?" "7602": "Q: Will you add lights separately, or bundle it with other objects in the scene (like lamps, for example)?" "7694": "Q: Not a question, but just wanted to tell you. Lost two daughters (twins) due to a freak accident, and binging Handmade Hero helped a lot with managing the loss during the hardest time. You help with more than you probably think" "7823": "Q: Do you think the current trend of dedicated ray tracing hardware is the right way to go for GPUs solving the lighting problem? Is there another route you would like to see?" "8076": "Q: I really like the platform and renderer setup you have. If your renderer needed to load files – for shaders or something, or had to allocate a lot of stuff – would you reimplement the platform specific functions in the renderer, or would you pass your platform API struct to the renderer initialise and use the ones your main executable implemented?" "8177": "Wrap it up" --- name: "day571" title: "Adding a Light Hierarchy" markers: "2": "Recap and set the stage for the day" "49": "Acquaint us with the problem of targeting and gathering nearby light sources" "228": "Consider making a data structure for figuring out which directions to cast our rays" "336": "Closest Light Query" "354": "Light Cuts" "775": "Introduce light_node" "943": "Modify lighting_solution to remove LightBoxTargetP and add RootLightBoxIndex, and begin to make BuildSpatialPartitionForLighting() build trees of occluders and lights" "1516": "Walk through SplitBox()" "1666": "Fix compile errors in BuildSpatialPartitionForLighting()" "1698": "Consider using the root light box to cast against, and continue to walk through SplitBox()" "1832": "Make SplitBox() set an accumulated RefC" "2002": "Consider initialising the root occluder and light boxes' RefC" "2142": "Introduce CalculateRefC() for BuildSpatialPartitionForLighting() to initialise the root boxes' RefC" "2337": "Rename GetSpatialLeafForP() to GetLightLeafForP() and make it query for the (not guaranteed) closest light source" "2697": "Introduce GetDistanceToBoxSq() and GetClosestPointInBox()" "3223": "Make GetLightLeafForP() call GetDistanceToBoxSq() properly" "3297": "See that our light is kind of busted" "3385": "Step in to TestCastFromProbes() and inspect our Solution" "3425": "Step through GetLightLeafForP() and watch what it does" "3453": "Fix BuildSpatialPartitionForLighting() to pass ActualLightCount to the lights' SplitBox()" "3511": "Step back in to GetLightLeafForP() and still see a ChildCount of 2" "3530": "Step through BuildSpatialPartitionForLighting() with an ActualLightCount of 8, and on through GetLightLeafForP()" "3774": "Stop BuildSpatialPartitionForLighting() from setting RootBoxIndex from AddBoxReference(), and +1 to the Source in light boxes' SplitBox() call" "3815": "See that we're still busted" "3830": "Make GetLightLeafForP() draw its spatial hierarchy walk" "4002": "See that our box spatial query is wrong" "4021": "Consider our problem to be in GetClosestPointInBox()" "4147": "Getting the closest point in a box" "4279": "Make GetLightLeafForP() call GetClosestPointInBox() directly, before itself then calling LengthSq()" "4315": "See that our box spatial query remains wrong" "4329": "Make GetLightLeafForP() draw the closest positions" "4395": "Check out our closest points, to see that it may actually be fine" "4460": "Scrutinise BuildSpatialPartitionForLighting()" "4551": "Fix BuildSpatialPartitionForLighting() to loop over the ActualBoxCount" "4606": "See that our spatial hierarchy remains misplaced" "4628": "Continue to scrutinise BuildSpatialPartitionForLighting() and SplitBox()" "4925": "Augment lighting_solution with a ScratchC for BuildSpatialPartitionForLighting() to use" "4973": "See that our spatial hierarchy is now correctly placed and queried" "5017": "Prevent CompileZBiasProgram() from disabling the lighting" "5040": "Admire our lighting" "5121": "Work on reading our test sphere, removing CubeSideWeight from light_sampling_sphere and Weights from sphere_store, and related code" "5265": "Prepare to invoke hhsphere" "5346": "Invoke hhsphere" "5565": "Invoke hhsphere in release mode" "5586": "Admire our generated handmade_sampling_sphere.inl" "5617": "Determine to implement ComputeVoxelIrradianceAt() and make BuildSpatialPartitionForLighting() preserve voxel contents" "5886": "Set up ComputeLightPropagationWork() to read from our light sphere, picking one random point on a light source" "6248": "Determine to figure out how to update our voxel field" "6296": "Q&A" "6422": "Q: What is the go to assembler for 64-bit code on Windows these days? Is MASM still maintained, people moving to NASM, something else?" "6667": "Q: If I buy RemedyBG now, will I also get access to upcoming versions of it or just the current and past ones?" "6676": "Q: Do you think with all recent processor vulnerabilities being found that future processors will use a fundamentally different optimizing architecture?" "6864": "Q: What's the go to thing for learning assembly" "6893": "Q: If assemblers were better would you consider programming in x86 / ARM directly (which ever you are trying to target primarily) for everything? Maybe it would auto translate on the backend and you could rewrite critical sections for secondary platforms" "7019": "cmuratori Do you know of a write-up similar to 'How to avoid C/C++ runtime on Windows' by Mārtiņš Možeiko on the Handmade Hero forum, but for Linux?" "7052": "Wrap things up" --- name: "day572" title: "Scrolling the Lighting Voxel" markers: "2": "Recap and set the stage for the day" "79": "Demo the current state of our lighting solution" "207": "Switch to the test sphere path in EndLightingComputation()" "323": "Demo our test light-field interpolation" "379": "Disable trilinear blending in OpenGLInit()" "433": "Demo the coarseness of our lighting storage resolution" "456": "Re-enable trilinear blending in OpenGLInit()" "474": "Demo our beguilingly smooth test light-field interpolation" "524": "Switch to the test transfer path in EndLightingComputation()" "531": "Briefly demo our ray casting to the closest light source" "553": "Describe TestCastFromProbes()" "630": "Make TestCastFromProbes() only use the light above the hero's head, to aid testing" "651": "Demo the ray casting to our single light source, considering blending of light sources and secondary bounces" "922": "Embark on delayed light blending, first preventing TestCastFromProbes() from clearing the voxel of lighting information" "950": "See that our light stops getting updated in areas we leave" "998": "Make TestCastFromProbes() and SpamVoxelSlice() decay and accumulate light across frames, augmenting lighting_solution with IrrBlendU and IrrBlendV" "1298": "Check out our delayed, but over-bright lighting" "1336": "On the need to weight our light accumulation to prevent over-brightness" "1466": "Introduce light_computation_cell for lighting_solution to contain as NewCells, augmenting light_voxel_cell with TotalWeight, LightCAccumulator and LightNAccumulator" "1584": "Make TestCastFromProbes() stably accumulate, blend and clear our lighting across frames, and SpamVoxelSlice() preserve the weighting" "1873": "Check out our lagged and not over-bright light blending" "1938": "Let TestCastFromProbes() ray cast from the entire spatial hierarchy" "1953": "Check out our (incorrect) blending of multiple light sources, noting that our lighting voxel is not pinned to the world" "2110": "Reacquaint ourselves with BeginLightingComputation()" "2139": "Check out our two lighting voxel bounds" "2228": "Scrolling the Lighting Voxel: Aligning and pinning it to the world" "2406": "Enable the checkerboard path in EndLightingComputation(), and disable trilinear filtering in OpenGLInit()" "2450": "Check out the varying alignment of our light voxel in the world" "2559": "Make BeginLightingComputation() align our light voxel in the world" "2692": "Check out our consistently aligned light voxel in the world" "2723": "Spot some possible X-fighting or a voxel edge sampling bug" "2777": "Distinguish between voxel–world alignment and placement consistency" "2858": "Switch to the test transfer path in EndLightingComputation()" "2899": "Check out the light transfer with inconsistent voxel placement" "2931": "Make BeginLightingComputation() identify the need to maintain consistent voxel placement across frames, augmenting lighting_solution with LastOriginP and introducing a v3s version of Hadamard()" "3471": "Check out the non-copied, but ready lighting" "3500": "Break in to BeginLightingComputation() and inspect our voxel placement preservation values" "3624": "Begin to make BeginLightingComputation() consistently position light voxel data in Y across frames" "3786": "Voxel Scrolling" "4061": "Make BeginLightingComputation() consistently position light voxel data in Y" "4480": "Hit an access violation in BeginLightingComputation()" "4498": "Fix typo in BeginLightingComputation()" "4574": "Hello, puss!" "4630": "Find that our voxel copy did not work correctly" "4701": "Fix two more typos in BeginLightingComputation()" "4795": "Hit an access violation in BeginLightingComputation()" "4815": "Unfix typo in BeginLightingComputation()" "4846": "Admire our stable downward copy, but broken upward copy" "4870": "Toggle off the upward copy in BeginLightingComputation()" "4890": "Check out the supposed downward copy" "4908": "Toggle off the downward copy in BeginLightingComputation()" "4921": "Find that the downward lighting does not go to black" "4957": "Toggle on the downward copy in BeginLightingComputation()" "4969": "Consider the downward copy to be continuous" "4984": "Fix the upward copy in BeginLightingComputation()" "5275": "Admire our light, stably copied in Y" "5317": "Begin to compress the voxel copying routine in BeginLightingComputation()" "5365": "Find that nothing changed" "5374": "Continue to compress the voxel copying routine in BeginLightingComputation()" "5577": "Find that that doesn't work at all" "5584": "Fix the upward clearing loop in BeginLightingComputation()" "5596": "Find that it's working" "5605": "Complete the compression of our voxel copying routine in BeginLightingComputation()" "5728": "Hit an access violation in BeginLightingComputation()" "5742": "Fix the voxel copying routine in BeginLightingComputation() to set the InitialY anew each time through" "5764": "Find that nothing changed" "5781": "Make BeginLightingComputation() consistently position light voxel data in X and Z" "6078": "Find that the voxel placement is not consistent in X" "6094": "Fix the voxel copying in X and Z" "6128": "Admire our consistently placed voxel" "6162": "Introduce BlockCopyVoxel(), and try writing it more and more succinctly" "6621": "Q&A" "6671": "Re-enable trilinear blending in OpenGLInit()" "6686": "Admire our blended and consistently placed light voxel" "6828": "Q: handmadehero.org time did not reflect the correct start time. What happened?" "6898": "Q: I'm really early in the episodes, only just finished 10. Reviewing where you are at now, what are some libraries that are added so I can study before I get to the episode they are added, i.e. OpenGL or something along those lines?" "6982": "Q: Care to give a guess completion percentage on the "final" lighting solution?" "7115": "Q: I'm exploring spatial grids for collision detection and am finding it challenging to reason about how to handle collision responses. Do you have any tips for using that sort of data structure as opposed to the usual trees (kd, quad, oct, etc.)?" "7229": "Q: Don't you normally need to put colliders inside the grid and somehow map those to entities, or perhaps enqueue into a procedure that handles the collisions? I guess more precisely, what is the pipeline for using the grids in the first place?" "7292": "Q: What episode do you talk about the blending problem you are facing? Not sure what you mean. Like color blending or some numerical blending?" "7449": "Wrap it up" --- name: "day573" title: "Wiring Up Light Transport" markers: "0": "Welcome to the stream" "40": "Demo the current state of our blended and stably positioned light" "172": "Set up to sample the voxel lighting like in the pixel shader" "250": "Begin to make ComputeVoxelIrradianceAt() sample the voxel lighting, and introduce GetIrradiance(), both based on the CompileZBiasProgram() pixel shader" "383": "Make ComputeVoxelIrradianceAt() take an Incidence query parameter, considering angular specularity" "530": "Set up ComputeVoxelIrradianceAt() to sample vector 3s" "565": "Change GetIrradiance() to take a LightColor directly" "611": "Fix compile errors" "677": "Embark on reimplementing OpenGL's texture() function in ComputeVoxelIrradianceAt()" "1003": "Voxel Sample" "1144": "Make ComputeVoxelIrradianceAt() pick the correct voxels to sample from, introducing LookUpVoxelClamped()" "1375": "Make ComputeVoxelIrradianceAt() sample four light normals and colours from our light field, introducing TriLerp()" "1583": "Trilinear blending" "1620": "Implement TriLerp()" "1753": "Implement LookUpVoxelClamped()" "1896": "Fix compile errors" "1938": "Make ComputeLightPropagationWork() pass the SampleD to ComputeVoxelIrradianceAt(), and consider doing the latter in SIMD" "2068": "Switch EndLightingComputation() to call our real ComputeLightPropagation()" "2176": "Hit an access violation error in ComputeLightPropagation()" "2186": "Switch ComputeLightPropagation() to operate single-threaded" "2277": "Hit an access violation error in ComputeLightPropagation()" "2301": "Restrict ComputeLightPropagationWork() to sample the one closest light, using GetLightLeafForP()" "2361": "See black" "2387": "See black in release mode" "2400": "Begin to investigate our blackness" "2504": "Step in to ComputeLightPropagationWork() and inspect the LightC" "2571": "Make EndLightingComputation() accumulate the lighting always" "2602": "See our crazily lit scene" "2640": "See our crazily and briefly lit scene in release mode" "2650": "Make ComputeLightPropagationWork() only perform moonlight transfer" "2711": "See bright ambient light" "2759": "Fix ComputeLightPropagationWork() to correctly weight the lighting" "2918": "See our ambient light darken" "2931": "Shift our MoonColor into the visible range in ComputeLightPropagationWork()" "3016": "Find that our location influences the ambient light" "3102": "Make ComputeLightPropagationWork() normalise the light direction" "3176": "Find that the ambient light looks more moonlight-y" "3246": "Let ComputeLightPropagationWork() perform the full light transfer" "3257": "Watch our lighting blow up, possibly due to NaN" "3304": "Scrutinise ComputeLightPropagationWork()" "3414": "Debug our TransferPPS and LightP, introducing LooksFishy()" "3545": "Break in to ComputeLightPropagationWork() on a supposedly fishy LightP" "3613": "Debug our ProbeSampleP, not LightP" "3623": "Break in to ComputeLightPropagationWork() on a fishy TransferPPS" "3882": "Make SpamVoxelSlice() use the LightDF directly as the LightA, without boosting the intensity" "3920": "See black" "3963": "See black and then craziness, in release mode" "4018": "Make EndLightingComputation() normalise our light normals" "4082": "See crazy lighting" "4107": "Consider clamping our light irradiance" "4224": "Try making EndLightingComputation() use a known stable normal" "4267": "See crazy lighting with stable normals" "4279": "Try instead making EndLightingComputation() use a known stable colour" "4379": "See bizarre, but flicker-free lighting" "4391": "Try also making EndLightingComputation() use a known stable normal" "4407": "See ordinary lighting" "4415": "Let EndLightingComputation() pack the actual normals" "4422": "Traverse the world, trying to make sense of our normals" "4502": "Begin to investigate our weird colours and normals" "4598": "Prevent SpamVoxel() from spamming out to all the slices" "4652": "Consider our lighting to be close to being good" "4723": "Switch EndLightingComputation() to call TestCastFromProbes()" "4738": "See our test cast lighting, without flood-filling" "4821": "Add a switch in EndLightingComputation() for the known stable colour test" "4898": "See black" "4915": "Increase the LightC intensity eight-fold in TestCastFromProbes()" "4924": "See gapped lighting" "4952": "Increase the LightC intensity in TestCastFromProbes() from 8 to 10" "4968": "See questionably gapped lighting" "4988": "Restrict ComputeLightPropagationWork() to sample the one closest light, using GetLightLeafForP()" "5004": "See potentially sensible light" "5042": "Decrease the tIrradiancePreservation delay in EndLightingComputation()" "5056": "Check out our light" "5070": "Increase the tIrradiancePreservation delay in EndLightingComputation()" "5092": "Check out our light, with the determination to clean up our light encoding and perform flood filling to room edges" "5253": "Make IrradiancePack() encode our light to allow for "tailroom"" "5571": "Enable CompileZBiasProgram() to handle our light's new tailroom" "5751": "See more sane, but unfortunately shifting lighting" "5821": "Encode our light in 16 bits, changing IrradiancePack() to return a 64-bit value" "6093": "See striped lighting" "6121": "Fix OpenGLEndFrame() to submit a 16-bit texture for the lighting" "6149": "Still see shifting lighting" "6179": "Determine to figure out the light encoding later, and now submit it all as floats" "6498": "See non-shifting, but slower lighting" "6543": "Make CompileZBiasProgram() only sample one of the lights" "6564": "See that our lighting has sped back up" "6724": "Plan our next steps for the lighting: 1) Encoding; 2) Flood filling; 3) Voxel centering" "6852": "Q&A" "6906": "Q: Remind us why you #define internal static" "7128": "Q: Hey master Casey. Is there a way to suggest / home [hint] the processor that a branch is likely / not likely taken? Goal is to help with branch prediction" "7265": "Q: I was watching an early stream where you said something along the lines of "I've never worked on a commercial compiler". So, have you ever worked on a non-commercial compiler or something of the sort?" "7355": "Q: Not relevant to today's episode but what C / C++ books do you recommend for a beginner?" "7373": "Q: What's your guess on how much faster GPU trilinear sampling is compared to CPU side? Also, could you not bounce the light on GPU side and be faster even on non RTX cards? What are the reasons against doing that? Is it just to keep complexity at Handmade Hero scope?" "7524": "Q: It seems unlikely that Intel / AMD would change the default behavior of branch prediction, considering things like PGO and gcc __builtin_expect assume that behavior" "7560": "Q: Have you considered the fact that if you just said Handmade Hero had an AI based lighting solution you could say it was now done?" "7573": "Q: I understand you're doing a unity build in Handmade Hero. What is the meaning of internal in this scenario?" "7606": "Q: Hi! I got contacted by two companies to work as a C programmer. One job on numerical computing and data visualization, and the other one on cryptography. They also wrote to me that they have a hard time in finding people who are interested in the low level-ish programming. Do you think it is because the majority of people use python, java script or high level languages? I guess there is always a job if someone can do C and a bit assembly" "7660": "Q: When running Visual Studio with my executable as an argument I can't find the project properties window in which you would set #defines. Do you know why that happens?" "7688": "Q: Just catching up on the show again. What do we have left, other than lighting and actual gameplay?" "7812": "Q: Which features of C++ do you think are conducive to performance oriented programming and which do you think are detrimental and should be avoided? I noticed that you use default arguments sometimes, for example" "7862": "Q: When adding the normals together, doesn't immediately normalizing after each add make the result dependent on the order of the vectors? I guess NOZ(NOZ(NOZ(a) + b) + c) != NOZ(NOZ(NOZ(c) + b) + a) is what I am saying. (I don't remember the exact routine where you did this.)" "7993": "Q: As you remember we talked about Valve's ACO shader compiler that is replacing LLVM. I heard that it reduces the shader compile time significantly compared to LLVM. They said that it is great for the open source graphic's driver on Linux" "8018": "Q: Do you track light energy?" "8079": "Q: How is irradiance different from radiance?" "8186": "Radiance is per surface area per solid angle" "8224": "No, different units" "8292": "Q: Have you read Sean Barrett's post on anti-aliasing?" "8351": "Close it down" --- name: "day574" title: "Experimenting with Voxel Filters" markers: "1": "Recap and set the stage for the day making the ray caster produce a stable set of inputs to pass to the light field interpolater, with thoughts on multiple light fields" "325": "Show the current state of the lighting" "431": "Show the current state of the lighting, without filling in negative light values" "455": "Consult our lighting TODOs" "483": "Show the absence of light flickering, thanks to our switch to floats" "542": "Reorganise and consult our lighting TODOs" "568": "Demo our need to flood fill the voxel so that unsampled portions get filled in from nearby samples" "723": "Consider where is most appropriate to perform the flood filled interpolation" "784": "Consider whether or not the reconstructed edge lighting values should persist across frames" "922": "Consider our options for flood filling the lighting voxel: 1) Persistently in lighting_solution; 2) In EndLightingComputation() when: a) pushing the cells to the graphics card each frame; b) accumulating light contribution over time" "1153": "Determine to make EndLightingComputation() flood fill the lighting voxel when pushing the cells to the graphics card" "1236": "Seperable Filters" "1503": "Cache implications of our light voxel" "1844": "Propose constraining our flood fill filter to cells predetermined to require filtering" "1955": "Abortively augment game_render_commands with a FloodIndices array" "2154": "Begin to make EndLightingComputation() flood fill the lighting voxel with purple when pushing the cells to the graphics card, asserting that we're well inside the hot region" "2297": "Try unsuccessfully to trigger our hot region assertions" "2342": "Make EndLightingComputation() flood fill out to neighbour cells, introducing HasLight() and FloodLight()" "3778": "Directional Flood Filling" "3868": "Fix FloodLight() to correctly fill in positive and negative directions, before welding its code in to EndLightingComputation()" "4102": "Check out our partially working flood filling" "4132": "Make EndLightingComputation() flood fill with purple" "4163": "Check out our purple flood filling, and spot some erroneously unlit / interpolated areas" "4228": "Make CompileZBiasProgram() clamp the light to 0, introducing Clamp0Inf()" "4477": "Still see dead zones" "4549": "Make CompileZBiasProgram() normalise the LightN" "4572": "Still see dead zones" "4641": "Prevent EndLightingComputation() from flood filling with purple" "4647": "Still see dead zones" "4666": "Toggle on the purple in EndLightingComputation()" "4668": "Change HasLight() to base its decision on LightC, rather than LightN" "4702": "Still see dead zones" "4753": "Make EndLightingComputation() flood fill with yellow the cells that have light" "4789": "Find that all cells are lit either purple or yellow" "4811": "Comment out the yellow in EndLightingComputation()" "4818": "See our dead zones return" "4845": "Make HasLight() less permissive with a threshold" "4910": "See our dead zones flood to purple (i.e. unlit)" "4956": "Toggle off the purple in EndLightingComputation()" "4980": "Check out the interpolation across the light boundaries" "5020": "Scrutinise the directional flood fill interpolation code in EndLightingComputation()" "5112": "Directional Flood Fill Interpolation" "5193": "Scrutinise the light value lookup and clamping in CompileZBiasProgram()" "5321": "Closely look at the apparent interpolation bug" "5419": "Make EndLightingComputation() flood fill purple if the LightWeight is 0" "5442": "See some erroneously purple areas" "5491": "Scrutinise EndLightingComputation() for gather bugs" "5532": "Closely look at the erroneously purple areas" "5561": "Remove the threshold from HasLight() and ensure that EndLightingComputation() can blend down to 0" "5675": "Still see our interpolation artifacts" "5770": "Toggle off the final flood filling in EndLightingComputation()" "5783": "Still see our interpolation artifacts" "5818": "Try making EndLightingComputation() regularise our light normals" "5840": "See no interpolation bugs" "5870": "Toggle on the final flood filling in EndLightingComputation()" "5886": "See some very bizarre half-lit artifacts" "5959": "Investigate our half-lit artifacts" "6026": "Toggle off the whole flood filling code in EndLightingComputation()" "6040": "Check out our lighting without flood filling, and spot some discontinuity across a wall" "6089": "Try making EndLightingComputation() regularise our light normals as 0, 0, 1" "6124": "Find that this doesn't help us" "6131": "Try making EndLightingComputation() regularise our light normals as 0, -1, 0" "6143": "Find that our discontinuity has gone" "6153": "Let EndLightingComputation() compute each voxel's normal" "6164": "Wonder if the discontinuity is due to the normal interpolation being unable to properly swing" "6177": "Make CompileZBiasProgram() visualise the normal" "6251": "Determine that we are getting a 0, 0, 0 normal" "6291": "Prevent CompileZBiasProgram() from normalising the normal" "6313": "Find that the hard-edged 0, 0, 0 normal remains" "6321": "Make GetIrradiance() in CompileZBiasProgram() always visualise the normals" "6394": "Find that the hard-edged 0, 0, 0 normal is gone" "6411": "Explain the problem when the light and world normals are orthogonal" "6463": "Make GetIrradiance() in CompileZBiasProgram() modify its result by the LightDC, and not visualise the normal" "6496": "Find that our discontinuity remains" "6524": "Make GetIrradiance() in CompileZBiasProgram() visualise the normal, modified by the LightDC" "6569": "Find that our discontinuity remains" "6598": "Make GetIrradiance() in CompileZBiasProgram() visualise the LightDC" "6636": "See our discontinuity" "6649": "Ponder our discontinuity" "6710": "Disable trilinear interpolation in OpenGLInit()" "6740": "Check out our non-interpolated LightDC" "6800": "Scrutinise GetIrradiance()" "6867": "Make GetIrradiance() in CompileZBiasProgram() visualise the normal" "6895": "See smooth interpolation" "6901": "Make CompileZBiasProgram() visualise just the normal, without the textures" "6925": "Check out our normals, with no – or at least less – discontinuity" "7050": "Let CompileZBiasProgram() use the textures and not visualise the normals" "7059": "Check out our discontinuity" "7083": "Temporarily make CompileZBiasProgram() hard set the LightDC to 0.5" "7102": "Find that our discontinuity has gone" "7165": "Let CompileZBiasProgram() gather in some light from perpendicular sources" "7192": "Find that our discontinuity has really gone" "7270": "Re-enable the flood filling code in EndLightingComputation()" "7289": "See that our flood filling brightens the light" "7308": "Prevent EndLightingComputation() from hard setting the normal to 0, 0, 1" "7350": "See that our flood filling fills in some areas" "7403": "Take a close look at our flood filling" "7469": "Respecify HasLight() as a smoothly varying GetLightAmount() for EndLightingComputation() to use as a multiplier" "7678": "Find that our flood fill's popping artifacts have been fixed" "7727": "Make SpamVoxel() spam out to all voxel slices" "7767": "Check out the spamming (with flood filling)" "7798": "Toggle off the flood filling in EndLightingComputation()" "7808": "Check out the spamming (without flood filling)" "7877": "Find that the spamming does not capture negative light properly in the outdoor area" "7898": "Prevent SpamVoxelSlice() from clamping the light's distance falloff to 0 to 1" "7917": "See that we're still not getting negative light interpolation" "7970": "Prevent EndLightingComputation() from clamping the light values" "8033": "See that we're still not getting negative light interpolation" "8064": "Scan the code for any more 0-clamping" "8140": "Make CompileZBiasProgram() draw negative values in red" "8182": "See no negative values" "8204": "Scan the code for any more 0-clamping" "8286": "Add an assertion in SpamVoxelSlice that LightDF >= 0.0f" "8317": "Fail to hit that assertion" "8323": "Scrutinise the LightDF calculation in SpamVoxelSlice()" "8450": "Run the game afresh and successfully hit our assertion in SpamVoxelSlice()" "8453": "Comment out the assertion in SpamVoxelSlice()" "8467": "Take another look at our non-interpolation of negative light" "8504": "Make TestCastFromProbes() fall-off the light more steeply" "8517": "Admire our steeper light falloff, and wonder where our stair-step pattern is coming from" "8583": "Prevent CompileZBiasProgram() from drawing negative values in red" "8592": "Consider our entire falloff to not be that smooth" "8615": "Try making SpamVoxelSlice() set the light's alpha to the LightDF squared" "8673": "Admire our ring of light falloff" "8691": "Make SpamVoxelSlice() preserve the sign of the LightDF" "8703": "Check out our hard light falloff" "8718": "Try making SpamVoxelSlice() set the light's alpha to the LightDF square-root" "8732": "Check out our hard light falloff" "8738": "Revert SpamVoxelSlice() to setting the light's alpha to the LightDF" "8751": "Check out our hard light falloff" "8764": "Determine that we are doing ShaderSimTexWriteSRGB" "8865": "Temporarily prevent CompileZBiasProgram() from square-rooting the SurfaceReflect" "8892": "See that our light falloff is much smoother" "8909": "Revert CompileZBiasProgram() to square-rooting the SurfaceReflect, and try making SpamVoxelSlice() set the LightDist to LightN squared" "8972": "See a bizarrely octagonal light falloff" "8981": "Our problem: The falloff interpolation is being interpreted linearly" "9073": "Revert SpamVoxelSlice() to not square the LightN, and instead make GetIrradiance() in CompileZBiasProgram() square the LightV when setting the LightColor, introducing Square()" "9173": "Make SpamVoxelSlice() square the LightN when setting the LightDist, and GetIrradiance() in CompileZBiasProgram() preserve the sign" "9312": "See our brighter light" "9390": "Fix the sign-preservation in GetIrradiance() in CompileZBiasProgram()" "9404": "See our falloff" "9433": "Make SpamVoxelSlice() square-root the LightC0, introducing SignedSquareRoot()" "9503": "Admire our softer falloff" "9518": "Make TestCastFromProbes() fall-off the light more gradually" "9543": "Admire our softer, yet wobbly falloff" "9576": "Make TestCastFromProbes() darken the LightC" "9585": "Admire our darker light, but doubt that the falloff is softer" "9660": "Make TestCastFromProbes() further darken the LightC" "9663": "Admire our darker light" "9686": "Toggle off the square-rooting / squaring" "9723": "Check out our less gradual light falloff" "9772": "Make TestCastFromProbes() brighten the LightC" "9784": "Check out our brighter and less gradual light falloff" "9856": "Q&A" "9889": "Q: Solution->HasCornerI.x + X + 2*dZ" "9910": "Fix typo in EndLightingComputation() and toggle on the flood filling" "9925": "Check out the blotchy flood filling" "9975": "Toggle off flood filling" "9983": "Consider our flood filling not to be close to working" "10024": "Damn, it wasn't that" "10109": "Wrap it up" --- name: "day575" title: "Generalizing Code Reloading" markers: "2": "Welcome to the stream with an apparently successful build of TensorFlow" "125": "Recap the current state of our lighting" "148": "Demo our current lighting" "225": "Determine to hook up the in-game audio recording" "253": "Consider going over the lighting with a fine tooth comb for some weeks, before leaving it with a view to maybe coming back to it at the end" "372": "Note that our lighting hierarchy and ray caster are working okay, but the summation and frame-to-frame persistence needs work" "474": "Consider giving our lighting values some real-world meaning, adding an exposure function, and creating debug visualisation" "601": "Set up to make the renderer hot reloadable" "833": "Begin to generalise code reloading, introducing win32_loaded_code for win32_game_code to contain, and win32_renderer_code" "1056": "Introduce WIN32_LOADED_CODE_ENTRY_POINT and win32_game_function_table" "1259": "Remove win32_game_code with a view to switching Win32LoadGameCode() over to use our new win32_game_function_table and win32_loaded_code structs" "1322": "Introduce Win32GameFunctionTableNames[] for Win32LoadGameCode() to lookup into for its GetProcAddress() calls, augmenting win32_loaded_code with FunctionCount, FunctionNames, Functions and TempDLLNumber" "1899": "Update Win32UnloadGameCode() and WinMainCRTStartup() to use our new win32_loaded_code and Win32LoadCode()" "2102": "Consider welding win32_state into win32_loaded_code" "2255": "Augment win32_loaded_code with FullPath and LockFullPath" "2334": "Introduce Win32CheckForCodeChange() and Win32ReloadCode() for WinMainCRTStartup() to call, renaming win32_loaded_code.FullPath to DLLFullPath" "2695": "Fix compile errors" "2759": "The code loading works" "2779": "Make UpdateAndRenderWorld() position the DebugLightP higher up" "2812": "Verify that the code reloading works" "2819": "Make UpdateAndRenderWorld() position the DebugLightP as before" "2824": "Verify that the code reloading works" "2835": "Move onto making the renderer hot reloadable" "2959": "Introduce Win32RendererFunctionNames[] in the renderer, move Win32InitDefaultRenderer() into win32_renderer_test.cpp and weld Win32LoadRendererDLL() into it" "3161": "Introduce win32_renderer_function_table" "3269": "Q: You can turn off the "assign with conditional expression" warning / error" "3289": "Make WinMainCRTStartup() push win32_handmade_opengl.dll and lock.tmp through Win32BuildEXEPathFileName(), updating build.bat for renderer hot reloading" "3642": "Update WinMainCRTStartup() to load the renderer using Win32LoadCode()" "3845": "The renderer code loading works" "3851": "Set up to reload the renderer" "4011": "Augment win32_renderer_function_table with BeginFrame and EndFrame, making build.bat export Win32BeginFrame() and Win32EndFrame(), and WinMainCRTStartup() operate on RendererFunctions" "4230": "Weld Win32InitDefaultRenderer() into RenderLoop()" "4370": "Verify that the renderer test loads" "4399": "Verify that Handmade Hero loads" "4423": "Enable WinMainCRTStartup() to reload the renderer" "4574": "Run the game" "4594": "Make OpenGLEndFrame() set the glClearColor to 1, 0, 1, 1" "4632": "Hit a "User-mode data execution prevention (DEP) violation"" "4699": "Make WinMainCRTStartup() handle not-loaded renderer, checking that RendererCode.IsValid before calling RendererCode.EndFrame(), and also issuing an "Unable to load renderer" fatal error" "5222": "Crash on OutputPlayingSounds()" "5247": "Fix WinMainCRTStartup() to correctly set the Frame" "5275": "Run the game" "5282": "Recompile" "5286": "Hit a "User-mode data execution prevention (DEP) violation"" "5326": "Try to step in to Win32ReloadCode()" "5393": "Run in debug mode, recompile and break on the RenderCode Win32ReloadCode() call, to find that the problem is in OpenGLEndFrame()" "5597": "Try unsuccessfully to break on Win32ReloadCode()" "5718": "Recompile and break on Win32ReloadCode(), then hit our "User-mode data execution prevention (DEP) violation" before entering OpenGLEndFrame()" "5775": "Rerun and find that our breakpoint no longer works" "5805": "Check build.bat for buggy reloading" "5860": "Recompile without RemedyBG running, step on to OpenGLEndFrame() and find the Renderer to be invalid" "6047": "Build afresh, run the game and rebuild, and step to Win32ReloadCode() to find that the Platform pointer is already NULL" "6145": "platform_renderer.TotalFramebufferMemory // TODO(casey): Reenable this!" "6184": "Continue to step through Win32LoadCode() to find that it pushes handmade_temp.dll through Win32BuildEXEPathFileName()" "6216": "Augment win32_loaded_code with TransientDLLName for Win32LoadCode() to use" "6449": "Build afresh, run the game and rebuild, to still hit the "User-mode data execution prevention (DEP) violation"" "6492": "Continue to step through Win32LoadCode(), inspect the TempDLLName and realise that it always fails to copy once" "6616": "Fix Win32LoadCode() to increment TempDLLNumber before every attempt to Copy" "6704": "Continue to step through Win32LoadCode() and on through OpenGLEndFrame(), to hit our "User-mode data execution prevention (DEP) violation" on glBindBuffer()" "6820": "Find that our RemedyBG breakpoint issue is unresolved" "6859": "Remove the *temp.dll files" "6878": "Run and rebuild the game, watching the *temp.dll files be created" "6952": "Get a new dotahero" "7003": "Ponder RemedyBG's breakpoint confusion" "7066": "Wonder why we're jumping to an unknown function" "7097": "Run, rebuild, step in to OpenGLEndFrame() and inspect the OpenGL struct" "7191": "Remember that our OpenGL functions reside in a dll-local table, and must be reinitialised" "7292": "Augment open_gl with our OpenGL functions, renaming OpenGLGlobalFunction() to OpenGLFunction()" "7703": "Make our OpenGL context available to all OpenGL-calling functions, and Win32InitOpenGL() initialise our OpenGL functions" "8224": "Make PlatformOpenGLSetVSync() initialise wglSwapIntervalEXT specially" "8367": "Run and rebuild the game successfully" "8421": "Prevent OpenGLEndFrame() from setting the glClearColor to 1, 0, 1, 1" "8443": "Hot-reload the game successfully" "8457": "Make OpenGLEndFrame() halve the RenderWidth" "8476": "Hot-reload the game successfully" "8485": "Prevent OpenGLEndFrame() from halving the RenderWidth" "8490": "Hot-reload the game successfully" "8513": "Q&A" "8566": "Q: A lighting question (but it also has applications in meteorology): Do you know of any algorithms to compute "shadow" or "no shadow" for all future February 2nds (assuming Gregorian calendar), or are we simply stuck with the Punxsutawney Phil algorithm, the current but rather limited state of the art?" "8608": "Q: Sorry, I missed it. What did you use TensorFlow for?" "8624": "Q: Is not faster to load shader from file and change them on the fly when the file is modified?" "8656": "Q: Khronos org says that we should load procs by wglGetProcAddress and, if it fails, then load library opengl32.dll and GetProcAddress. In which situations is it relevant? Or I missed something?" "8686": "Q: Would you recommend the OpenGL struct function table for versioned C libs?" "8716": "Q: If you wanted to implement Stereoscopic 3D, are there OpenGL functions specifically for that (making it easier) or would you have to do everything manually?" "8829": "Q: You mentioned there being no standard way to interface with graphics and the politics behind it. Do you see a specific reason why console manufacturers couldn't push hardware vendors for standardisation and have that standard bleed out into general computing?" "8899": "Q: If it matters, I once implemented a network in C++ from TensorFlow and it was faster single threaded by order of magnitude compared to the 28 core multithreaded TensorFlow implementation" "8937": "handmade_hero Is the same OpenGL context being used after renderer reload?" "8994": "Q: For APIs with the requirement of being downwards compatible and introducing breaking changes is only allowed in a second API struct" "9123": "Q: Tomorrow is my first day of work at a AAA company. How do I jump into a huge codebase (UE4) that I know very little of? I am a little bit intimidated also by the "object-orientedness" of the engine" "9441": "Q: Have you heard of IPFS? I know you don’t like web stuff, but IPFS seems to be redesigning the web to be content-addressed and simpler... It doesn't get rid of HTML and all that crap but I think it’s a step forward. What do you think of it?" "9492": "IPFS: Interplanetary file system. A decentralized file system which is Hash Based Mapping on the Nodes on the network for file lookup rather than the location of a file" "9706": "Take a look: IPFS" "9829": "Yeah, There's more to it. Take a look at the Whitepaper. It is cool" "10060": "handmade_hero Are they even trying to solve that problem? It appears they are trying to make an extremely public file system" "10106": "Q: I think that no single node on the network has 100% of a file, so you can only request an incomplete fragment, which will make it harder for the node hosting it to guess what it is" "10256": "Q: (Again off-topic) Do you know some (good) resources that explains how the internet works? You said that it cannot be used as a backbone of internet, but I don't understand why" "10494": "Close it down" --- name: "day576" title: "Octahedral Encoding" markers: "4": "Recap our generalised hot reloading and set the stage for the day" "163": "Set up to recompile shaders when reloading the renderer" "273": "Augment game_render_settings with Version, for WinMainCRTStartup() to increment and trigger shader recompilation" "591": "Run the game" "609": "Toggle off / on PushDebugBox() and watch it hot reload" "639": "Make CompileZBiasProgram() hard set the SurfaceReflect.r to 1.0" "675": "See the shader recompilation take effect" "682": "Revert CompileZBiasProgram() to set the correct SurfaceReflect.r and see it hot reload" "734": "Decide against flood filling the lighting voxel" "957": "Spherical Harmonics" "1286": "A few words on DuckDuckGo's technical searches" "1334": "Research Spherical Harmonics truncation" "1559": "Consult Peter-Pike Sloan's 'Efficient Spherical Harmonic Evaluation'" "1903": ""Reconstruction of a HDR light probe into order 1 to 6 Spherical Harmonics"" "2155": "Consult 'Dynamic Diffuse Global Illumination with Ray-Traced Irradiance Fields'" "2510": "Consult the Code and Video supplement of 'Dynamic Diffuse Global Illumination with Ray-Traced Irradiance Fields'" "3260": "Consult 'Survey of Efficient Representations for Independent Unit Vectors' with octahedral.glsl from the Code and Video supplement of 'Dynamic Diffuse Global Illumination with Ray-Traced Irradiance Fields'" "4007": "Admire Octahedral Encoding" "4143": "Consider the cage building part of Octahedral Encoding" "4366": "Consider edge-wrapping in Octahedral Encoding, using an atlas rather than a texture array" "4566": "Octahedral Encoding: Wrapped Sampling" "4795": "It is flipped" "4823": "Octahedral Encoding: Edge Orientation" "4975": "Research the wrapping modes of glTexParameter" "5071": "Research Cage Sampling in Octahedral Encoding" "5348": "Q&A" "5414": "Q: What is tomorrow?" "5448": "Q: Are you preferring Chrome over Firefox? And if yes, what's the reason?" "5473": "Question: You mentioned on Twitter you were building a Learn to Program course. Can you tell us more about it?" "5580": "Q: How has the sparse entity system been? Has there been any drastic modification to it?" "5640": "Q: You can include the string "!g" in a DuckDuckGo query to get google search results" "5696": "Q: There are some Spherical Harmonics implementations on shadertoy.com you could look at. Don't know if something like this helps" "5751": "Q: So what is entity cache?" "5861": "Q: Basically cache tables?" "5935": "Google vs DuckDuckGo" "6232": "Get some lunch" --- name: "day577" title: "Adding Octahedral Light Atlases" markers: "4": "Recap last stream's Octahedral Encoding paper research and set the stage for the day" "118": "Consider Octahedral Encoding: Texture Array vs Atlas" "423": "Skim read 'Dynamic Diffuse Global Illumination with Ray-Traced Irradiance Fields'" "655": "Consult IrradianceField.cpp from the Code and Video supplement of 'Dynamic Diffuse Global Illumination with Ray-Traced Irradiance Fields'" "856": "Embark on Octahedral Encoding: 1) Setup Texture Atlas; 2) Draw Texture Atlas; 3) Place Octahedral Unwrapped Quads into the World" "999": "Build and run the game" "1016": "Augment open_gl with LightAtlasHandle" "1158": "Note the use of depth textures in 'Dynamic Diffuse Global Illumination with Ray-Traced Irradiance Fields'" "1323": "Modify open_gl replacing the texture array with Color and Depth texture atlases for Octahedral Encoding" "1653": "Consider our Octahedral Texture Atlas storage in open_gl" "1725": "Update OpenGLInit() to set up our new Octahedral Texture Atlases" "1874": "Calculate the storage (and GPU-submission) requirements of our Octahedral Texture Atlas: 32^3*10^2*4 = 13,107,200 bytes" "2131": "Continue updating OpenGLInit() to set up our Octahedral Texture Atlases" "2392": "Update OpenGLBeginFrame() and game_render_commands in line with our new Octahedral Texture Atlases" "2481": "Update OpenGLEndFrame() to bind and use our new Octahedral Texture Atlases, doubling the X dimension" "2863": "Set up CompileZBiasProgram() to use our new Octahedral Texture Atlases" "3086": "Update EndLightingComputation() in line with our new Octahedral Texture Atlases" "3116": "Hit OpenGL Error "GL_INVALID_ENUM"" "3195": "Fix GL_TEXTURE_3D to GL_TEXTURE_2D in OpenGLInit()" "3244": "Hit OpenGL Error "GL_INVALID_ENUM"" "3288": "Fix GL_R to GL_RED in OpenGLInit()" "3298": "Hit exception "Access violation reading location"" "3341": "Step through to OpenGLEndFrame()" "3433": "Fix OpenGLEndFrame() to pass GL_RED rather than (the larger) GL_RGB to glTexSubImage2D()" "3454": "Run the game without lighting, with the determination to output standard spherical lighting into octahedrons" "3510": "Introduce OctahedralFromUnitVector() and UnitVectorFromOctahedral()" "3871": "Explain the Octahedral wrap / unwrap" "3955": "Continue to implement OctahedralFromUnitVector() and UnitVectorFromOctahedral()" "4310": "Octahedral to Unit" "4645": "Solving the Octahedral to Unit equation" "4828": "Understanding the Octahedral to Unit mapping diagrammatically" "5052": "How to solve the Octahedral to Unit equation if we know Oz²" "5177": "Finish implementing UnitVectorFromOctahedral()" "5515": "Check our implementation with 'Dynamic Diffuse Global Illumination with Ray-Traced Irradiance Fields'" "5606": "Fix the swizzle in UnitVectorFromOctahedral() in line with 'Dynamic Diffuse Global Illumination with Ray-Traced Irradiance Fields'" "5695": "Modify light_voxel_cell for Octahedral Encoding" "5882": "Stub out ComputeVoxelIrradianceAt(), SpamVoxelSlice(), GetLightAmount() and EndLightingComputation() for Octahedral Encoding" "6101": "Toggle to TEST_LIGHT_SPHERE in EndLightingComputation() and implement that path for Octahedral Encoding" "7022": "Run the game" "7068": "Capture a frame in RenderDoc" "7274": "Fix the ElIndexC and ElIndexD computations in EndLightingComputation()" "7510": "Capture a frame in RenderDoc" "7574": "Q&A" "7609": "Q: Quick note, you overwrite the x value which is used for the y value with encoding / decoding octahedrals" "7621": "Fix UnitVectorFromOctahedral() to use O.x and O.y in the Ox and Oy settings" "7655": "And I think the Oz doesn't need to be negated in the UnitVectorFromOctahedral() function" "7738": "Q: Does it always have to be positive?" "7763": "Fix UnitVectorFromOctahedral() to set the Result from Ox, Oy and Oz" "7771": "Fix OctahedralFromUnitVector() to compute Ox and Oy as temporary variables" "7818": "Q: If 1 - SumXY is less than 0, then Oz would already be negative" "7849": "Prevent UnitVectorFromOctahedral() from negating Oz" "7873": "Q: Reference code uses a "signNotZero" function instead of "signOf"" "7920": "Q: I think you have a typo on the Trilerp code where you index by [Ty][Ty] and [Tx][Tx] instead of [Ty][Tx] in both places" "7937": "Q: But it's returning positive for 0" "7953": "Q: It should return 0 for 0" "8122": "Q: I think you have a typo on the Trilerp code where you index by [Ty][Ty] and [Tx][Tx] instead of [Ty][Tx] in both places" "8151": "Q: Another RenderDoc image?" "8164": "Capture a frame in RenderDoc" "8219": "Q: Is Oxy supposed to be mapped between 0 and 1 or -1 and 1 in the setup light code?" "8271": "Fix EndLightingComputation() to map Oxy from -1 to 1" "8334": "Capture a frame in RenderDoc" "8388": "Q: If it's okay to ask something off-topic? Why aren't more engines using dynamic .dll / .so for hot-deployment of game code?" "8411": "Q: Do you find it annoying to keep hopping between editor and debugger when you are programming? In your ideal environment would these two tools be unified in the same window?" "8496": "Q: Could be a good idea to add to the debug system a way to look at the OpenGL texture? So we could switch less from the game?" "8511": "Q: Don't you think using a .cpp file instead of a batch file for build setup and configuration would be better since batch files are so bad?" "8539": "Q: Unreal only does it fairly recently using an external tool which cost them almost zero implementation effort" "8621": "Wind it down" --- name: "day578" title: "Sampling Octahedral Atlases" markers: "5": "Recap and set the stage for the day debugging and making meaningful our Octahedral Encoding" "193": "Show our unlit game" "270": "Prepare to draw our octahedral light map" "617": "Make OpenGLInit() generate octahedral light map vertices for the purposes of drawing them, augmenting open_gl with LightMapDebugBuffer" "888": "Make OpenGLEndFrame() draw our octahedral light map vertices" "991": "See our light map vertices covering the whole screen" "1022": "Investigate why our light map vertices cover the whole screen" "1108": "Make OpenGLEndFrame() end the FinalStretch program before binding the LightMapDebugBuffer and restarting the FinalStretch program" "1142": "See our light map vertices correctly located" "1240": "Make OpenGLInit() generate an enlarged central subset of our light map" "1531": "See our zoomed in light map vertices" "1585": "Make OpenGLInit() generate a square portion of the light map, adjusting for the window's aspect ratio" "1803": "Producing a square on a non-square window" "1912": "Make OpenGLInit() correctly invert the window's 16:9 aspect ratio" "1929": "See our square light map vertices" "1959": "Understanding the extraction of a square from a non-square" "2037": "Fix OpenGLInit() to extract a non-stretched square from the entire light atlas" "2085": "See our square (but empty) light map vertices" "2100": "Make OpenGLInit() generate a more readily adjustable proportion of the light map" "2157": "See our light map" "2171": "Make OpenGLChangeToSettings() generate the octahedral light map, so the debug visualisation may be hot-reloaded" "2258": "Adjust the octahedral light map drawing in OpenGLChangeToSettings()" "2462": "Take a good look at our octahedral light map" "2580": "Determine to carefully test the octahedral mapping" "2642": "Make OpenGLChangeToSettings() responsible for binding and setting the parameters of our light atlas textures" "2768": "Disable linear blending of the light atlas visualisation while running" "2832": "Make EndLightingComputation() draw all blue into our octahedral light map" "2902": "See all blue" "2916": "Make EndLightingComputation() colour the sampling directions per coordinate" "3017": "Check out our octahedral light map" "3036": "Make EndLightingComputation() differentiate between the positive and negative directions" "3130": "See that our light map does not look like an octahedron" "3163": "Make EndLightingComputation() draw the left–right in increasingly red and the up–down in green" "3226": "Check out our light map" "3261": "Make OpenGLChangeToSettings() zoom way in to our light map" "3287": "Check out our light map" "3317": "Make EndLightingComputation() shift our light colours into the 0 to 1 range" "3375": "See 10 steps in X, as expected, but only 5 in Y" "3394": "Investigate our apparent octahedral light map error in EndLightingComputation()" "3700": "Fix EndLightingComputation() to correctly stride through and populate the octahedral light map" "4016": "Make OpenGLChangeToSettings() zoom out and draw the bottom-left corner of the light map" "4062": "Check out our more correct light map" "4070": "Make OpenGLChangeToSettings() zoom in to the light map" "4089": "Make EndLightingComputation() populate the whole light map" "4210": "See our much more valid light map" "4214": "Make EndLightingComputation() colour the sampling directions per coordinate" "4253": "Check out our light map" "4290": "Make EndLightingComputation() leave a 1px border around each octahedron" "4374": "Check out our offset octahedral light map" "4472": "Step through EndLightingComputation() and inspect the Oxy" "4530": "Fix the 1px bordering in EndLightingComputation()" "4585": "Check out our more correct octahedral light map" "4646": "Make EndLightingComputation() produce a coloured octahedron" "4747": "See that our octahedron is not quite correct" "4817": "Make EndLightingComputation() just leave the z-blue of our octahedron" "4835": "See that our z-blue looks correct" "4860": "Make EndLightingComputation() just leave the x-red of our octahedron" "4868": "See that our x-red might be correct" "4894": "Make EndLightingComputation() just leave the y-green of our octahedron" "4907": "See that our y-green might be correct" "4911": "Let EndLightingComputation() draw the whole octahedron" "4915": "Check out our whole octahedron" "4925": "Toggle on our actual octahedral mapping in EndLightingComputation()" "4962": "Admire our octahedral light map" "5012": "Make OpenGLChangeToSettings() zoom out of the light map" "5033": "Admire our octahedral light map" "5081": "Determine to use the lighting" "5127": "4coder feature request: Syntax highlighting of here docs" "5188": "Make CompileZBiasProgram() sample our octahedral lighting" "6151": "Research OpenGL's sign() and the signNotZero() implementation in 'Survey of Efficient Representations for Independent Unit Vectors'" "6277": "Implement SignOf(), continuing to make CompileZBiasProgram() sample our octahedral lighting" "6351": "Hit shader errors" "6384": "Fix shader errors, stubbing out SampleLighting()" "6452": "Hit shader errors" "6470": "Fix typo in CompileZBiasProgram()" "6481": "Run successfully" "6516": "Q&A" "6563": "Q: Can you show the octahedral map with linear blending?" "6578": "Show the octahedral map" "6603": "Enable linear blending in OpenGLChangeToSettings()" "6652": "Show the blended octahedral map" "6682": "Q: Can you say a few words about octahedral mapping?" "6736": "Q: Kinda off-topic. Have you ever been at a point where you thought that programming might not be the right thing for you?" "7070": "Q: Have you ever used / heard of Spherical Gaussians before?" "7167": "Q: I remember we moved away from manual trilinear filtering on voxel samples because it was a lot of texture bandwidth. How is this better than the old approach?" "7314": "Q: Do you think step(x) * 2 - 1 could be faster than our current sign implementation?" "7381": "Q: Why is the depth not red squares?" "7456": "I think you just didn't apply the fix to the depth buffer" "7480": "Fix EndLightingComputation() to correctly stride through the depth buffer" "7508": "Check out our correct depth buffer" "7531": "Q: Do you have any opinion on potential new computing devices / platforms, i.e. "mobile" operating systems, tablets, multi screen devices, etc? Is there anything interesting going on, or are companies just throwing stuff at the wall?" "7546": "Q: What do you think of Carmack working on general AI? I hear he's going to use Sesame Street as the learning data" "7607": "Q: Some people have probably already mentioned this but it'd be cool to see more handmade chats / talks with guests etc. similar to the data compression talk with Charles" "7618": "Q: Is the bilinear sampling from the octahedral map exact, then, or is there some distortion due to the way we are mapping the sphere in 2 dimensions?" "7689": "Q: Would you ever consider doing a tutorial on testing for something like a library, where it's important to be thorough?" "7708": "Q: I thought ours might be scalar. But was just a guess" "7749": "Q: What other than the games at Molly Rocket, are you working on? (Referring to the "cleaning up other people's mess" you said earlier, maybe I misunderstood?)" "7973": "Q: step(x) might be hardware accelerated. It works on v2 and is branchless. Not sure how impactful it actually is" "8213": "Q: Did you get any traction on your "The Thirty Million Line Problem" video? In terms of people wanting to collaborate with better programming of the hardware directly, ISAs for the GPU, etc, etc. Things in that direction" "8227": "Q: I enjoyed your talk on API design, but I see that it's 15 years old. Have your thoughts changed or is it still the model you follow?" "8295": "Q: Where could one find concrete resources on 2D lighting? I can't seem to find anything useful on google, just unity and godot stuff" "8320": "Q: I agree with you that software generally sucks, but do you think you're letting it get to you too much? There's something to say about staying positive, despite the madness" "8352": "Q: What are some of the major changes you have made to 4coder worth mentioning?" "8402": "Q: Is it possible to implement the idea of dynamic language without garbage collection, e.g implementing ECMAScript?" "8434": "Q: When is your C course coming out? I missed the beta" "8469": "Q: Can you elaborate on the issue C made with tying types strongly with operations?" "8577": "Q: How many people pre-ordered the source code (I certainly did!)?" "8615": "Q: If SendOwl continues to be shady, is there a plan to switch platforms, so people will still be able to get it if something happens?" "8787": "Q: What are the challenges with finding good distribution platforms?" "8945": "Q: What about itch.io?" "9116": "GOG?" "9132": "You might be able to get permission. The people at Epic who are running the Epic Game Store are good people" "9169": "Q: Does Steam have any requirements to put their DRM into any program that's being uploaded, or is that up to the programmer?" "9246": "Sweeney seems like a great guy" "9378": "Is there anything of Steam to improve? It does what it does right?" "9481": "Q: What are your thoughts on undefined behaviour?" "9623": "Q: Is there an advantage to having undefined behaviour?" "9654": "Wrap it up" --- name: "day579" title: "Debugging Octahedral Shading" markers: "3": "Recap and set the stage for the day" "31": "Demo our octahedral light map" "203": "Understanding the Octahedron" "295": "Orienting the octahedral wrapping by importance" "366": "Determine to fill in the cracks and sample the octahedron in the shaders" "456": "Make SampleLighting() in CompileZBiasProgram() light the pixels by their position within voxels" "572": "Check out our lit voxels" "643": "Determine to sample from our octahedral map" "748": "Set up SampleLighting() to sample from the octahedral light map" "954": "Make SampleLighting() compute the location from where to sample the octahedral light map" "1653": "Set up CompileZBiasProgram() to pass the values required by SampleLighting() to lookup into the octahedral light map" "1723": "Consider not using different resolutions for the light and depth maps" "2044": "Set up CompileZBiasProgram() to pass the LIGHT_LOOKUP_SQUARE_DIM to SampleLighting()" "2090": "Voxel Atlas UVs" "2440": "Make SampleLighting() compute the dimensions required to lookup into the octahedral light map" "2899": "Hit shader errors" "2958": "Fix the Result assignments in SampleLighting()" "2991": "See our darkly and incorrectly lit world" "3049": "Change SampleLighting() to orient our lookup around the octahedron centres" "3322": "Hit shader errors" "3330": "Fix naming in SampleLighting()" "3342": "See our discontinuously lit world" "3493": "Try making SampleLighting() lookup into a shrunken area of the octahedral light map" "3528": "See no improvement" "3581": "Introduce VOXEL_OFFSET_C() and VOXEL_OFFSET_D() for EndLightingComputation() to call" "3837": "Verify that our new macros work" "3849": "Set up to copy the values at the seams around the octahedron" "4000": "Make EndLightingComputation() copy the values at the seams around the octahedron" "4152": "Check out the light map" "4179": "Toggle on the coloured octahedron in EndLightingComputation(), and make OpenGLChangeToSettings() zoom in to it" "4231": "Check out the light map to see no copying" "4247": "Make EndLightingComputation() copy in to the bottom row of the octahedron" "4299": "See copying in the light map" "4318": "Make EndLightingComputation() copy in to the top row of the octahedron" "4358": "See copying in the light map" "4372": "Temporarily make EndLightingComputation() copy in coloured values" "4385": "See our correctly flipped copying in the light map" "4399": "Make EndLightingComputation() copy in to the left and right columns of the octahedron" "4616": "See copying in the light map, only missing the corners" "4630": "Check our left–right vertical copies with the paper" "4666": "Make EndLightingComputation() copy in to the corners of our octahedron" "4770": "See our fully filled light map" "4781": "Let EndLightingComputation() populate the light map with real values" "4789": "See our full light map, with no improvement to our discontinuity" "4865": "Scour CompileZBiasProgram() for octahedral mapping bugs" "5051": "Explicitly write out the OctMapCenterUV and OctExteriorUVDim initialisations in SampleLighting(), and continue to scour this function for bugs" "5301": "Fix OctMapInteriorUVDimC.y in SampleLighting()" "5383": "Hit shader error" "5399": "Fix typo in SampleLighting()" "5420": "See different lighting discontinuities" "5440": "Continue to scour SampleLighting() for bugs" "5518": "Take a close look at our lighting discontinuities, and wonder if we have a blending error" "5638": "Centred, Padded Lookup" "5691": "Consider SampleLighting() to be doing a correct lookup" "5752": "Toggle on the coloured octahedron in EndLightingComputation()" "5785": "Observe the lighting discontinuities along with the light map" "5861": "Make CompileZBiasProgram() colour the world directly with light" "5878": "Observe the lighting discontinuities with the world coloured with light" "5971": "Let EndLightingComputation() populate the light map with real values" "5977": "Note that the lighting discontinuities are not at copy points" "5994": "Toggle on the coloured octahedron in EndLightingComputation()" "5998": "Realise why we're not smoothly interpolating between adjacent, non-copied octants" "6055": "Toggle on linear blending in OpenGLChangeToSettings()" "6082": "Admire our continuous lighting" "6088": "Let EndLightingComputation() populate the light map with real values" "6114": "Admire our continuous, yet popping lighting" "6144": "Shoulder the Owl of Shame" "6170": "Admire our lighting" "6187": "Revert CompileZBiasProgram() to modulate the world's real colours with light" "6201": "Admire our lighting, noting its directionality" "6294": "Make CompileZBiasProgram() colour the world directly with light" "6299": "Check out our lighting seam" "6321": "Toggle on the coloured octahedron in EndLightingComputation()" "6330": "Consider the seam to be along the wrapping border" "6339": "Let EndLightingComputation() populate the light map with real values" "6350": "Consider the seam not to be along the wrapping border" "6359": "Toggle on the coloured octahedron in EndLightingComputation()" "6360": "Consider the seam to be straight down the middle of the pink" "6399": "Let EndLightingComputation() populate the light map with real values" "6409": "See the seam run in a different orientation" "6419": "Toggle on the coloured octahedron in EndLightingComputation()" "6426": "Inspect our seam" "6478": "Let EndLightingComputation() populate the light map with real values" "6493": "Note the brightening as the character hops up" "6582": "Try making SumLight() sample the lighting from the direction you're pointing, ignoring the actual reflection vector" "6597": "See no lighting discontinuities" "6681": "Revert SumLight() to use the reflection vector" "6722": "Wonder if EndLightingComputation() is populating the octahedron incorrectly" "6796": "Sampling Within Pixels" "6908": "Fix EndLightingComputation() to offset the light population by half a pixel" "6989": "Still see the seam" "7009": "Toggle EndLightingComputation() between offsetting the light population and not, to see difference but no improvement" "7109": "Q&A" "7141": "Q: Can you vary the light height to see its impact?" "7169": "Either way" "7170": "Q: Can you draw in the light probe positions?" "7215": "Make EndLightingComputation() draw the light probes, introducing IsInDebugVoxDim()" "7638": "See our misplaced light probes" "7659": "Fix the position of the light probe drawing in EndLightingComputation()" "7792": "See our light probes, and consider the brightening to be due to a Z-discontinuity" "7896": "Q: Should you gutter copy from the opposite / flipped sides of the octal mapping so the bilinear blend will blend correctly?" "7970": "Make UpdateAndRenderWorld() vary the height of the light" "8075": "See no light popping" "8088": "Increase the height variance of the light in UpdateAndRenderWorld()" "8102": "See light popping as the light passes through probes" "8328": "Remove the light height varying code" "8338": "Call it for today" --- name: "day580" title: "Investigating Octahedral Interpolation" markers: "3": "Recap and set the stage for the day streamlining the lighting system, operating directly in the octahedral map, and hook up the light convection" "298": "Determine to hook up the bounce-based light convection" "362": "Demo the current state of the lighting" "477": "On assuming we have a bug, and not rationalising away by manufacturing an explanation that the code is correct" "796": "Determine to investigate the octahedral interpolation" "950": "Prevent GenerateRoom() from varying the floor height" "1014": "Take a close look at the apparent square lighting falloff artifact" "1285": "Try making SumLight() in CompileZBiasProgram() overwrite the top-level voxel with the value of the first bottom-level voxel" "1318": "Note the weird shape of our angular falloff" "1399": "Scrutinise SumLight() in CompileZBiasProgram() for anything that may affect the angular falloff" "1541": "Try making SumLight() in CompileZBiasProgram() lookup into the octahedral light map at a known location" "1570": "Find no interpolation variance while moving the camera" "1603": "Revert SumLight() in CompileZBiasProgram() to interpolate the full voxel hierarchy" "1610": "Find that our lighting interpolates coherently, which suggests that our weirdness is coming from the octahedral light map" "1695": "Revert SumLight(0 in CompileZBiasProgram() to lookup into the octahedral light map in the correct direction" "1701": "Take a close look at the octahedral-shaped lighting falloff artifact, in conjunction with Jeff Knox's octahedral unwrapping visualisation in Desmos" "2011": "Disable interpolation in OpenGLChangeToSettings()" "2085": "See a hard-edged artifact" "2121": "Set up to make EndLightingComputation() copy known values to the border rows" "2229": "See no change" "2238": "Make OpenGLChangeToSettings() zoom out the light map viewer" "2298": "View the light map" "2326": "Make EndLightingComputation() copy known values to the border rows" "2336": "See the red and green lines in the light map viewer, but not in the game" "2386": "Enable interpolation in OpenGLChangeToSettings()" "2415": "See our red and green, but not at the artifact edges" "2433": "Disable interpolation in OpenGLChangeToSettings()" "2441": "Consider our artifact to occupy the interior of the octahedral light map" "2452": "Make EndLightingComputation() copy known values to the border columns" "2495": "See the yellow and cyan lines in the light map viewer, but not in the game" "2514": "Enable interpolation in OpenGLChangeToSettings()" "2522": "See our yellow and cyan, but not at the artifact edges" "2537": "Disable interpolation in OpenGLChangeToSettings()" "2542": "Consider our copy operation not to be implicated" "2588": "Try making SumLight() in CompileZBiasProgram() overwrite the top-level voxel with the value of the first bottom-level voxel" "2610": "Clearly view our diamond-shaped artifact" "2848": "Make OpenGLChangeToSettings() zoom out the light map viewer" "2858": "See no especially bright areas in the light map viewer" "2886": "Pan around the light map for our expected bright areas" "3195": "See two identical neighbouring values in the light map" "3285": "Continuities" "3358": "Enable interpolation in OpenGLChangeToSettings()" "3374": "Discontinuities in the rate of change" "3503": "Toggle on EDGE_COLORING in EndLightingComputation()" "3510": "Disable interpolation in OpenGLChangeToSettings()" "3520": "Recall that the artifact is not on an edge copy" "3617": "Make EndLightingComputation() write purple structured art into the interior of the octahedral light map, with thanks to Mike Biddlecombe" "3689": "See a great swathe of purple, revealing that the artifact is from the interpolation between texels" "3773": "Make EndLightingComputation() write a 3×3 structured art matrix in the octahedral light map" "3941": "View our structured art" "3974": "Enable interpolation in OpenGLChangeToSettings()" "3982": "See our bilinear interpolation artifact, and consider trying radial interpolation" "4146": "Make EndLightingComputation() blank out the central texel of our 3×3 matrix" "4159": "See the bilinear interpolation artifacts radiating from the centre" "4212": "Consider writing our own radial interpolation in CompileZBiasProgram(), seeing what Texture Lookup Functions are available in OpenGL 3.2" "4492": "Embark on implementing our own radial interpolation routine in CompileZBiasProgram()" "4790": "Bilinear Fudge" "4926": "Fudging Bilinear to be Radial" "5321": "Graph our radial interpolation equation in Desmos" "6928": "Understanding our radial discontinuity" "7053": "Hack our radial interpolation equation in to CompileZBiasProgram()" "7536": "With the radial interpolation toggled off, see our bilinear interpolation artifacts" "7567": "Manually reproduce the bilinear interpolation in CompileZBiasProgram()" "7637": "Bilinear Interpolation" "7817": "Toggle on and complete our manual interpolation path in CompileZBiasProgram()" "7937": "Hit and fix shader validation errors" "8016": "See our manual bilinear interpolation artifacts" "8050": "Toggle off our manual interpolation path in CompileZBiasProgram()" "8056": "See a difference between our and OpenGL's bilinear interpolation" "8126": "Offsetting our manual bilinear interpolation" "8184": "Offset our manual bilinear interpolation back by half a pixel in CompileZBiasProgram()" "8208": "See no difference between our and OpenGL's bilinear interpolation" "8255": "Toggle on our radial interpolation in CompileZBiasProgram()" "8299": "See our radial falloff" "8325": "Toggle off our manual interpolation path in CompileZBiasProgram()" "8335": "See OpenGL's bilinear interpolation artifact return" "8341": "Toggle on our manual interpolation path in CompileZBiasProgram()" "8346": "Take a close look at our radial interpolation" "8379": "Let EndLightingComputation() produce real lighting values in our 3×3 structured art matrix" "8389": "Perceive but prefer our radial interpolation discontinuities" "8414": "Revert SumLight() in CompileZBiasProgram() to interpolate the full voxel hierarchy" "8461": "View our smoothly interpolated lighting" "8506": "Revert CompileZBiasProgram() to modulate the world's real colours with light" "8515": "View our really lit world" "8536": "Q&A" "8570": "Q: Why is the lighting behind the character so dark? Shouldn't a point light be more round?" "8643": "Q: For a look at Desmos: see 'Untitled Graph'" "8788": "Q: How fast is this lighting method when we compile in debug mode?" "8816": "Q: I have to say that your debug videos are often more educational than implementation-heavy ones. Very insightful into your process. Thanks!" "8918": "Q: Is octahedral lighting the only way to go for what you want?" "8972": "Q: Once you take depth samples, could you do bounce lighting by fetching the depth sample and then moving that far down the normal to seek directly to the next voxel?" "9026": "Q: Sorry that was just a temp graph, I hadn't saved it. But now with an account and all, the permanent link (I guess) is here" "9096": "Q: Could you do a stream on RAD's Telemetry one day, showing all the things you can do with it? I'm really interested in the tool, but the only good video source on it is Jon Blow, and his streams aren't very "tutorial-y" by nature!" "9203": "Q: With the octahedral map, both the bilinear filtering and the "puffy" filtering seemed to have a pretty quick falloff between samples. Would you consider doing something like bi-cubic filtering for a smoother blend?" "9428": "Q: Do you you use any equation for the light density attenuation?" "9449": "Q: Thanks! Do you know if RAD has discounts for students?" "9517": "Q: Yes, I meant intensity attenuation?" "9568": "Q: Would you ever go back to RAD?" "9606": "Q: Does the paper from nVidia about octahedral sampling cover also the sampling filter, or did they just use linear and bump up the size of the bitmap to have more samples?" "10067": "Q: When doing game logic, do you think it's ever a good idea to write in async / await style and have that transformed into a state machine?" "10236": "Q: Thoughts on the ML family of languages and tagged unions?" "10278": "Q: Do you know about the inverse distance weight interpolation method? Do you think it can be used for games?" "10294": "Q: What do you think of C++20 modules and, separately, of constexpr in C++ in general?" "10316": "Q: I've only really focused much on python, and I'm trying to learn another language. What do you think of Golang?" "10328": "Wind it down" --- name: "day581" title: "Preparing for Octahedral Indirect Lighting" markers: "4": "Recap our new radial interpolation of lighting samples and set the stage for the day" "223": "This is Molly Bean" "298": "Determine to: 1) Use the ray caster in the octahedral light maps, and 2) Streamline the lighting voxels intermediate storage out of the equation" "535": "Demo the current state of the lighting, noting our artifacts when a light passes through a probe, and the persistent flower shape due to texel interpolation" "674": "Toggle off the light probe drawing in EndLightingComputation()" "691": "Traverse the garden without visible light probes" "726": "Toggle off EDGE_COLORING in EndLightingComputation() and the light and depth map viewers in OpenGLEndFrame()" "771": "Traverse the clean garden, with the determination to bounce light around" "799": "Set up to use the ray caster in the octahedral light maps" "876": "Remove the accumulation data from light_voxel_cell, for EndLightingComputation() to update the light directly, enabling TEST_LIGHT_TRANSFER" "1046": "See a data-less world" "1057": "Remove SpamVoxel() and trim down SpamVoxelSlice()" "1236": "Consider casting rays from locations other than at light probes" "1343": "Rename SpamVoxelSlice() to SpamVoxel() and make it blend in the lighting directly, augmenting lighting_solution with tUpdateBlend" "1716": "Make TestCastFromProbes() pass an octahedral light map location to SpamVoxel(), introducing GetOctahedralOffset()" "2370": "See some lighting" "2500": "Investigate our apparent voxel spamming bug" "2645": "Make TestCastFromProbes() always call SpamVoxel(), whether or not we hit a light" "2665": "See that we mostly write out a tile's lighting only once we stand on it" "2703": "Investigate our light writing bug" "2791": "Scrutinise OctahedralFromUnitVector() and GetOctahedralOffset() for bugs" "2985": "Break in to GetOctahedralOffset() and inspect its values" "3265": "Make SpamVoxel() write structured art into the voxel" "3388": "See no structured art in the voxels" "3425": "Scrutinise EndLightingComputation() for bugs" "3527": "Make SpamVoxel() write red everywhere" "3542": "Only see red in voxels we land on" "3555": "Wonder why we're apparently not spamming the voxels" "3641": "Break in to SpamVoxel() and watch it write to all the voxels" "3745": "Try making TestCastFromProbes() pass an upward-pointing OctOffset vector to SpamVoxel()" "3796": "See red spammed as expected" "3823": "Revert SpamVoxel() to use the computed lighting values" "3842": "Find that moving the light around does not change the intensity" "3880": "Make TestCastFromProbes() fall-off the light" "3944": "See our lighting fall-off work correctly" "3988": "Revert TestCastFromProbes() to only call SpamVoxel() if we hit a light" "3998": "Find that we fail to light into newly visible corners" "4019": "Make TestCastFromProbes() always call SpamVoxel(), but blank out the LightC it we didn't hit a light" "4064": "Find that our light interpolation is pretty fast" "4104": "Try reducing the tUpdateBlend in EndLightingComputation()" "4118": "Find that our light fades out slower than it fades in" "4178": "Try further reducing the tUpdateBlend in EndLightingComputation()" "4186": "Watch the speed of light fading" "4269": "Prevent TestCastFromProbes() from boosting the light brightness" "4279": "Briefly watch our light fade" "4294": "Increase the tUpdateBlend in TestCastFromProbes()" "4310": "Consider our light fade in and out to be more uniform" "4328": "Reduce the tUpdateBlend in TestCastFromProbes()" "4330": "Find that our light fades out slower than it fades in" "4425": "Hunt the code for other pieces of non-linearity in the light fade in / out" "4614": "Make a note in SpamVoxel() to hunt down the attack / decay non-linearity" "4657": "Our faster attack may happen if two out of three probes switch from 0 to 1" "4716": "Make GenerateRoom() generate one, rather than two, light probes per tile" "4757": "Find that our light still fades out slower than it fades in" "4811": "Make GenerateRoom() generate zero light probes per tile" "4824": "See no lighting" "4827": "Make GenerateRoom() generate one light probe per tile" "4844": "Find that our light still fades out slower than it fades in" "4862": "Revert GenerateRoom() to generate two light probes per tile" "4866": "Consider how to investigate our fading speed discrepancy" "4908": "Begin to plot our lighting update equation in Desmos" "5069": "Set the day" "5126": "Lighting Linear Blend Per Frame: In vs Out" "5626": "Further study: Perceptual rate of fading in vs out" "5725": "Remove Frumbledygok(), and toggle from TestCastFromProbes() to ComputeLightPropagation() in EndLightingComputation()" "5846": "Make ComputeLightPropagationWork() call SpamVoxel() and cast our real rays into the octahedral light map" "6154": "Begin to update ComputeVoxelIrradianceAt() to sample the octahedral light map" "6347": "Diffuse Sampling" "6587": "Consult 'Dynamic Diffuse Global Illumination with Ray-Traced Irradiance Fields' on diffuse sampling" "6742": "Consult 'Real-Time Global Illumination using Precomputed Light Field Probes' on diffuse sampling" "7393": "Spec out specular sampling in ComputeVoxelIrradianceAt()" "7524": "Glimpse the (broken) specular lighting" "7532": "Defer figuring out diffuse sampling of the octahedral map" "7584": "Q&A" "7670": "Q: Is the diffuse component going to be computed on the CPU or the GPU then?" "7713": "Q: Since hardware standards move quickly, have you considered doing a pass on the codebase to move to newer versions of OpenGL and SSE? The optimization implications alone should be worth it, or?" "7796": "What is the current OpenGL version?" "7838": "Q: Did the paper say that they compute a separate cosine-weighted radiance for every probe? Where do they store that information?" "7930": "Q: Any pointers on reading research papers effectively?" "7955": "Is this a "research paper"?" "8005": "Journal of Fluffy Opinion Papers" "8038": "Wrap it up" --- name: "day582" title: "Converting Specular Maps to Diffuse" markers: "3": "Recap and set the stage for the day, debugging the lighting stability over time, and efficiently sampling diffuse surface reflections" "269": "Diffuse sampling efficiency: 1) Downsampling our map" "433": "Diffuse sampling efficiency: 2) Take multiple interior samples, e.g. 4×4" "528": "Diffuse sampling efficiency: 3) Downsampling, with pre-computed diffusion" "588": "Full diffuse sampling solution: Cosine-weight an 8×8 specular to 8×8 diffuse solution" "870": "Remove OutputLightingPointsRecurse() and GetCurrentQuads(), and switch EndLightingComputation() to TEST_LIGHT_SPHERE" "951": "Demo our specular lighting" "1006": "Set up to convert our specular maps to diffuse" "1079": "Switch EndLightingComputation() to TestCastFromProbes() and TEST_LIGHT_TRANSFER" "1150": "See lighting weirdness" "1227": "Introduce TestLightSphere() to perform the TEST_LIGHT_SPHERE lighting voxel writing code from EndLightingComputation()" "1456": "See our light sphere test working as before" "1471": "Remove the TEST_LIGHT_SPHERE code from EndLightingComputation()" "1545": "See our light sphere test continuing to work as before" "1553": "Embark on our full-fat specular–diffuse conversion in EndLightingComputation()" "1674": "Calculate our operations per map: 4096" "1734": "Set up EndLightingComputation() to sum up weighted samples" "1820": "Big O notation, and separable filters" "1970": "Introduce diffuse_weight_map for lighting_solution to contain and EndLightingComputation() to use" "2205": "Introduce BuildDiffuseLightMaps() for InitLighting() to call, and DirectionFromTxTy() based on TestLightSphere()" "2512": "See slow, but beautiful diffuse lighting" "2721": "Toggle on the light map viewers in OpenGLEndFrame()" "2746": "Check out the light maps" "2816": "Set up to optimise the diffuse lighting" "2945": "Compute 4-wide the diffuse light sampling in EndLightingComputation()" "3216": "Consider how to store our diffuse lighting data for SIMD computation" "3597": "Store our diffuse lighting data RRRR GGGG BBBB and swizzle it on output, introducing Transpose()" "3815": "Swizzling RRRR GGGG BBBB to RGBR GBRG BRGB" "4178": "Consider how best to swizzle our diffuse lighting data" "4267": "Load-Without-Broadcast" "4451": "Trying _mm_shuffle_ps() or _mm_unpacklo_ps() to swizzle" "5160": "Non-interleaved unpack using _mm_unpackhi_pd()" "5441": "Masked picking from two SIMD values using _mm_blend_ps()" "5563": "Trying _mm_blend_ps() to swizzle" "5729": "Trying our full RRRR GGGG BBBB to RGBR GBRG BRGB swizzle" "6079": "All the possible unpacks" "6392": "Constraints on Final Op" "6766": "Introduce Transpose() from six Shuffle4X() operations, for RRRR GGGG BBBB to RGBR GBRG BRGB swizzle" "7203": "Define Shuffle4x() macro" "7389": "Fill Transpose() with known values for testing" "7586": "Switch diffuse_weight_map and BuildDiffuseLightMaps() to be SIMD" "7722": "See faster diffuse lighting" "7756": "Try to step in to Transpose(), but hit a read-access violation on DestD[Tx4] in EndLightingComputation()" "7819": "Force DestC and DestD to be stored unaligned using _mm_storeu_ps() in EndLightingComputation()" "7916": "Try to step in to Transpose()" "7933": "Make EndLightingComputation() call Transpose()" "7948": "Step in to Transpose() to see what it produces" "7974": "Fix Transpose() to set the Order as desired" "7998": "Step in to Transpose() to see that it swizzles incorrectly" "8022": "Fix Shuffle4x() to shift by 2-bytes" "8079": "Step in to Transpose() to see that it swizzles more sanely, but still incorrectly" "8379": "Check our 6-shuffle swizzle" "8413": "Fix Transpose() to interleave every third lane" "8507": "Step in to Transpose() to see that it swizzles 100% correctly" "8537": "Add a VERIFY_SHUFFLE preprocessor path in Transpose()" "8583": "Admire our almost right lighting" "8666": "Fix BuildDiffuseLightMaps() and diffuse_weight_map inspired by EndLightingComputation()" "9082": "Admire our closer to correct lighting" "9192": "Q&A" "9288": "Transposes are symmetric" "9330": "Q: Why can't you do the unpack on the GPU side?" "9407": "Q: Looks like in this article they do it in six shuffles similarly to how you do it" "9449": "Q: Could it be feasible to pack into a different GPU-supported format, maybe even compressed?" "9508": "Q: They have an example on 128 bits, second picture" "9521": "Consider the performance of dependent shuffles, all on port 5" "9776": "Q: Would you consider using the vector extension from clang if you would go clang only?" "9802": "Q: Do all the work we did to generate the sphere samples and not use them anymore?" "9806": "Show the sphere samples-based lighting" "9904": "Q: 15FPS? Ship it!" "9937": "Q: What's next on the TODO list after lighting?" "9964": "Q: Is there a reasonable performance difference between aligned and unaligned move in SSE2?" "10140": "Q: How do you reason about separable filters when, say, running along the Y axis for an image kernel might incur a cache miss on each sequential access (for non-block storage)?" "10205": "Q: But is there a reason to use MOVAPS instead of MOVUPS, then? Other than MOVAPS throws an exception if you are not aligned" "10282": "Q: So how do we go back to 60FPS now?" "10372": "Q: You said, after lighting you'll start with level design etc. so how far from release is Handmade Hero?" "10432": "Wrap it up with a glimpse into the future" --- name: "day583" title: "Streamlining the New Lighting Pipeline" markers: "4": "Recap and set the stage for the day debugging and streamlining our lighting" "281": "Launch the game, with continued thoughts on hardware rendering" "315": "Demo our diffuse lighting, considering disabling it for the debug overlay" "435": "Set up to thread the whole of EndLightingComputation()" "603": "Draw the voxels in TestLightSphere()" "619": "Show the voxels" "645": "Determine that Global_Lighting_ShowProbes controls the probe drawing" "651": "Consult the debug overlay for the ShowProbes toggle" "678": "Set Global_Lighting_ShowProbes to true" "687": "Show, explain and consider pulling the light probes" "808": "Remove LightProbeCount and LightProbeP from lighting_solution, and propagate this removal" "849": "Our mistake: Making Z primal" "1007": "Replace OnePastLastLightProbeIndex with VoxelX in lighting_work (i.e. making X primal), and continue to switch ComputeLightPropagation() away from light probes to a voxel-direct, X slice-based scheme" "1404": "Consider the potentially increased cache-friendliness of our voxel-direct scheme" "1492": "Switch ComputeLightPropagationWork() to our voxel-direct scheme" "2196": "Augment lighting_work with SamplePointEntropy and LightPointEntropy for ComputeLightPropagation() to set" "2332": "Continue to switch ComputeLightPropagationWork() to our voxel-direct scheme" "2411": "Augment lighting_solution with a game_render_commands pointer, for ComputeLightPropagation() to take" "2498": "Continue to switch ComputeLightPropagationWork() to our voxel-direct scheme, making it call TestLightSphere()" "2652": "Weld ComputeLightPropagation() in to EndLightingComputation(), and replace TestCastFromProbes() with a voxel-direct TestCast()" "2980": "Introduce FullCast(), respecifying SpamVoxel() as UpdateVoxel()" "3441": "Rename TestLightSphere() to TestSphere(), updating it to our voxel-direct scheme" "3682": "Clean up compile errors in ComputeLightPropagationWork()" "3734": "Remove InLargeVoxel(), GetVoxelIndex(), GetVoxelCenterP(), SignedSquareRoot() and GetLightAmount(), and weld GetIrradiance() in to ComputeVoxelIrradianceAt()" "4057": "Hit assertion in EndLightingComputation()" "4088": "Change lighting_work in lighting_solution to be a pointer, allocated by InitLighting(), and remove AccumulatedPPS" "4171": "Run slowly" "4199": "Restrict ComputeLightPropagationWork() to loop over only one Z-slice" "4255": "See nothing lit" "4279": "Scour TestSphere() for bugs" "4327": "Remove InvHotDim from TestSphere() and switch it to set the LightC based directly on the light's direction" "4345": "See our lit world" "4361": "Reduce the brightness of the direction-based lighting in TestSphere()" "4391": "See our diffusely lit world" "4424": "Make EndLightingComputation() add the ComputeLightPropagationWork() calls to our queue" "4449": "See our diffusely and multithreaded lit world" "4463": "Set Global_Lighting_ShowProbes to false" "4513": "See our lit world, spotting a hole in our light map, and check our performance" "4610": "Switch TestSphere() back to set the LightC as computed, fixing that actual computation to not be done in UV-space" "4719": "Admire our light" "4779": "Make CompileZBiasProgram() fall-off the lighting not quite to black, to hide the voxelisation" "4877": "Admire our less apparently voxelised lighting" "4998": "Switch ComputeLightPropagationWork() to TEST_CAST" "5027": "Hit a write-access violation in GetLightLeafForP()" "5064": "Prevent TestCast() from asking GetLightLeafForP() to draw the voxel hierarchy, because PushDebugLine() is not thread-safe" "5091": "Admire our ray-cast lighting" "5103": "Increase the light brightness in TestCast()" "5111": "Admire our brighter ray-cast lighting, with misaligned voxel" "5211": "Reflect on the slow performance of our lighting solution" "5271": "Q&A" "5319": "Q: You don't assign the clamp of S back to S in the shader. And is there a bug in the octahedral map? I mean the black pixels in the corners and the line just below" "5326": "Fix CompileZBiasProgram() to set S" "5337": "Admire our lighting" "5373": "Q: Shouldn't wall side be in light state at the moment?" "5392": "Q: If we like the voxelized light, can we keep it?" "5407": "Comment out the "voxel-smoothing" code in CompileZBiasProgram()" "5412": "Show the apparently voxelised lighting" "5425": "Let CompileZBiasProgram() smooth out the voxelisation" "5443": "Q: Can you show the disassembly of Transpose() in optimized build" "5520": "Check the assembly of Transpose()" "5800": "Q: Can you zoom out on the octahedral debug drawing?" "5807": "Q: Why does the clamped light have a kind of heart shape from some angles with the sphere lighting (two lobes jutting out behind the hero to his left and right when viewing from a low angle)?" "5854": "Q: Maybe you fixed it up already but I think you might have a copy-paste error in the border fill. If you look at the sphere test the octahedral maps show a weird black line on each" "5895": "Hunt the orphanage for border copies" "5928": "Toggle on EDGE_COLORING in ComputeLightPropagationWork()" "5951": "View the light map" "5978": "Make a note in ComputeLightPropagationWork() to verify the border copies" "6030": "Q: How will you light the top of the “walls” but make them block light in the middle?" "6042": "Check the wall lighting" "6081": "Switch ComputeLightPropagationWork() to TEST_SPHERE" "6094": "See that the wall uprights are now lit" "6148": "Switch ComputeLightPropagationWork() to TEST_CAST" "6156": "See that the wall uprights are incorrectly lit" "6225": "Q: Just wondered how you would light the wooden top? Or will that be the moon?" "6262": "Q: I didn't follow what the next step is. I assume you want to merge the test sphere and test cast into their final form. Is that correct?" "6313": "Q: Are you planning in putting in tone mapping?" "6353": "Q: Does it take a significant amount of time to switch head spaces between different programming projects for you (e.g. between Handmade Hero and 1935), and do you have any techniques that you use to re-familiarise yourself about an old project that you haven't worked on in a while?" "6417": "That looks like it" --- name: "day584" title: "Enabling Infinite-Bounce Lighting" markers: "2": "Recap and set the stage for the day" "73": "Describe the problem with black gaps in the light map" "117": "Describe the indexing discrepancy between BuildDiffuseLightMaps() and ComputeLightPropagationWork()" "276": "Fix ComputeLightPropagationWork() to look up into the light map correctly" "317": "See the correct lighting of our world, but not of the hero, and the misaligned simulation region" "512": "Determine to enable infinite-bounce lighting" "555": "Switch to TEST_SPHERE in ComputeLightPropagationWork()" "569": "Check out our sphere fall-off lighting" "636": "Let CompileZBiasProgram() clamp the light to brighter values" "711": "Check out our brighter lighting" "743": "Let CompileZBiasProgram() clamp the light to further brighter values" "748": "Check out our brighter lighting with the determination to enable bounce lighting" "836": "Toggle off TEST_SPHERE in ComputeLightPropagationWork() and fix it to pass Work to FullCast()" "883": "Check out our full bright, slower ray-cast lighting" "993": "Prepare to enable distributive ray-casting in FullCast()" "1042": "Blank out the MoonColor in FullCast()" "1062": "See no difference, except that the light map appears to be accumulating to full brightness" "1077": "Consult the casting code in FullCast()" "1154": "Prevent FullCast() from biasing towards the light source" "1176": "Check out our lighting without biasing towards the light source" "1182": "Correctly prevent FullCast() from biasing towards the light source" "1200": "Check out our lighting without biasing towards the light source" "1215": "Try blanking out the TransferPPS in FullCast()" "1275": "See a black world" "1278": "Try setting a TransferPPS of a quarter full bright white in FullCast()" "1290": "Check out our lit world, noting that the high brightness of the light" "1383": "Switch to TEST_CAST in ComputeLightPropagationWork()" "1431": "Check out our test cast lighting" "1437": "Try making TestCast() output a known grey light" "1459": "See the light fade" "1467": "Try making TestCast() call UpdateVoxel() many times" "1470": "See no difference" "1476": "Remove the multiple calls to UpdateVoxel() in TestCast(), and toggle off TEST_CAST in ComputeLightPropagationWork()" "1508": "See our bright light" "1514": "Consider the problem to be in pulling light from multiple octahedral offsets" "1599": "Check BuildDiffuseLightMaps() for possible bugs" "1697": "Break in to FullCast() and inspect the DiffuseWeightMap" "1895": "Diffuse Map Filtering" "2139": "Directional reflection bounce" "2377": "Consider BuildDiffuseLightMaps() to be handling bounce direction correctly" "2423": "See if CompileZBiasProgram() samples light based on its direction" "2580": "Diffuse sampling of cosine-weighted directional light" "2936": "Make SumLight() in CompileZBiasProgram() just use the surface normal as the reflection vector when sampling Lambertian (ideally diffuse) surfaces" "3023": "Switch to TEST_CAST in ComputeLightPropagationWork()" "3042": "See our darkly lit world" "3045": "Prevent TestCast() from outputting a known grey light" "3059": "Check out the test ray cast lighting" "3075": "Switch to TEST_SPHERE in ComputeLightPropagationWork()" "3085": "Check out the correct sphere light" "3154": "Toggle off TEST_SPHERE in ComputeLightPropagationWork()" "3180": "Check out the full ray cast lighting, wondering where falloff comes into it" "3220": "Reduce the TransferPPS from ×0.25f to ×0.1f in FullCast()" "3234": "See the dimmer light" "3238": "Further reduce the TransferPPS from ×0.1f to ×0.01f in FullCast()" "3241": "See the unlit world, despite the light map containing non-zero values" "3272": "Increase the TransferPPS from ×0.01f to ×0.02f in FullCast()" "3278": "See the world lighten, and recall that we clamp the lighting down" "3288": "Further increase the TransferPPS from ×0.02f to ×0.03f in FullCast()" "3290": "Consider our lighting transfer clamping to be okay" "3305": "Prevent FullCast() from post-modifying the TransferPPS, and try commenting out the ray hit computations" "3355": "See no lighting" "3366": "Prevent FullCast() from blanking out the MoonColor" "3381": "Check out the moonlit world" "3406": "Scrutinise the moonlighting code in FullCast()" "3483": "Negate the EmissionDirection in the TransferPPS computation for the moon in FullCast()" "3498": "See more expected moonlight" "3505": "Respecify MoonP as MoonDir in FullCast()" "3617": "Check out our slowly moonlit world" "3635": "Darken the moon from ×3 to ×1 in FullCast()" "3643": "Watch the moonlight darken" "3648": "Further darken the moon from ×1 to ×0.2 in FullCast()" "3657": "Watch the moonlight darken further" "3682": "Further darken the moon from ×0.2 to ×0.1 in FullCast()" "3688": "Watch the moonlight darken further, and spot a shadow cast by our (unlit) light sources" "3724": "Work on the handling of ray cast bounces in FullCast(), respecifying ComputeVoxelIrradianceAt() to take an Outgoing vector" "4034": "Watch the light emerge with style (exploding to bright, before settling)" "4059": "Wonder why we are getting more light than expected" "4149": "Try making ComputeVoxelIrradianceAt() produce a known value" "4169": "See lighting, without the over-brightness" "4260": "Blank out the MoonColor in FullCast()" "4271": "See the single-bounce lighting" "4315": "Prevent FullCast() from blanking out the MoonColor" "4320": "Consider our lighting to look right" "4324": "Scrutinise ComputeVoxelIrradianceAt()" "4495": "Try making CompileZBiasProgram() reduce the VoxUVW by half, in line with ComputeVoxelIrradianceAt()" "4507": "See the light disappear completely" "4511": "Revert VoxUVW and try making CompileZBiasProgram() reduce the VoxR by half" "4544": "See that the light is now centred properly, and the moonlight cannot reach downstairs" "4626": "Continue to scrutinise ComputeVoxelIrradianceAt()" "4700": "Try making ComputeVoxelIrradianceAt() reduce the real result by ×0.01f" "4716": "Watch the light emerge again with style (exploding to bright)" "4722": "Try making ComputeVoxelIrradianceAt() further reduce the real result from ×0.01f to ×0.001f" "4735": "See the light hover without exploding" "4742": "Try making ComputeVoxelIrradianceAt() increase the real result from ×0.001f to ×0.002f" "4749": "Watch the light slowly explode" "4789": "Try making ComputeVoxelIrradianceAt() decrease the real result from ×0.002f to ×0.0015f" "4802": "Watch the light slowly explode" "4824": "Try making ComputeVoxelIrradianceAt() decrease the real result from ×0.0015f to ×0.00125f" "4832": "Watch the light explode a little" "4847": "Conceptualising photons per second" "4947": "Assert in FullCast() that Emission is <= 1.0f" "4966": "Happily fail to hit that Emission <= 1.0f assertion in FullCast()" "4978": "Remove that Emission <= 1.0f assertion in FullCast(), and instead assert that the SampleRefColor values are all <= 1.0f" "5087": "Happily fail to hit those SampleRefColor <= 1.0f assertions in FullCast()" "5088": "Remove those SampleRefColor <= 1.0f assertions in FullCast()" "5149": "Try blanking out the Emission of hit rays in FullCast()" "5164": "See our moonlit world" "5180": "Prevent ComputeVoxelIrradianceAt() from modifying its result" "5187": "Watch the light explode, even with such dim moonlight" "5278": "Assert in ComputeVoxelIrradianceAt() that the Result values are <= 0.5f" "5304": "Happily hit our Result <= 0.5f assertions in ComputeVoxelIrradianceAt()" "5328": "Run to ComputeVoxelIrradianceAt() and inspect its values, to find that the UVW is garbage" "5609": "Separate out the UVW computation in ComputeVoxelIrradianceAt(), and remove VoxCellDim from the BCoord computation" "5703": "Step in to ComputeVoxelIrradianceAt() and inspect its values, to find a more expected UVW" "5771": "Check the moonlit world in release mode" "5808": "Prevent FullCast() from blanking out the Emission" "5819": "See a more sanely and stably lit world" "5881": "Hit a read access violation in ComputeVoxelIrradianceAt()" "5949": "Make a note in ComputeVoxelIrradianceAt() to fix the sampling error" "5956": "Q&A" "5995": "Q: The UI is drawn at Z levels less than -999 so to disable the lighting just compare the Z to -999. Can you quickly re-enable it?" "6024": "Make CompileZBiasProgram() only light surfaces that are above Z -999" "6069": "Check out our unlit UI" "6117": "Make FullCast() be a TIMED_FUNCTION" "6237": "Check the CPU usage of FullCast() (73%) and ComputeLightPropagationWork() (21%)" "6272": "Try preventing ComputeVoxelIrradianceAt() from blending the whole lighting hierarchy" "6297": "FullCast() still uses 73% of our CPU cycles" "6319": "Make ComputeVoxelIrradianceAt() be a TIMED_FUNCTION" "6354": "Hit a write access violation" "6366": "Prevent ComputeVoxelIrradianceAt() from being a TIMED_FUNCTION" "6390": "Try preventing FullCast() from calling ComputeVoxelIrradianceAt()" "6441": "FullCast() uses 67% of our CPU cycles" "6485": "Toggle on the ComputeVoxelIrradianceAt() call in FullCast()" "6489": "FullCast() uses 73% of our CPU cycles" "6497": "Remove that ComputeVoxelIrradianceAt() toggle in FullCast(), and consider the ray cast to be our most expensive consumer" "6550": "Q: I think you mentioned before that you don't like regular expressions. Can you elaborate on why?" "6634": "Q: If we have a probe near a wall and that probe is updated with the color sampled at the wall, the next frame the wall might be brighter due to the new probe color. Couldn't this spiral up to a very bright probe? How does the system prevent this?" "6764": "Try reducing our RayBundleCount to 1 in FullCast()" "6804": "FullCast() uses 14% of our CPU cycles" "6845": "Try reducing our RayBundleCount from 1 to 4 in FullCast()" "6858": "Our lighting runs not too poorly" "6886": "Let FullCast() use our full RayBundleCount, and try biasing towards the light source" "6902": "Hit a read access violation in ComputeVoxelIrradianceAt()" "6910": "Our Ty and Tx values in ComputeVoxelIrradianceAt() have apparently wrapped, but why?" "6958": "Try making GetOctahedralOffset() blank out the Dir" "6986": "Step in to GetOctahedralOffset() and inspect its values" "7042": "Introduce ApproxNOUp() for FullCast() to call, and avoid a divide-by-zero in OctahedralFromUnitVector()" "7217": "Hit a read access violation in ComputeVoxelIrradianceAt(), and see that its SampleN is zero" "7321": "Scrutinise RayCast() for HitNormal errors" "7490": "Try to make RayCast() never produce a zero HitNormal, by always enabling one of the directional masks" "7616": "Run without hitting that read access violation in ComputeVoxelIrradianceAt()" "7618": "Make a note in RayCast() to "Verify that this produces correctly only-one-1 normals for all equivalences"" "7664": "Admire our light source-biased lighting" "7685": "Prevent FullCast() from biasing towards the light source" "7700": "See minimal difference with light source-biasing" "7717": "Toggle off the light source-biasing in FullCast()" "7756": "Admire our lighting" "7778": "Q: How would you share memory across functions in a shared library? I know the user could allocate memory and pass that to the library, but I was wondering how to have the library allocate memory for internal use without the library user having to know anything about it, but that the dll would keep a reference to across library calls. I tried using a global that gets initialized in the dll main with VirtualAlloc, but later when I call a function the library exports the global is zero" "7844": "Wrap it up" --- name: "day585" title: "Centralized Light Atlas Handling" markers: "5": "Welcome to the stream" "23": "Demo the current specular lighting" "177": "Prepare to use the diffuse light map for bounce lighting, first treating the light voxel cells as a texture atlas" "331": "Introduce light_atlas" "412": "Consider leaving the depth map out of it" "527": "Swizzling light atlases for optimal GPU submission" "713": "Fill in the light_atlas, renaming it to game_light_atlas" "881": "Consider how to handle specular surfaces" "962": "Replace the LightVoxel data with a game_light_atlas in game_render_commands, and augment open_gl with game_light_atlas" "1065": "Update ComputeLightPropagationWork() and BeginLightingComputation() to use our new game_light_atlas" "1646": "Introduce v3s overloaded-operator versions of * and /" "1706": "Finish updating BeginLightingComputation() to use our new game_light_atlas" "1733": "Hit a write access violation in ComputeLightPropagationWork()" "1751": "Make OpenGLInit() initialise our DiffuseLightAtlas" "1880": "Run without crashing to see no obvious differences" "1907": "Create handmade_light_atlas.h, and rename game_light_atlas to light_atlas" "2110": "Prepare to systematise the light atlas initialisation" "2221": "Introduce GetLightAtlasTexelSize(), MakeLightAtlas(), GetLightAtlasSize() and SetLightAtlasTexels() for Win32InitOpenGL() to call, creating handmade_light_atlas.cpp" "2995": "See no lighting" "3009": "Remove LightColorData and LightDepthData from open_gl, and update OpenGLEndFrame() to use the new DiffuseLightAtlas, introducing GetLightAtlasTexelCount(), GetLightAtlasTexels(), GetLightAtlasWidth(), GetLightAtlasHeight() and a light_atlas version of IsFloat()" "3494": "Admire our lit world" "3519": "Augment open_gl with a SpecularLightAtlas, and replace the old Color and Depth handles with ones for the Diffuse and Specular atlases, propagating these changes to OpenGLInit(), OpenGLChangeToSettings() and OpenGLEndFrame()" "3826": "Hit OpenGL error "Invalid texture format"" "3851": "Make Win32InitOpenGL() initialise the SpecularLightAtlas" "3924": "Admire our lit world" "3952": "Prepare to write into our specular atlas directly" "4046": "Remove redundant code related to the lighting" "4416": "See that it looks the same" "4426": "Continue to remove redundant code related to the lighting, augmenting the light_atlas" "5087": "Consider the performance implications of removing LIGHT_COLOR_LOOKUP_SQUARE_DIM in relation to DirectionFromTxTy()" "5250": "Augment light_atlas with OxyCoefficient and OctDimCoefficient for MakeLightAtlas() to compute and DirectionFromTxTy() and GetOctahedralOffset() respectively to take" "5923": "Replace all mentions of LIGHT_COLOR_LOOKUP_SQUARE_DIM in ComputeLightPropagationWork(), introducing FillLightAtlasBorder() and respecifying VOXEL_OFFSET_C() as LIGHT_ATLAS_OFFSET()" "6791": "Replace all mentions of LIGHT_COLOR_LOOKUP_SQUARE_DIM in BuldDiffuseLightMaps()" "7097": "Run unexpectedly successfully" "7126": "Determine to sample from the correct maps next stream" "7155": "Admire the specular lighting" "7186": "Q&A" "7237": "Quick question: Does this game use stuff CRT like VCRUNTIME140.dll?" "7322": "Check the external dependencies of win32_handmade.exe in Depends: GDI32.dll, KERNEL32.dll, USER32.dll and WINMM.dll" "7343": "Check the external dependency of handmade_game_temp.dll in Depends: KERNEL32.dll" "7370": "Check the external dependencies of handmade_renderer_temp.dll in Depends: GDI32.dll, KERNEL32.dll, OPENGL32.dll and USER32.dll" "7422": "Q: Do you know why some game require you to restart it if you change the graphics settings? Is it because they can't reload different textures at runtime?" "7541": "Q: Why don't all studios use the dynamic .dll loading?! It's the best thing ever, right?" "7590": "Q: Did you forget to upload the previous episode to YouTube?" "7599": "Q: Casey, great series. Congrats! Any plans to open source the code?" "7620": "Q: Apologies in advance if this was already answered previously, but is there a particular reason you use structs and global functions instead of classes?" "7910": "Q: Also, I managed to extract the cl.exe from Visual Studio but I can't redistribute it. Has anyone been sued for redistributing the free cl.exe compiler?" "7943": "Q: What is your plan to ensure the orphanage our hero lives in will have sufficient access to paper products, especially toilet paper? How will hand washing work in a world where everything is handmade but the children have no limbs?" "8005": "(Thinks about coronavirus) *touches face*" "8028": "Q: I'm not completely familiar with this environment, that's why I'm enjoying this streaming, but why today did we moved from an array of light voxel cell to a light atlas? Is that because of OpenGL atlases or other?" "8063": "Q: Is using _mm_load_ps() and _mm_store_ps() more efficient (or better) then just casting to floats or accessing it through a union?" "8205": "Q: [Off-topic] Would you be able to give an intuitive / geometric explanation for what the adjoint matrix computes, and why you need it for doing generalized transforms on surface normal vectors?" "8419": "Q: Do you think using OpenGL for making games is still fine for the next couple of years? I've heard Jon Blow's rant about it not being a valid API, but I'm not sure why" "8515": "Right, but they still support the existing versions (we are up to 4.6, right?). Why aren't the current features enough?" "8532": "Q: What do you think about the style of using a bunch of defines to control the generated code of an include for things like libraries (similar to your float define but more extreme)?" "8547": "Q: Did you take any programming courses at a college? Do you have any recommendations?" "8553": "Q: On the Wikipedia page,the 2x2 generic example" "8831": "Q: Do you have a Raspberry 4?" "8836": "Q: Why would id support Vulkan instead of just DX?" "8846": "Q: Will you ship the game with debug GUI? Mike Acton said at GDC conference that you should be able to debug the release version of your game. How do you do that?" "8933": "It's been a pleasure" --- name: "day586" title: "Finishing Indirect Diffuse Sampling" markers: "2": "Mention the 'Handmade Collectives Worldwide" thread in the handmade.network forums" "224": "Fix typo in CompileZBiasProgram()" "317": "Show our current specular indirect-bounce lighting" "374": "Embark on the switch to looking up into the diffuse light atlas, guided by the removal of light_voxel_cell from lighting_solution" "416": "Consider relieving the lighting system of keeping stale data around" "516": "Respecify light_voxel_cell as light_atlas_tile" "597": "Update LookUpVoxelClamped() to use the light_atlas_tile, rename it to GetTileClamped(), and introduce GetTileRowStride()" "841": "Augment light_atlas with a TileRowStride for MakeLightAtlas() to set and LIGHT_ATLAS_OFFSET() to use" "1064": "Remove Stride from light_atlas_tile, rename its Base to Texel and update ComputeVoxelIrradianceAt() to sample from the DiffuseAtlas as a light_atlas_tile" "1453": "Set up ComputeVoxelIrradianceAt() to sample based on the surface reflection direction" "1564": "Update UpdateVoxel() to use our light_atlas_tile, respecifying the latter as light_atlas_texel containing a Value, introducing OffsetFromTexel()" "1828": "Update TestCast(), TestSphere(), FullCast() and ComputeLightPropagationWork() to use our light_atlas_texel" "2048": "Update ComputeLightPropagationWork() to blur from the SpecAtlas to the DiffuseAtlas, introducing a version of OffsetFromTexel() that takes a Tx and Ty" "2363": "Respecify BlockCopyVoxel() as BlockCopyAtlas()" "2681": "Introduce CopyTile(), a light_atlas_texel version of AdvanceRow(), and ZeroTile()" "2996": "Update BeginLightingComputation() to use BlockCopyAtlas() on both atlases" "3040": "Consider adding assertions in our new code to aid testing" "3083": "Hit a read access violation in FillLightAtlasBorder()" "3125": "Run in debug mode without crashing" "3169": "Hit a read access violation in FillLightAtlasBorder() in release mode" "3207": "Introduce GetTileUnclamped() to CopyTile() and ZeroTile() to use, asserting that we are looking up within the bounds of the atlas" "3364": "It's all just moving memory around" "3386": "Fix compile error" "3391": "Hit a read access violation in ComputeLightPropagationWork(), and determine to hunt for classes of bugs" "3452": "Assert in GetTileUnclamped() that Tx and Ty are in bounds, and there and also in OffsetFromTexel() and AdvanceRow() that the resulting pointer is in bounds, introducing PointerIsInBounds()" "3702": "Hit our PointerIsInBounds() assertion in GetTileUnclamped()" "3744": "Remove the LIGHT_LARGE_VOXEL_DIM definitions from lighting_solution, and propagate this change" "3905": "Embark on updating BeginLightingComputation() to place our hot voxel, removing LIGHT_CHUNK_COUNT, augmenting lighting_solution with LightingEnabled and turning off the lighting for now" "4108": "See no lighting" "4138": "Disable the lighting in CompileZBiasProgram()" "4148": "See the orphanage with no lighting, hop to the neighbouring room and hit our PointerIsInBounds() assertion in GetTileUnclamped()" "4217": "Run in debug mode to investigate our PointerIsInBounds() assertion hit in GetTileUnclamped()" "4273": "Fix PointerIsInBounds() to find the atlas extents using GetLightAtlasSize()" "4296": "Hit our PointerIsInBounds() assertion in AdvanceRow(), called by ZeroTile()" "4379": "Remove the PointerIsInBounds() assertion from AdvanceRow(), instead asserting the same within CopyTile() and ZeroTile()" "4444": "Hit no assertions in the light_atlas_tile code" "4465": "Make BeginLightingComputation() draw the voxels" "4513": "Hit an assertion in GetTileUnclamped(), called by BlockCopyAtlas() within BeginLightingComputation()" "4925": "Fix BlockCopyAtlas() to correctly operate within bounds" "5112": "Run without hitting any assertions in GetTileUnclamped(), with a few words on paranoid bounds checking" "5202": "Check out the unexpectedly large and correctly centred lighting voxel" "5250": "Re-enable the lighting in BeginLightingComputation()" "5258": "Double-check the lighting distribution code in EndLightingComputation()" "5276": "Run in debug mode without hitting any assertions" "5303": "Run in release mode and hit a read access violation in ComputeLightPropagationWork()" "5398": "Toggle off the specular–diffuse atlas blurring code in ComputeLightPropagationWork()" "5414": "Run successfully in release mode" "5454": "Toggle on the specular–diffuse atlas blurring code in ComputeLightPropagationWork()" "5468": "Consider removing LIGHT_ATLAS_OFFSET()" "5523": "Scour for bugs the specular–diffuse atlas blurring code in ComputeLightPropagationWork()" "5691": "Toggle off the store calls in ComputeLightPropagationWork()" "5711": "Break on the final Transpose() call in ComputeLightPropagationWork() and check the asm to ensure the blurring loop has not been optimised out" "5750": "Continue to run without storing, but also without crashing" "5765": "Fix ComputeLightPropagationWork() to use the DiffuseTexel.Value pointer itself, rather than its address" "5798": "Run successfully with the specular–diffuse blurring and bouncing" "5821": "Re-enable the lighting in CompileZBiasProgram()" "5840": "Admire our diffuse lighting" "5913": "Try hard-setting the SampleRefColor to 70% in FullCast()" "5981": "See the light brighten and brighten" "6004": "Try decreasing the SampleRefColor from 70% to 25% in FullCast()" "6015": "See the light's brightness remain stable" "6030": "Try increasing the SampleRefColor from 25% to 50% in FullCast()" "6035": "Hit a write access violation in the debug arena" "6051": "Admire our diffuse lighting" "6066": "Remove the commented out reflectance code from ComputeVoxelIrradianceAt(), and the SampleRefColor hard-setting from FullCast()" "6139": "Try modifying the W by ×0.25 in BuildDiffuseLightMaps()" "6189": "See our lighting bounce less" "6197": "Try increasing the W modification from ×0.25 to ×0.5 in BuildDiffuseLightMaps()" "6199": "Hit a write access violation in DEBUGGetArena()" "6222": "Check out our ×0.5 bounced lighting" "6241": "Try increasing the W modification from ×0.5 to ×0.75 in BuildDiffuseLightMaps()" "6243": "Check out our more correct ×0.75 bounced lighting" "6329": "Try increasing the W modification from ×0.75 to ×0.85 in BuildDiffuseLightMaps()" "6338": "Check out our ×0.85 bounced lighting, with the determination to tighten our lighting equation" "6414": "Try increasing the W modification from ×0.85 to ×0.9 in BuildDiffuseLightMaps()" "6416": "Check out our ×0.9 bounced lighting" "6459": "Try increasing the W modification from ×0.9 to ×0.95 in BuildDiffuseLightMaps()" "6463": "Check out our still stable ×0.95 bounced lighting" "6538": "Remove the W modification from BuldDiffuseLightMaps()" "6547": "Check out our (slowly destabilising) bounced lighting" "6594": "Q&A" "6630": "Q: What is the cause of the flickering in the lighting? Will you do some de-noising or cast more rays in the future to try to fix it?" "6654": "Try modifying the W by ×0.975 in BuildDiffuseLightMaps()" "6737": "Q: I think you might have flipped the tx / /ty in TestSphere() while rewriting the code" "6753": "Q: Could it be useful to have it print a value like the average texel color of the diffuse and / or specular maps on the screen?" "6785": "Q: Are you using different level on assert also for release build? Or you only use asserts on debug builds?" "6790": "Disable HANDMADE_INTERNAL and HANDMADE_SLOW in build.bat" "6804": "Hit a read access violation in OpenGLEndFrame(), and identifier not found compile errors" "6826": "Make HANDMADE_INTERNAL define the macros that HANDMADE_SLOW – within HANDMADE_INTERNAL – would have been able to define" "6924": "Run with both HANDMADE_INTERNAL and HANDMADE_SLOW disabled, but asserts enabled" "7013": "Can't find anything with DuckDuckGo" "7047": "Q: How slow are we? Is there any significant change in speed from the changes today?" "7050": "Check out the performance of our lighting" "7266": "Q: And was the goal is to get to 30FPS in debug mode?" "7276": "Q: So we are faster than the previous solution? I don't remember the performance of the old system" "7308": "Consider removing all mentions of LIGHT_LOOKUP_VOXEL_DIM" "7369": "Temporarily reduce LIGHT_LOOKUP_VOXEL_DIM_POW_2 from 5 to 4" "7379": "Admire our much faster lighting" "7422": "Revert our LIGHT_LOOKUP_VOXEL_DIM_POW_2 to 5" "7449": "Q: Can you still parameterise the voxel size? I'm curious if decreasing voxel size will remove some cubeness" "7482": "Q: For what are you still using voxels?" "7540": "Q: Off-topic: Do you see Rust replacing C / C++ in the game industry in the next 5–10 years?" "7865": "Interesting that you think Rust doesn't help with swizzling. There are many libs for it just like C. It's not really a language problem" "7923": "Q: Are there any language features in C++ (that is not borrowed from C) that you like, and are there other language features than metaprogramming, that you want in a new language?" "8019": "Have you looked at the macro power of Rust? You can manipulate the AST as desired" "8042": "Functional languages like Haskell allow developing embedded DSLs and you can write compiler extensions to do symbol replacement" "8182": "Procedural Macros?" "8266": "handmade_hero Oh sorry, I wasn't asking for specific detail. I was just curious if you had looked at it at all" "8329": "Q: Where can I find Moustache?" "8341": "Q: What do you think of clang tooling to create such AST manipulation tools as part of the build pipeline?" "8369": "Wrap this up" --- name: "day587" title: "Optimizing the Specular to Diffuse Transform" markers: "3": "Demo the current state and performance of our lighting" "97": "Reacquaint ourselves with the lighting's blend-over-time parameter in EndLightingComputation()" "182": "Demo the fast-response lighting blend" "191": "Decrease tUpdateBlend from 10/60 to 1/60" "194": "Check out the slower-response, but noiseless lighting blend" "216": "Increase tUpdateBlend from 1/60 to 5/60" "230": "Check out the usable-response, but flickery lighting blend" "261": "Decrease tUpdateBlend from 5/60 to 2/60" "262": "Check out the slower-response, but less flickery lighting blend" "279": "Increase tUpdateBlend from 2/60 to 8/60" "285": "Check out the faster-response, but noisy lighting blend" "322": "Notice light buildup in the dungeon" "356": "Check that light buildup in the dungeon, possibly due to the voxel switch" "418": "Determine to gauge the performance of our specular–diffuse transform" "459": "Consider shrinking the lighting lookup voxel in Z" "553": "Comment out LIGHT_LOOKUP_VOXEL_DIM, and respecify ComputeLightPropagationWork() and EndLightingComputation() to operate in X-slices" "892": "Define MAX_LIGHT_LOOKUP_VOXEL_DIM for InitLighting() to use" "1036": "Replace mentions of LIGHT_LOOKUP_VOXEL_DIM in ComputeLightPropagationWork()" "1235": "Replace mentions of LIGHT_LOOKUP_VOXEL_DIM in CompileZBiasProgram()" "1654": "Reintroduce LIGHT_LOOKUP_VOXEL_DIM for Win32InitOpenGL() to use" "1676": "Get the same thing we saw before" "1690": "Split out LIGHT_LOOKUP_VOXEL_DIM to all three dimensions for Win32InitOpenGL() to use" "1708": "Check out our cubic lighting lookup voxel" "1721": "Decrease the LIGHT_LOOKUP_VOXEL_DIM_Z from 32 to 16" "1729": "Check out our squatter, faster lighting lookup voxel" "1774": "Increase the LIGHT_LOOKUP_VOXEL_DIM_Z from 16 to 32" "1783": "125ms per frame, with a 32×32×32 voxel" "1795": "Decrease the LIGHT_LOOKUP_VOXEL_DIM_Z from 32 to 16" "1804": "75ms per frame, with a 32×32×16 voxel" "1862": "24% frame time spent in ComputeLightPropagationWork()" "1877": "Disable the specular–diffuse transform in ComputeLightPropagationWork()" "1905": "65ms per frame with 3% frame time spent in ComputeLightPropagationWork(), without the specular–diffuse transform" "1938": "Prepare to optimise the specular–diffuse transform" "2016": "Re-enable the specular–diffuse transform in ComputeLightPropagationWork()" "2032": "25% frame time spent in ComputeLightPropagationWork()" "2039": "Disable the specular–diffuse transform in ComputeLightPropagationWork()" "2043": "Hit assertion in DEBUGGetArenaByLookupBlock()" "2073": "3% frame time spent in ComputeLightPropagationWork(), without the specular–diffuse transform" "2114": "Enable ComputeLightPropagationWork() to count up the zero weights" "2281": "Step in to ComputeLightPropagationWork() to find a ZeroWCount of 196" "2362": "Consider our potential for optimising ComputeLightPropagationWork()" "2409": "Inspect the assembly of the specular–diffuse transform in ComputeLightPropagationWork()" "2514": "Define LIGHT_ATLAS_ASSERT()" "2599": "Inspect the assembly of the specular–diffuse transform in ComputeLightPropagationWork()" "2613": "Disable multithreading of the lighting, wondering if RemedyBG supports step-single-thread" "2683": "Inspect the assembly of the specular–diffuse transform in ComputeLightPropagationWork()" "2975": "Optimise ComputeLightPropagationWork() to load and shuffle a row at once, introducing LoadF32_4X() and Broadcast4x()" "4535": "Inspect the assembly of the specular–diffuse transform in ComputeLightPropagationWork()" "4588": "Re-enable multithreading of the lighting" "4606": "11% frame time spent in ComputeLightPropagationWork(), but with chromatic aberration" "4652": "Double-check the specular–diffuse transform" "4821": "Fix ComputeLightPropagationWork() to load the specular texels in strides of 4, rather than 12" "4852": "Admire our correct and faster lighting" "4911": "Consider our potential for optimising the specular–diffuse transform: Separable blur" "5460": "Check out our lighting" "5470": "Decrease the light transmission rate from 0.975 to 0.75 in BuildDiffuseLightMaps()" "5483": "More readily see our darker light map viewer" "5548": "Set up ComputeLightPropagationWork() to perform the specular–diffuse transform as a separable filter" "6484": "Check out our lighting" "6500": "Q&A" "6555": "Q: Are there any caching concerns? I'm not familiar with how much data is being pushed around here" "6736": "Q: This scene has a little bit of variance in the lighting between frames. Is there a way to set up this solution so that the scene looks more "static", without taking a significant performance hit?" "6815": "Q: The light seems to be repeating outside of the light box (before the rewrite). Is it still there and, if so, is it a modulus issue?" "6893": "Q: You mentioned something about shaders API being better at this kind of job. I lost your point on that because of me being unfamiliar with the environment. Can you please explain that a little bit more?" "7178": "Q: You often say that there should be some high level language feature which allows you to write SIMD code easier. Can you tell how this feature would exactly look like? Do you mean something like Jon Blow has in Jai (fast SOA, AOS switching)? Can't you do this feature yourself using metaprogramming?" "7265": "Intel Intrinsics Guide is broken, it seems" "7305": "He's got it cached" "7316": "You can't specify specific architecture" "7345": "Plug uops" "7427": "Admire the lighting" "7462": "Close it on up" --- name: "day588" title: "Aligning Light Voxels with the Camera" markers: "3": "Welcome to the stream" "8": "12% frame time (64ms per frame) spent in ComputeLightPropagationWork()" "73": "Consider shrinking the lighting box" "106": "Decrease the LIGHT_LOOKUP_VOXEL_DIM_Y from 32 to 24" "184": "11% frame time (50ms per frame) spent in ComputeLightPropagationWork()" "234": "Consider aligning the light voxel with the camera" "278": "Make UpdateAndRenderWorld() draw the camera bounds" "400": "Check out the camera bounds" "476": "Respecify BeginLightingComputation() to take (and use) the CameraCenterOffset rather than CameraOffsetFromOrigin" "543": "Prepare to align the light voxel with the camera, moving by the more fine-grained world tiles" "669": "Set up BeginLightingComputation() to align the light voxel in two stages: by chunk, then around the camera position" "851": "The lighting remains stable across chunks" "901": "Make BeginLightingComputation() align the light voxel around the camera, introducing RoundToV3S() and augmenting lighting_solution with VoxelCameraOffset" "1268": "The lighting is almost copying backwards" "1313": "Check the lighting in a scrolling room" "1374": "Check the copying in BeginLightingComputation() for bugs" "1468": "Make BeginLightingComputation() factor in the VoxelCameraOffset to the VoxMinCornerHot" "1569": "The lighting copy remains broken" "1583": "Pull out the OriginOffsetForCamera part of the VoxMinCornerHot() computation in BeginLightingComputation()" "1630": "The lighting is indeed copying backwards" "1653": "Invert the computation of VoxMinCornerHot in BeginLightingComputation()" "1678": "The lighting now copies correctly" "1706": "The lighting does not centre correctly" "1779": "Try zeroing out the VoxelCameraOffset in BeginLightingComputation()" "1859": "The lighting centring is worse, as hoped" "1876": "Prevent BeginLightingComputation() from zeroing out the VoxelCameraOffset" "1879": "Reacquaint ourselves with BlockCopyAtlas()" "1999": "Make BlockCopyAtlas() self-documenting" "2113": "Prepare to respecify BeginLightingComputation() to offset the light voxel in the correct direction" "2198": "Consider aligning the light voxel by re-canonicalising its coordinates" "2280": "Revert BeginLightingComputation() to align the light voxel to the OriginP, making UpdateAndRenderWorld() pass as this value the Camera.SimulationCenter mapped into chunk space" "2410": "The light brightens and moves in the opposite direction" "2439": "Try making UpdateAndRenderWorld() pass the Camera.SimulationCenter directly to BeginLightingComputation()" "2472": "The lighting is normal" "2477": "Make UpdateAndRenderWorld() pass to BeginLightingComputation() the Camera.SimulationCenter mapped into chunk space" "2486": "The lighting is nuts" "2501": "Remove VoxelCameraOffset from lighting_solution" "2514": "The light brightens" "2525": "Toggle off the BlockCopyAtlas() calls in BeginLightingComputation()" "2545": "The light still brightens" "2551": "Reinstate the BlockCopyAtlas() calls in BeginLightingComputation()" "2592": "The light brightens" "2607": "Remove the light probe data from lighting_solution, and make UpdateAndRenderWorld() pass the Camera.SimulationCenter directly to BeginLightingComputation()" "2620": "The lighting is normal" "2641": "Make UpdateAndRenderWorld() pass to BeginLightingComputation() the Camera.SimulationCenter mapped into chunk space" "2649": "The light voxel moves, but barely" "2668": "Scour BeginLightingComputation() for bugs that may affect the lighting accumulation" "2768": "The lighting region moves in the opposite direction" "2811": "Scour BeginLightingComputation() for lighting region movement bugs" "2882": "Try making BeginLightingComputation() invert the dChunk" "2927": "The lighting moves oddly" "2937": "Revert the lighting movement code in BeginLightingComputation()" "2967": "What Is Happening??? [Light voxel alignment]" "3306": "Focus on the VoxMinCornerHot in BeginLightingComputation()" "3446": "Make UpdateAndRenderWorld() pass the Camera.SimulationCenter directly to BeginLightingComputation()" "3452": "The lighting is normal" "3474": "Make UpdateAndRenderWorld() draw the SimBounds" "3496": "The lighting bounds are not centred about the simulation region" "3545": "Try making UpdateAndRenderWorld() set the SimBounds from the Camera.SimulationCenter" "3716": "The lighting bounds remain not centred about the simulation region" "3721": "Scour UpdateAndRenderWorld() for lighting bounds centring bugs" "3793": "Try making BeginLightingComputation() draw a centred 1³ HotVoxelRect" "3830": "See nothing" "3834": "Increase the HotVoxelRect size from 1³ to 10³ in BeginLightingComputation()" "3846": "The lighting bounds are not centred about the simulation region" "3864": "Try making UpdateAndRenderWorld() draw a centred 10³ rectangle from the same Camera.SimulationCenter" "3922": "This Camera.SimulationCenter rectangle is also in the wrong place" "3939": "Make UpdateAndRenderWorld() draw the SimBounds, and BeginLightingComputation() invert the centring of the HotVoxelRect" "3987": "The HotVoxelRect is centred" "3993": "Make BeginLightingComputation() invert the VoxMinCornerHot offset" "4043": "The light voxel is now aligned to the simulation region" "4106": "Make UpdateAndRenderWorld() pass to BeginLightingComputation() the Camera.SimulationCenter mapped into chunk space" "4125": "The light voxel moves with the camera, but not centred" "4175": "Make BeginLightingComputation() take a SimOriginP from which to offset the VoxMinCornerHot" "4341": "The light voxel moves with the camera, centred" "4429": "Increase the SimBounds size in UpdateAndRenderWorld()" "4465": "Check out our expanded SimBounds" "4536": "Make BeginLightingComputation() move the lighting bounds by the more coarse-grained chunk" "4581": "The lighting bounds moves by the more coarse-grained chunk" "4625": "Consider voxel centres" "4643": "The lighting copy looks roughly correct" "4728": "Set up BeginLightingComputation() to move the lighting bounds by the more fine-grained voxel" "4898": "Check out the lighting" "4909": "Make BeginLightingComputation() account for the camera offset when moving the lighting bounds" "5000": "The lighting bounds are drawn properly positioned" "5041": "Make BeginLightingComputation() copy the lighting into position as the bounds move, augmenting lighting_solution with VoxCameraOffset" "5212": "The lighting is entirely correct" "5236": "Toggle off the light map viewers in OpenGLEndFrame()" "5250": "Admire the lighting" "5256": "Toggle off the lighting debug visualisation in BeginLightingComputation() and UpdateAndRenderWorld()" "5274": "Traverse the world admiring the lighting, and note light transmission problems" "5473": "Determine to optimise the ray caster, improve the light quality, add collectors for trees and colour the walls correctly" "5622": "Q&A" "5648": "Q: How can we disable lighting for the debug UI?" "5700": "Looks like OBS is skipping a lot of frames due to encoding lag. Even the webcam is low FPS when you move in-game" "5776": ""Dropped frames" are due to network only, you need to go to View → Stats to see skipped frames, handmade_hero" "5833": "The game is probably fighting OBS for the GPU" "5973": "Q: I read a twitter conversation from an engine programmer at id software, about the engine for the new Doom game not having a main thread or render thread, only tasks and queues. Could you comment on this architecture?" "6063": "Q: I think that is a twitch problem on the servers because Jon on his stream got the same problem where the frame rate on the game gets lower while streaming, and only on twitch it looks laggy. So maybe backend stuff on twitch" "6340": "Q: You once mentioned that there are two types of GPU: tiled and non tiled, and mobiles use the tiled method. But why? What are the benefits for mobiles of using it?" "6696": "Q: Fabian recently described GPUs as possessing throughput caches as opposed to latency caches. How does a throughput cache operate differently than a latency cache?" "6962": "Q: But why are desktops using non-tiled method then? It looks like a clear benefit, including the fact that there are lots of units nowadays" "7118": "Q: The new COD Battle Royale installs a shader for better game performance when being in the game. I thought shaders are "GPU programs". Can you imagine what might be behind that? It takes quite a while to install" "7278": "Q: But on OpenGL I think there is now a way to compile the shader and read it back?" "7425": "Q: Pardon me for I did not catch the end of the stream; but, what frame rate (time per frame) are we at now? I believe at the start we were at roughly 60 ms" "7431": "68ms per frame" "7502": "Decrease the LIGHT_LOOKUP_VOXEL_DIM_X and Y from 32 / 24 to 24 / 16 respectively" "7527": "Check out the lighting" "7537": "Make BeginLightingComputation() offset the light voxel two cells into the distance" "7563": "33ms per frame" "7634": "Q: Could you recommend some literature / resources etc. to dig deeper?" "7644": "Q: So could it be easier to not have this dimension in a define? So that maybe the world gen can produce per-room voxel dim? That would result in optimized light system in general, I guess?" "7659": "Q: What do you think about the new kind of pipeline that NVIDIA is pushing with mesh and task shaders?" "7681": "Q: If we had a major light source from behind and we had, say, a large tree / house behind us, if this light box is too small, would it mean we would not get the shadow of whatever is behind us?" "7758": "Q: Is it possible to make these 2D trees cast shadows in the shape of a tree on the ground? If yes, can you tell what keyword should I write in google to find out more about that? I wanna use it in my own 2D game" "7868": "Q: Would solving the lighting wrapping in X reduce CPU load to significant extent?" "7880": "Q: Would you consider using compute shaders for some of these lighting calculations?" "7938": "Wrap it up" --- name: "day589" title: "Aligning Sampling Spheres with the Octahedral Map" markers: "3": "Welcome to the stream" "9": "Demo our more tightly bound lighting region, at 33ms per frame" "119": "Determine to optimise the lighting ray caster, then improve the quality" "191": "80% frame time (40ms per frame) spent in FullCast()" "271": "Check the lighting performance statistics" "313": "Remove all mention of light probes from the entity system" "575": "Check the lighting performance statistics, with the determination to simplify the full cast" "767": "Add a RaysPerProbe DEBUG_VALUE in EndLightingComputation()" "858": "RaysPerProbe: 72" "880": "Determine to perform 64-ray stratified sampling" "1045": "Set up to make FullCast() light the texels directly" "1159": "Modify FullCast() to load and store back to the texels directly, introducing StoreF32_4X()" "2402": "Consider welding the texel loading / storing into RayCast()" "2446": "Weld FullCast()'s texel loading / storing into RayCast(), removing raycast_result and TestCast()" "3097": "The light seems to accumulate infinitely" "3140": "Consider relieving RayCast() of computing the normal" "3281": "Try making FullCast() cast rays in known directions" "3442": "The lighting accumulates stably" "3490": "Introduce GeneratePoissonLightingPattern() and GenerateOctahedralLightingPattern() based on GenerateLightingPattern(), and InterleaveDirections()" "3915": "Plan to generate a blue noise sphere to be evaluated within each tile" "4054": "Introduce GeneratePoissonDistribution()" "4891": "Invoke hhsphere 16 16 sphere_test.inl" "5005": "Peek at our lighting" "5063": "Fix GenerateOctahedralLightingPattern() to pick from the octahedral map correctly" "5071": "Invoke hhsphere 16 16 handmade_sampling_spheres.inl" "5135": "See no noise reappear" "5149": "Double-check GenerateOctahedralLightingPattern() for bugs" "5208": "The light has accumulated infinitely" "5224": "Make EndLightingComputation() draw the sampling spheres" "5486": "See the submerged sampling sphere" "5497": "Make EndLightingComputation() elevate the sampling spheres" "5522": "Admire our 2D sampling sphere" "5548": "Fix GenerateOctahedralLightingPattern() to set the Pick before marking the Check as used" "5572": "Invoke hhsphere 16 16 handmade_sampling_spheres.inl" "5611": "Admire our correctly 3D sampling sphere" "5648": "Make EndLightingComputation() colourise the sampling sphere by region" "5674": "Admire our coloured sampling sphere" "5701": "Toggle off the sampling sphere drawing in EndLightingComputation()" "5718": "75% frame time (30ms per frame) spent in FullCast()" "5762": "Scour RayCast() and FullCast() for sampling bugs" "5835": "Assert in FullCast() that RayBundleIndex <= LIGHT_SAMPLING_RAY_BUNDLES_PER_SPHERE" "5864": "Fail to hit that assertion" "5872": "Assert in FullCast() that DirSampleIndex < LIGHT_SAMPLING_SPHERE_COUNT" "5882": "Fail to hit that assertion" "5891": "Continue to scour FullCast() and RayCast() for sampling bugs" "6019": "Fix RayCast() to correctly set S1 and S2" "6029": "Admire our correct lighting" "6081": "Q&A" "6124": "Q: When will brogramming return?" "6161": "Q: I don't really use "static" anywhere and I've been fine without it. Am I doing something wrong?" "6282": "Q: Is 3D shear transformation useful in graphics programming for games? How to construct 4x4 shear matrix?" "6408": "Shear Matrix" "6758": "Q: Yeah, makes sense. Thank you" "6761": "Q: Which kind of light does Handmade Hero support? Did I assume right it supports any as long you put light correctly? Maybe moon light can be a planar light put over rooms marked as "outside"" "6825": "Q: Can you check how much slower the build is if you define internal to nothing?" "6846": "4.887 seconds -O2 build" "6863": "2.203 seconds -Od build" "6896": "#define internal to nothing" "6907": "2.360 seconds -Od build, without internal" "6922": "Remove hhsphere.cpp from the compilation" "6934": "2.000 seconds -Od build, without internal or hhsphere.cpp" "6943": "#define internal static" "6951": "1.969 seconds -Od build, without hhsphere.cpp" "6969": "#define internal to nothing" "6973": "2.000 seconds -Od build, without internal or hhsphere.cpp" "6983": "#define internal static" "6989": "4.375 seconds -O2 build, without hhsphere.cpp" "7013": "#define internal to nothing" "7016": "4.657 seconds -O2 build, without internal or hhsphere.cpp (with an "unresolved external symbol memcpy" error)" "7023": "Investigate the "unresolved external symbol memcpy" error" "7134": "Mark Copy() as static rather than internal" "7137": "Build and still hit that "unresolved external symbol memcpy" error" "7146": "Mark Copy() as internal" "7182": "#define internal static" "7184": "4.390 seconds -O2 build, without hhsphere.cpp" "7206": "Q: You REM'd something and forgot to unREM it?" "7244": "Wrap it up" --- name: "day590" title: "Starting Raycast Optimizations" markers: "2": "Welcome to the stream with a plug of the post-stream stream on Jon Blow's channel" "105": "Demo our stochastically sampled lighting, with the determination to optimise the ray caster" "268": "Check the lighting performance statistics" "413": "Calculate our ray casting cycle budget: 2000 cycles per cast" "546": "Consider our scope for optimising RayCast()" "664": "Comment out two unwanted ifs from RayCast()" "683": "~350k cycles (70% frame time) spent in 6144 calls to FullCast()" "849": "Make ComputeLightPropagationWork() call the ray caster in a checkerboard pattern" "1008": "Check out our lighting" "1039": "Toggle on the light maps viewers in OpenGLEndFrame()" "1061": "Check out the light maps" "1080": "Make OpenGLChangeToSettings() zoom out of the light maps" "1124": "Check out the light maps" "1149": "Double-check out checkerboard code in ComputeLightPropagationWork()" "1201": "Consider our checkerboard to be correct" "1226": "Make ComputeLightPropagationWork() checkerboard the ray caster calls in X" "1266": "Check out the checkerboard light maps" "1294": "Make ComputeLightPropagationWork() flip the checkerboard mode each frame" "1383": "~175k cycles (62% frame time) spent in 3072 calls to FullCast()" "1439": "Make OpenGLChangeToSettings() zoom in to the light maps, and toggle them off in OpenGLEndFrame()" "1459": "Admire our lighting" "1486": "This makes the propagation twice as slow, though, right?" "1563": "Consider our scope for optimising RayCast(): Casting against bundles of boxes" "1902": "Ray cast against bundles of boxes, respecifying RayCast() as BoxWiseRayCast() and introducing lighting_box_4x" "2189": "Consider how best to determine whether to push a box onto the stack or record a hit" "2427": "Spec out the box bundle pushing in BoxWiseRayCast(), written to hopefully generate a conditional move" "2686": "Consider approaching box-bundle ray casting another way" "2808": "Consider turning this into a codex-style problem: Writing what we can do, then encoding a hierarchy that accommodates what we've written" "3070": "Try making BoxWiseRayCast() always load 4-wide, and set a mask as it descends the box hierarchy, introducing light_box_stack_entry" "3312": "Consider what the mask gains us" "3400": "Write our dream version of box-bundle ray casting" "3450": "Consider how to push the boxes most efficiently" "3523": "Work through efficient box bundle pushing in BoxWiseRayCast(), removing light_box_stack_entry and augmenting lighting_box with IsLight_IsLeafContainer" "4091": "20ms per frame, without ray casting" "4121": "Make SplitBox() set IsLight_IsLeafContainer" "4318": "The ray casting doesn't fully happen" "4345": "Scour SplitBox() for possible bugs" "4447": "Check the lighting performance statistics: 0 TotalPartitionsTested, 0 TotalPartitionLeavesUsed" "4465": "Scour RayCast() for possible bugs" "4550": "Step in to RayCast(), wondering if RemedyBG can freeze threads" "4595": "Disable multithreading in EndLightingComputation()" "4620": "Step in to RayCast(), see TotalPartitionsTested increment on the first frame, but not on subsequent frames" "4874": "Enable SplitBox() to unset LightBox_IsLeafContainer if it did split" "4950": "50ms per frame, single-threaded, with a correctly lit world" "4988": "Enable multithreading in EndLightingComputation()" "4998": "20ms per frame, with a correctly lit world" "5125": "Stop timing FullCast() and ComputeLightPropagationWork()" "5171": "20ms per frame, EndLightingComputation and Frame Display vying for the top consumer spot" "5230": "Disable the checkerboard in ComputeLightPropagationWork()" "5248": "30ms per frame, 50% frame time in EndLightingComputation" "5287": "Toggle off the specular–diffuse transform in ComputeLightPropagationWork()" "5313": "30ms per frame, 47% frame time in Frame Display, 40% frame time in EndLightingComputation" "5324": "Toggle on the specular–diffuse transform in ComputeLightPropagationWork()" "5331": "22–30ms per frame, up to 50–70% frame time in EndLightingComputation" "5376": "Try making SplitBox() split boxes into eight" "5390": "24ms per frame, 67% frame time in EndLightingComputation" "5398": "Try making SplitBox() split boxes into two" "5403": "24ms per frame, 67% frame time in EndLightingComputation" "5407": "Try making SplitBox() split boxes into four" "5411": "24ms per frame, 67% frame time in EndLightingComputation" "5423": "Consider casting more rays, four out of the same slot" "5506": "30ms per frame, 48% frame time in EndLightingComputation" "5516": "Toggle off the specular–diffuse transform in ComputeLightPropagationWork()" "5518": "30ms per frame, 44% frame time in EndLightingComputation" "5528": "Toggle on the specular–diffuse transform in ComputeLightPropagationWork()" "5530": "30ms per frame, 48% frame time in EndLightingComputation" "5546": "Toggle off the specular–diffuse transform in ComputeLightPropagationWork()" "5549": "24ms per frame" "5560": "Toggle on the specular–diffuse transform in ComputeLightPropagationWork()" "5564": "26ms per frame" "5597": "Decrease tUpdateBlend from 8/60 to 4/60 in EndLightingComputation()" "5609": "Check out the lighting flicker" "5622": "Decrease tUpdateBlend from 4/60 to 1/60 in EndLightingComputation()" "5626": "Check out the lighting flicker" "5636": "Increase tUpdateBlend from 1/60 to 2/60 in EndLightingComputation()" "5638": "Check out the lighting flicker, looking for a stable solution" "5676": "Increase tUpdateBlend from 2/60 to 4/60 in EndLightingComputation()" "5684": "Check out the lighting flicker" "5688": "Decrease tUpdateBlend from 4/60 to 2/60 in EndLightingComputation()" "5691": "Check out the lighting flicker, and consider basing the tUpdateBlend on the light's contribution" "5760": "Increase tUpdateBlend from 2/60 to 8/60 in EndLightingComputation()" "5769": "Check out the lighting flicker" "5812": "Try making FullCast() oversample by 4×, modifying the EntropyIndex each loop" "5885": "Check out the lighting flicker" "5928": "Set tUpdateBlend to 2/60 in FullCast()" "5945": "Admire the flicker-free lighting" "5983": "Remove the oversampling from FullCast()" "6143": "Admire the lighting" "6157": "Q&A" "6184": "Q: Did you notice the instability in timing was connected to the hovering text in the debug UI? The dip seemed correlated with the cursor being on the bar indicating the dip in the debug UI. (When you left the cursor on the same bar it had the dip every time it was passed over, not sure how logical that is.)" "6260": "Damn, the scrolling in your editor is just silky smooth, cmuratori. Is it Emacs, 4coder?" "6270": "Q: What do you think causes the flickering in these lighting calculations? Folks in the chat were discussing it: Do you want the flicker that exists to be more intentional or is it there as a strange side effect of how the lighting is implemented?" "6369": "Integration Over Spatial Samples" "6603": "Q: As previously mentioned in chat, both isLight and IsLeafContainer were 0x1" "6617": "Fix LightBox_IsLight to be 0x2" "6665": "Q: Talking about character movement, will we implement a transaction system, something like Jon's?" "6765": "Check Jon's status" "6827": "Q: Is this already the best lit 2-but-3D game in the whole history of gaming?" "6846": "Q: Are you using a diffusion / heat model to average the texture samples over space / time?" "7132": "Q: Is it okay to use some features from later versions of C++ I may find useful, e.g. lambdas, templates?" "7432": "Q: Would you mind explaining Transactional and vs. What?" "7688": "Stop the recording now" --- name: "day591" title: "Making a Stand-alone Lighting Performance Test" markers: "1": "Recap and set the stage for the day" "60": "Plug x13pixels' RemedyBG version 0.3.0.0, with a brief history of Microsoft Visual Studio" "309": "Conditional Breakpoints in RemedyBG" "418": "I didn't end up doing that, no" "437": "It was already 15x faster just doing it the "normal" way. Well, okay, there are some tricks under the covers" "464": "Yup!" "468": "Further love for RemedyBG" "757": "Demo the current state of the lighting" "831": "30ms per frame" "900": "Make ComputeLightPropagationWork() a TIMED_FUNCTION" "960": "Check the Threads performance" "1138": "Determine to reduce our time spent ray tracing" "1190": "Describe our two-branch RayCast()" "1345": "Why we separated the collision detection and hierarchy traversal code in RayCast()" "1462": "Inspect the assembly of RayCast()" "1581": "Describe our k-d-tree-like SplitBox()" "1625": "Consider speeding up the hierarchy traversal code in RayCast()" "1794": "Launch VTune" "1859": "Set up to write our lighting data out to file" "2030": "Make BuildSpatialPartitionForLighting() write out the lighting boxes to file, introducing DEBUGDumpData() and a Dump platform_file_type" "2817": "Traverse the world out to the dungeon with a view to triggering a debug dump of the lighting boxes" "2930": "RemedyBG feature request: Editable values" "2946": "Enable the LightBoxDumpTrigger" "2962": "Dump the lighting boxes to file" "2990": "Create hhlightprof.cpp, adding it to build.bat" "3388": "Invoke hhlightprof" "3432": "Fix hhlightprof to correctly get the DumpName" "3441": "Add hhlightprof to RemedyBG" "3532": "Might have to append EXE? Thought that worked, though" "3537": "Launch hhlightprof in RemedyBG" "3574": "Introduce TestRayCast() in hhlightprof" "3756": "Make hhlightprof set up the lighting Solution from our dump" "4004": "Make hhlightprof initialise the SpecAtlas and DiffuseAtlas, and derive the BoxCount from the dump" "4421": "Hit a write access violation on the Solution" "4446": "Initialise the Solution globally" "4469": "Successfully run hhlightprof" "4496": "Step through hhlightprof" "4545": "Fix the order of the arguments to fseek()" "4563": "Step through hhlightprof and inspect the Solution" "4646": "Increase the BoxCount in an effort to allow room for all our child boxes" "4686": "Hit a read access violation on the Box->Radius in BuildSpatialPartitionForLighting()" "4740": "Revert the BoxCount and instead allocate memory for four times that number to allow room for child boxes" "4767": "Hit a read access violation on the Solution->tUpdateBlend in RayCast()" "4774": "Make TestRayCast() initialise the Work" "4806": "Run hhlightprof successfully" "4822": "Make TestRayCast() set up the sampling sphere and cast many rays" "4999": "Run hhlightprof, casting all its rays" "5006": "Prepare to cast enough rays to last a minimum of 10 seconds" "5115": "Make TestRayCast() multiply the rays cast by 256" "5125": "Run hhlightprof for just over 10 seconds, without completing" "5136": "Decrease the ray multiplier from 256 to 32 in TestRayCast()" "5145": "Run hhlightprof for just almost 10 seconds, without completing" "5154": "Decrease the ray multiplier from 32 to 8 in TestRayCast()" "5162": "Run hhlightprof for 9 seconds, to completion" "5172": "Decrease the ray multiplier from 8 to 4 in TestRayCast()" "5180": "Run hhlightprof for 5 seconds, to completion" "5185": "Prepare to time our ray caster in VTune" "5292": "Create a project in VTune for hhlightprof" "5329": "A few words on the sheer plethora of performance counters" "5444": "Set up our project for hhlightprof" "5643": "Run hhlightprof in VTune" "5819": "Run a -O2 build of hhlightprof in VTune" "5831": "Increase the ray multiplier from 8 to 32 in TestRayCast()" "5848": "Run hhlightprof for under 1 second, to completion" "5850": "Increase the ray multiplier from 32 to 256 in TestRayCast()" "5859": "Run hhlightprof for 5 seconds, to completion" "5866": "Run hhlightprof in VTune" "5981": "Check the Hotspots of hhlightprof in VTune" "6105": "Microarchitecture Exploration in VTune" "6195": "Run a Microarchitecture Exploration of hhlightprof in VTune" "6840": "Run a Memory Access analysis of hhlightprof in VTune" "6909": "Reflect on our isolated ray caster" "6941": "Q&A" "6983": "Q: Might be a good idea to explain the difference between sampling and instrumentation profilers and how they work on some basic level, and why sampling profiling is not great idea, despite most people believing and saying that it is very good" "7119": "Q: VTune organizes those metrics by something called the "top-down performance analysis methodology". There is a pretty detailed paper that introduced this that would likely help" "7129": "Q: Have you ever tried using clang-cl? It's a drop-in MSVC compatible compiler that has much better codegen than MSVC CL. It's compatible with link.exe, but even lld-link will give you usable PDBs. When I used it in my ray tracer, it ended up being 15 times faster than with regular MSVC CL" "7260": "Q: Games like CS:GO go up to 300fps. Are they pretty good optimized? Seems like getting Handmade Hero to that FPS would be hard?" "7303": "Q: I think you never use the sphere sampling direction in hhlightprof, also when dumping boxes, you write out Solution->BoxCount * sizeof(Solution->Boxes), the sizeof takes the size of a pointer instead of a lighting_box" "7307": "Fix the SampleDirB setting in TestRayCast()" "7324": "Q: What's the status of meowhash? Will it be reaching a new version soon?" "7371": "Q: Have you tried debugging why the stream loses so many frames when you move the character around?" "7424": "Q: What should meowhash (not) be used for?" "7647": "Q: Are you sure the hash is "secure"? People have previously pointed out some issues with meowhash, if I recall correctly, generating collisions" "7803": "Q: What do you use meowhash for?" "7814": "Q: Would Handmade Hero run on a 32-bit system as it is now, or would it need porting?" "7822": "Even for security?" "7858": "Q: Not using the SampleDir?" "7861": "Fix TestRayCast() to set (and use) RayD" "7882": "Q: Is meowhash cross platform? For ARM, PowerPC, etc?" "7949": "Q: Any reason we're not using the checkerboard rendering?" "7974": "Begin to wind down the stream, with a plug of the upcoming Jon and Sean talk" "8049": "Q: You use meowhash for normal hash tables in your everyday code, strings, vectors, etc?" "8079": "Anticipate the Jon and Sean talk" "8132": "Wind down the stream" --- name: "day592" title: "Capturing the Entire Lighting Data" markers: "2": "Welcome to the stream" "8": "Plug the Meow the Infinite printed comic Kickstarter and the related fun videos at Molly Rocket's YouTube channel" "246": "Dive into the code" "286": "Fix hhlightprof to allocate memory for four times the BoxCount to allow room for child boxes" "312": "Determine to pseudo-verify our standalone ray tracer" "404": "Determine to learn VTune" "439": "Run hhlightprof for 16 seconds, to completion" "461": "Decrease the ray multiplier from 256 to 64 in TestRayCast()" "471": "Run hhlightprof for 4 seconds, to completion" "480": "Increase the ray multiplier from 64 to 128 in TestRayCast()" "488": "Run hhlightprof for 7 seconds, to completion" "495": "Launch VTune and hunt its interface for custom analysis capabilities" "705": "Launch VTune as administrator" "731": "Consult VTune's documentation" "849": "Research VTune's Hardware Event-based Sampling Collection" "945": "Research VTune's Microarchitecture Exploration Analysis for Hardware Issues" "962": "Research VTune's Custom Analysis" "987": "Create a new "Fruit Salad x12" custom analysis in VTune" "1095": "Some words on x64 performance counters" "1274": "Continue to create our "Fruit Salad x12" custom analysis in VTune" "1405": "Rename "Fruit Salad x12" to "No Counters Template" and clone it as "The Ultimate Fruit Salad"" "1476": "Enable our desired counters in "The Ultimate Fruit Salad"" "1542": "Run hhlightprof in VTune" "1558": "Consult our VTune Hardware Events analysis" "1664": "A few words on 4 µOPs per cycle issuance" "1794": "Continue to consult our VTune Hardware Events analysis" "1844": "Rename "The Ultimate Fruit Salad" to "Instructions Per Clock" and swap out the UOPS_EXECUTED.CORE_CYCLES_NONE counter for UOPS_EXECUTED.CORE_CYCLES_GE_4" "1918": "Run our "Instructions Per Clock" analysis of hhlightprof" "1933": "Consult our "Instructions Per Clock" VTune analysis" "1962": "Interpret our "Instructions Per Clock" VTune analysis" "2076": "Get the Work In More Efficiently vs Do the Work More Efficiently" "2104": "Create a new "Arithmetic Port Usage" custom analysis in VTune" "2296": "Understanding port usage with uops.info" "2588": "Enable the counters of ports 0, 1 and 5, renaming "Arithmetic Port Usage" to "Float Port Usage"" "2648": "Run our "Float Port Usage" analysis of hhlightprof" "2663": "Consult our "Float Port Usage" VTune analysis" "2814": "Create a new "All Ports Usage" custom analysis in VTune" "2864": "Run our "All Ports Usage" analysis of hhlightprof" "2880": "Consult our "All Ports Usage" VTune analysis, noting that port 4 is the write port" "3026": "Interpret our "All Ports Usage" VTune analysis, desiring to Get the Work In More Efficiently" "3154": "Determine to validate our code" "3219": "Step through an -Od build of hhlightprof" "3518": "Disable the LightBoxDumpTrigger" "3526": "Continue to step through hhlightprof" "3745": "Make EndLightingComputation() call DEBUGDumpData() on the SpecAtlas, DiffuseAtlas, and the entire lighting Solution" "4051": "Dump the lighting data to file" "4109": "Check out our lighting debug dumps" "4132": "Make TestRayCast() in hhlightprof do the full ComputeLightPropagationWork(), replacing Commands in the lighting_work with the DiffuseAtlas and SpecAtlas" "4493": "Introduce LoadEntireFile() in hhlightprof, and load in all our lighting dumps" "4861": "Set up hhlightprof to use our loaded dumps" "5112": "Hit a write access violation on the Solution->SamplingSpheres" "5141": "Hit a write access violation on Byte in ZeroSize()" "5145": "Allocate memory for the Solution->Works" "5291": "Run hhlightprof successfully" "5301": "Make hhlightprof validate our SpecAtlas texels" "5474": "Run hhlightprof with non-zero errors" "5517": "Run hhlightprof in -O2 with non-zero errors" "5522": "Make hhlightprof print the TexelCount" "5548": "Run hhlightprof with non-zero errors" "5571": "Try making hhlightprof overwrite the tUpdateBlend as 1.0f" "5629": "Run hhlightprof with a similar number of errors" "5672": "Double-check our SpecAtlas validity checking" "5704": "Try making hhlightprof overwrite the tUpdateBlend as 0.0f" "5722": "Run hhlightprof with a changed number of errors" "5741": "Try making hhlightprof overwrite the tUpdateBlend as 100.0f" "5755": "Run hhlightprof with an infinite number of errors" "5763": "Try making hhlightprof overwrite the tUpdateBlend as 10.0f" "5774": "Run hhlightprof with many errors" "5776": "Try making hhlightprof overwrite the tUpdateBlend as 1.0f" "5782": "Run hhlightprof with few errors" "5793": "Prevent hhlightprof from overwriting the tUpdateBlend" "5801": "Continue to scour hhlightprof and Handmade Hero's lighting system for inconsistencies" "6227": "Make TestRayCast() set the Work->VoxelX" "6279": "Run hhlightprof, still with errors" "6294": "Introduce InternalLightingCore() to perform our dumps" "6562": "Run hhlightprof, still with errors" "6573": "Q&A" "6598": "Q: Is it still building under the overdose flag?" "6632": "Q: Maybe capture a single threaded run?" "6725": "Q: On your UOPS info table earlier in the stream, you were set to Skylake rather than Kaby Lake, just in case that's why you were seeing issues then" "6929": "Q: Have you considered releasing your C course earlier as a beta release (even full price) just because so many of us and people we know are currently on quarantine!" "6959": "How long would the course be?" "7044": "Q: Is it really bad on x86 to do unaligned pointers? Because I have a packed structure with pointers and the compiler is warning me about unaligned pointers. (Apparently there is a declspec to allow unaligned pointers?)" "7215": "Q: Do instructions with memory operands actually use the arithmetic units before the data is ready?" "7383": "Q: Is it going to be useful for hardcore fans of Handmade Hero?" "7431": "Q: Will the course be project-based, where throughout the course you'll be making x or y project?" "7440": "Q: Is there an API to access the performance counters so you don't have to use VTune?" "7545": "Wrap it up with a plug of the Meow the Infinite printed comic Kickstarter and related fun videos at Molly Rocket's YouTube channel" --- name: "day593" title: "Debugging Lighting Validation" markers: "3": "Plug the Meow the Infinite printed comic Kickstarter and tease the related fun stuff in celebration of it" "52": "Recap our lighting discrepancy between the game and hhlightprof" "120": "Change the dump file paths in hhlightprof, with the determination to dump new lighting data in a single-threaded run of the game" "178": "Make InternalLightingCore() disable the LightBoxDumpTrigger() after dumping one set of data" "245": "Hit our Work alignment assertion in InternalLightingCore()" "282": "Build in -Od" "295": "Hit our Work alignment assertion in InternalLightingCore()" "306": "RemedyBG bug report: AND'ing a location with an integer" "373": "Sheeet. I'll get that fixed" "387": "Fix the BigPad in lighting_work" "472": "Run without hitting that alignment assertion in InternalLightingCore" "493": "Run the game with the determination to capture lighting dumps" "553": "Add the LightBoxDumpTrigger to the debug UI in EndLightingComputation()" "606": "Dump our multithreaded lighting" "625": "Disable multi-threading of the lighting" "643": "Dump our single-threaded lighting" "693": "Re-enable multi-threading of the lighting" "710": "Run hhlightprof on the single-threaded lighting data, with errors" "743": "Run hhlightprof on the multi-threaded lighting data, also with errors" "763": "Scour hhlightprof for bugs" "997": "Make InternalLightingCore() dump the light Boxes and BoxTable after the BuildSpatialPartitionForLighting() call" "1209": "Dump our lighting" "1237": "Make hhlightprof load in and validate the Boxes and BoxTable" "1492": "Run hhlightprof to find that the light boxes don't match" "1510": "Make hhlightprof validate the BoxTable" "1576": "Run hhlightprof to find that the boxrefs don't match" "1601": "Note the simplicity of BuildSpatialPartitionForLighting()" "1653": "Enable the LightBoxDumpTrigger, to dump the first frame of lighting" "1679": "Break in to InternalLightingCore()" "1723": "Fix InternalLightingCore() to dump the correct amount of light boxes at the head" "1751": "Dump our lighting" "1774": "Run hhlightprof to find that the light boxes still don't match, but the error / texel is much lower" "1956": "Fix InternalLightingCore() to dump the correct amount of light boxes after BuildSpatialPartitionForLighting()" "1987": "Dump our lighting" "2002": "Run hhlightprof to find that the light boxes now match" "2020": "Check InternalLightingCore() for BoxTable dumping errors" "2058": "Step in to InternalLightingCore() and inspect the BoxTable values" "2131": "Step through hhlightprof and find the BoxTable file size to be wrong" "2318": "Step through the DEBUGDumpData() of the BoxTable" "2364": "Add a SetFileSize() function pointer to the platform" "2975": "Make DEBUGDumpData() call SetFileSize()" "3003": "Dump our lighting" "3031": "Run hhlightprof to find that the light refs now match" "3049": "Make hhlightprof record the max error / texel;" "3087": "Max error / texel: 0.001786" "3176": "Dump our lighting in -O2, with a max error / texel of 0.001814" "3189": "Disable the LightBoxDumpTrigger" "3214": "Walk through the orphanage and dump our lighting" "3234": "Max error / texel: 0.001195" "3240": "Walk outside and dump our lighting" "3252": "Max error / texel: 0.002587" "3261": "Walk down to the dungeon and dump our lighting" "3271": "Max error / texel: 0.009179, and the light boxes don't match" "3318": "Consider how to proceed" "3385": "Run our "Instructions Per Clock" analysis of hhlightprof" "3513": "Make InternalLightingCore() compute 5 seconds of lighting" "3644": "Introduce ProfileRun() in hhlightprof, to run it multiple times" "3725": "Run hhlightprof for 9 seconds, to completion" "3743": "Decrease the iterations of ProfileRun() from 60*5 to 60" "3762": "Run hhlightprof for 3 seconds, to completion" "3768": "Increase the iterations of ProfileRun() from 60 to 60*2" "3782": "Run our "Instructions Per Clock" analysis of hhlightprof" "3803": "Consult our "Instructions Per Clock" VTune analysis" "3842": "Optimisation Opportunities: 1) Post-processing textures" "3883": "Optimisation Opportunities: 2) Accessing the lighting_box in the spatial partition" "3943": "Optimisation Opportunities: 3) Efficient loading of data" "3967": "Prepare to pack our ray casting data more concisely" "4145": "Run hhlightprof" "4159": "Make hhlightprof record its execution time" "4375": "hhlightprof total seconds elapsed: 7.173237" "4438": "Introduce ray_cast_stack_entry to more concisely store the data needed by RayCast()" "4783": "hhlightprof total seconds elapsed: 8.112103" "4832": "Inspect the assembly of RayCast()" "4928": "Replace ray_cast_stack_entry with a PACK_CAST_ENTRY() for RayCast() to use" "5208": "hhlightprof total seconds elapsed: 7.259090" "5264": "Inspect the assembly of RayCast() to see many jmp instructions" "5343": "Introduce lighting_box_pack for lighting_box to contain, and RayCast() to use" "5625": "hhlightprof total seconds elapsed: 7.063448" "5656": "Inspect the assembly of RayCast() to still see jmp instructions" "5815": "Consult AnyTrue()" "5921": "Let RayCast() push on a box regardless of its proximity" "5946": "hhlightprof total seconds elapsed: 8.120685" "5976": "Revert RayCast() to only push on boxes within a certain distance of the ray's origin" "5986": "Consider determining more efficiently if RayTest() should push a box" "6050": "Make RayTest() determine more efficiently if it should push a box" "6140": "hhlightprof total seconds elapsed: 6.932234" "6168": "Inspect the assembly of RayCast() to still see jmp instructions" "6253": "Try to make RayTest() determine even more efficiently if it should push a box" "6320": "Inspect the assembly of RayCast() to still see jmp instructions" "6347": "Research cmov intrinsic generation" "6423": "Read the gamedev.net forum post "Dependable cmov in Visual C++"" "6457": "Try to make the compiler generate a cmov for the conditional box pushing code in RayTest()" "6556": "Inspect the assembly of RayCast() to still see no cmov instructions" "6567": "Try again to make the compiler generate a cmov for the conditional box pushing code in RayTest()" "6615": "Inspect the assembly of RayCast() to see one cmov instruction" "6641": "Try again to make the compiler generate a cmov for the conditional box pushing code in RayTest()" "6652": "Inspect the assembly of RayCast() to see no further cmov instructions" "6715": "Consult the Intel Intrinsics Guide for mask instructions" "6833": "Try making RayCast() determine in SIMD if it should push a box" "7099": "Inspect the assembly of RayCast() to still see no further cmov instructions" "7184": "Try changing RayCast() to store off the StackAt to write back to the BoxStack" "7230": "Inspect the assembly of RayCast() to see cmov instructions" "7262": "hhlightprof total seconds elapsed: 7.496200" "7293": "Toggle RayCast() back to determine in scalar if it should push a box" "7301": "Inspect the assembly of RayCast() to see our dreaded jmp instructions" "7317": "Try making RayCast() set ShouldPush using a bitwise, rather than a conditional, OR" "7342": "Inspect the assembly of RayCast() to see cmov instructions" "7351": "Consider our ShouldPush setting, in terms of OR'ing" "7452": "hhlightprof total seconds elapsed: 7.360275" "7475": "Inspect the assembly of RayCast()" "7520": "Try making RayCast() compute ShouldPush bitwise OR'ing and AND'ing only tInside, Mask and CloseEnough" "7621": "Inspect the assembly of RayCast()" "7643": "hhlightprof total seconds elapsed: 7.307276" "7660": "Note that it seems cheaper to jmp than cmov" "7707": "Try making RayCast() compute ShouldPush using conditional tests" "7727": "hhlightprof total seconds elapsed: 7.253258" "7736": "Revert RayCast() to the original box pushing code" "7769": "hhlightprof total seconds elapsed: 6.878540" "7785": "Save off our jmp and cmov versions of the box pushing code in RayCast()" "7936": "hhlightprof total seconds elapsed: 6.888590" "7951": "Toggle RayCast() to the slower cmov box pushing code" "7961": "hhlightprof total seconds elapsed: 7.079671" "7991": "Q&A" "8004": "Realise why the cmov version isn't faster" "8096": "Q&A" "8109": "Q: I think the MSDN you were looking at is SetFileInformationByHandle, maybe?" "8160": "Q: Logical || and && are short-circuited, so they will always have a jump, unless compiler can figure out some property that will allow it to collapse the expression. So to avoid jumps one should use bitwise | and & if possible. But also there were some people saying that cmov is worse than a jump over a few instructions. I think LLVM people, but I may be wrong" "8195": "Q: Can't you just use CloseEnough instead of CloserCloseEnough in the ShouldPush assignment? CloseEnough is already AND'd with Mask. Oh, and the assignment of StackY is busted. There is a 0, 1 instead of 2, 3 at the end" "8219": "Fix the StackY setting in RayCast() and toggle to the faster jmp box pushing code" "8257": "hhlightprof total seconds elapsed: 6.963080" "8300": "Toggle RayCast() to the slower, SIMD cmov box pushing code" "8307": "hhlightprof total seconds elapsed: 7.533641" "8319": "Toggle RayCast() to the faster, scalar cmov box pushing code" "8324": "hhlightprof total seconds elapsed: 7.265596" "8340": "Q: Can't you just use CloseEnough instead of CloserCloseEnough in the ShouldPush assignment? CloseEnough is already AND'd with Mask" "8371": "Remove the superfluous CloserCloseEnough from RayCast()" "8417": "hhlightprof total seconds elapsed: 7.195799" "8429": "Toggle RayCast() to the faster jmp box pushing code" "8445": "hhlightprof total seconds elapsed: 6.874347" "8460": "Make a note to try pushing boxes using a circular buffer" "8537": "Q: Somebody in chat had the idea of loading the ray caster through the dll for testing. Could this remove the floating point errors in the test code?" "8605": "Q: Is it possible to structure the game code so it would run reasonably fast in debug mode? Would that be worth the hassle?" "8633": "Q: Will you come to the dark side and try const?" "8680": "Q: When you dropping that low level course?" "8691": "Q: Why have you uploaded the last Handmade Hero episode on Molly Rocket's YouTube account?" "8747": "Q: MSVC is very often not optimizing away obvious things (basically you cannot do so-called zero cost abstractions with it). For example it always does short circuiting. Or from experience, I also remember it sometimes calling empty constructors. Why not use some reasonable compiler like clang / gcc / icc?" "8818": "Q: In one of the first episodes of Handmade Hero you mentioned maybe it would be a good idea to recreate the window if WM_DESTROY was caught in the window procedure. In what sort of scenario does that happen?" "8868": "A few words on the C++ spec effectively preventing the optimising compiler from using const" "8888": "Q: These optimisations seem to be very low level. How do you know when it is worth going to this level vs zooming out to examine the overall algorithm, or memory layout, data volume, etc?" "9020": "Q: Will you be in Jon's talk today? It's already started! Let's go there after" "9030": "Q: I guess what I'm curious about is why you shouldn't just terminate the application if you get WM_DESTROY in the window procedure" "9042": "Q: How many hours do you work a week normally?" "9098": "Q: Has your RSI problem improved from a couple of years back? If so, what helped you?" "9120": "Q: Is it possible to not call VirtualAlloc at all? You can create global array of bytes of whatever size you want and point Persistent / Transient storages to those arrays. Global storage should go to BSS (is it?), and the operating system must allocate enough memory at startup time (and you already allocated a determined amount of space (so you know how much it is at compile time))" "9152": "handmade_hero Hey Casey, I was wondering what's the current plan for Handmade Hero? Will you be releasing pieces of this code to the public domain?" "9167": "Q: What do you use instead of Ctrl / Alt keys? Vim controls?" "9218": "Q: Could you stream your daily working process( of 1935, for example) sometime?" "9232": "Here's an example where adding const with clang induced some optimization (minutes 27–28)" "9277": "Is it important nowadays to still support x86?" "9306": "Apologies if you've answered this before but would there be any chance we'd see Vulkan on Handmade Hero?" "9328": "Wrap it up with a plug of the Meow the Infinite printed comic Kickstarter and related fun videos at Molly Rocket's YouTube channel, and Jon's stream" --- name: "day594" title: "Switching from Center-Radius to Min-Max" markers: "3": "Plug the Meow the Infinite printed comic Kickstarter" "25": "Recap our creation of hhlightprof" "86": "Demo hhlightprof (7.150223 total seconds elapsed)" "151": "Describe the two distinct ray casting / box categorisation routines in RayCast()" "286": "Describe the lighting_box structure, with the determination to reduce extraneous computations by storing the BoxMin and BoxMax" "410": "Replace P and Radius with BoxMin and BoxMax in lighting_box, and begin to propagate this change" "448": "Why compute the BoxMin and BoxMax part way down the lighting pipeline?" "524": "Continue to update the lighting routines to use BoxMin and BoxMax" "983": "Run hhlightprof to find that the light boxes and boxrefs don't match, because our storage format has changed" "1022": "Enable hhlightprof to transform the old Center-Radius dump to the new Min-Max format" "1129": "hhlightprof total seconds elapsed (with the same results as earlier): 6.702761" "1161": "Make a note to remove the dump transform from hhlightprof" "1187": "Reflect on our data storage / computation improvement" "1234": "Further RayCast() optimisations" "1337": "Further RayCast() optimisations: 1) How do we want to store our tree?" "1360": "Further RayCast() optimisations: 2) What does our tree want to look like (e.g. k-d tree)?" "1391": "Further RayCast() optimisations: 3) Do we want the ray casting and the box categorisation in the same loop?" "1439": "Determine to investigate the efficiency of our information streaming" "1494": "Separate the ray casting and box categorisation loops in RayCast()" "1577": "Augment lighting_work with a lighting_box_pack ScratchSpace array" "1646": "Make InternalLightingCore() initialise our new ScratchSpace, and make ProfileRun() in hhlightprof allocate space for it" "1856": "Memory per thread" "1979": "Make a note to add memory per thread" "2030": "A few words on memory per thread" "2095": "Run hhlightprof with the same results" "2107": "Temporarily make RayCast() push lighting boxes onto the ScratchSpace" "2160": "Run hhlightprof with the same results" "2167": "Revert RayCast() to push boxes onto the old stack array" "2200": "CTAssert() lighting_box_pack" "2219": "Make RayCast() do the box pushing and box categorisation in two passes" "2576": "Run hhlightprof with different results" "2594": "Scour RayCast() for bugs" "2688": "Use consistent language in both loops for accessing lighting_box_pack" "2705": "Continue to scour RayCast() for bugs" "2755": "Remove the compiled-out code in RayCast()" "2764": "Continue to scour RayCast() for bugs" "2793": "Run hhlightprof still with different results from originally" "2821": "Toggle RayCast() back to the old one-pass code" "2829": "Run hhlightprof with the same results as originally" "2832": "Toggle RayCast() to the new two-pass code" "2836": "Continue to hunt for inconsistencies between the one-pass and two-pass code in RayCast()" "2913": "Fix the box pushing loop to only push a box if necessary" "2957": "Run hhlightprof with different results from originally" "3008": "Continue to scour RayCast() for bugs" "3061": "Assert in the box categorisation loop that the previously pushed box is a LeafContainer" "3083": "Run hhlightprof without hitting that assertion" "3089": "Continue to scour RayCast() for bugs" "3262": "Q: The while(Depth) loop doesn't wrap the second loop" "3296": "Continue to scour RayCast() for bugs" "3314": "Make hhlightprof stream out to files the box leaves and partitions, introducing RECORD_LEAF_BOX() and RECORD_PARTITION_BOX()" "3593": "Run hhlightprof" "3634": "Make hhlightprof only stream out the first run of box leaves and partitions" "3654": "Run hhlightprof" "3659": "Rename our box leaves and partitions files to new*" "3693": "Toggle RayCast() back to the old one-pass code" "3704": "Run hhlightprof" "3708": "Rename our box leaves and partitions files to old*" "3722": "Try to compare our partitions in Meld" "3834": "Install Beyond Compare" "3899": "Compare our box leaves in Beyond Compare, to see differences" "3973": "Compare our partitions in Beyond Compare, to see differences" "4029": "Toggle RayCast() to the new two-pass code" "4036": "Scour RayCast() for a reason why we're pushing more boxes" "4097": "Consult our box leaves differences in Beyond Compare" "4216": "Continue to scour RayCast() for a reason why we're pushing more boxes" "4236": "Assert in RayCast() that the partitioning loop does not receive a non-leaf container" "4255": "Toggle off the box / partition streaming in hhlightprof" "4314": "Run hhlightprof without hitting that assertion" "4317": "Puzzle over our bug in RayCast()" "4381": "Make ProfileRun() print out the total input and output boxes" "4445": "Run hhlightprof to find a mismatch between the total boxes counts" "4468": "Consult our box leaves differences in Beyond Compare" "4526": "Restrict our dumping to one ray's worth of work" "4680": "Run hhlightprof" "4695": "Enable RECORD_RAYCAST_STACK" "4704": "Run hhlightprof" "4710": "Rename our box leaves and partitions files to new*" "4745": "Toggle RayCast() back to the old one-pass code" "4755": "Run hhlightprof" "4756": "Find our box leaves and partitions dumps to match" "4771": "Increase our dumping to sixteen rays' worth of work" "4813": "Run hhlightprof" "4819": "Consult our box leaves and partitions files to see partition box indices lower than the input box count" "4970": "Reacquaint ourselves with SplitBox()" "5144": "Disable RECORD_RAYCAST_STACK" "5155": "hhlightprof total seconds elapsed: 6.682471" "5168": "Prepare to remove the indirect table-read from SplitBox()" "5303": "Change SplitBox() to split boxes directly into storage, removing AddBoxReferences() and AddBoxReference()" "5798": "Update BuildSpatialPartitionForLighting() to use AddBoxStorage() instead of AddBoxReference()" "5856": "Run hhlightprof with a high max error / texel" "5880": "Check all GetBox() calls, and SplitBox() for bugs" "6028": "Fix AddBoxStorage() to correctly store the box index" "6045": "hhlightprof total seconds elapsed: 6.460956" "6091": "Make a note to remove the BoxRefTable from lighting_solution, removing all mentions of them" "6165": "hhlightprof total seconds elapsed: 6.449993" "6214": "Enable RECORD_RAYCAST_STACK" "6233": "Run hhlightprof" "6242": "Consult our box leaves and partitions files to see high partition box indices, as expected, and rename the files to new*" "6257": "Toggle RayCast() to the new two-pass code" "6266": "Run hhlightprof" "6271": "Rename our box leaves and partitions files to new*, and diff them in Beyond Compare" "6326": "Make RayCast() record box partition pushes, introducing RECORD_PARTITION_PUSH()" "6535": "Toggle RayCast() back to the old one-pass code" "6551": "Run hhlightprof and rename the files to old*" "6592": "Fix RayCast() to call RECORD_PARTITION_PUSH() in the correct place" "6608": "Run hhlightprof and see our pushes in the files" "6631": "Make RECORD_RAYCAST_END() append a newline after each ray" "6652": "Run hhlightprof, see our rays and rename the files to old*" "6678": "Toggle RayCast() to the new two-pass code" "6694": "Run hhlightprof and rename the files to new*" "6703": "Diff our partitions files in Beyond Compare, to see different treatment of boxes 1638 and 1844" "6857": "Set up a breakpoint on box 1638 in RayCast(), and switch the build to -Od" "6954": "Toggle RayCast() back to the old one-pass code, and comment out the __debugbreak()" "6967": "Run hhlightprof and compare these box leaves and partitions with the existing old ones" "6986": "Reinstate the __debugbreak() in RayCast()" "6996": "Run to our __debugbreak() and inspect the values" "7063": "Determine to check that the leaf count is not larger than our available size" "7140": "Make ProfileRun() save the GlobalMaxWorkStackDepth for RayCast() to assert the LeafCount against, toggling RayCast() back to the old one-pass code" "7219": "Toggle RayCast() back to the old one-pass code" "7231": "Run hhlightprof and hit an assertion" "7300": "Toggle off the __debugbreak() in RayCast()" "7327": "Run hhlightprof without hitting our LeafCount assertion" "7334": "Step through RayCast() to see a consistently low LeafCount" "7370": "Consider ProfileRun() to be allocating enough memory" "7409": "Remove our LeafCount assertion from RayCast(), and reinstate the __debugbreak() calls on box 1638" "7454": "Run to our __debugbreak() and inspect Box 1638" "7469": "RemedyBG feature request: Save Watch Window to File" "7489": "Continue to inspect Box 1638, and save off its Min and Max" "7647": "Realise that our two-loop RayCast() will necessarily test more boxes for partitioning because we pushed more leaves onto the stack" "7723": "Remove the two-pass streaming from RayCast(), because we want to early-out" "7741": "Plan to go forward with k-d tree, testing the near side before the far side, and early-out if we hit" "7792": "Remove the __debugbreak() calls from RayCast()" "7811": "Remove the ScratchBuffer from lighting_work" "7875": "Run hhlightprof successfully" "7884": "Run the game successfully" "7921": "Q&A" "7958": "Q: Just wanted to let you know we have an IsMemoryEqual() function. Nice debug work today" "8028": "Q: Off-topic, but I noticed your last blog post is dated 2019" "8085": "Q: Why is it that software companies increasingly seem to not care about performance? I've heard you talk about the technical reasons, but I still don't understand why companies would give up on having better software quality than their competitors. Is it because education is bad? Is it because non-performance oriented software is being normalized to the point people don't care about it? Is it because hardware has been compensating for the lack of software performance?" "8240": "Q: Do you have a git repo for any of your code? Not necessarily Handmade Hero code but something small that I could read to see what sort of "patterns" you use to write good code" "8344": "Q: About my question before the stream started, I am looking for a doubly linked list structure, and usually that's done through a structure with a first and last entry pointers, and those have a structure with a next, prev and value pointers. (Let's call this entry_structure.) In order to add an item to the end of the list you need to create a new entry_structure, set the prev pointer to the previous last entry, and UPDATE THE LAST entry_structure in order to have next point to the new last item. Is there any other structure that represents a doubly linked list without this prerequisite?" "8462": "Q: Are there any scalability / usability issues when using enums vs something like a hash table for indexing assets?" "8590": "Q: Do you know of some sane way of learning a bit of DirectX 11 other than trial and error while scavenging information on MSDN?" "8600": "Q: How would you recommend writing assembly directly for a function if the complier refuses to optimize it the way you want?" "8657": "Q: How important is it, in game development and in general, to be concerned with microarchitecture-level optimizations and using metrics from CPU performance counters?" "8691": "Q: How many lines of code are there in the Handmade Hero project?" "8716": "34,292 lines of code" "8747": "Q: If you do another programming discussion with Jon, do you think it would be valuable do a discussion about entity systems?" "8774": "Q: Visual Studio 19 has support for x86 but not x64 assembly. Why's one in it, but the other isn't? Are they so different from each other?" "8836": "Q: I meant like what you guys consider is a good go-to approach to entities" "8882": "Wonder if we heard back from mattiamanzati about the doubly linked list question" "8961": "Wander around the orphanage" "8999": "Q: I think they wanted to know if there is something that acts like a doubly linked list that isn't actually a doubly linked list" "9042": "Wrap it up with a plug of the Meow the Infinite printed comic Kickstarter and the determination to raid Jon's stream" --- name: "day595" title: "Sketching Out A K-d Tree Loop" markers: "0": "Welcome to the stream with a plug of the Meow the Infinite printed comic Kickstarter" "57": "Show RayCast() with the determination to use our ray cast hits as a k-d tree" "97": "Demo hhlightprof (6.538543 total seconds elapsed)" "170": "Print out the number of partitions and leaves tested over repeated runs" "374": "hhlightprof tested 229860 partitions, and 524241 leaves" "387": "Always print out the number of partition and leaves tested, including the single-run case" "404": "hhlightprof tested 2338596 partitions, and 524285 leaves" "413": "Revert hhlightprof to print the number of partitions and leaves tested in the multiple-run case" "423": "Print partitions per leaf" "512": "hhlightprof tested 2339860 partitions and 524241 leaves, at 4.46 partitions per leaf" "535": "Print total partitions plus leaves" "575": "hhlightprof tested 2864101 total boxes, 2339860 partitions and 524241 leaves, at 4.46 partitions per leaf" "685": "Determine to make a special-purpose design for the k-d tree" "799": "Check the day" "859": "k-d Tree" "1177": "Embark on k-d tree-style categorisation in RayCast()" "1355": "Doing a dot-product using a known +/− value" "1496": "Initialise our desired data for k-d tree-style categorisation in RayCast()" "1943": "Our menu of operations: 1) Push both boxes; 2) Push one box; 3) Push no boxes" "1986": "Pushing no boxes" "2069": "Set up RayCast() to push onto our BoxStack the boxes on the close side and, optionally, the far side" "2258": "Consider the resource-usage implications of four rays sharing the same origin" "2798": "Determine to use SIMD lanes suboptimally for now, then read the literature on k-d trees to inform any improvements" "2851": "Make RayCast() push the boxes onto our BoxStack" "3472": "Consider how to classify the EndSide in terms of signedness" "3784": "Work through the EndSide classification, XOR'ing the sides into a mask" "4006": "Consider restructuring the box categorisation loop" "4050": "Restructure the box categorisation loop such that a box pulled off the stack is always known to be on the far side" "4342": "Set up to take a timing" "4383": "hhlightprof total seconds elapsed: 6.362055" "4415": "Restructure the ray hit testing loop within the categorisation loop, to avoid unnecessary box pushes" "4693": "hhlightprof total seconds elapsed: 6.110083" "4721": "Remove stale code from RayCast()" "4781": "Continue to work through the box categorisation routine" "4913": "hhlightprof total seconds elapsed: 6.173270" "4931": "Print out the Expected ms" "4980": "hhlightprof expected ms: 50.74" "5024": "Print out the Expected ms / thread" "5056": "hhlightprof expected ms / thread: 8.49" "5091": "Undefine HANDMADE_INTERNAL and HANDMADE_SLOW" "5107": "hhlightprof expected ms / thread: 8.51" "5115": "Run the game" "5166": "Run the game in Nsight: 21 ms / frame" "5273": "Check our frame profile in Nsight" "5348": "Decrease our resolution from 1920×1080 to 480×270" "5383": "Run the game" "5415": "Run the game in Nsight: 21 ms / frame" "5466": "Increase our resolution from 480×270 to 1920×1080" "5473": "Disable the lighting in EndLightingComputation()" "5509": "Run the game" "5529": "Run the game in Nsight: 16.67 ms / frame" "5556": "Re-enable the lighting in EndLightingComputation()" "5562": "Make ComputeLightPropagationWork() compute the lighting for only every other tile" "5656": "Run the game in Nsight: 16.67 ms / frame" "5724": "Revert ComputeLightPropagationWork() to compute the lighting for every tile" "5732": "Continue work on structuring our categorisation loop for better k-d processing" "6264": "Our menu of split cases" "6421": "Complete our categorisation and ray hit testing loops for better k-d processing" "7420": "Reflect on our k-d tree-based RayCast()" "7466": "Q&A" "7502": "Q: Groovy?" "7535": "Q: Is this PHP?" "7556": "Q: Is there a good way to get intuitions about bit masks etc, or is it just practice?" "7632": "Fix our usage of _mm_movemask_ps() in the StartSideBit and EndSideBit initialisers" "7650": "Describe _mm_movemask_ps" "7734": "Q: Do you write shader code often for work?" "7767": "Q: Do you sometimes feel the urge to make Handmade Hero truly 3D?" "7849": "Your asset pipeline becomes Unreal Engine 4" "7935": "Q: I'm bit behind on the VoDs. Do you ever trace secondary rays that bounce off in random directions that might lead to incoherent ray packets? (You mentioned the ray origins are always the same)" "8016": "Q: Can't C++11 use something like 0b1111" "8149": "Q: In an IMGUI situation, how do you create a unique ID for a UI control? What I don't get is, if you draw everything immediately, if some condition changes, won't the ID also change?" "8199": "Q: Has Handmade Hero gone as you planned, or did you not have any expectations or scope when you set off on this journey?" "8222": "Q: How many % is Handmade Hero done?" "8265": "Q: Would you consider moving Handmade Hero to JAI when it releases, or perhaps have another project to help showcase the language? I assume it'd be something that would at least interest you" "8304": "Wrap it up with a plug of the Meow the Infinite printed comic Kickstarter" --- name: "day596" title: "Fleshing Out Kd-Tree Traversal" markers: "1": "Welcome to the stream" "52": "Determine to implement the k-d tree loop, demoing the lighting variance" "107": "Describe our current k-d tree code in RayCast()" "383": "Stackless k-d tree traversal" "513": "More efficient k-d tree side selection" "654": "Make RayCast() directly index the StartSide and EndSide, rather than masked Select() them" "952": "On the need to disambiguate the negative and positive sides, to correctly test the EndSideBit" "1091": "Disambiguating the negative and positive sides: Storing a multiplier, -1 or 1" "1186": "Check out the old blackboard.mlt" "1270": "milton feature request: Display the save file location; or Auto-save to our designated (non-temporary) file path" "1398": "Launch and set the Overlay" "1451": "Side Bit Masks" "1678": "Make RayCast() set the EndSide using a PlaneTestPattern" "1834": "Set up to store the data needed for our k-d tree" "1883": "Plan our k-d tree data storage" "1974": "Make RayCast() track IsLeafContainer in the BoxStack" "2143": "Run hhlightprof" "2158": "Augment lighting_solution with the k-d tree data, introducing kd_tree_node" "2441": "Make RayCast() use our new kd_tree_node" "2922": "Begin to update SplitBox() to use our new kd_tree_node" "3072": "Consider packing the LeafCount in the BoxStack" "3141": "Undo our changes to SplitBox()" "3146": "Key & Peele diner order authenticity sketch: "Forget everything I said"" "3249": "Make RayCast() identify leaf nodes from a KdStack PackedValue" "4127": "I feel like there needs to be an algorithm / data structure named after Key & Peele" "4151": "Make RayCast() encode the PackedValue in the KdStack, introducing PACK_KD_STACK(), UNPACK(), UNPACK_PLANE_D(), UNPACK_LEAF_COUNT(), UNPACK_NODE_INDEX(), UNPACK_PLANE_TEST_PATTERN() and UNPACK_KD_INDEX(), and kd_stack_pack" "4956": "Fix compile errors in RayCast()" "5321": "Consider our k-d tree routine to be fully sketched out" "5391": "Determine to make SplitBox() build our k-d tree tomorrow" "5455": "Q&A" "5490": "Q: Nice hair!" "5509": "Q: Side stuff: How is that course on C coming along?" "5532": "Q: What about writing a plugin for 4coder that highlights unclosed parentheses?" "5579": "Q: It's Day 596" "5623": "Q: Looks like you can recover the milton temp file from %APPDATA%\MiltonPaint\data" "5629": "Check %APPDATA%\MiltonPaint\data" "5704": "Q: Where do I get the info about the C course?" "5738": "Q: Today Jon said that deferred rendering is a bad idea. Why?" "5826": "Didn't he just mean that almost no one uses deferred rendering anymore?" "5846": "Consult Adrian Courrèges' 'DOOM (2016) Graphics Study', 'Metal Gear Solid V - Graphics Study' and 'GTA V - Graphics Study'" "5950": "New DOOM does not use it" "5966": "Wonder what technique Jon was referring to" "6094": "Q: Could you explain the == 0000 1111 k-d side test thing again?" "6120": "k-d side testing: 0000 or 1111" "6420": "Walk through the k-d side testing code in RayCast()" "6492": "Q: Yes, what is the initial t value?" "6547": "Q: Someone also mentioned learning OpenGL with its tutorials about deferred rendering and he said "be careful who you learn from". Is it (deferred rendering) has some pitfalls or something bad that only pro programmers know about? Just confused" "6584": "Q: You could theoretically go full forward using clustered shading. It makes using many lights fairly straightforward. I wrote a blog post about it a while ago. It also explains what most people mean as deferred and why it's good in principle" "6610": "Clustered rendering in DOOM" "6739": "Q: Call of Duty does it, but they call it z-binning and it's 10x crazier" "6794": "Q: This one" "6956": "Q: It's faster but, god, is it harder to understand what they're doing" "7015": "Q: Worked faster in our engine, but it's early days yet" "7041": "I still think he was just mixing naming, problem is we can't ask him because he is angry about it" "7085": "I think Carmack said deferred rendering doesn't work so well in VR" "7123": "VR is the future" "7230": "Wrap it up with a plug of the Meow the Infinite printed comic Kickstarter" --- name: "day597" title: "Basic Kd-tree Construction" markers: "1": "Recap our Snuffleupagus oriented k-d tree implementation, and set the stage for the day" "124": "Introduce SplitKd() to replace SplitBox()" "172": "Determine to divide up the lighting box hierarchy the same as before" "234": "Note that the current splitting code allows overlapping rectangles" "483": "Begin to change RayCast() to handle overlapping rectangles" "630": "Undo our changes to RayCast()" "703": "Begin to make RayCast() use the FirstLeafIndex to permit overlapping rectangles" "883": "Undo our changes to RayCast()" "905": "Implement SplitKd() to split boxes in half along the k-d axis" "1955": "Consider packing the FirstLeafIndex, LeafCount and KdIndex into the Sides value" "2034": "Make SplitKd() pack the FirstLeafIndex, LeafCount and KdIndex into the Sides value" "2317": "Permit SplitKd() to push U16Max KdNodes, and clean up compile errors" "2480": "Enable SplitKd() to perform the actual split, adding to both sides if we split down the middle" "3062": "Make BuildSpatialPartitionForLighting() call SplitKd(), defining a LIGHTING_USE_OLD_KD switch" "3230": "Run hhlightprof successfully with the old k-d way" "3257": "Toggle off LIGHTING_USE_OLD_KD and fix compile errors, augmenting lighting_solution with a RootKdValue" "3414": "Run hhlightprof and hit a read access violation" "3429": "Run hhlightprof and hit a read access violation on the KdNodes" "3446": "Make ProfileRun() allocate space for the KdNodes" "3509": "Run hhlightprof and apparently infinitely loop on SplitKd()" "3550": "Remove FirstLeafIndex, LeafCount and KdIndex from kd_tree_node, storing the KdIndex in the Sides value and introducing UNPACK_NEXT_KD_INDEX()" "3912": "Scour SplitKd() for bugs" "4183": "Step through SplitKd() to our feedback loop situation, and inspect the values" "4356": "RemedyBG feature request: User-programmable data type watch summary / representation" "4718": "Again step through SplitKd() and inspect the BoxBounds" "4833": "Enable SplitKd() to handle non-split leaves" "4959": "Run hhlightprof without crashing" "4973": "Step through RayCast() and inspect its values, until hitting a write access violation" "5120": "Run hhlightprof without completing the first ray cast pass" "5173": "Again step through RayCast() and inspect its values" "5263": "Run hhlightprof in -O2 to completion of the first ray cast pass" "5351": "Switch to -Od and toggle on LIGHTING_USE_OLD_KD" "5364": "Run hhlightprof to completion" "5375": "Toggle off LIGHTING_USE_OLD_KD" "5385": "Scour RayCast() for bugs" "5443": "Try restricting RayCast() to only traverse down the StartSide" "5464": "Run hhlightprof to (non-instant) completion" "5471": "Continue to scour RayCast() for bugs" "5557": "Run hhlightprof in -O2" "5580": "Make RayCast() increment the TotalPartitionsTested before pushing on the StartSide" "5620": "Run hhlightprof in -O2" "5636": "Toggle on LIGHTING_USE_OLD_KD" "5648": "Run hhlightprof to find that the new k-d implementation tests many more leaves" "5693": "Toggle off LIGHTING_USE_OLD_KD" "5768": "Try making SplitKd() build a more usable k-d tree" "5895": "Run hhlightprof without completing" "5921": "Make ProfileRun() print out the KD Mode" "6075": "Run hhlightprof" "6081": "Toggle on LIGHTING_USE_OLD_KD" "6095": "Run hhlightprof to see that the new k-d implementation does not add many more leaves" "6109": "Scour RayCast() for bugs" "6201": "Try preventing RayCast() from descending the tree" "6207": "Old k-d hhlightprof leaves tested: 496197" "6235": "Toggle off LIGHTING_USE_OLD_KD" "6249": "New k-d hhlightprof leaves tested: 5773056" "6310": "Step through RayCast() in -Od to find 32 unsplit leaves" "6384": "Scour SplitKd() for bugs" "6614": "Try making SplitKd() split boxes that are on the PlaneD" "6662": "Step through SplitKd() to find that almost all boxes straddle the centre of the bounds" "6789": "Scour BuildSpatialPartitionForLighting() and SplitKd() for bugs" "6911": "Step through SplitKd() to find a 35 unit long box" "6977": "Scour ProfileRun() for bugs in transforming the box bounds" "7042": "Continue to step through SplitKd() to find identical BoxMax values for all boxes" "7105": "Step through the box bounds transformation in ProfileRun(), and on to SplitKd()" "7308": "Realise we incorrectly index into the Box, thanks to RemedyBG" "7376": "Fix SplitKd() to index into the Box using DimIndex rather than KdIndex" "7399": "Run hhlightprof in -Od" "7424": "-O2 k-d hhlightprof leaves tested: 375920" "7458": "Let RayCast() traverse the whole tree" "7472": "Run hhlightprof until… the heat death of the universe?" --- name: "day598" title: "Exploring Voxel Partitions for Raycasting" markers: "0": ""If anything, we should be looking for technologies that allow us to reduce latency"" "9": "Welcome to the stream with a plug of the Meow the Infinite printed comic Kickstarter" "48": "Set up to talk about spatial partitioning for lighting" "113": "A few words on our "Binary AAB Tree", with Axis-aligned split planes" "148": "Old k-d hhlightprof total seconds elapsed: 6.279085" "177": "Toggle off LIGHTING_USE_OLD_KD" "183": "Run the new k-d hhlightprof without completing" "255": "Toggle on LIGHTING_USE_OLD_KD" "264": "Run the old k-d hhlightprof and consult the profiling statistics" "357": "Make ProfileRun() print the average Partitions and Leaves per Ray" "506": "Old k-d hhlightprof Partitions per Ray: 5; Leaves per Ray: 24" "569": "Consider the notion of a Voxel Containment Field for raycasting" "708": "Leaves and Planes switched, handmade_hero" "713": "Fix the average Partitions and Leaves per Ray printing in ProfileRun()" "720": "Old k-d hhlightprof Partitions per Ray: 24; Leaves per Ray: 5" "778": "Grid Raycasting" "840": "Current "Binary AAB Tree" Raycasting" "929": "Possible new Grid Raycasting" "1072": "Storing grid square occupants as indices vs copies" "1197": "Determine to measure the voxel occupancy of our current geometry elements (occluders, light sources)" "1390": "Introduce GridRayCast() using RayCast() as the starting point" "1436": "Change RayCast() to increment TotalCastsInitiated by 4" "1507": "Continue to implement GridRayCast()" "2566": "Set up to make BuildSpatialPartitionForLighting() swizzle the lighting boxes into a 4-wide SIMD format" "2771": "Continue to implement GridRayCast()" "2981": "Consider the instructional implications of each ray having their answer spread across multiple values" "3375": "Sketch out our tRay selection in GridRayCast()" "3660": "Consult the old ray hit extraction code in RayCast()" "3753": "Enable GridRayCast() to directly extract the ray hit" "4590": "Consider our grid raycasting to be worth doing, only questioning the tRay selection, especially its horizontal comparing" "4676": "_mm_shuffle_epi8 in SSSE3 and its availability according to the Steam Hardware & Software Survey" "4939": "Enable GridRayCast() to select the tRay using _mm_shuffle_epi8, and to extract the ray hit in SIMD" "5255": "Clean up the ray hit extraction in GridRayCast(), and set up RayCast() to compare our old and new ray casting schemes" "5448": "Reflect on our new grid raycasting scheme" "5700": "Lighting is really really simple… until you want to make it run in real-time" "5737": "Toggle off GridRayCast() and sketch out the grid build in BuildSpatialPartitionForLighting()" "6366": "Q&A" "6407": "Q: Couldn't you use a couple of "_mm_hsub" to do your horizontal compare?" "6433": "_mm_minpos_epu16 in SSE4.1" "6523": "Begin to sketch out the tRay selection using _mm_minpos_epu16 from SSE4.1" "6750": "Q: When it comes to game dev / engine dev what do you believe is the hardest aspect to implement? Lighting, editors, etc?" "6847": "Q: How can you switch that fast between navigating into code and typing? The arrow keys are pretty far from the home row" "6890": "naysayer88 the never ending raid chain" "6910": "Jon has lunch" "6942": "End it here" --- name: "day599" title: "Implementing the Grid Raycast Postamble" markers: "0": "Welcome to the stream with a plug of Slipways" "48": "Begin to recap the new grid-based raycasting" "102": "Toggle on LIGHTING_USE_FOUR_RAYS (i.e. the tree-based raycaster)" "117": "Demo the lighting with the determination to reduce the sampling noise and speed it up" "176": "Toggle off LIGHTING_USE_FOUR_RAYS mentioning our refusal to use Apple hardware" "207": "GridRayCast() work: 1) Implement the routine correctly" "230": "GridRayCast() setup work: 2) Produce the ray-direction lookup tables" "241": "GridRayCast() setup work: 3) Grid up our geometry" "249": "Embark on implementing GridRayCast() correctly" "442": "Delete archived videos and disable Storage Sense on the streaming machine" "550": "Implement the leaf picking in GridRayCast(), introducing lighting_spatial_grid_node and lighting_spatial_grid_leaf" "768": "Reflect on our grid-based raycaster, comparing it with the tree-based one" "872": "SIMD inefficiency considerations, including packing on-demand" "1012": "Make a note to do a single-leaf spatial structure version" "1050": "Continued SIMD inefficiency considerations when we have between 1 and 3 pieces of data to work with" "1142": "Prepare to implement the tRay picking in GridRayCast() using _mm_minpos_epu16()" "1465": "Implement the tRay picking in GridRayCast() using _mm_minpos_epu16()" "1920": "Recall platform-specific bugginess of _mm_set1_epi32()" "2361": "Try _mm_set1_epi32() in GridRayCast()" "2488": "Consider a special floating-point comparison circuit to be unnecessary" "2680": "I can confirm that I am in fact not an IEEE expert" "2684": "Continue to implement versions of tRay picking in GridRayCast(), with and without _mm_cvtepi32_ps()" "3177": "Continue to consider special comparison of the top 16-bits of a floating-point value to be unnecessary" "3237": "Write the HCompShuffler in GridRayCast()" "3660": "Learn that _mm_minpos_epu16(), given duplicated input, is documented to return the first matching value" "3793": "Write the ShuffleTable in GridRayCast()" "3982": "Fix compile errors in GridRayCast()" "4001": "Check the assembly of _mm_set1_epi32() in Compiler Explorer to find that the compiler generates the full broadcast table, rather than our desired broadcast instruction" "4125": "Manually write out the full ShuffleTable in GridRayCast(), to abandon _mm_set1_epi32()" "4289": "Reflect on the efficiency of our tRay picking" "4354": "Move on to the ray hit extraction" "4501": "Correctly implement the ray hit extraction in GridRayCast()" "4887": "Introduce PShufB(), with a rant on C++ vs assembly" "5134": "Introduce Extract0() for GridRayCast() to use" "5297": "Continue to implement the ray hit extraction in GridRayCast(), making it set the TransferPPS in a passed-in value" "7106": "Change Extract0() to use _mm_cvtss_f32(), and introduce Extract1() and Extract2(), using _mm_extract_ps()" "7308": "Get GridRayCast() in a compilable state" "7457": "Q&A" "7474": "Q: Jon said you had opinions on signed / unsigned. He said you said "maybe it's the wrong complication to have". Do you know what he was referring to and, if so, can you elaborate?" "7628": "Q: Are you familiar with Home Assistant?" "7639": "Q: Are there alternatives to inline assembly other than intrinsic?" "7682": "Q: Hey Casey, on episode 300-ish you mentioned that OpenGL 4.5 is much closer to a good graphics API then something like Vulcan. I'm wondering if other developers you know agree with you on this and if so, then why would something like Vulkan get support? Who exactly makes the design / adoption decisions for these kinds of technologies? Do developers have any say?" "7804": "Q: Why is it slow for the CPU to do horizontal SIMD operations?" "7839": ""Slow" → What does this mean?" "7929": "Horizontal Operations = High Latency" "8135": "_mm_minpos_epu16() and _mm_hadd_epi32() as horizontal operations" "8272": "Q: Wouldn't you use Vulkan for cross platform?" "8369": "Close everything down with a plug of the Meow the Infinite printed comic Kickstarter and a further mention of Slipways" --- name: "day600" title: "Better AABB Normal Derivation" markers: "1": "Welcome to the stream with a plug of the Meow the Infinite printed comic Kickstarter" "41": "Recap our ongoing move to grid-based ray casting" "116": "Yeah, he's been saying "only gameplay code now" since day 300" "174": "Toggle on the normal derivation code in GridRayCast()" "199": "Refresh our memories on the SIMD grid-based ray casting" "312": "Floating-point ALUs, and when to drop down from wide to scalar operations" "460": "Continue to refresh our memories on the ray hit extraction in GridRayCast()" "560": "Make GridRayCast() set ProbeSamplePSingle and ProbeSampleNSingle" "669": "Producing the normal of the box surface we hit" "759": "Embark on making GridRayCast() produce the normal of the box surface we hit" "1634": "Consult ComputeVoxelIrradianceAt() for SIMD potential" "1706": "Rewrite our ShuffleTable in GridRayCast()" "2273": "Try making GridRayCast() test the box surfaces unpacked" "2641": "Consider unpacked testing to be worse" "2669": "Switch our attention to making GridRayCast() test the box surfaces while packed, renaming ShuffleTable to ClearMaskTable" "3099": "Make GridRayCast() pack up the ray hit" "3525": "Consider the performance of our ray packing" "3569": "Determine to set up the SpatialGridNodes and SpatialGridLeaves, and pre-generate the WalkTable" "3734": "Introduce light_sample_direction for GridRayCast() to take" "3972": "Consider the performance of our grid-based ray casting" "4133": "Ray Hit Normal Derivation" "4506": "On the possibility to remove the PShufB() calls if the BoxMin and BoxMax were not shuffled" "4549": "Consider what information obtained while picking the tRay may we use to derive the box surface normal" "4745": "Temporarily relieve GridRayCast() of storing the HitBoxMin and HitBoxMax" "5032": "Change GridRayCast to store HitTMinX and HitTMinY rather than HitBoxMin and HitBoxMax" "5242": "Make GridRayCast() more efficiently derive the box surface normal" "5906": "Consider GridRayCast() to be done" "6082": "Fix up compile errors in GridRayCast()" "6149": "Run hhlightprof successfully" "6210": "Q&A" "6235": "Q: Nice upgrade of the routine! Just wanted to let you know there is a double PShufB() in the creation of tRaySingle. Which leads me to a question, what do the P and B in PShufB() stand for, position and bit?" "6253": "Relieve GridRayCast() of calling PShufB() twice in the creation of tRaySingle" "6261": "What PShufB stands for: Packed Shuffle Bytes" "6574": "Q: Hi Casey, love your show. Lately you seem to be having some problems with your voice (breaking, coughing). Have you considered visiting a speech therapist?" "6591": "Q: Mostly off-topic: Happy 600th Day! The stars have aligned and the Episode Guide has received an update" "6663": "Q: Could you explain the math and diagram behind why the sign bits are the inverse of the ray's sign again? I showed up halfway through that and I think I'm missing some context" "6685": "Plug(?) "Behind the Curve"" "6961": "Understanding why the sign of the hit surface normal is the inverse of that of the ray, in infinite planes" "7135": "Understanding why the sign of the hit surface normal is the inverse of that of the ray, in boxes" "7339": "But it forms nine quadrants, not four quadrants? I guess we know we're not stuck in between the fake heavens somehow?" "7368": "Deterministically knowing which surface we hit when our ray is in the edge octants" "7478": "But assuming that we know we're in the four corner quadrants, and that the boxes are axis-aligned, then that all makes sense now" "7489": "The utility of transforming into an axis-aligned space for hit testing" "7772": "Is it faster to do the matrix rotation or the dot product, though? I guess there's only one rotation and plenty of dot products" "7833": "Signed distance fields" "7911": "Wrap it up with a plug of the Meow the Infinite printed comic Kickstarter" --- name: "day601" title: "Sketching Out the Walk Table Generator" markers: "1": "Recap and set the stage for the day improving our lighting performance" "193": "Reflect on yesterday's work on GridRayCast()" "301": "Determine to generate the WalkTable" "350": "Set up GridRayCast() to index into the WalkTable" "423": "On striding through the voxel, and the need to bounds-check in multiple dimensions" "602": "Make RayCast() set a WalkCount for GridRayCast() to use when striding through the WalkTable, augmenting light_sample_direction with an EndAtWalkOffset" "748": "Micro- and Macro-op Fusion" "1155": "Looping in clang -O2" "1233": "clang's loop unrolling" "1494": "Looping in msvc -O2" "1624": "Looping in clang -O3, with its micro-architectural analysis" "1704": "Micro- and Macro-op Fusion" "1834": "Micro- and Macro-op Fusion of non-deterministic looping" "2265": "Non-deterministic looping in clang -O3, with its micro-architectural analysis" "2689": "Make GridRayCast() loop through the WalkTable, renaming the indices in light_sample_direction" "3003": "Consider how to generate the WalkCount" "3140": "Walk Table Truncation" "3310": "Replace the WalkCount with a SPATIAL_GRID_NODE_TERMINATOR skirt surrounding the spatial grid" "3440": "Prepare RayCast(), GridRayCast(), FullCast() and ComputeLightPropagationWork() to develop the WalkTable generation and compare the current and resulting routines, introducing GridIndexFrom()" "4998": "WalkTable generation, à la Bresenham Line Drawing" "5285": "Introduce ComputeWalkTable()" "5991": "Q&A" "6014": "Q: https://imgur.com/a/A28qRIw" "6075": "Billy Mitchell has recently sued some people for slandering him" "6151": "Did they say he used an emulator rather than a real arcade?" "6195": "Q: Can you explain more what a micro-op is?" "6212": "Skylake-ish Core Micro-op (µop)" "7109": "Micro-op Fusion and Limits" "7299": "Macro-op Fusion" "7622": "Q: I don't think they fuse the instructions anymore. Take a look at LOOP, LOOPE and LOOPNE on uops.info. They take a lot of uops. (No expert here, but pure from poking Godbolt and the x86_64 instruction set / byte codes)" "7657": "Q: Never mind, I thought you meant that the compiler fused the instructions, not the uops in the pipe" "7668": "Q: What if it is an HTML DIV in the scheduler?" "7673": "WebAssembly" "7703": "They do even crazier instruction squashing now" "7814": "We're all good here" "7864": "Probably not!" "7888": "I should have OBS'd it" "7907": "Does he have a save game? Or are there no save games?" "7921": "Look, if my screenshot is invalid, then YOURS is invalid, and my score being higher, my invalid screenshot is better than yours" "7936": "That's it, everybody" --- name: "day602" title: "Early Termination for the Grid Raytracer" markers: "2": "Welcome to the stream" "44": "Grid Raytracing for Light Probes" "180": "Early Termination of Grid Raytracing" "568": "Prepare to enable GridRayCast() to early terminate the tRay picking" "734": "Enable GridRayCast() to early terminate the tRay picking using a CostMetric" "1155": "Erroneous hit registration due to multiple pieces of geometry in the same voxel" "1271": "Make a note in BuildSpatialPartitionForLighting() to clip boxes to the cells" "1350": "Continue to enable GridRayCast() to early terminate the tRay picking, introducing a version of ComputeVoxelIrradianceAt() that takes a grid index" "1458": "Reacquaint ourselves with the Outgoing parameter of ComputeVoxelIrradianceAt()" "1646": "Make a note in ComputeVoxelIrradianceAt() to use -Outgoing" "1678": "Set up the early termination path in GridRayCast() to use the original ComputeVoxelIrradianceAt()" "2507": "Introduce walk_table_entry for GridRayCast() to use" "2682": "Make GridRayCast() decrement the CostMetric when testing leaves" "2949": "Consider the case when our ray doesn't hit anything, using ambient or moon light" "3148": "Crash hhlightprof in RayCast()" "3181": "Crash an -Od build of hhlightprof in RayCast()" "3268": "Update BuildSpatialPartitionForLighting() to build the SpatialPartition with an apron for grid raycasting, introducing GetVoxelIndexForP()" "4831": "Break" "4854": "New Away From Keyboard Screen!" "5013": "Return with Bunny Fruit Snacks" "5037": "Q: I think there is a bug in GridIndexFrom(), VoxelDim.z is used instead of just Z" "5060": "Fix GridIndexFrom() to use the passed in Z, and a typo in GetVoxelIndexForP()" "5168": "Continue to update BuildSpatialPartitionForLighting() to build the SpatialPartition for grid raycasting" "6021": "Make BuildSpatialPartitionForLighting() clip boxes to the voxels, introducing GetVoxelCellBounds() and Intersect()" "6596": "A few words on balancing code cleanliness and avoidance of work that gets undone" "6722": "Make ProfileRun() initialise a TempArena to pass to InternalLightingCore() and through to BuildSpatialPartitionForLighting(), removing TestRayCast()" "7039": "Make BuildSpatialPartitionForLighting() mark the SPATIAL_GRID_NODE_TERMINATOR apron nodes" "7360": "Anticipate building the WalkTable" "7487": "Sketch out the tTerminate computation in ComputeWalkTable()" "7563": "Q&A" "7585": "Q: While you typed in the check for the apron filling with special value, in checking the last max I think you put an X instead of a Z" "7588": "Fix typo in BuildSpatialPartitionForLighting()" "7628": "Q: Salad isn't real saving anyway, don't start with a cloudy day is it quantum computing?" "7640": "Q: Did you watch the UE 5 demo? Have you any thoughts about it?" "7670": "Q: Can you watch the demo live?" "7722": "Q: What was the original justification for switching to the probe-based GI?" "7944": "Q: Did I remember correctly that our lighting partitions aren't fixed in world size, but are fixed in number among x / y / z? Does that mean that eventually we can't have the ideal situation where the lighting voxel is aligned with world blocks, and light voxel size is a multiplier / subdivider of the game grid size, so that most of the lighting occluder voxels are not partially filled but mostly filled?" "8109": "Q: Could you put moon blocks in the apron so you always hit something instead of using a special index? Maybe that might help your multi-condition loop?" "8233": "Q: Can you move the play button on the page a bit down because on first glance the horizontal line of "L" lets it look like it has a partial drop shadow which drives me mad" "8253": "Q: Uuuh, so essentially every LightingVoxelDim is consistent across frames even if camera zooms in / out? I thought that VoxelDim was calculated by taking WorldRegionToRenderSize divided by max number of lighting voxels per axis" "8300": "Q: What is my best shot at getting a standalone C++ compiler bundled with my engine?" "8428": "Q: Do you think "const" is useful for function arguments in certain cases or is it kind of whatever? Sorry if you get asked this often" "8512": "Q: What do you compile with? cl.exe" "8657": "Close this down" --- name: "day603" title: "Grid Raycaster Table Generation" markers: "3": "Welcome to the stream" "102": "Set up to implement ComputeWalkTable()" "213": "Implement ComputeWalkTable()" "444": "Consider how to encode the dGrid in walk_table_entry, computing it at runtime" "550": "Augment the lighting_solution with a walk_table_entry" "613": "Make ComputeWalkTable() write to our dynamic lighting_solution" "982": "Make InitLighting() call ComputeWalkTable(), removing light_sampling_sphere_2" "1281": "Desire a big, easy-to-clean glass bottle" "1331": "Augment lighting_solution with a memory_arena TableMemory and TableVoxelDim for BeginLightingComputation() to use" "1769": "Estimate the memory requirements (393,216 rays' worth) and cycles available (509) for the ray casting" "1913": "Define our LIGHT_SAMPLING values for FullCast() to use, and include handmade_simd.h and handmade_sampling_spheres.inl in handmade_lighting.cpp" "2538": "Consider the pipeline to be running properly" "2563": "Break" "2572": "afk" "2713": "Return" "2727": "Plot twist: Casey accidentally hit the switch and is still coding / talking" "2750": "Can I get a recap of the first hour?" "2754": "Make OutputSphereINL() write out the new light_sample_direction struct and LIGHT_SAMPLING defines" "2922": "Reacquaint ourselves with GenerateOctahedralLightingPattern()" "3052": "Make GenerateOctahedralLightingPattern() return the OutputDirections to be passed to OutputSphereINL()" "3297": "Invoke hhsphere" "3318": "Respecify hhsphere to take as arguments and " "3640": "Invoke hhsphere" "3651": "Respecify hhsphere to take as an argument " "3734": "Invoke hhsphere" "3782": "Jonathan Blow would like to know your address" "3816": "Always send him your address" "3819": "Send our address to Jon" "3934": "They're trolling" "3949": "Inspect temp.inl" "3977": "Make OutputSphereINL() write out the RawDirections" "4069": "Everyone is fired" "4094": "Invoke hhsphere" "4123": "Inspect temp.inl and copy it into place" "4181": "Fix compile errors" "4195": "Fix OutputSphereINL() to insert the semicolon" "4201": "Make ProfileRun() initialise the TableMemory" "4377": "Run hhlighprof and hit a read access violation in BuildSpatialPartitionForLighting()" "4433": "Make BuildSpatialPartitionForLighting() allocate memory for the SpatialGridNodes" "4507": "Run hhlighprof and hit a read access violation in ComputeVoxelIrradianceAt()" "4574": "On indexing into similar but not identical overlapping sets of data" "4786": "Fix ComputeLightPropagationWork() to index in to the aproned voxel" "4961": "Run hhlighprof and hit the same read access violation in ComputeVoxelIrradianceAt()" "5084": "Fix ComputeWalkTable() to set the tTerminate to a valid value" "5152": "Run hhlighprof and hit the same read access violation in ComputeVoxelIrradianceAt()" "5298": "Make GridRayCast() initialise the ProbeSamplePSingle to the incoming RayOriginSingle" "5316": "Run hhlighprof and hit the same read access violation in ComputeVoxelIrradianceAt()" "5441": "Consider the rounding subtraction in ComputeVoxelIrradianceAt()" "5526": "Prevent ComputeVoxelIrradianceAt() from rounding down when setting the FCoord" "5547": "Run hhlighprof and hit the same read access violation in ComputeVoxelIrradianceAt()" "5599": "Make GridRayCast() initialise the ProbeSampleNSingle to the incoming RayDSingle" "5629": "Run hhlightprof successfully" "5651": "hhlightprof total seconds elapsed: 5.363018" "5746": "Q&A" "5774": "Q: Cathedral or bust?" "5849": "Q: Can we try the game in the current state?" "5875": "Run the game to see a black screen" "5905": "Q: Since this new pass is to speed up performance, where do you foresee getting speedups after this pass?" "5970": "Q: Given two points, do you think there might be a way to calculate the number voxel cells a Bresenham-like line algorithm will touch? Without walking?" "5998": "Q: Can you run hhlightprof?" "6100": "Q: Has it ever happened that you put so much work in an idea and it turned out not working out?" "6213": "Q: Could we generate all these tests we do for the lighting at box creation?" "6236": "Q: Since hhlightprof just runs RayCast(), maybe we put more work into building the occluder leaves than before?" "6428": "Q: Glass milk bottles" "6473": "Q: You've mentioned before at RAD you made a tool for detecting indexing errors. How would a tool like that work?" "6633": "sagian2005 How old are you?" "6699": "Q: Could we look for only the farthest box a Ray would hit, and eliminate testing all the boxes in between?" "6744": "Q: How has that 30 Million Lines Problem been going on? Have some hardware vendors contacted you about it or maybe said something?" "6828": "Wrap it up" --- name: "day604" title: "Adding a Voxel Utility Struct" markers: "2": "Recap and set the stage for the day" "172": "Lighting walkthrough: Voxelisation recording the octahedral map" "261": "Lighting walkthrough: Grid ray tracing, for writing to the octahedral map" "441": "Lighting walkthrough: Traversing the aproned voxel" "565": "Lighting walkthrough: Computing and writing to the octahedral map" "756": "Lighting walkthrough: Grid ray casting, propagating light through the system" "967": "Lighting walkthrough: Grid ray casting, for sampling from the spatial grid" "1406": "Consider the correctness of our partial-floating-point MinTest computation in GridRayCast()" "1604": "Make a note in GridRayCast() to consider computing MinTest using the full 32-bit compare" "1769": "Lighting walkthrough: Grid ray casting, for sampling from the spatial grid, continued" "2135": "Lighting walkthrough: Pre-pass spatial grid construction" "2205": "Antibiotics, COVID-19, throat culture tests and medical practice" "2319": "Lighting walkthrough: Pre-pass spatial grid construction, continued" "2519": "Document the Intersect() call in BuildSpatialPartitionForLighting()" "2564": "Determine to step through the lighting code" "2599": "Try to break into InteralLightingCore()" "2665": "Step through InternalLightingCore()" "2863": "Make BuildSpatialPartitionForLighting() subtract the apron from the MaxGridIndex" "2884": "Step back in to BuildSpatialPartitionForLighting()" "2909": "Respecify MaxGridIndex as GridCount in BuildSpatialPartitionForLighting()" "2980": "Continue to step through BuildSpatialPartitionForLighting()" "3075": "Assert in GridIndexFrom() that our P is inside the Voxel" "3291": "Extend the voxel by an ExtraOcclusionRadius, augmenting lighting_solution with a SpatialGridCorner and SpatialGridIndexOffset" "3744": "Create handmade_voxel.h and handmade_voxel.cpp, introducing voxel_grid and related utility functions" "4513": "Clean up and augment lighting_solution with new voxel_grid AtlasGrid and SpatialGrid" "4810": "Include handmade_voxel.h and handmade_voxel.cpp, fix errors and introduce voxel_relative_p" "5139": "Update the lighting system to use our new voxel utility functions" "8561": "Consider collapsing BeginLightingComputation() and InternalLightingCore()" "8803": "Introduce SetLightingValues() to do all the render_group initialisation work from BeginLightingComputation()" "8922": "Respecify BeginLightingComputation() as SetUpLightingRegion(), EndLightingComputation() as UpdateLighting(), and introduce PushLightingDebugValues()" "9484": "Q&A" "9506": "Q: When assigning SpatialMinCorner in SetUpLightingRegion(), the AtlasGrid's MinCorner is probably not yet initialized. So I think it should use the AtlasMinCorner variable" "9545": "Fix the SpatialMinCorner assignment in SetUpLightingRegion()" "9571": "Q: Whisky?" "9588": "Q: ETA for 603, 604 hitting YouTube? I missed last Sunday's stream. Miss anything good?" "9639": "Q: Maybe it got fixed already. MaxNodeIndex = GetVoxelIndexForP (... Solution->SpatialGridMinCorner ...) should be SpatialGridMaxCorner" "9702": "It's missing the Grid pointer" "9715": "Enable HANDMADE_INTERNAL and HANDMADE_SLOW, and fix the Assert in FlatIndexFrom()" "9779": "Delete the lighting .dump and .txt files" "9820": "We'll pick this up tomorrow" --- name: "day605" title: "Cleaning Up the Lighting Code" markers: "0": "Recap and set the stage for the day" "40": "Copy into handmade_lighting.h the function signatures of our lighting system functions" "81": "Describe the two-stage lighting system structure, noting our desire to have only one function, UpdateLighting()" "237": "Look into relieving PushLightingRenderValues() of the need to call SetLightBounds()" "350": "Consider storing our light voxel in game_render_commands" "509": "Move the VoxelMinCorner and VoxelInvTotalDim from render_setup to game_render_commands as LightingVoxelMinCorner and LightingVoxelInvTotalDim, and propagate this change" "713": "Toggle on LIGHTING_USE_FOUR_RAYS" "750": "Break in ComputeWalkTable()" "785": "Fix the infinite loop in ComputeWalkTable()" "797": "See a blank screen" "832": "Make the new BuildSpatialPartitionForLighting() only operate if LIGHTING_USE_FOUR_RAYS is disabled" "877": "See the old lighting, albeit broken" "896": "Build in -O2" "911": "Check out our broken old lighting" "928": "Collapse SetUpLightingRegion() into UpdateLighting()" "1325": "See a blank screen" "1330": "Make UpdateAndRenderWorld() call EnableLighting()" "1483": "Check out our broken, yet streamlined, old lighting" "1522": "Clean up and document UpdateLighting()" "1997": "Demo the incorrect lighting computations and the flash when the camera moves" "2027": "Fix UpdateAndRenderWorld() to pass the incoming Camera.SimulationCenter to UpdateLighting()" "2110": "The flash when moving the camera is fixed" "2131": "Finish documenting UpdateLighting()" "2208": "Determine to debug wrong lighting results and remove the lighting_box storage from lighting_solution" "2261": "Prepare to debug wrong lighting results, removing SplitKd() and trimming out old test cases from RayCast()" "2448": "The game looks the same" "2453": "Remove more stale lighting code" "2666": "Demo the wrong lighting results" "2724": "Scrutinise RayCast() for errors" "2953": "Scrutinise ComputeVoxelIrradianceAt() and related functions for errors" "3076": "Scrutinise the lighting setup code for errors" "3308": "Fix FullCast() to pass the RayD from the Solution->SamplingSpheres to RayCast()" "3479": "Admire our more correct, old lighting" "3487": "Build in -O2" "3498": "Admire our more reasonable, old lighting" "3535": "Provide an easy means of toggling between the new grid-based and the old AABB ray caster, renaming RayCast() to AABBRayCast()" "4091": "Check out our old AABB ray cast lighting" "4115": "Split BuildSpatialPartitionForLighting() into GridBuildSpatialPartition() and AABBBuildSpatialPartition()" "4251": "Check out our old AABB ray cast lighting" "4263": "Toggle on LIGHTING_USE_GRID and fix compile errors" "4297": "Hit our assertion in FlatIndexFrom()" "4420": "Make GridBuildSpatialPartition() clip the SpatialGrid down by a CellDim" "4572": "Hit our assertion in FlatIndexFrom()" "4655": "Fix GridBuildSpatialPartition() to pass the BoxBounds to GetIndexForP()" "4690": "Admire our moonlight" "4716": "Build in -O2" "4723": "Admire our moonlight" "4771": "Toggle off LIGHTING_USE_GRID" "4795": "Determine to remove the lighting_box storage from lighting_solution" "4807": "Rename Boxes to AABBBoxes in lighting_solution, remove RootLightBoxIndex, and flow InputBoxes separately through the pipeline" "5401": "Hit a write access violation on the ParentBox in SplitBox()" "5414": "Make AABBBuildSpatialPartition() initialise the AABBBoxCount to 1" "5458": "Run successfully" "5466": "Add a toggle between the AABB and grid ray caster data in lighting_solution" "5599": "Run successfully" "5621": "Build in -O2" "5628": "Run successfully" "5648": "Change the DebugLines in lighting_solution to be allocated" "5861": "Run successfully" "5880": "Consider further areas for cleanup" "6142": "Introduce lighting_update_params" "6335": "Plan to split the lighting_solution into pieces" "6524": "Q&A" "6558": "Q: Is the MaxNodeIndex supposed to be in bounds or one past the bound?" "6610": "Q: Does the lighting solution support direct lighting like the sun / moon?" "6675": "Q: Are you doing this on the CPU purely for educational reasons or is there something else?" "6806": "Q: We can put mirrors in every level like Labyrinth" "6873": "Q: Can you at some point go over the AVX scatter gather intrinsics?" "7178": "Q: Do you have an idea of how the gameplay will look like or will you wait to finish the engine before getting to it?" "7208": "Q: (Off-topic) On earlier streams you have trouble with RSI. After decades of typing, I too have RSI. Any tips?" "7284": "Q: Probably covered in some other day, but what's the best update-rate to choose for a game? Jon says it's good to have it high so it looks good on high-update screens, but 120 FPS isn't a multiple of 144 FPS. So what do you recommend?" "7460": "Q: Why not take a stab at game design when it's done? Just not interested?" "7508": "Thank you, everybody" --- name: "day606" title: "Debugging Grid Raycasting with Visualizations" markers: "1": "Recap and set the stage for the day with a few words on indirect lighting" "125": "Demo the old AABB ray cast lighting" "176": "Toggle on LIGHTING_USE_GRID and fix compile errors" "207": "Demo the new, unfinished grid ray cast lighting" "296": "Grid ray casting: 1) Spatial partitioning" "335": "Grid ray casting: 2) Walk table, which tells you which grid squares to sample" "358": "Grid ray casting: 3) The ray cast routine itself" "385": "Grid ray casting: 1a) SIMD packing of the AABB units" "443": "Determine to debug the spatial partitioning using visualisation, with a few words on unit testing" "848": "Make GridRayCast() draw the rays from one grid location, introducing DimIndexFrom()" "1349": "Introduce a version of PushDebugBox() that takes a rectangle3" "1383": "Hunt the scene for the debug box" "1396": "Change GridRayCast() to draw the rays from grid location 200" "1435": "Hunt the scene for the newly located debug box" "1465": "Try unsuccessfully to break on our PushDebugBox() call in GridRayCast(), and find an InitialGridIndex of 4677" "1525": "Change GridRayCast() to draw the rays from grid location 4677" "1539": "Break on our PushDebugBox() call in GridRayCast()" "1566": "Note that PushDebugLine() is not thread-safe, which is fine for the grid ray caster" "1628": "Check out the debug box" "1675": "Make GridRayCast() draw the ray origin, hit and synthetic destination locations" "1907": "Check out the rays cast from our 4677 grid location, to see that we are not casting spherically" "2007": "Scour OutputSphereINL() for bugs" "2181": "Note the area untouched by the ray cast" "2201": "Consider there to be something wrong other than the SampleDirectionTable values" "2228": "Note the black colouration of the rays, themselves lit by the lighting system" "2326": "Scour FullCast() for sampling bugs" "2426": "Fix FullCast() to stride through the SampleDirectionTable in fours" "2437": "Admire our more spherical ray distribution" "2488": "Note that our rays never hit anything" "2525": "May GridRayCast() limit the drawing of rays to those pointing upwards" "2630": "Admire our upward pointing rays" "2662": "Make GridRayCast() draw the boxes visited by our rays" "2703": "See no boxes visited by our rays" "2763": "Make GridRayCast() shrink the ray origin box" "2794": "See both the origin box and the initial walk box" "2825": "Note that GridRayCast() terminates prematurely" "2875": "Step in to GridRayCast()" "2901": "Disable multithreading of the lighting" "2940": "Wonder why a second thread apparently hit the RayDebugging branch" "3009": "Step through GridRayCast()" "3044": "Fix the CostMetric test in GridRayCast() to let it actually proceed through the walk" "3069": "Step through GridRayCast()" "3086": "Switch to -O2 and re-enable multithreading of the lighting" "3109": "See that the ray cast is walking through the grid in the wrong direction" "3168": "Scour ComputeWalkTable() for a sign bug" "3362": "Fix ComputeWalkTable() to recentre the test At location within the cell as it proceeds" "3449": "See that the ray cast continues to walk in the wrong direction" "3473": "Continue to scour ComputeWalkTable() for a sign bug" "3560": "Follow the WalkTable through GridRayCast()" "3660": "Switch to -Od and disable multithreading of the lighting" "3718": "Step in to GridRayCast() to find a WalkTableOffset of 0 for everybody" "3802": "Fix ComputeWalkTable() to increment the DestIndex" "3820": "Run (or walk?) a single-threaded -Od build of the game" "3834": "Switch to -O2 and re-enable multithreading of the lighting" "3869": "Compiler feature request: Swappable optimised and debug versions of routines" "3930": "See that the ray cast now walks in the correct general direction, but never diverges from the vertical" "3949": "Fix GridRayCast() to increment the WalkTable" "3991": "Admire our nice walk table stepping" "4076": "Try to limit GridRayCast() to draw only one ray" "4149": "See our single ray" "4171": "Make FullCast() pass a designated debug ray to GridRayCast()" "4403": "See our single ray, which sadly does not hit" "4415": "Make FullCast() pass different rays to GridRayCast() using trial and error" "4576": "Reacquaint ourselves with GenerateOctahedralLightingPattern() from hhsphere" "4660": "Make FullCast() pass ray 36, the central one in the map, to GridRayCast()" "4669": "Admire our single ray, which hits" "4711": "Rerun the game to regenerate the WalkTable, and admire our ray" "4801": "Try and make GridRayCast() colour the boxes differently" "4864": "See that the boxes remain the same colour" "4872": "Embark on systemically disabling the lighting for CompileZBiasProgram()" "4935": "Demo the unlit debug UI" "4948": "Make CompileZBiasProgram() use a passed in Emission value to apply lighting to the texture, augmenting opengl_program_common with a VertEmission" "5586": "Hit OpenGL error: Index out of range" "5627": "Make OpenGLCreateProgram() set the VertEmission" "5703": "Hit OpenGL error: Undefined variable "Emission"" "5745": "Fix naming of FragEmission in CompileZBiasProgram()" "5754": "Hit a read access violation inside the OpenGL driver" "5797": "Fix the Emission texture binding in UseProgramBegin()" "5822": "See that the debug UI is now being lit" "5835": "Make WriteQuad() set Emission to 0, and PushQuad() set it to black or white depending on whether lighting is enabled" "6061": "See that the debug UI is correctly unlit again" "6081": "Make PushLineSegment() pass to PushQuad() an Emission value of 1.0f" "6242": "See that our ray walk boxes are now coloured differently" "6286": "Make GridRayCast() colour the leaf and edge nodes differently" "6373": "Check out our differently coloured ray walk boxes" "6400": "Make GridRayCast() colour the leaf and edge nodes even more differently" "6418": "Check out our differently coloured ray walk boxes" "6469": "Q&A" "6483": "Casey's hair is starting to look a little cartoonish" "6513": "Tease a Wilson cosplay attempt" "6532": "Q: 5+ hour Majora's Mask?" "6548": "Q: Performance might have changed since you removed the early-out" "6636": "Wrap it up" --- name: "day607" title: "Finishing Debugging the Grid Raycaster" markers: "2": "Recap and set the stage for the day" "35": "Demo the differently coloured ray walk boxes, notably the magenta leaf ones beyond the occluding box" "228": "Describe the ray colouring debug visualisation code in GridRayCast()" "304": "Make GridRayCast() draw the occluders within leaf boxes" "489": "See no occluders within those leaf boxes" "543": "Make GridRayCast() colour the occluder boxes white" "570": "See no white occluder boxes" "580": "Make GridRayCast() enlarge the occluder boxes" "612": "See no occluders" "624": "Compile in -Od" "644": "Try unsuccessfully to break on PushDebugBox() for an occluder" "788": "Fix GridBuildSpatialPartition() to modify StartIndex only after having used it to set OnePastLastIndex" "799": "How to succeed in the game industry, according to Jon Blow: Always update OnePastLastIndex before StartIndex" "858": "Again try unsuccessfully to break on PushDebugBox() for an occluder" "923": "Fix GridBuildSpatialPartition() to increment OnePastLastIndex" "1054": "Break on PushDebugBox() for an occluder, and inspect the values" "1112": "See that our ray walk debug visualisation now reports more correct results" "1136": "In an -O2 build, with our ray hitting, we are not drawing the ray itself" "1179": "Prevent GridRayCast() from enlarging the occluder boxes, and make it draw the ray" "1319": "See our ray" "1354": "Determine the ProbeSampleP computation in GridRayCast() to be busted" "1411": "Step into the origin ray drawing PushDebugLine() in GridRayCast(), to see that tRay is erroneous" "1587": "Add a break location in the SomethingHit branch in GridRayCast()" "1621": "Break into the SomethingHit branch in GridRayCast(), scrutinise the HComp shuffling code, and consider the hit detection code to be wrong" "1850": "Scrutinise GridRayCast() for hit bugs, keeping it in the back of our mind" "1981": "Again break into the SomethingHit branch in GridRayCast(), and scrutinise the HComp shuffling code" "2163": "Fix GridRayCast() to make _mm_extract_epi16() select the 1st 16-bit integer when setting ShuffleIndex" "2194": "Break into the SomethingHit branch in GridRayCast(), and past the ray selection" "2336": "Compile in -O2" "2345": "Our hit detection is now correct" "2359": "Make GridRayCast() draw a small box at the hit point" "2417": "Our hit detection is definitely close" "2458": "Make GridRayCast() decrease the distance walked by our rays" "2525": "See our shorter ray travel distance" "2531": "Make GridRayCast() slightly increase the distance walked by our rays" "2547": "See our better ray travel distance, and check the performance" "2575": "Make GridRayCast() slightly decrease the distance walked by our rays" "2584": "Our frame time is basically unchanged" "2597": "Rerun the game to regenerate the walk table" "2626": "Make GridRayCast() increase the distance walked by our rays" "2640": "Make GridRayCast() draw the normal of our hit surface" "2685": "Check out our correct normal" "2702": "Add a DebugGridIndex for FullCast() to use" "2844": "See the DebugGridIndex in our UI" "2870": "Begin to make DEBUGBeginInteract() and DEBUGInteract() support editable u32 values" "3068": "Revert, and instead make the DebugGridIndex be a float, for editing" "3110": "Try editing the DebugGridIndex" "3144": "Change DEBUGInteract() to edit draggable values in X" "3157": "Try editing the DebugGridIndex" "3201": "Make FullCast() set the DebugGridIndex to 5×4677" "3223": "Edit the DebugGridIndex" "3234": "Make FullCast() set the DebugGridIndex to 3×4677" "3248": "Edit the DebugGridIndex to 14889" "3347": "Make FullCast() set the DebugGridIndex to 14889 + (24×16)" "3391": "Check out our ray" "3402": "Make FullCast() set the DebugGridIndex to 14889 + (26×18)" "3418": "Try to check out our ray" "3427": "Make FullCast() set the DebugGridIndex to 14889 + (SpatialGrid.CellCount.x × SpatialGrid.CellCount.y)" "3472": "Check out our ray" "3485": "Augment lighting_solution with a DebugGridIndex and DebugRayIndex for the single-threaded UpdateLighting() to set" "3711": "Try editing our DebugGridIndex and DebugRayIndex to 16317 and 42" "3887": "Make UpdateLighting() set DebugGridIndex and DebugRayIndex to 16317 and 42" "3913": "Confirm that we've picked the right ray" "3918": "Consider scrutinising ComputeWalkTable() for bugs" "3954": "Show our erroneous hit" "3984": "Fix ComputeWalkTable() to correctly set tTerminate" "4042": "Check out our correct hit" "4068": "Try editing our DebugGridIndex and DebugRayIndex, and consider the ray cast to be correct" "4134": "Consider scrutinising GridRayCast() for bugs in the TransferPPS" "4246": "Disable LIGHTING_USE_GRID" "4267": "Check out the old AABB ray traced lighting" "4281": "Enable LIGHTING_USE_GRID" "4291": "Check out the new grid ray traced lighting" "4338": "Scrutinise the TransferPPS computation in GridRayCast()" "4759": "Make GridRayCast() at least index into a different TransferPPS for each ray" "4816": "Our lighting remains wrong" "4850": "Prevent GridRayCast() from applying the moon light, and make it always set ProbeSamplePSingle" "5004": "See immediate full-bright light" "5101": "Edit our DebugRayIndex and note that our speed has reduced" "5151": "Rerun the game to see that our speed begins fine, but degrades" "5416": "Make GridRayCast() force the TransferPPS to 0" "5475": "Rerun the game to see that our speed begins and remains fine" "5585": "Let GridRayCast() compute the TransferPPS as normal" "5598": "Rerun the game to see that our speed begins fine, but degrades" "5639": "Make GridRayCast() add our SpecTexel DEBUG_VALUE to the debug system" "5745": "Do not see a SpecTexel in the profiler" "5789": "Make GridRayCast() add a SpecTexel DEBUG_VALUE before disabling Debugging" "5816": "See our SpecTexel begin large and descend to 0" "5877": "Make GridRayCast() add each SpecTexel DEBUG_VALUE to the debug system" "5886": "Our SpecTexel values begin the same but progress differently" "5935": "Make GridRayCast() zero-initialise TransferPPS" "5982": "Our SpecTexel values remain the same" "5989": "Revert the zero-initialisation" "6006": "Step through GridRayCast() and inspect the TransferPPS values" "6072": "Determine to disable multithreading of the lighting" "6088": "RemedyBG feature request: Stepping through the current thread" "6146": "Disable multithreading of the lighting" "6172": "Step through GridRayCast() and inspect the TransferPPS and SpecTexel values" "6295": "Assert in GridRayCast() that the SpecTexel doesn't look fishy" "6358": "See that the first few frames look good, until we hit our assertion" "6466": "Try decreasing the W modification from ×0.75 to ×0.01 in BuildDiffuseLightMaps()" "6513": "Consider the TransferPPS to perhaps be feeding back" "6564": "Note the slowness of a -O2 build" "6596": "Try increasing the W modification from ×0.01 to ×0.1 in BuildDiffuseLightMaps()" "6614": "See that the TransferPPS is fascinatingly unstable" "6714": "Consult the Intel Developer Zone, Intrinsics Guide and JUCE Forum for denormal prevention information" "7000": "Make WinMainCRTStartup() set the DAZ and FZ bits, for denormal prevention" "7093": "The lighting transfer still happens slowly" "7102": "Read 10.2.3 MXCSR Control and Status Register in the Intel 64 and IA-32 Architectures Software Developer Manuals" "7276": "Fully define and set our desired MXCSR Control and Status Register" "7647": "Hit a "Floating-point Inexact Result" exception" "7694": "Set our DesiredBits to be the ControlMask" "7715": "Run successfully, but still with slow lighting transfer" "7739": "Compile in -Od" "7755": "Step through WinMainCRTStartup() to see the CSR bits being set" "7810": "Move the CSR setting mode into UpdateLighting()" "7856": "Step through UpdateLighting() to see the CSR bits being set" "7868": "Compile in -O2" "7882": "The lighting transfer still happens slowly" "7907": "Introduce SetDefaultFPBehavior() for WinMainCRTStartup() to call" "7949": "The lighting transfer still happens slowly" "7972": "Enable multithreading of the lighting" "7989": "Our lighting transfer is quicker, but still feeds back" "8009": "Remove the LooksFishy() assertions from GridRayCast()" "8022": "Try increasing the W modification from ×0.1 to ×0.75 in BuildDiffuseLightMaps()" "8060": "Our speed begins fine, but degrades slightly" "8127": "Make UpdateLighting() call SetDefaultFPBehavior() every frame" "8159": "Our speed begins fine, but still degrades slightly" "8225": "handmade_hero The control register is per thread, right? Are you setting it for the worker threads?" "8243": "Make ComputeLightPropagationWork() call SetDefaultFPBehavior() for each thread" "8275": "Excellent catch, xxthebigfoxx" "8285": "Our speed begins and remains fine, confirming that our problem was due to denormals" "8377": "Go crazy with the camera to see if it causes shenanigans" "8422": "Q&A" "8457": "Q: I'm building my first BVH for my raytracer. Do the previous episodes where you work on a k-d tree go into how to traverse the tree using SIMD without slamming your face into the wall nose-first? I'm having a hard time understanding how to traverse the structure effectively without throwing all the performance benefits of SIMD out the window" "8633": "Q: Can you explain more why denormals could cause performance to degrade?" "8791": "Q: "The volatile portion consists of the six status flags, in MXCSR[0:5], while the rest of the register, MXCSR[6:15], is considered nonvolatile." By the way, so much for flush to zero once per thread being enough" "8811": "Q: Could you put the code back up where you set the control register bits?" "8849": "Q: Would it be worth special-casing the occurrences when a ray runs parallel to the grid of the walk table? Or would the special-casing cost as much as / more than the potential time save?" "8893": "Q: Do you think GPUs would have the denormalized issue?" "9072": "Q: Hi, I came from Day 523 (Introduction to Git), and that's just… The terminology that git uses in such commands like "git bless --by-gnome --assume-mutable-gnomes" and any other command piss me off and makes me feel like git was developed by some Star Wars fan or something and now it's Industrial Standard! Am I doing something wrong? Is it okay to name things in computer science like "gnomes"? Is there any tutorial that explains git in an accessible format? Or do I have to bite the bullet and live through that?" "9221": "So Linus Torvalds is not a good programmer?" "9336": "Isn't Linus pronounced lainus?" "9412": "I guess it's more Swedish than Finnish?" "9485": "Q: So it was a joke‽" "9689": "cmuratori Not wasteful if your job is to integrate patches from hundreds of branches from thousands of developers, day–in day–out. I'd guess 50% of a kernel maintainer's workload is dealing with source control and not programming" "9918": "Which VCS do you use?" "9994": "Call it, with a glimpse into the future debugging the lighting transfer" --- name: "day608" title: "Visualizing Lighting Values" markers: "1": "Note Twitch's latest twitchiness" "86": "Determine to do a lighting quality pass" "290": "Debugging the lighting: 1) Trial-and-error eyeballing" "328": "Debugging the lighting: 2) Create and validate against our own definition of correct lighting behaviour" "468": "Regret not having gained much experience with lighting" "507": "Demo our ability to debug the raycaster" "619": "ComputeLightPropagationWork cycle use: 82%" "683": "Approaching lighting transfer" "832": "Approaching lighting transfer: Draw lines through the centre of each grid cube, derived from the octahedral map, with brighter directions drawn longer" "959": "Try increasing the W modification from ×0.75 to ×0.1 in BuildDiffuseLightMaps()" "983": "Demo the slow, but feeding back, lighting transfer, with the determination to step the lighting frame-by-frame" "1069": "Determine to draw those octahedral lines in a smaller secondary debug bounds" "1174": "Introduce DebugDrawOctahedralValues() for UpdateLighting() to call" "1265": "Note that the diffuse blur is probably providing too much power to the system" "1343": "Make DebugDrawOctahedralValues() draw out our desired debug bounds" "1784": "Introduce a version of * that takes a v3s and s32, and fix compile errors" "1860": "Check out our debug boxes" "1897": "Make DebugDrawOctahedralValues() draw our octahedral lines" "2353": "Check out our octahedral lines" "2400": "Make PushLightingRenderValues() Clamp01() the Color" "2566": "The octahedral lines do not remain white" "2590": "Fix PushLightingRenderValues() to Clamp01() the Line->Color and pass the resulting Color to PushLineSegment()" "2604": "Our octahedral lines still do not remain white" "2629": "Fix PushLightingRenderValues() to pass the clamped Color to PushLineSegment() for both ends" "2641": "Our octahedral lines now remain white" "2660": "Determine to support stepping the lighting frame-by-frame" "2698": "Prevent UpdateAndRenderWorld() from calling UpdateLighting()" "2768": "We get no lighting" "2779": "Make UpdateAndRenderWorld() call UpdateLighting() when we press F9" "2878": "Step the lighting frame-by-frame with F9" "2965": "Delete moonlight variables from GridRayCast()" "3041": "Our system contains no moonlight, yet our octahedral maps are seeing more light from above" "3131": "Make PushLight() draw the light" "3235": "Check out our lights, and see that our octahedral maps are not really responding to them" "3338": "Move the DebugGridIndex and DebugRayIndex DEBUG_VALUE() initialisers from UpdateLighting() to PushLightingRenderValues()" "3403": "Edit our DebugGridIndex and DebugRayIndex to 17912 and 100" "3510": "Make UpdateLighting() set DebugGridIndex and DebugRayIndex to 17912 + (SpatialGrid.CellCount.x × SpatialGrid.CellCount.y) and 100" "3535": "Edit our DebugGridIndex and DebugRayIndex to 17912 and 99" "3730": "Make UpdateLighting() set DebugGridIndex to 17912" "3751": "Edit our DebugRayIndex to 156, and wonder if we are writing back into the wrong parts of the octahedral map" "3861": "Make UpdateLighting() set DebugRayIndex to 156" "3870": "Edit our DebugRayIndex to 155" "3935": "Make UpdateLighting() set DebugRayIndex to 155" "3942": "Try making FullCast() pass an Ignored buffer to GridRayCast(), to rule out the debug system interfering with the SpecAtlas" "4137": "Our problem remains" "4178": "Make FullCast() draw the ExpectedDirection that our rays point into their octahedral map" "4538": "Our rays and octahedral directions are closely aligned" "4612": "Try increasing the W modification from ×0.1 to ×0.75 in BuildDiffuseLightMaps()" "4636": "Step through the lighting" "4663": "Make DebugDrawOctahedralValues() increase the length of our octahedral lines" "4714": "Step through the lighting" "4747": "Make DebugDrawOctahedralValues() draw the diffuse atlas lines, introducing DebugDrawColorDir()" "4923": "Step through the lighting, to see that the diffuse atlas grows quickly" "4986": "Temporarily prevent DebugDrawOctahedralValues() from drawing the diffuse atlas lines" "4999": "Step through the lighting, and note the upwards bias" "5034": "Prevent GridRayCast() from transferring the light for non-hits" "5236": "Our SpecAtlas is getting light from the wrong directions" "5294": "Prevent GridRayCast() from transferring the light for hits" "5312": "We correctly see no light" "5340": "Our bug possibilities: 1) False hit reports; 2) Incorrectly writing the direction; 3) Incorrect debug drawing" "5441": "Scrutinise FullCast() for write-back errors" "5618": "Check out our apparent ray hit" "5636": "Prevent GridRayCast() from transferring the light for non-hits" "5661": "Our target ray is correctly not drawn" "5695": "Move the debug line drawing branch in GridRayCast() outside of the SomethingHit condition" "5725": "Check out our misinformed octahedral lines" "5820": "Edit our DebugGridIndex to 17788" "5888": "Make UpdateLighting() set DebugGridIndex to 17788" "5909": "Edit our DebugRayIndex, hopefully towards a light" "6121": "Try decreasing the W modification from ×0.75 to ×0.1 in BuildDiffuseLightMaps()" "6171": "Edit our DebugRayIndex to 325, directly towards a light" "6211": "Make UpdateLighting() set DebugRayIndex to 325" "6256": "Check out our direct hit" "6316": "Rename ControlMask to FPControlMask in SetDefaultFPBehavior()" "6400": "Q: Maybe just have one light source?" "6427": "Temporarily prevent GenerateRoom() from adding lamps" "6446": "Check out our one light" "6473": "Try increasing the W modification from ×0.1 to ×0.75 in BuildDiffuseLightMaps()" "6480": "Our octahedral maps are still seeing light from the wrong directions" "6518": "A few words on languages with non-helpful "error-catching" features" "6656": "Consider our problem to be an indexing one" "6792": "Q&A" "6809": "Q: Try moving the light" "6822": "Step through the lighting" "6837": "Make UpdateAndRenderWorld() offset the debug light in X" "6863": "See how that affects our octahedral lines" "6901": "Make UpdateAndRenderWorld() offset the debug light the opposite direction in X" "6917": "See how that affects our octahedral lines" "6992": "Prevent UpdateAndRenderWorld() from offsetting the debug light" "7022": "Q: Why are there two lit areas in the map with only one light source?" "7034": "The lighting gets tiled around the world" "7117": "Disable LIGHTING_USE_GRID" "7133": "Our debug visualisation is wrong" "7167": "Let UpdateAndRenderWorld() call UpdateLighting() every frame" "7180": "Our debug visualisation is wrong" "7201": "Scrutinise DebugDrawOctahedralValues() and related functions for bugs" "7571": "Check out our octahedral lines while moving the light" "7661": "Let LIGHT_ATLAS_ASSERT() actually Assert()" "7791": "Happily fail to hit any LIGHT_ATLAS_ASSERT()" "7863": "Q: PushDebugLine() parameter order maybe?" "7925": "Q: Direction inverted?" "7931": "Eyeball the octahedral lines, not seeing inversion" "8015": "Briefly scrutinise DirectionFromTxTy() for bugs" "8069": "Q: Does this not pass through the thing we did for having the 3D texture? Maybe we are tilting the line in the shader" "8117": "Thank you, everyone" --- name: "day609" title: "Reducing Light Contributions from Inaccessible Voxels" markers: "1": "Welcome to the stream, having dreamt up the source of our current bug" "118": "Demo our nonsensical light direction bug, even in the old AABB raytracer" "227": "Walk through DebugDrawOctahedralValues()" "312": "Fix DebugDrawOctahedralValues() to correctly index in to the SpecAtlas" "343": "Our octahedral maps all now point at our light source" "374": "Decrease the line length scaling factor in DebugDrawColorDir() from 1 to 0.15" "400": "Admire our octahedral map lighting directions" "439": "Let GenerateRoom() add lamps again" "458": "Check out our octahedral map lighting directions" "558": "Make GenerateRoom() increase the lamps' light intensity" "646": "Check out our octahedral map lighting directions, and consider increasing the casting density of our rays" "841": "Enable LIGHTING_USE_GRID" "866": "Our octahedral map lighting directions exhibit a positive feedback loop" "900": "Determine to debug the grid ray caster from the perspective of a lighting quality pass" "1036": "Make UpdateAndRenderWorld() call UpdateLighting() when we press F9" "1058": "Step the lighting frame-by-frame with F9" "1144": "Temporarily prevent GenerateRoom() from adding lamps" "1162": "Step the lighting and see the light leaking through the wall" "1285": "Temporarily prevent UpdateAndRenderEntities() from drawing occluders" "1341": "Octahedral maps embedded in geometry see lots of light" "1449": "Disable LIGHTING_USE_GRID" "1460": "Octahedral maps embedded in geometry do not see lots of light" "1569": "Temporarily make UpdateAndRenderEntities() draw occluders as outlines" "1625": "Check out our occluder outlines" "1633": "Reduce the thickness of our occluder outlines" "1648": "Check out our occluder outlines, step the lighting and consider how to treat rays embedded in geometry" "1808": "Determine to try zeroing out rays embedded in geometry" "1852": "Let UpdateAndRenderWorld() call UpdateLighting() every frame, and enable LIGHTING_USE_GRID" "1896": "Watch our lighting feed back" "1925": "Enable FullCast() to detect and handle rays embedded in geometry" "2472": "Our lighting feeds back more slowly" "2508": "Make UpdateAndRenderWorld() call UpdateLighting() when we press F9" "2525": "Step the lighting to see embedded rays remain in the dark" "2583": "Try to disable LIGHTING_USE_GRID, before leaving it enabled" "2620": "Determine to focus on light directional propagation" "2636": "Let UpdateAndRenderEntities() draw occluders like normal" "2675": "Step the lighting to an attractive state" "2711": "Determine to address the light emanating from the underside of our floor" "2820": "Make DebugDrawOctahedralValues() draw the DiffuseAtlas" "2904": "Check out our octahedral map lighting directions into the DiffuseAtlas" "3100": "Determine not to sample from obstructed light probes" "3203": "That's impressive!" "3232": "Use the clear lighting leakage to guide our debugging" "3320": "Determine to enable ComputeVoxelIrradianceAt() to mask out obstructed light probes" "3387": "Weighted Blend" "3661": "Flattening our recursive weighted blend equation" "3869": "How flattening the weighted blend equation helps us" "4080": "Disable LIGHTING_USE_GRID and fix the resulting compile errors" "4111": "See the AABB raycasted lighting" "4121": "Let UpdateAndRenderWorld() call UpdateLighting() every frame, and enable LIGHTING_USE_GRID" "4135": "Check the AABB raycasted lighting" "4158": "Change the 2D Tiles array in ComputeVoxelIrradianceAt() to be 1D" "4281": "The lighting results look the same" "4304": "Transform ComputeVoxelIrradianceAt() to blend the light using a weighted blend" "4599": "The lighting results look the same" "4629": "Make ComputeVoxelIrradianceAt() take a set of Coefficients to omit tiles from the blend" "5071": "The lighting results look the same" "5131": "Try making UpdateAndRenderEntities() omit the Green and Blue components of the occluders" "5199": "Check out the bounce lighting" "5227": "Disable the moonlight in AABBRayCast()" "5248": "Our single-source bounce lighting looks reasonable" "5315": "Try making AABBRayCast() omit all the left-side tiles from the GatherC" "5350": "That screwed up our lighting" "5371": "Briefly eyeball the weights in ComputeVoxelIrradianceAt()" "5440": "Build in -Od" "5456": "Step in to ComputeVoxelIrradianceAt() and inspect the W" "5563": "Prevent a divide-by-0 error in ComputeVoxelIrradianceAt()" "5617": "Our lighting is no longer screwed up" "5688": "Let AABBRayCast() instruct ComputeVoxelIrradianceAt() to gather light from all tiles" "5698": "See red fringing on the right side of the fall-off area" "5778": "Enable LIGHTING_USE_GRID and fix the resulting compile errors" "5808": "Our whole world is tinted red, indicating that the propagation occurs in secondary bounces" "5823": "Set up to prevent ComputeVoxelIrradianceAt() from sampling obstructed light probes" "5933": "Preventing light propagation from obstructed light probes" "6101": "Look into preventing ComputeVoxelIrradianceAt() from sampling obstructed light probes" "6175": "Our eventual light propagation" "6265": "Determine to classify surface obstruction based on the normal" "6333": "Deriving the surface normal from the SampleP" "6512": "Make ComputeVoxelIrradianceAt() classify surface obstruction based on the normal" "6668": "Our obstructed octahedral lighting directions are now zeroed out" "6765": "A few words on visualisation versus unit testing" "6987": "Q&A" "7000": "Q: Is this the cube raycasting or the old AABB raycast?" "7032": "Q: Do you have any suggestions regarding how to study and better retain information? I remember you said you learned math only because you realized you needed to in order to program things. So particularly in relation to math, do you have any advice on how to learn in ways that are more efficient?" "7408": "Q: When you were building the weight table, why were the negative values 1-UVW.x instead of 0-UVW.x? Sorry if you already answered this, I tuned in late" "7470": "Q: The Nvidia paper you were using in the beginning was using depth info on the light probes to avoid light leaking. Is this something you also want to try?" "7566": "Q: Abner said all the info was on the site. He had to go" "7598": "Plug Handmade Seattle 2020" "7806": "Q: Any thoughts on the Nanite Unreal engine demo?" "7868": "Q: My common way to see math and programming is to see the sub-concepts of the concept I'm trying to learn. And do like a tree until I get to the "leafs" which are concepts I already know or axioms. Then I go upwards from there and try to specially understand the how and why of the concepts' connections. Works well for both programming and math" "7894": "Q: Could we just create a distance limit to stop bouncing light?" "7931": "Q: In what way does a custom engine affect the feel of a game? Is it always a question of having better performance allowing for more flexibility? I've always thought there's nothing you can't do in Unity or Unreal. It's just going to be slower" "8141": "The various feels of ColecoVision games" "8384": "I would argue it's not the fault of the engines, but rather lazy devs. You can roll a lot of things on your own in pre-made engines. You could even go some custom / pre-made hybrid" "8567": "My opinion is that this issue of uncreative games arises mostly due to people wanting to earn money with the work they put in. The same happens in music, movies, writing" "8821": "Superhot did that" "8856": "So to make a creative game, look at the constraints of Unity and Unreal, and specifically break them?" "8941": "handmade_hero have you ever worked with HRTF based audio, and do you have an opinion on it?" "9021": "Do you live under rock? What about Cyberpunk 2077, handmade_hero?" "9208": "Thank you, everyone" --- name: "day610" title: "Removing Incorrect Voxel-Voxel Reflections" markers: "1": "Recap and set the stage for the day" "51": "Demo the current state of our grid-based ray cast lighting, noting the occasional feedback" "210": "Determine to: 1) visualise lighting energy levels, and 2) interpolate the lighting more diffusely, to avoid the squared artifacting" "401": "Prevent DebugDrawColorDir() from factoring the Intensity in to the line length" "442": "Check out our balled octahedral map DiffuseMap lighting directions" "457": "Let DebugDrawColorDir() factor the 0–1 clamped Intensity in to the line length" "495": "Check out our more tractable octahedral map DiffuseMap lighting directions" "571": "Consider our bounce-lighting to be plausible" "639": "Leave our lighting flicker for later" "698": "Determine to establish the notion of lighting energy levels" "775": "Maintaining Constant Energy" "973": "Explain that BuildDiffuseLightMaps() pre-creates incoming lighting energy values" "1038": "Specular to Diffuse Blend" "1179": "Cosine-falloff Scattering of Photons" "1341": "Make BuildDiffuseLightMaps() scatter out only as much light as comes in" "1794": "Our world contains a lot less light" "1815": "Let GenerateRoom() add lamps" "1844": "Our lamps don't bounce much light" "1873": "Increase the lamps' light intensity from 2 to 10 in GenerateRoom()" "1886": "Our lamps bounce more light" "1898": "Increase the lamps' light intensity from 10 to 100 in GenerateRoom()" "1917": "Our world ends up turning red" "1929": "Decrease the lamps' light intensity from 100 to 50 in GenerateRoom()" "1943": "Our light is not propagating stably" "2056": "Scrutinise BuildDiffuseLightMaps() for bugs" "2121": "Prevent GridRayCast() from applying the cosine-falloff to ReflectColorFoo" "2162": "Our light is still not propagating stably" "2231": "Let GridRayCast() sample the light when our ray also does not hit" "2269": "Our light now propagates" "2279": "Decrease the lamps' light intensity from 50 to 10 in GenerateRoom()" "2295": "Our light still propagates" "2303": "Increase the lamps' light intensity from 10 to 15 in GenerateRoom()" "2306": "Our light looks great" "2329": "Increase the lamps' light intensity from 15 to 20 in GenerateRoom()" "2344": "Our light does seem to leak again great" "2411": "Prevent GenerateRoom() from adding lamps, and increase the intensity of the debug light by 10× in UpdateAndRenderWorld()" "2443": "Our light is powerful enough to bounce" "2463": "Increase the intensity of the debug light from 10 to 20 in UpdateAndRenderWorld()" "2480": "Our debug light bounces and leaks" "2507": "Scrutinise the termination sampling in GridRayCast() for bugs" "2604": "Test preventing terminator hits from transferring the light in GridRayCast()" "2669": "Our light still leaks" "2699": "Test preventing early-outs from transferring the light in GridRayCast()" "2719": "Our light no longer leaks" "2757": "Scrutinise the terminator sampling code in GridRayCast()" "2881": "Make ComputeWalkTable() terminate within the current cell, not sample from the next one" "2922": "Our light still leaks" "2974": "Add a PieceType_Occluder to entity_visible_piece_flag for UpdateAndRenderEntities() to use" "3142": "Our light spreads, not occluded" "3157": "Make GenerateRoom() add occluders, introducing AddPieceOccluder()" "3343": "Check out our occluders" "3364": "Make GenerateRoom() extend the wall occluders to the top of the tile" "3515": "Our occluders are not aligned properly" "3527": "Make GenerateRoom() size the occluders relative to their position" "3562": "Our light leaks less" "3680": "Our light does leak below from the start" "3690": "Test preventing apron hits from transferring the light in GridRayCast()" "3765": "Our light still leaks" "3781": "Test preventing terminator hits from transferring the light in GridRayCast()" "3795": "Our light no longer leaks" "3805": "Scrutinise the terminator related code in GridRayCast() and ComputeWalkTable()" "4064": "See our non-leaky light" "4082": "Let terminator hits transfer the light in GridRayCast()" "4090": "Our light leaks" "4139": "Scrutinise the termination code ComputeWalkTable()" "4227": "Remove the DEBUG_ZERO code from GridRayCast()" "4250": "Edit our DebugGridIndex towards a grid index below our orphanage" "4306": "Try setting DebugGridIndex to 10788 in UpdateLighting()" "4334": "Edit our DebugGridIndex towards a grid index below our orphanage" "4355": "Try setting DebugGridIndex to 11788 in UpdateLighting()" "4367": "Edit our DebugGridIndex towards a grid index below our orphanage" "4384": "Try setting DebugGridIndex to 13788 in UpdateLighting()" "4403": "Edit our DebugGridIndex and DebugRayIndex to 13586 and 335" "4480": "Make UpdateLighting() set DebugGridIndex and DebugRayIndex to 13586 and 335, and increase the height of our octahedron drawing region in DebugDrawOctahedralValues()" "4545": "Hit a LIGHT_ATLAS_ASSERT in GetTileUnclamped()" "4557": "Fix the VoxStart centering computation in DebugDrawOctahedralValues()" "4595": "See our taller octahedron drawing stack" "4609": "Try making DebugDrawOctahedralValues() draw the entire height's worth of octahedral values" "4626": "Hit an assertion in PushQuad()" "4629": "Make DebugDrawOctahedralValues() originate the octahedral drawing region at 0 in z" "4662": "Check out our nonsensical octahedral values down below the orphanage" "4686": "Note that, while we can only sample from cells inside our lighting voxel, we may cast outside it" "4711": "Pick a grid cell to closely observe" "4812": "Make UpdateLighting() set DebugGridIndex to 0, and remove the AtlasToSpatialGrid expansion (beyond the apron)" "4864": "Find the DebugGridIndex (717) and DebugRayIndex (531) for our close observation grid cell and ray" "5108": "Make UpdateLighting() set DebugGridIndex and DebugRayIndex to 717 and 531" "5119": "Take a look at our debug ray" "5135": "Make DebugDrawOctahedralValues() position the lighting voxel to encompass our ray's target hit" "5188": "Our target is indeed receiving light was somewhere" "5328": "Make ComputeVoxelIrradianceAt() take an OcclusionN which opposes our sampling direction, until we hit" "5482": "Our light no longer leaks" "5533": "Increase the intensity of the debug light from 20 to 50 in UpdateAndRenderWorld()" "5577": "Our light leaks a little bit" "5590": "Decrease the intensity of the debug light from 50 to 30 in UpdateAndRenderWorld()" "5598": "Our light seems to leak" "5633": "Decrease the intensity of the debug light from 30 to 10 in UpdateAndRenderWorld(), let UpdateAndRenderEntities() colour occluders like normal and GenerateRoom() add lamps" "5669": "Check out our lighting" "5721": "Make GenerateRoom() add occluders for trees" "5809": "Check out our occluding trees" "5830": "Make GenerateRoom() add shrunken occluders for trees" "5950": "Hop towards the outside area" "5961": "Make UpdateAndRenderEntities() draw occluder outlines" "5975": "Our trees lack occluders" "5991": "Fix GenerateRoom() to use the expanded TreeVol for the occluder" "6002": "Check out our thinned tree occluders" "6009": "Make GenerateRoom() further thin the tree occluder, and shrink its height" "6163": "Check out our thinned and shrunken tree occluders" "6217": "Decrease the LIGHT_FLOOR_VALUE from 0.2 to 0.0" "6280": "Admire our more lit world" "6337": "Prevent UpdateAndRenderEntities() from drawing occluder outlines, and UpdateLighting() calling DebugDrawOctahedralValues()" "6361": "Admire our lighting" "6409": "Prevent PushLight() from drawing light outlines, and make AddSnake() increase the intensity of the lamps" "6460": "Admire our lighting, and plan for: 1) adapting the power curve; 2) better spreading; and 3) reducing the noise" "6560": "Q&A" "6585": "Q: In the diffuse map weighting divide, could you get divide by zero?" "6665": "Q: With this system, how could we give a more physically-based rendering look to the light?" "6756": "Q: Does the diffuse bounce use the albedo of the materials yet to color the bounce light?" "6795": "Make trees bounce green light, and everything else bounce blue" "6840": "See our tinted light" "6874": "Make trees bounce yellow light" "6888": "See our tinted light" "6935": "Make trees bounce red light" "6946": "See our red-tinted trees" "6966": "Revert the light tinting" "7000": "Q: Can you compare with the older raycast?" "7017": "Disable LIGHTING_USE_GRID" "7023": "Check the old AABB ray cast lighting" "7115": "Q: After the shader modification, it appears the light is still leaking. Why is that?" "7148": "Enable LIGHTING_USE_GRID" "7158": "Our light doesn't seem to leak" "7272": "Increase the intensity of the debug light from 10 to 50 in UpdateAndRenderWorld()" "7299": "Our light does leak" "7310": "Decrease the intensity of the debug light from 50 to 10 in UpdateAndRenderWorld()" "7335": "Make GenerateRoom() add ceiling occluders" "7469": "Check out our ceiling" "7492": "Increase the intensity of the debug light from 10 to 50 in UpdateAndRenderWorld()" "7510": "Our light does leak" "7525": "Decrease the intensity of the debug light from 50 to 10 in UpdateAndRenderWorld()" "7556": "Check our regularly non-leaking light" "7596": "Q: Is it possible to smooth out the lighting so it's not flickering as much?" "7634": "Q: From what I have "perceived" watching Handmade Hero is that lighting has taken up a pretty sizeable chunk of the episodes. Is lighting this inherently complex or am I missing something?" "7677": "Q: What are your plans to fix the square looking interpolation?" "7704": "Q: Do you think, will there be such topics with which we (you) will spend as much time as with light?" "7727": "Q: Even fluid simulation, such as plasma?" "7887": "handmade_hero I'd argue networking which has the same issue. Trying to simulate two things which are apart as temporally the same" "7944": "Q: Yet it seems like when you walk you drag the light behind you with inertia, more like a liquid. Is that on purpose or an effect of computation per frame?" "8033": "I'm sorry, but that just sounds ignorant to the complexities of game networking" "8174": "Q: What is so special in RTX?" "8224": "Q: Is the difficulty of global illumination part of the reason why you're doing it?" "8283": "Q: Even the RTX version of Minecraft has noticeable light lag" "8346": "Q: If someone were making a different game with much sparser scenes containing more complex geometry, would you have any alternative prescriptions? Could the probes be arranged in a sparse grid? Or in camera-frustum-space rather than world-space?" "8496": "Q: When you tested the secondary bounces with the red light, it seemed like it only worked in left and down directions. Do you have an explanation for that?" "8593": "Scrutinise the obstruction Coefficient array computation code in ComputeVoxelIrradianceAt()" "8648": "Masking out obstructed light cells" "8728": "Q: How does an RTX card actually perform ray tracing? Is it similar to what the PS5 can provide, which is hardware to work on a BVH structure to perform ray tracing, or is that different?" "9018": "Q: Are the probes in the wall still getting cleared to zero?" "9048": "The "ray incoherence" is really why a regular GPU has trouble with it as well since thread divergence wreaks havoc with traditional SIMT" "9286": "Thank you, everyone" --- name: "day611" title: "Examining the CPU Voxel Sampling" markers: "0": "Recap and set the stage for the day" "31": "Determine to blur the lighting samples across voxels and reducing the flicker, after speeding up the performance of the grid ray tracer" "182": "Prepare to enable hhlightprof to capture a grid-based ray cast run" "416": "Update InternalLightingCore() to dump out the new source_lightboxes" "587": "Compile in hhlightprof and update it to work with our grid ray caster" "987": "Break in to InternalLightingCore()" "1104": "Reload, to see the walk table break" "1128": "Investigate the walk table breakage on hot reloading" "1252": "Run in -Od, hot-reload and see the walk table break" "1292": "Refamiliarise ourselves with the walk table structure and code" "1362": "Break in to InternalLightingCore() and inspect the LightSamplingWalkTable" "1528": "Break in to GridRayCast() and inspect the WalkTable usage" "1622": "Fix our walk table breakage by making ComputeWalkTable() block copy the SampleDirections, and set a fresh RayD and WalkTableOffset" "2012": "Run in -Od, hot-reload and see the walk table remain intact" "2048": "Run in -O2, hot-reload and see the walk table remain intact" "2082": "Enable then disable the LightBoxDumpTrigger, to dump the lighting" "2117": "Check out our lighting dump files, noting the large size of the source_lighting.dump" "2204": "Hit a read access violation in GetAlignmentOffset() from hhlightprof" "2234": "Make ProfileRun() push the SampleDirectionTable onto the TempArena" "2254": "Hit a write access violation in PushDebugLine()" "2264": "Make ProfileRun() disable UpdateDebugLines" "2283": "Run hhlightprof successfully" "2315": "Run an -O2 build of hhlightprof" "2339": "hhlightprof total seconds elapsed: 7.646482" "2403": "Disable LIGHTING_USE_GRID" "2420": "hhlightprof total seconds elapsed: 7.287836" "2442": "Save off our timings, enable LIGHTING_USE_GRID and make GridRayCast() return early if not Debugging" "2554": "A few words on replacing language / compiler "Errors" and "Warnings" with "I could not compile this" and "Things I noticed about the code"" "2729": "hhlightprof total seconds elapsed (without ray casting): 1.246065" "2804": "Let GridRayCast() do its work" "2814": "hhlightprof total seconds elapsed: 7.706672" "2830": "Reorganise GridRayCast() to decrement the CostMetric after the loops, and comment out debugging code" "3018": "hhlightprof total seconds elapsed: 7.479611" "3046": "Note why the AABB testing loop in GridRayCast() does not tend to use all four SIMD lanes, and the simplicity of ComputeWalkTable()" "3173": "Determine to decouple the spatial and lighting voxel grids" "3235": "Try decreasing the CostMetric from 16 to 4 in GridRayCast()" "3268": "hhlightprof total seconds elapsed: 6.321697" "3300": "Try decreasing the CostMetric from 4 to 0 in GridRayCast()" "3313": "hhlightprof total seconds elapsed: 4.679288" "3334": "Interpret our 4.679288 seconds performance when casting no rays" "3496": "Alignment of Atlas Cells" "4008": "Determine to remove the mutex from our atlas traversal code" "4218": "Change ComputeLightPropagationWork() to distribute the lighting computation along the Y axis" "4320": "hhlightprof total seconds elapsed: 4.422329" "4361": "Consider compacting the lighting atlases" "4484": "Consider the performance of ComputeVoxelIrradianceAt()" "4541": "Try greatly simplifying ComputeVoxelIrradianceAt()" "4606": "hhlightprof total seconds elapsed: 3.160531" "4619": "Try further simplifying ComputeVoxelIrradianceAt()" "4653": "hhlightprof total seconds elapsed: 1.815950" "4670": "Determine to speed up ComputeVoxelIrradianceAt()" "4702": "Instrument ComputeVoxelIrradianceAt() to more specifically gauge its performance" "4908": "hhlightprof total seconds elapsed: 2.806293" "4920": "Break in to ComputeVoxelIrradianceAt() and inspect the assembly" "5011": "Determine to optimise out some of the math in ComputeVoxelIrradianceAt()" "5206": "Make ComputeVoxelIrradianceAt() operate wide" "6547": "Dependents, and Cycle Ordering" "6752": "Continue to make ComputeVoxelIrradianceAt() operate wide" "7643": "Let GridRayCast() use the original CostMetric" "7668": "We are back to normal" "7673": "Q&A" "7695": "Q: Would things go better if you started with U, V and W each 4 wide?" "7776": "Q: Could you not pad by 8 bytes to fix the overlap?" "7803": "Q: The L0 determines how many cache lines the CPU can hold, right?" "7843": "Q: Would you ever consider just going over explaining how an operations takes x amount of CPU ops? Or will that be in the Intro to C?" "7859": "Q: Hi, do you recommend learning vi keybindings, emacs keybindings, or neither?" "7920": "Q: The memory caches on the CPU" "7997": "Hardware Caches" "8570": "Q: Yes, that answers my question. I just was just off by one index" "8595": "Q: How much time are you expecting to shave off from making this routine wide? About 2 / 3 or so? What are your expectations for your grid walk optimization? Are you trying to get under 4 seconds or lower?" "8631": "Q: Yeah, I mentioned those L caches. I was wondering how to determine how many cache lines a core holds" "8663": "8-Way Caches" "8941": "Thanks, everyone" --- name: "day612" title: "First Pass Optimization of Voxel Sampling" markers: "1": "Recap and set the stage for the day" "128": "Describe our vectorisation of ComputeVoxelIrradianceAt()" "191": "Instrument ComputeVoxelIrradianceAt() to verify the new SIMD against the old scalar code" "548": "Continue to make ComputeVoxelIrradianceAt() operate wide" "794": "Introduce an f32_4x version of Clamp01(), with a few words on optimising compilers" "979": "Continue to make ComputeVoxelIrradianceAt() operate wide" "1750": "Change the f32_4x version of Clamp01() to use ZeroF32_4x()" "1797": "How is he going to test the Clamp01() if he deleted it from the original code?" "1804": "Introduce an f32_4x version Floor()" "1906": "Fix compile errors in our ComputeVoxelIrradianceAt() vectorisation" "2152": "Optimise ComputeVoxelIrradianceAt() to sum weights before broadcasting them" "2299": "On the cognitive demand of SIMD, as opposed to instruction sets like AVX-512 and NEON" "2521": "Continue to make ComputeVoxelIrradianceAt() operate wide, loading in the tiles" "4146": "Introduce ConvertS32()" "4364": "Finish making ComputeVoxelIrradianceAt() operate wide, introducing an f32_4x version of Clamp()" "4719": "Run the game" "4742": "Step through ComputeVoxelIrradianceAt() to find that our vectorised code has been compiled out" "4768": "Make ComputeVoxelIrradianceAt() return the SIMD computed result" "4790": "Step through ComputeVoxelIrradianceAt() and try to check out our vectorised code" "4875": "Disable multithreading of the lighting" "4905": "Step through our multithreaded ComputeVoxelIrradianceAt()" "4939": "Comment out the old scalar ComputeVoxelIrradianceAt()" "4996": "Step through our single-threaded ComputeVoxelIrradianceAt()" "5034": "Update RemedyBG" "5190": "Step through the assembly of our new vectorised ComputeVoxelIrradianceAt()" "5321": "Our lighting looks like the vectorisation just worked" "5327": "Enable multithreading of the lighting" "5345": "Our lighting looks like it did before" "5358": "hhlightprof total seconds elapsed: 5.110175" "5456": "Disable LIGHTING_USE_GRID" "5473": "hhlightprof total seconds elapsed: 6.390334" "5556": "Enable LIGHTING_USE_GRID" "5574": "77% of our frame time spent in ComputeLightPropagationWork" "5649": "Q&A" "5700": "Q: Do you plan on bringing your editor on stream, or not? You keep bragging about it" "5705": "Q: Can you run lightprof without any days?" "5717": "rays" "5728": "Try decreasing the CostMetric from 16 to 0 in GridRayCast()" "5763": "hhlightprof total seconds elapsed: 2.583887" "5807": "Q: Can we time that function with the debug system? So we see how long the top part of that function takes?" "5821": "Q: Why is frame time stability such a rare / impossible thing without leaving headroom?" "5934": "Q: Did you activate threading again for the benchmark?" "5958": "Q: Casey, I just sent you an email. It's re: the SSE stuff you did on today's stream. You might get a smile out of it" "5969": "Q: naysayer88 mentioned that you discussed with him why programming languages shouldn't have unsigned integers. Have you posted your rationale somewhere that I can read? Would you be willing to?" "6049": "Q: Can I compile all files in all subdirectories with CL recursively?" "6066": "Q: Can you use some of the lighting work you do on Handmade Hero in different projects?" "6091": "Q: When do we add special sauce, and how much of it? I feel this game needs a Sauce-O-Meter" "6151": "Q: Couldn't the v3 XYZ be loaded with a single load if we pad them?" "6371": "Q: Are there any fundamental differences between games engines that use low poly models vs this one?" "6454": "How can I get your emacs config?" "6488": "Shut it down" --- name: "day613" title: "Merging the Raycaster with the Sampler" markers: "4": "Recap and set the stage for the day" "25": "Our world remains in the dark" "68": "Let GridRayCast() set a non-zero CostMetric" "85": "Demo the current lighting" "96": "Describe and consider the performance of our lighting" "279": "Rare 4coder crash" "326": "Consider gauging the grid ray casting performance if ComputeVoxelIrradianceAt() was optimal" "505": "Break into ComputeVoxelIrradianceAt()" "569": "RemedyBG feature request: Tabulated / colourised disassembly" "737": "Inspect the assembly of ComputeVoxelIrradianceAt()" "746": "Research the comiss instruction" "940": "Try to interpret the origin of the comiss instructions" "1266": "Compare our f32_4x and f32 versions of AbsoluteValue() in the Compiler Explorer" "1798": "Point out our comiss instructions" "1816": "Redo our f32 version of AbsoluteValue() based on the f32_4x version" "1989": "Our comiss instructions are replaced with a call, which in turn retains the comiss ones" "2055": "Revert the f32 version of AbsoluteValue() to use fabs()" "2067": "Our comiss instructions are back, welded in" "2087": "Weld GetOctahedralOffset() in to ComputeVoxelIrradianceAt()" "2197": "Our comiss instructions remain" "2281": "Weld OctahedralFromUnitVector() in to ComputeVoxelIrradianceAt()" "2350": "SignOf() is the source of two comiss instructions" "2404": "Make SignOf() branchless" "2674": "Two of our comiss instructions are gone" "2726": "The lighting still looks the same" "2772": "Make the UV computation in ComputeVoxelIrradianceAt() fully branchless" "3006": "Note why _mm_extract_ps() is often not a good idea, as mmozeiko pointed out" "3198": "Finish making the UV computation in ComputeVoxelIrradianceAt() fully branchless, also noting to change Extract1() and Extract2() to use SHUF+CVTSS" "3256": "All of our comiss instructions are gone" "3286": "Seek improvements to our ComputeVoxelIrradianceAt() vectorisation" "3594": "Remove the stupidity from our ComputeVoxelIrradianceAt() vectorisation" "3902": "A few words on being aware of gotchas in poorly designed instruction sets" "4005": "Continue to remove the stupidity from our ComputeVoxelIrradianceAt() vectorisation, introducing an f32_4x version of SignOf()" "4358": "Hit a read access violation in ComputeVoxelIrradianceAt()" "4418": "Remove the problematic part of the BaseXYZ computation in ComputeVoxelIrradianceAt()" "4430": "We no longer hit that read access violation" "4448": "Scrutinise ComputeVoxelIrradianceAt() for bugs" "4885": "Make ComputeVoxelIrradianceAt() call GetOctahedralOffset() as originally" "4961": "Step into ComputeVoxelIrradianceAt() and compare the Txy and Check" "5088": "Weld GetOctahedralOffset() into ComputeVoxelIrradianceAt() to facilitate closer comparison" "5267": "Hit our assertion in ComputeVoxelIrradianceAt(), and compare the check and newly computed values" "5389": "Weld OctahedralFromUnitVector() into ComputeVoxelIrradianceAt() to facilitate comparison" "5545": "Hit our assertion in ComputeVoxelIrradianceAt(), and compare the check and newly computed values" "5574": "Fix ComputeVoxelIrradianceAt() to use AbsoluteValue() when computing the OneNorm" "5606": "We run successfully" "5615": "Remove the checking code from ComputeVoxelIrradianceAt()" "5631": "Our ray casting performance is improving" "5738": "hhlightprof total seconds elapsed: 5.244874" "5853": "Inspect the assembly of ComputeVoxelIrradianceAt()" "5906": "Replace Extract0(), Extract1() and Extract2() with ConvertF32() and ConvertS32()" "6128": "Our lighting looks the same" "6135": "hhlightprof total seconds elapsed: 5.055217" "6191": "Change ComputeVoxelIrradianceAt() to return the f32_4x ResultRGB, for the callers to use directly" "6373": "Our lighting looks the same" "6378": "hhlightprof total seconds elapsed: 4.963887" "6434": "Weld ComputeVoxelIrradianceAt() straight in to GridRayCast(), to save computing values twice" "6556": "Our lighting looks the same" "6570": "hhlightprof total seconds elapsed: 4.701094" "6640": "Seek further improvements to GridRayCast()" "6859": "Our lighting looks the same" "6862": "Q&A" "6883": "Q: Sorry to be off-topic. I've finished all the five days in the Intro to C and it was awesome. But there's a huge gap between the intro and the main course that I'm not able to fully understand. What's your suggestion? I'm new to programming, started reading K&R recently." "6995": "Plug Star Code Galaxy" "7059": "Close it down" --- name: "day614" title: "Continuing Streamlining the Raycaster" markers: "1": "Welcome to the stream" "6": "Determine to continue with optimisation" "57": "Recap yesterday's welding optimisation in GridRayCast()" "249": "Consider optimisation potential of the SpecTexel load / stores in GridRayCast()" "442": "Illustrate the possibility of loading in the SpecTexel values and InvBlend at the outset" "563": "Seek easier optimisation opportunities in GridRayCast()" "703": "Simplify out OcclusionN from GridRayCast()" "747": "Seek optimisation with OcclusionD and RayD in GridRayCast()" "1128": "Streamline the SignRayD and NormalXYZ computations in GridRayCast()" "1535": "Reacquaint ourselves with the hit testing and shuffling code in GridRayCast()" "1830": "Streamline the Normal selection in GridRayCast()" "2086": "Check out the port usage of various instructions, noting that we may get an AND for free" "2423": "Continue to streamline the Normal selection in GridRayCast(), introducing a NormalTable, before toggling back to the old code" "2892": "Run successfully" "2911": "Streamline the ProbeSampleNSingle usage in GridRayCast()" "3301": "Run successfully, and consider unit testing the grid ray cast" "3409": "Treat ProbeSampleNSingle wide in GridRayCast()" "3694": "Run successfully" "3710": "Treat OcclusionD wide in GridRayCast()" "3808": "Run successfully" "3842": "Finish streamlining the Normal selection in GridRayCast()" "4066": "Run successfully" "4093": "Temporarily try hard setting the NormalIndex to 0 in GridRayCast()" "4107": "We can't tell it's wrong" "4136": "Let GridRayCast() set the computed NormalIndex and make a note to test this" "4176": "hhlightprof total seconds elapsed: 4.534789" "4220": "Simplify out tUpdateBlend in GridRayCast()" "4369": "Augment light_atlas with StrideXYZ_4x and VoxelDim_4x" "4665": "Run successfully" "4674": "Make MakeLightAtlas() set the StrideXYZ and VoxelDim, for GridRayCast() to load out of that atlas, changing their format in light_atlas to be an array of 4" "4837": "Run successfully" "4846": "hhlightprof total seconds elapsed: 4.513986" "4929": "Remove the old AABBRayCast()" "5082": "Run successfully" "5091": "Prepare lighting_box to pack down to 64-bits total, propagating this change" "5309": "Run successfully" "5318": "Clean out the sprawl from FullCast()" "5780": "Run successfully" "5785": "Look into welding the GridRayCast() calling loop from FullCast() into GridRayCast() itself" "5961": "hhlightprof total seconds elapsed: 4.511818" "5976": "Extend GridRayCast() to operate on twice as many samples" "6044": "Run successfully" "6046": "hhlightprof total seconds elapsed: 4.394170" "6112": "Toggle off the debug code in FullCast()" "6206": "hhlightprof total seconds elapsed: 4.392245" "6221": "Consider welding the GridRayCast() calling loop from FullCast() into GridRayCast() itself" "6357": "Q&A" "6427": "Q: Yesterday you changed your SIMD extract functions to use shuffles instead. Could you explain again why that is better?" "6446": "Extract vs Shuffle" "6974": ""Semantic" Extraction" "7082": "Unnecessary extract and cast, with thanks to mmozeiko" "7145": "Shuffle" "7241": "Q: Is there such a thing as smooching too much and causing the compiler to bail before doing optimizations?" "7271": "Q: Would we gain any speed by moving ahead 16 and doing 12 ops per pass?" "7300": "Thank you, everyone" --- name: "day615" title: "Optimized Grid Step Selection" markers: "2": "Welcome to the stream with a plug of Handmade Seattle 2020 and thanks to Abner" "325": "Demo the current state of the lighting" "421": "Explain our lighting system's two hot zones GridRayCast() and ComputeLightPropagation()" "532": "hhlightprof total seconds elapsed: 4.534990" "579": "Toggle off the DiffuseWeightMap update in ComputeLightPropagation()" "586": "hhlightprof total seconds elapsed: 3.599488" "696": "Determine to further optimise GridRayCast()" "716": "Try decreasing the CostMetric from 16 to 0 in GridRayCast()" "737": "hhlightprof total seconds elapsed: 2.211856" "753": "Try increasing the CostMetric from 0 to 1 in GridRayCast()" "777": "hhlightprof total seconds elapsed: 2.629898" "802": "Note the sensitivity of GridRayCast() to repetition" "876": "Let GridRayCast() set the CostMetric to our default 16" "895": "Seek improvements to GridRayCast()" "1108": "Note the fine-grained nature of our lighting grid" "1203": "Make ProfileRun() print the spatial grid occupancy" "1905": "Step in to ProfileRun()" "1928": "Try to demo RemedyBG's , [comma] Watch window syntax, with thanks to x13pixels" "2037": "RemedyBG feature request: Formatters for regular variables in the Watch window" "2073": "Check the box occupancy values produced by ProfileRun()" "2105": "hhlightprof box occupancy: Low" "2194": "Determine to perform ComputeWalkTable() inline" "2352": "Introduce ComputeWalkTableFast(), which does not return anything, but may be used to verify our results" "2583": "Run hhlightprof successfully" "2592": "Induce an error in ComputeWalkTableFast()" "2602": "Run hhlightprof without faulting" "2658": "Step through ComputeWalkTableFast()" "2771": "Use a hand-coded assertion in ComputeWalkTableFast()" "2833": "Run hhlightprof with a fault" "2842": "Remove our induced error from ComputeWalkTableFast()" "2850": "Run hhlightprof successfully" "2868": "Embark on optimising ComputeWalkTableFast() in SIMD" "3307": "Run hhlightprof with a fault, due to tTerminateResult being totally wrong" "3362": "Fix ComputeWalkTableFast() to compute At4 inside the loop" "3415": "Run hhlightprof successfully" "3435": "Optimise ComputeWalkTableFast() to compute BestDim using an HCompShuffler" "3746": "Run hhlightprof with a fault, due to dGridResult being wrong" "3797": "Remove 14 and 15 from the HCompShuffler in ComputeWalkTableFast()" "3897": "Run hhlightprof with a fault, due to tBestRef and tBest differing" "4017": "Consider how best to traverse the walk table" "4243": "Look into _mm_minpos_epu16() at the Intel Intrinsics Guide" "4394": "Introduce a second HCompShufflerLow to compare the low 16-bits of values with equivalent high 16-bits" "4514": "Revert the HCompShufflerLow" "4554": "Optimise our WalkTable traversal using all four SIMD lanes, replacing the HCompShuffler with BestTable" "5473": "Run hhlightprof with a verification fault" "5640": "Assert in ComputeWalkTableFast() that the CompMask is within bounds of the BestTable" "5687": "Run hhlightprof with a verification fault not on the BestTable bounds" "5795": "Add a breakpoint in ComputeWalkTableFast() on SampleDirIndex 135" "5818": "Step through ComputeWalkTableFast() on SampleDirIndex 135" "6055": "Linguistically flip the Best checker in (the working) ComputeWalkTable()" "6081": "Run hhlightprof with a verification fault on SampleDirIndex 256" "6138": "Logically flip the sense of the Best checker in ComputeWalkTable(), and redo the BestTable in ComputeWalkTableFast() in line with the original logic" "6314": "Run hhlightprof with a verification fault right off the bat" "6324": "Verify the BestTable in ComputeWalkTableFast()" "6428": "Reacquaint ourselves with the Best picking in ComputeWalkTable()" "6464": "Revert the sense of the Best checker in ComputeWalkTable()" "6537": "Run hhlightprof successfully" "6566": "Introduce a ShuffleTable in ComputeWalkTableFast()" "6664": "Run hhlightprof successfully" "6672": "Optimise ComputeWalkTableFast() to pick the tBest out of the ShuffleTable" "6852": "Run hhlightprof successfully" "6860": "Optimise ComputeWalkTableFast() to track tTerminate in SIMD" "6918": "Run hhlightprof successfully" "6922": "Optimise ComputeWalkTableFast() to initialise At4 before the loop, and individually offset the four steps by the CellDim" "7205": "Run hhlightprof successfully" "7208": "Optimise ComputeWalkTableFast() to offset all four steps in SIMD, branchless, using a MaskTable" "7480": "Run hhlightprof with a verification fault" "7495": "Scrutinise our MaskTable" "7537": "Compute a Compare for At4 in ComputeWalkTableFast()" "7565": "Break in to ComputeWalkTableFast() and compare the Compare with our actual At4" "7624": "Set At4 equal to Compare, saving off the OldAt4" "7639": "Run hhlightprof successfully" "7654": "Try making ComputeWalkTableFast() offset the At4 in two steps" "7698": "Run hhlightprof successfully" "7707": "Gauge the performance of our ComputeWalkTableFast()" "7908": "Build in -O2" "7932": "Run the game successfully" "7946": "Make ComputeWalkTable() compute InvRayD before the stepping loop, to remove a divide within it" "7981": "The lighting looks completely different" "8015": "Make ComputeWalkTable() compute the InvRayD using a safe ratio" "8137": "The lighting remains different" "8166": "Fix ComputeWalkTable() to compute InvRayD after RayD itself" "8186": "The lighting is back to how it was" "8190": "Make ComputeWalkTable() compute InvRayD as normal" "8201": "The lighting is fine" "8218": "Build in -Od" "8234": "Run hhlightprof with a verification fault" "8242": "Make ComputeWalkTableFast() also precompute InvRayD" "8270": "Run hhlightprof successfully" "8330": "Q&A" "8351": "Q: Hi Casey! I was very sick and my health condition was very bad and for the last three months and now I am fortunately back to life and to Handmade Hero. Could you briefly say what the focus of Handmade Hero was in the last three months? Thank you!" "8416": "Q: handmade_hero Hello Casey, this question may be off-topic but it's really important for me. I know you were doing some UI development. I saw your video on immediate mode UI. I have the only job opportunity to develop UI for mobile app but I've never done that and I need this job. So can you please give me some advice on where to find information, maybe some guides on UI development and were you using some library or did you write everything from scratch? It would be very helpful for me" "8594": "Q: What is the best way to debug something that only happens in optimized code?" "8630": "Q: How expensive do you think the table lookups are?" "8883": "Q: Can you give a general idea of how to optimise branches out of a function?" "8989": "Q: Hello, thank you for all the videos. I am a bored CS student that aced his exams and now does not know what to do during his vacation" "8998": "Q: What kinds of things would you like the compiler to do to help with this table stuff (if any)?" "9012": "Q: Could you explain the compile time execution as we have in jai?" "9019": "Q: Would meowhash be suitable to create a custom UUID? It wouldn't be part of the UUID spec, but could it serve the same purpose?" "9042": "End it there" --- name: "day616" title: "Tableless Grid Walk" markers: "2": "Recap and set the stage for the day" "39": "hhlightprof total seconds elapsed: 4.508690" "92": "Set up to gauge the performance of the inline lighting grid traversal computation" "229": "Walk through ComputeWalkTableFast()" "371": "Begin to enable GridRayCast() to invoke and verify the inline lighting grid traversal" "579": "Consider the problem with our WalkTable X, Y, X, Z ordering" "631": "Revert GridRayCast()" "641": "Consider ordering our WalkTable X, Y, Z, X" "840": "Run hhlightprof successfully" "848": "Provoke an error in the BestTable" "861": "Run hhlightprof with a fault" "868": "Change ComputeWalkTableFast() to pack our SIMD lanes X, Y, Z, X" "1188": "Run hhlightprof with a fault" "1194": "Update the MaskTable in ComputeWalkTableFast() to work with X, Y, Z, X ordering" "1230": "Run hhlightprof with a fault" "1271": "Fix the X, Y, Z, X ordered MaskTable in ComputeWalkTableFast()" "1288": "Run hhlightprof with a fault" "1317": "Update ComputeWalkTableFast() to set t4s from shuffled X, Y, Z, X ordering" "1336": "Run hhlightprof with a fault" "1622": "Fix the BestTable documentation" "1677": "Investigate why t4's fourth SIMD lane is unset" "1716": "Fix MaskTable to set the fourth SIMD lane" "1740": "Run hhlightprof successfully" "1743": "Change ComputeWalkTableFast() to leave the fourth SIMD lane blank, to give X, Y, Z" "2075": "Run hhlightprof with a fault" "2100": "Make ComputeWalkTableFast() zero out the fourth lane of InvRayD4" "2119": "Run hhlightprof with a fault" "2200": "Update the MaskTable in ComputeWalkTableFast() for X, Y, Z ordering" "2233": "Run hhlightprof with a fault" "2263": "Update the ShuffleTable in ComputeWalkTableFast() for X, Y, Z ordering" "2289": "Run hhlightprof with a fault" "2320": "Step through ComputeWalkTableFast()" "2431": "Document the BestTable in ComputeWalkTableFast()" "2877": "Make ComputeWalkTableFast() set the BestTable entry for all-equal as 0 (or X)" "2905": "Run hhlightprof until faulting on SampleDirIndex 1012 (out of 1024)" "3026": "Document and determine that the Y > Z case simply involves a preference problem" "3173": "Change the old ComputeWalkTable() to prefer Z in the Y > Z case" "3265": "Run hhlightprof successfully" "3277": "Loft up the BestTable, ShuffleTable, MaskTable and related values from ComputeWalkTableFast() to GridRayCast(), prefixing their names with t" "4044": "Run hhlightprof with a fault" "4099": "Fix GridRayCast() to update tTerminateVerify after verifying" "4107": "Run hhlightprof with a fault" "4234": "Double-check what ComputeWalkTable() does when a Ray is pointing backwards" "4324": "Step through GridRayCast()" "4591": "The WalkTable contains garbage also in-game" "4729": "Step through GridRayCast() watching the tTerminate values" "4904": "Break into GridRayCast() and investigate the inf tTerminate" "5057": "Add a breakpoint in ComputeWalkTable() on DestIndex 6913" "5097": "Break into ComputeWalkTable() on DestIndex 6913, with inf tTerminate" "5279": "Add a breakpoint earlier in ComputeWalkTable() on DestIndex 6912" "5296": "Step through ComputeWalkTable() on DestIndex 6912" "5372": "Make ComputeWalkTable() and ComputeWalkTableFast() use the AbsoluteValue of the ray direction" "5431": "Successfully step through ComputeWalkTable() on DestIndex 6912, and into the game" "5464": "Run the game successfully in -O2" "5492": "Switch GridRayCast() over to use the inline lighting grid traversal" "5566": "Run the game successfully" "5581": "hhlightprof total seconds elapsed: 6.826915" "5627": "Toggle GridRayCast() to the precomputed WalkTable" "5637": "hhlightprof total seconds elapsed: 4.458800" "5745": "Change GridRayCast() to compute InvRayDPacked more concisely" "5836": "hhlightprof total seconds elapsed: 4.470019" "5854": "Toggle GridRayCast() to the inline lighting grid traversal" "5863": "hhlightprof total seconds elapsed: 7.426753" "5875": "Try letting GridRayCast() both use the precomputed WalkTable, and compute the traversal inline" "5912": "Run hhlightprof with a fault" "5971": "Break into GridRayCast() on our fault" "6076": "Prevent GridRayCast() from setting tTerminate to tTerminateVerify" "6086": "Run the game with a fault" "6132": "Prevent GridRayCast() from setting GridIndex to dGridResult" "6144": "Run the game successfully" "6157": "Run the game in -O2" "6177": "hhlightprof total seconds elapsed: 6.543860" "6209": "Inspect the assembly of our inline lighting grid traversal" "6336": "Q&A" "6355": "Q: I think the first entry of the tShuffle and tMask tables haven't changed to x, as you have done for the BestDim table (the all equal case). It is a rare case, though (if it happens at all)" "6398": "Fix the ShuffleTable and MaskTable for X, Y, Z ordering" "6435": "Run the game successfully" "6464": "Q: Could we be going out of the cache and that made it slow? How would we check that?" "6588": "Wrap it up" --- name: "day617" title: "Half-resolution Spatial Grid" markers: "0": "Recap and set the stage for the day" "27": "Briefly show the current lighting" "37": "Describe the new inline lighting grid traversal" "165": "Table-driven Raycast" "321": "Correspondence Between the Lighting and Spatial Grids" "508": "Storage costs and compressibility of grid correspondence" "713": "High-resolution lighting grid marching, before stepping down to the low-resolution spatial grid" "908": "Prepare to define a lower resolution spatial occupancy grid" "957": "Toggle off the inline lighting grid traversal in GridRayCast()" "978": "hhlightprof total seconds elapsed: 4.453437" "1070": "Consider how to reduce the spatial grid resolution" "1168": "Halve the SpatialGrid resolution in ProfileRun(), updating ComputeLightPropagation() to account for this" "1574": "hhlightprof BoxCount[0]: 1400" "1601": "Fix the SpatialGrid apron size in ProfileRun()" "1641": "hhlightprof BoxCount[0]: 1400" "1657": "Build in -Od" "1680": "Step through ProfileRun() and inspect the SpatialGrid" "1752": "Make ProfileRun() position the SpatialGrid using SetMinCorner()" "1880": "hhlightprof BoxCount[0]: 1400" "1897": "Step through ProfileRun() and inspect the SpatialGrid" "1906": "Make ProfileRun() account for the lower resolution when setting SpatialMinCorner" "2021": "hhlightprof box distribution: More desirable" "2100": "Statistically speaking, how much of Twitch chat do you think understands the principles the streamer is transmitting?" "2127": "Assess our box distribution" "2198": "Build in -O2" "2221": "hhlightprof total seconds elapsed: 4.673890" "2294": "Toggle off the SpatialGrid downscaling in ProfileRun()" "2317": "Introduce voxel_sparse_index and SparseIndexFrom()" "2749": "Revert voxel_sparse_index and SparseIndexFrom()" "2756": "Why safely build the additional tables" "2804": "Expand the LightSamplingWalkTable in lighting_solution and introduce GetOctantFor() to correctly index into it" "3369": "Decrease MaxCostPerRay from 16 to 8 in UpdateLighting() and ProfileRun()" "3486": "Make ComputeWalkTable() build all eight octants of the LightSamplingWalkTable" "3765": "On indexing mismatch bugs" "3876": "Toggle on the grid positioning code in ProfileRun()" "3915": "Crash hhlightprof" "3934": "Change LightSamplingWalkTable to be an array of 8 in lighting_solution" "3946": "Run hhlightprof successfully" "3961": "Build in -O2" "3976": "hhlightprof total seconds elapsed: 4.226165" "4000": "Our world is unlit" "4032": "Remove stale code from the lighting system" "4225": "Build in -Od" "4260": "Step in to GridRayCast() and inspect the LightSamplingWalkTable and indices" "4494": "Remove further stale code from GridRayCast()" "4591": "Step through GridRayCast() watching the Node indices" "4642": "Make UpdateLighting() halve the SpatialGrid resolution and reposition it" "4795": "Our world is lit" "4806": "Build in -O2" "4814": "Admire our lighting" "4842": "hhlightprof total seconds elapsed: 4.256591" "4914": "Note down our hhlightprof lighting timing" "4958": "Toggle off FullCast() in ComputeLightPropagationWork()" "5003": "hhlightprof total seconds elapsed: 1.028882" "5079": "Gauge our lighting performance improvement" "5111": "Toggle off GridBuildSpatialPartition() in InternalLightingCore()" "5135": "Crash hhlightprof" "5148": "Toggle off the SpatialGrid accessing in FullCast()" "5166": "Crash hhlightprof" "5174": "Revert our SpatialGrid toggles, and instead toggle off the main loops in GridBuildSpatialPartition() itself" "5222": "hhlightprof total seconds elapsed: 1.035324" "5236": "Revert our GridBuildSpatialPartition() toggless" "5257": "hhlightprof total seconds elapsed: 4.230452" "5268": "Q&A" "5314": "Q: Takeover the world, yet anything thing?" "5337": "Q: Missed a fair few weeks. Can you run through how the lighting looks now?" "5465": "Q: Do you plan to implement any de-noising on the light?" "5487": "Q: Is neon any better?" "5524": "Q: Given that AVX2 is seven years old, would it help to use it instead of SSE?" "5606": "Q: Skylake-X also supports AVX-512" "5652": "Q: Skylake-X is not server. But it is true that nobody has them" "5733": "Q: Couldn't we do two paths, one with and one without AVX2?" "5795": "Why is AVX-512 so uncommon?" "5859": "There are a few laptops out with Ice Lake that has AVX-512" "5881": "Wrap it up" --- name: "day618" title: "Analyzing the Diffuse Blur" markers: "2": "Recap and set the stage for the day" "40": "Demo the lighting with different resolution spatial and lighting grids" "142": "Determine to optimise the lighting pipeline, and work on quality, smoothing out the rectilinear pattern and reducing flicker" "302": "Determine to compile at least the lighting in clang, to gauge the SIMD performance" "410": "How the ABI works on Microsoft Windows, in terms of register use" "601": "On the possible work getting the code to compile with clang, including its exploitation of undefined behaviour" "826": "hhlightprof total seconds elapsed: 4.221848" "832": "Determine to optimise the diffuse blur" "871": "Toggle off the diffuse blur in ComputeLightPropagationWork()" "890": "hhlightprof total seconds elapsed: 3.233531" "915": "Briefly describe our diffuse blur in ComputeLightPropagationWork()" "959": ""Seperable" Filters" "1135": "Example filter: Linear blend" "1433": "Example filter: Bilinear blend" "1640": "Example seperable filter: two-pass, one-dimensional blends" "1756": "Get some tissues" "1760": "afk" "1801": "Return with tissues" "1820": "Our current cosine-weighted falloff equation" "2147": "Walk through UnitVectorFromOctahedral()" "2258": "Determine to print the weight map table" "2351": "Regular tea break" "2360": "afk" "2406": "Return with the realisation that we're at risk of infringing Jon Blow's on-stream tea-making patent" "2427": "Make ProfileRun() print the DiffuseWeightMap to stdout" "2789": "hhlightprof DiffuseWeightMap: Many 0s" "2811": "Reacquaint ourselves with the use of DiffuseWeightMap in ComputeLightPropagationWork" "2926": "Make ProfileRun() print out the DiffuseWeightMap, based on BuildDiffuseLightMaps()" "3116": "hhlightprof DiffuseWeightMap: Sensibly populated" "3140": "Make ProfileRun() print dashes when the Entry is 0" "3169": "hhlightprof DiffuseWeightMap: More visible shape" "3190": "Regular tea break" "3194": "afk" "3280": "Return, with the tea now steeping" "3285": "Analyse the DiffuseWeightMap printout for reused values" "3523": "Approaches to making the cosine falloff seperable: 1) Produce a somewhat similar, but regular pattern; 2) Classify values by their position" "3572": "There's the tea" "3577": "afk" "3617": "Return and pour the tea" "3650": "Try making ProfileRun() print out the DiffuseWeightMap 16×16, to see the shape when it wraps" "3723": "hhlightprof DiffuseWeightMap: 16×16 shapes, and identical rows between maps" "3917": "Consider changing the cosine falloff function to a basic blur" "3988": "Accidentally add a threshold of 0.01f to BuildDiffuseLightMaps()" "4040": "hhlightprof DiffuseWeightMap: Without threshold" "4058": "Add a threshold to the DiffuseWeightMap printout" "4093": "hhlightprof DiffuseWeightMap: Still without threshold" "4104": "Eyeball ProfileRun() for threshold bugs" "4192": "Step in to ProfileRun() and inspect W" "4235": "Fix the DiffuseWeightMap printout threshold in ProfileRun()" "4285": "hhlightprof DiffuseWeightMap: With threshold, blank columns" "4425": "Try various thresholds for the DiffuseWeightMap printout" "4494": "Make ProfileRun() print out the DiffuseWeightMap 8×8" "4505": "hhlightprof DiffuseWeightMap: 8×8 shapes, with threshold" "4547": "Make ProfileRun() print out the X, Y and Z directions of a DiffuseWeightMap Element" "4695": "hhlightprof DiffuseWeightMap: Element directions" "4722": "Make ProfileRun() add a dash to its 0 printout" "4736": "hhlightprof DiffuseWeightMap: Element directions, completely symmetric" "4955": "Our cosine falloff equation, and its reusable terms" "5513": "Rephrasing the DiffuseWeightMap generation in a seperable way" "6028": "Determine to ruminate on the DiffuseWeightMap" "6055": "Q&A" "6095": "Q: Couldn't at least the tetrahedron unit vector function use a lookup table and lerp?" "6158": "Q: Speed up that function, if it gets called a lot" "6227": "Toggle on the diffuse blur in ComputeLightPropagationWork()" "6232": "Our desire to do the cosine falloff seperable, if we can" "6321": "Wrap it up" --- name: "day619" title: "Adding Asset Tag Hashes" markers: "1": "Welcome to the stream" "93": "Determine to start editing the game, keeping an eye on our 4coder config" "124": "Demo the "d" key's "delete range" behaviour, describing our desired one" "209": "Update casey_delete_to_end_of_line for the new 4coder, and bind it to "d"" "390": "Find that casey_delete_to_end_of_line deletes one extra character at the start" "426": "Fix casey_delete_to_end_of_line" "445": "casey_delete_to_end_of_line now partially works" "456": "Enable casey_delete_to_end_of_line to join the following line with the current one when the cursor is at the latter's end" "596": "Find that casey_delete_to_end_of_line deletes the whole line" "610": "Fix casey_delete_to_end_of_line to correctly join lines" "629": "casey_delete_to_end_of_line now fully works" "642": "Our parentheses and line highlight colours are the same" "698": "Download 4coder_fleury and remedybg 0.3.1.1" "981": "Check out theme_example.4coder from 4coder_fleury" "1032": "Rebuild and launch 4coder" "1064": "Modify 4coder_fleury.cpp to include 4coder_fleury_casey.cpp" "1087": "Hit a compile error in 4coder_fleury_casey.cpp" "1122": "Merge in our cursor drawing code, with a recommendation of Beyond Compare" "1349": "Build 4coder successfully but see a weird purple pane" "1394": "Update our theme-casey.4coder based on theme_example.4coder" "1592": "Our colours are now working" "1623": "Edit our colours" "1736": "Our parentheses are now distinguishable from the line highlight, but now there's another mystery" "1756": "Continue to edit our colours" "1841": "Our parentheses are now fine" "1890": "Continue to edit our colours" "2007": "The braces now highlight a little bit" "2076": "Note our theme issues to deal with off-stream" "2158": "Zero out the cursor roundness and dim the line and annotation colours" "2218": "Our colours are now tolerable, but the cursor interpolation seems a little broken" "2278": "Fix compile error in the cursor roundness and reduce the thickness" "2305": "The thickness only gets applied to the start mark" "2396": "Try out editing and building our real code" "2524": "Determine to remove the idea of entity pieces" "2586": "Traverse the orphanage, with the determination to ease the setup of art assets with entities" "2642": "Describe the complexity – both unneeded and necessary – of base_game.hht" "2868": "Determine to replace manual asset tags with the notion of an indexing scheme" "3399": "Sketch out a new set of tags in base_game.hht" "3625": "Add our new tags to asset_tag_id, noting that token-move skips past semicolons" "3706": "Continue to sketch out a new set of tags in base_game.hht and asset_tag_id" "4238": "Revert the new tags" "4270": "Consider hashing the asset tags" "4464": "Introduce asset_hash_entry" "4537": "Bind word_complete everywhere and disable compilation of the sampling generator and lighting profiler" "4616": "Augment game_assets with an asset_hash_entry array, noting that it'll be more like a bit field" "4810": "Introduce GetTagHash()" "5027": "Augment entity_visible_piece with TagHash, with a few words on the inefficiency of variable-length data" "5155": "Make GetTagHash() weld the AssetCategory into the TagHash" "5559": "Begin to prepare UpdateAndRenderEntities() to use our new TagHash" "5658": "Consider how parameters such as FacingDirection may interact with our TagHash" "5795": "Make UpdateAndRenderEntities() simplify the MatchVector as a v4 and pass that and the TagHash to GetBestMatchBitmapFrom()" "5861": "4coder feature request: Unobtrusive function signature placement, maybe in a multipurpose compilation console" "6075": "Or make it a shortcut, like Ctrl-Space or something to pop it up when it's needed?" "6206": "I have an idea... maybe a "peek buffer" that you can stick into a panel?" "6247": "As a vim user, I never found code peek that useful as an idea, because with vim's jump history you can just jump to the definition, look at it, maybe even copy it, and then jump back with minimal effort, and no new UI needed" "6309": "But what if you only have one pane?" "6334": "Jump history, you'll never go back!" "6351": "Update GetBestMatchBitmapFrom() and friends to use our new TagHash, introducing asset_tag_hash and GetAssetFrom() to replace GetBestMatchAssetFrom() and GetFirstAssetFrom()" "6578": "Allow SSE4.1" "6731": "Introduce Hash32() using two rounds of _mm_aesdec_si128() for GetAssetFrom() to call" "7165": "Consider the performance of Hash32()" "7237": "Make Hash32() set a random Seed from random.org" "7357": "Set up GetAssetFrom() to work with a welded Coordinate, introducing asset_match_vector" "8047": "Q&A" "8080": "Just put four VMs in front of the code and you get your answer as to why it's so slow" "8122": "Q: Off-topic, feel free to ignore, but someone told me that on PlayStation (didn't specify which PlayStation) games run in a sandbox, and if you forget to free any memory you allocated when you exit, that sandbox will be kept alive in the background. That sounds like nonsense. Is it true? (If this can be answered without breaking NDA)" "8274": "Q: I would like to hear a discussion between you and Jon about metaprogramming philosophy. On one of his streams, I asked whether he thought Jai would ever satisfy you in terms of metaprogramming, and he said that the way you think of metaprogramming is really different from the way he thinks of it, and he thinks you are very wrong about it. He said it's fine that you disagree, though. Sounds like a good discussion" "8485": "Q: Why are new compression techniques such as Microsoft Direct Storage / PS5 compression needed for instant loading. Why are NVME speeds not enough? What's the bottleneck?" "8894": "Q: So I'm out of touch, where did you move to?" "8915": "Q: The thing is, if I go from SSD to NVMe, speeds are not improved 500MB/s to 4GB/s" "8968": "Q: Yes, SATA to NVMe" "9031": "Wrap it up for today, with a plug of Star Code Galaxy and a glimpse into the future" --- name: "day620" title: "Asset Tag Usage Code" markers: "0": "Recap and set the stage for the day working on asset tag matching" "23": "Plug the Meow the Infinite sale" "93": "Q: Is international shipping included?" "176": "Set up to continue work on our new TagHash and MatchVector asset matching scheme" "432": "Compress out the old asset matching code for the TagHash and MatchVector matching" "672": "Determine to clarify GetAssetFrom()" "768": "Describe Hash32(), in particular _mm_aesdec_si128()" "936": "Introduce hashable_value for Hash32() to operate on and asset_hash_entry to contain, creating handmade_hash.cpp and .h" "1619": "Consider simplifying game_assets and storing the asset data structure directly in the hash" "1869": "Revert the hashable_value introduction and handmade_hash.cpp and .h creation, and instead augment asset_hash_entry with an MatchVector" "2099": "Invoke fleury_toggle_power_mode and fleury_toggle_battery_saver" "2109": "Implement our new TagHash and MatchVector matching scheme in GetAssetFrom(), augmenting asset with NextInTagHash, TagHash, MatchVector and MatchAnyFlags" "2905": "Fix compile errors, replacing asset_hash_entry with u32 in game_assets" "3072": "Make InitParticleCache() and ExecuteBrainHero() call GetTagHash(), and default to zero the MatchVector in all the GetBestMatch*() function" "3340": "Begin to make UpdateAndRenderEntities() prepare the MatchVector to pass to GetBestMatchBitmapFrom(), introducing an asset_match_vector_element enum" "3928": "Is the indentation broken because virtual whitespace is disabled? The fact that you can edit the leading whitespace on a line tells me you have virtual whitespace turned off. Is this intentional?" "4018": "Make UpdateAndRenderEntities() map the MatchVector's FacingDirection octant to the nearest quadrant" "4491": "Consider our support for variant picking in FillUnpackedEntity()" "4790": "Fix UpdateAndRenderEntities() only keep the bottom two bits of the FacingDirIndex" "4814": "Update FillUnpackedEntity() to use GetTagHash()" "5011": "Prepare FillUnpackedEntity() to call GetVariantCount() for random picking" "5109": "Introduce a sizing tag, Tag_Large" "5430": "Introduce a stubbed out GetVariantCount()" "5539": "Update AddPiece() to take an asset_tag_hash" "5598": "Introduce ShotIndex* and LayerIndex* for use in intro_cutscene.hht" "5917": "A few thoughts on Ron Gilbert as a brilliant programming architect" "6588": "Update RenderLayeredScene() to use GetTagHash()" "6797": "Consider (but decide against) supporting order-independent tag matching" "6910": "Continue to update RenderLayeredScene() to use the new matching scheme" "7065": "Update InitializeUI() to use GetTagHash(), removing asset_font_type and FontType(10) for a newly-introduced Tag_DebugFont tag" "7365": "Update all definitions of AddPiece() to take asset_tag_hash and their call sites to use GetTagHash(), introducing a version of GetTagHash() that takes an asset_tag_hash for merging in" "7774": "Seek to bind "~" to Shift-Tick in 4coder" "7893": "write_text_input, handmade_hero" "7900": "Bind write_text_input to Shift-Tick in 4coder" "7919": "Try unsuccessfully to type a "~"" "7956": "I am not sure why it's not just working" "7963": "Leave a note in GetTagHash() to INSERT TILDE HERE" "7973": "Ctrl-c Ctrl-v one" "7997": "Obtain a "~" from handmade_intrinsics.h" "8033": "Determine to update everyone else to use GetTagHash() next time" "8089": "Double-check the 4coder bindings regarding the "~"" "8151": "Thank you, with a plug of the redesigned site, Meow the Infinite and Star Code Galaxy" --- name: "day621" title: "Asset Tags in the World Generator" markers: "1": "Recap and set the stage for the day" "54": "Consider the order-dependence of the asset tag order" "193": "Consider the performance of Hash32() in terms of order-independence" "419": "Consider the point of order-independent asset tagging" "488": "Sketch out updates to base_game.hht" "638": "Check out our compile errors" "668": "Bind "J" globally" "750": "handmade_hero `fleury_toggle_compilation_expand`" "753": "Bind "Insert" to fleury_toggle_compilation_expand" "782": "Try making AddPieceLight() and AddPieceOccluder() pass {} to AddPiece()" "859": "Function parameter lookup and failed namespacing in C++" "1232": "Update AddPlayer() to use GetTagHash()" "1443": "Reacquaint ourselves with the GEN_CREATE_ENTITY() macro and its calling sites" "1786": "Shrink the Tags array in gen_entity from 14 to 4" "1818": "Consider how to encode (random) variants in our tag hash" "2296": "Consider doing GetAssetFrom() exactly as the old GetBestMatchAssetFrom(), just without the WeightVector" "2606": "Make GetAssetFrom() match based on the old GetBestMatchAssetFrom(), just without the WeightVector" "3012": "Reflect on our new asset matching, with optimisation potential and exact matching on tags" "3061": "Change asset_match_vector to be an f32 array and remove TagRange from game_assets" "3115": "Consider introducing a Modulus() function for facing direction" "3285": "Embark on updating the picking of FacingDirection in UpdateAndRenderEntities()" "3447": "Revert the removal of TagRange from game_assets" "3550": "Augment entity_visible_piece with an f32 Variant for UpdateAndRenderEntities() to use" "3632": "Update AllocateGameAssets() to operate on MatchElement" "3708": "Hmmm I don't know, handmade_hero… He's online so I will ping him about it" "3779": "Consider making GEN_CREATE_ENTITY() take a tag hash" "3838": "Yeah, that is weird… because it's different from the virtual whitespace behavior…" "3844": "Make GEN_CREATE_ENTITY() and all entity generation functions take a BaseHash" "4064": "Look into updating GenerateRoom() to our new asset matching scheme" "4164": "Delete AddTag() and the Tags array from entity, and propagate this change" "4325": "Consider providing a source of entropy to AddPiece()" "4414": "Introduce entity_piece_asset for entity_visible_piece to contain" "4668": "Workaround C++'s ambiguous interpretation of {} in our AddPiece() calls" "4761": "Respecify AddTreeTags() as GetTreeTags() and change GEN_CREATE_ENTITY() to take an entity_piece_asset" "5002": "Introduce ChangeHash()" "5153": "Change the AddPiece() forward-declarations to take an entity_piece_asset, and pass {} to AddPiece() again" "5193": "Introduce GetPieceAsset() for AddPlayer() to call" "5375": "4coder feature request: Early scrolling out from behind an on-top window" "5405": "Make AddPlayer() use GetPieceAsset() and ChangeHash()" "5575": "Defer our GenerateRoom() update to next time" "5632": "Fix the GenEntityAtTraversable() call in GenerateRoom()" "5699": "Q&A" "5747": "handmade_hero I have alerted the 4th dimension of the bug" "5771": "Q: Are asset tags used for something like lister panels?" "5793": "Q: The API you mentioned not existing earlier for bulk sending packets: why doesn't it exist? Is there some hardware limitation?" "6022": "Q: Thoughts on Unity / Unreal / Godot (their quality)? How would an engine made by you look like?" "6169": "Ori and the Will of the Wisps is done in Unity. Doesn't that count for AAA-quality? Though they had to modify it a bit" "6411": "Q: Have you ever explained bit-fields and, if not, can you and is it still useful to use today? I just saw that in an old code base to do flags" "6635": "HmartArg handmade_hero If it matters, bit-fields are nice to use in networking, because you can pack the booleans in 1 or 2 bytes instead of taking up a byte for each one" "6664": "Q: I didn't see you using any version control. Aren't you using any and are you not afraid of losing something valuable due to the mistake of deleting a bunch of code lines too quickly?" "6750": "Using compression, not bit-fields, to minimise transmission bandwidth for networking" "6803": "Q: Could you explain the downside of the JSON data format?" "6940": "Q: Why do you use 32-bit bools – bool32 – rather than something smaller?" "7009": "Q: Have you heard about zstandard data compression developed by facebook?" "7051": "Wrap it up" --- name: "day622" title: "Debugging Asset Tag Hashes" markers: "2": "Recap and set the stage for the day" "126": "Flexible vs Rigid Asset Lookup" "355": "Why Flexi-Rigid Asset Lookup: 1) Straightforward coding" "436": "Why Flexi-Rigid Asset Lookup: 2) Performance" "632": "Moving from per-entity to per-piece tags" "689": "Meow" "744": "Product request: Task chair (attachment) with a pussy perch" "846": "Try a baby pouch" "903": "Commit to investing in a Task Cat chair" "928": "Introduce gen_entity_tag_builder as an asset tag aggregator, for GenerateRoom() to pass to AddTag()" "1425": "Augment gen_entity with a FacingDirection" "1583": "Update everyone to use the new gen_entity_tag_builder and FacingDirection" "1975": "handmade_hero Not GET but GEN" "1979": "Make GenerateRoom() pass a BaseHash to GenEntityAtTraversable()" "2174": "Introduce a version of GetPieceAsset() that takes a gen_entity_tag_builder" "2331": "Remove gen_entity_tag and fix compile errors" "2497": "Run the game and hit our TextureIndex == TextureIndex32 assertion in PushQuad()" "2566": "Run the game in -Od and again hit our TextureIndex == TextureIndex32 assertion in PushQuad()" "2679": "Investigate our 0 ID issue" "2771": "Eliminate the union from asset" "2789": "Run the game without asserting" "2795": "Abandon the union from asset, documenting this" "2889": "Determine to add assets to the hash table and verify the need to size the table by a prime number" "3025": "Begin to add assets to the hash table, replacing SetAssetType() with AddAssetToHash() and RemoveAssetFromHash(), and removing FirstAssetOfType from game_assets" "3318": "Introduce GetAssetHashSlot() and GetAssetHashSlotFrom(), and implement AddAssetToHash() and RemoveAssetFromHash()" "3856": "Remove MatchAnyFlags from asset" "4038": "What is your vim colorscheme?" "4062": "Set up to enable AllocateGameAssets() to set the AssetHash, removing GetAssetHashSlotFrom()" "4317": "Consider removing Tags from the hha_header" "4393": "Enable AddAssetToHash() to rebuild the asset's TagHash" "4958": "Fix compile errors and remove GetVariantCount()" "5020": "Enable UpdateSingleAssetMetadata() to report errors" "5091": "Run the game with more success than expected" "5132": "Consider this to be an order-dependency problem" "5322": "Trim down the specificity of the orphanage asset tags in base_game.hht" "5341": "Prevent GenerateRoom() from adding the "manmade" tag" "5367": "Still see no wall textures" "5446": "Try to Reload HHTs, to no effect" "5539": "Investigate our apparent asset matching error" "5641": "Try unsuccessfully to break in to UpdateAndRenderEntities()" "5779": "Did you get a later version of VS? If so, need 0.3.1.3 or later" "5786": "Update remedybg to 0.3.1.4" "5881": "Break in to UpdateAndRenderEntities()" "5964": "Inspect the Asset values for a ground cube" "6073": "remedybg feature request: Get enum name from integer value" "6113": "Continue to decrypt our cube asset tag hash" "6219": "Note that our grass assets work" "6296": "Traverse the untextured orphanage in -O2" "6353": "Change GenerateRoom() to use the Asset_Block tag for cubes, inspired by GenerateApron()" "6410": "See our wall and floor textures, but no bodies and heads or lighting" "6462": "Relaunch without triggering the lighting bug" "6513": "Begin to investigate our bodies / heads bug" "6698": "Consider removing Tag_BasicCategory" "6791": "Step in to AddPlayer() and inspect the HeroTags" "7007": "See the glove, with facing direction mostly working" "7057": "Seek the player asset files for clues" "7093": "Prevent ImportBody() from adding Tag_Idle" "7226": "See the body" "7253": "Prevent ImportHead() from adding Tag_Idle" "7272": "See the head" "7286": "Trigger the load-time lighting bug" "7335": "Investigate our orphan assets bug" "7539": "Break in to AddOrphan() and inspect the asset tags" "7711": "Q&A" "7733": "Q: Hi, I'm waiting for your Star Code Galaxy, but meanwhile, reading K&R. Do you think I should be able to solve all exercises one by one or I could skip them and continue with the text and get back to them later? For example, before chapter one there's an exercise to remove comments from a C program and I'm having trouble to solve it at this stage. Thank you" "7847": "Q: Do you think that (possibly optional) memory safety features are desirable to have in languages? Or should it be the programmer's job?" "8050": "Would you like to participate in our regular competition for JavaScript and TypeScript developers? Prize fund: $100" "8132": "Q: Do you think that using void * as some blank is data good practice? For example, if you have a somewhat generic struct called item, and then based on what item type it is its void * data points to a different struct that describes that item type" "8398": "Q: Do game engines use a common library to import assets from, say, Maya / Blender?" "8510": "Q: Watched your design chat with Jon, which was really cool. Are you moving into designing the gameplay of Handmade Hero?" "8547": "Q: If I wanted to make a game with a modding interface or a lot of items, how should I go about it? In both cases union-based polymorphism that you just described don't seem the best solution" "8694": "Q: Do you recommend reading a book about Win32 API to begin the course (like Petzold's)?" "8707": "Q: Do you already have something on your agenda after you finish Handmade Hero?" "8747": "That looks like about it, with a glimpse into the future cleaning the asset system" "8799": "Plug the Episode Guide" --- name: "day623" title: "Investigating a Lighting Bug" markers: "1": "Recap and set the stage for the day" "82": "Reacquaint ourselves with the lighting bug" "131": "The lighting works in -Od" "161": "Check out the lighting and asset bugs manifested in -O2" "260": "Investigate the monstar asset absence" "436": "Make PlaceSnake() add the Undead tag" "452": "Our monstar's head asset now appears" "491": "Our downward-facing asset direction is not working" "549": "Refamiliarise ourselves with the facing direction code in GetAsetFrom()" "690": "We are unexpectedly in power mode" "735": "handmade_hero Hahaha sorry, probably a bug. You can disallow it if you want to turn it off" "808": "Continue to reacquaint ourselves with GetAssetFrom()" "924": "Make GetAssetFrom() set D1 equal to D0" "947": "See no difference in the asset picking" "993": "Remove the tag range mapping from GetAssetFrom() and game_assets" "1063": "Our asset picking is still fine" "1075": "False alarm with our tau-based facing direction computation" "1269": "4coder feature request: Line overflow indicators" "1291": "Plug the circle stuff in Star Code Galaxy" "1308": "Map the facing direction to 0–1 when adding the asset tags" "1494": "Change base_game.hht to try and trigger a rebuild" "1503": "Run the game" "1516": "Make UpdateAndRenderEntities() import the facing directions in the correct tau space" "1545": "Our facing directions are now remapped, still without downward" "1569": "Pushing Alt provokes a flash" "1612": "Reacquaint ourselves with the facing directions art" "1677": "handmade_hero There are some "big" codegen bug reported and fixed lately" "1693": "Consider our possible problems causing the downward facing bug" "1860": "The downward facing bug exists in -Od" "1888": "Add a BreakHere in UpdateAndRenderEntities() for facing direction > 0.6" "1931": "Try to break in to UpdateAndRenderEntities()" "2010": "Then they broke old vs new version ability to debug programs because they fucked the pdb somehow. That has been fixed in preview 4 after I reported it" "2026": "A few words on not updating MSVC" "2050": "This one seems like a RemedyBG bug. Probably not MSVC this time!" "2071": "Should be able to, yes" "2089": "Update RemedyBG to v0.3.3.3" "2359": "Try unsuccessfully to break in to UpdateAndRenderEntities()" "2403": "Try adding a __debugbreak() in UpdateAndRenderEntities()" "2448": "Weird things are happening, and the __debugbreak() did not trigger" "2493": "Add a more general __debugbreak() in UpdateAndRenderEntities()" "2504": "Successfully break in to UpdateAndRenderEntities()" "2524": "Investigate our settings of FacingDirection" "2611": "Our orphans are not drawn" "2653": "PlaceOrphan() sets FacingDirection to 0.75*Tau32, and ExecuteBrainHero() uses ATan2()" "2808": "Make UpdateAndRenderEntities() shift negative facing directions to the 0.5–1.0 range" "2930": "Our hero's downward facing direction now works" "2969": "Investigate our orphan absence" "3166": "Tag the orphan bodies in line with the heads in base_game.hht" "3295": "Our orphans are back, but facing the wrong direction" "3438": "See if our orphans' facing direction may be overwritten" "3674": "Break in to PlaceOrphan()" "3750": "Add a __debugbreak() in UpdateAndRenderEntities() if Facing > 0.5" "3791": "Break in to UpdateAndRenderEntities() on Facing > 0.5" "3843": "Break in to PlaceOrphan() and add a data break point on FacingDirection" "3912": "Recall the Clear in entity" "3944": "Our orphan's original entity memory is being reclaimed" "4005": "Consult EnsureRegionIsUnpacked() for bugs" "4071": "Each orphan is not a full entity, but a gen_entity" "4246": "Fix GenerateRoom() to copy the FacingDirection of pending entities" "4300": "Break in to UpdateAndRenderEntities() on Facing > 0.5" "4358": "Check out our orphans in -O2" "4406": "Align our orphans' head and body" "4988": "Our lighting now appears to work in -O2" "5092": "Provoke our lighting bug" "5227": "Q: If I remember correctly, this bug was introduced when you added the fade on load. Maybe it's a race condition with that on-load fade?" "5252": "Traverse the orphanage" "5299": "Scour the entity system for our lighting bug" "5416": "Scour the lighting system itself for our bug" "5596": "Make UpdateLighting() single-thread the lighting" "5604": "Provoke our lighting bug single-threaded" "5704": "insobot feature request: Auto-timeout on mentioning rust" "5730": "Continue to investigate our lighting bug" "5912": "Introduce ValidateAtlas()" "6273": "Trigger ValidateAtlas()" "6306": "Change ValidateAtlas() to return a bool, so that UpdateLighting() may continue despite invalidation" "6540": "Our SpecValid and DiffuseValid values do not align with the actual bug" "6562": "Why our validation and the bug may not align: 1) Too tight bounds; 2) Invalid values that don't normally contaminate things" "6603": "Widen the bounds in ValidateTexelComponent()" "6624": "Our lighting atlases still fail validation" "6702": "Tighten the bounds in ValidateTexelComponent()" "6717": "Watch our lighting validation" "6815": "Our intro cutscene doesn't work" "6865": "Q&A" "6913": "Q: Do you render the computed light bounces into a texture?" "7131": "Q: Do you ever suffer from decision paralysis when making a new feature?" "7268": "Q: When do you plan on releasing Star Code Galaxy?" "7274": "Q: Was the bug mostly in the start area? Once you start walking it was better" "7292": "Q: For the breakpoint at handmade_entity.cpp line 295 I believe what we were seeing was that the DLL wasn't yet loaded and the breakpoint wasn't yet resolved (hence the "?" icon). I think letting Handmade Hero run will eventually resolve the breakpoint and hit it. At least that is what I'm seeing here" "7324": "Break successfully in to UpdateAndRenderEntities()" "7369": "Q: Can you please go into more detail about the lighting floating point and cache inefficiency?" "7487": "Q: What is the best game sound track you have ever listened to?" "7546": "Q: Hey, you mentioned programs used to debug port usage. Could you name some, so I can check them out? Also, can you explain execution port "notation" on uops, e.g. 1*p06 for CMOVL (conditional move)? Thanks!" "7575": "Understanding uops.info" "7972": "Understanding uops analysis in Compiler Explorer" "8343": "Example loop uops analysis in Compiler Explorer" "8818": "Q: Has to be inside the scope" "8842": "Example manual goto loop uops analysis in Compiler Explorer" "9541": "Q: So what tool do you use on your projects? IACA?" "9600": "Looks like there's an open-source tool called OSACA that's meant to be a replacement for IACA" "9682": "Wrap it up" --- name: "day624" title: "Turns Out It Really WAS a Feature" markers: "3": "Recap and set the stage for the day" "59": "Try to provoke our lighting bug" "127": "See our "value contamination" lighting bug" "194": "Demo the cutscene asset finding bug" "230": "Reacquaint ourselves with the cutscene asset picking code" "339": "Fix RenderLayeredScene() to use the Tag_IntroCutscene" "355": "Our cutscene now plays fine" "441": "Who did this art!!!" "451": "Cutscene, continued" "523": "Are you in Texas?" "529": "Cutscene, continued" "568": "I stopped programming two years ago so I haven't watched for a long time, but I still have so much respect for your work" "571": "Consider the cutscene good" "593": "We don't have trees, but we do have an unaligned baby in the garden" "617": "Align the baby" "683": "We need our trees back" "743": "Investigate our trees absence" "876": "Fix GetTreeTags() to use the Tag_Tree" "915": "Our trees are back" "961": "Scale and position the trees" "1062": "Restart with proper trees" "1128": "Move on to our lighting bug" "1383": "Make ValidateTexelComponent() consider values less than −0.1 invalid" "1485": "Invalid values with apparently working lighting" "1546": "Add a break line in ValidateTexelComponent() and compile in -Od" "1606": "Try to break in to ValidateTexelComponent()" "1624": "remedybg bug: Breakpoint failure despite fully loaded .dll" "1791": "remedybg bug: Duplicate file loading" "1884": "remedybg bug due to Microsoft change: C:\ baked in to paths in .pdb, breaking subst drives" "1995": "Add our breakpoint in ValidateTexelComponent() but never hit it in -Od" "2094": "Resize the window and pick up a snake head partner" "2128": "Compiling with /fp:fast on release?" "2165": "Realise that we've gathered the snake head" "2320": "Investigate the gathering of our snake head, breaking in to ExecuteBrain() and ExecuteBrainHero()" "2658": "AddPlayer() does not use the head (to associate a hat)" "2788": "Break in to ExecuteBrainHero() to see the Head containing multiple pieces" "2858": "Investigate this as an improper entity initialisation problem" "3136": "ClearWorldEntityBlock() does not clear, but CreateEntity() does" "3252": "Hunt for clues as to how we gathered the snake head" "3423": "AddBrain() increments the World->LastUsedEntityStorageIndex" "3465": "CheckForJoiningPlayers() sets BrainID to ReservedBrainID_FirstHero + ControllerIndex" "3547": "dukedoHand" "3555": "I was on reddit" "3579": "The snake gets the controller's brain ID" "3587": "I'm guessing you're using a new brain index instead of a reserved one" "3605": "Reacquaint ourselves with the ReservedBrainID_ values and usage" "3895": "Chat didn't find the bug because there is no bug, obviously" "3921": "Continue to investigate our snake head gathering bug" "4024": "RegisterEntity() does not check slot usage" "4559": "The snake head's tBob, dtBob and ddtBob are FLT_MIN" "4740": "AddSnake() is the only running function that sets HitPointMax to 3" "4926": "Step in to AddSnake() and inspect the BrainID" "5024": "Investigate this as a post-initialisation corruption bug" "5203": "Scour CheckForJoiningPlayers() for possible problems" "5292": "It was a feature all along?" "5365": "Try out our snake head collection feature" "5474": "Make AddPlayer() create the Head as an associable entity" "5574": "Try out our nearby head swapping feature" "5657": "Make ExecuteBrainHero() position the Head nearer the Body" "5713": "Our head has a Z-offset and disappears when moving left" "5748": "Make ExecuteBrainHero() decrease the clutch offset" "5777": "Try out our closer clutch" "5783": "Make ExecuteBrainHero() raise the head" "5806": "Try making ExecuteBrainHero() set the Head's position to match the Body's" "5815": "The head no longer disappears" "5832": "Check the ddP computation in ExecuteBrainHero()" "6092": "Try making ExecuteBrainHero() use ConHero->ddP in the Head->P computation" "6119": "Our head disappears" "6122": "Try making ExecuteBrainHero() use the left-facing (−1, 0, 0) values always" "6147": "The head is always missing" "6154": "Try making ExecuteBrainHero() use the right-facing (1, 0, 0) values always" "6159": "The head is always visible" "6161": "Continue to consider our head disappearance" "6198": "Meow" "6302": "Investigate this as a downstream computation problem" "6463": "Make ExecuteBrainHero() use the left-facing (−1, 0, 0) values, and #if 0 out all Head->P related code" "6534": "The head has returned" "6546": "Reintroduce the ddP computation code" "6554": "The head remains" "6558": "Focus on the HeadDelta" "6601": "Let ExecuteBrainHero() use the computed ddP for the Head->P" "6615": "The head remains" "6622": "Let ExecuteBrainHero() use the HeadDelta" "6678": "The head disappears" "6684": "Comment out the Body->FloorDisplace setting in ExecuteBrainHero()" "6689": "The head disappears" "6692": "Instead comment out the Body->YAxis setting in ExecuteBrainHero()" "6696": "The head remains" "6702": "Investigate our problem in the Body->YAxis" "6797": "Try making ExecuteBrainHero() set Body->YAxis to (0, 1)" "6805": "The head remains" "6815": "Remove Body->YAxis" "6820": "Reacquaint ourselves with the Entity->FloorDisplace usage" "6839": "Consider the Entity->FloorDisplace to be fine" "6843": "Try out conversations and swappable heads" "6926": "Q&A" "6980": ""It's not a bug, it's a feature"" "7006": "What's your Windows coding environment? Is it Vim inside mingw?" "7017": "Q: The Linux branch has the debug / release bug as well, and it triggers all the time on my setup at least" "7037": "Yes, it is a Q&A request in Day 290" "7072": "Q: Looks like MSVC is writing the subst'd drive to the PDB as long as you build from the subst drive (as one would expect). Does building from 4coder somehow change to the C: drive before building or something like this? In any case, will make RemedyBG more resilient to these sorts of things! Thank you!" "7120": "handmade_hero There is something wrong with capturing 4coder. The screen gets very busy, which is distracting. I saw it last week too, but we thought it might be on my side. It also shows on the YouTube upload of last week's episode. The older YouTube uploads are clean…" "7334": "Q: Someone asked if the swap would work on the orphans as well?" "7373": "Might help if you go black background for the time being. It did not show on your black cmd window" "7447": "I would rather blame twitch encoding than your machine" "7557": "Q: Handmade Hero is running for a while by now. Is there any scheduled ending? I'm at episode 308 and I love the series" "7587": "Thank you, everyone" --- name: "day625" title: "Fixing the "Lighting" Bug" markers: "0": "Welcome to the stream" "21": "Look into our incorrect usage of _mm_blendv_ps() in the f32 version of SignOf()" "419": "Fix the f32 SignOf() in SIMD" "683": "Hunt in vain for SignOrZero()" "858": "Determine to look at octahedral code to see if we're using SignOf() as SignOrZero()" "897": "Fix compile errors in SignOf()" "916": "Double-check our SignOf()" "995": "Update the f32_4x SignOf()" "1193": "Traverse the orphanage, and successfully provoke our lighting bug" "1412": "Exhibit our lighting bug localised" "1427": "Consider a possible lighting quality improvement" "1516": "Determine to investigate our lighting bug" "1553": "Try to provoke our lighting bug in -Od" "1663": "In -O2 our SpecValid and DiffuseValid values start at 0" "1691": "Introduce ValidateTexel() and make BlockCopyAtlas() assert with ValidateAtlas()" "1877": "Hit our top ValidateAtlas() assertion in BlockCopyAtlas()" "1966": "Make SetLightAtlasTexels() assert with ValidateAtlas()" "1984": "Never hit our assertion in SetLightAtlasTexels()" "2011": "Use LIGHT_ATLAS_ASSERT() for our assertions" "2041": "Hit none of our assertions" "2055": "Try replacing LIGHT_ATLAS_ASSERT() with Assert() in BlockCopyAtlas()" "2089": "Hit our ValidateAtlas() assertion in BlockCopyAtlas()" "2095": "Replace Assert() with LIGHT_ATLAS_ASSERT() in BlockCopyAtlas()" "2106": "Hit our ValidateAtlas() assertion in BlockCopyAtlas()" "2130": "Describe our method for zeroing in on a bug, lacking a theory as to its source" "2260": "Plan our lighting map validation" "2408": "Make ComputeLightPropagationWork() assert with ValidateAtlas()" "2480": "Hit our DiffuseAtlas assertion in ComputeLightPropagationWork() after FullCast()" "2527": "Remove our ValidateAtlas() calls" "2554": "Focus our lighting map validation on FullCast()" "2693": "Consult the chat for Japanese speakers" "2712": "Bikkuri shita!" "2731": "I mean it's 5:30 am in Japan" "2755": "handmade_hero How good is your Japanese?" "2767": "Request a link to Mr Yabatan making a hotpot, with his Dad on the phone" "2826": "Foreigner meets Ramen 🍜 ラーメンで興奮する外国人!" "2891": "handmade_hero Talking about this?" "2922": "Add ValidateAtlas() assertions in FullCast()" "2993": "Hit our bottom SpecAtlas ValidateAtlas() assertion in FullCast()" "3016": "Disable multithreading" "3114": "Try and hit our assertion in FullCast()" "3131": "I just checked the octrahedral paper. It uses signNotZero()" "3162": "We hit our assertion in FullCast() single-threaded" "3169": "Focus our lighting map validation on GridRayCast()" "3359": "Request a reminder from chat to rerun the sphere generator" "3382": "Make GridRayCast() assert with ValidateTexel()" "3436": "Hit our bottom 6th SpecAtlas ValidateTexel() assertion in GridRayCast()()" "3484": "Fail to hit our assertion in -Od" "3524": "Fail to hit our assertion in -O2, until hitting it on the bottom 7th SpecAtlas texel" "3586": "Wonder if TransferPPS never gets initialised, causing our negative lighting values" "3715": "Make GridRayCast() initialise TransferPPS" "3733": "Hit our bottom 7th SpecAtlas ValidateTexel() assertion in GridRayCast()" "3747": "Scrutinise the TransferPPS values in GridRayCast()" "3888": "Make GridRayCast() assert TransferPPS with ValidateTexel()" "3922": "Hit our 1st TransferPPS ValidateTexel() assertion in GridRayCast()" "3955": "Make GridRayCast() assert TransferPPS with ValidateTexel() upon setting it" "3995": "Exhibit our lighting bug without hitting an assertion, before hitting the TransferPPS one" "4062": "Scrutinise our TransferPPS computation in GridRayCast()" "4201": "Try to make GridRayCast() assert TransmissionLevel and HitRefColor with ValidateTexel()" "4250": "Scrutinise our TransmissionLevel and HitRefColor computations in GridRayCast()" "4321": "Introduce an f32_4x version of ValidateTexel()" "4444": "Hit our 0th HitRefColor ValidateTexel() assertion in GridRayCast()" "4474": "Scrutinise our HitRefColor computations in GridRayCast()" "4581": "Make GridRayCast() assert HitRefColor with ValidateTexel() upon initialisation" "4592": "Hit our TransferPPS ValidateTexel() assertion in GridRayCast() upon setting it" "4619": "Make GridRayCast() assert HitRefColor with ValidateTexel() upon setting TransferPPS" "4630": "Hit our 0th HitRefColor ValidateTexel() assertion in GridRayCast()" "4644": "Scrutinise our HitRefColor usage in GridRayCast()" "4695": "Make GridRayCast() assert Leaf.RefColor with ValidateTexel()" "4721": "Hit our 0th Leaf.RefColor ValidateTexel() assertion in GridRayCast()" "4888": "Focus our lighting map validation on GridBuildSpatialPartition()" "5031": "Make GridBuildSpatialPartition() assert Leaf.RefColor with ValidateTexel()" "5120": "Hit our 0th Leaf.RefColor ValidateTexel() assertion in GridBuildSpatialPartition()" "5123": "Make GridBuildSpatialPartition() clear the SpatialGridLeaves" "5159": "Hit our 0th Leaf.RefColor ValidateTexel() assertion in GridBuildSpatialPartition()" "5166": "Fix parentheses of ZeroArray()" "5197": "Assert in GridBuildSpatialPartition() that we are in bounds" "5258": "Do not hit our bounds-checking assertion in GridBuildSpatialPartition()" "5261": "Make GridBuildSpatialPartition() assert Leaf.RefColor with ValidateTexel() upon initialisation" "5308": "Do not hit our Leaf.RefColor initialisation assertion in GridBuildSpatialPartition()" "5312": "Make GridBuildSpatialPartition() assert Leaf.RefColor with ValidateTexel() after fill-in" "5324": "Hit our 0th Leaf.RefColor ValidateTexel() assertion in GridBuildSpatialPartition() after fill-in" "5328": "Make GridBuildSpatialPartition() assert Leaf.RefColor with ValidateTexel() around their setting" "5406": "Hit our 0th Leaf.RefColor ValidateTexel() assertion in GridBuildSpatialPartition() after setting" "5451": "Make GridBuildSpatialPartition() assert Box->RefC with ValidateTexel()" "5488": "Hit our Box->RefC ValidateTexel() assertion in GridBuildSpatialPartition()" "5540": "Focus our validation on PushCube(), PushOccluder() and PushLight()" "5757": "Hit our Box->RefC ValidateTexel() assertion in GridBuildSpatialPartition(), but none of the ones upstream" "5895": "Scrutinise our upstream Box->RefC code" "6102": "handmade_hero You are missing an assert in PushOccluder()" "6107": "Make PushCube(), PushOccluder() and PushLight() assert Box->RefC with ValidateTexel()" "6140": "Hit our Hit our ValidateAtlas() assertion in BlockCopyAtlas()" "6152": "Hit our Box->RefC ValidateTexel() assertion in PushOccluder()" "6369": "#if 0 out the Tag_Ghost indexing into MatchVector.E in UpdateAndRenderEntities()" "6490": "Try to provoke our "lighting" bug" "6596": "#define ValidateTexel() as VALIDATE_TEXEL()" "6797": "Run successfully" "6809": "Re-enable multithreading" "6824": "Run successfully" "6977": "Reflect on our indexing bug, and our pincering method for debugging" "7045": "Make VALIDATE_TEXEL() self-assert, and #define ValidateAtlas() as VALIDATE_TEXEL_ATLAS()" "7173": "Run successfully" "7188": "#define out LIGHT_ATLAS_ASSERT()" "7193": "Run successfully" "7218": "Determine to improve the lighting filtering" "7248": "Compile and invoke hhsphere" "7385": "Rebuild and run the game" "7445": "Make UpdateLighting() decrease tUpdateBlend from 8/60 to 1/60" "7488": "Our lighting is smoother but slower to update" "7523": "Make UpdateLighting() increase tUpdateBlend from 1/60 to 4/60" "7537": "Our lighting is quicker to update, but doesn't propagate evenly" "7582": "Q&A" "7597": "Q: Is it only me or does the lighting seem brighter with the blendv_ps fix?" "7654": "Q: Is there a way to test my GLSL shader compilation success / failure on other GPUs without actually having to buy a bunch of GPUs myself?" "7705": "Whoa. Godbolt for shaders" "7781": "There is Shader Playground but that's only for shader libraries (parser / validation / some codegen), not using actual drivers to compile" "7809": "(Viewbot #420) MrDestructoid Hello Mr. Teapot, I am here to "view" your channel as was previously discussed" "7826": "Consider lighting improvements" "7906": "Q: Are you planning to release Star Code Galaxy this year? Will this project be like a Handmade Hero where you make usage code first and everything from scratch?" "7945": "Are you in a tent?" "7958": "Q: Anyone know what browser Casey is using? I don't recognise it" "7974": "Thank you for joining" --- name: "day626" title: "Cleaning Up Traversables" markers: "0": "Welcome to the stream" "36": "Consider throwing in some gameplay stuff" "173": "Determine to add lockable doors" "290": "Note our broken transactional occupy points" "341": "Reacquaint ourselves with TransactionalOccupy()" "565": "Test transactional occupation with a snake entity" "612": "Reacquaint ourselves with tree placement in GenerateRoom()" "686": "Make GenerateRoom() set each tile to be occupied by a tree as not open" "702": "Our garden now lacks some trees" "713": "Consider this to be an entity packing / unpacking bug" "867": "Make UpdateAndRenderEntities() mark tiles by occupation" "951": "Hit a write access violation in PushCube()" "1000": "Hit an Emission assertion in PushCube()" "1014": "Make UpdateAndRenderEntities() pass an Emission value of 1.0f to PushCube()" "1024": "See our tile occupation" "1041": "Our tile occupation markers do not change colour" "1068": "Investigate this as an entity packing / unpacking bug" "1290": "Respecify entity_traversable_point to use an entity_id rather than an entity *, introducing an entity_id version of IsValid()" "1582": "Our tile occupation markers still do not change colour" "1616": "Scour the entity system for traversable preservation" "1688": "Step through TransactionalOccupy()" "1899": "Our tile occupation marker has not changed colour" "1933": "Fix UpdateAndRenderEntities() to use our "occupied" Color" "1967": "Our tile occupation markers now change colour" "1983": "Hop over to the garden, yearning for a click-and-move debug feature" "2051": "Our tree tiles are not marked as occupied" "2114": "Our hero tile is also considered unoccupied on startup" "2130": "Make GenEntityAtTraversable() call TransactionalOccupy()" "2246": "Our trees now occupy their tiles" "2279": "We have mysterious tile occupation markers" "2357": "What is this built on?" "2366": "Unity" "2383": "On the legitimacy of the question" "2409": "Windows is built on Unity" "2434": "Start to investigate our mystery occupation points" "2464": "You'd actually be surprised how many are working on their own engines / games from scratch. It's pretty encouraging" "2518": "There should be disclosure policies in place so we can specifically avoid using hard real-time systems that are written in JavaScript in the future" "2537": "Make GenEntityAtTraversable() and PlaceOrphan() use GenEntity_IsNotOccupier" "2854": "Our conversation tiles work fine, but we still have mystery occupation points" "2966": "Our plan for doors: Supporting multiple door unlocking mechanisms" "3136": "We lack a door texture" "3175": "Create a locking door entity, augmenting gen_connection with DoorFromAToB and DoorFromBToA" "3505": "Enable GenerateRoom() to create doors, using Intersect() and AddObstacle()" "3975": "Introduce GetTileAbs()" "4042": "Finish enabling GenerateRoom() to create doors" "4197": "Our orphanage is no different" "4225": "Make CreateDungeon() request a DoorFromAToB" "4261": "Our dungeon contains a door" "4343": "Disable the tile occupation markers in UpdateAndRenderEntities()" "4350": "Plan to sink the doors into the floors next time" "4366": "Q&A" "4408": "handmade_hero Here's a hot question live off the press: Stack Overflow says you must use smart pointers. The Handmade Hero codebase has no smart pointers, how can this be?!" "4442": "Programmer stages of mental development wrt architecture" "4483": "Programmer stages of mental development wrt architecture: n) individual element thinking / architecture" "4680": "Programmer stages of mental development wrt architecture: n+1) grouped element thinking" "5084": "handmade_hero The good of having to learn the Handmade Hero codebase is that the use of internal imposes the inability to use the STL as it is there too defined and broke the compilation. So is the reason why we skip C++ badness" "5111": "n+2 is when you reached guru stage after 30 years and your code finally "looks" as simple as written by someone at n-3 stage, but it is free of all the BS" "5283": "Q: If you look at the old id code (Wolf3D, Doom, Quake, ...) there they already think of large groups when it comes to memory or at least they allocate just once (for the most part) and then go with it. Then why did we go "backwards"? n) is what I was taught at university from Professors who were around at the "Doom" time. What happened?" "5419": "Nowadays, engineers aren't engineers" "5462": "Maybe people like Carmack (and you) should be more vocal. Now it's the mediocre guys shouting and the gurus keeping quiet. How are we supposed to learn?" "5542": "Q: Does this stuff apply to game engine programming only or also to corporate logistics (crud)?" "5589": "I really appreciate the way that you presented that. Matches my first response to auto_ptr but I couldn't express the rationale as well. Also why I like C, because you have more pressure to think in the n+1 way" "5937": "Example of transitioning from n to n+1: Character creation in Granny" "6133": "Designing out memory allocation failure bugs by creating a "working" stub arena" "6208": "Q: A lot of your n category seems to cover error handling. Are you concerned at all with any secure coding concepts to cover undefined behavior with people looking to exploit it?" "6312": "Growable arenas and failure handling" "6418": "Q: Let's say I want to push some dynamic amount of data, and I run out of space. The calling code expects N bytes, and will write N bytes, but I don't have N bytes. How do you handle this case in that style?" "6530": "Programmer stages of mental development wrt architecture: n+2?) ZII" "6620": "Is a repeat mapped page an OS thing, or is that something custom?" "6709": "Q: Have you read the paper Fast Efficient Fixed-Size Memory Pool No Loops and No Overhead by Ben Kenwright?" "6751": "Q: So all of the code has a check to see if the struct is a stub and doesn't do anything?" "6827": "Q: Could you quickly take a look at the paper?" "7210": "handmade_hero Are you familiar with Richard Fabian's Data-Oriented Design book? He's an advocate of laying out data in normalized form, and representing relationships between entities in tables, much like a relational database though not literally SQL of course" "7332": "On publishing papers on known knowledge" "7427": "In related works it does say "On the other hand, the technique we present here is not novel, but is a modification of an existing technique"" "7529": "Q: Could you explain about ECC memory?" "7705": "handmade_hero It's called Hamming codes. It can correct single bit flips, and detect two bit flips. It's all done in very simple hardware. Ben Eater and 3blue1brown have very good videos on the topic" "7727": "Q: In Handmade Hero, do you align the elements you put into the arena? Someone told me that nowadays on desktop CPUs the alignment for read / write is not as important but it is probably better to get as many things into a cache line as possible" "7905": "Q: Can hyperthreading cause false sharing?" "7955": "handmade_hero Did you ever have any problems with your back sitting all day long, or you just buy an expensive chair and all problems go away?" "8024": "Plug the Space Series Mesh Back Task Chair" "8082": "We are good to go" --- name: "day627" title: "Opening Doors with Tiles" markers: "2": "Welcome to the stream" "65": "Traverse the orphanage to our new dungeon door" "209": "Our plan for doors: Q*bert style light-up tiles that unlock doors" "241": "Light-up tile logic" "410": "Create light-up door switch tiles, introducing brain_switches for brain_type to contain" "640": "Introduce ExecuteBrainSwitches()" "1482": "Augment entity_traversable_point with a PrevOccupier for TransactionalOccupy() to set" "1998": "Traverse the orphanage" "2015": "Make ExecuteBrainSwitches() call TransactionalOccupy(), and handle switch state" "2211": "Rename IsEqual() to AreEqual()" "2302": "Make ExecuteBrainSwitches() depress the switches" "2346": "Make GenerateRoom() initialise a RoomSwitchBrain using AddBrain()" "2825": "Our large garden lacks a colourised tile" "2969": "Step into our tile colourisation path in GenerateRoom()" "3017": "Large orphanage rooms contain a colourised tile" "3051": "Make GenerateRoom() colourise our test tile faintly and add a room switch on it" "3252": "Hit a read access violation upon occupying our test switch" "3282": "Make ExecuteBrainSwitches() colourise occupied switches" "3425": "Traverse the orphanage" "3466": "Make ExecuteBrainSwitches() only process occupation for a valid Unlock" "3486": "Our switches toggle on, but the snakes can also toggle (and get trapped on) them" "3625": "Check the door creation logic in GenerateRoom()" "3787": "Doors open before we've landed on their switch" "3841": "Make GenerateRoom() create more test door switches" "3917": "Our squares of switches work great" "4002": "Make ExecuteBrainSwitches() spring the switches back up (but remain lit) when their occupier departs" "4110": "Our switches spring back up after occupation" "4138": "Possibly flawed door unlocking when a door and its switches aren't in the same sim region" "4212": "Make ExecuteBrainSwitches() only partially submerge opened doors and unlock them once" "4313": "We do have an already opened door" "4403": "Consider how to make brains work across sim regions" "4517": "Add a GenEntity_IsSwitch and introduce PlaceTilePattern() for GenerateRoom() to use" "4853": "Our door switches now don't fully work" "4965": "Make PlaceTilePattern() chain switch tiles together" "5238": "Hit our assertion in Layout()" "5266": "Make PlaceTilePattern() produce fewer switch tiles" "5289": "Hit our assertion in Layout()" "5302": "Step through PlaceRoomAlongEdge()" "5360": "Temporarily compile out PlaceTilePattern()" "5369": "Do not hit that assertion in Layout()" "5409": "Investigate our assertion hit in Layout()" "5729": "Prevent PlaceTilePattern() from using Entropy" "5752": "No longer hit that assertion in Layout(), but now hit the Query.Found one in GenerateRoom()" "5775": "Inspect our EntityGroup" "5818": "Investigate our Query.Found assertion hit in GenerateRoom()" "6001": "Step in to PlaceTilePattern() and watch AllowedDirectionsForNext" "6106": "Make PlaceTilePattern() set AllowedDirectionsForNext for every Tile" "6122": "No longer hit that Query.Found assertion in GenerateRoom()" "6141": "Our chained switches now work" "6190": "Plan to turn the switch chains into a list" "6228": "Q: Is it worth having the renderer check if it’s running in debug mode or not, and dropping the number of lighting samples to make it more playable? Or is having code behave differently in debug and release modes a bad idea? (I know we’re not in Q&A yet, but I've gotta bounce)" "6304": "Q: Why is MSVC's #pragma optimize("something", on/off) on that file hard?" "6348": "Q: So if I am following you correctly, this door / switch stuff only allows for switches to trigger doors that are in the same room, or can this work for triggering things in other / multiple rooms, etc?" "6484": "Could you turn it on then wrap the entire compilation unit in a pragma (turning it off) then turn it on when you need it?" "6552": "Thank you, everyone" --- name: "day628" title: "Brains and Aprons" markers: "1": "Recap and set the stage for the day" "61": "The brain system's multi-component entity construction per frame" "346": "Set up the lightboard" "532": "Brains and Aprons" "716": "Partial gather of multi-component entities" "914": "Entity activation beyond the sim-region" "1123": "Return to the keyboard" "1161": "Q: You were great and the light board is still magic" "1175": "Wait, why have more than one brain?" "1255": "Augment brain with an Active boolean for MarkBrainActives() to set and Simulate() to use" "1334": "We already have an opened door" "1463": "Comment out PlaceSnake() in CreateDungeon()" "1480": "Our snakes are gone, but we have a placed door that lacks tiles" "1574": "Change CreateDungeon() to pass the PrevRoom to PlaceTilePattern()" "1611": "Our door tiles are now placed correctly, but a placed door still lacks tiles" "1709": "Break in to the SwitchesSet branch of ExecuteBrainSwitches()" "1874": "Hit our breakpoint erroneously and inspect the Switches" "1940": "Check our use of EntityFlag_Active and UpdatableBounds" "2151": "Meow" "2218": "Determine to expand the UpdatableBounds" "2260": "*clambers*" "2287": "Determine to draw the sim region and apron" "2424": "*makes a decision*" "2463": "Eyeball the broken door paging in using the debug camera" "2609": "Make BeginWorldChange() expand the SimRegion->Bounds using AddRadiusTo()" "2835": "Our broken door is now fixed" "2956": "Augment game_mode_world with a StandardApronRadius for CreateWorld() to set" "3423": "Our doors work well" "3544": "Remove "TODO(casey): If entities were stored in the world, we wouldn't need the game state here!" from BeginWorldChange()" "3572": "Wasn't the TODO there actually describing the bug?" "3611": "handmade_world_mode.cpp around l300" "3657": "Remove "TODO(casey): There are risks to allowing the simulation region to be determined by the camera, because of the way we use "brains" where logical entity collections can be split by a simulation boundary" from UpdateAndRenderWorld()" "3683": "Re-enable PlaceSnake() in CreateDungeon(), and make it add a brain and body segments" "3934": "Augment gen_entity with a BrainID and BrainSlot for the entity generation functions to set" "4950": "Replace the brain_id values with gen_room_connection pointers in gen_connection, and augment gen_room_connection with a brain_id DoorBrainID" "5202": "Hit a null-pointer dereference" "5276": "Assert in GenerateRoom() that PendingEntity->Creator is not 0" "5374": "Hit that assertion in GenerateRoom()" "5408": "Make PlaceSnake() pass AddSnakeBody to AddEntity()" "5422": "Run successfully" "5465": "Our snakes have bodies but no assets, and our switches can fail to spring back up" "5573": "Fix PlaceSnake() to add Tags to the segments" "5643": "Our snake segments have assets but incorrect facing direction" "5707": "Introduce ExecuteBrainSnake() and make it set the segments' FacingDirection" "6038": "Our snake segments now face the correct direction" "6131": "Q&A" --- name: "day629" title: "Removing Entity Generators" markers: "2": "Recap and set the stage for the day" "59": "Plan to optionally start the player in the dungeon" "248": "Try making CreateWorld() set StartRoom to the Dungeon.EntranceRoom" "287": "We didn't start in the dungeon" "309": "Make CreateWorld() set HeroRoom to the Dungeon.EntranceRoom->Vol" "348": "We start in the dungeon" "367": "Plan to place the door switch tiles in interesting formations" "612": "Begin to introduce gen_entity_pattern" "774": "Consider replacing entity creators with custom-written pattern generators" "958": "Remove gen_entity_pattern" "962": "Plan to remove entity generators" "1080": "Introduce GEN_CREATE_ENTITY_PATTERN() as a function creator" "1198": "Introduce an AddCat GEN_CREATE_ENTITY_PATTERN, and remove the old GEN_CREATE_ENTITY" "1503": "Remove GEN_CREATE_ENTITY and get_entity_tag_builder" "1628": "Make gen_create_pattern a function pointer in gen_entity, and remove unneeded values" "1763": "Change all the GEN_CREATE_ENTITY() functions to be regular functions" "1933": "Respecify the GenEntityAt*() functions as PlaceEntityAt*() and introduce PlaceEntityOnTraversable()" "2113": "Replace PlaceSnake(), AddSnakeHead() and AddSnakeBody() with an AddSnake GEN_CREATE_ENTITY_PATTERN" "2587": "Augment gen_entity with an asset_tag_hash for AddSnake to set" "2660": "Make CreateDungeon() call AddPattern(), renaming AddSnake to SnakePattern" "2861": "Consider ending up with gen_create_pattern as a flags field" "2960": "Introduce TileSwitchPattern and NPCPattern GEN_CREATE_ENTITY_PATTERN" "3264": "Streamline base_game.hht" "3433": "Add asset_tag_id for Molly, Fred and Hannah" "3548": "Remove RecursiveOpenTileSearch(), FindPlaceToPutEntityGroup(), GetPieceAsset() and ChangeHash()" "4086": "Implement TileSwitchPattern" "4251": "Implement NPCPattern" "4491": "Respecify AddEntity() as AddPattern(), and remove AddTag() and AppendEntity()" "4571": "Weld gen_entity in to gen_entity_group as gen_entity_pattern" "4903": "Introduce AddTree() and replace GetTreeTags()" "5192": "Port the Lamp and Door creation code" "5606": "Port the pattern creator dispatch loop" "5696": "Port the apron and tree placement code in GenerateApron()" "5771": "Consider pattern placement" "5841": "Spec out pattern placement in SnakePattern, NPCPattern and TileSwitchPattern" "6368": "Introduce FindRandomOpenTile() and FindAdjacentOpenTile()" "7980": "Hit our Contents assertion in GenerateRoom()" "8039": "Mark TraversableIsOpen() as NotImplemented" "8137": "GenerateRoom() is indexing beyond the extent of the tile's Y dimension" "8179": "Fix Advance() to work in X and Y (not Z)" "8207": "Hit our NotImplemented marker in TraversableIsOpen()" "8210": "Implement TraversableIsOpen()" "8375": "Hit our assertion in GetTraversable()" "8430": "Fix TraversableIsOpen() to require a TraversableCount" "8468": "We generated a lot of actual stuff" "8533": "Scan FindAdjacentOpenTile() for bugs" "8590": "Step through FindAdjacentOpenTile()" "8711": "Consider TileSwitchPattern to be doing what we've told it to" "8777": "Fix AddPlayer() to use our stripped down set of tags" "8809": "Our stone walls are broken" "8839": "Make CreateWorld() start the hero in the bedroom" "8910": "Our orphans work, but the conversation tile is considered occupied" "8935": "Fix the edit_tile version of PlaceEntityAtTraversable() to call its namesake" "8945": "Our conversation tiles are unoccupied again" "8965": "Set the cats' asset alignment points" "9287": "Introduce a StandardLightingPattern GEN_CREATE_ENTITY_PATTERN" "9545": "Our orphanage lacks light" "9562": "Make CreateDungeon() use our StandardLightingPattern" "9634": "Our dungeon is spectacularly lit" "9712": "Make CreateOrphanage() use our StandardLightingPattern" "9815": "Our orphanage is lit" "9840": "Spec out a light spacing rule in StandardLightingPattern, enabling Advance() to operate on passed Base and dGrid parameters, and introducing CalcBasePForOffset()" "10232": "Crash in GetSimSpaceTraversable()" "10247": "Fix StandardLightingPattern to use a newly introduced version of PlaceEntityAtP() that takes an edit_tile" "10347": "Our orphanage is well lit" "10381": "Make StandardLightingPattern decrease the light intensity" "10395": "Our orphanage is better lit" "10430": "Make UpdateAndRenderEntities() draw the lights" "10512": "Our lights are well distributed" "10595": "Remove the snake segment lights" "10654": "Start to make CalcBasePForOffset() work from the centre" "10787": "Introduce AddBlock() for GenerateRoom() to use for doors" "11386": "Our doors remain invisible" "11407": "Make CreateWorld() set HeroRoom to the Dungeon.EntranceRoom->Vol" "11425": "We start in the dungeon" "11441": "Scan AddBlock() for bugs" "11491": "Our door is placed, just invisible" "11604": "Try making GenerateRoom() pass Tag_Floor to AddBlock()" "11613": "Our door is placed and visible" "11631": "Make GenerateRoom() set the DoorDim" "11768": "Our doors are visible and operable" "11809": "Make ExecuteBrainSwitches() move unlocked doors further into the floor" "11831": "Our doors drop fully into the floor" "11881": "Q&A" "11913": "handmade_hero Maybe it could actually be a gameplay feature for the door movement to obscure the tiles one floor down?" "11932": "Q: When plopping down furniture / props do you want to allow for pattern variations, e.g. desk above, chair below desk, lamp on the right? But another pattern on a side wall would require a completely different arrangement" "11969": "Q: Can you explain again why only one switch is being added to a room?" "12024": "Q: You were talking about switching bodies vs switching heads. Would you be able to switch to have a snake / cat / bird / dragon body? That would be pretty cool, especially if it was required to accomplish something later in the game, like using the snake body to press down on multiple adjacent buttons at the same time" "12125": "Q: Will you add normal maps to sprites for lighting effects?" "12140": "Q: Are you intending for it to be a mix of hand-authored rooms and generated patterns, or pure generation?" "12172": "Q: Gameplay-wise are you going for something like needing to enter a pattern in a particular way, monsters get in the way, clearing the room makes it feasible to enter the code to unlock the door? Or are you thinking, have monsters that can't die that you need to look at their behavior and wrangle them into opening the doors for you?" "12197": "handmade_hero I've heard you say before that you don't believe it's good or necessary to know many programming languages because, in your words, "programming works from first principles". I do hear all the time, though, that you shouldn't be married to a programming language and you should always use the best language for the problem you're trying to solve. Why do you think people think this way and can you elaborate on why you disagree?" "12389": "Q: Do you find it harder to design the engine without the concrete requirements of a specific game design? I find sometimes I rathole on abstractions / generalisations I'll never end up using if I don't have a specific goal in mind" "12415": "Q: I don't know if I can ask these here, but how's Star Code Galaxy doing? When will something be available?" "12459": "Q: How do you avoid overcomplicating your code?" "12578": "Q: If I like a low level language like C, but a syntax feature like member function, what's the solution? Metaprogramming?" "12617": "Q: Yeah, I meant a feature that doesn't exist" "12657": "Plug Discord for questions on Star Code Galaxy" "12710": "Q: When someone notes "// TODO(casey)", does that mean it's a TODO casey noted or a TODO for casey to do?" "12766": "Q: Following up on the question about programming languages. A lot of people seem to think that dynamic languages are way more expressive than non-dynamic ones in the sense that you can accomplish a lot with very little code. When you say these languages are limited do you mostly mean they don't allow you to write performant code or do you mean more than that?" "13297": "handmade_hero It took me 400 lines of code to write a 2D plotting calculator in JavaScript. I don't know why it takes so much for a simple crud website though" "13413": "Thank you, everyone, with a plug of Wednesday's lecture for the University of Twente about optimising the grass and plant distribution code in The Witness" --- name: "day630" title: "Adding Interesting Tile Patterns" markers: "1": "Recap and set the stage for the day" "139": "Balancing random and hand-coded procedural generation" "360": "Demo the door pressure plates" "441": "Describe our entity pattern generator" "603": "Augment gen_entity_pattern with a Difficulty for TileSwitchPattern() to use" "849": "Discover 4coder's Index (Project)" "998": "Set up TileSwitchPattern() to generate difficulty-based patterns" "1202": "Introduce tile_pattern for TileSwitchPattern() to use" "1361": "Separate game design from engine programming" "1457": "Introduce TileAlreadyExists()" "1499": "4coder's indentation and f4_search_for_definition__project_wide" "1653": "Finish implementing TileAlreadyExists()" "1755": "Make TileSwitchPattern() generate a pattern that avoids existing tiles" "2134": "Introduce AppendTile()" "2201": "We have no tiles" "2219": "Fix the TileAlreadyExists() test in TileSwitchPattern()" "2227": "We still only get one tile" "2238": "Fix TileSwitchPattern() to pass random numbers to FindRandomOpenTile()" "2255": "We still only get one tile" "2268": "Double-check FindRandomOpenTile()" "2361": "Slightly rewrite TileAlreadyExists() for consistency and clarity" "2428": "We're still only placing one tile" "2459": "Make TileSwitchPattern() generate exactly four tiles in the lowest Difficulty case" "2471": "We generated four tiles" "2512": "Check our random number generator" "2555": "Test our random number generator in TileSwitchPattern()" "2774": "Our random number generator seems well distributed" "2794": "Decrease our random number generator test's sample count from 1000000 to 100" "2803": "Our random number generator has a touch of bias towards the second quadrant" "2849": "Increase our random number generator test's sample count from 100 to 1000" "2854": "Our random number generator seems well distributed" "2868": "Test _mm_aesdec_si128() in TileSwitchPattern()" "3156": "_mm_aesdec_si128() has a similar distribution to our generator" "3177": "Add a mixing step to our _mm_aesdec_si128() test" "3184": "_mm_aesdec_si128()'s distribution remains similar" "3196": "Decrease our _mm_aesdec_si128() test's sample count from 1000 to 100" "3208": "_mm_aesdec_si128() has a similar distribution to our generator" "3220": "Increase our _mm_aesdec_si128() test's sample count from 100 to 1000000" "3226": "_mm_aesdec_si128() remains well distributed" "3239": "Remove our prng test" "3294": "Set up TileSwitchPattern() to generate specified patterns" "3544": "Q: After stream, you should mirror webcam so you are looking at the code" "3608": "Q: Casey, I don't know if it's local to me, but I'm getting a lot of pixel flickering on the 4coder capture. Cam is fine" "3704": "On source, it's very subtle, not an issue" "3807": "Spec out the pattern rules in TileSwitchPattern()" "4217": "Create an overloaded v3s version of +=" "4290": "We have horizontal patterns" "4331": "Implement the TilePattern_Scatter case in TileSwitchPattern()" "4439": "Split out the pattern computation and generation in TileSwitchPattern()" "4539": "We have vertical patterns" "4602": "Pick the TilePattern_Snake in TileSwitchPattern()" "4619": "We have snake patterns" "4650": "Increase our Tiles.MaxCount from 4 to 8 in TileSwitchPattern()" "4660": "We have longer snake patterns" "4719": "Increase our Tiles.MaxCount from 8 to 16 in TileSwitchPattern()" "4731": "Hit our out-of-bounds assertion in RegisterEntity()" "4763": "Enlarge the Tiles array from 12 to 16 in brain_switches" "4787": "We have even longer snake patterns" "4813": "Augment tile_pattern with a RequiredEmptyNeighborCount, for TileSwitchPattern() to use in the TilePattern_Snake case" "5096": "Our snake patterns work beautifully" "5160": "Pick the TilePattern_Branching in TileSwitchPattern()" "5171": "We have branching patterns" "5190": "++SwearCount" "5211": "We need a cuss word counter in the Episode Guide" "5259": "Pick the TilePattern_Scatter in TileSwitchPattern()" "5274": "We have scatter patterns" "5282": "Increase the Tiles.RequiredEmptyNeighborCount from 3 to 4 in TileSwitchPattern()" "5288": "We have disconnected scatter patterns" "5332": "Determine to fix the stairs-to-nowhere problem, and add a light to pressure plates" "5382": "Make TileSwitchPattern() add a light to the pressure plates" "5451": "We cannot see our lights" "5472": "Make UpdateAndRenderEntities() draw the light outlines" "5489": "See our lights" "5500": "Make TileSwitchPattern() elevate the lights" "5506": "Our lights sit above our pressure plates" "5531": "Make our pressure plates light up when pressed" "5615": "Our lights are no longer there" "5721": "Double-check our pressure plate light code" "5830": "Make TileSwitchPattern() initialise the light with 5.0f Emission" "5857": "Our lights are back" "5910": "Make UpdateAndRenderEntities() keep the light Color's fourth component at 1.0f" "5988": "Our lights remain" "5992": "Try increasing the pressed light intensity from 5 to 10 in ExecuteBrainSwitches()" "6027": "Our pressure plates never light up" "6077": "Try making ExecuteBrainSwitches() operate on Pieces[2]" "6145": "Our pressure plates remain unlit" "6170": "Step on to the AddPieceLight() call in TileSwitchPattern()" "6289": "GenerateRoom() places occluders in the environment" "6371": "Fix GenerateRoom() to place occluders more sensibly" "6419": "Make ExecuteBrainSwitches() loop through the pressure plate pieces to find its light" "6542": "Hello there" "6627": "Our pressure plates light up" "6670": "Comment out AddPattern() in CreateDungeon()" "6688": "I'm back" "6711": "Our dungeon is more brightly lit than expected" "6735": "Double-check our pressure plate lights" "6758": "Our dungeon is not dark" "6820": "Restrict GenerateRoom() to generate a stairwell from a Lower to Upper floor (and not also the other way)" "6925": "Our stairwells are better placed" "6932": "Make GenerateRoom() prevent traversal under staircases" "7098": "We can't go under the stairs" "7152": "Q&A" "7225": "Audio was good" "7270": "Q: Any idea how to stop the snakes from getting stuck?" "7443": "Q: Following up on the question I asked you before… I thought about what you said, and I'm not sure I understand. I'm sending this now just so you know I'm writing the question right now" "7474": "Q: Ouroboros! How about taking the thing we want to prevent and creating a unique game feature that emerges from it, i.e. Let the snake eat itself to become unstuck, etc?" "7502": "Q: I've seen things about having a fixed update clock for the game (60Hz etc) but rendering at a higher frame rate requires you to interpolate between states. To do this would you just duplicate your game state each time and interpolate between the current and previous for every entity etc? That seems quite expensive" "7566": "Q: I am looking up for a lightweight way to traverse 3D voxels along a ray and accumulate a color in OpenGL. Any suggestion about algorithms that are mostly branchless (if I remember correctly this was covered in Handmade Hero only on CPU)?" "7667": "Q: I want to get deeper into C / assembly, but I already have three projects ongoing in C# and running my business. How do / did you manage learning new topics while inundated with other work?" "7808": "Q: One thing that always gets me: How do you stop yourself from over-complicating things? I always seem to try be "clever" and it almost always seems to be a bad idea" "8006": "Q: Would it be possible to have two switch tiles in very distant rooms that you have to hop on to open a door or unlock something?" "8118": "Hi Casey, you are looking very handsome today" "8144": "That cat hair floating around" "8184": "Q: From what I understand, you started Handmade Hero because you thought people didn't know what it took to make a real game and it would be good if they did, so it seems that you do care about influencing people to do things a certain way. Don't you think that teaching is more than just giving people the facts? You also need to show them why they should care and that takes convincing" "8598": "handmade_hero I still enjoy your rants. There's truth to them" "8653": "Q: Do you find value in checking out other parts of the computing space, even those you disagree with? Without interfering, of course" "8805": "Q: Hope it's okay to ask one last question. If tomorrow everyone started using JavaScript for everything, you wouldn't care at all? Like, you will probably always use software written by other people. Wouldn't it be better that software was of good quality and, if you agree with that, shouldn't you try to influence people to care about software being high quality?" "9056": "Why does JavaScript suck? Modern JavaScript is pretty nice" "9167": "Wrap it up" --- name: "day631" title: "Revisiting Collision" markers: "0": "Recap and set the stage for the day" "91": "Enjoy the door switch tiles and determine to explore combat" "294": "Start with asymmetric combat, with enemies floating and the player tile-bound" "498": "Introduce SingleEnemyPattern" "756": "See no familiar" "789": "Make CreateDungeon() call AddPattern() with our SingleEnemyPattern" "860": "We have a familiar" "882": "Reacquaint ourselves with ExecuteBrain()" "997": "Force ExecuteBrain() to run the "!Blocked" path" "1023": "Our familiar remains stationary" "1051": "Compile in -Od" "1091": "Step in to ExecuteBrain()" "1192": "Reacquaint ourselves with the movement code in the entity system" "1312": "Implement the MovementMode_Floating case in UpdateAndRenderEntities()" "1397": "Our familiar now moves" "1425": "Our familiars are subject to collision volumes" "1495": "Make ExecuteBrain() conditionally run the "!Blocked" path" "1514": "Familiars can still float and interact with us through walls" "1529": "Reacquaint ourselves with the "Blocked" code in ExecuteBrain()" "1732": "Make UpdateAndRenderEntities() draw the collision volumes" "1761": "Our walls have collision volumes" "1782": "Make ExecuteBrain() set MovementMode_Floating for the familiar" "1803": "Our familiar follows us again" "1821": "Make SingleEnemyPattern add a collision volume" "1848": "Our familiar has a collision volume" "1855": "Increase the collision volume dimensions from 0.75³ to 1.25³ in SingleEnemyPattern" "1871": "Check our familiar's collision volume" "1873": "Decrease the collision volume dimensions from 1.25³ to 1³ in SingleEnemyPattern" "1878": "Our familiars fail to collide" "1900": "Make SingleEnemyPattern set the EntityFlag_Collides" "1930": "Our familiars can still float through walls" "1954": "Reacquaint ourselves with EntityFlag_Collides" "2021": "Let CanCollide() ignore the EntityFlag_Collides" "2034": "Our familiar collides with the doorway" "2057": "Make SingleEnemyPattern elevate the collision volume off the ground" "2072": "Our familiar still collides with the doorway" "2122": "Remove EntityFlag_Collides" "2232": "Our familiar may be colliding with the room boundary" "2290": "Replace the EntityFlag_Collides with collision responses, starting with SpeculativeCollide() ignoring room boundary collisions" "2550": "Our familiars collide, but can lock" "2615": ""We can see this dude grinding against the wall, which is nice." -Casey, 2021" "2633": "Determine to change the glove movement scheme from a "generalised coordinates" to a "Lagrangian" simulation system" "2926": "Glove management example: Getting caught on doors" "3006": "Determine to replace the glove's kinematic movement with an active management system" "3176": "Make AddPlayer() set the Glove's MovementMode to Floating" "3209": "Our glove is still controllable" "3230": "Introduce PDC() – proportional derivative controller – for ExecuteBrainHero() to use on the glove" "3507": "Our glove follows us" "3528": "Make ExecuteBrainHero() stiffen the glove's spring" "3609": "Our glove remains close to the hero" "3656": "Enable ExecuteBrainHero() to throw simulated punches" "3907": "Throw punches" "3968": "Increase GloveFloatHeight from 0.25 to 0.5 in ExecuteBrainHero()" "3981": "Our glove still skates along the ground, and punches are too slack" "4044": "Punch speed-based damage" "4104": "Tighten up our glove spring in ExecuteBrainHero()" "4118": "Our glove still feels sticky" "4163": "Further tighten up our glove spring in ExecuteBrainHero()" "4169": "Try throwing punches" "4209": "Look into MovementMode_Floating" "4287": "Our glove movement behaves oddly" "4297": "Make ExecuteBrainHero() match the Glove's FacingDirection to the body's" "4312": "Our glove movement feels odd" "4359": "Reacquaint ourselves with MoveEntity() and the entity DistanceRemaining" "4534": "Begin to rewrite MoveEntity() without DistanceRemaining" "4896": "Our problems: 1) Determining how far we can go in a particular direction; 2) Sliding against surfaces" "5049": "Continue to rewrite MoveEntity(), determining the closest point to move to" "5223": "Set up the lightboard" "5233": "afk" "5397": "Switch the scene" "5415": "Check the sound levels" "5440": "Closest point movement and collision detection" "5489": "Our problem: Gliding along collision volumes" "5721": "Deterministic gliding collision system structure" "5938": "Gliding collision as a pathfinding problem" "6119": "The Witness's localised grid for gliding collision" "6240": "Gliding collision as a pathfinding problem (cont.)" "6559": "Legal path segment picking" "6778": "Overlap testing" "7002": "Window cleaning, dreaming of a self-erasing board" "7133": "Hemispherical gliding collision" "7377": "Small-scale localised grid for gliding collision" "7566": "Legal position picking, subdividing cells by nine" "7863": "Boundary-avoiding subdivision" "7963": "Data requirements: "Closest to Dest" and "Connectivity" (Exits)" "8332": "Subdividing by changing the collision sphere's enlargement radius" "8466": "Determine to sleep on our collision" "8490": "We're out of time" "8538": "Q&A" "8554": "Q: Wouldn't this allow longer paths than the original, since you could still reach the goal while going a longer route?" "8643": "Q: Has there been any advancement on the 4-simplex case of GJK? Been reading your blog about this topic" "8673": "Q: Why not just move the character to the closest legal point of the desired end point?" "8704": "Q: I've never used a lightboard, so take this with a grain of salt, but if the edges were sealed so water couldn't get there, could you just spray and squeegee it?" "8756": "Q: I mean not the closest point on the path but closest point in the half sphere. But, yeah, I guess the problem is finding the closest point?" "8816": "That's probably a stupid question" "8904": "If there is a frame stutter, then the small movement becomes really large?" "8990": "handmade_hero For the lightboard there are already large transparent TVs, so the only question is price and pen tracking which is a solved problem" "9117": "Q: At any point in your development as a programmer, have you ever dealt with pointer aversion? I tend to avoid storing pointers, using array index lookups every time instead, to avoid the possibility of a bad / null pointer. I feel like I'm limiting myself by doing this, but it also feels valid. Have you dealt with this, and have any advice / opinion on it?" "9445": "Q: Is it possible to replace the entire web stack by C? I mean both back-end and front-end" "9483": "Q: When your 0th slot is reserved, do your loops start from 1 or 0 then?" "9531": "What would you then say to the idea that pointers can be be better because the compiler knows to prefetch the targets of pointers. This is not the case with indices as there are no "pointy" semantics there that the compiler understands" "9659": "handmade_hero You better post pictures of that to #food or I will find you" "9677": "I cannot give an example. It is just somethings that I've heard other people talk about when they give counter arguments for using indices" "9720": "Prefetching pointer targets" "10163": "handmade_hero Pass in -Os for small code?" "10185": "__builtin_prefetch() is the way to hint, but still gotta test it" "10253": "It's __builtin_prefetch(&location, optional)" "10305": "Yep, it's not in the optimizer" "10319": "GCC vs Clang loop unrolling" "10764": "Try -Oz in clang" "10776": "GCC vs Clang loop unrolling (cont.)" "10879": "Gotta go" --- name: "day632" title: "Experimenting with Voxelized Collision" markers: "1": "Recap and set the stage for the day" "62": "Demo our collision boxes" "96": "Positive-sense (where you can go) collision detection" "245": "Collision tasks: 1. Change MoveEntity() to look for and pick the nearest legal position" "315": "Collision tasks: 2. Upgrade to support simultaneous motion" "442": "Make MoveEntity() use the DesiredPosition, with no concern for collision" "481": "Our familiar "penetrates" us and walls" "528": "Plan to introduce "requested physics" stuff for MoveEntity() to take" "601": "Plan to replace the all entities iteration in MoveEntity() with a spatial partition" "758": "Rearrange and clear out the cruft from MoveEntity()" "915": "Collision from a game design perspective" "1016": "Demo conversation zooming" "1057": "Collision from a game design perspective (cont.)" "1091": "Remove SpeculativeCollide() and add EventOnCollision and PreventMotionOnCollision entity_flags" "1154": "Reject dynamic event-based collision, in favour of deterministic entity_flags" "1393": "Remove HandleCollision() and CanOverlap()" "1446": "Determine to make MoveEntity() search in subdivided space" "1537": "4coder theming" "1636": "Purple means it couldn't find the variable in the theme file" "1653": "handmade_hero I wrote this addition you can disable it with // f4_disable_cursor_token_occurance = true; in config.4coder" "1670": "The color option is: fleury_color_token_minor_highlight = 0xC0797979; in the theme" "1675": "4coder: Set fleury_color_token_minor_highlight = 0xff2f2f37" "1755": "Make MoveEntity() search in subdivided space, initially a fixed-size grid, introducing MoveEntityLocally()" "2109": "Write a voxel iterator in MoveEntityLocally()" "2204": "Make MoveEntityLocally() perform the collision test in each voxel" "2249": "Determine to extend our voxel search with an apron to permit screw-up recovery" "2375": "Extend our voxel search with an apron in MoveEntityLocally()" "2606": "Introduce v3 overloaded / and * operators, and replace Hadamard() with * overloads" "3043": "There's f4_backspace_token_boundry and f4_delete_token_boundry you can try" "3054": "4coder bindings" "3077": "Backspace and Del are much better" "3099": "Can we delete just a character at a time from the "Open" line?" "3113": "Replace Hadamard() with * overloads (cont.)" "3172": "I believe the lister thing is this param in the config: lister_whole_word_backspace_when_modified" "3190": "4coder: Set lister_whole_word_backspace_when_modified = true" "3268": "The Hadamard changes did not break anything" "3291": "Consider how to determine where in the voxel we can move" "3450": "Initialise a Vacant voxel in MoveEntityLocally()" "3537": "Introduce IterateVoxel(), voxel_iter and related IsValid() and NextInOrder() functions" "3780": "Respecify Vacant as Occupied in MoveEntityLocally(), and set it up to set Occupied to true" "3842": "Set up MoveEntityLocally() to test if the entire voxel, one level up, is completely unoccupied" "3932": "Can the amount of time the "entering second hour" notice is displayed be adjusted?" "4023": "Make MoveEntityLocally() test the entire Occupied array" "4187": "handmade_hero You don’t seem to have virtual whitespace enabled in 4coder. Is that deliberate?" "4212": "Enable MoveEntityLocally() to find the best closest position, permitting movement to the desired position" "4571": "In-cell movement works" "4604": "Set up to make MoveEntityLocally() do a point-in-box test" "4686": "Break" "4702": ""Away from Keyboard" Presentation" "4930": "Return with refilled water" "4971": "Make MoveEntityLocally() call RectanglesIntersect() to do its point-in-box test" "5154": "This doesn't work yet" "5161": "Double-check MoveEntityLocally()" "5182": "We can punch through walls" "5199": "Triple-check MoveEntity() and MoveEntityLocally()" "5344": "Temporarily make MoveEntityLocally() default to preventing movement" "5358": "Our glove does not move" "5360": "Scour MoveEntityLocally() for errors" "5489": "Step through MoveEntityLocally()" "5555": "Hi" "5690": "We forgot to test the entity_flags" "5737": "*cuddles*" "5811": "Make MoveEntityLocally() test entity_flags, renaming PreventMotionOnCollision to AllowsMotionOnCollision, and making GenerateRoom() and AddConversation() set entity_flags" "6004": "Our entities can move, notably our proportional derivative controlled glove" "6081": "Double-check our occupation test in MoveEntityLocally()" "6197": "We never collide" "6250": "Double-check RectanglesIntersect()" "6301": "Make MoveEntityLocally() draw occupation state" "6536": "We seem to be detecting collision" "6628": "Try making MoveEntityLocally() default to preventing movement" "6642": "We detect collision and prevent movement" "6701": "Apologise to speedrunners" "6715": "We collide, allowing tunnelling and recovery" "6924": "Make MoveEntity() subdivide the voxelized collision search" "7488": "Our glove no longer moves, but the familiar does" "7625": "Consider how to handle the glove's interpenetration" "7722": "Prevent MoveEntityLocally() from drawing the occupation state" "7733": "Our performance has degraded" "7767": "Add an assertion on the StepCount in MoveEntity()" "7787": "Hit our assertion in MoveEntity()" "7835": "Inspect our values in MoveEntity()" "7879": "Make MoveEntity() cap the voxel subdivision StepCount to 5" "7932": "Our performance remains poor" "7983": "Q&A" "7996": "Q:I am always wondering why we use CPU optimization if the rendering is done by GPU. Maybe it is a silly question" "8023": "Disable the lighting in UpdateLighting()" "8070": "Our unlit performance in -O2 is fine" "8076": "Our unlit performance in -Od is slow" "8125": "Re-enable the lighting in UpdateLighting()" "8137": "UpdateAndRenderEntities() takes 10% of our frame time" "8177": "Make MoveEntity() a TIMED_FUNCTION" "8207": "MoveEntity() takes 5% of our frame time" "8239": "Disable MoveEntity()" "8261": "ComputeLightPropagationWork() takes 90% of our frame time" "8284": "Disable the lighting in UpdateLighting()" "8291": "UpdateAndRenderEntities() takes 69% of our frame time" "8343": "Re-enable the lighting in UpdateLighting()" "8357": "Q: Doesn't the OrigP need to be updated each step?" --- name: "day633" title: "Narrowing in on a Collision Scheme" markers: "0": "Recap and set the stage for the day" "25": "Demo the current state of movement" "60": "Simple and stable collision detection and resolution" "134": "Re-enable the MoveEntityLocally() loop in MoveEntity()" "143": "We lack collision" "157": "Double-check MoveEntity()" "187": "Our glove penetrates the wall" "197": "Make MoveEntityLocally() draw occupation state" "209": "We detect collision but then tunnel through the familiar" "221": "Double-check MoveEntityLocally()" "295": "Increase the StepCount from 5 to 10 in MoveEntity()" "303": "We clearly see collision detection in red" "321": "Reacquaint ourselves with MoveEntityLocally() and MoveEntity()" "509": "The utility of stating a universally minimum thickness, as MOTION_DISPLACEMENT_SIZE" "639": "Reacquaint ourselves with MoveEntityLocally() and MoveEntity() (cont.)" "712": "Prevent MoveEntity() from capping the StepCount" "722": "We still detect collisions, but tunnel" "734": "Scour MoveEntityLocally() for bugs" "979": "Delete VoxelI from MoveEntityLocally()" "994": "Scour MoveEntityLocally() for bugs (cont.)" "1003": "Disable the BestP computation loop in MoveEntityLocally()" "1018": "Entities can erroneously move" "1046": "Scour MoveEntity() for bugs" "1088": "Prevent MoveEntity() from modifying Entity->P" "1108": "Entities can no longer move, as desired" "1114": "Re-enable the BestP computation loop in MoveEntityLocally()" "1125": "Entities now collide, but can get embedded" "1216": "Conceptualising the voxelised collision search, to prevent / recover from embedding" "1686": "Make MoveEntityLocally() test the occupation state of only the one voxel en route to the target" "1875": "Non-embedded entities collide nicely" "2012": "A familiar has got stuck underground" "2042": "Consider pathfinding our collision through a stack of voxels" "2242": "Enable MoveEntityLocally() to detect and resolve embedding" "2345": "Our initially embedded glove may now move, but can tunnel" "2384": "Investigate our tunneling issue" "2447": "Make MoveEntityLocally() test the occupation state of all eight surrounding voxels" "2458": "We still tunnel" "2465": "Consider drawing more collision information" "2544": "Make MoveEntityLocally() test the occupation state of only the one voxel en route to the target" "2566": "Consider drawing more collision information (cont.)" "2655": "Take a closer look at our glove vs familiar collision" "2697": "Wonder why it fails our AnyOpen check" "2745": "Make MoveEntityLocally() test the occupation state of all eight surrounding voxels" "2762": "We still tunnel" "2775": "Prevent MoveEntityLocally() from using the target position if embedded" "2785": "We can't test tunneling" "2792": "Make AddPlayer() elevate the glove" "2834": "We can test it, and no longer tunnel" "2969": "Let MoveEntityLocally() use the target position if embedded" "2983": "We tunnel trivially" "2995": "Make MoveEntityLocally() set AnyOpen using an OccupiedCount" "3095": "We still tunnel" "3110": "Wonder how MoveEntityLocally() detects embedding so often" "3184": "Increase the ApronSize to the full MOTION_DISPLACEMENT_SIZE in MoveEntityLocally()" "3191": "We still tunnel, but less easily" "3260": "How are two frames disagreeing on which collision volumes are occupied?" "3401": "Make MoveEntity() only allow one micro-move, i.e. one call to MoveEntityLocally()" "3431": "We still tunnel" "3478": "Delete VolumeDim and VolumeP from MoveEntityLocally()" "3488": "Consider drawing more collision information" "3680": "Should we start visualisation now?" "3705": "The game looks like it lags hard when the punch flies around. Is that because of the debugging tools being active?" "3895": "Compile in -Od" "3916": "Show off the performance in -Od" "3932": "Use #pragma optimize("gt", on) and #pragma optimize("", on) around handmade_lighting.cpp" "4048": "ComputeLightPropagationWork() takes 78% of our frame time" "4072": "Toggle off MoveEntity()" "4105": "Gauge our performance in -Od" "4143": "Use #pragma optimize("gt", on) and #pragma optimize("", on) around handmade_light_atlas.cpp" "4223": "Gauge our performance in -Od" "4245": "Remove the #prama optimize() and re-enable MoveEntity()" "4312": "Step through MoveEntityLocally()" "4368": "Initialise a TestP in MoveEntityLocally()" "4409": "Step through MoveEntityLocally() watching the TestP and other values" "4524": "Set a break point in the !AnyOpen path" "4607": "Tunnel through, without hitting that break point" "4698": "Compile in -O2" "4707": "It pushed the skeleton up over the glove?" "4716": "The glove is not tunneling, but passing beneath the familiar" "4869": "Make MoveEntityLocally() test the occupation state of only the one voxel en route to the target" "4887": "Our glove and familiar are stuck" "4936": "Enable MoveEntityLocally() to clip away the voxel search directions behind our direction of motion" "5208": "Our glove may be blocked from moving upwards, but may perhaps move sideways" "5231": "Consider clipping the collision box" "5495": "Start to make MoveEntityLocally() clip the collision box" "5752": "Consider making MoveEntityLocally() permit movement within the voxel interior" "5806": "Enable MoveEntityLocally() to (dis)allow movement on a direction-by-direction basis" "6203": "Our glove and familiar get unstuck" "6219": "Make a note to pathfind through the voxel" "6249": "Q: The second if has a problem: it should be Dir.y not Dir.z" "6267": "Our movement is slow" "6292": "Let MoveEntity() allow all micro-moves, i.e. multiple calls to MoveEntityLocally()" "6300": "Our movement is normal" "6344": "That's it for today" "6376": "Q&A" "6428": "Q: Can you explain this direction check a bit more?" "6513": "Q: Have you forgotten to upload Day 632 to YouTube?" "6546": "Q: So it can't move backwards?" "6607": "After discovering the glove was moving under the skull you are now trying to prevent that?" "6619": "Q: If you're trapped and have the vector in, why can't you just follow the vector back out?" "6717": "Q: (Semi off-topic) With the live code reloading, I made a thing where global variables in the dll can be saved and restored when you reload the dll. Have you tried that before? I thought it's kind of neat" "6796": "Wrap it on up" --- name: "day634" title: "Final Collision Resolution Design" markers: "0": "Recap and set the stage for the day" "130": "Determine to switch the collision detection to use voxel-by-voxel stepping" "333": "Introduce an f32 version of Floor()" "441": "Center the FromP around stable collision voxel bounds in MoveEntityLocally()" "676": "Introduce a v3 version of Floor()" "786": "Continue to switch MoveEntityLocally() to use stable voxel-by-voxel stepping" "989": "Thoughts on embedding recovery" "1144": "Introduce move_result for MoveEntityLocally() to return" "1253": "Voxel collision states: 1) Any legal corners" "1319": "Voxel collision states: 2) Where would the entity be placed?" "1353": "Make MoveEntityLocally() use GetClosestPointInBox() to compute the entity placement" "1381": "Deep thoughts on collision" "1423": "Consider using GetClosestPointInBox() on repeated subdivisions of the collision voxel" "1595": "Something I wondered about The Witness is: Why does the player not move on a navmesh? Then you wouldn't have needed that brute force testing thingy" "1779": "Are you and Jon Blow on the same team or something?" "1789": "Introduce CollidesAtP() for MoveEntityLocally() to call" "1959": "So, tuned in just in time to witness a Casey epiphany?" "1976": "Yup" "2019": "Do I need a code word?" "2072": "Introduce Mike Biddlecombe" "2089": "In Vancouver" "2103": "3D movement realisation: If we could place an entity in a cell, we may then root-find to pick exactly where" "2186": "Introduce a root-finding RefineVoxelPlacement() for MoveEntityLocally() to call" "2957": "Explain RefineVoxelPlacement()" "3013": "Fix RefineVoxelPlacement() to halve the tStep each iteration" "3023": "Explain the root-finding of RefineVoxelPlacement() (cont.)" "3263": "Make MoveEntity() call RefineVoxelPlacement() at the end" "3298": "Recap the parameters passed to RefineVoxelPlacement()" "3339": "Handling shifting FromP: 1) Map it into the cell" "3347": "Handling shifting FromP: 2) Convect it around the centre of voxel faces" "3376": "Make MoveEntity() and MoveEntityLocally() map the FromP and ToP into the cell" "3460": "I am really confused with the quality of the video and lighting setup. Why is it so good?" "3528": "Remove the voxel subdivision code from MoveEntity()" "3557": "Plan to pathfind to our nearest legal destination" "3701": "What happened to the glasses?" "3732": "Now I need to learn this stuff. StarCinematographyGalaxy when?" "3805": "You need a red arrow in the thumbnail" "3822": "Setup MoveEntity() to pathfind to our nearest legal destination, welding in MoveEntityLocally()" "3918": "Consider calling RefineVoxelPlacement() on multiple cells" "3943": "The tip professional Cinematographers do not want you to know!" "3960": "Make MoveEntity() pathfind to our nearest legal destination (cont.)" "4152": "Yeah, now I also spot the divide outside the floor somebody mentioned earlier, at VoxelMinCorner" "4158": "Fix the computation of VoxelMinCorner in MoveEntity()" "4182": "Make MoveEntity() pathfind to our nearest legal destination (cont.)" "4349": "Is there a return statement in the refine function?" "4376": "Make MoveEntity() pathfind to our nearest legal destination (cont.)" "4592": "Flipped refinement and movement legality" "4714": "Determine to make MoveEntity() handle movement from a legal place" "4944": "Make MoveEntity() handle movement from a legal place" "5476": "Introduce voxel_move for MoveEntity() to use" "5529": "Make MoveEntity() handle movement from a legal place (cont.)" "6038": "Implement UpdateBest()" "6242": "Consider this okay for one day's work" "6273": "Step through MoveEntity()" "6366": "Step through MoveEntity() in -Od" "6426": "Set MOTION_DISPLACEMENT_SIZE to 0.125 (as the closest power of 2 to 0.1) in MoveEntity()" "6460": "Step through MoveEntity()" "6585": "Pull out the DeltaP in UpdateBest() for debugging convenience" "6623": "Step in to UpdateBest()" "6717": "Retain the Best.DistanceSq as the nearest valid distance in MoveEntity()" "6811": "Step wildly" "6857": "Update remedybg from 0.3.3.3 to 0.3.3.5" "7108": "Step wildly still" "7167": "Try stepping in -O2, unsuccessfully" "7180": "Casey, you might need new glasses" "7189": "This is still in a bad state" "7203": "Compile in -Od" "7233": "handmade_hero Did you order the glasses from Apple?" "7240": "Fallacious positive arguments for Apple vs consumer rights law" "7542": "That's where competition comes in" "7651": "Step through MoveEntity()" "7780": "tl;dr I love capitalism when it works for me. Screw other people" "8077": "handmade_hero Can we get Handmade Political as a podcast?" "8185": "Step through MoveEntity()" "8215": "Flip the sense of our Occupied tests in MoveEntity()" "8246": "Step through MoveEntity()" "8419": "Fix MoveEntity() to reset Best.Moved each iteration" "8436": "Step through MoveEntity()" "8453": "The glove moves by whole voxel steps" "8473": "Make MoveEntity() use the result of the pathfinding loop in its final position settings" "8510": "Collision is getting there, but the glove can still penetrate the wall" "8545": "Q&A" "8563": "Hey dude! In love with the stream title, definitely stealing next time I play that game" "8602": "Q: My apologies for the stepping issue you were seeing. I'll take a look and see wtf is going on!" "8642": "Q: Can you explain how that .125 thing works?" "8899": "Recommend 'What Every Computer Scientist Should Know About Floating-Point Arithmetic'" "8972": "Check out random ASCII (Bruce Dawson) blog posts on floating point" "8985": "handmade_hero The Floating-Point Guide" "8997": "But how much of a difference can this minute computation really make in real time?" "9054": "Temporarily set MOTION_DISPLACEMENT_SIZE to 0.1 in MoveEntity()" "9086": "Inspect the ToP" "9121": "Revert MOTION_DISPLACEMENT_SIZE to 0.125 in MoveEntity()" "9160": "This was a bad example" "9176": "Temporarily set MOTION_DISPLACEMENT_SIZE to 0.1 in MoveEntity()" "9190": "Inspect the values resulting from a MOTION_DISPLACEMENT_SIZE of 0.1" "9205": "Revert MOTION_DISPLACEMENT_SIZE to 0.125 in MoveEntity()" "9219": "Inspect the values resulting from a MOTION_DISPLACEMENT_SIZE of 0.125" "9262": "How long have you been working on this project?" "9363": "You look like a render" "9379": "We need more codelesthenics, Casey, and you need it as well" "9449": "Q: How does your fancy transparent whiteboard work? Did you learn to write backwards, or is it all just mirrored?" "9464": "I don't understand why we can't show birthdays on the user profile page" "9480": ""et-zio" "ow-dit-or-A"" "9497": "Everyone needs to say the word dynamically at least once" "9540": "Q: Ezio Auditore is the main character from Assassin's Creed 2" "9557": "Reflect on the collision routine" "9575": "Thanks, everyone" --- name: "day635" title: "Debugging Voxel Motion Stepping" markers: "0": "Recap and set the stage for the day" "110": "Plug Star Code Galaxy and its nonlinear teach–challenge structure" "359": "Show the start of MoveEntity()" "400": "Run in -Od" "420": "The collision code sadly permits tunnelling" "502": "blow raid" "538": "Admire the notes feature of Jon's programming language" "735": "Walk through MoveEntity()" "854": "Defining collision around the minimum thickness to obstruct motion" "972": "Walk through MoveEntity() (cont.)" "1067": "Bug in MoveEntity(): It determines collision based on location in space" "1150": "TODO(casey): This may be incorrect, let's see" "1196": "Walk through MoveEntity() (cont.)" "1245": "Meow" "1372": "Walk through MoveEntity() (cont.)" "1509": "Remove CenterP declaration from MoveEntity()" "1527": "Walk through MoveEntity() (cont.)" "1672": "Walk through UpdateBest()" "1751": "Walk through MoveEntity() (cont.)" "1785": "Comment out the StartCollide declaration in MoveEntity()" "1823": "Walk through MoveEntity() (cont.)" "1878": "Temporarily make MoveEntity() finish by positioning the entity at the BestCell's center, rather than using RefineVoxelPlacement()" "1907": "Run in -Od" "1947": "The movement looks too smooth" "2066": "Make MoveEntity() draw the final BestCell" "2120": "Our collision cells are tiny" "2233": "Make MoveEntity() draw the intermediary BestCell" "2266": "The BestCell doesn't get updated" "2296": "Make MoveEntity() instead draw the intermediary Cell" "2322": "We have collision voxel trails, and interpenetration of walls" "2400": "Inspect MoveEntity() for unseemliness" "2515": "Make UpdateBest() only consider not Occupied cells" "2698": "Our collision behaviour hasn't changed" "2707": "Make UpdateBest() draw cells based on their consideration and occupancy" "2830": "A flash of red may precede interpenetration" "2897": "Scour MoveEntity() and CollidesAtP() for bugs" "3097": "Remove OccupiedCount from MoveEntity()" "3113": "Scour MoveEntity() for bugs (cont.)" "3400": "It looks like the test volume is so small that it is only colliding at the wall boundary, and when the test cell pushes far enough into the wall, it is no longer detecting a collision" "3545": "Doesn't CollidesAtP() need to grow each collision volume with the moving entity's collision volume?" "3580": "Plan to capture collision" "3618": "Hunt the code for the F-key handling" "3689": "Add a DevMode_collision action on F9" "3740": "Introduce CollisionEditor() for UpdateAndRenderEditor() to call, augmenting game_mode_world with TimeStepScale" "3991": "Time does not flow" "4000": "Make PlayWorld() initialise TimeStepScale to 1.0f" "4050": "Time flows but F9 doesn't work" "4064": "Elevate DevMode_collision into the editor section of dev_mode" "4135": "F9 is still a little weird" "4144": "Set DevMode_last_editor to DevMode_collision" "4158": "Slow down the TimeStep in Collision Recorder" "4222": "Our configuration of collision boxes seems wrong" "4271": "Consider our collision box configuration" "4372": "Make UpdateBest() pass the Dir as the colour to PushVolumeOutline()" "4457": "Try to interpret our collision box configuration" "4575": "Make MoveEntity() draw the starting BestCell" "4602": "Interpret our collision box configuration" "4664": "Try to provoke stickiness" "4722": "Make MoveEntity() finish by calling RefineVoxelPlacement()" "4744": "Determine to set up a test case" "4756": "Make CreateWorld() place the player in their bedroom" "4793": "Try to penetrate the bedroom wall at different timesteps" "4925": "Investigate why ToP is erroneously affecting the collision detection" "5037": "Add a lerp sanitation assertion in RefineVoxelPlacement()" "5084": "Never hit that assertion" "5097": "Make RefineVoxelPlacement() draw the lerp test in cyan (can place) or magenta (cannot place)" "5218": "Check out our refinement placement" "5261": "Add a "Single Stepping" boolean button to CollisionEditor(), augmenting game_mode_world with SingleStep" "5621": "Single Stepping does not work" "5631": "Change CollisionEditor() to draw a Red / Green "Single Stepping" button" "5853": "Our "Single Stepping" button works" "5873": "Add a "Step" boolean button to CollisionEditor(), augmenting game_mode_world with StepLatch" "5978": "Enable MoveEntity() to step through the movement, augmenting sim_region with DEBUGPreventMovement" "6237": "Try out Single Stepping" "6402": "Revert UpdateBest() to draw cells based on their consideration and occupancy" "6422": "Collision seems entirely based on direction" "6468": "Toggle off the combined and individual z and y Occupied checking in MoveEntity()" "6525": "The x Occupied check is rock solid" "6568": "Toggle on the z and y Occupied checking in MoveEntity(), leaving only the combined checking off" "6593": "The individual x, y, z Occupied checking permits tunnelling" "6611": "Toggle off the z and y Occupied checking in MoveEntity()" "6624": "The x Occupied check remains rock solid" "6647": "Toggle on the y Occupied checking in MoveEntity()" "6659": "We can tunnel easily" "6696": "Toggle off the x Occupied checking in MoveEntity()" "6721": "The y Occupied check remains rock solid" "6780": "Introduce GetClosestPointInBoxConservative()" "7056": "Our glove can only move in Y" "7078": "Toggle on the x Occupied checking in MoveEntity()" "7098": "We can still tunnel easily" "7138": "Try Single Stepping" "7214": "Produce a collision test case" "7250": "Toggle off the y Occupied checking in MoveEntity()" "7264": "Hopping pushes the glove through the wall" "7344": "The x Occupied check remains rock solid" "7380": "Toggle on the combined and off the individual x, y and z Occupied checking in MoveEntity()" "7396": "We are punching up" "7469": "We clearly tunnel through walls" "7529": "Investigate our corner collision test" "7603": "Spot the bug" "7634": "Sure..." "7672": "Let MoveEntity() compute the occupancy of all surrounding cells" "7692": "Our combined corner Occupied checking is rock solid" "7709": "Toggle on the individual x, y and z Occupied checking in MoveEntity()" "7719": "Our collision is much more stable" "7891": "Determine to improve gliding" "7981": "Q&A" "7992": "Can you still hop / push the glove into the wall?" "7994": "Hopping no longer pushes the glove through the wall" "8170": "handmade_hero Shouldn't you also add Eps to the min side in the conservative test?" "8249": "TODO(casey): RectanglesIntersect should probably be changed to be properly >= and < instead of >= and <= ??" "8298": "handmade_hero What kind of pathfinding would you use for the glove's return path? A* or do you use something simpler?" "8338": "handmade_hero What would you do differently for collision detection in non AABB geometry?" "8366": "Q: I think this C model of programming is a bit time consuming in that we need to compile and look at the result and go back and forth to fix a problem. Do you think what would be a better model of programming and I also don't mean the scripting language" "8382": "Demo hot reloading" "8516": "In retrospect, would it have been worth it to make a visualiser for collision code before actually writing it?" "8591": "The glove can stick and fail to glide" "8660": "Make MoveEntity() only tell UpdateBest() that Occupied is true if all (rather than any) sides are occupied" "8703": "Gliding happens more nicely" "8881": "TODO(casey): Handle getting "unembedded"" "8908": "Q: Would collision cylinders have rounded caps or flat?" "8939": "Q: Couldn't you simply clamp to X,Y. What does having Z axis movement on the glove in this problem space accomplish?" "8946": "Demo movement in Z" "9053": "The collision could have a max z delta" "9132": "Wrap it up with a glimpse into the future" --- name: "day636" title: "Unembedding Colliding Objects" markers: "1": "Recap and set the stage for the day" "44": "Demo the current state of collision" "112": "Collision TODOs: 1) Cylindrical boxes" "267": "Collision TODOs: 2) Getting unembedded" "628": "Walk through the gliding collision routine in MoveEntity()" "872": "Collision detection philosophy: Test the same thing every frame" "969": "Set up MoveEntity() to handle unembedding" "1269": "Let MoveEntity() permissively unembed entities in any direction" "1333": "Our embedded glove gets unstuck" "1550": "Embed the glove in the wall" "1637": "Determine to unembed based on a displacement motion vector" "1884": "Determine to produce the motion vector for each voxel position" "2013": "Determine to make CollidesAtP() produce a repulsion field" "2135": "Unembedding example" "2244": "Introduce collision_field for CollidesAtP() to return" "2328": "Our collision behaves identically" "2341": "Set up MoveEntity() to set its target to the summed Repulsion computed by CollidesAtP()" "3276": "The glove can get unembedded laterally" "3315": "Change MoveEntity() to unembed in the Repulsion-adjusted target direction" "3509": "Our glove can move when embedded" "3541": "Make MoveEntity() update the Best.DistanceSq repeatedly" "3704": "Our glove cannot move when embedded" "3735": "Plan to make CollidesAtP() compute its quadrilateral Repulsion vector" "4022": "Meow" "4162": "Make CollidesAtP() compute its quadrilateral Repulsion vector" "4291": "Our repulsion-based unembedding works" "4428": "Q&A" "4441": "Show off Grimm Audio UC1" "4595": "A bit late to the stream, but what about tracking a previous location and always moving back towards where the entity came?" "4701": "What was the name of that audio box?" "4724": "Grimm Audio UC1" "4846": "handmade_hero As someone who started the series a few days ago and wants to make a game of his own, how do I manage to catch up with the current stage of the game? And should I even care to do that? It's true that I should always pay extra attention where I think I need to, but I don't know what's coming within the 600 episodes and whether spending extra time on things that I thought needed the extra time will be worth it or not as opposed to getting a conceptual idea on the subject and move on" "4872": "Plug and provide feedback on the Episode Guide" "5029": "handmade_hero I recently discovered your stream (so forgive me if you have covered this before). I learn a lot from the in-depth videos on how a computer actually works on a fundamental level, like the C tutorial and the blackboard videos (and I have been programming for 10 years). I am really excited about Star Code Galaxy. Do you have any information about when it will launch and what kind of material it will it cover?" "5167": "handmade_hero Can you tease just how awesomesauce the SCG player will be?" "5331": "Q: Have you implemented some kind of the friction effect for the player walks or runs along the voxel boxes?" "5366": "Q: Did you make the final products for each module first and then build the course around each for each module?" "5384": "Q: Can you explain again how the unembedded vector is calculated?" "5460": "Q: Any idea on an approximate price for the Star Code Galaxy course?" "5502": "Oh it's $50 per module? That's fair, I thought it would be, like, $200" "5590": "Q: My friend started working as a C++ programmer and he showed the codebase he has to work with and it was a jungle of classes, template, std:: and it was very slow to compile. Is it a common thing in the industry to have this kind of code base? I guess that is why software are of bad quality" "5714": "Q: Is SCG your full time occupation nowadays, or also a side project like Handmade Hero?" "5725": "Q: Do you think putting "completed SCG" on a resume will be valuable? I guess it depends on if the employer has heard of it" "5758": "handmade_hero Related to the point, I guess: But would it be easy to show someone in the industry, who sticks to those beliefs, that cutting off most of the C++ BS is beneficial? Not asking you to do it right now, just about the concept really" "5965": "Q: I use some templates in my C++ code, to avoid large amounts of code duplication, but I struggle with compile times. Could you recommend any material on metaprogramming in C / C++ which you think is good (if I have understood correctly, you do not use templates)? Do you show any metaprogramming in your steams?" "6010": "handmade_hero Did you use to use std libs and then switch to the "handmade" style?" "6132": "Q: What is declare anywhere?" "6214": "Q: So would you recommend Rust over C++?" "6276": "Q: Given that Handmade Hero is running for quite a while, doesn't it seem unfeasible for solo indie devs to go with a custom engine, especially since you are more experienced?" "6755": "handmade_hero On this subject, if you keep your Unreal game to just stuff achievable in blueprints it seems pretty accessible. If you want to do C++ code then it is very nuts" "6886": "Wrap it up with a glimpse into the future" --- name: "day637" title: "Adding Collision Spheres" markers: "1": "Welcome with thanks to our sponsor the Rust Recovery Foundation" "85": "Recap and set the stage for the day" "136": "Demo our collision system" "180": "Collision system clean-up phase: 1) Spatial partition" "333": "Collision system clean-up phase: 2) Spherical collision volume" "497": "Collision system clean-up phase: 3) Partial embedding" "565": "Determine to add collision spheres" "699": "Set up CollidesAtP() to support collision spheres" "954": "Respecify CollidesAtP() to compute collision of various shapes in the same branch" "1102": "Branchless programming?" "1149": "Introduce ShapesCollide()" "1210": "If less code is better, isn't no code at all most best? Why are we even doing programming then?" "1349": "Implement ShapesCollide()" "2039": "Describe ShapesCollide()" "2134": "Add EntityFlag_SphereCollision and fix compile errors" "2167": "Rectangular collision continues working" "2234": "Make the Glove use SphereCollision in AddPlayer()" "2265": "We don't know if our Glove is a sphere" "2305": "Make UpdateAndRenderEntities() draw SphereCollision entities in orange" "2359": "Our Glove is a sphere" "2445": "Double-check CollidesAtP() and ShapesCollide()" "2753": "Consider diagramming spherical collision" "2957": "Determine to enable CollidesAtP() to use the repulsion direction computed by ShapesCollide()" "3153": "Consider adding spherical drawing to the renderer" "3334": "Change ShapesCollide() to use CenterDelta and Radius for its rectangle vs rectangle test" "3637": "The Glove's spring is wild" "3671": "Make the rectangle vs rectangle collision test less permissive in ShapesCollide()" "3708": "Familiar movement is still broken" "3734": "Double-check the rectangle vs rectangle collision test in ShapesCollide()" "3743": "Use Square() in the rectangle vs rectangle collision test in ShapesCollide()" "3816": "Meow" "3920": "Our familiar does move and collide fine" "3959": "Reflect on ShapesCollide()" "4028": "Scrolling around" "4098": "Consider improvements to ShapesCollide()" "4197": "Put the mouse out of action" "4251": "Suspect improvements to shape vs shape collision" "4312": "Instrument ShapesCollide() to diagram various shaped collisions" "4839": "Set up MoveEntity() to call DIAGRAM_Phase()" "4954": "Create handmade_diagram.h with stubs of the various DIAGRAM_*() functions" "5264": "Q&A" "5271": "handmade_hero I just tested and 4coder 4.1.8 does fix the indentation. It's a one-line diff" "5294": "const? Did I see him instinctively type const" "5432": "Q: Why is a new diagramming system needed? Why not just use the existing renderer?" "5446": "Demo the current debug visualisation" "5540": "handmade_hero Off-topic: Should the PushArray() for SpatialGridLeaves in handmade_lighting.cpp be aligned to 16 bytes, for movaps on 128-bit memory operands?" "5677": "Make GridBuildSpatialPartition() align the SpatialGridLeaves PushArray() to 16 bytes" "5712": "The lighting remains fine" "5824": "Q: Are we still planning on adding cylinder or capsule collisions?" "5848": "handmade_hero Should the ID.Value be checked to be not null in handmade_asset.cpp?" "5887": "LoadFont()" "5931": "Make LoadFont() check that ID.Value is not null" "6093": "handmade_hero Hi Casey! First time catching your stream live after I finally caught up on every Handmade Hero episode. Wanted to tell you it's been really fun and very enlightening following along. Super looking forward to Star Code Galaxy as well!" "6115": "handmade_hero For the upgrade to 4coder 4.1.8, it seems to break something with modal bindings" "6161": "Q: Could you explain flood fill algorithm as it was used in the Minesweeper game? Thanks!" "6195": "handmade_hero The fix for the auto indentation is one line. You could apply it to your current 4coder" "6204": "Q: Any reason you only have the xyz-diagonal case in the voxel collision system? Wouldn't you want xy-, xz-, and yz-diagonal motion as well?" "6294": "TODO(casey): Try having edge-diagonal motion as well as corner-diagonal motion?" "6319": "Q: Does Handmade Hero really not have a sphere drawing routine?" "6408": "Q: Couldn't you just apply a circle to a camera-facing quad to fake a sphere?" "6438": "Q: This algorithm" "6505": "Q: How does it work?" "6697": "Will it be finished before Cyberpunk 2077?" "6762": "Thanks, everyone" --- name: "day638" title: "Recording Diagram Commands" markers: "0": "Recap and set the stage for the day" "39": "Thoughts on diagrammed debugging of our collision system" "307": "Describe our DIAGRAM_*() functions" "411": "Introduce DIAGRAM_Color() and DIAGRAM_Thickness()" "541": "Introduce diagram_entry and diagram_group structs" "864": "Wonder how Jon handles conditional compiling out of functions in JAI" "903": "Remove DIAGRAM_Phase() in favour of permitting nested diagrams at the Begin and End, and introduce DIAGRAM_Point(), DIAGRAM_Text() and DIAGRAM_Out()" "1100": "Check the chat for JAI info" "1129": "Rename DIAGRAM_Text() to DIAGRAM_Overlay(), and make diagram_entry be a linked list in an arena" "1236": "Set up diagram_entry as a linked list, augmenting diagram_group with an Arena and PhaseDepth" "1381": "Add Text to diagram_entry and rename DIAGRAM_Out() to DIAGRAM_Text()" "1524": "Introduce AppendDiagramEntry(), with thoughts on threading and architecture-transparent debug systems" "1699": "Fix up compile errors at diagramming calling sites, introducing DIAGRAM_IsOn()" "2122": "Implement AppendDiagramEntry() and introduce diagram_attributes" "2307": "Introduce DIAGRAM_Stick()" "2373": "Implement DIAGRAM_Color() and DIAGRAM_Thickness()" "2429": "Continue to implement the AppendDiagramEntry() linked list" "2574": "Implement DIAGRAM_Sphere(), _Line(), _Box(), _Point() and _Overlay()" "2683": "Implement DIAGRAM_Begin() and DIAGRAM_End()" "2763": "Reflect on our diagramming code" "2811": "Consider recording the diagramming state for the renderer to track" "2930": "Make a union of the P[] and Attrib values in diagram_entry, including the Text buffer from diagram_attributes" "3117": "Implement DIAGRAM_Text(), augmenting diagram_group with a FormatBuffer[1024]" "3426": "Consider future work on our diagramming system" "3552": "Introduce RenderDiagrams()" "3615": "Hit a write access violation on DEBUG_RECORD_ALLOCATION() in PushSize_()" "3655": "Compile in -Od and again hit that write access violation on DEBUG_RECORD_ALLOCATION() in PushSize_()" "3723": "Investigate our write access violation on DEBUG_RECORD_ALLOCATION() in PushSize_()" "3815": "Disable HANDMADE_DIAGRAMS" "3852": "Demo the memory arena viewer" "4000": "Our debug_event array in debug_table is 136 MiB" "4167": "Increase our debug_event array to 2*64*65536 (544 MiB)" "4179": "Run the game" "4202": "Revert our expansion of the debug_event array" "4210": "Introduce DIAGRAM_Reset() for GAME_UPDATE_AND_RENDER() to call" "4484": "In -O2, overflow the debug_event array via the collision system" "4506": "In -Od, overflow the debug_event array via the diagramming system" "4616": "Increase our debug_event array to 2*64*65536 (544 MiB)" "4630": "Again overflow the debug_event array via the diagramming system" "4676": "Decrease our debug_event array to 2*16*65536 (136 MiB)" "4690": "Step in to DIAGRAM_Reset() and through to diagramming calls" "4776": "Determine to limit our diagramming to a particular entity" "4880": "Set up AppendDiagramEntry() to conditionally push on a diagram_entry" "4981": "Run in -Od without overflowing the debug_event array" "4985": "Run in -O2 without overflowing the debug_event array" "5004": "Introduce DIAGRAM_SetFilter() and DIAGRAM_Filter(), augmenting diagram_group with Filter and FilterPassed values" "5277": "Run without overflowing the debug_event array" "5333": "Disable the debug visualisation in the entity system" "5437": "Q&A" "5476": "Q: Do you know about WebView2?" "5542": "Q: What's sphere roll-off?" "5589": "Q: You made a note about rewinding a memory arena? Does a rewind free the allocation?" "5661": "Q: Shouldn't we add spatial partitioning for collision and such at this point?" "5719": "Q: You mentioned you are doing memory arenas differently now. What are you doing differently?" "5767": "Q: In the early videos you were mentioning if the series got enough attraction, you could probably look into adding networking features. What is your stance on this now?" "5812": "Q: Why did you forward-declare the diagram functions in the header file? I thought you did the unity build system so you didn't need to do that kind of thing. Unless the #include order requires it?" "5913": "Q: Off-topic: Do you know any particular reason why MSVC would optimize a piece of code better with /Ox instead of /O2 (2x speed-up)?" "5960": "Plug godbolt" "6148": "Q: Sorry but what do you mean by grow linearly? Is that like reallocating so it's contiguous?" "6182": "Q: (cont.) No, the code performs better with /Ox and not /O2 which doesn't make sense to me because /O2 enables more optimizations" "6342": "Q: Would it be possible to render all of the unfiltered N-squared diagrams if the number of debug events was huge? Or are there just way way too many diagrams for that?" "6425": "Recommend making a highly optimised debug system as a project" "6492": "Q: What do you use to build on Linux?" "6511": "Q: Do you know that Sean Barrett is writing a C compiler. Are you going to use it?" "6532": "Q: Any build system? Or just .sh files?" "6561": "Wrap it up with a glimpse into the future" --- name: "day639" title: "Drawing Debug Diagrams" markers: "0": "Recap and set the stage for the day" "88": "Conditionally define HANDMADE_DIAGRAMS to HANDMADE_INTERNAL" "121": "Prepare to draw our diagrams" "201": "Demo the debug overlays and plan our diagram drawing and filtering" "571": "Determine to move the entity debug visualisation into the diagramming system" "678": "Change MoveEntity(), RefineVoxelPlacement() and UpdateBest() to use our diagramming system, introducing a version of DIAGRAM_Color() that takes R, G and B separately" "1061": "Our old debug visualisation is gone" "1092": "Force AddPlayer() to let the glove pass our diagramming filter" "1181": "Hit an assertion on DEBUG_RECORD_ALLOCATION() via a DIAGRAM_Text() call in ShapesCollide()" "1259": "Investigate our DEBUG_RECORD_ALLOCATION() assertion hit" "1322": "Try disabling the diagramming in ShapesCollide()" "1347": "No longer hit that DEBUG_RECORD_ALLOCATION() assertion" "1384": "Add an assertion in RenderDiagrams()" "1438": "Never hit that assertion in RenderDiagrams()" "1446": "Make UpdateAndRenderWorld() call RenderDiagrams()" "1504": "Implement RenderDiagrams()" "1819": "Consider not buffering the diagrams" "1951": "Continue to implement RenderDiagrams()" "2032": "Our glove's collision diagrams are not drawn" "2045": "Quickly sanity check the diagramming code" "2072": "Make RenderDiagrams() reset the Current diagram_attributes upon finishing the Diagram_Box case" "2106": "Step through RenderDiagrams()" "2281": "Our glove's collision diagrams are drawn after all, in -Od" "2326": "Our glove's collision diagrams are also drawn in -O2" "2344": "Decrease Sticky.Thick from 0.1f to 0.01f in RenderDiagrams()" "2362": "Our diagramming system is in action" "2419": "Implement the Diagram_Line case in RenderDiagrams()" "2534": "Change the v3 Color in diagram_attributes to be a v4, augmenting diagram_entry with separate Color and Thick values" "2626": "Implement the Diagram_Point case in RenderDiagrams()" "2715": "Reacquaint ourselves with our text rendering" "3030": "Fix RenderDiagrams() to pass RenderGroup->WhiteTexture to PushCube()" "3076": "Enable diagramming in ShapesCollide() when its Result is true" "3144": "Try out our collision-based diagramming" "3182": "Consider putting filtering into the system" "3250": "Diagramming in The Witness: Capturing diagrams over multiple frames" "3417": "Interpret our collision-based diagramming" "3579": "Determine to add a "Capture" button to remember diagrams, which we may then "Step" through" "3657": "Augment diagram_group with a Captured boolean, introducing DIAGRAM_Capture()" "3836": "Add a "Capture" / "Resume" button in CollisionEditor(), introducing DIAGRAM_IsCaptured()" "4030": "Try out our "Capture" button" "4112": "Remove SingleStep and StepLatch from game_mode_world" "4166": "Meow" "4309": "Reinstate SingleStep and StepLatch in game_mode_world" "4337": "Try "Single Stepping"" --- name: "day641" title: "Voxel Flood Fill for Collision Search" markers: "0": "Recap and set the stage for the day" "201": "Direct vs path-solved collision voxel movement" "304": "Path solvers: Dijkstra, A*" "374": "Turning our collision system into more of an A* style search" "445": "Describe the direct-descent collision in MoveEntity()" "593": "Begin to switch MoveEntity() to do flood fill collision search, separating out the Collision testing and Movement loops" "1006": "Conceptualising flood fill" "1181": "Stack up the voxels to test for collision tracking purposes in MoveEntity()" "1582": "Automatic stacking by proximity" "1648": "Respecify UpdateBest() as PushVoxelCheck() in MoveEntity()" "1818": "Consider checking voxels more efficiently" "2044": "Make MoveEntity() consider the voxels in only the six 3D cardinal directions" "2619": "Consider how to produce the closest point" "2727": "Note our possible inability to use GetClosestPointInBoxConservative() for LocalFromP" "2752": "Consider how to produce the closest point (cont.)" "2876": "Introduce a voxel_stack and helper functions: PushVoxelStack() and PopVoxelStack()" "3387": "Meow" "3452": "By the way, does anyone here know why the sphere collision geometries should help sliding around corners with "Search in P"?" "3562": "Make MoveEntity() call PushVoxelStack()" "3624": "Introduce PopVoxelStack()" "3666": "Note an optimisation in PushVoxelStack(): Known early termination" "3777": "Implement PopVoxelStack(), and introduce StackNotEmpty() for MoveEntity() to call" "4029": "Consider how to handle embedding, in our flood search scheme" "4133": "Plan our next steps in MoveEntity()" "4175": "Delete UpdateBest() and voxel_move" "4218": "Specify how MoveEntity() accepts motion" "4497": "Consider our problem with GetClosestPointInBoxConservative()" "4620": "Fix compile errors in MoveEntity()" "4669": "Consider caching the collision voxel checks" "4746": "Make MoveEntity() set up the collision voxel stack" "5112": "Reflect on the current state of our flood search routine" "5160": "TODO(casey): We should use the minimum grid size necessary to bound the from/to points..." "5220": "Q&A" "5225": "Make MoveEntity() compute and use the minimum grid size necessary to bound the from / to points" "5710": "Q&A for reals" "5764": "Q: Does your in-house editor cache tokens for a buffer and keep them around? I have my incremental tokenization but the memory overhead is pretty gross and unnecessary. I'm thinking of just fully caching line states (like whether you're in a block comment or not) and then caching only N lines of tokens with LRU eviction or something. I have a suspicion I am just overcomplicating things" "5793": "Q: PushVoxelStack has typo two times: double I.z?" "5801": "Fix typos in PushVoxelStack()" "5806": "Caching considerations in parsing" "6010": "Q: What do you think about using Search in P in games with movement that should feel "physically correct" (gravity, jumping, etc.)? Is there an extension of your work on The Witness that would work well there, or would you go with a classical approach like GJK or MPR?" "6321": "handmade_hero parsing is definitely what has made this text editor feel like a mistake. I figured I might as well follow through making it because of how easy it is to improve upon the functionality of my daily driver (vim), but text editing is definitely sad. I had been retokenizing fully on every edit but it got too slow especially when making multiple edits on a single keystroke (for example with multiple cursors)" "6486": "Jon's streaming today, or at least he is right now" "6508": "Q: How would one store text instead?" "6603": "So books are okay as text? But program files would need some sort of idea about discrete chunks, i.e. structs, functions, whatever?" "6698": "How much does compression help with this? Doesn't compression map it better?" "6742": "What is the alternative?" "6949": "Q: So a C/C++ file just with free functions and no declarations / definitions between these functions is pretty much random access?" "7000": "So C files would have all the defines in a separate data area?" "7057": "Q: So the JSON format is also bad in that sense because it is a text format?" "7128": "But if code is in, let's say AST, you won't be able to use any text editor to modify it. You will need some specific software" "7183": "Q: You should get the new Remedy if you have not already. It has some nice stuff" "7247": "Remedy 0.3.6 was pretty crashy for me when I was on my laptop" "7285": "Are there any editors or programming languages that don't use text and can highlight gigabyte files currently?" "7353": "Q: What happened to RAD Game Tools. Did Epic Games buy the company?" "7418": "If you still worked at RAD would you have got a massive bag of cash?" "7623": "Q: How is the sale platform for SCG progressing?" "7802": "Jonathan raid yay" "7909": "Thoughts on e-commerce server engineering when your payment processor is, and is not, reliable" "8065": "Q: How do you even test your code against an unreliable payment processor?" "8204": "The whole idea of crypto is decentralizing "trust"" "8378": "Yeah, after an economic collapse, people still still have GPUs going on crypto, they won't just be fighting over food and water" "8434": "Q: Can you make your cam bigger for the Q&A?" "8465": "Have we had a Casey rant about NFTs yet?" "8558": "It isn't even that because at no step in creating an NFT you cannot confirm the person creating it actually owns the item" "8798": "handmade_hero Then you can say the same for any art. What are they solving? What is the painting that is hanging in my room solving?" "8979": "With Mona Lisa, they actually hang fakes intentionally most of the time, so they don't get damaged by all the jerks taking flash photography nonstop" "9042": "I was very surprised how small the Mona Lisa was, when I saw it. Popular media always depicts it as bigger" "9072": "handmade_hero It is an appreciation and value of the creation. If I would create the exact game of yours after two years from publication, no one would buy it. I would say there is an appreciation to creation in society which makes the original piece valuable" "9162": "NFTs produce a lot of excess CO2" "9204": "Totally agree with value being subjective to the person buying the art. How does this tie into supporting the artist? Don't NFTs help there?" "9252": "handmade_hero What about using NFT for creating a digital used market? I can't sell you a game I bought off steam" "9334": "Hey, the idea to want to be close to the actual thing that da Vinci touched with his hands is somewhat relatable. Not important for everybody, but it's certainly not "arbitrary"" "9596": "MaIlchad No it's because I'm interested in the history of certain pieces of art. If that's "arbitrary" then so is anything else you value" "9759": "How did Avengers create value to society? If anything it has negative value because it stole two hours of people's lives they could have used to create actual value" "9870": "handmade_hero What should be the price of Mona Lisa? Every copy of Mona Lisa should be 1 million, then, or should all be 1 dollar including original?" "10021": "handmade_hero This sounds like tulips bubble or more recent coin bubble, or more recent crypto bubble" "10095": "So how much can I buy the Wacom tablet for that da Vinci painted the Mona Lisa with?" "10115": "Assuming the great masters all used an iPad Pro, would they all have been arrested for child porn after Apple flagged them?" "10255": "handmade_hero If the value of art is arbitrarily decided by people, why can't originality be arbitrarily chosen as valuable?" "10484": "Yeah, instead of curating and verifying priceless art, they should be doing something productive like making a videogame!" "10586": "Pyramids are pretty damn useless and quite permanent" "10632": "Closing thoughts about energy wasted on NFTs and cryptocurrencies" "10794": "Crypto also carries anti-bank, anti-government ideological strain" "10891": "handmade_hero The payment processors aren't the government, though, they're a private institution who don't own a military and couldn't stop something like crypto" "10933": "handmade_hero By that argument, having passwords is useless, because a robber can make you type the password by force" "11072": "With crypto, governments technically can't confiscate your money (without torturing passwords out of you). They can make it very difficult to spend that money" "11108": "handmade_hero But couldn't society decide that we switch to crypto for our currency, and change the laws accordingly?" "11224": "Oh yeah, turns out that's not true: blockchain is public, if you know the size of the transaction and when, you can trace it back quite quickly" "11259": "That's it" --- name: "day642" title: "Debugging Voxel Collision Bounds" markers: "0": "Recap and set the stage for the day" "63": "Demo our incomplete collision detector" "209": "Reacquaint ourselves with the collision detector in MoveEntity()" "319": "Thoughts on allowing for buggy gameplay code" "543": "Reacquaint ourselves with the collision detector in MoveEntity() (cont.)" "704": "A* and Dijkstra's algorithm" "1009": "handmade_hero Dijkstra?" "1022": "Dijkstra's algorithm seems like a bad name when the guy created, like, 50 algorithms" "1128": "Reacquaint ourselves with the collision detector in MoveEntity() (cont.)" "1219": "TODO(casey): We should probably store corners and only test when they are untested" "1332": "Reacquaint ourselves with the collision detector in MoveEntity() (cont.)" "1383": "Photolithography machines manufacturer ASML is also Dutch, supplying TSMC and Samsung" "1387": "If you tell me your name and date of birth my brain will actually process what you sound like" "1410": "Dutch national pride" "1595": "TODO(casey): We need to think through the way we handle embedding…" "1657": "Reacquaint ourselves with the collision detector in MoveEntity() (cont.)" "1741": "Investigate why the glove did not move" "1805": "The glove's collision search doesn't go beyond the "home" voxel" "1882": "Make MoveEntity() diagram the full voxel span" "1993": "The glove's collision search doesn't touch the full voxel span" "2046": "Make MoveEntity() diagram the line from FromP to ToP" "2063": "The glove's full voxel span does not encompass the whole line from FromP to ToP" "2110": "Make MoveEntity() colour in grey the line from FromP to ToP" "2116": "Clean out old code from MoveEntity() and correctly set the VoxelEndingCorner" "2365": "The glove's full voxel span correctly encompasses the whole line from FromP to ToP" "2398": "Start to investigate why the flood search doesn't work" "2448": "Make MoveEntity() diagram the tested voxel" "2512": "The glove's collision search tests one cell" "2524": "Investigate why MoveEntity() never calls PushVoxelStack() in the "Flip" loop" "2640": "Step in to MoveEntity()" "2674": "Flip the Occupied tests in MoveEntity()" "2720": "Step in to MoveEntity() to find that it now calls PushVoxelStack()" "2733": "Our glove's collision flood search now permits movement" "2748": "Our collision erroneously permits embedding and corner roll-off doesn't happen" "2829": "Increase the collision search space by one voxel in MoveEntity()" "2870": "Our corner roll-off now works" "2880": "We must fix embedding and performance" "2909": "Plan to fix embedding" "2988": "Plan to fix embedding: 1) Track tested voxel corners" "2998": "Plan to fix embedding: 2) Track embedding, to prevent movement to an embedded cell" "3060": "Disable the embedding recovery code in MoveEntity()" "3077": "Our collision still permits embedding" "3085": "Scrutinise MoveEntity() for code that permits embedding" "3218": "Make MoveEntity() test for embedding before considering a cell" "3269": "Our collision still permits embedding" "3309": "Scrutinise MoveEntity() for code that permits embedding" "3339": "Fix the embedding test loop in MoveEntity() to use Cell.Min" "3371": "Our collision now prevents embedding" "3399": "Our glove gets stuck on a corner" "3451": "Relieve MoveEntity() of testing for embedding before considering a cell" "3467": "Our collision continues to prevent embedding, but we can get stuck in the doorway" "3571": "Optimising the collision routine" "3637": "Let MoveEntity() early-out of the collision voxel pushing loop if BestDistanceSq == 0" "3675": "Our glove can get embedded in the hero" "3702": "Our collision flood search tests all voxels in a clear straight line" "3800": "Determine to push collision voxels closest-first" "3871": "Determine to improve our early-out condition in MoveEntity()" "3932": "Change MoveEntity() to early-out if the BestCellI and TargetCellI match, introducing ClampToVoxelDim()" "4117": "Our collision is more efficient" "4152": "Rephrase the collision voxel expansion in MoveEntity()" "4200": "The glove can penetrate right through the wall" "4234": "Scan MoveEntity() for code that permits through-embedding" "4260": "The glove can penetrate right through the wall when turning" "4300": "Scrutinise MoveEntity() for code that permits embedding" "4353": "Try to single-step the collision detector" "4493": "Walk into the wall, getting the glove embedded" "4543": "Introduce Round() for MoveEntity() to use when setting VoxelStartingCorner and VoxelEndingCorner" "4820": "Our glove's and the expanded collision search voxels are not aligned" "4875": "Investigate our voxel misalignment in MoveEntity()" "4928": "Revert MoveEntity() to use Floor() when setting VoxelStartingCorner and VoxelEndingCorner" "4968": "Increase the VoxelMaxCorner by 2× the CellDim" "5015": "Our performance has tanked" "5045": "Reduce VOXEL_STACK_DIM from 16 to 8" "5066": "Our collision voxels remain misaligned" "5150": "Change MoveEntity() to include the starting point, factoring in a DeltaPClamp to the VoxelEndingCorner" "5504": "Our collision search bounds and embedding are improved" "5576": "Continue to optimise the collision routine, augmenting voxel_stack with Repulsion and introducing voxel_corners and CheckCorners() for MoveEntity() to use" "6769": "Hit an assertion on CornerI in CheckCorners()" "6812": "Rephrase assertions in CheckCorners()" "6846": "Add assertions in CheckCorners on the incoming CellI dimensions" "6918": "Hit an assertion on CellI in CheckCorners()" "6928": "Investigate our out-of-bounds collision voxel push in MoveEntity()" "7012": "Respecify MaxVoxelDim as MaxDeltaDim in MoveEntity()" "7053": "Hit an assertion on CellI in CheckCorners()" "7063": "Continue to investigate our out-of-bounds collision voxel push in MoveEntity()" "7098": "Change MoveEntity() to use FloorToV3S() when setting VoxelDim" "7114": "Hit an assertion on CellI in CheckCorners()" "7129": "Add assertions on the VoxelDim in MoveEntity()" "7164": "Hit an assertion on VoxelDim in MoveEntity()" "7184": "Run in -Od, hit an assertion on VoxelDim in MoveEntity() and inspect the values" "7313": "Fix our assertions on the VoxelDim in MoveEntity()" "7328": "Hit an assertion on VoxelDim in MoveEntity() and inspect the values" "7407": "Decrease the MaxDeltaDim by 3 per axis in MoveEntity()" "7419": "No longer hit that assertion on VoxelDim in MoveEntity()" "7442": "Run in -O2, and no longer hit that assertion on VoxelDim in MoveEntity()" "7474": "Corner roll-off now works, we no longer embed, but we can still get stuck on corners" "7624": "TODO(casey): Do initial check to see if we're embedded..." "7672": "Q&A" "7764": "Q: Polling raw input make it reasonable to give it a coincidence that we do not worry about the nail salon?" "7828": "handmade_hero, insobot has cheered me up, but I've been real down on programming lately. Have you ever had a phase where you were just totally over computers?" "8184": "Q: Do you think it is safe to assume if a CPU has AVX2 it has FMA, or should I always check the cpuflags? I'm not sure where to look if such a thing is true" "8479": "Ya, I was wondering if all AVX2 CPUs on the market have the FMA extensions because all two of mine have them" "8962": "We're done" --- name: "day644" title: "Stepping Through Diagrams" markers: "0": "Recap and set the stage for the day" "20": "Try to reproduce our tunnelling bug" "156": "Hit a corner embedding bug" "312": "Diagramming displacement upon camera re-centering" "640": "Double-check that we checked Day 643" "681": "Consider re-centering the debug visualisation with the camera" "791": "Introduce OffsetDebugDiagrams() for UpdateAndRenderWorld() to call" "1068": "Reacquaint ourselves with the lighting re-centering code" "1210": "Unify the camera offset, introducing DIAGRAM_SetOrigin() and augmenting diagram_group with LastOriginP" "1669": "Our diagram offsetting is slightly off" "1678": "Fix the Diagram_Sphere case in DIAGRAM_SetOrigin()" "1707": "Our diagram offsetting remains slightly off" "1716": "Invert the Offset computation in DIAGRAM_SetOrigin()" "1742": "Our diagram offsetting remains slightly off" "1766": "Investigate our incorrect offsetting in DIAGRAM_SetOrigin()" "1969": "Revert the orientation of the Offset computation in DIAGRAM_SetOrigin()" "1984": "Try to understand our offsetting incorrectness" "2137": "Investigate our incorrect offsetting in DIAGRAM_SetOrigin() (cont.)" "2228": "Step in to DIAGRAM_SetOrigin()" "2351": "Make DIAGRAM_SetOrigin() offset the diagrams when LastOriginP and OriginP differ" "2387": "Our diagram offsetting is now perfect" "2430": "Demo the need for stepping through diagrams" "2491": "Plan to support stepping through diagrams" "2595": "Enable RenderDiagrams() to filter diagrams" "3267": "We see no diagrams" "3281": "Make RenderDiagrams() initialise ShouldDraw to true" "3301": "We see diagrams" "3308": "Discover 4coder Fleury right-clicking purple" "3370": "Make CollisionEditor() create diagram filter hierarchy stepping buttons" "3709": "Try out our diagram filter buttons" "3758": "Make CollisionEditor() draw the Up / Down buttons on the same line" "3783": "Try out our diagram filter buttons" "3798": "Make CollisionEditor() create a diagram stepping slider" "3910": "Hit a read access violation in EditablePx()" "3930": "Fix CollisionEditor() to only create the diagram stepping slider when valid" "3946": "Try out our diagram stepping slider" "3968": "Fix CollisionEditor() to print the filter max depth as a u32" "3988": "Try out our diagram stepping slider" "4031": "Scour RenderDiagrams() for bugs" "4129": "Reduce the verbosity of RenderDiagrams()" "4165": "Scour RenderDiagrams() for bugs (cont.)" "4223": "Fix RenderDiagrams() to set whether we ShouldDraw a filter level, before preparing ShouldDraw for the next filter level" "4243": "Try out our diagram filtering buttons and stepping slider" "4316": "Make EditablePx() take a specified dX value" "4378": "Try out our more precise diagram stepping slider" "4394": "Surpassing the total diagram count is problematic" "4442": "Scour RenderDiagrams() for diagram stepping bugs (cont.)" "4535": "Make RenderDiagrams() assert that DiagramDepth ends up 0" "4555": "Hit that assertion in RenderDiagrams()" "4561": "Check if our DIAGRAM_Begin() and DIAGRAM_End() calls are balanced" "4633": "Hit that assertion in RenderDiagrams() and see that DiagramDepth ends up 1" "4750": "Consider how best to balance the DIAGRAM_Begin() and DIAGRAM_End() calls in the "Collision Voxel" loop of MoveEntity()" "4902": "Balance the DIAGRAM_Begin() and DIAGRAM_End() calls in the "Collision Voxel" loop of MoveEntity()" "4949": "Still hit the DiagramDepth == 0 assertion in RenderDiagrams()" "5004": "Double-check that our DIAGRAM_Begin() and DIAGRAM_End() calls are balanced" "5063": "Try unsuccessfully to hit our DiagramDepth == 0 assertion in -Od" "5142": "Hit the DiagramDepth == 0 assertion in -O2 and see from the asm that DiagramDepth ends up 1" "5196": "Double-check that our DIAGRAM_Begin() and DIAGRAM_End() calls are balanced" "5252": "Fix MoveEntity() to call DIAGRAM_End() before DIAGRAM_Capture()" "5278": "Try stepping through our diagrams" "5371": "Scour RenderDiagrams() for diagram filtering bugs" "5483": "Fix RenderDiagrams() to reset the DiagramIndex to 0 on Diagram_End" "5527": "Try stepping through our diagrams at various filter levels" "5689": "Try setting FundamentalUnit to 1.375 in PlayWorld(), to make that and MOTION_DISPLACEMENT_SIZE well-defined in relation to each other" "5820": "Our glove still gets stuck" "5834": "Our simulation centres don't move by an even amount" "5872": "Consider fixing our collision voxel sliding issue" "5897": "Reacquaint ourselves with the simulation centering code in UpdateCameraForEntityMovement()" "5957": "Consider rounding the SimulationCenter to the FundamentalUnit" "6064": "Revert the FundamentalUnit to 1.4 in PlayWorld(), and make UpdateCameraForEntityMovement() round the SimulationCenter to the MOTION_DISPLACEMENT_SIZE" "6142": "No longer hit that camera movement-based sticking bug" "6189": "Embed in a wall, and step through the diagrams" "6288": "Introduce AlignToMovementVoxel() for UpdateCameraForEntityMovement() to call" "6492": "Reflect on our diagram stepping" "6543": "Hit a collision detection bug" "6602": "Investigate our collision detection bug" "6695": "Reproduce a collision detection bug" "6749": "Consider enabling ShapesCollide() to dump the diagram data" "7034": "Q&A" "7055": "Maybe it's a gigantic box and not a little one?" "7069": "Q: Could it be the hero's head? Odd it's not drawing it" "7091": "Q: Can we move diagonally in the game?" "7105": "Q: Can we not write somewhere like in the debug output the box P and size?" "7167": "Q: Is the refinement still running?" "7183": "Q: So is the bug that it got this bug in the corner and then it got launched into the wall, explaining the tunneling?" "7197": "Q: Do we still use the entity cache system? I remember it was a cool thing introduced in Handmade Hero" "7245": "Q: So you don't think the mystery box pushed it into the wall?" "7317": "Q: Maybe the opposite is happening here: It's colliding then the camera is moving?" "7323": "Try to reproduce our collision detection bug" "7512": "Q: We can ask general questions now?" "7533": "Try to reproduce our collision detection bug (cont.)" "7560": "Step through the diagrams of our collision detection bug" "7731": "Q: What is that line going off to the left?" "7774": "Q: Are the direction indicators normalised? Any way to also visualise the magnitude?" "7900": "Investigate the possibility of us having an inverted phantom box" "7949": "Assert in ShapesCollide() that each box HasArea()" "7984": "Hit our assertion in ShapesCollide()" "8017": "Hit our assertion in ShapesCollide() in -Od and inspect the phantom boxes" "8104": "Make CollidesAtP() only check for collisions if the TestEntity->CollisionVolume HasArea()" "8204": "Provisionally consider our collision detection bug to be fixed" "8306": "Wrap it up with a plug of Meow the Infinite: Book Two" "8386": "Your camera is still flipped. Meow is backwards" "8419": "Finish wrapping it up with the determination to see what those phantom entities were, and plugs of the Cryptocurrency interviews and Babylon 5 season one recap with Jonas Kyratzes" --- name: "day645" title: "Switching to Voxel Centers for Collision" markers: "0": "Recap and set the stage for the day" "74": "Consider: 1) Giving entities a "participates in collision" bitfield" "104": "Consider: 2) Is the world generator erroneously creating entities without a collision volume?" "112": "Consider: 3) Finishing the collision system, with embedding recovery and spatial partitioning" "324": "Demo our unoptimised collision performance" "439": "Step through the diagrams of a collision embedding bug" "560": "Consider making the collision checks symmetric" "843": "Consider snapping the entity's position to the voxel center before testing for collision" "890": "Reproduce an embedding bug between the glove and familiar" "992": "Set up to perform collision on discrete boundaries" "1083": "Consider switching to voxel centers for collision" "1250": "Switch to voxel centers for collision, modifying voxel_stack" "1361": "A few words on feeling stupider vs smarter than you are" "1423": "Respecify voxel_corners as voxel_center" "1455": "Consider our collision testing to be faster and symmetric, once it's switched over" "1506": "Switch MoveEntity() to use voxel centers for collision, changing AlignToMovementVoxel() to use Round()" "2011": "Introduce GetMovementVoxelIndex() for MoveEntity() to use, and remove voxel_grid from voxel_stack" "2254": "The problem with feeling stupid is that it can make you want to quit. While feeling smart makes you want to keep going" "2313": "Continue switching MoveEntity() to use voxel centers, relieving it of checking corners" "2531": "Make PushVoxelStack() call CollidesAtP()" "3023": "Augment voxel_stack with a MinCenterP for MoveEntity() to set" "3102": "Introduce GetVoxelCenterP() for MoveEntity() to call, removing the voxel iterator" "3248": "Change PushVoxelStack() to call IsInArrayBounds() and use HaveTested" "3551": "Remove CheckCorners() and change MoveEntity() to call GetVoxelCenterP()" "3602": "Introduce GetVoxelBounds() for MoveEntity() to call" "3724": "Consider cleaning up this code" "3775": "Our voxel center-based collision runs first time" "3844": "Let UpdateAndRenderEntities() call PushCube(), to draw the walls" "3886": "Try out our voxel center-based collision" "3919": "Determine to clean up this code" "4035": "Make MoveEntity() pass GetVoxelCenterP() as FromP to RefineVoxelPlacement()" "4119": "Clean up the PushVoxelStack() branch in MoveEntity()" "4358": "Enable PushVoxelStack() to handle embedding recovery" "4872": "Replace the voxel_stack's b8 HaveTested with u8 OccupyCode, for MoveEntity() to pass to PushVoxelStack(), introducing GetOccupyCode()" "5042": "Enable PushVoxelStack() to handle embedding recovery (cont.)" "5183": "Remove embedding repulsion code from MoveEntity(), and search for the nearest unoccupied position around the initial embedded position, introducing occupy_code" "5461": "Try out our collision and embedding recovery" "5560": "Make CollidesAtP() call AlignToMovementVoxel() on each TestEntity" "5629": "Try out our collision detector" "5727": "Make CollisionEditor() create a "Disable Diagrams" button" "5842": "Try out our "Disable Diagrams" button" "5861": "Augment diagram_group with CaptureFrameCount and make CollisionEditor() create a "Capture Frames" slider to set this value" "6022": "Try out our "Capture Frames" slider" "6077": "Try out our collision detector" "6172": "Q&A" "6198": "Chat was too quiet this stream" "6245": "Q: Can you explain the issue with two objects colliding again? Does using voxel centers fix it?" "6386": "Q: Do you have chat set to subscriber only again?" "6401": "How much verticality is there going to be? Because gameplay-wise you may end up restricting collision to a plane, and then maybe this would all be a lot simpler" "6428": "Q: Won't that result in clipping?" "6480": "If you check based on the center then adjust the position, then you can have sprites appearing inside walls" "6581": "Q: Did you know you can set enum types now. Just ': type' after the name. It still has to be integral" "6638": "Try using : u8 on occupy_code" "6736": "Q: Do you recommend this book "Tricks of the Windows Game Programming Gurus" by André Lamothe in 2021?" "6779": "Q: What is the reason that things like SimRegion get passed around instead of plucking it from a global variable? Is it just preference? Are there cache considerations?" "6914": "Wrap it up with a plug of Meow the Infinite: Book Two and further streams" "7126": "Man, I've been loving these lightboard code talks. I would pay good money for more of these. I think you've got a good concept here!" "7208": "Q: Does Handmade Hero work on Linux or do I need to follow on Windows?" "7245": "Plug Star Code Galaxy" "7549": "Wrap it up with a plug of an upcoming cryptocurrency interview with Alex Gladstein" --- name: "day646" title: "Removing Z from Lighting" markers: "0": "Welcome to the stream, with admiration of our lighting" "52": "Consider lighting improvements, e.g. speeding up our long-term average blend" "98": "70% frame time on ComputeLightPropagationWork" "170": "Moving to 2D lighting" "181": "Moving to 2D lighting: 1) Eliminating Z-stacking" "197": "Reducing the lighting voxel memory footprint" "420": "Decrease LIGHT_LOOKUP_VOXEL_DIM_Z from 16 to 1" "441": "Check the ramifications of removing Z from the lighting" "891": "Toggle on lighting voxel drawing in PushLightingRenderValues()" "961": "Our world is completely black" "989": "Increase LIGHT_LOOKUP_VOXEL_DIM_Z from 1 to 8" "994": "Our world is lit" "1006": "Decrease LIGHT_LOOKUP_VOXEL_DIM_Z from 8 to 4" "1014": "Our world remains lit" "1017": "Decrease LIGHT_LOOKUP_VOXEL_DIM_Z from 4 to 2" "1029": "Our world remains lit" "1034": "Decrease LIGHT_LOOKUP_VOXEL_DIM_Z from 2 to 1" "1042": "Is the voxel too thin to pick up light sources?" "1063": "Increase LIGHT_LOOKUP_VOXEL_DIM_Z from 1 to 2" "1072": "Consider keeping the lighting voxel 2-high, with vertical movement sampling fixed" "1154": "Plan our Z-elimination strategy" "1309": "Try making UpdateLighting() zero out all the incoming Z-values" "1356": "Our lighting bounds are relatively too low, but tall enough" "1443": "Check the call stack of UpdateLighting() for sources of Z" "1519": "Prevent UpdateLighting() from zeroing out all the incoming Z-values" "1526": "Check where to clamp Z" "1670": "Toggle on WorldCameraRect drawing in UpdateAndRenderWorld()" "1686": "Check out our camera and lighting volumes" "1759": "Make UpdateAndRenderWorld() draw a -1 to 1 origin cube" "1805": "Check out our -1 to 1 origin cube" "1875": "Determine to lock the simulation center Z" "1985": "Try making UpdateCameraForEntityMovement() set SimulationCenter.Z to 0" "2009": "The game looks good" "2020": "Consider drawing the simulation region" "2049": "The simulation region does not follow us downstairs" "2103": "Make UpdateAndRenderWorld() zero out the LightingCenter.ChunkZ and LightingCenter.Offset_.z" "2175": "The camera bounds wobble" "2264": "Assert in UpdateLighting() that Z is 0" "2334": "Never hit our assertions in UpdateLighting()" "2367": "Consider making Z == 0 the lowest point in the world" "2449": "Consider Z simplifications" "2550": "Reacquaint ourselves with the alignment code in UpdateLighting" "2625": "Determine to keep Z == 0 at the center point" "2757": "Make GetTotalVolume() offset the MinP negatively by half a tile" "2898": "Our world is lit again" "3016": "Make GetTotalVolume() zero out the MinP.Z" "3072": "Our world looks fine, but the lighting and camera are offset" "3099": "Investigate why the camera is incorrectly positioned" "3267": "Make UpdateAndRenderWorld() set FocusZ to 0" "3286": "Our camera remains incorrectly positioned" "3305": "Reacquaint ourselves with FocusZ relativity" "3397": "Simplify the FocusZ values in game_camera down to ExpectedFocusZ" "3710": "Make UpdateAndRenderWorld() compute ExpectedFocusZ" "4158": "Our camera remains incorrectly positioned" "4177": "Reacquaint ourselves with GetCameraRectangleAtDistance()" "4247": "Break in to UpdateAndRenderWorld() in -Od, and inspect CameraZ and DeltaFromSim" "4390": "Reacquaint ourselves with UpdateCameraForEntityMovement()" "4530": "Break in to UpdateCameraForEntityMovement(), and never enter the InRoom branch" "4564": "Reacquaint ourselves with the procedural generation code in terms of Z" "4795": "Make BeginGridEdit() enlarge rooms by 5 units in Z" "4852": "Enter the InRoom branch in UpdateCameraForEntityMovement()" "4863": "Our camera is now correctly positioned, and our frame rate is far higher" "4900": "~30% frame time on ComputeLightPropagationWork, but our fogging is incorrect" "4985": "Make UpdateAndRenderWorld() set the camera's fogging FocusMinZ and FocusMaxZ based on the ExpectedFocusZ" "5095": "Our focused level is no longer fogged out" "5128": "Determine to position light probes relative to the floor and ceiling" "5236": "Make UpdateLighting() call DebugDrawOctahedralValues()" "5354": "Hit a read access violation on DebugDrawColorDir()" "5393": "Hit a read access violation on Texel.Value in DebugDrawColorDir() in -Od" "5436": "Fix DebugDrawOctahedralValues() to account for our "Z-less" world" "5483": "Run correctly" "5501": "Check out our light probes in -O2" "5546": "Try letting DebugDrawOctahedralValues() draw all the light probes" "5561": "Hit our "overflow" assertion in PushQuad()" "5564": "Try making DebugDrawOctahedralValues() draw half the light probes" "5574": "Check out our light probes, with potential bugs" "5648": "Make UpdateAndRenderEntities() draw the colliders" "5684": "Based on the colliders, our light probes look buggy" "5863": "Reflect on our lighting simplifications, and consider next steps" "6000": "Consider removing spatial partitioning of our 2D lighting grid, raycasting directly on it" "6205": "Determine to investigate our buggy light probes" "6324": "Force all light probes through the not-inside branch in FullCast()" "6353": "Those buggy light probes now pick up light" "6372": "Let light probes enter the inside branch in FullCast()" "6392": "Consider debugging versus simplifying the spatial partition for raycasting" "6600": "Simplifying raycasting spatial partition: 1) Removing Z" "6612": "Simplifying raycasting spatial partition: 2) Turning it into a grid" "6628": "Plan to remove Z from GridBuildSpatialPartition()" "6876": "Step in to UpdateLighting() and inspect the VoxCellDim and SpatialCellCount" "7072": "Make UpdateLighting() set the AtlasToSpatialGridIndexOffset.Z to 0" "7127": "Make PushLightingRenderValues() draw the spatial grid" "7147": "Our spatial grid is too low" "7179": "Make UpdateLighting() give the spatial grid three layers of height" "7238": "Our spatial grid remains too low" "7253": "Reacquaint ourselves with the spatial grid alignment code" "7313": "Make UpdateLighting() offset the spatial grid in Z by a third of the usual amount" "7332": "Our spatial grid is now correctly aligned" "7365": "Remove the Z loop from ComputeWalkTable(), respecifying GetOctantFor() as GetQuadrantFor()" "7818": "Hit our assertion in GetQuadrantFor()" "7876": "Make FullCast() zero out the Remainder.z" "7907": "Our quadrant table should be being computed correctly" "8037": "Step through FullCast() watching that HalfAtlasIndex.z remains 0" "8161": "Determine to inspect the spatial partition" "8224": "Disable light probe direction drawing in DebugDrawOctahedralValues()" "8253": "Check out our light probe boxes" "8264": "Try making DebugDrawOctahedralValues() draw all the light probes" "8278": "Check out our complete set of light probes" "8286": "Relieve UpdateAndRenderEntities() of drawing the colliders" "8295": "Check our set of debug visualisation" "8311": "Introduce DebugDrawSpatialGrid() for UpdateLighting() to call" "8494": "Check out our spatial grid, with eight probes per cell" "8582": "Make DebugDrawSpatialGrid() checkerboard the spatial grid colouring" "8667": "Check out our checkerboard spatial grid" "8678": "Make DebugDrawSpatialGrid() enlarge the cells slightly" "8743": "Check out our enlarged checkerboard spatial grid" "8770": "Fix DebugDrawSpatialGrid() to shrink the cells" "8782": "Check out our shrunken checkerboard spatial grid" "8807": "Make DebugDrawSpatialGrid() draw the leaves" "9156": "Try to view our spatial grid leaves" "9166": "Prevent DebugDrawSpatialGrid() from drawing the cell boundaries" "9193": "Our spatial grid contains no leaves" "9199": "Scour GridBuildSpatialPartition() for bugs" "9266": "Fix GridBuildSpatialPartition() to retain Z in the ClippingRegion" "9299": "Our spatial grid still contains no leaves" "9320": "Scour GridBuildSpatialPartition() for bugs (cont.)" "9374": "Assert(Z == 0) in GridBuildSpatialPartition()" "9391": "Scour GridBuildSpatialPartition() for bugs (cont.)" "9424": "Fix GridBuildSpatialPartition() to not consider Z as part of the apron" "9453": "Hit our "overflow" assertion in PushQuad()" "9465": "Toggle off DebugDrawOctahedralValues() in UpdateLighting()" "9492": "Check out the spatial partition leaves of our lit world" "9713": "Check GridRayCast() for the source of light emission" "9800": "Leave a TODO to handle light probes inside a light source" "9866": "Try to make sense of the tangled mess of spatial partition leaves" "9941": "Toggle off DebugDrawSpatialGrid() in UpdateLighting()" "9960": "Check out the world's lighting, at 16ms per frame" "10038": "Increase tUpdateBlend from 1/60 to 30/60 in UpdateLighting()" "10050": "Our lighting flickers" "10095": "Decrease tUpdateBlend from 30/60 to 15/60 in UpdateLighting()" "10107": "Our lighting still flickers" "10121": "Decrease tUpdateBlend from 15/60 to 5/60 in UpdateLighting()" "10143": "Our lighting flicker may be eliminated by casting four times as many rays" "10209": "Increase tUpdateBlend from 5/60 to 20/60 in UpdateLighting()" "10236": "Our shading rate is pretty responsive" "10292": "Reacquaint ourselves with GridRayCast()" "10574": "Reacquaint ourselves with the entropy-based light sampling" "10610": "Remove EntropyFrameCount and LightPointEntropy" "10671": "Reacquaint ourselves with the entropy-based light sampling (cont.)" "10733": "Try making ComputeLightPropagationWork() increment the EntropyIndex by 1 (rather than 234987)" "10744": "Our lighting looks broadly similar" "10758": "Make FullCast() take EntopyIndex as a pointer so that it may increment it" "10832": "Our lighting looks the same" "10838": "Add a SampleBatch loop to FullCast() to perform the GridRayCast() code eight times" "10875": "Our lighting works, but is not as smooth as hoped" "10903": "Increase the SampleBatch loop from 8 to 16 in FullCast()" "10916": "Our lighting remains flickery" "10947": "Rethink how casting more rays may affect the smoothing" "10994": "Check out our lighting flicker" "11060": "Remove the SampleBatch loop from FullCast()" "11074": "Add a SampleBatch loop to ComputeLightPropagationWork() to perform the FullCast() code sixteen times" "11117": "Our lighting remains flickery" "11123": "Increase the SampleBatch loop from 16 to 32 in ComputeLightPropagationWork()" "11141": "Our lighting remains flickery" "11150": "Decrease tUpdateBlend from 20/60 to 1/60 in UpdateLighting()" "11165": "We see other lighting issues" "11185": "Move the SampleBatch loop from ComputeLightPropagationWork() in to FullCast()" "11218": "Our performance is great, just with other lighting bugs to fix" "11263": "Plan to meticulously remove Z from the lighting" "11417": "Consider lighting to be good enough, once debugged" "11456": "Decrease the SampleBatch loop from 32 to 16 in FullCast()" "11472": "~20ms per frame, and ~84% frame time on ComputeLightPropagationWork" "11502": "That's good enough for today, planning next time to clean up the spatial partition and intersect rays properly" "11581": "Soon = before next Sunday?" "11587": "Thanks, everybody" --- name: "day647" title: "Debugging Simplified Lighting" markers: "0": "Recap and set the stage for the day" "194": "Demo the lighting performance" "259": "Describe the old eight-ray octahedral lighting" "426": "Increase the SampleBatch loop from 16 to 64 in FullCast()" "442": "Our performance has degraded" "448": "Decrease the SampleBatch loop from 64 to 8 in FullCast()" "456": "We could easily hit 60 FPS" "485": "Consider moving the SampleBatch loop down to GridRayCast()" "627": "Consider analysing the sampling distribution of FullCast()" "737": "Move the SampleBatch loop from FullCast() down to GridRayCast()" "857": "Check the call stack of GridRayCast() for EntropyIndex" "916": "Change FullCast() to take Entropy not as a pointer, and setup ComputeLightPropagationWork() increment the Entropy" "980": "Reacquaint ourselves with our random number generation" "1239": "Make ComputeLightPropagationWork() get Entropy from RandomSeedOffset()" "1317": "Consider usage of our random number code, and then just casting all 16 octahedrons" "1489": "Remove entropy from FullCast() and make GridRayCast() just sample all the octahedrons" "1901": "Reacquaint ourselves with the sample direction picking code in GridRayCast()" "2169": "Fix GridRayCast() to correctly step through the lighting table" "2276": "Consider structuring the lighting table with Rows being prime, and Octahedrons being interior" "2352": "Make GridRayCast() take an Sy value from FullCast(), for stepping through the sample table" "2496": "Remove Entropy from the call to FullCast() in ComputeLightPropagationWork()" "2529": "Our lighting is now stable" "2547": "Increase tUpdateBlend from 1/60 to 15/60 in UpdateLighting()" "2576": "The lighting doesn't seem to line up correctly when shifting around" "2656": "~28ms per frame, and ~82% frame time on ComputeLightPropagationWork" "2745": "Determine to debug the lighting computation" "2814": "Walk through GridRayCast() and ComputeWalkTable() to refresh our memories" "3172": "Toggle on DebugDrawOctahedralValues() in UpdateLighting()" "3181": "Check out the light probes" "3251": "Toggle on DebugDrawSpatialGrid() in UpdateLighting()" "3261": "Flood the debug system with vertices" "3289": "Make UpdateLighting() double the MaxDebugLineCount" "3296": "Still flood the debug system with vertices" "3303": "Make PushLightingRenderValues() batch up the debug lines into 16-bit capable chunks" "3522": "Still flood the debug system with vertices" "3538": "Investigate the bug in our lighting debug line batching" "3624": "Decrease the batch size from U16Max to 4096 in PushLightingRenderValues()" "3645": "Check out our spatial grid" "3785": "Consider restoring our lighting alignment" "3897": "Make UpdateLighting() offset the AtlasMinCorner by half a voxel" "4054": "Admire our light poisoning" "4170": "Comment out the AtlasMinCorner offset in UpdateLighting()" "4183": "Traverse the orphanage, pondering the offset-induced lighting poisoning" "4223": "Consider why the lighting alignment affects its feedback behaviour" "4288": "Let UpdateLighting() offset the AtlasMinCorner by half a voxel" "4291": "Take one last look at the light poisoning" "4318": "Toggle off DebugDrawOctahedralValues() and DebugDrawSpatialGrid() in UpdateLighting()" "4334": "Consider it to be a sampling direction bug" "4396": "Toggle on DebugDrawOctahedralValues() in UpdateLighting(), and the octahedral map drawing" "4420": "Check out our octahedral map koosh balls" "4506": "Toggle on and make DebugDrawSpatialGrid() draw just the cell boundaries" "4535": "Check out the cell boundaries in relation to the octahedral map koosh balls" "4570": "Toggle on the occluder drawing in DebugDrawSpatialGrid()" "4582": "Light probes inside light sources inconsistently see light and no light" "4707": "The hero's light box is sometimes red and sometimes green" "4713": "Demo the spatial grid checkerboard colouring" "4734": "Toggle off the non-occluder drawing in DebugDrawSpatialGrid()" "4744": "Demo the spatial grid checkerboard colouring" "4871": "Determine to investigate the ray caster" "4890": "In handmade_lighting.cpp: line 152 SampleDir = ... Should the first factor be Sy*16*8?" "4934": "Explain the SampleDirectionTable indexing line in GridRayCast()" "5053": "I was just wondering because the outer index did not seem to incorporate two factors" "5268": "Set up to investigate the ray caster for bugs" "5382": "Scour FullCast() for bugs" "5460": "Make FullCast() write magenta into each SpecTexel inside geometry" "5615": "Admire our magenta light probes" "5670": "Lights incorrectly fail to pick up light" "5727": "Debugging lighting is the biggest pain in the ass" "5734": "Optionally make FullCast() write black into each SpecTexel inside geometry" "5772": "Our "inside" light probes are now black" "5788": "Toggle off DebugDrawSpatialGrid() in UpdateLighting()" "5821": "Our light probes are picking up illogical light" "5906": "Consult the SampleDirectionTable for clues regarding our illogical light probes" "6023": "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" "6225": "Check the Remainder code in FullCast()" "6420": "The light probes inside geometry are correct, but our shifting block-copy is wrong" "6491": "Check that GridRayCast() and ComputeWalkTable() work in consort" "6615": "Consider replacing the walk table with on-the-fly computation" "6741": "Check that GridRayCast() and ComputeWalkTable() work in consort (cont.)" "7034": "Determine to draw a particular ray cast" "7117": "Reduce the LightSamplingWalkTable pointer array from 8 to 4 in lighting_solution" "7155": "The lighting looks the same" "7172": "Scour GridRayCast() for bugs" "7380": "Increase MaxCostPerRay from 8 to 16 in UpdateLighting()" "7432": "~38ms per frame, and ~69% frame time on ComputeLightPropagationWork" "7461": "Toggle off DebugDrawOctahedralValues() in UpdateLighting()" "7467": "~27ms per frame, and ~81% frame time on ComputeLightPropagationWork" "7491": "Toggle on DebugDrawOctahedralValues() and decrease MaxCostPerRay back from 16 to 8 in UpdateLighting()" "7601": "Re-enable ray drawing in GridRayCast()" "7744": "Reacquaint ourselves with RectCenterDim() and the ProbeSamplePSingle value in GridRayCast()" "7937": "Enable GridRayCast() to use ProbeSamplePSingle and ProbeSampleNSingle for drawing" "8045": "Consider supporting picking of a particular ray" "8151": "Re-enable ray cast drawing in FullCast()" "8352": "Hunt in vain for our drawn ray cast" "8376": "Toggle off DebugDrawOctahedralValues() in UpdateLighting()" "8397": "Hunt in vain for our drawn ray cast" "8412": "Decrease DebugGridIndex from 717 to 200 and DebugRayIndex from 531 to 0 in UpdateLighting()" "8487": "Hunt in vain for our drawn ray cast" "8502": "Elevate GRID_RAY_CAST_DEBUGGING to the top of handmade_lighting.h" "8566": "Break in to FullCast() to find that we never get to our DebugGridIndex of 200" "8681": "The spatial partition is half the voxel dimensions, a mere 96" "8743": "Decrease DebugGridIndex from 200 to 30 in UpdateLighting()" "8764": "Break in to FullCast() and see our drawn ray cast" "8883": "Re-enable support for debug ray picking in FullCast(), introducing debug_ray_pick" "9245": "Quick break for water and snacks" "9274": "Allocates 256 megs, keeps playing. Employees are encouraged to kill yourself" "9292": "Are you providing the snacks?" "9303": "afk" "10051": "Return with water and snacks" "10121": "I used to inhale that stuff as a kid" "10131": "Resume re-enabling support for debug ray picking in FullCast()" "10408": "The magenta "expected direction" line does not go in the direction we ray cast" "10512": "Investigate the "expected" and "ray" direction misalignment in FullCast()" "10587": "Try making FullCast() add 1 to the ExpectedDirection axes to account for the apron" "10607": "The "expected" and "ray" directions remain misaligned" "10619": "Investigate the "expected" and "ray" direction misalignment in FullCast() and GridRayCast()" "10709": "The "expected" and "ray" lines only need to come out of the same face of the octahedron" "10736": "Re-enable editing of the ray picking values in DEBUGInteract() and DEBUGBeginInteract()" "10985": "Try editing GridIndex in-game" "11046": "Clamp the DebugTick values in FullCast()" "11213": "GridIndex 48 yields two sets of ray casting" "11268": "Replace GridIndex with a v3s AtlasIndex in debug_ray_pick, for more specific ray picking" "11469": "Introduce a v3s version of Clamp()" "11531": "Make FullCast() keep the AtlasIndex in range" "11545": "Try unsuccessfully to edit AtlasIndex" "11590": "Add s32 editing support to DEBUGInteract() and DEBUGBeginInteract()" "11628": "Try editing our AtlasIndex values" "11692": "Add DevUI_Interaction_TickValue to edit integer values by clicking (rather than dragging)" "11868": "Decrementing by clicking works, but incrementing does not" "11887": "Fix DEBUGInteract() to increment integer values by clicking" "11901": "Click-and-hold increments integer values" "11914": "Make DEBUGEndInteract() rather than DEBUGInteract() handle integer editing by clicking" "11961": "Our integer editing is more sane, but still doesn't clamp" "12047": "Atlas (10, 4, 1) on our octahedral map has a straight-down expected direction" "12099": "Investigate our straight-down expected direction" "12230": "Are light bleed and light poisoning the same thing?" "12394": "Inspect atlas (10, 4, 1)" "12424": "Initialise AtlasIndex to 10, 4, 1 UpdateLighting()" "12434": "Ray casting on AtlasIndex (10, 4, 1) fails from Octahedron 4 onwards" "12462": "Investigate SampleDirectionTable and GridRayCast() for the source of our ray casting failure" "12680": "Octahedron 4 to 15 remain incorrect" "12742": "Check again that GridRayCast() and ComputeWalkTable() work in consort" "12905": "Initialise DirOffset in GridRayCast() for easy inspection" "12952": "Step in to GridRayCast() and inspect DirOffset and RayDSingle, to find values we didn't think existed in handmade_sampling_spheres.inl" "13223": "Is this 2D or 3D global illumination?" "13315": "Determine to fix GenerateOctahedralLightingPattern() next time" "13576": "Poisson distributions!" "13585": "Consider keeping Poisson distribution sampling" "13700": "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?" "13784": "Determine to rebuild SampleDirectionTable next time" "13819": "Set up GridRayCast() to traverse the SampleDirectionTable in a single loop" "13957": "Call it here, with the determination to rebuild SampleDirectionTable next time" "14001": "Consider the possibility of smarter ways to batch up ray processing" "14072": "Thank you, everyone" --- name: "day648" title: "Rebuilding Light Tables" markers: "1": "Recap and set the stage for the day building light tables" "76": "Demo our lighting colour bleed" "127": "Our SampleDirectionTable in handmade_sampling_spheres.inl samples direction [0, 0, 1] multiple times" "215": "Plan to rebuild our light table in an evenly distributed blue noise pattern" "359": "Consider sampling the light at 16 samples per texel" "445": "You also need it to be blue-noise temporally as well as spatially for best result" "473": "Consider using a pseudo-blue noise sampling pattern, or tuning the distance parameter manually" "553": "Toggle on the sphere drawing in PushLightingRenderValues()" "586": "Check out our sampling sphere" "622": "Plan to rebuild the table then view our drawing" "646": "Reacquaint ourselves with hhsphere.cpp" "848": "Remove SamplingSpheres from lighting_solution, the LightSamplingSphereFloatTable from handmade_sampling_spheres.inl with its generator in OutputSphereINL(), InterleaveDirections(), cube_store and sphere_store" "1097": "Plan to make OutputSphereINL() output the SampleDirectionTable with all the octahedral rays for a given texel, then all those for the next texel, etc." "1220": "Make OutputSphereINL() output the SampleDirectionTable with all the octahedral rays for a given texel, then all those for the next texel, etc." "1480": "Reacquaint ourselves with the light sample sieving in GeneratePoissonDistribution()" "1601": "Propose to draw the sampling sphere coloured by texel, then fix hhsphere.cpp" "1652": "Make PushLightingRenderValues() draw the sampling sphere coloured by texel" "1998": "Rework GenerateOctahedralLightingPattern() to structure the sampling directions with all the octahedral rays for a given texel, then all those for the next texel, etc." "2158": "The bug: Our call to GeneratePoissonDistribution(), with its randomness, using TotalDirectionCount, may yield fewer samples on a texel than we need" "2258": "Consider asking GeneratePoissonDistribution() for more sampling points" "2320": "Introduce direction_gen for GeneratePoissonDistribution() to return, and remove GeneratePoissonSamples(), TestFunc() and GeneratePoissonLightingPattern()" "2568": "Hunt for a v2u + operator overload" "2648": "Introduce a v2u + operator overload" "2677": "Update GenerateOctahedralLightingPattern() to use our direction_gen, and ask GeneratePoissonDistribution() for 20% more samples than we'll use, introducing AllocDirArray()" "3094": "Make GenerateOctahedralLightingPattern() print an error on "Direction count underflow for texel"" "3167": "Finish up the usage code of hhsphere.cpp" "3458": "Run hhsphere, and hit a number of "Direction count underflow for texel" errors" "3561": "Inspect handmade_sampling_spheres.inl, try to compile with it and hit a syntax error" "3625": "Manually append a ")" to TOTAL_LIGHT_SAMPLE_DIRECTION_COUNT in handmade_sampling_spheres.inl" "3689": "Remove stale #if 0 from GridRayCast()" "3702": "Append the missing ")" to TOTAL_LIGHT_SAMPLE_DIRECTION_COUNT OutputSphereINL()" "3712": "Update GridRayCast() to use our newly structured SampleDirectionTable" "4689": "Hit a read access violation in GridRayCast()" "4723": "Investigate our read access violation in GridRayCast()" "4862": "Reacquaint ourselves with tTerminate in ComputeWalkTable()" "5124": "Make ComputeWalkTable() set tTerminate to 0 if greater than or equal to 1000000" "5240": "Plan to update remedybg from 0.3.5.0 to 0.3.6.3" "5285": "Again hit a read access violation in GridRayCast()" "5379": "Let ComputeWalkTable() use tTerminate as is, and instead make GenerateOctahedralLightingPattern() output a valid [0, 0, 1] ray direction on underflow" "5458": "Run hhsphere, and hit a number of "Direction count underflow for texel" errors" "5509": "Inspect handmade_sampling_spheres.inl and compile just fine" "5549": "Run the game without crashing, but with the sampling sphere possibly being drawn wrong" "5592": "Check RenderDiagrams() for participation in lighting" "5652": "Make PushLightingRenderValues() draw the sampling sphere lower down" "5671": "Our sampling sphere is lit, and contains gaps" "5755": "Fix GridRayCast() to set TransferPPS[Tx] to the already accumulated TransferPPSAccum" "5831": "Our lighting is no longer overblown, but still bleeds, and dims while moving" "5959": "Try making GenerateOctahedralLightingPattern() ask GeneratePoissonDistribution() for 100% more samples than we'll use, and tighten the convergence criteria from 0.025 to 0.0125" "6099": "Run hhsphere without completing" "6161": "Revert the convergence criteria to 0.025 in GenerateOctahedralLightingPattern()" "6193": "Run hhsphere, and still hit a number of "Direction count underflow for texel" errors" "6226": "Investigate why GenerateOctahedralLightingPattern() is not receiving enough sample directions" "6423": "Our lighting sphere looks the same" "6437": "We're missing something" "6491": "Break for snacks" "6518": "afk" "6716": "Return with snacks" "6732": "Consider abandoning vs debugging the sampling point picking scheme" "7000": "What snacks?" "7041": "Need more chicharrones" "7068": "Consider evenly distributing sampling points in texel space" "7141": "Propose seeding 16 rays per texel, using a white noise distribution, repulsed to increase evenness, and prevented from leaving their containing texel" "7262": "Won't you get clamping on the edges?" "7297": "Consider starting with the 16 rays per texel white noise distribution, without repulsion" "7329": "Make GeneratePoissonDistribution() seed the requested rays per texel in a white noise distribution, and remove GenerateOctahedralLightingPattern()" "7763": "Run hhsphere, and find a more coherent SampleDirectionTable" "7795": "Our lighting sphere is only half filled in" "7832": "Fix GeneratePoissonDistribution() to produce a -1 to 1 distribution" "7918": "Run hhsphere" "7929": "Our lighting sphere is complete, if clumpy" "7985": "Make GeneratePoissonDistribution() repulse the rays, keeping them in the same quadrant" "8296": "Run hhsphere and quickly lock up" "8348": "Loosen the convergence criteria from 0.025 to 0.14 in GeneratePoissonDistribution()" "8375": "Run hhsphere to completion" "8392": "Our lighting sphere is not horrible, but good enough for now" "8479": "Our rays now look more sane" "8546": "Make FullCast() clamp the RayIndex to the total count minus 1" "8554": "Determine to investigate our green light leakage" "8599": "Investigate our green light leakage" "8687": "Toggle on the light atlas drawing in OpenGLEndFrame()" "8696": "Our light atlases clearly contain energy bleed" "8708": "Make OpenGLChangeToSettings() draw our light atlases in their entirety" "8795": "Check out our full light atlases" "8809": "Make OpenGLChangeToSettings() draw 0.25 of our light atlases in both X and Y" "8822": "Glimpse our light atlases" "8831": "Make OpenGLChangeToSettings() draw 0.025 of our light atlases in both X and Y" "8854": "Glimpse our light atlases" "8857": "Make OpenGLChangeToSettings() draw 0.025 of our light atlases in X" "8885": "Check out our light atlases" "8915": "Make OpenGLChangeToSettings() draw 0.0125 of our light atlases in X" "8926": "Our light atlases have a consistent light bleed" "8935": "Let OpenGLChangeToSettings() draw the original portion of our light atlases" "8944": "Traverse the orphanage and watch the light bleed in certain areas" "9054": "Start by investigating BlockCopyAtlas()" "9125": "Assert in UpdateLighting() that dVoxel.z is 0" "9143": "Correctly fail to hit the dVoxel.z assertion" "9156": "Scour UpdateLighting() for errors in other dVoxel values" "9321": "Assert in UpdateLighting() that dVoxel.x and dVoxel.y are <= 1" "9378": "Hit our dVoxel.x assertion" "9390": "Make UpdateLighting() skip the dVoxel.x and dVoxel.y assertions first time round" "9425": "Correctly fail to hit the dVoxel.x and dVoxel.y assertions" "9435": "Remove the dVoxel.x and dVoxel.y assertions from UpdateLighting()" "9456": "Scour BlockCopyAtlas() for bugs" "9592": "Traverse the orphanage and watch the light bleed in certain areas" "9603": "Toggle off the light atlas drawing in OpenGLEndFrame()" "9615": "Traverse the orphanage and carefully watch the lighting at a slow 0.04 timestep" "9710": "Set tUpdateBlend to 1 in UpdateLighting()" "9727": "The lighting clearly blinks when copying the atlases" "9809": "Scour BlockCopyAtlas() for bugs" "9872": "Toggle on the LIGHT_ATLAS_ASSERT for VALIDATE_TEXEL_ATLAS() to fire" "9883": "Trap on VALIDATE_TEXEL_ATLAS() of the DiffuseAtlas" "9911": "Make ValidateTexelComponent() consider a component of between -100 and 100 to be valid" "9930": "Immediately trap on VALIDATE_TEXEL_ATLAS() of the SpecAtlas" "9944": "Consider deferring until next time the investigation of our out-of-bounds lighting values" "10153": "Introduce VoxelIndexIsInDim() for GridRayCast() to assert that the sample fetch is in bounds" "10554": "Hit our IsInBounds assertion in GridRayCast()" "10716": "Get it" "10834": "Toggle off the ray drawing in PushLightingRenderValues(), and toggle on DebugDrawSpatialGrid() in UpdateLighting()" "10896": "Immediately trap on VALIDATE_TEXEL_ATLAS() of the SpecAtlas" "10909": "Toggle off the LIGHT_ATLAS_ASSERT" "10917": "Our bug: We can sample garbage in Z when not hitting an occluder" "11186": "GridRayCast() is already clamping" "11350": "Scour GridRayCast() for a subtle bug causing out-of-bounds sampling" "11640": "Set the first entry of SampleDirectionTable to an invalid [0, 0, 0]" "11689": "Hit our read access violation in GridRayCast() on an invalid [0, 0, 0] sample direction" "11692": "Inspect the values in GridRayCast() on an invalid [0, 0, 0] sample direction" "11901": "GridRayCast() produces a bogus Txy value" "11957": "Revert the first entry of SampleDirectionTable to the generated value" "11965": "Consider calling it for today" "12004": "Take one last look at our light bleed, blinking on copy and light source occlusion" "12186": "Brooo what is going on, Casey is about to do Unreal Engine 6 by himself at this point" "12198": "Call it for today" --- name: "day649" title: "Removing Lighting Walk Tables" markers: "2": "Recap and set the stage for the day debugging lighting" "63": "Demo our light bleed bug" "105": "Demo our light copying bug" "360": "Describe BlockCopyAtlas()" "429": "Assert in BlockCopyAtlas() that the Z loop doesn't happen" "470": "Hit our Z loop assertion in BlockCopyAtlas()" "529": "Move our Z loop assertion in BlockCopyAtlas() down to the Z clearing loop" "551": "Hit our Z clearing loop assertion in BlockCopyAtlas()" "585": "Inspect the BlockCopyAtlas() values in an -Od build" "686": "Comment out the Z clearing loop in BlockCopyAtlas()" "711": "Try to eyeball our light copying bug" "734": "Toggle off DebugDrawSpatialGrid() in UpdateLighting()" "764": "Our light copying / flashing bug seems to still occur" "887": "Uncomment the Z clearing loop in BlockCopyAtlas()" "914": "Scour BlockCopyAtlas() for bugs" "1087": "Remove the minus 1 from the StopZ computation in BlockCopyAtlas()" "1115": "We still see a little bit of flashing" "1134": "Enable LIGHT_ATLAS_ASSERT" "1165": "Immediately trap on VALIDATE_TEXEL_ATLAS() of the SpecAtlas" "1175": "Toggle off the VALIDATE_TEXEL_ATLAS() calls in UpdateLighting()" "1187": "Trap on VALIDATE_TEXEL_ATLAS() in BlockCopyAtlas()" "1194": "Toggle off the VALIDATE_TEXEL_ATLAS() calls using #if TEMPORARY" "1219": "Trap on VALIDATE_TEXEL_ATLAS() at the end of BlockCopyAtlas()" "1229": "Toggle off the final VALIDATE_TEXEL_ATLAS() call using #if TEMPORARY" "1243": "Successfully run without fetching out of bounds" "1262": "Remove the minus 1 from the StopX and StopY computations in BlockCopyAtlas()" "1282": "We have lighting movement across tiles" "1405": "Decrease tUpdateBlend from 1 to 15/60 in UpdateLighting()" "1429": "Still see the lighting shift" "1453": "Decrease tUpdateBlend from 15/60 to 1/60 in UpdateLighting()" "1469": "The shift is due to the light being recomputed differently" "1522": "Toggle off the -1 to 1 origin cube in UpdateAndRenderWorld()" "1619": "The wall tiles darken after shifting" "1687": "Toggle off PushLight() on the DebugLightP in UpdateAndRenderWorld()" "1706": "The room still seems to brighten when we enter" "1818": "The light bleed takes longer with our slower tUpdateBlend" "1861": "Increase tUpdateBlend from 1/60 to 1 in UpdateLighting()" "1910": "The copy is now fine, but the ray casting differs when shifting the lighting voxel" "2052": "Prevent UpdateLighting() from offsetting VoxCameraOffset.Y by 2" "2103": "The lighting region is now centred" "2198": "Scour GridRayCast() for a reason for differences when shifting the lighting voxel" "2476": "Scour ComputeWalkTable() for bugs" "2560": "Make WalkTableOffset be an array of 4 in sample_direction, for ComputeWalkTable() to use" "2592": "The light doesn't seem to have changed" "2638": "Double-check ComputeWalkTable() for correctness" "2716": "Consider removing lighting walk tables" "2816": "The ray casting still differs when shifting the lighting voxel" "2847": "Consider making UpdateLighting() force dVoxel to be a multiple of 2 so the quadrant doesn't change" "2912": "The problem changed, though, there's still a dark spot but it doesn't move now" "2931": "Demo the moving dark spot" "2986": "I mean it seems like it only moved when leaving the room but not while moving within the room as before, no?" "3007": "Demo the changing dark spot when the lighting voxel alignment changes within a room" "3059": "Consider removing lighting walk tables" "3315": "FruFru is a great variable name, though" "3320": "Consider removing lighting walk tables" "3378": "Check GridRayCast() to inform our lighting walk table removal decision" "3590": "Toggle on WalkTable stepping in GridRayCast()" "3606": "Traverse the orphanage into a relatively stably lit room" "3617": "Change the CostMetric-based ray casting loop in GridRayCast() to iterate over a hard-bounded GridWalkIteration" "3647": "The lighting looks the same" "3656": "Remove CostMetric entirely from GridRayCast()" "3683": "The lighting remains fine" "3706": "Consider formulating an exit criterion in GridRayCast() upon leaving the spatial partition" "3869": "Determine to make GridRayCast() work without a walk table" "4165": "Sketch out walk table-eliminated grid stepping in GridRayCast()" "6342": "DirCurP is 2*DirCurP+dX/Y at the moment" "6366": "XStepV have it included already" "6395": "Determine to remove lighting walk tables" "6451": "Break" "6490": "afk" "6606": "Return and centre the camera" "6745": "Implement on-the-fly grid stepping in GridRayCast()" "8030": "Hit an overflow read access violation on SpatialGridLeaves in GridRayCast()" "8043": "Introduce a CheckGridIndex to separate out the two grid stepping routines in GridRayCast()" "8086": "The lighting behaves the same as before" "8111": "Break in to GridRayCast() and compare the values of the two grid stepping routines" "8193": "Fix the dGridIndexXBase and dGridIndexYBase computations in GridRayCast()" "8211": "Break in to GridRayCast() and compare the values of the two grid stepping routines" "8271": "Assert in GridRayCast() that GridIndex and CheckGridIndex match" "8294": "Run the game" "8304": "Update remedybg from 0.3.5.0 to 0.3.6.4" "8421": "Hit the GridIndex and CheckGridIndex matching assertion in GridRayCast()" "8509": "Swap in the new on-the-fly grid stepping in GridRayCast()" "8569": "Our ray casting correctly no longer differs when shifting the lighting voxel" "8659": "Consider how to update tTerminate" "8986": "Make GridRayCast() compute tTerminate on the fly" "9523": "Our lighting happily looks no different" "9548": "Remove the lighting walk tables" "9668": "Run successfully and briefly consider our remaining light bleed bug" "9868": "Reflect on today's work and consider further simplifications" "9935": "~82% frame time (~400,000,000 cycles) on ComputeLightPropagationWork" "10003": "Make GridRayCast() only cast one ray" "10025": "~35% frame time (~35,000,000 cycles) on ComputeLightPropagationWork" "10056": "Make GridRayCast() cast the full LIGHTING_OCTAHEDRAL_RAYS_PER_TEXEL" "10062": "~82% frame time (~400,000,000 cycles) on ComputeLightPropagationWork" "10080": "Make GridRayCast() only cast no rays" "10088": "~11% frame time (~8,800,000 cycles) on ComputeLightPropagationWork" "10104": "Make GridRayCast() cast the full LIGHTING_OCTAHEDRAL_RAYS_PER_TEXEL" "10107": "~82% frame time (~400,000,000 cycles) on ComputeLightPropagationWork" "10138": "Make GridRayCast() cast half of the LIGHTING_OCTAHEDRAL_RAYS_PER_TEXEL" "10152": "Admire the cool red light bleed" "10189": "Make GridRayCast() double the RayWeight to compensate for the halved number of rays" "10209": "Admire the apparently structured light bleed bug" "10288": "Let GridRayCast() cast all the rays, at their appropriate weight" "10311": "Disable LIGHT_ATLAS_ASSERT" "10330": "~28ms frame time" "10356": "Disable HANDMADE_SLOW" "10368": "~24ms frame time" "10413": "That's it for today" "10452": "Are the GPU shaders just lerping from the results that the CPU is doing?" "10627": "Is that like a spherical harmonics encoding?" "10862": "That's it for today, with a glimpse into the future and reflections on the engine" "10962": "Can Z be re-added in an easier way now that the system is easier?" "11113": "That's it" --- name: "day650" title: "Debugging Light Sampling Locations" markers: "2": "Recap and set the stage for the day debugging our light contamination bug" "136": "Describe ValidateTexelComponent()" "192": "Make ValidateTexelComponent() consider a component greater than or equal to 0 to be valid, enabling LIGHT_ATLAS_ASSERT" "208": "Run without producing an invalid texel component" "246": "Make ValidateTexelComponent() consider a component of between 0 and 100 to be valid" "261": "Run without producing an invalid texel component" "298": "Force ValidateTexelComponent() to consider all components to be invalid" "305": "Trap on SetLightAtlasTexels(), proving that ValidateTexelComponent() is being called" "317": "Revert ValidateTexelComponent() to validate normally" "322": "Traverse the orphanage and never produce an invalid texel component" "364": "Restrict ValidateTexelComponent() to consider a component of between 0 and 10 to be valid" "375": "Run without producing an invalid texel component" "384": "Restrict ValidateTexelComponent() to consider a component of between 0 and 1 to be valid" "402": "Trap on PushLight() in an -O2 build" "413": "Trap on VALIDATE_TEXEL() within PushLight() in an -Od build" "445": "Expand ValidateTexelComponent() to consider a component of between 0 and 5 to be valid" "463": "Trap on VALIDATE_TEXEL() within PushLight(), and inspect the Emission" "492": "Reacquaint ourselves with StandardLightingPattern() and AddPieceLight()" "611": "Restrict ValidateTexelComponent() to consider a component of between 0 and 1.1 to be valid" "625": "Trap on VALIDATE_TEXEL() within PushLight()" "634": "Make StandardLightingPattern() reduce the Emission value passed to AddPieceLight() from 10 to 1" "645": "Run without trapping" "657": "Run an -O2 build without trapping for a while, before trapping on PushLight() in UpdateAndRenderEntities()" "746": "Revert StandardLightingPattern() to pass an Emission value of 10 to AddPieceLight()" "758": "Trap on VALIDATE_TEXEL() within PushLight()" "768": "Expand ValidateTexelComponent() to consider a component of between 0 and 10 to be valid" "774": "Consider the possibility of this being an artifact of the way our system convects light" "824": "Questions of our lighting system: 1. Why do our lights have falloff? It's the inverse-square law, as an artifact of sampling" "919": "Questions of our lighting system: 2. Why do we have over-brighting?" "964": "Let GridRayCast() walk the grid all the way to the SPATIAL_GRID_NODE_TERMINATOR" "1030": "We still get over-brighting" "1058": "Make GridRayCast() walk the grid only eight steps, and zero out the HitRefColor if it gets that far" "1104": "We no longer get over-brighting indoors, but we do in some exteriors" "1224": "Make DebugDrawSpatialGrid() draw the occluders, and toggle on the call to it in UpdateLighting()" "1256": "Over-brighting outdoors is affected by the player's position" "1645": "Toggle on DebugDrawOctahedralValues() and off DebugDrawSpatialGrid() in UpdateLighting()" "1684": "The interior lighting gets tinted green when the lighting bounds do not encompass the exterior wall" "1799": "Make StandardLightingPattern() colour the lights a non-random pure grey" "1823": "The interior lighting no longer gets tinted green" "1873": "We no longer get over-brighting outdoors" "1935": "Make StandardLightingPattern() colour the lights a more powerful grey" "1949": "We do get our over-brighting bug again" "1991": "Remove cruft from GridRayCast()" "2095": "Investigate why the light only leaks on the quarters" "2207": "Begin to illustrate our leaking case" "2240": "Plug the Qualcomm Keynote from CES 2013" "2543": "Light leaking clues: 1. Exterior light probes beyond the wall unexpectedly pick up light" "2718": "Light leaking clues: 2. Enclosed light probes can suddenly pick up light" "2780": "Plan our light leak investigations" "3081": "I don't know how that code works, but I see an x value be used for y variable called somethingY" "3186": "Reorient SteppingDeltaX as a negative offset in GridRayCast()" "3289": "Shouldn't there be a minus sign somewhere then?" "3316": "Take a close look at our enclosed light probes suddenly picking up light" "3511": "Find the Owl" "3552": "Owl of Shame Parade" "3664": "Light leaks below the world" "3809": "Reacquaint ourselves with GenerateApron()" "3935": "Somewhere else Microsoft is receiving packages full of owls, but they don't know what they're for" "3943": "Recommend Microsoft to build a giant Owl of Shame on their new campus" "3992": "They have the same bug" "4004": "Recommend Microsoft to put the Owl of Shame on a rotating base" "4065": "Consider whether to enclose the world with floors or clamp the light ray cast's movement in Z" "4287": "Why not clamp the light ray cast's movement in Z" "4368": "Start to make GenerateApron() always generate ground cover" "4520": "Note the uneven ground outside generated rooms" "4545": "Make GenerateApron() reduce the vertical placement of overlapping entities by 1" "4581": "Light no longer leaks below the world" "4646": "Make GenerateApron() also reduce the vertical placement of overlapping entities besides trees" "4670": "The ground cover's vertical placement appears to be low" "4678": "Make GenerateApron() further decrease the vertical placement from 1 to 5" "4689": "The apron seems the same" "4699": "Make GenerateApron() further decrease the vertical placement from 5 to 10" "4735": "Nothing sticks out the bottom" "4762": "Put the P.z offsetting on its own line in GenerateApron() and build in -Od" "4779": "Break in to GenerateApron() and inspect its values" "4983": "Move the P.z offsetting below the Vol initialisation line in GenerateApron()" "5011": "Build in -O2" "5029": "Is everything overlapped?" "5037": "Overlapped entities now below the spatial partition" "5053": "Make GenerateApron() decrease the vertical placement less from 10 to 2" "5064": "Overlapped entities are back" "5086": "Overflow our entity count in EnsureRegionIsUnpacked()" "5113": "Temporarily increase MAX_SIM_REGION_ENTITY_COUNT from 2*8192 to 4*8192" "5189": "We report non-overlapped entities as overlapped" "5224": "Revert MAX_SIM_REGION_ENTITY_COUNT to 2*8192, and remove the overlapped entity offsetting in GenerateApron()" "5243": "Scour OverlappingEntitiesExist() and GenerateApron() for bugs" "5347": "Toggle on collision volume drawing in UpdateAndRenderEntities()" "5380": "Our room boundaries are wrong" "5424": "Make GenRoomVolume() offset the dimensions down by half" "5518": "Our room boundaries remain wrong" "5559": "Fix GenRoomVolume() to offset the dimensions down by half a TileDim" "5613": "Our rooms are now correctly aligned" "5636": "Our light still leaks" "5712": "Reacquaint ourselves with the occluder generation code" "5996": "Provoke the position-dependent interior light leak bug" "6020": "Make GenerateApron() call AddPieceOccluder() to generate a ceiling for each tile" "6286": "Traverse the orphanage" "6304": "Toggle off collision volume drawing in UpdateAndRenderEntities()" "6317": "Successfully provoke the position-dependent interior light leak bug" "6337": "Toggle on DebugDrawSpatialGrid() and off DebugDrawOctahedralValues() in UpdateLighting()" "6376": "With floors and ceilings, our enclosed light probes correctly no longer pick up light" "6698": "Make GenerateRoom() generate a ceiling light indoors" "6777": "Provoke the position-dependent interior light leak bug" "6893": "Disable StandardLightingPattern()" "6951": "The exterior area gets light from its ceiling tiles, but the interior does not" "7002": "Fix GenerateRoom() to generate the ceiling light outdoors, and the ceiling occluder indoors" "7060": "The interior now gets light" "7155": "Re-enable overhead light placement StandardLightingPattern()" "7186": "Briefly run the game" "7191": "Toggle off DebugDrawSpatialGrid() in UpdateLighting()" "7206": "Admire the lighting where it isn't buggy" "7361": "What graphics engine are you using?" "7382": "The apron is not sealed" "7426": "You could blame younger you" "7473": "Wonder if the unsealed apron affects our light bleed bug" "7510": "Are trees 2D?" "7591": "Ponder our position-dependent light feedback bug" "7655": "New here, do you plan on making a full game to play or just focusing on the engine?" "7691": "Plug Jonathan Blow's stream" "7713": "Provoke our position-dependent light bleed bug outdoors" "7750": "It could be educational to watch someone learn game design" "7771": "Z cannot be implicated in the position-dependent light bleed bug indoors" "7921": "Can the ray escape through the door into nothingness?" "8023": "Is there any way to prevent the wrapping, so it can't sample from the wrapped region?" "8063": "I don't understand how bypassing some light barriers would lead to the kind of positive feedback loop we're seeing in some places" "8075": "The enclosed light bug is back" "8097": "The inverse-square law applies when hitting a light, but not when sampling indirect light. Is that wrong?" "8176": "Make GridRayCast() zero out the HitEmission upon walking the distance" "8208": "Walls are oddly lit on every other shift of the lighting voxel" "8278": "Does this happen with pure white / pure red lights?" "8292": "Make StandardLightingPattern() colour the interior light pure [5, 5, 5] white" "8301": "The position-dependent interior light leak bug is gone" "8321": "Make StandardLightingPattern() colour the interior light a brighter [7, 7, 7] white" "8338": "The position-dependent interior light leak bug is back" "8347": "Make StandardLightingPattern() colour the interior light a dimmer [6, 6, 6] white" "8361": "The position-dependent interior light leak bug remains" "8385": "Make StandardLightingPattern() colour the interior light a dimmer [5, 5, 5] white" "8398": "The position-dependent interior light leak bug is gone" "8486": "Consider the value sensitivity of our position-dependent light leak bug" "8539": "Why is the light bottom-left in that room brighter than the others?" "8619": "Inspect the ray casting on the brighter bottom-left tile" "8781": "The light source box looks bigger than one tile, like it's 1.0 and not "tile sized"" "8812": "Toggle on drawing of the lights in UpdateAndRenderEntities()" "8827": "Check out our lights" "8846": "Make UpdateAndRenderEntities() draw the lights at their correct size" "8948": "Check out our lights" "9000": "There was a TODO in CalcBasePForOffset that said it still needed to be implemented" "9010": "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?" "9091": "CalcBasePForOffset() doesn't matter" "9131": "We have position-dependent brightening in the non-traversable outdoors" "9363": "Scour GridRayCast() for the ramifications of hitting tTerminate and zeroing HitRefColor" "9534": "Check out the rays cast in the brighter non-traversable outdoors" "9563": "Toggle on DebugDrawOctahedralValues() in UpdateLighting()" "9582": "The light apparently comes through the wall" "9680": "Scour GridRayCast() for bugs in getting the light atlas" "9862": "Reproduce our position-dependent brightening" "9893": "Rename Grid to AtlasGrid in GridRayCast()" "10085": "Check our region alignments" "10131": "PushLightingRenderValues() draws the HotVoxelRect in cyan and the SpatialGrid in green" "10210": "Our light sampling reads and writes are misaligned" "10317": "Vote for a quick break" "10372": "afk" "10603": "Return" "10628": "No! Brain-parasite music!" "10637": "Fanfare" "10678": "Maybe you should let Cody handle the second part of the stream, then you don't need a break" "10725": "niftywifty *Will Smith approaching...*" "10913": "Will the Handmade Hero awards have exciting moments? Maybe you can invite and then slap a Microsoft employee" "10971": "Investigate our sampling read–write misalignment" "11078": "Keep! My struct's name! Out your fuckin' mouth!!!" "11098": "The GetCellCenterP() call in ComputeLightPropagationWork() is horse poop" "11117": "We're eating Peanut Butter Pretzels from Costco" "11175": "Would you like me to talk to Mr Costco for you?" "11188": "Change ComputeLightPropagationWork() to set BoxCenterP using GetCellBounds().Min" "11310": "The octahedral value drawings are now positioned wrong" "11334": "Rename BoxCenterP to CastFromP in ComputeLightPropagationWork()" "11380": "Fix DebugDrawOctahedralValues() to position the drawings at the Bounds.Min" "11449": "We have light probes unable to pick up light around the perimeter" "11520": "Our light leaking is now more pronounced" "11623": "Reacquaint ourselves with the atlas grid and spatial grid creation code in UpdateLighting() and MakeLightAtlas()" "11864": "Make UpdateLighting() shrink the atlas grid by one in all dimensions" "11920": "Our light probes now fill the atlas grid" "12018": "Make UpdateLighting() position the light atlas at half a VoxCellDim in Z" "12071": "The light atlas is too high" "12102": "Stop UpdateLighting() from repositioning the light atlas in Z" "12112": "The light atlas is a little too low" "12133": "Make UpdateLighting() offset the light atlas upwards in Z by half a VoxCellDim" "12143": "The light atlas is better positioned and aligned" "12210": "Reacquaint ourselves with the light sample read–write alignment in PushLightingRenderValues() and SampleLighting()" "12478": "Prevent SumLight() from offsetting VoxR by -0.5 in all dimensions, and make SampleLighting() clamp our lookups within the lighting voxel" "12634": "Our floors are now lit" "12723": "Scour GridRayCast() for sampling bugs" "12967": "Our debug ray picking is now broken" "13023": "Fix FullCast() to clamp the ray picker's atlas index to the full cell count" "13055": "Our debug ray picking remains broken" "13096": "Temporarily prevent FullCast() from clamping the ray picker's atlas index" "13108": "Our debug ray picking remains broken" "13125": "Let FullCast() clamp the ray picker's atlas index" "13133": "Investigate our ray picking bug" "13164": "Make UpdateLighting() compute an offset AtlasGridCellCount to prevent the light map from being reset every frame" "13229": "Our debug ray picking works again" "13264": "Inspect our rays to determine that they are offset" "13412": "Scour FullCast() for alignment bugs" "13607": "Make FullCast() map the light probes into the spatial grid, using GetIndexForP()" "13683": "Briefly run the game" "13693": "Remove AtlasToSpatialGridIndexOffset from lighting_solution" "13746": "We still have casting bugs" "13783": "Why is there no timer?" "13802": "Start the timer" "13820": "Glance at UpdateLighting() for bugs" "13865": "Consider the lighting bounds placement to be correct" "13917": "Scour UpdateLighting() and FullCast() for bugs" "14041": "Rename the VoxCenterP argument to LightProbeP in FullCast()" "14057": "Scour GridRayCast() for bugs" "14133": "Delete CellDim4 and related code in GridRayCast()" "14198": "Scour GridRayCast() for bugs (cont.)" "14277": "Toggle off DebugDrawOctahedralValues() in UpdateLighting()" "14291": "The spatial partition and lighting voxel are oddly aligned" "14358": "Make UpdateLighting() offset the spatial grid by half a VoxCellDim in x and y" "14408": "Inspect our rays to determine that they seem pretty good" "14504": "Our lighting is more stable, but the lighting voxel slides relative to the spatial grid" "14556": "Investigate our lighting voxel sliding bug" "14969": "Make UpdateLighting() set the HotDim to the AtlasGrid's dimensions" "15063": "Our lighting now flickers, and has black spots" "15115": "Revert the HotDim initialisation in UpdateLighting()" "15130": "The flicker and black spots have gone" "15164": "Toggle on DebugDrawOctahedralValues() in UpdateLighting()" "15202": "The octahedrons don't shift, only their values alter" "15287": "Toggle on DebugDrawSpatialGrid() and off DebugDrawOctahedralValues() in UpdateLighting()" "15295": "The spatial grid looks pretty solid" "15337": "Toggle on DebugDrawOctahedralValues() and off DebugDrawSpatialGrid() in UpdateLighting()" "15349": "Eyeball the light probes and realise that our scale is wrong" "15377": "Reacquaint ourselves with the scaling in PushLightingRenderValues() and SumLight()" "15667": "Make SumLight() contract the LIGHT_LOOKUP_VOXEL_DIM by 1 in all dimensions when setting VoxR" "15694": "Our scaling now seems right" "15714": "Toggle off drawing of the lights in UpdateAndRenderEntities() and DebugDrawOctahedralValues() in UpdateLighting()" "15744": "The light seems pretty stable" "15836": "Consider aligning the lighting region such that the camera remains well within it" "15883": "The lighting region is biased" "15928": "Increase the LIGHT_LOOKUP_VOXEL_DIM_X from 24 to 28, and LIGHT_LOOKUP_VOXEL_DIM_Y from 16 to 20" "15952": "The lighting region remains biased" "15998": "Toggle off the camera bounds drawing in UpdateAndRenderWorld()" "16052": "Traverse the orphanage as if playing the game" "16119": "Decrease tUpdateBlend from 1 to 15/60 in UpdateLighting()" "16158": "Traverse the orphanage" "16167": "Move the ray debug drawing out of the way in UpdateLighting()" "16187": "Traverse the orphanage as if playing the game, and admire the lighting" "16224": "Toggle off LIGHT_ATLAS_ASSERT and GRID_RAY_CAST_DEBUGGING" "16265": "~41ms per frame" "16328": "Toggle off HANDMADE_INTERNAL and HANDMADE_SLOW, and stub out DIAGRAM_SetOrigin() and RenderDiagrams()" "16453": "Feel the performance" "16469": "Delete WalkTableOffset from light_sample_directions" "16530": "Run hhsphere with an octahedron texel count and ray per texel of 8" "16593": "Feel the performance with 8 rays per texel" "16609": "Toggle on HANDMADE_INTERNAL and stub out world and world_position" "16676": "~23ms per frame" "16698": "Toggle on HANDMADE_SLOW" "16707": "~26ms per frame" "16727": "Determine to toggle off the diffuse blend" "16761": "~29ms per frame" "16767": "Toggle off the diffuse blend in ComputeLightPropagationWork()" "16772": "~29ms per frame" "16794": "Toggle on the diffuse blend in ComputeLightPropagationWork()" "16803": "~29ms per frame" "16813": "Toggle off FullCast() in ComputeLightPropagationWork()" "16821": "~16ms per frame" "16842": "Toggle on FullCast() in ComputeLightPropagationWork()" "16852": "Admire our excellent interior lighting" "16919": "Consider specially handling light probes embedded in geometry" "17012": "Toggle on the player's light in UpdateAndRenderWorld()" "17090": "Lights produce a glow when eclipsing a light probe" "17119": "Toggle on DebugDrawOctahedralValues() in UpdateLighting()" "17129": "Our player's light occludes the light probes, removing light from the system" "17149": "Darken the player's light from 10 to 5, and increase its size in Z from 0.5 to 1" "17173": "Check out the player's light" "17186": "Revert the player's light size, and elevate it from 2 to 2.5" "17202": "The player's light still occludes the light probe" "17204": "Elevate the player's light from 2.5 to 3" "17210": "The player's light no longer occludes the light probe" "17217": "Toggle off DebugDrawOctahedralValues() in UpdateLighting()" "17226": "Traverse the orphanage admiring the light" "17237": "Brighten the player's light from 5 to 8" "17244": "Traverse the orphanage admiring the light" "17276": "Toggle off StandardLightingPattern()" "17306": "Illustrate the checkerboard patterning from the sampling sphere" "17382": "Prevent GridRayCast() from zeroing out HitRefColor and HitEmission upon walking the distance" "17434": "See no difference in the lighting, but admire it nevertheless" "17501": "Switch GridRayCast() from the sample table lookup to sampling in a white noise pattern" "17728": "The light flickers with this white noise sampling" "17761": "Make GridRayCast() cast 32 rays" "17779": "The light goes over-bright" "17785": "Make GridRayCast() cast 32 rays correctly weighted" "17842": "The light flickers less with 32 rays" "17897": "Decrease the RayCount from 32 to 16 in GridRayCast()" "17906": "The light flickers more with 16 rays" "17910": "Increase the RayCount from 16 to 64 in GridRayCast()" "17919": "The light barely flickers with 64 rays" "17942": "Decrease the RayCount from 64 to 8 in GridRayCast(), and decrease tUpdateBlend from 15/60 to 6/60 in UpdateLighting()" "17971": "The light looks pretty good" "18026": "Toggle on the room lights in StandardLightingPattern()" "18043": "We barely notice flicker, and can get over-brighting indoors with many lights" "18181": "Toggle off the player's light in UpdateAndRenderWorld()" "18192": "I think the darker one looked awesome" "18203": "The interior does not over-brighten without the player light" "18215": "Toggle off AddPattern() on the MainRoom in CreateOrphanage()" "18244": "Traverse the orphanage to the unlit main room" "18263": "Make MoveEntity() move the entity and then leave" "18343": "Hit our DiagramDepth == 0 assertion in RenderDiagrams()" "18355": "Make MoveEntity() call DIAGRAM_End() after moving the entity" "18398": "Make MoveEntity() return after moving the entity entity system" "18409": "Our glove now moves with us" "18430": "Make AddPlayer() call AddPieceLight() on the Glove" "18549": "Our light convects too much" "18556": "Make GridRayCast() zero out HitRefColor and HitEmission upon walking the distance" "18593": "Our light still convects too much" "18599": "Prevent GridRayCast() from zeroing out HitRefColor and HitEmission upon walking the distance" "18625": "Darken the glove's light from 5 to 1 in AddPlayer()" "18626": "Take our dim green glove light into the main room" "18647": "Brighten the glove's light from 1 to 3 in AddPlayer()" "18657": "Our light feeds back when we stand still" "18765": "Prevent FullCast() from blacking out light probes inside geometry" "18812": "Our light no longer blacks out when a light probe is inside geometry" "18854": "Consider our over-brighting bug" "18901": "Let FullCast() cast rays from inside geometry" "18923": "The light goes over-bright" "18933": "Consider our over-brighting bug" "19026": "Make FullCast() blacken rather than cast rays from inside geometry" "19084": "Determine to add an exposure curve and make all lights between 0 and 1 brightness" "19125": "handmade_hero I like this super basic neutral exposure curve as a default" "19180": "handmade_hero Greetings Casey! May you update SendOwl code download, please? It seems stuck on Day 346 with no updates" "19226": "One last look at our light contamination" "19252": "handmade_hero_646_source.zip is what I'm showing" "19261": "One last look at our light contamination (cont.)" "19307": "End it here for today" "19321": "Sorry, I wrote it wrong. 646. But 646 is February 28th" "19366": "Call it there" --- name: "day651" title: "Fixing Light Feedback" markers: "0": "Recap and set the stage for the day looking into light transport" "175": "Light Transport" "194": "Light Transport: 1. Throwing a light source in a scene, sampling and the inverse-square law" "1019": "Light Transport: 2. Our lack of a reflectance equation that distributes energy fairly without adding energy to the system" "1664": "Light Transport: Distributing reflected light fairly" "2114": "Drink of water" "2118": "afk" "2132": "Return and clean the board" "2217": "Light Transport: Photon counting, Collection 1 (Direct)" "2616": "Light Transport: Photon counting, Collection 2 (Reflected)" "3196": "Light Transport: Energy conservation and collection of light from other probes" "3318": "afk" "3325": "Return" "3335": "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" "3341": "Reduce the lightboard scene's audio" "3392": "Energy conservation confusion" "3424": "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?" "3549": "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" "3626": "Consider reading about light probes" "3855": "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" "3931": "Recall the original paper we read on light probes" "4035": "Consult 'Dynamic Diffuse Global Illumination with Ray-Traced Irradiance Fields'" "4445": "Reacquaint ourselves with ComputeLightPropagationWork() and BuildDiffuseLightMaps()" "4617": "Consider ordering Real-Time Rendering" "4707": "Consult 'Real-Time Global Illumination using Precomputed Light Field Probes'" "5388": "Demo the light feedback" "5410": "Darken the glove's light from 3 to 1 in AddPlayer()" "5421": "The light does not feed back" "5479": "Brighten the glove's light from 1 to 2 in AddPlayer()" "5488": "The light slowly feeds back" "5511": "Darken the glove's light from 2 to 1 in AddPlayer()" "5531": "The light does not feed back, but why?" "5622": "1.1 * 1.1 = larger than original" "5688": "Consider fixing the occlusion bug" "5743": "Reacquaint ourselves with the bilinear filtering code in GridRayCast()" "5959": "Reacquaint ourselves with our surface colours" "6202": "Brighten the glove's light from 1 to 1.25 in AddPlayer()" "6255": "The light does not feed back" "6274": "Brighten the glove's light from 1.25 to 1.3 in AddPlayer()" "6288": "The light appears not to feed back" "6309": "Brighten the glove's light from 1.3 to 1.5 in AddPlayer()" "6318": "The light appears not to feed back" "6330": "Brighten the glove's light from 1.5 to 1.75 in AddPlayer()" "6339": "The light slowly feeds back" "6428": "Q: Is it possible that the color dampening hits some negative values and adds to the lighting instead?" "6498": "But did we always have this problem? Like, can be the removal of Z or the walking grid make this happen?" "6521": "Decrease tUpdateBlend from 6/60 to 1/60 in UpdateLighting()" "6532": "The light appears not to feed back" "6552": "Brighten the glove's light from 1.75 to 2 in AddPlayer()" "6562": "The light slowly feeds back" "6574": "Increase tUpdateBlend from 1/60 to 6/60 in UpdateLighting()" "6578": "The light quickly feeds back" "6646": "Consider how to progress, possibly applying an exposure curve" "6753": "Consult LearnOpenGL's HDR article for a simple exposure curve" "6822": "Make CompileZBiasProgram() clamp SurfaceReflect in a single call" "6839": "That seems fine" "6847": "Make CompileZBiasProgram() apply Reinhard tone mapping to the SurfaceReflect" "6895": "The light feeds back" "6932": "Remove Reinhard tone mapping from SurfaceReflect in CompileZBiasProgram()" "6948": "Are beginner questions okay?" "6963": "Eyeball our over-brighting bug" "7045": "Make GridRayCast() zero out HitRefColor and HitEmission upon walking the distance" "7112": "The light feeds back" "7133": "Make GridRayCast() only zero out HitRefColor and HitEmission upon hitting the SPATIAL_GRID_NODE_TERMINATOR" "7151": "The light feeds back" "7159": "Revert our changes to GridRayCast()" "7212": "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?" "7333": "Last time I watched, there was sus copy pasta code at the TransferPPSAccum line endings. Can we peak there again?" "7367": "Yeah, there, 0 as last args" "7390": "Describe the shuffler code in GridRayCast()" "7707": "Consider our definition of the light transfer problem to be wrong" "7745": "Consider working through the light transfer problem on the light board" "7798": "What is the normal storing thing the paper was talking about?" "7808": "Toggle on DebugDrawOctahedralValues() in UpdateLighting()" "7837": "Describe our light probe octahedral values" "7883": "Darken the glove's light from 2 to 1 in AddPlayer()" "7906": "Describe our light probe octahedral values, without feedback" "8006": "Toggle on GRID_RAY_CAST_DEBUGGING" "8017": "Describe the paper's storage of hit surface normal" "8194": "Toggle off room lights in StandardLightingPattern()" "8243": "Our glove alone does not contaminate" "8268": "Make CompileZBiasProgram() multiply the SurfaceReflect by 10" "8325": "Our glove is brighter" "8336": "Make CompileZBiasProgram() multiply the SurfaceReflect by 100" "8341": "Our glove is brighter still, and does not feed back" "8368": "Toggle on room lights in StandardLightingPattern(), and reduce their intensity from 10 to 0.1" "8404": "Our world is the brightness we'd like, and the light does not feed back" "8417": "Toggle off DebugDrawOctahedralValues() in UpdateLighting()" "8436": "Our world is the brightness we'd like, and the light does not feed back" "8526": "Darken the glove's light from 1 to 0.2 in AddPlayer()" "8551": "Our lighting looks basically correct" "8573": "Darken the moonlight from 0.2 to 0.025 in GenerateApron()" "8606": "The exterior light is still quite bright" "8610": "Darken the moonlight from 0.025 to 0.01 in GenerateApron()" "8617": "The exterior light is maybe about right" "8621": "Darken the moonlight from 0.01 to 0.005 in GenerateApron()" "8629": "The light looks as we'd like" "8694": "Gorgeous light that we don't understand" "8709": "An unanticipated portion of the system is working as a percentage" "8771": "Determine to address our occluded light probe darkening problem" "8800": "Toggle on DebugDrawOctahedralValues() and DebugDrawSpatialGrid() in UpdateLighting()" "8826": "Illustrate our darkened occluded light probe" "8857": "Make DebugDrawSpatialGrid() colour the leaves with their RefColor" "8949": "The spatial grid leaves are all white" "8964": "Make DebugDrawSpatialGrid() account for Emission when colouring the leaves" "9005": "Illustrate our darkened embedded light probes" "9079": "Describe the code that blackens embedded light probes in FullCast()" "9119": "Prevent FullCast() from touching embedded light probes" "9133": "Light probes no longer darken when occluded by the glove, but neither do they receive its full light contribution" "9180": "Consider running the occlusion check on every sample" "9318": "Let FullCast() cast rays from embedded light probes" "9336": "The light looks good" "9397": "Document the embedded light probe ray casting" "9444": "The light leaks through walls" "9525": "Make FullCast() distinguish between emitters and occluders, making only the latter contribute to the IsInside check" "9738": "The light no longer leaks through walls" "9819": "Wouldn't IsEmission <= Zero work?" "9824": "Reorient the Mask computation around IsOccluder in FullCast()" "9845": "Light probes remain not directly lit by overlapping emitters" "9967": "Toggle off DebugDrawSpatialGrid() in UpdateLighting()" "9988": "Our octahedron directions may be nonsense" "10021": "DebugDrawOctahedralValues() isn't nonsense" "10052": "Consider writing our emission values into the light probes as a pre-pass" "10115": "Curious what the total size of Handmade Hero is (clientside)" "10132": "Consider writing our emission values into the light probes as a pre-pass (cont.)" "10180": "The binary" "10195": "1 MiB executable size" "10239": "Without assets? That's so small" "10278": "Consider writing our emission values into the light probes as a pre-pass (cont.)" "10365": "I'd say to the left" "10452": "Consider writing the emission value of light volumes into light probes proportional to their overlap" "10728": "Consider writing the emission value of light volumes into light probes stochastically" "10807": "Reacquaint ourselves with our use of the specular light atlas" "11034": "Rename LightDepthSampler to SpecularSampler in the OpenGL renderer" "11055": "Consider sampling from the specular map rather than the diffuse map" "11139": "Yearn for the ability in C++ to #include a file as a string" "11239": "Remove GetIrradiance()" "11321": "I think std::embed got killed sadly" "11548": "Enough of those committees and you can work towards eliminating all bad decisions" "11617": "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)" "11640": "I just always have my own path for #embed in my metaprogram, and throw my shaders into metacode" "11663": "Reacquaint ourselves with SampleLighting()" "11712": "If you don't like C++ why are you using C++?" "11746": "Reacquaint ourselves with specular and diffuse map usage in SampleLighting()" "11851": "Check out our light" "11867": "Toggle from radial to our manual bilinear interpolation in SampleLighting()" "11882": "Our light looks the same" "11898": "Toggle off our manual interpolation path in CompileZBiasProgram()" "11905": "Our light looks the same" "11938": "Double-check that we call SampleLighting()" "11991": "Toggle off DebugDrawOctahedralValues() in UpdateLighting()" "11996": "Our light interpolation looks a little squarer" "12053": "Toggle on our radial interpolation in SampleLighting9)" "12057": "Our light looks the same" "12063": "Try making SampleLighting() colour the light red" "12085": "We're reloading shaders" "12090": "Let SampleLighting() work as normal, toggling from our radial to the regular bilinear interpolation" "12106": "Consider the regular bilinear sampling to be fine" "12137": "Remove our fancier interpolation code from SampleLighting() and use v3 rather than v4" "12229": "Our light looks the same" "12239": "Fix indentation of SumLight()" "12297": "Is there really no way to indent multiple lines together in 4coder?" "12342": "Rename LightColorSampler to DiffuseSampler in the OpenGL renderer" "12378": "Our light looks the same" "12385": "Make SampleLighting() use the SpecularSampler" "12409": "Our light now looks unpleasant and shiny" "12449": "Reacquaint ourselves with the reflection directionality in SumLight()" "12528": "So you can just say move these 10 lines one to the left without it messing it up? This sounds painful" "12591": "Check out our specular light" "12609": "Switch SumLight() to use the reflection vector" "12650": "Check out our actual specular light" "12724": "handmade_hero You can use a macro like '#define shader_code(a) #a' and then on 'char *shader = shader_code();' the gets auto indented. At least that works for me. (Sorry if you read the previous one and ignored it on purpose)" "12787": "Introduce OctFrom() for SumLight() to call and compute both the specular and diffuse atlases to pass to SampleLighting()" "12994": "Our light kind of looks right" "13024": "Make SampleLighting() sum together the specular and diffuse atlases" "13046": "Check out our half-and-half specular / diffuse lighting" "13066": "Set up SampleLighting() to interpolate between our specular and diffuse atlases using a Material" "13126": "Check out our light" "13163": "#define EmbedShader()" "13255": "Hit a "Shader validation failed" error" "13320": "Scour our EmbedShader() calls for syntax errors" "13371": "I think the preprocessor isn't going to preserve the #if's" "13425": "Try removing the #if's from our EmbedShader() calls" "13449": "Run without hitting a "Shader validation failed" error" "13461": "Revert our introducing of EmbedShader()" "13516": "Consider our light to be too bright" "13547": "Prevent CreateOrphanage() from adding light outdoors" "13598": "Our moonlight is still a little too bright" "13640": "Darken the moonlight from 0.2 to 0.01 in GenerateRoom()" "13665": "Our moonlight seems better" "13716": "Decrease tUpdateBlend from 6/60 to 3/60 in UpdateLighting()" "13737": "Our light doesn't look very flickery" "13763": "Decrease tUpdateBlend from 3/60 to 1/60 in UpdateLighting()" "13768": "Our light still doesn't flicker" "13782": "Increase tUpdateBlend from 1/60 to 20/60 in UpdateLighting()" "13791": "Our light flickers" "13803": "Decrease tUpdateBlend from 20/60 to 12/60 in UpdateLighting()" "13816": "Our light is a little flickery" "13980": "Increase RayCount from 8 to 16 in GridRayCast()" "13992": "Our light minimally flickers" "14076": "Determine to tackle forward-rasterisation next week" "14099": "Toggle off room lights in StandardLightingPattern()" "14112": "Admire our spooky orphanage" "14182": "Make CreateOrphanage() put a Snake in BedroomA, and darken the light from 5 to 1 in SnakePattern()" "14304": "Watch the snake in BedroomA" "14331": "Darken the light from 1 to 0.25 in SnakePattern()" "14342": "I think the glove needs some glowy light emitting particle effects now" "14348": "Watch the snake get stuck in the corner" "14366": "Make CreateOrphanage() put Snakes in BedroomB and BedroomC" "14397": "Our snakes lock up in the corner" "14430": "Prevent CreateOrphanage() from putting snakes in the bedrooms, and make StandardLightingPattern() create dimmer and randomly coloured room lights" "14468": "Admire our fantastic light" "14521": "Plan to fix the overlapped emitter and light probe dimming bug, and maybe bundle our rays" "14573": "So we're just ignoring the feedback issue?" "14677": "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?" "14794": "That's it for today" --- name: "day652" title: "Stochastic Ray Origins" markers: "0": "Recap and set the stage for the day handling light emitters overlapping light probes" "161": "Q: Scene is wrong" "181": "Illustrate our overlapped light emitter-probe dimming bug" "236": "Note how FullCast() doesn't cast rays from overlapped light probes" "268": "Toggle on DebugDrawOctahedralValues() and DebugDrawSpatialGrid() in UpdateLighting()" "289": "Illustrate our overlapped light emitter-probe dimming bug" "492": "Possible overlapped emitter-probe solutions: 1. Rasterise light into overlapped probes as a pre-pass" "652": "Possible overlapped emitter-probe solutions: 2. Jitter sampling locations" "672": "Possible overlapped emitter-probe solutions: 3. Disallow overlapping of emitters and probes" "831": "Consider how to handle overlapped light emitters and probes, admiring our specular lighting" "1026": "Toggle off DebugDrawOctahedralValues() and DebugDrawSpatialGrid() in UpdateLighting()" "1034": "Consider trying jittering the sampling locations" "1132": "Possible overlapped emitter-probe solutions: 4. Permit rays to hit geometry they're inside of" "1194": "Reacquaint ourselves with the intersection testing code in GridRayCast()" "1434": "Let GridRayCast() cast rays from inside everything" "1459": "Embedded probes now see light" "1519": "Enable GridRayCast() to track if a light probe was inside geometry" "1616": "Embedded probes still see light" "1671": "Toggle on DebugDrawOctahedralValues() in UpdateLighting()" "1679": "Light probes do not gather light from overlapping emitters" "1708": "Our light probe's rays must be hitting the overlapping emitter" "1776": "That tInside variable doesn't seem to be used, in case you assume it is?" "1793": "Investigate why GridRayCast() doesn't light up our overlapped light probe" "2003": "Make GridRayCast() clamp the tMin to 0 and above" "2069": "Light probes gather light from overlapping emitters, but too brightly" "2167": "Toggle on room lights in StandardLightingPattern()" "2186": "We happily lack light bleed" "2228": "Comment tInside as intentionally not used in GridRayCast()" "2304": "Note our overly bright eclipsed probes, also with square artifacting" "2504": "Consider jittering light ray origins in X and Y" "2616": "Weld FullCast() and GridRayCast() together" "2798": "We run just as before" "2814": "Toggle off DebugDrawOctahedralValues() in UpdateLighting()" "2825": "Consider jittering light ray origins in X and Y" "2865": "Rename Pick to DebugPick in FullCast()" "2997": "Determine to jitter light ray origins in X and Y" "3047": "Make FullCast() jitter light ray origins in X and Y" "3165": "Our lighting system is still doing something" "3215": "Make FullCast() keep jittered rays within their original tile" "3295": "Our lighting looks a little wrong" "3342": "Consider how to proceed" "3413": "Reduce the JitterRadius in FullCast()" "3424": "We have a little bit of light bleed" "3486": "Consider what could be wrong with the jittered lighting" "3548": "Not backface culling rays" "3578": "Enable GRID_RAY_CAST_DEBUGGING" "3612": "Our debug overlay is now over-bright" "3632": "Our ray casting isn't obviously wrong" "3712": "Make FullCast() draw our ray's starting location" "3776": "Check out a ray's starting locations" "3873": "Change FullCast() to clamp the tRay to 0 as tClampedCompare, to retain the negatives" "3992": "Our embedded ray casting looks technically correct" "4127": "The jittering looks okay, but doesn't behave well when moving between probes" "4255": "It looks like water reflecting light rays" "4289": "Make SampleLighting() use a pure diffuse material" "4294": "Demo our pure diffuse light" "4321": "Make SampleLighting() use a pure specular material" "4328": "Demo our pure specular light" "4392": "Make SampleLighting() use a half-and-half specular / diffuse material" "4405": "Demo our half-and-half specular / diffuse light" "4441": "Illustrate our square artifacting around overlapped light probes" "4507": "Make AddPlayer() shrink the glove's light from 0.5 to 0.25" "4552": "Our glove's smaller light almost disappears" "4645": "Make AddPlayer() brighten the glove's light from 0.2 to 0.5" "4652": "Our glove's smaller but brighter light still almost disappears" "4825": "Make AddPlayer() enlarge the glove's light from 0.25 to 2" "4839": "Our glove's larger light works" "4866": "Make AddPlayer() darken the glove's light from 0.5 to 0.125" "4889": "Our glove's larger and darkened light looks just right" "4918": "Make AddPlayer() darken the glove's light from 0.125 to 0.05" "4927": "Our glove's larger and darkened light looks as expected" "5033": "Make AddPlayer() shrink the glove's light from 2 to 1, and brighten it from 0.05 to 0.1" "5048": "Our glove's light remains" "5112": "Make AddPlayer() shrink the glove's light from 1 to 0.5" "5125": "Our glove's light remains" "5160": "Make AddPlayer() shrink the glove's light from 0.5 to 0.4" "5172": "Our glove's light blinks" "5283": "Consider stratifying the light sampling" "5365": "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" "5398": "Clean out cruft from UpdateLighting()" "5590": "We still run" "5592": "Make FullCast() stratify the samples into a 4×4 grid" "5806": "Our glove's light still blinks" "5935": "Temporarily make FullCast() seed its random series with a constant value, to fix the rays" "5964": "Our glove's light still pulsates with fixed rays, but why?" "6246": "Scour FullCast() for sources of noise" "6307": "Maybe the position of the glove, the bobbing, turn that off?" "6311": "The glove doesn't bob" "6338": "Increase tUpdateBlend from 12/60 to 1 in UpdateLighting()" "6384": "Our glove's light blinks vigorously" "6496": "Runaway NaNs" "6526": "Our glove's light blinks vigorously (cont.)" "6586": "Toggle off room lights in StandardLightingPattern()" "6603": "Only overlapped light probes have the blinking bug" "6670": "Temporarily prevent GridRayCast() from casting rays from inside geometry" "6701": "Our light still blinks, but less vigorously" "6729": "Let GridRayCast() cast rays from inside geometry" "6734": "Consider how to approach our blinking bug" "6854": "Could you turn on NaN exceptions so if we hit a NaN the program will halt?" "6859": "Check our tUpdate and JitterRadius" "6921": "Decrease the JitterRadius multiplier from 0.45 to 0.4 in FullCast()" "6930": "Our light still blinks" "6934": "Decrease the JitterRadius multiplier from 0.4 to 0.1 in FullCast()" "6936": "Our light blinks more sporadically" "6970": "Increase the JitterRadius multiplier from 0.1 to 0.45 in FullCast()" "6991": "Determine to get snacks and enable NaN exceptions" "7013": "Maybe try just setting tUpdateBlend to 1 in both clauses of that if?" "7022": "Remove the tUpdateBlend modification branch from UpdateLighting(), and remove Accumulating, AccumulationCount and FrameOdd from lighting_solution" "7055": "Our light continues to blink" "7089": "Determine to get snacks and enable NaN exceptions" "7127": "Grab snacks" "7137": "afk" "7386": "Return with snacks" "7422": "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" "7451": "Casey: If the ray can be negative, then couldn't tMin be > tMax some of the time?" "7482": "Why'd it change from a throb to a blink?" "7504": "Demo the blinking light" "7512": "Toggle on room lights in StandardLightingPattern()" "7522": "Demo the blinking, with stable lighting" "7574": "Revert FullCast() to seed its random series randomly" "7593": "Demo the blinking with noisy lighting" "7634": "The blinking?" "7651": "Demo the flickery lighting (cont.)" "7791": "So temporal averaging made the blink into a throb, got it" "7841": "Wonder why the glove light blinks when small enough" "7867": "Make AddPlayer() enlarge the glove's light from 0.4 to 0.5" "7896": "Our glove's larger light rarely blinks" "7929": "Can you see if the gameplay speed is related by slowing down the clock?" "7941": "Slowing the timestep stops the light from blinking (even after speeding it back up again)" "8088": "Toggle on DebugDrawOctahedralValues() and DebugDrawSpatialGrid() in UpdateLighting()" "8091": "Our light probe is suspiciously positioned in Z relative to the glove" "8157": "Toggle off DebugDrawOctahedralValues() and DebugDrawSpatialGrid() in UpdateLighting()" "8176": "Halve the JitterRadius along Z, and make FullCast() jitter light ray origins in Z" "8201": "Our glove's light flickers more sporadically" "8251": "Increase the JitterRadius multiplier from 0.45 to 0.5 in FullCast()" "8264": "Our glove's light still flickers sporadically" "8336": "Decrease tUpdateBlend from 1 to 12/60 in UpdateLighting()" "8339": "The glove's light now barely flickers" "8405": "Light leaks to the outdoors" "8473": "Admire the lighting, and consider putting in an exposure curve and a notion of brightness (for bloom)" "8627": "Make AddPlayer() shrink the glove's light from 0.4 to 0.25, and brighten it from 0.1 to 0.2" "8648": "The glove's smaller light varies more" "8679": "Make AddPlayer() enlarge the glove's light from 0.25 to 0.75, and darken it from 0.2 to 0" "8703": "Our glove's light is dark" "8710": "Make AddPlayer() brighten the glove's light from 0 to 0.1" "8728": "The glove's larger light is pretty stable" "8786": "Consider adding spheres" "9096": "Make AddPlayer() shrink the glove's light from 0.75 to 0.25" "9106": "Our glove's smaller light is dimmer" "9119": "Make AddPlayer() brighten the glove's light from 0.1 to 1" "9131": "Our glove's small and bright light is not too noisy" "9199": "Consider how to proceed" "9247": "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)" "9567": "How do the other engines "skip" the direct light and only use secondary bounces?" "9688": "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?" "9786": "So you either have to do all sphere lights or all AABB lights?" "9792": "Describe the changes to FullCast() required to support spherical lights" "9959": "But shouldn't a small enough box give a spherical falloff as well?" "9991": "Consider how to proceed" "10073": "Increase RayCount from 16 to 256 in GridRayCast()" "10100": "The light still doesn't look great around the light source" "10129": "Decrease RayCount from 256 to 16 in GridRayCast()" "10139": "Our glove's light is noisier" "10146": "Make AddPlayer() shrink the glove's light from 0.25 to 0.1" "10161": "Run the game" "10164": "Make AddPlayer() shrink the glove's light from 0.1 to 0.05" "10168": "Our glove's light is barely visible" "10188": "Increase RayCount from 16 to 1024 in GridRayCast()" "10196": "Our glove's light is barely visible" "10259": "Make AddPlayer() brighten the glove's light from 1 to 10, and decrease the RayCount from 1024 to 16 in GridRayCast()" "10283": "Our light flickers" "10303": "Increase RayCount from 16 to 1024 in GridRayCast()" "10311": "Our light no longer flickers" "10388": "Decrease RayCount from 1024 to 16 in GridRayCast(), and make AddPlayer() brighten the glove's light from 10 to 20" "10401": "Our light flickers" "10425": "Increase RayCount from 16 to 1024 in GridRayCast()" "10429": "Our light no longer flickers" "10452": "Make AddPlayer() brighten the glove's light from 20 to 100, and decrease the RayCount from 1024 to 64 in GridRayCast()" "10474": "Our performance has degraded" "10491": "Decrease RayCount from 64 to 16 in GridRayCast()" "10501": "Our light flickers" "10521": "Increase RayCount from 16 to 1024 in GridRayCast()" "10527": "Our light no longer flickers" "10557": "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()" "10593": "Our glove's light has a square falloff" "10608": "Increase RayCount from 16 to 1024 in GridRayCast()" "10615": "Our glove's light still has a square falloff" "10637": "Decrease RayCount from 1024 to 16 in GridRayCast()" "10647": "Our glove's light still has a square falloff" "10675": "Could you then also remove the temporal smooth?" "10688": "Increase tUpdateBlend from 12/60 to 1 in UpdateLighting()" "10692": "Our light flickers" "10700": "Increase RayCount from 16 to 1024 in GridRayCast()" "10706": "Our glove's light still has a square falloff" "10743": "Decrease RayCount from 1024 to 16 in GridRayCast()" "10761": "Our light flickers" "10779": "Start to enable FullCast() to handle spherical lights" "10947": "Switch to the lightboard" "11036": "Sphere vs. Ray" "11322": "Sphere vs. Ray intersection equation, Take 1" "11796": "Sphere vs. Ray intersection equation, Take 2" "11999": "Switch to the code" "12012": "Do we need the coordinates? Or do we just need to know if it intersects?" "12051": "Reacquaint ourselves with the sphere intersection code in CastSampleRays() from ray.cpp" "12272": "SQRTPS() and DIVPS() are on ports 0, and cost 3 cycles" "12459": "Enable FullCast() to handle spherical lights based on CastSampleRays() from ray.cpp" "13332": "Introduce SquareRoot()" "13361": "Enable FullCast() to handle spherical lights based on CastSampleRays() from ray.cpp (cont.)" "13498": "Our sphere code is running" "13504": "Toggle off the spherical intersection in FullCast()" "13565": "Our glove's light has a square falloff" "13578": "Toggle on the spherical intersection in FullCast()" "13586": "Our light is doing something different" "13596": "Enable GridBuildSpatialPartition() to handle spherical lights" "13823": "Our glove's light looks less square" "13861": "Decrease tUpdateBlend from 1 to 12/60 in UpdateLighting()" "13867": "Our glove's light looks even less square" "13893": "Increase RayCount from 16 to 1024 in GridRayCast()" "13918": "Our glove's light is centred wrong" "13967": "Decrease RayCount from 1024 to 16 in GridRayCast(), and make AddPlayer() darken the glove's light from 1 to 0.25" "13990": "Our glove's light is centred wrong" "14053": "Double-check the spherical light code in GridBuildSpatialPartition() and GridRayCast()" "14305": "Eyeball our spherical light" "14350": "Make AddPlayer() add a light to the hero's head rather than the glove" "14408": "We may be detecting intersections where the sphere doesn't actually touch" "14510": "Probably NaN I would guess" "14545": "Fix the RootTerm computation in GridRayCast(), and test it before square rooting it" "14682": "Our spherical light looks better" "14741": "Make AddPlayer() brighten the glove's light from 0.25 to 0.5" "14763": "Our light still looks a bit square" "14800": "Increase RayCount from 16 to 1024 in GridRayCast()" "14813": "Our light still looks a bit square" "14906": "Disable LIGHTS_ARE_SPHERES" "14920": "Our light looks brighter and more prominently square" "14971": "Yeah, it looks like it's just being clipped to the voxel somehow" "14990": "Enable LIGHTS_ARE_SPHERES" "14995": "Our light looks dimmer and less square" "15089": "Decrease RayCount from 1024 to 16 in GridRayCast()" "15101": "Our light trails behind us" "15119": "Increase tUpdateBlend from 12/60 to 20/60 in UpdateLighting()" "15142": "Our light trails less, but flickers" "15168": "Increase tUpdateBlend from 20/60 to 1 in UpdateLighting()" "15174": "Our light flickers, and seems to have a frame of lag" "15260": "Increase tUpdateBlend from 1 to 12/60 in UpdateLighting()" "15271": "Determine to make the light interpolation less square" "15331": "Disable LIGHTS_ARE_SPHERES" "15337": "Our light looks brighter and more prominently square" "15368": "That's it for today, with a plug of Molly Movie Club" --- name: "day653" title: "Adding a Filmic Response Curve" markers: "0": "Recap and set the stage for the day improving the quality of single bright light sources" "67": "Decrease RayCount from 16 to 8 in GridRayCast()" "84": "Smooth framerate with good light everywhere other than around small fast-moving light sources" "155": "Diffuse gather looks quite good, and the flicker is good enough" "319": "Consider writing light into overlapping probes as a forward pass" "446": "Toggle on DebugDrawSpatialGrid() in UpdateLighting()" "459": "Our light source is lower than expected" "507": "Make AddPlayer() elevate the head light from 0 to 0.5" "550": "Our light is higher up" "559": "Make AddPlayer() elevate the head light from 0.5 to 1" "567": "Our light is less square" "651": "Toggle on DebugDrawOctahedralValues() in UpdateLighting()" "661": "Glimpse our spatial grid and octahedral values" "665": "Toggle off DebugDrawOctahedralValues() and DebugDrawSpatialGrid() in UpdateLighting()" "672": "Our light is still a bit square" "699": "Make AddPlayer() decrease the head light's intensity from 0.5 to 0.25, and add the glove light" "715": "Our glove light has a fair bit of lag, and it's still a bit square" "810": "Wait, I grabbed some water. Is this with tone mapping now?" "848": "Make AddPlayer() elevate the glove light from 0 to 0.5" "870": "Consider the possibility of repairing the squareness" "905": "Consider doing filmic tone mapping" "1795": "Introduce ACESFilm() and remove IrradiancePack() and stale code from SumLight()" "2043": "Check out our "before tone mapping" lighting" "2057": "Make the fragment shader in CompileZBiasProgram() call ACESFilm()" "2137": "Our light already looks a lot more dramatic, but still square" "2247": "Enable LIGHTS_ARE_SPHERES" "2252": "The lights dim, but remain square" "2277": "Disable LIGHTS_ARE_SPHERES" "2284": "Consider rasterising light into overlapped probes as a pre-pass" "2473": "How about jittering the light probe positions?" "2540": "Admire the lighting besides the squareness" "2634": "Toggle off room lights in StandardLightingPattern()" "2647": "Admire the indirect lighting with only one light source" "2674": "Increase RayCount from 8 to 64 in GridRayCast()" "2692": "The light now has very little flicker" "2711": "Decrease RayCount from 64 to 16 in GridRayCast()" "2713": "Consider rasterising light into overlapped probes as a pre-pass" "2810": "Toggle on DebugDrawOctahedralValues() in UpdateLighting()" "2812": "Our light fall-off has a hard edge not explained by linear interpolation" "2969": "Make SampleLighting() use a pure diffuse material" "3000": "Our diffuse map doesn't quite have the same problem" "3021": "Toggle off DebugDrawOctahedralValues() in UpdateLighting()" "3028": "Our light is still more square than we'd like" "3038": "Make SampleLighting() use a pure specular material" "3045": "Our small moving light is very hard edged in the specular map" "3056": "Make DebugDrawOctahedralValues() draw the SpecAtlas values, toggling it on in UpdateLighting()" "3083": "Our light probes pick up a far more gradual fall-off than appears" "3217": "Reacquaint ourselves with SumLight()" "3670": "Check out our current light" "3682": "Prevent SumLight() from shrinking LIGHT_LOOKUP_VOXEL_DIM by 1 when computing VoxR" "3690": "Our lighting shifts" "3777": "Revert SumLight() to shrink LIGHT_LOOKUP_VOXEL_DIM by 1 when computing VoxR" "3816": "Hunt for a corresponding minus 1 in FullCast()" "3979": "The light fall-off's hardness is influenced by the reflection angle" "4100": "Make SampleLighting() use a pure diffuse material" "4106": "Check out our pure diffuse light" "4193": "Consider changing the interpolation of the octahedral map" "4298": "Introduce Mestre() for SumLight() to use" "4747": "Our light is more circular" "4800": "Toggle off DebugDrawOctahedralValues() in UpdateLighting()" "4810": "Our more circular light is nicer, but maybe still not quite right" "4887": "Toggle on room lights in StandardLightingPattern()" "4904": "Our more circular light is better than the alternative" "4979": "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" "5062": "Comment out the Mestre() calls in SumLight()" "5081": "Our light looks great barring the squareness" "5095": "Determine to place a known point of light in the system" "5190": "Determine to make ComputeLightPropagationWork() further slice up the work for better threading" "5287": "Make FullCast() hard set the TransferPPS of all light probes in a radial pattern" "5494": "Our light fall-off does not look radial" "5516": "Multiply the distance between the origin and light probe by 0.1 to try and prevent more distant probes from zeroing out" "5525": "Our light fall-off looks radial" "5527": "Multiply the distance between the origin and light probe by 0.25" "5536": "Our light fall-off looks more blocky" "5618": "Make the fragment shader in CompileZBiasProgram() remove a guessed 0.1 from the SurfaceReflect" "5651": "Our light is blown out" "5660": "Make the fragment shader in CompileZBiasProgram() clamp SurfaceReflect to 0" "5711": "Our light fall-off is now circular" "5729": "Decrease the SurfaceReflect light floor removal from 0.1 to 0.01" "5741": "Our light fall-off is a little blocky again" "5748": "Increase the SurfaceReflect light floor removal from 0.01 to 0.05" "5762": "Our light fall-off is circular" "5778": "Comment out the hardcoded TransferPPS in FullCast()" "5789": "Our light falls to black" "5846": "Comment out the SurfaceReflect light floor removal in the fragment shader" "5856": "Our light is back" "5869": "Check Clamp0Inf() for bugs" "5888": "Decrease the SurfaceReflect light floor removal from 0.05 to 0" "5901": "Our light remains" "5906": "Increase the SurfaceReflect light floor removal from 0 to 0.01" "5915": "Our light darkens considerably" "5921": "Decrease the SurfaceReflect light floor removal from 0.01 to 0.001" "5930": "Our light brightens somewhat" "5947": "Increase the SurfaceReflect light floor removal from 0.001 to 0.01" "5959": "Our light fall-off is very circular" "5984": "Considering this is supposed to be specular, I find it odd that the region at full brightness is so large" "5997": "Make SampleLighting() use a pure specular material" "6004": "Our specular light fall-off remains circular" "6025": "Make SampleLighting() use a pure diffuse material" "6028": "Applying a natural floor enables our light to fall off radially" "6180": "Decrease the SurfaceReflect light floor removal from 0.01 to 0.0001" "6194": "Our light fall-off is square again" "6203": "Increase the SurfaceReflect light floor removal from 0.0001 to 0.01" "6213": "Our light fall-off is circular, but the solution is too dark" "6238": "Remove the SurfaceReflect light floor removal" "6258": "Is the ACESFilm() function contributing to the badness?" "6267": "The light with ACESFilm()" "6273": "Remove the ACESFilm() call" "6286": "The light without ACESFilm()" "6295": "Reinsert the ACESFilm() call" "6302": "The light with ACESFilm()" "6327": "Consider the light pretty reasonable" "6420": "Without flooring, linear interpolation won't cut it" "6459": "Would it be practical to up the voxel resolution a bit? Just to see the comparison" "6518": "Double the LIGHT_LOOKUP_VOXEL_DIM_X and LIGHT_LOOKUP_VOXEL_DIM_Y" "6541": "Our lighting region is larger" "6563": "Make UpdateLighting() halve the VoxCellDim in all dimensions" "6604": "Hit an out-of-bounds assert in GridBuildSpatialPartition()" "6628": "Make UpdateLighting() retain the full VoxCellDim in Z" "6663": "Hit an out-of-bounds assert in GridBuildSpatialPartition()" "6693": "Scour UpdateLighting() for sources of our out-of-bounds lookup" "6742": "Run an -Od build until hitting our IsInBounds() assertion in FlatIndexFrom()" "6910": "Investigate our IsInBounds() assertion hit in FlatIndexFrom()" "7017": "Remove the Z loops from GridBuildSpatialPartition()" "7120": "Run an -O2 build without asserting" "7146": "The light looks better, but with shiny sampling errors" "7187": "Quadruple the LIGHT_LOOKUP_VOXEL_DIM_X and LIGHT_LOOKUP_VOXEL_DIM_Y and make UpdateLighting() quarter the VoxCellDim in X and Y" "7216": "Hit an OpenGL error" "7226": "Revert LIGHT_LOOKUP_VOXEL_DIM_X, LIGHT_LOOKUP_VOXEL_DIM_Y and VoxCellDim to their original values" "7241": "Consider bigger light sources to be our only option" "7292": "Bigger and slightly weaker light source could work there, though" "7311": "Our light is pretty good" "7328": "Make AddPlayer() increase the lights' size to 0.7 and decrease the brightness to 0.1" "7368": "Our moving lights are less square" "7394": "Uncomment the Mestre() calls in SumLight()" "7417": "Our moving lights are more radial" "7432": "Make AddPlayer() increase the lights' size to 1" "7457": "How trivial is it to move to GPU?" "7484": "This bigger light actually looks square as the main light source outdoors" "7620": "Make AddPlayer() increase the lights' brightness to 0.5" "7650": "Our lights are blown out" "7662": "Reinstate the SurfaceReflect light floor removal of 0.01" "7707": "Our light fall-off is radial" "7827": "Rewrite the SurfaceReflect floor removal and ACESFilm() application" "7854": "Our light fall-off is radial" "7863": "Make StandardLightingPattern() increase the room lights' brightness to 0.5" "7932": "Patches of the solution fall to full darkness" "7995": "Make StandardLightingPattern() increase the room lights' brightness to 1" "8012": "Patches of the solution still fall to full darkness" "8060": "Revert the room lights' brightness to 0.05 in StandardLightingPattern(), and that of the head and glove lights to 0.1 in AddPlayer()" "8103": "Our light is dim but circular" "8106": "Decrease the SurfaceReflect light floor removal from 1 to 0" "8119": "Our light fall-off is square" "8137": "Try squaring the SurfaceReflect" "8159": "Our light fall-off is way less blocky" "8179": "Increase the SurfaceReflect multiplier from 100 to 1000" "8184": "Our light brightens a touch" "8226": "Partially revert the SurfaceReflect light floor removal to 0" "8233": "Our light fall-off is square" "8258": "Try to flatten the ACES filmic tone mapping curve" "8371": "Try setting B to 0 in ACESFilm()" "8384": "Our light fall-off doesn't differ much" "8405": "Play with the ACES filmic tone mapping curve" "8462": "Try setting Z to 0.05 [typo] in ACESFilm()" "8470": "Our light fall-off remains square" "8504": "Revert ACESFilm()" "8516": "I think you typed 0.05?" "8524": "Fix typo of Z from 0.05 to 0.5 in ACESFilm()" "8526": "Our light fall-off remains square" "8602": "Revert ACESFilm()" "8642": "Consider adding self-illumination and bloom, maybe leaving the square fall-off, removing 3D from the collision and adding gameplay rooms" "8816": "Enable LIGHTS_ARE_SPHERES" "8842": "Our light fall-off isn't materially different" "8855": "Disable LIGHTS_ARE_SPHERES" "8861": "Our light fall-off isn't materially different" "8872": "Decrease RayCount from 16 to 8 in GridRayCast()" "8876": "The light looks great" "8931": "Call it a day, with the determination to add bloom next time" "8950": "Framerate too high! Go back to 1 fps!" "8960": "Thank you, everyone" "9021": "We need an RTX ON comparison" "9024": "Thanks, everyone" --- name: "day654" title: "Self-illuminating Floor Tiles" markers: "0": "Recap and set the stage for the day" "18": "Demo the lighting" "130": "Determine to add self-illuminating tiles" "251": "Reacquaint ourselves with our rendering pipeline" "674": "Consider doing self-illumination through the ACES film curve vs directly (like the cutscene)" "890": "Reacquaint ourselves with the source of FragEmission" "957": "Introduce the notion of FragTone in the vertex and fragment shaders in CompileZBiasProgram()" "1022": "Run successfully" "1036": "Indent the fragment shader" "1088": "Yearn for lunch" "1138": "Indent the fragment shader (cont.)" "1299": "Not sure if this is part of Buddhist teaching" "1343": "Don't tell me this is about the 4coder layer" "1393": "Reacquaint ourselves with the fog, emission, etc. "tuning knobs" in the fragment shader" "1543": "Separate out the fogging and ACES filtered rendering knobs" "1702": "The game is not tone-mapped, and the cutscene looks right" "1733": "Premiere the cutscene narration" "1929": "The cutscene is still working" "1952": "No way, this game has TF2 hats?" "1978": "Thank you for the sub gifting" "2036": "Your posh British accent isn't terrible" "2082": "Start to enable PushQuad() to set the Tone renaming Reserved to Tone in textured_quad" "2274": "A really sweet 4coder layer feature would be to log per-line edits and correlate them with timestamps in a session" "2288": "Plug AndrewJDR's annotated Handmade Hero source code linking to the indexed episode guide" "2348": "Enable PushQuad() to set Tone to a VertTone, which is either 255 or, if lighting is off, 0" "2489": "The game remains not tone-mapped" "2500": "Specify a Tone vertex array in UseProgramEnd() and UseProgramBegin()" "2667": "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)" "2727": "You can in D3D11 with StructuredBuffer" "2746": "Associate VertTone in OpenGLCreateProgram()" "2778": "Yeah, you can use the vertexid to index the buffer" "2820": "Our tone-mapping is back, the debug overlay is now correctly unlit and the cutscene still looks right" "2855": "Determine to add self-illuminating blocks" "2903": "We've have it all" "2972": "This DLSR autofocus is in... UNACCEPTABLE CONDITION" "3028": "Change CreateWorld() to connect the dungeon entrance room to the north of (rather than below) the forest entrance" "3084": "Traverse to the outdoors, where the ground cover is not lit" "3133": "Reacquaint ourselves with the ground cover drawing code" "3178": "Make VertexOut() set the Tone to 255 (i.e. tone-map and light it)" "3185": "Our ground cover is lit again" "3194": "It fixed the blocky lighting bug?" "3204": "Traverse to the dungeon" "3262": "Volunteer voice acting services to "Downward Dungeon"" "3412": "Sample reel for "Downward Dungeon"" "3434": "Workshop some dungeon-based game titles" "3530": "There should be a game about travelling to the dungeon but not actually doing the dungeon" "3583": "Workshop some dungeon-based game titles (cont.)" "3617": ""Dude, Where's the Dungeon?"" "3634": "I wrote a game once called "Walking Simulator" - it was a text adventure where all you did was walk different directions and 'look'" "3643": "Pitch "Dungeon?" / "Imagine Dragons"" "3789": "You could make a Tycoon-style game where you design such a town" "3877": ""Dave Made a Dungeon"" "3901": "Toggle on TileSwitchPattern in CreateDungeon()" "3968": ""My First Dungeon", and make the game all bright red, yellow and blue" "3974": "Traverse to the dungeon's tile switches" "4030": "Reacquaint ourselves with the tile switch lighting code" "4079": "Make ExecuteBrainSwitches() decrease the light's brightness from 10 to 1" "4097": "Consider making hot reloading work with the procedural generation" "4128": "Make CreateWorld() place the player in the dungeon" "4150": "Start in the dungeon and toggle the tile switches" "4182": "Consider not adding a light source, but just setting the emission of the cube" "4228": "Is the light never going away?" "4234": "Consider removing the AddPieceLight() call from TileSwitchPattern()" "4257": "Imagine the "Downward Dungeon" theme song" "4318": "Prevent TileSwitchPattern from calling AddPieceLight()" "4339": "The tiles turn on but do not light up" "4351": "Prevent AddPlayer() from adding a head light, and make the glove's light less green" "4397": "The glove light is a bit too bright" "4401": "Make AddPlayer() dim the (commented out) head light from 0.1 to 0.05" "4409": "The glove light remains too bright" "4415": "Make AddPlayer() dim the glove light from 0.1 to 0.025" "4423": "Our glove's glow is more like it" "4437": "Make TileSwitchPattern() apply the Tag_Stone tag" "4551": "Our stone switches look better" "4578": "Heh, the certificate for 4coder website expired" "4612": "The AI goes wherever it wants" "4630": "Did one of those heads just phase through the wall?" "4749": "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" "4774": "Consider how to represent self-illumination" "4893": "Try making UpdateAndRenderEntities() pass 1 as the Emission value to PushCube()" "4900": "All our cubes are lit" "4904": "Revert UpdateAndRenderEntities() to pass 0 as the Emission value to PushCube()" "4935": "Consider how best to articulate our desired Emission value to the system" "5041": "Introduce cube_piece containing an Emission value to replace cube_uv_layout in entity_visible_piece" "5126": "The game still runs" "5130": "Make UpdateAndRenderEntities() unpack the Emission" "5206": "There are no emission cubes" "5218": "Make ExecuteBrainSwitches() set the switch's emission to 50" "5244": "The switches don't emit light" "5274": "Make UpdateAndRenderEntities() pass the unpacked Emission to PushCube()" "5299": "The switches emit light, but don't tell the lighting system they're doing it" "5334": "Reacquaint ourselves with PushOccluder() and its use" "5760": "Replace the IsLight boolean with an Emission float in lighting_box" "5901": "The switches still emit light" "5924": "Fold PushLight() and PushOccluder() into a unified PushLightingElement()" "6084": "The switches still emit light" "6099": "Make ExecuteBrainSwitches() set the Emission on the switch's occluder, rather than the base piece" "6116": "The switches are not lit" "6133": "Make ExecuteBrainSwitches() also set the Emission on the switch's base piece" "6181": "What would translucent lighting even be?" "6195": "The switches remain not telling the lighting system about their emission" "6246": "The light leaks a little" "6310": "Make UpdateAndRenderEntities() unpack and pass the Emission of occluders to PushLightingElement()" "6350": "The switches emit light and tell the lighting system about it" "6366": "Make ExecuteBrainSwitches() set the Color of the switch's occluder piece" "6389": "The switches emit cyan light" "6435": "Make ExecuteBrainSwitches() dim the light from 50 to 25" "6445": "Our tile switch light is better" "6472": "That's it, with a plug of Molly Movie Club" "6575": "Are you watching Better Call Saul season 6?" "6652": "Do I need to watch Interstellar to enjoy the podcast?" "7040": "Thanks, everyone" --- name: "day656" title: "Sketching Out Move Queues" markers: "0": "Recap and set the stage for the day" "44": "The audio tears and previously floating entities no longer move" "126": "This poor tortured piano" "147": "Toggle off the OutputPlayingSounds() call in GameGetSoundSamples()" "228": "The music has gone" "236": "Use #if 0 TEMPORARY" "317": "Hero hopping feels fine, just needing trailing-edge events" "398": "Determine to move the glove with the hero, and sweep out a prescribed pattern upon attack" "587": "Continue with the idea of a move queue" "651": "Augment move_queue_entry with Damage and Speed" "790": "Determine to implement non-recallable glove attacks" "1057": "Consider after-touch, and chaining attacks" "1106": "Embark on attack patterns in ExecuteBrainHero(), changing Dest to Delta in move_queue_entry" "1220": "Thoughts on the game looking grid-based, but actually being arbitrary" "1270": "Enable ExecuteBrainHero() to begin attacks in the correct direction" "1719": "Set up ExecuteBrainHero() to push attack patterns onto the move queue" "1794": "enum is not in C" "1894": "Enable ExecuteBrainHero() to push attack patterns onto the move queue (cont.)" "1960": "Consider chaining attacks together" "2037": "Augment entity with a MoveGroupCount to limit the attack chain length created by ExecuteBrainHero()" "2188": "Consider what constitutes the glove having "returned to hero"" "2299": "Consider item statistics" "2495": "Guys, if integers are more efficient than floats, should we make our int pointers point to decimal numbers?" "2525": "Consider item statistics (cont.)" "2606": "Introduce stats" "2693": "Consider how to articulate modifiable glove statistics" "2884": "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" "2925": "Introduce move_square_type and stat_coeff for stats to use / contain" "3125": "Introduce move_pattern" "3189": "Consider status effects" "3402": "Fill in move_pattern, introducing move_pattern_entry and move_queue_flag" "3626": "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" "3634": "Reflect on our stats and move_pattern sketch" "3708": "Add a MoveFlag_Ephemeral to move_queue_flag" "3750": "Reflect on our stats and move_pattern sketch (cont.)" "3859": "Enable ExecuteBrainHero() to initialise attack patterns, augmenting move_pattern with an EntryCount" "3988": "tk_dev I had a similar thought, but you need some initial bullshit idea of structs and enums to start playing with usage code" "4019": "I don't understand how the "pattern" is involved in the game play. Like, what is the function of a pattern?" "4113": "Like a chess move" "4159": "Enable ExecuteBrainHero() to translate attack patterns from their canonical orientation, to the requested one" "4394": "Set up ExecuteBrainHero() to handle move queue overflow" "4442": "Explore 4coder's function prototype HUD" "4559": "Set up ExecuteBrainHero() to handle move queue overflow (cont.)" "4649": "Set up ExecuteBrainHero() to limit move queue pushes to the MaxMoveGroupCount" "4715": "Consider how / when to evaluate entity stats" "4793": "Should the "if" just be the assert?" "4816": "Consider how / when to evaluate entity stats (cont.)" "4995": "Reacquaint ourselves with the game update loop in Simulate()" "5073": "Consider how / when to evaluate entity stats (cont.)" "5240": "Consider entity stats evaluation to be harder than the move queue" "5287": "Use swappable hats to guide our entity stats evaluation considerations" "5640": "Consider evaluating entity stats when adding to hash" "5729": "Try making AddEntityToHash() recompute stats" "5850": "Augment entity with BaseStats, ActiveStats and AccumStats" "5897": "Have you considered just dynamically calculating stats based off the current modifiers?" "6035": "Well that way they just never get stale" "6229": "Reacquaint ourselves with our ATan2() calls" "6296": "Rename the entity struct's ActiveStats and AccumStats to Stats and StatsAccum" "6416": "Introduce AdvanceEntityStats() for AddEntityToHash() to call" "6484": "Augment stats with Speed, for ExecuteBrainHero() to use" "6565": "Finish making ExecuteBrainHero() push moves onto the queue" "6681": "Make ExecuteBrainHero() consider the glove to be with the body if it is closer than 0.5 units away" "6775": "TODO(casey): Set a return move when there's no moves in the queue?" "6810": "That's it for today" --- name: "day657" title: "Implementing Move Queues" markers: "1": "Recap and set the stage for the day moving the glove" "34": "Describe our sketched out move patterns and queues, and stats" "325": "Walk through our move queue enqueuing code in ExecuteBrainHero()" "458": "Demo the brain-directed movement synchronisation" "539": "Consider move queue-directed movement integrity" "701": "Our facing direction is wrong when pressing Up" "717": "Investigate why our facing direction is wrong" "750": "Make ExecuteBrainHero() compute the FacingDirection with the ATan2 of the X vector" "771": "Our facing direction remains wrong" "785": "Investigate why our facing direction is wrong" "822": "Make ExecuteBrainHero() compute the FacingDirection with the ATan2 of y / x of the X vector" "834": "Our facing direction is now correct" "847": "Consider where the glove should sit" "1003": "Determine to put the glove on the hero's tile, and not occupy tiles it passes through" "1492": "Make ExecuteBrainHero() move the glove without transactionally occupying tiles" "1589": "Our glove doesn't move with us" "1615": "Investigate why the glove doesn't move" "1680": "Move without hitting extra keys, and the glove still not following us" "1691": "Break into the "glove at rest" branch in ExecuteBrainHero()" "1798": "Step through UpdateAnimation()" "1983": "Reacquaint ourselves with UpdateAnimation()" "2063": "Check that the glove's animation data doesn't get overwritten" "2206": "Break into AddPlayer() for the glove's entity ID (10845), then see what UpdateAnimation() does to that entity" "2678": "Find that UpdateAndRenderEntities() sets Entity->GroundP" "2843": "Remove GroundP from entity" "2968": "Entities are now in different locations" "2994": "Our glove follows us, but does not animate" "3063": "Investigate why the glove does not animate" "3170": "Fix ExecuteBrainHero() to set the Glove's tMovement to 0" "3190": "Our glove follows us, animating smoothly" "3226": "Determine to offset the glove's location relative to the player" "3280": "Try making AddPlayer() offset the glove in X" "3313": "Our glove is offset in X" "3326": "Try making AddPlayer() offset the glove in Z" "3356": "Our glove is offset in Z" "3370": "Increase the glove's X offset from 0.25 to 0.5 in AddPlayer()" "3378": "Our glove offsetting doesn't respect its parent entity's facing direction" "3587": "Traverse the dungeon admiring the lighting" "3688": "With a fixed offset from the actual position, animating would get hard, I guess" "3739": "Determine to dequeue moves off the move queue" "3822": "Enable UpdateAndRenderEntities() to dequeue moves off the move queue, augmenting entity with a MoveQueueIndex" "4111": "The game still runs" "4123": "Make UpdateAndRenderEntities() draw move queues" "4252": "See no move queue drawings" "4262": "Make UpdateAndRenderEntities() elevate the move queue drawing above the ground" "4288": "Still see no move queue drawings" "4290": "Make AddPlayer() set the Glove->Stats.MaxMoveGroupCount to 1, and ExecuteBrainHero() reset Glove->MoveQueueIndex to 0 when with the body" "4421": "Still see no move queue drawings" "4430": "Scour ExecuteBrainHero() for bugs" "4463": "Break in to ExecuteBrainHero() to find the glove's stats are not set" "4507": "Change AddPlayer() to set the Glove->BaseStats.MaxMoveGroupCount to 1" "4535": "Break in to ExecuteBrainHero() to find the glove's stats remain not set" "4551": "accumulate entity stats" "4580": "Love insobot, and feel like insofaras needs to use GPT-3 and have insobot do everything" "4625": "Make AdvanceEntityStats() acquire the Entity->BaseStats" "4651": "Break in to ExecuteBrainHero() to find the glove's stats are now set, and move queue boxes are drawn" "4691": "Make ExecuteBrainHero() locate the move queue drawings relative to its entity's occupying position" "4775": "Our move queue drawings work pretty well" "4784": "Determine to make the glove return to the body after punching" "4874": "People always wonder when insobot is going to become sentient" "4908": "Our move pattern rotates properly" "4915": "Investigate why the glove doesn't return to the body after punching" "4938": "Fix the glove reset condition in ExecuteBrainHero()" "4954": "Our glove now returns after punching" "4975": "Increase Glove->BaseStats.MaxMoveGroupCount from 1 to 2 in AddPlayer()" "4991": "We can chain punches, but the pattern direction is off" "5010": "Investigate why the second punch's direction is off" "5103": "Have fun reading it, if you can find a copy. It's gotta be, what, 40 years old at least by now?" "5112": "Gain insight into the chained punching direction" "5132": "Try using a WentDown input event in ExecuteBrainHero()" "5176": "The Adolescence of P-1" "5189": "We have HalfTransitionCount but not WentDown in game_button_state" "5240": "Make ExecuteBrainHero() also factor in the HalfTransitionCount to its attack checks" "5275": "We can chain punches in the correct directions" "5355": "Consider the definition of collision" "5431": "Change ExecuteBrainHero() to give the glove a 1-step attack pattern" "5453": "Try our simple punch" "5467": "Introduce SetAnimation() for the ExecuteBrain*() functions to call, augmenting entity with a dtMovement" "5810": "That all looks fine" "5824": "Switch UpdateAndRenderEntities() to use the new Entity->dtMovement" "5846": "Our glove doesn't move" "5860": "Consider where and how to set the glove's dtMovement" "6058": "Let UpdateAndRenderEntities() also move entities if their dtMovement is 0" "6083": "Our glove now moves" "6093": "Increase the glove's animation speed from 4 to 8 in ExecuteBrainHero()" "6113": "Our glove punches faster" "6164": "Would the attack pattern define the speed?" "6203": "Make UpdateAndRenderEntities() set the Entity->dtMovement, and AddPlayer() the glove's BaseStats.Speed" "6313": "Our glove still punches faster" "6316": "Toggle to the 3-step attack pattern in ExecuteBrainHero()" "6343": "Try out our fast-slow-fast punch" "6384": "There is a function to determine if the button was pressed this frame (named WasPressed)" "6389": "Call it for today with a glimpse into the future doing damage and collapsing down to grid" --- name: "day659" title: "Immediate-mode Level Generation" markers: "0": "Recap and set the stage for the day working on level generation" "93": "Overlay didn't appear, by the way, Casey" "108": "Turn on ctray" "151": "Reacquaint ourselves with our declarative Verilog-style level generator" "284": "Consider switching to a more direct, hand-coded level generation scheme, with lessened procedural generation" "561": "Prepare to work on CreateWorld()" "620": "Thoughts on getting better by productively reorganising systems" "716": "Prepare to work on CreateWorld() (cont.)" "788": "Comment out the GenerateWorld() part of CreateWorld()" "837": "Contextualise our world design thought process with the Legend of Zelda map" "1318": "Consider gated world exploration" "1615": "Stairs" "1620": "Consider gated world exploration (cont.)" "1737": "Yeah, it drains the water" "1749": "Aim for a world structure similar to The Legend of Zelda" "1775": "What does the whistle do in The Legend of Zelda?" "1939": "The whistle in The Legend of Zelda drains the lake" "1983": "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" "1989": "Oh, Link to the Past has the wind thing in front of the bird statue" "1994": "Initial thoughts for us on gated access based on item possession" "2079": "Consider placing tougher dungeons more distant from the start" "2161": "Determine to place dungeons using a tunable blue noise distribution" "2299": "Set up CreateWorld() to generate six dungeons" "2530": "Thoughts on floating difficulty of rogue-like games" "2669": "Hi" "2737": "You could have hints at the dungeon entrance that lets the player know how difficult it is, so they could show up anywhere" "2817": "Consider making dungeon exploration less about difficulty between dungeons, but more about how deep you want to go" "2893": "Angband" "2901": "Depth-choice dungeon exploration in Angband" "2994": "Consider increasing the difficulty per floor, not per dungeon" "3020": "Could you make it so that completing dungeons makes future dungeons harder?" "3049": "Won't intro floors become grating by the end of the game, then?" "3085": "Let CreateWorld() possibly generate up to nine dungeons" "3099": "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" "3142": "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" "3149": "Set up CreateWorld() to generate its dungeons, the forest and orphanage" "3314": "I just want the Awesome Button. You press the Button, something Awesome happens. Button -> Awesome" "3324": "Story time: The Million Dollar Button in Gabriel Knight 3" "3514": "Augment world_generator with DungeonLocations for CreateWorld() to set" "3596": "Consider how to space out dungeons" "3677": "Make CreateWorld() space out dungeons" "4167": "I got tired of saying "distance squared" all the time and discovered that it's called a quadrance" "4361": "Google ngram search hasn't heard of it" "4372": "Make CreateWorld() space out dungeons (cont.)" "4500": "Reflect on our annulus-shaped dungeon placement" "4555": "Note our need to visualise the dungeon generation" "4765": "Toggle on the procedural generation drawing in UpdateAndRenderWorld()" "4808": "Stub out CreateDungeon(), CreateDungeons(), CreateForest() and CreateOrphanage(), augmenting world_generator with OrphanageLocation and DungeonCount" "5054": "Determine to get a debug map going" "5087": "Stretch to infinity, just like Sausage Dog Tends To Infinity" "5254": "Implement CreateDungeon(), introducing PlaceDebugMarker()" "5698": "Casey has Bobby McFerrin car vibes today" "5823": "What is that internal keyword for?" "5867": "#define internal static" "5882": "Anticipate the next Bobby McFerrin craze" "5922": "Toggle off the camera placement in CreateWorld()" "5956": "Run straight into the cutscene, because there's no world" "6001": "Determine to vaporise GenRoom()" "6025": "I did just show up again" "6028": "What is happening with Sausage Dog Tends To Infinity?" "6076": "I played an early version of it like 3–4 years ago" "6144": "Release Date Tends to Infinity" "6164": "Maybe we get Half-Life 3 first" "6180": "Simplify GenerateRoom() for our new generator to call procedurally, delete GenerateWorld() and let CreateWorld() set the camera position" "6413": "It's so interesting to see both j_blow and 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" "6520": "Visual Studio changes text what I typed instead of suggesting. That's even worse" "6550": "Augment world_generator with StartingRoom for CreateWorld() to set" "6605": "Set up CreateOrphanage() to call GenerateRoom()" "6677": "Almost nobody designs autocomplete any more so that you can just type and not look" "6783": "Make CreateOrphanage() initialise a RoomSpec, removing the gen_apron_spec * from gen_room_spec, and GenRoom()" "6930": "Thoughts on forward-declarations in C / C++" "6990": "They "fixed it" with C++ 20 and modules" "7009": "But what would you ship with the library then?" "7156": "Fix compile errors in GenerateRoom()" "7205": "That rant on forward-declarations was enough for a sub" "7298": "Make CreateOrphanage() set the RoomVol" "7380": "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" "7460": "Make CreateOrphanage() set the RoomVol (cont.)" "7477": "Launch into our newly-generated room" "7498": "Toggle off CollisionVolume drawing in UpdateAndRenderEntities()" "7534": "Check out our generated world" "7564": "Disable GRID_RAY_CAST_DEBUGGING" "7573": "Our dungeons are too close together" "7605": "Make CreateDungeons() further separate out the dungeons" "7629": "Fall into an infinite loop with our random dungeon placement" "7647": "Decrease MinDungeonSeparationDistance from 100 to 10 in CreateDungeons()" "7667": "Dungeons are not distributed evenly" "7688": "Tweak the distance values in CreateDungeons()" "7776": "Our dungeons may now be too far away" "7802": "Decrease the distance values in CreateDungeons()" "7832": "Our dungeon placement seems not terrible" "7925": "Determine to let CreateWorld() use a random seed" "8024": "That was Banjo-Kazooie, I'm sure of it" "8062": "Make CreateWorld() take an InitialSeed, augmenting game_input with Entropy and EntropyRequested" "8317": "Judicially requesting entropy" "8474": "Make WinMainCRTStartup() request Entropy, introducing Win32GetEntropy() using BCryptGenRandom()" "8838": "Step in to Win32GetEntropy()" "8862": "Our procedural generation passes now differ" "8940": "That's good enough for now, with a glimpse into the future" --- name: "day660" title: "Randomized Overworld Layout" markers: "0": "Recap and set the stage for the day" "68": "Demo our randomly generated dungeon placement" "137": "Pull up the original Legend of Zelda map" "200": "Note the proximity-ordered placement of dungeons in The Legend of Zelda" "249": "Recap our plan to make each dungeon increase in difficulty as you go deeper into them" "321": "Consider how to motivate exploration of our overworld" "395": "Note the Legend of Zelda's difficulty cues that motivate overworld exploration" "504": "Why would you care about how you are traversing things?" "532": "If you think C++ is bad and C better, then why don't you just use C instead of C++?" "584": "Why would you care about how you are traversing things? (cont.)" "650": "Exploration motivation ideas: 1) Enemy generators, with overlapping ranges" "869": "Exploration motivation ideas: 2) Temporary destruction of generators, which strengthen upon regenerating" "939": "So what you get in return for taking out a generator should be worth increasing the long-term difficulty" "1010": "Is there a way to tie the overworld difficulty to the dungeon difficulty system, or is it better to keep separate?" "1024": "Consider making multiple and different routes overlap different generators" "1179": "Consider using the dungeon generator for enemy generators" "1212": "Augment world_room with a DebugColor for AddWorldRoom() to set" "1335": "Our orphanage outline is red" "1360": "Fix CreateOrphanage() to pass green to PlaceDebugMarker()" "1375": "With our green orphanage and yellow dungeons, plan to place red enemy generators" "1432": "By the way, is Handmade Hero going to get multiplayer?" "1514": "Set up CreateForest() to generate enemy generators, augmenting world_generator with GeneratorCount and GeneratorLocations" "1744": "Your game design woes are the essence of my existence as a programmer. I feel your pain in my soul" "1773": "Consider specifying the notion that "these points in the world should have this many overlapping generators"" "1885": "Introduce world_gen_location and world_gen_location_type, to replace DungeonLocations and GeneratorLocations in world_generator" "2114": "Update CreateDungeon() to use our new world_gen_location, introducing GetLocation()" "2267": "Anyone know if this error highlighting is public or is it Casey's own thing?" "2297": "Introduce GetClosestLocationTo() and GetClosestDistanceTo() for CreateDungeons() to use" "2633": "Set up CreateWorld() to call all the location creation functions, respecifying world_gen_location_type as plain ints rather than flags" "2916": "Rename CreateForest(), CreateOrphanage() and CreateDungeons() to Layout*(), and introduce CreateMonsterGenerator() and CreateItemRoom()" "3068": "Introduce PushLocation()" "3184": "Implement GetClosestLocationTo(), and make CreateWorld() push the orphanage location first" "3578": "Infinitely loop in our location placement code" "3590": "Scour our location placement code for problems" "3694": "Enable GetClosestLocationTo() to handle exclusion types, introducing Matches() and FlagOf()" "3914": "Hit a write access violation" "3951": "Hit the Gen->LocationCount assertion in PushLocation()" "3959": "Fix LayoutOverworld() to increment PlacedDungeonCount(), relieving it of using dungeons as an exclusion type" "3979": "Run successfully in -Od" "3995": "Run successfully in -O2" "4007": "Consider generalising our half-annulus point-picking code" "4147": "Drop frames" "4224": "Quick break" "4230": "afk" "4328": "Return and eyeball the dropped frames counter" "4415": "Introduce PickPointInAnnulus() and world_gen_annulus" "4966": "Our dungeons remain dispersed along a half-annulus" "4974": "Make LayoutOverworld() generate item rooms using PickPointInAnnulus()" "5094": "Hit our max iteration assertion in PickPointInAnnulus()" "5099": "Fix LayoutOverworld() to strew items along a different annulus" "5134": "We now have item rooms, but can still hit our max iteration assertion in PickPointInAnnulus()" "5162": "Consider improvements to PickPointInAnnulus()" "5249": "Switch PickPointInAnnulus() to use a random angle and distance, to discard fewer points" "5413": "Locations are placed behind the orphanage" "5442": "Augment world_generator with an OrphanageYLine for PickPointInAnnulus() to clip to, introducing IsInForest()" "5574": "Hit our max iteration assertion in PickPointInAnnulus()" "5591": "Decrease MinDistFromExistingLoc from 40 to 20 for item rooms" "5597": "We successfully place locations" "5626": "Establish the notion of min distance from everything / specific, introducing world_gen_filter for world_gen_annulus to contain" "5699": "Enable PickPointInAnnulus() to apply our new world_gen_filter" "5993": "Locations may only be placed far from their same type but near different types" "6033": "Determine to add the monster generators" "6109": "Make LayoutOverworld() generate enemy generators, augmenting world_gen_location with OverlappingGeneratorCount" "6765": "Hit our max iteration assertion in PickPointInAnnulus()" "6772": "Temporarily decrease MinDist from 10 to 0 for the monster generator filter in LayoutOverworld()" "6782": "Hit our max iteration assertion in PickPointInAnnulus()" "6788": "Revert MinDist in LayoutOverworld()" "6807": "Try making LayoutOverworld() place monster generators at our annulus-dispersal centroids" "6836": "Crash on PushLocation()" "6843": "Scour our monster generator placement code for bugs" "6866": "Hit our Gen->LocationCount assertion in PushLocation()" "6884": "Count up our locations" "6911": "Make LayoutOverworld() add 1 to our MaxLocationCount for the orphanage" "6921": "Run successfully in -Od" "6927": "In -O2, our monster generators are all placed in the same location" "6952": "Try letting LayoutOverworld() place monster generators at the centroid of dungeons and item rooms without overlapping generators" "7041": "Our monster generators are placed better" "7055": "Desire random location picking for monster generators" "7174": "Let LayoutOverworld() place monster generators along their annuli" "7193": "We have plenty more locations" "7210": "Increase MonsterGeneratorCount from between 12 and DungeonCount + ItemRoomCount in LayoutOverworld()" "7286": "Hit our max iteration assertion in PickPointInAnnulus()" "7295": "Let LayoutOverworld() place monster generators around other monster generators" "7311": "Successfully place all locations" "7364": "Increase MinDist from 10 to 20 for the monster generator filter in LayoutOverworld()" "7373": "Hit our max iteration assertion in PickPointInAnnulus()" "7389": "Make PickPointInAnnulus() try 10× more points" "7400": "Successfully place all locations, with the determination to place paths next week" "7469": "Plug the Handmade Hero pre-order and Molly Movie Club" "7636": "That's about it" "7650": "Saves me from having to watch Dune" "7654": "Take it easy, everybody" --- name: "day661" title: "Connecting the Overworld Map" markers: "0": "Recap and set the stage for the day" "35": "Demo our sparse overworld layout" "59": "Thicken the location outline from 0.01 to 0.1" "82": "Demo our annulus-based location regeneration" "349": "Determine to connect locations with paths" "444": "Is he using compute shaders?" "474": "For the entire rendering I think is what he meant" "488": "Determine to compute a connectivity graph for our locations" "590": "Check the chat" "629": "Compute shaders" "696": "These questions are so off-topic" "743": "Overflow the debug system" "826": "Consider clustering up locations" "924": "Determine to create waypoint locations" "948": "Demo our need for waypoints" "1026": "Add a WorldLoc_NavRoom and introduce CreateNavRoom()" "1100": "Determine to fill gaps in the map with nav rooms" "1126": "Enable LayoutOverworld() to generate nav rooms" "1261": "Hit our max iteration assertion in PickPointInAnnulus()" "1293": "Let the world generator complete if locations cannot be placed, augmenting world_gen_annulus with RequirePlacement, and introducing world_gen_pick_v2" "1602": "We have one green waypoint, standing at the edge" "1613": "Decrease MinDist from 60 to 30 for the nav rooms in LayoutOverworld()" "1627": "We have many more waypoints" "1658": "Hit our max iteration assertion in PickPointInAnnulus()" "1675": "Desire a better annulus picker, and regenerate many layouts" "1708": "Determine to connect nearby and unobstructed pairs of rooms" "1880": "Confirm that we can draw lines" "1910": "Introduce world_room_connection, and augment world with ConnectionCount and Connections" "1966": "Set up LayoutOverworld() to connect locations" "2228": "WutFace" "2294": "Augment world_room_connectionw with DebugColor and introduce AddWorldConnection(), for LayoutOverworld() to call" "2449": "We see no location connections" "2456": "Make UpdateAndRenderWorld() draw the location connections" "2704": "All the locations are connected, but a blue room overlaps the orphanage" "2747": "Prevent GenerateRoom() from creating a WorldRoom" "2807": "That blue room has gone" "2829": "Specify a location connection criterion in LayoutOverworld(): 1) Locations must be nearby" "2940": "All the locations remain connected" "2948": "Fix our "nearby" criterion in LayoutOverworld()" "2959": "Most rooms are not connected" "2969": "Increase our "nearby" location criterion from 30 to 60" "2978": "Our rooms are mostly, but not entirely, connected" "3223": "Determine to repair disconnections, using a disjoint-set forest" "3260": "Determine to forcibly connect the closest two rooms of disjoint islands" "3305": "Regenerate many disjoint layouts" "3364": "Make LayoutOverworld() draw location connections of satellites in purple, augmenting world_gen_location with ConnectedToOrphanage" "3701": "Immediately hit our !B->ConnectedToOrphanage assertion in LayoutOverworld()" "3707": "Propagate our ConnectedToOrphanage checks in LayoutOverworld()" "3810": "Location connections of satellites are purple" "3841": "Make LayoutOverworld() instead draw all rooms of satellites in purple" "3981": "Our satellite rooms are not purple" "4001": "Make CreateWorld(), rather than LayoutOverworld(), colour satellite rooms in purple" "4044": "Now all rooms are purple" "4055": "Fix the !Loc->ConnectedToOrphanage test in CreateWorld()" "4068": "Satellite rooms are now coloured purple" "4109": "Enable LayoutOverworld() to connect satellite locations to the orphanage's locations" "4230": "Hey 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!" "4235": "Enable LayoutOverworld() to connect satellite locations to the orphanage's locations (cont.)" "4408": "We have an unconnected satellite" "4435": "Double-check our satellite connection code" "4481": "Fix typo in the satellite connection code's inner loop" "4493": "Potential satellites are now connected" "4688": "Temporarily remove nav rooms" "4703": "It's better without nav rooms" "4720": "Let LayoutOverworld() create fewer nav rooms" "4735": "Sometimes extra rooms fill in the world too much" "4744": "Hit our Pick.PassedFilters assertion in LayoutOverworld()" "4776": "Consider a world with fewer nav rooms to feel better" "4816": "Let LayoutOverworld() create between 4 and the DungeonCount nav rooms" "4841": "Consider forcing nav rooms to have multiple connections" "4906": "Is a nav room <-> nav room connection also redundant?" "4919": "Somehow I think I would have set the startup view to be way zoomed out ages ago, if I were testing this" "5034": "Q: Maybe just remove nav rooms with one connection?" "5071": "Determine to forcibly connect nav rooms following the trajectory from their inbound connection, removing ones where this is impossible" "5170": "Enable LayoutOverworld() to remove the connection of all orphaned nav rooms" "5293": "Orphaned nav rooms are now jettisoned" "5375": "Enable LayoutOverworld() to remove the connections of "jointly orphaned" nav rooms" "5541": "Orphaned nav rooms are no longer jettisoned" "5571": "Double-check our orphaned nav room jettisoning code" "5635": "Orphaned nav rooms are mostly left intact" "5677": "Fix LayoutOverworld() to remove the connections of orphaned nav rooms with 0 or 1 connections" "5690": "We can delete valuable nav rooms" "5725": "Enable LayoutOverworld() to remove the connection only of nav rooms with one connection" "5783": "Tolerate exterior "jointly orphaned" nav rooms" "5814": "Hit our Pick.PassedFilters assertion in LayoutOverworld()" "5836": "Our connections are nice" "5848": "Specify a location connection criterion in LayoutOverworld(): 2) Connections must not pass too close to other locations" "6042": "Introduce DistanceBetweenLineSegmentAndPointSq()" "6709": "We still produce obstructed connections" "6728": "Make LayoutOverworld() draw viable connections green on nonviable ones red" "6805": "Double-check DistanceBetweenLineSegmentAndPointSq()" "6859": "Determine to debug nonviable connections" "6892": "Muted?" "6926": "Determine to debug nonviable connections (cont.)" "6966": "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" "6993": "Fix DistanceBetweenLineSegmentAndPointSq() to compute the distance along the line's perpendicular" "7259": "We still produce obstructed connections" "7273": "Double-check DistanceBetweenLineSegmentAndPointSq()" "7300": "Fix DistanceBetweenLineSegmentAndPointSq() to multiply in the Dir to the ClosestP" "7310": "We now identify obstructed connections" "7364": "Increase the connection obstruction radius from 10 to 20 in LayoutOverworld()" "7374": "We identify more connections to be obstructed" "7413": "That's it" "7431": "Enjoy the maps" "7508": "Make LayoutOverworld() set orphaned rooms as WorldLoc_None to prevent CreateWorld() from creating them" "7537": "We have no unconnected rooms" "7545": "What's up with the boxes with no connections?" "7565": "Temporarily prevent LayoutOverworld() from setting orphaned rooms as WorldLoc_None" "7575": "Describe orphaned nav rooms removal" "7657": "Temporarily prevent LayoutOverworld() from removing the connections of orphaned nav rooms" "7679": "Describe orphaned nav rooms removal (cont.)" "7708": "Let LayoutOverworld remove the connections of orphaned nav rooms" "7728": "Describe orphaned nav rooms removal (cont.)" "7742": "Let LayoutOverworld() set orphaned rooms as WorldLoc_None" "7754": "Describe orphaned nav rooms removal (cont.)" "7798": "Will the world still be infinite?" "7828": "Would it correctly remove a leaf sequence of multiple nav rooms?" "7871": "Admire our maps" "7898": "Is the plan to still have smooth transitions between rooms, or will the player "teleport" between rooms?" "7948": "There is just a lot of space between rooms now" "8072": "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?" "8170": "Compare SQRTPS, DIVPS, RCPPS and RSQRTPS performance" "8338": "Consider simplifications to DistanceBetweenLineSegmentAndPointSq()" "8469": "Sorry to disturb the train of thought. Meow finally arrived this month and we loved it. Any hints on when the next volume will be out?" "8911": "What other projects are you working on?" "8980": "The print quality is second to none, it's so good!" "9157": "Plug Meow the Infinite" "9347": "Does violence and sex improve things?" "9370": "That's it for today, with a glimpse into the future filling in entities" "9441": "Why didn't you do this generator backwards, like with the Witness grass?" "9465": "Creating the connections first" "9504": "Yeah, and then you do not need to cull the connections" "9714": "Thank you, everyone" --- name: "day662" title: "Generating Entities from Layouts" markers: "1": "Recap and set the stage for the day" "58": "Demo our procedurally laid-out overworld" "278": "Generate a new map, with the determination to place environmental entities respecting the connectivity graph" "329": "Environment generation: 1) Using the connection line literally" "418": "Environment generation: 2) "Jankifying" or making the lines meander" "482": "Determine to start by following the lines literally" "581": "Consider the performance of our entity structure" "630": "Prepare to generate our connected forest, encompassed by an impenetrable wall" "735": "Pull up the code for CreateWorld()" "747": "We could generate stuff in the other room types" "757": "Make CreateItemRoom() call GenerateRoom()" "779": "Our item rooms are not close enough to be paged in" "803": "Let CreateOrphanage() generate a far larger room" "828": "There's a nav room in our orphanage" "836": "Make CreateNavRoom() call GenerateRoom()" "857": "Our nav room is generated, but offset" "897": "Reacquaint ourselves with CreateNavRoom() and PlaceDebugMarker()" "963": "Our nav rooms are shifted inconsistently" "1007": "Wonder if we have a scaling disparity between the debug marker drawing and entity placement" "1099": "Reacquaint ourselves with the debug marker drawing in UpdateAndRenderWorld(), to see it is done in a RenderGroup" "1134": "Expect our room markers to shift with the simulation region" "1180": "Try to disable boundaries by making CreateOrphanage() set RoomSpec.Outdoors to true" "1216": "We still have boundary trees" "1231": "Try to disable tree creation by making GenerateRoom() set OnEdge to false" "1248": "Our room markers do not shift with the simulation region" "1354": "Reconsider it to be a scaling disparity" "1489": "Our debug markers and grid edits occur in totally different spaces" "1577": "Determine to line up our debug markers and grid edits" "1659": "Change PlaceDebugMarker() to position it using ChunkPositionFromTilePosition()" "1851": "Our map is maybe too big" "1863": "Make PlaceDebugMarker() scale the positions by 0.5" "1890": "Our map is probably more what we want" "1904": "Move the scaling factor from PlaceDebugMarker() out to LayoutOverworld()" "2011": "We now produce over-long and, again, obstructed connections" "2055": "Fix LayoutOverworld() to apply the Scale to GeneratorRadius" "2157": "Generate maps" "2172": "Generate a buggy map" "2193": "Wonder if LayoutOverworld() gave up in a loop" "2214": "Decrease the Scale from 1 to 0.5 in LayoutOverworld()" "2230": "Our map is much tighter, but we still generate obstructed connections" "2254": "Wonder if making PlaceDebugMarker() use ChunkPositionFromTilePosition() caused our obstructed connection generation" "2302": "Revert PlaceDebugMarker() to not use ChunkPositionFromTilePosition()" "2324": "Generate maps" "2331": "Generate a buggy map" "2386": "Scour CreateWorld() for any uninitialised values" "2493": "Scour LayoutOverworld() for a cause of our obstructed connections" "2589": "Generate maps, and manage to get a buggy one on startup" "2646": "Scour the AddWorldConnection() loop in LayoutOverworld() for bugs" "2700": "Scour DistanceBetweenLineSegmentAndPointSq() for bugs" "2830": "Scan through LayoutOverworld(), describing the white and purple line colouring, and AddWorldConnection()" "2892": "Seek a pattern in our buggy map generation" "2989": "Wonder if our rooms got moved after connection" "3080": "Try disabling the if(Viable) check in LayoutOverworld() to aid debugging our obstructed connection generation" "3123": "Check out our rejected, red connection lines" "3202": "Check out our rejected, red connection lines on a buggy map" "3232": "Try toggling off the connection removal of unnecessary nav rooms in LayoutOverworld()" "3311": "Generate a plethora of non-buggy maps" "3343": "Wonder if there actually is a room 0" "3351": "Generate another plethora of non-buggy maps" "3383": "Investigate how setting the two rooms to 0 can generate obstructed connections" "3528": "It is an indexing bug: Setting LocA->Type to WorldLoc_None, thus not creating a room, throws the connection indices off-by-1" "3635": "Leave the connection removal of unnecessary nav rooms toggled off, and add a TODO to track indices correctly" "3816": "Enable LayoutOverworld() to scale the map after the fact" "3879": "Generate a map" "3884": "Decrease the WorldScale from 1 to 0.5 in LayoutOverworld()" "3895": "Our world is now more smooshed" "3909": "Introduce TileFromPoint() to line up the debug markers and grid edits coordinate systems" "4065": "Make CreateOrphanage() use TileFromPoint()" "4127": "Our orphanage remains lined up" "4133": "Make CreateItemRoom(), CreateMonsterGenerator() and CreateDungeon() use TileFromPoint()" "4185": "Our rooms' generated entities all line up with their debug markers" "4213": "Determine to fill in the connective tissue between rooms" "4517": "Consider subdividing the map into a coarse grid and rasterising each populated region" "4574": "Make LayoutOverworld() compute the union between all locations, for CreateWorld() to generate as a world room, augmenting world_generator with WorldBounds" "4965": "Hit a read access violation in CreateWorld()" "4992": "Fix CreateWorld() to call EndWorldGen() at the very end" "5004": "Our map is now outlined" "5016": "Increase the WorldScale from 0.5 to 0.7 in LayoutOverworld()" "5038": "We now have a perimeter within which we may march and generate entities" "5083": "Determine to march through and rasterise everything" "5146": "Reduce CreateNavRoom(), CreateItemRoom(), CreateMonsterGenerator() and CreateDungeon() to only call PlaceDebugMarker()" "5185": "Our rooms are no longer filled in" "5191": "Introduce GenerateBlock() to generate environmental entities throughout the block, for CreateOrphanage() to call" "5994": "Hit our !World->UnpackedIsOpen assertion in EnsureRegionIsUnpacked()" "6001": "Make GenerateBlock() call EndGridEdit() at the very end" "6027": "The camera begins not set to anything" "6034": "Make GenerateBlock() put the camera somewhere" "6081": "We have a patch of grass as the orphanage" "6102": "Make GenerateBlock() place trees on non-walkable tiles, using IsOnEdge() as the IsWalkable() test" "6159": "Trees are placed around the edge" "6174": "Make GenerateBlock() use the room locations and connection lines as its IsWalkable() tests, to generate environmental entities there" "6410": "Our orphanage remains as a patch of grass" "6425": "Make CreateWorld() rather than CreateOrphanage() call GenerateBlock()" "6467": "I'm scared of doing anything with enough tomato in a seasoned wok" "6477": "Make CreateWorld() subdivide the world into blocks, on which to call GenerateBlock()" "6748": "Crash in AddEntity()" "6765": "Compile in -Od" "6782": "Hit the InvalidCodePath in AcquireUnpackedEntitySlot()" "6801": "Check EndGridEdit() for bugs related to AcquireUnpackedEntitySlot()" "6860": "Investigate our InvalidCodePath hit in AcquireUnpackedEntitySlot()" "7068": "Break on the CountExceeded check in EnsureRegionIsUnpacked()" "7145": "Try unsuccessfully to break on the IsOutsideVolume assertion in EnsureRegionIsUnpacked() before hitting the InvalidCodePath in AcquireUnpackedEntitySlot()" "7319": "Fix CreateWorld() to subdivide the world into different blocks to pass to GenerateBlock()" "7350": "Run successfully without hitting an InvalidCodePath" "7373": "Fix CreateWorld() to offset the block subdivisions by MinTileI" "7394": "Everyone is fired" "7396": "Just throw any leftover vegetables in" "7399": "Our room connections are filled with environmental entities, but entities do not get streamed in" "7442": "Uncomment the hero's head light in AddPlayer()" "7485": "Our room connections remain filled correctly, only lacking entity streaming" "7619": "Decrease BlockDim from 32 to 16 in CreateWorld()" "7644": "Hit a write access violation on AcquireUnpackedEntitySlot() upon moving between sim regions" "7676": "Run in -Od and hit the InvalidCodePath in AcquireUnpackedEntitySlot()" "7727": "End it there" "7742": "Compile in -O2, and consider removing the 3rd dimension" "7758": "Traverse our forest" "7795": "Inflate our WorldBounds in LayoutOverworld()" "7826": "Traverse our forest" "7838": "Determine to remove Z next week" "7850": "Consider our start-up performance to be good" "7906": "Is there going to be a stream next week? I actually try to plan my Sunday around the stream" "7914": "Plug the Molly Movie Club stream here on Friday 30th September 2022" "8001": "Determine to remove Z and update entity streaming next week" --- name: "day663" title: "Simplifying Entity Storage, Part I" markers: "0": "Recap and set the stage for the day" "34": "Demo our updated world generation without entity unpacking" "79": "Determine to simplify entity storage" "252": "Describe our entity packing system" "351": "Plan our entity storage simplification" "441": "Remove ChunkZ from world_chunk and world_position" "673": "The game runs just the same" "742": "Reacquaint ourselves with the TODO in world_position" "779": "Consider removing the ChangeTicket ticket_mutex from world" "1047": "Plan to simplify the world" "1126": "Reorganise Rooms and Connections to the end of the world" "1143": "Describe our rooms and connections debug visualisation" "1188": "Reacquaint ourselves with the entity packing system" "1327": "Consider switching to an updatable entity hash table: 1) Removing the sim_region" "1456": "Consider switching to an updatable entity hash table: 2) Moving the unpacked stuff from the world into the sim_region" "1515": "Consider the need to handle distant unpacked sim regions, e.g. free-exploring couch co-op" "1650": "Consider the need for spatial partitioning" "1812": "Usually I take a nap to think about things" "1841": "Consider the need for spatial partitioning (cont.)" "1960": "Reacquaint ourselves with the world's LastUsedEntityStorageIndex" "2014": "Respecify world_entity_block as packed_entity_block, and remove FirstFree from the world" "2188": "Introduce unpacked_entity_block for world_chunk to contain" "2427": "Consider moving EntityHash from sim_region to the world, for entity ID lookup" "2472": "Consider switching entity hash collision resolution from probing to chaining" "2619": "Consider removing entity ID lookup entirely in favour of spatial querying" "2714": "Briefly run the game" "2726": "Speculatively remove GetEntityByID()" "2795": "Plan entity storage simplification: 1) Remove traversables in favour of grid square occupation" "2842": "Amazing content! I like the theme color palette. I would like to know: which theme are you using?" "2885": "Can you share the theme? The one in the source files is outdated" "3009": "I always thought it was Ryan's theme. It looked very similar" "3018": "The repo is archived now. I don't think you can submit it" "3023": "Copy theme-casey.4coder into the Handmade Hero directory" "3062": "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" "3107": "I have access to the Handmade Hero code so as long as your happy with it being public I can chuck it in when it goes up" "3119": "Remove StompOnEntity()" "3138": "Determine to change the idea of traversables to be based on an actual position" "3221": "Plug OALabsLive" "3331": "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?" "3552": "Plan our removal of traversables" "3630": "Change IsOccupied() and Vacate() to take a v2s rather than traversable_reference" "3701": "Introduce v2s, to possibly replace v2u" "3775": "#define function as static" "3865": "Rust: Hold my fn" "3876": "Remove Vacate() and change TransactionalOccupy() to take a v2s rather than traversable_reference" "3959": "Consider respecifying IsOccupied()" "4078": "Remove GetClosestTraversable()" "4199": "Remove GetClosestTraversableAlongRay()" "4256": "Remove GetMovementVoxelIndex() and AlignToMovementVoxel()" "4313": "IsCrossable()? I used this terminology in my Lemmings game" "4351": "Is it intentional for TransactionalOccupy() to always return false?" "4354": "Enable TransactionalOccupy() to return true" "4358": "Yearn for sbrabez's Lemmings game" "4400": "Stream will not continue until this Lemmings game is found" "4432": "Not released yet, it was a personal project in Java" "4446": "We need LemmingsVR" "4488": "Augment entity with TileIndex and add EntityFlag_OccupiesTile" "4615": "I swear someone will make an "open world" Lemmings" "4637": "Replace GetClosestTraversable() with tile indexing in ExecuteBrainHero(), changing Occupying and CameFrom to be a v2s in entity" "4819": "Update DeleteEntity(), CreateEntity(), IsRoom() and EndWorldChange() to use our new "function" keyword" "4882": "Note mis-parsed error by 4coder" "4904": "Introduce a v2s overload of operator+()" "4983": "When I implement this code in C I tend to just make a macro festival to declare all the operator boilerplate" "5032": "This is one of the things I despise about GLM" "5039": "Introduce a v2s overload of AreEqual()" "5067": "It's the C++ math library everybody on the open source internet likes to use" "5080": "Implement the v2s overload of AreEqual()" "5098": "Best music I've heard all year" "5140": "Indiana Jones theme is mouth-trumpetty" "5179": "Change ExecuteBrainHero() to test on EntityFlag_OccupiesTile rather than IsValid()" "5302": "Move on to ExecuteBrainSnake()" "5317": "Wonder why ExecuteBrain*() first set CameFrom to Occupying" "5351": "Replace GetClosestTraversable() with tile indexing in ExecuteBrainSnake()" "5406": "Consider changing how TransactionalOccupy() works" "5536": "Fix ExecuteBrainHero() to set CameFrom to Occupying before TransactionalOccupy()" "5574": "Introduce SingleTileDeltaFrom() for ExecuteBrain*() to use" "5720": "Remove Traversables and Occupying from entity" "5746": "Change ExecuteBrainSwitches() to use IsOccupied(), removing entity_traversable_point and traversable_reference, and augmenting entity with WasOccupiedLastCheck" "6123": "Temporarily make IsOccupied() simply return false" "6151": "Determine to replace the ATan2() calls in ExecuteBrainSnake()" "6275": "Introduce GetFacingDirectionFromSingleTileDelta() for ExecuteBrainSnake() to use" "6476": "Pi and Tau have been cancelled" "6524": "It's a math thing, and "Turns" hasn't become popular enough yet" "6576": "Implement GetFacingDirectionFromSingleTileDelta()" "6639": "Do you configure your sin, cos and tan functions to use 0-1, then, instead of radians?" "6648": "Some dude said tau > pi in some early stream's Q&A and we all fell for it" "6714": "Just don't let the math people see the video" "6764": "For the assert would it be better to use an XOR since you don't want dTile x and y to both be 0?" "6797": "Yes please!" "6827": "Implement GetFacingDirectionFromSingleTileDelta() (cont.)" "6979": "2 - y and 1 - x then some type of mask?" "7004": "Implement GetFacingDirectionFromSingleTileDelta() (cont.)" "7512": "Replace all ATan2() calls in ExecuteBrain*() with GetFacingDirectionFromSingleTileDelta()" "7877": "Introduce a v2s overload of operator-()" "7911": "Scan through our remaining traversable replacement work" "7981": "#undef function for Windows" "8007": "Scan through our remaining traversable replacement work (cont.)" "8038": "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)" "8070": "Fix the parentheses in IsActive()" "8080": "Yep" "8103": "And goes before or, if I am correct" "8130": "I meant the execution" "8188": "What editor is it? Smooth scroll looks nice" "8294": "You can try to search for "scroll" right on GitHub and pray that their search will work" "8554": "Pretty sure smoothscroll is default behaviour. Did you submit it to Allen and he added it to the default layer maybe? So it's probably part of 4coder_default_hooks.cpp" "8774": "Reflect on our cubic-spline interpolation scrolling for 4coder" "8799": "Call it a day" --- name: "day664" title: "Simplifying Entity Storage Part II" markers: "0": "Recap and set the stage for the day" "157": "Reacquaint ourselves with the brain_type enum" "283": "Delete Type_brain_monstar and AddMonstar()" "332": "Seek simplification of UpdateAndRenderEntities()" "372": "Delete the BoostTo branch from UpdateAndRenderEntities()" "381": "Scan through code to rewrite and keep" "420": "Consider moving the camera with the entity in question, rather than by doing an entity lookup by ID" "552": "Reacquaint ourselves with the Type_brain_familiar case in ExecuteBrain()" "749": "Improve the wording of the Type_brain_familiar case in ExecuteBrain()" "878": "Consider changes to the entity struct that may mostly obviate the need for the sim region" "996": "Remove dAbsTileZ from entity" "1004": "Port the Type_brain_familiar case in ExecuteBrain() to our simplified entity storage scheme" "1147": "Consider performing TransactionalOccupy() in the movement, rather than the brain, code" "1216": "Port the Type_brain_familiar case in ExecuteBrain() to our simplified entity storage scheme (cont.)" "1326": "Reacquaint ourselves with the familiar velocity setting code" "1444": "Describe the purpose of TransactionalOccupy() in ExecuteBrain()" "1498": "Port the Type_brain_familiar case in ExecuteBrain() to our simplified entity storage scheme (cont.)" "1544": "Note popping artifacts in this movement code" "1574": "Introduce a v2s overload of V2()" "1618": "Port the Type_brain_familiar case in ExecuteBrain() to our simplified entity storage scheme (cont.)" "1637": "Port UpdateAnimation() to our simplified entity storage scheme" "1754": "Port the move queue code in UpdateAndRenderEntities() to our simplified entity storage scheme, changing Delta in move_queue_entry to be a v2s" "1800": "Consider making UpdateAndRenderEntities() set the TileIndex directly" "1852": "Port UpdateAndRenderEntities() to our simplified entity storage scheme, using a v2s TargetTile" "1908": "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*()" "2132": "Port AddPlayer() to our simplified entity storage scheme" "2268": "Port CheckForJoiningPlayers() to our simplified entity storage scheme, introducing GetClosestEmptyTileTo() and augmenting sim_region with OriginTileIndex" "2505": "Consider introducing TileSpaceToSimRegion()" "2606": "Respecify UpdateAnimation() to orient movement around the delta of the current and previous tile" "2702": "Fix typo in GetClosestEmptyTileTo()" "2722": "Remove the sim_region overloads of PlaceEntityAtTraversable() and PlaceEntityOnTraversable()" "2770": "Consider also removing the edit_grid version of PlaceEntityAtTraversable() and related functions" "2957": "Move the edit_tile traversal functions from handmade_edit_grid.cpp to handmade_sim_region.cpp" "3000": "Consider removing the edit grid entirely" "3130": "#if 0 GenerateApron() and GenerateRoom()" "3154": "Rename TraversableIsOpen() to TileIsOpen(), and IsOccupied() to TileIsOccupied(), removing the former's check" "3218": "Consider changing FindRandomOpenTile() to spiral outwards" "3271": "Delete handmade_gen_math.{h,cpp}, stowing the cpp code in handmade_math.h" "3774": "Remove the bulk of handmade_edit_grid.cpp" "3994": "Relieve GenerateBlock() of calling BeginGridEdit(), removing the latter, EndGridEdit() and GetAbsoluteTileIndex()" "4256": "Move IsOnEdge() from handmade_edit_grid.cpp to handmade_math.h" "4365": "Consider keeping code from handmade_edit_grid.cpp" "4444": "Move GetTileVolume() from handmade_edit_grid.cpp to handmade_room_gen.cpp, and rewrite it" "4585": "Move GetMinZCenterP() and GetVolumeFromMinZ() from handmade_edit_grid.cpp to handmade_room_gen.cpp" "4633": "Relieve GenerateBlock() of calling IterateAsPlanarTiles(), removing the latter" "4701": "Delete handmade_edit_grid.{h,cpp}" "4756": "Decide against debugging Visual Studio with Visual Studio" "4789": "Change GEN_CREATE_ENTITY_PATTERN() to take a world_generator" "4805": "We can't compile" "4961": "Declare world_generator before GEN_CREATE_ENTITY_PATTERN()" "4997": "Thoughts on compilers" "5105": "This is awesome though, but work in progress – Circle C++ Compiler – especially the extensions that should've been in C++ for a long time already" "5123": "It's a new C++ compiler" "5126": "C++ itself is a mess" "5155": "Remove PlaceEntityAtP(), and the edit_grid versions of PlaceEntityAtTraversable() and PlaceEntityOnTraversable()" "5209": "Write the edit grid out of SingleEnemyPattern()" "5249": "molly_rocket Have you already discussed Carbon and Go? Would be interesting to hear your take on those languages" "5258": "Write the edit grid out of SingleEnemyPattern() and SnakePattern(), augmenting world_generator with a *SimRegion" "5441": "Change TileAlreadyExists() and AppendTile() to take a v2s" "5470": "Write the edit grid out of TileSwitchPattern()" "5642": "Introduce tile_result for GetClosestEmptyTileTo(), FindRandomOpenTile() and FindAdjacentOpenTile() to return" "5763": "Update SingleEnemyPattern() and SnakePattern() to use our new tile_result" "5885": "Investigate our FindAdjacentOpenTile() compile error" "5967": "Make FindRandomOpenTile() and FindAdjacentOpenTile() NotImplemented" "6004": "Update CheckForJoiningPlayers() to use our new tile_result" "6036": "#if 0 the compile errors in BeginWorldChange()" "6053": "Introduce a v2s overload of operator+=()" "6075": "Update TileSwitchPattern() to use our new tile_result" "6210": "Consider making TileSwitchPattern() generate an index list for GenerateBlock() to use" "6265": "#if 0 TileSwitchPattern()" "6285": "Update NPCPattern() to use our new tile_result" "6371": "Fix compile errors in StandardLightingPattern() and remove CalcBasePForOffset()" "6459": "Remove Z from SetSize()" "6490": "Remove PlaceRoomInVolume(), PlaceRoom(), GetDeltaAlongAxisForCleanPlacement(), PlaceRoomAlongEdge(), GetRandomDirectionFromMask() and Layout()" "6538": "Switch the block rasterisation code in CreateWorld() to use v2s" "6605": "Switch rectangle2i to contain v2s Min and Max, and propagate this change" "6924": "What do you think about Rust?" "6973": "Switch HeroRoom in CreateWorld() to be a rectangle2i" "7008": "Switch GetCameraOffsetZForDim() to take a v2s" "7015": "Switch GetMinZCenterP() and GetVolumeFromMinZ() to take a world_generator, not an edit_tile" "7096": "Port GenerateBlock() and WinMainCRTStartup() to our updated rectangle2i" "7212": "Rename Region to SimRegion in GenerateBlock(), and unset it at the end" "7232": "Call it there" --- name: "day665" title: "Changing How Entities are Packed and Unpacked" markers: "1": "Recap and set the stage for the day" "69": "Describe our storage of the world as geographic / geometric chunks" "326": "Consider removing sim_region" "394": "Note our need for entity lookup tables by ID" "439": "Geometric / spatial query entity operations: collision, movement or lighting gather" "474": "Non-geometric entity operations" "493": "Non-geometric entity operations: 1) Matching gamepad with entity" "523": "Non-geometric entity operations: 2) Focusing camera on player's entity" "594": "Non-geometric entity operations: 3) Grouping entities" "695": "Consider the need for entity identification irrespective of world location" "744": "Non-positional entity identification" "758": "Non-positional entity identification: 1) Giant direct addressing table" "803": "Non-positional entity identification: 2) Localised direct addressing table" "853": "Non-positional entity identification: 3) Disallowed, everything is a spatial query" "1020": "Consider storing moving and static entities separately" "1082": "Consider augmenting world_chunk with a table of movable entities, or unpacked_entity_block with a movable / skippable signifier" "1206": "Remove the #if 0 from unpacked_entity_block and fix the order of declarations" "1283": "Determine to store moving and static entities separately, with everything as a spatial query" "1310": "Determine to implement world_chunk (un)compressing" "1424": "world_chunk: TODO(casey): Probably need to track access patterns here so we know what to repack for lack of use" "1458": "Consider changing the entity management threading scheme" "1579": "Describe EnsureRegionIsUnpacked()" "1691": "Determine to enable interleaving of entity unpacking and updating for cache-friendliness" "1764": "I just got here, so no" "1774": "Yeah" "1779": "Yes, you gotta eat your food while it's hot" "1786": "Respecify EnsureRegionIsUnpacked() to support unpack and update interleaving, introducing world_chunk_iterator, IterateChunks(), IsValid() and Next()" "2236": "Implement our world chunk iterator: IterateChunks(), IsValid() and Next(), introducing EnsureValidChunk()" "3290": "Fix compile errors in the world chunk iterator" "3403": "Consider making the caller unpack the entity block" "3441": "Change world_chunk_iterator to contain a world_chunk for the caller to unpack as required" "3596": "Introduce EnsureChunkIsUnpacked() and EnsureChunkIsPacked()" "3649": "Consider not having a lookup table for unpacked entities in the world" "3841": "Implement EnsureChunkIsPacked() based on PackEntity()" "3960": "Consider who is responsible for moving entities between chunks" "4067": "Temporarily introduce MoveEntityToNewChunk()" "4096": "Determine to move entities between chunks immediately" "4158": "Introduce MoveEntityToNewPosition()" "4274": "Simplify EnsureRegionIsUnpacked()" "4480": "Implement EnsureChunkIsUnpacked() based on EnsureRegionIsUnpacked()" "4490": "Plan our memory strategy for entity chunk unpacking" "4539": "Make EnsureChunkIsPacked() call AddToFreeList()" "4580": "Remove EnsureRegionIsUnpacked(), RepackEntitiesAsRequired(), ClearUnpackedEntityCache() and AcquireUnpackedEntitySlot()" "4736": "Note the orientation chunk dimensions around their centre" "4809": "Check the time" "4839": "Remove MAX_SIM_REGION_ENTITY_COUNT" "4849": "Introduce entity_block_storage to contain packed_entity_block and unpacked_entity_block, making them roughly the same size" "5161": "Remove entity packing data from world" "5202": "Finish implementing EnsureChunkIsUnpacked(), renaming FirstBlock to FirstPacked in world_chunk" "5454": "Reacquaint ourselves with FillUnpackedEntity()" "5489": "Relieve FillUnpackedEntity() of taking the SimRegion" "5502": "Reacquaint ourselves with FillUnpackedEntity() (cont.)" "5529": "Change UpdateAndRenderEntities(), not EnsureChunkIsUnpacked(), to call FillUnpackedEntity(), adding EntityFlag_Unpacked" "5716": "End our streaming with a plug of Molly Rocket's 25% Off Everything sale" --- name: "day666" title: "Entity Packing and Unpacking" markers: "0": "Recap and set the stage for the day continuing our entity system simplification" "113": "Recap our sim_region and entity ID removal considerations" "319": "Consider simplifying the UpdatableBounds and BrainHash out of the sim_region struct" "416": "Remove sim_region, entity_hash and brain_hash, and GetHashFromID()" "459": "Reacquaint ourselves with our IterateAllEntities() call sites" "546": "Clear out handmade_sim_region.h" "564": "Remove AddBrain(), AllocateEntityID() and MarkOccupied()" "605": "Move MarkBit() and IsEmpty() from handmade_sim_region.cpp to handmade.cpp" "643": "Remove GetHashFromID() and GetEntityByID_()" "660": "Move EntityOverlapsRectangle() and EntityOverlapsEntity() from handmade_sim_region.cpp to handmade_entity.cpp" "704": "Remove GetOrAddBrain(), AddEntityToHash(), MapIntoSimSpace() and RegisterEntity()" "719": "Move BeginWorldChange(), CreateEntity() and DeleteEntity() from handmade_sim_region.cpp to handmade_world.cpp" "834": "Move IsRoom() from handmade_sim_region.cpp to handmade_entity.cpp" "854": "Remove RegisterEntity()" "875": "Move TileIsOpen(), TileIsOccupied(), TransactionalOccupy(), OverlappingEntitiesExist(), closest_entity, GetClosestEntityWithBrain(), GetClosestEmptyTileTo(), FindRandomOpenTile() and FindAdjacentOpenTile() from handmade_sim_region.cpp to handmade_world.cpp" "914": "Move the entity iterator – FindNextEntity(), IterateAllEntities() and Advance() – from handmade_sim_region.cpp to handmade_world.cpp" "933": "Move UpdateCameraForEntityMovement() from handmade_sim_region.cpp to handmade_world_mode.cpp" "945": "Reflect on our sim_region removal" "960": "Delete handmade_sim_region.{cpp,h}" "998": "Remove the late sim_region from the entity code, moving DeleteEntity() from handmade_world.cpp to handmade_entity.cpp" "1136": "Perform the easy removals of sim_region from UpdateAndRenderEntities()" "1183": "Note our need to replace the final use of sim_region in UpdateAndRenderEntities() with a pre-pass gathering all local entities" "1220": "Note our new need to move entities between spatial partition nodes" "1306": "Remove the forward-declaration of FillUnpackedEntity() from handmade_entity.h" "1323": "Reacquaint ourselves with AdvanceEntityStats()" "1336": "Lament our lack of sleep and need for caffeinated coffee and / or sugar" "1383": "Consider the discontinuity arising from distant, active entities wanting to interact with inactive entities" "1586": "Enable UpdateAndRenderEntities() to gather all local entities, making it take the world and a rectangle3, not a sim_region" "1629": "Turn off phone" "1643": "Introduce our regional entity iterator: IterateEntityInBounds()" "1768": "Consider fixed- vs floating-point precision for our entity iteration" "1839": "Change UpdateAndRenderEntities() to take a world_position and v2 Radius, not a rectangle3" "1879": "Introduce world_region for UpdateAndRenderEntities() to take" "1912": "Rename IterateEntitiesInBounds() to IterateEntitiesIn(), taking a world_region" "1968": "Reacquaint ourselves with world_sim" "2177": "Remove world_sim, and the sim_region * from world_generator" "2204": "Unify AddEntity() as an overload of CreateEntity(), both taking a world and world_position, not a sim_region" "2404": "Move the CreateEntity() functions from handmade_entity.cpp to handmade_world.cpp" "2417": "Make CreateEntity() pass the world and world_position, not the late sim region's World, to AcquireUnpackedEntitySlot(), removing AddEntity()" "2451": "Embark on setting up the world storage" "2497": "Switch entity_block_storage to be a union" "2506": "Describe packed_entity_block and unpacked_entity_block" "2631": "Structure ChunkX and ChunkY as a v2s Chunk in world_position" "2658": "Consider relieving entities of storing their containing chunk information" "2729": "Remove NullPosition() and the world_position overload of IsValid()" "2777": "Fix up accesses of our structured Chunk in world_position" "2837": "Reacquaint ourselves with the TILE_CHUNK_SAFE_MARGIN" "2965": "Remove TILES_PER_CHUNK and reposition TILE_CHUNK_SAFE_MARGIN" "3002": "I believe it was arbitrary" "3038": "Consider the TILE_CHUNK_SAFE_MARGIN" "3079": "Reduce TILE_CHUNK_SAFE_MARGIN from INT32_MAX / 64 to INT32_MAX - 1024" "3201": "Reacquaint ourselves with the bulk allocation of world chunks" "3364": "Enable GetWorldChunk() to allocate memory for the chunks, structuring the ChunkX and ChunkY as a Chunk in world_chunk" "3571": "Remove RemoveWorldChunk()" "3650": "Remove stale code from CreateWorld()" "3741": "Update accesses of the world_position Chunk in MapIntoChunkSpace()" "3755": "Change the world_position overload of Subtract() to operate in fixed-point" "3870": "Consider our world-level multithreading ticketing scheme" "3996": "Remove the ticket_mutex from the world" "4050": "Thoughts on humidifiers" "4109": "Note the existence of MoveEntityToNewPosition()" "4143": "Consider the relative difficulty of determining which chunks to pack" "4229": "Consider maintaining rectangles bounding all unpacked entities, resizing as we pack distant entities" "4464": "Augment world with a rectangle2i UnpackedRegions array" "4565": "Mentally sketch out the least recently used chunk packing scheme" "4665": "Reacquaint ourselves with UseChunkSpace()" "4765": "Inline ClearWorldEntityBlock() in UseChunkSpace()" "4845": "Introduce EnsureFreeBlockExists() for UseChunkSpace() to call, renaming the latter to UsePackedSpace()" "4928": "Unify the sizes of packed_entity_block and unpacked_entity_block" "5157": "Yearn to programmatically size struct members" "5203": "Update accesses via packed_entity_block_header, and make UsePackedSpace() use Chunk->FirstPacked" "5274": "Image Jai to support relative sizing of struct members" "5340": "Isn't he shooting guns today?" "5359": "Update accesses via packed_entity_block_header" "5377": "Unify packed_entity_block and unpacked_entity_block as a generic entity_block, splitting HasRoomFor() out as HasRoomForPackedBytes() and HasRoomForUnpackedEntityCount()" "5570": "Update EnsureFreeBlockExists() and UsePackedSpace() to use our new entity_block" "5661": "Respecify UseChunkSpace() as a world_position overload of UsePackedSpace()" "5715": "Simplify world_chunk *Old out of AddToFreeList()" "5822": "Consider doing UsePackedSpace() inline in EnsureChunkIsPacked()" "6018": "Remove both overloads of UsePackedSpace(), and inline the world_chunk one in EnsureChunkIsPacked()" "6088": "Determine to make EnsureChunkIsPacked() loop over each unpacked chunk" "6179": "Make EnsureChunkIsPacked() loop over each unpacked chunk, packing the entities and discarding their blocks" "6378": "Implement EnsureChunkIsUnpacked() based on EnsureChunkIsPacked(), introducing ChunkIsValid()" "6708": "Consider distinguishing between the creation of an entity in an unpacked chunk, and in one in the process of being unpacked" "6811": "Hey, I'm thinking it through!" "6817": "Finish implementing EnsureChunkIsUnpacked()" "6910": "Introduce UseBlockSpace(), respecifying entity_block in terms of a UsedByteCount" "7371": "Simplify EnsureChunkIsPacked() to use UseBlockSpace()" "7463": "Update CreateEntity() to use GetWorldChunk(), EnsureChunkIsUnpacked() and UseBlockSpace()" "7604": "Glimpse into the future working on entity iteration" "7624": "Reorganise CreateEntity() above the entity iteration code" "7656": "Call it there with thoughts on deleting and tightening code, and a plug of Molly Rocket's 25% Off Everything sale" --- name: "day667" title: "Simplified Tile Occupancy Checking" markers: "1": "Recap and set the stage for the day pushing around some entity code" "53": "Describe our spatial-primary–id-secondary lookup system" "196": "Reacquaint ourselves with the sketched entity (un)pack code" "292": "Determine to maintain spatial coherence" "336": "Reacquaint ourselves with the world_chunk_iterator" "392": "Fix typo in the world_chunk_iterator overload of IsValid()" "429": "Describe EnsureValidChunk() as a double-to-single loop and reusable iterator" "535": "Consider the utility of EnsureValidChunk() skipping empty chunks" "671": "Reacquaint ourselves with GetWorldChunkInternal()" "708": "Update EnsureValidChunk() to pass Result->P as a v2s to GetWorldChunkInternal()" "719": "Update IterateChunks() to unbundle the MinChunkP and MaxChunkP values to pass to RectMinMax(), and pass Result.P as a v2s to GetWorldChunkInternal()" "811": "Consider removing BeginWorldChange(), only retaining the brain scan" "1040": "Remove BeginWorldChange() and EndWorldChange()" "1062": "Implement TileIsOpen()" "1474": "Update TileIsOccupied() and TransactionalOccupy() for our new TileIsOpen()" "1520": "Reacquaint ourselves with OverlappingEntitiesExist() and GenerateApron()" "1630": "Consider stateful querying of TileIsOpen()" "1700": "Remove OverlappingEntitiesExist()" "1714": "Reacquaint ourselves with GetClosestEmptyTileTo() and FindAdjacentOpenTile()" "1761": "Embark on stateful querying of TileIsOpen()" "1829": "Add EntityFlag_SupportsOccupation" "1893": "Respecify TileIsOpen() as OrAllFlagsOnTile()" "1932": "Review the call site of TileIsOccupied() in ExecuteBrainSwitches()" "1973": "Respecify TileIsOccupied() as TileCanBeOccupied()" "2047": "Update TransactionalOccupy() to call TileCanBeOccupied()" "2064": "Update ExecuteBrainSwitches() to call TileCanBeOccupied()" "2109": "Reacquaint ourselves with GetClosestEntityWithBrain()" "2133": "Update GetClosestEntityWithBrain() to take a world and world_position" "2242": "molly_rocket I think TileCanBeOccupied() should read && instead of & in between" "2258": "Fix TileCanBeOccupied() to use a boolean && rather than a bitwise &" "2318": "Yo, the #embed gang sends their regards" "2421": "Consider how to encode world positions for GetClosestEntityWithBrain()" "2478": "Encoding world positions: 1) Integer TileIndex + Offset" "2497": "Encoding world positions: 2) Tile-aligned chunk-relative offset" "2522": "Have you removed the math library and made the functions like sqrt? If not, do you have any plans on how to do that?" "2630": "Wolfram|Alpha's Padé approximant of cos(x) order 10,10" "2681": "Wolfram|Alpha's Chebyshev approximation formula" "2741": "Roughly describe a Sin() function" "2853": "But those divides will bite you" "2872": "Consider where GetClosestEntityWithBrain() will get the TestEntity->P from" "2888": "The divides in the Padé are slow" "2953": "DIVPS (XMM, M128), DIVPS (XMM, XMM) and RCPSS (XMM, XMM)" "3142": "Speculatively introduce GetTileIndexOf() and GetWorldPositionOf()" "3279": "Determine to check the call sites of FindRandomOpenTile()" "3338": "Move closest_entity from handmade_world.cpp to handmade_world.h" "3360": "Remove FindNextEntity(), IterateAllEntities() and the entity_iterator overload of Advance()" "3375": "Review the call site of GetClosestEmptyTileTo() in CheckForJoiningPlayers()" "3457": "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" "3582": "Consider the placement by AddPlayer() of pieces in the world to be fine" "3615": "Introduce tile_result, and update GetClosestEmptyTileTo(), FindRandomOpenTile() and FindAdjacentOpenTile() to take a world" "3671": "Update FindAdjacentOpenTile() to work with v2s rather than gen_v3 and edit_tile" "3774": "Consider the meaning of FindAdjacentOpenTile() from its call sites" "3848": "Make FindAdjacentOpenTile() call TileCanBeOccupied() rather than TraversableIsOpen()" "3865": "Reacquaint ourselves with GetDirection()" "3908": "Move GetDirection() from handmade_math.h to handmade_box.cpp" "3953": "Make FindAdjacentOpenTile() set the Result" "3974": "Consider the meaning of FindRandomOpenTile() from its call sites" "4092": "#if 0 FindRandomOpenTile() for now" "4107": "Determine to write the entity iterator" "4119": "Check the absolute time" "4146": "Wind it down with the determination to do brains next time" ---