 Okay, so our first task, our first goal is to just create a simple window with nothing in it. We're not going to actually draw yet. We just want to have a window that we can draw into into our next exercises. So for the purpose of creating a window, we don't want to have to deal with our platform APIs like Win32 here on Windows or the equivalents on Mac or Linux. We just want to have an abstraction layer that handles that stuff for us and also an OpenGL responsible for creating what's called a context that has to be associated with the window. And then we can draw into the context. All that business is really ugly boilerplate that we don't want to deal with. So there's a nice library called GLFW, which I think stands for graphics library for Windows, I believe. Anyway, it's a nice library that will handle all that business in a platform independent way. It'll get us a window we can draw into with OpenGL. It also handles basic input, mouse, keyboard, even gamepad, though it lacks so-called haptic support. It lacks force feedback. Also what it doesn't do for us is expose the functions and constants of OpenGL itself. For that, we're going to need a so-called OpenGL extension loading library. And the one we're using here is called GLAD. What that does is that for the shared object on Windows, the DLL, that is the OpenGL library that's linked into our program, we need to have all the appropriate functions declared in our code so that the compiler knows what we're talking about. And so what GLAD does is it creates a bunch of function pointers matching the API of OpenGL. And then when we init GLAD, it's going to link those function pointers to the appropriate code in the shared object. So those are our two main dependencies. Later on, when dealing with textures, we're going to want to have an image loading library and we're going to be using STB image for that. But in this exercise, we're just creating a window and we're not actually even drawing into it yet. No, we're also including IOStream. That's just for printing out messages to console on the event of errors. And let's skip down here to main. So first thing for GLFW, we need to init it. And then down here, we're going to create our actual window. But before creating the window, we need to give some hints, so-called, to GLFW. These first two are specifying what version of OpenGL we want to use. In this case, 3.3. This here is specifying what's so-called profile. We're using the core profile here of 3.3. And 3.3 is actually quite old by now. It was released, I think, in 2010, 2011. And now we're up to version 4.6. But that's fine because nothing added in later versions is actually going to be relevant for our beginner purposes. So anyway, now we create the window specifying what the width and the height are, which are defined as these constants. We'll just start with a small window 800 by 600. This string specifying what the title of the window is. And these last two arguments are both null. This one, I think, is concerning the monitor. Yes, something to do with if you have some kind of multi-monitor setup, you might want to specify what monitor you're creating the window on, I believe. And I'm not entirely sure what this is about, but we don't need it for our purposes. We're just creating a simple window. And when this returns, if it's successful, if it actually creates the window, then the window will be non-null. But in the event that it is null, we just need to print out the error and terminate. Assuming our window is created successfully, we set the context, our OpenGL drawing context, to the window. And we're also setting up this callback with events generated with the window. In the event that the frame buffer size resizes, which generally is because we resize the window, then we want to call this function, which we've defined down at the bottom, which is simply going to GL viewport as the OpenGL function that defines how large the image is we're outputting. So we just want it to be the same as the width and the height of our full window. So that's all we're doing here. And then next, this is where we're initializing GLAD. This returns true in the event it works successfully. So upon an error, we're going to print out a message and an abort. And come to think of it, I would assume that we would want to call GLFW terminate here as well, if we're going to avoid early. I'm not confident about that, but I assume that's the case. The reason you want to call this terminate function before exiting is because GLFW in some cases will set certain global configuration of your system. I think mainly having to do with like monitor modes, like switching to full screen mode. And so, yes, it releases resources associated with GLFW, but of course, if it's just memory that gets cleaned up when your process dies anyway, that's not really the issue. I believe the real concern is about like monitor modes and perhaps some other kind of global state. Anyway, now we have our window to render into. And normally, if we want to have animation, of course, then we would not just render once we'd have a loop in which we render. And we want this loop to keep going as long as the exit event has not been triggered on our window. So that's why we call this to check if the window is supposed to close. If not, we render one more time. Down at the bottom, though, that's where we tell GLFW to read the events from the event queue. If we didn't call poll events, then our program would be a badly behaved windows application that isn't properly consuming its message queue. And I suppose actually, there's no reason why this is done down here rather than first thing before the input. The way this is arranged is effectively for the for the first frame. We're not going to be processing any input. I don't know if there's any real reason to do that. But in a way, this arrangement should work fine. Typically in any game, you handle input at the start of the frame that somehow affects what the state of the world and what we're going to render is and then we do our actual rendering. So here in this case, we're just rendering just a blank window. And we're doing so by clearing the frame buffer. Geo clear is what makes it actually happen. This constant means we're clearing the color portion of the frame buffer, not the depth buffer, not the stencil buffer. Those things will come into the picture later for now. We're just clearing the color and clear color here beforehand, though, is specifying what the color is going to be. And this is RGBA. So an alpha of one fully opaque red of point two, like 20 percent red, 30 percent green and 30 percent blue. So we've rendered our full image. And by the way, the size of the output image, again, is determined by GL viewport, which I guess normally you would call this before doing your first rendering, but I imagine this gets called the very first time our windows created, I assume. And let's perhaps viewport defaults to the size of the window. Maybe that's what actually happens. And the viewport defines where within the window we are drawing, which is not necessarily the full width of the window, not necessarily the full height. And also the image isn't necessarily centered or in one of the corners. The zero and zero here, those are the X and Y values of the bottom left of the window from which we are drawing. Our viewport coordinate system has its origin of the bottom left of the viewport. And the window as well, its origin is considered to be at the bottom left. So say if our width and height were less than the actual width and height of our window, then we'd be effectively drawing a rectangle into the low left corner of the window. Last thing in our loop is that having rendered our image, we've drawn into a frame buffer, but our program actually has two primary frame buffers, one of which is currently being displayed, the other which we are currently drawing into. And so what we wanna do is swap which of these two buffers is currently being displayed and which one we're gonna draw into. And that's what swap buffers here does. And I believe by default, the buffer swapping is tied to v-sync of your monitor. So say if your monitor has a 60 hertz refresh rate, when you call swap buffers, it's gonna wait until the next interval of 60th of a second comes along and then it swaps the buffers. So as long as v-sync is enabled, our program actually has a rate limit to it where because a swap buffers call is going to wait for the next occurrence of that interval, our loop is not going to run faster than the refresh rate of your monitor. So again, assuming 60 hertz, that would mean 60 frames a second. If we turn v-sync off, you're generally then gonna wanna add some logic to add some pauses to space out the runs through the loop. You don't want it to run as fast as possible. That's generally not desirable. And oh wait, we didn't actually look at the process input function. What does it do? It calls this method get key that for the window checks if escape has been pressed since the last time we called pull events. If so, then this returns true and we're going to set window should close to true such that next time this is called, it's going to return true and we're gonna exit our loop, come down here, terminate and leave the program. So right now our program is just simply looking for the escape key being pressed and that's what will close the program. So now that's all the code. It's all just one source file with two major dependencies and I come here and I'm gonna build the project. The build is successful and it's gonna end up under the project directory there's bin, then the exercises are divided into different sections. What is it? Yeah, these seven sections we're getting started. Debug and this is 1.2. I run it and then we have just a nice blank window which if I resize notice that there's a delay until I actually let go of the mouse button because it doesn't trigger the resize event until I let go but then for the next frame it properly draws to the proper size window. I think there actually are some window events you can hook into in windows so you can actually redraw as you resize but for most purposes that's not really a big deal so we're not gonna bother with that.