[video output=day475 member=cmuratori stream_platform=twitch stream_username=handmade_hero project=code title="Abstracting the Renderer Interface" vod_platform=youtube id=EguT5zni4J4 annotator=Miblo]
[0:02][Recap and set the stage for the day][:speech]
[0:49][Walk through our test RenderLoop() with a view to streamlining the :camera and fog code, and cleaning up the drawing calls in PushSimpleScene()][:api :rendering :research]
[3:34][Our framerate problems incurred by the :lighting][:performance :rendering :research]
[6:12][Crank up the grass sprite count in PushSimpleScene()][:rendering]
[7:53][:Run the game and step in the RenderLoop() to see that we are using 184 bytes of our 64 megabyte-capacity PushBuffer][:memory :performance :rendering]
[9:15][Reduce the PushBuffer size to 1 megabyte][:memory :rendering]
[10:09][Consider simplifying the PushBuffer out of the renderer :API][:memory :rendering]
[16:26][Change open_gl to no longer be initialised as a global variable, but locally by Win32InitOpenGL()][:api]
[28:49][Introduce platform_renderer to generalise our renderer and decouple it from the OpenGL :API]
[35:04][Introduce GetWhiteBitmap(), and continue the :API decoupling, renaming DefaultRenderCommands() to BeginFrame() and OpenGLRenderCommands() to EndFrame()]
[41:38][Set up implement platform_renderer dispatching][:api :speech]
[42:49][Change LoadBMP() to call AddOp() and take a renderer_texture_queue and renderer_texture rather than call QueueTextureOp() and take a platform_renderer][:api]
[46:50][Introduce AllocateTextureQueue() and ProcessTextureQueue() for RenderLoop() to call][:api :memory]
[50:17][Implement AllocateTextureQueue(), setting it up to use the platform :memory allocation call][:api :"platform layer"]
[52:23][Remove AllocateTextureQueue() in favour of making RenderLoop() call InitTextureQueue(), allocating :memory in that call using Win32AllocateMemory()][:api :"platform layer"]
[55:19][Respecify InitTextureQueue() to take MemorySize, and itself compute the possible TextureOpCount to fit in that :memory][:api]
[58:09][Rename MaxVertexCount to MaxQuadCountPerFrame in RenderLoop(), leaving the possibility open for the platform to specially allocate the :memory][:api]
[1:00:15][Reorder RenderLoop() slightly][:api]
[1:01:11][Make Win32InitOpenGL() allocate our open_gl, adding PushBufferMemory and textured_vertex and renderer_texture arrays to this struct][:api :memory]
[1:08:09][Demo C++ inheritance to abstract the renderer][:api :language]
[1:11:38][Abstract out the renderer dispatch with an enum in platform_renderer, for newly introduced Win32AllocateRenderer(), ProcessTextureQueue(), BeginFrame() and EndFrame() to switch on][:api]
[1:27:33][Introduce OpenGLBeginFrame(), adding WindowWidth and WindowHeight to game_render_commands, and stubbing out the various API-specific functions][:api]
[1:38:54][:Run the Renderer Test and check out our :memory usage, to see that we have reserved 1.5 gigabytes][:performance]
[1:41:20][Step through RenderLoop() to determine that EndFrame() allocates this :memory][:performance :run]
[1:44:19][Step through OpenGLEndFrame() into OpenGLChangeToSetting() to see that the first CreateFramebuffer() call reserves 300 megabytes][:memory :performance :run]
[1:46:33][Step in to CreateFramebuffer() to see that the glFramebufferTexture2D() call reserves 200 megabytes, and investigate whether this is reasonable][:memory :performance :run]
[1:51:17][:Run the game and consider our high :memory usage][:performance]
[1:53:29][Temporarily disable multisampling in OpenGLInit()][:rendering]
[1:53:49][:Run the game to see that it now only reserves 312 megabytes][:memory :performance]
[1:54:09][Re-enable multisampling in OpenGLInit() and reduce the grass sprite count in PushSimpleScene()][:rendering]
[1:54:51][:Run the game, and compare the edge :rendering with and without multisampling]
[1:58:03][Disable pixelisation in OpenGLInit()][:rendering]
[1:58:32][:Run the game and consider that enabled pixelisation to be a bug][:rendering]
[1:58:53][Switch [~hero Handmade Hero] over to our abstracted renderer interface[ref
    site=MSDN
    page="wglGetCurrentDC function"
    url=https://docs.microsoft.com/en-us/windows/desktop/api/wingdi/nf-wingdi-wglgetcurrentdc]][:api :memory :rendering]
[2:12:51][:Run both the Renderer Test and game successfully][:api]
[2:13:28][Refresh our memories as to how the mouse position is handled][:"input handling" :research]
[2:15:24][Prevent DEBUGEnd() from calling ClipSpaceFromPixelSpace() to map the mouse coordinates][:"debug system" :"input handling"]
[2:16:01][:Run the game to find that the clicking doesn't work][:"debug system" :"input handling"]
[2:16:20][Introduce ClampBinormalMapToRange() for WinMainCRTStartup() to clamp the mouse coordinates to -1 to 1 space][:"debug system" :"input handling"]
[2:19:03][:Run the game to find that the mouse works again, but that the rotation and scaling controls are broken][:camera :"debug system" :"input handling"]
[2:19:31][Tweak the :camera rotation and zooming multipliers in UpdateAndRenderWorld()][:"input handling" :programming :run]
[2:21:22][Change the Mouse coordinates in game_input to be one v3 called ClipSpaceMouseP][:"input handling"]
[2:23:21][:Run the game to see that all is working, except for the positions of the :"debug system" menus]
[2:24:34][Reflect on our renderer :API][:research]
[2:25:47][Make OpenGLChangeToSettings() responsible for setting VSync using a newly introduced PlatformOpenGLSetVSync()][:api :rendering]
[2:29:58][:Run the game and the Renderer Test to gauge the VSync][:rendering]
[2:31:34][:Run the Renderer Test in -Od to see that we do request that VSync is disabled][:rendering]
[2:32:20][Q&A][:speech]
[2:32:47][Reflect again on our cleaner renderer :API][:research]
[2:33:45][@ivereadthesequel][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][:language]
[2:36:51][@vateferfout][Q: Not important, but I think that in your LoadBMP() function you're still declaring a renderer_texture result]
[2:37:29][@rationalcoder][Q: Is there something about your render passes that prohibits hybrid AA techniques, like MSAA 4X plus conservative FXAA? MSAA 16X is way overkill][:rendering]
[2:40:33][Reduce MaxMultiSampleCount in OpenGLInit()][:rendering]
[2:41:00][:Run the game to gauge our multisampling quality][:rendering]
[2:43:50][@uplinkcoder][Q: Could you take a look at 'Typo in win32_render_test.cpp'[ref
    site=HandmadeHero/cpp/Issues
    page="Typo in win32_render_test.cpp"
    url=https://github.com/HandmadeHero/cpp/issues/76]]
[2:44:06][Fix typo in PushSimpleScene()][:"procedural generation"]
[2:45:16][@Rounin][Q: The plants look worse with 8-bit][:rendering]
[2:46:03][@centhusiast][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?][:memory]
[2:47:39][@ivereadthesequel][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?][:language]
[2:51:34][We're all good[ref
    site="Handmade Hero"
    url=https://handmadehero.org/][ref
        site="Molly Rocket's Site Nexus"
        url=https://mollyrocket.com/nexus]][:speech]
[/video]
