[video member=cmuratori stream_platform=twitch stream_username=handmade_hero project=code title="Adding Distance-based Fog" vod_platform=youtube id=RvEOtCTDWf0 annotator=Miblo] [0:09][Recap and set the stage for the day] [2:51][Run the game and show where we left off] [3:18][handmade_world_mode.cpp: Make PlayWorld() stack up 10 rooms and run the game to view them] [4:57][handmade_world_mode.cpp: Make AddStandardRoom() create holes on every floor] [5:18][Run the game to view the entities each floor comprises, and determine to reintroduce fog] [11:57][handmade_opengl.cpp: Try to introduce a GlobalFrameBufferDepth for OpenGLRenderCommands() to output a bitmap[ref site="docs.GL" page="glBlitFramebuffer" url="http://docs.gl/gl3/glBlitFramebuffer"]] [14:51][Run the game to find that glFramebufferTexture2D() failed, and undo our changes] [17:47][handmade_opengl.cpp: Begin to reintroduce fog] [20:13][Blackboard: "Fog" darkening based on distance] [25:30][handmade_opengl.cpp: Enable the VertexCode to linearly interpolate between the FragColor and FogColor, using GLSL's mix()[ref site="OpenGL Registry" page="The OpenGL Shading Language 1.50 Quick Reference Card" url="https://www.khronos.org/files/opengl-quick-reference-card.pdf"]] [36:16][Run the game to see the blending between the two colours] [36:53][handmade_opengl.cpp: Investigate why the bitmaps are not getting fogged] [41:42][handmade_opengl.cpp: Enable the FragmentCode to perform the fogging lerp] [44:09][Run the game to see what we'd expect to see] [44:33][handmade_opengl.cpp: Enable the VertexCode to compute the FogAmount based on the distance from camera] [49:14][handmade_opengl.cpp: Introduce Clamp01MapToRange() in the shader] [51:14][handmade_opengl.cpp: Make the VertexCode call that Clamp01MapToRange()] [52:32][Run the game and assume that nothing is incorrect there] [52:45][handmade_opengl.cpp: Make OpenGLInit() and OpenGLRenderCommands() setup our fog data] [56:18][A few words on threading cables through conduits] [58:18][handmade_render_group.h: Consider removing render_entry_cliprect in favour of render_entry_textured_quads] [1:01:03][handmade_render_group.h: Remove render_entry_bitmap, render_entry_rectangle, render_entry_clear and render_entry_saturation] [1:02:38][Note that this simplification provides us with the ability to view the fog from a different direction] [1:03:34][handmade_render_group.h: Add fog data to render_entry_cliprect] [1:03:54][handmade_opengl.cpp: Make the render_entry_textured_quads case in OpenGLRenderCommands() set the fog data] [1:05:08][win32_handmade.cpp: Pull in glUniform1f, glUniform2fv, glUniform3fv and glUniform4fv from corearb.h[ref site="Khronos" page="glcorearb.h" url="https://www.khronos.org/registry/OpenGL/api/GL/glcorearb.h"]] [1:08:06][Run the game to determine that we are passing everything through correctly] [1:08:16][handmade_render_group.h: Add a render_entry_cliprect LastSetup to render_group and propagate that change] [1:13:36][handmade_render_group.cpp: Clean up how the render_entry_cliprect NewSetup gets used] [1:19:58][handmade_math.h: Introduce versions of RectMinMax() and RectMinDim() that return a rentangle2i] [1:21:32][handmade_render_group.cpp: Continue cleaning up the use of NewSetup] [1:22:42][Run the game to see nothing yet] [1:23:01][handmade_render_group.cpp: Make BeginRenderGroup() initialise the fog distances] [1:23:45][Run the game to see our game drawing correctly, and note why] [1:24:47][handmade_render_group.cpp: Enable SetCameraTransform() to compute the fog by its distance] [1:26:36][Run the game to see the fog taking effect through the hole] [1:27:21][handmade_opengl.cpp: Enable the FragmentCode to take a FogColor and blend part of it] [1:30:19][handmade_render_group.h: Add FogColor to render_entry_cliprect] [1:30:28][handmade_opengl.cpp: Make OpenGLRenderCommands() set that FogColor] [1:31:40][Run the game to see our programatically set fog colour] [1:31:45][handmade_render_group.cpp: Tweak the FogColor in BeginRenderGroup()] [1:33:14][handmade_render_group.cpp: Investigate how Clear() is working] [1:35:57][handmade_math.h: Introduce LinearTosRGB()] [1:36:33][handmade_render_group.cpp: Make BeginRenderGroup() Square the FogColor, and run the game to determine that the Clear does not go through sRGB] [1:37:06][handmade_platform.h: Label the ClearColor in game_render_commands as not in linear space, but in sRGB space] [1:39:05][handmade_render_group.cpp: Make Clear() set the FogColor] [1:41:21][Run the game and consider that to be quite good] [1:42:30][Consider handling alpha fading of levels nearer to the camera than the hero's current level] [1:43:39][handmade_world_mode.cpp: Enable AddStandardRoom() to generate stairs] [1:49:23][Run the game and hop down the stairs] [1:51:25][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()] [2:13:17][handmade_render.cpp: Remove LinearizeClipRects() and PrepForRender()] [2:14:39][Run the game to see that that worked just great, with a few words on how much cleaner the render commands are now] [2:15:57][Q&A] [2:16:50][@nyeecola][Has the framerate tanked after implementing fog? Or was that a wrong impression of mine?] [2:17:02][Compile and run with various optimisation settings] [2:19:54][@Miblo][Now that we're full 3D, may it be worth extending the debug visualisation rectangles into the third dimension?] [2:20:19][@nyeecola][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)] [2:21:28][handmade_sim_region.cpp: Make a KillSwitch to disable GetClosestTraversable()] [2:23:42][Run the game and compare the framerate with and without GetClosestTraversable() running] [2:25:43][Step in to GetClosestTraversable() and calculate how many operations it performs, and the number of cycles in which it must execute] [2:30:12][Look at the disassembly for GetClosestTraversable() when compiled with -Od] [2:33:00][Switch to -O2 and look at the disassembly for GetClosestTraversable() again] [2:36:08][Compiling with optimisations on inhibits our ability to debug the code effectively] [2:39:55][@macielda][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?] [2:40:24][@macielda][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?] [2:41:10][@thesizik][What does the software renderer look like at the moment?] [2:41:33][@chrysos42][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?] [2:44:18][@rocketbuny][How many lines of code does Handmade Hero have?] [2:47:42][Wind it on down with a glimpse into the future] [/video]