We are now going to talk about Window system interactions and callbacks. Note that Window system interactions are not a part of OpenGL. Nevertheless, there are a number of toolkits available such as the GLUT toolkit that you will be using in your homework assignments, also freeglut, which is very popular. These toolkits include callback functions for events in a manner similar to other kinds of programming interfaces such as X Windows or Java. In particular, you can define functions that apply when the user types a key on the keyboard or presses a mouse button, also when the user opens or resizes the window. The main function in our program included a callback for the display to redisplay the scene, for reshape if you change the size of the window, for the keyboard function if you press keys on the keyboard, as well as for the mouse function and for dragging or moving the mouse. Let's first talk about the keyboard function. As you can see, it takes in inputs of the key pressed, which is an unsigned char, it's essentially the ASCII code of the key, as well as the location on the screen when the key is pressed, x and y, which we do not need to use here. Note that we are not doing very much with the keyboard function. Simply if the user types the Escape key, then we quit the program. The ASCII code for Escape is 27. And all that the program does is that it enters a switch statement based on this key. If the key is 27, which is Escape, it exits, otherwise it just continues. Let us now talk about the reshape callback where the user is changing the width and the height of the window, that's what the w and h input arguments are. This is one of the rare occasions where we'll actually use the glViewport command in OpenGL, essentially to set the width and height of the window. Thereafter, we have to define the appropriate projection matrix so that the scene is displayed within this window. For this purpose, we could, in old OpenGL, have used the gluPerspective command directly. However, in modern OpenGL, we instead use the GLM equivalent, which is glm::perspective. And I'll talk about the arguments to it. The first argument corresponds to this value of 30. That is just 30 degrees. That means the field of view seen by the camera, which is the field of view in the y direction, so we can write that as corresponding to the field of view in the y direction. If you remember our discussion of gluPerspective, this corresponds to how large an angle the camera is seeing, and in the y direction. Notice that because we have to convert it to radians, we are dividing by 180 and multiplying by pi, okay? So this is the conversion to radians. The next argument to this projection command is the aspect ratio, which corresponds to the width and the height of the scene. Note that the scene is still displayed in a one-to-one aspect, but we have to adjust the field of view in y with respect to x, in order to maintain the aspect ratio of the window properly, which is why we have this w over h, and that corresponds to the aspect. Finally, you have the near plane and the far plane. Let's look at the next line, which is the glUniformMatrix4fv line. It now corresponds to our shader. In old OpenGL, you could just specify gluPerspective and stop. In our case, we have to still give the projection matrix to this shader. projectionPos is the position in the shader of the location of the projection matrix. One sees that we are passing only one matrix. This command can actually be used to pass multiple matrices. GL_FALSE just says we're not going to transpose the matrix. And, finally, we give it the location of the projection matrix, which is just a pointer to the first entry. And as noted in this comment, this is to send the projection matrix to the shader. We now talk about mouse motion. The input to the mouse command is the button that is pressed, the state whether it's up or down, and the location where the mouse is pressed, which is x and y. If the button is the left button and the state is up, you do nothing. If the sate is down, that means I'm pressing the left button down. We will set mouseoldx and mouseoldy to be x and y coordinates so that we can do a drag. And finally, if the button is the right button, and the state is down, then we reset the lookAt position. Notice, again, to reset the lookAt position you first set eyeloc to its original value of 2. Then you set the modelview matrix using the glm::lookAt command, so that is the lookFrom position, based on eyeloc, (0,-2,2). Where it's looking at, which is the origin. And, finally, what the up vector is. Thereafter, you send this matrix to the shader. Just as we sent the projection matrix earlier, you put the matrix in the location modelview position. You're sending only one value, you're not transposing, and you give it the first value in the matrix, which is the pointer to the modelview matrix. Finally, you will redraw the scene. Let me just show you a demo now of how mouse motions works. Here is my simple demo. This is mytest1. Actually, this has two planes, but I'm going to zoom in so that I see only one of them. Notice that if I stop my mouse here and I click on it, then if I move my mouse up, I zoom into the scene. Notice if I zoom too much, part of the plane gets cut off by the near plane. And I can zoom out. Ultimately, I can zoom out to see the entire scene, including the upper plane on top. Also, if I press the right button, then it resets to the original paramaterization. I already showed you what happens to drag when you move your mouse continuously. There is a separate callback for this purpose. What it is doing is seeing how far you've used the mouse relative to when you started the drag and you pressed the left button. That's what yloc is doing, is just considering the current value of y minus the old value, and using that to zoom in or out. So, in particular, it will change the value of the eye location. So we have the 0.005 times the increment in y location. Of course, if eyeloc is less than zero, you don't let that happen. Finally, there is some code which sets the eye location. So this sets the modelview matrix, which is just lookAt from the appropriate eye location, looking at the origin of coordinates with a given up vector. And just as we've done previously, we send this information to the shader, so you put this information in modelviewPos. There's only one value, there's no transposition happening and you set it to the initial modelview value. Finally, you redraw the scene.