Выбрать главу

We rotate the 'real' ball, and again, because the y-axis is not mirrored, the ball will spin the opposite direction of the reflected ball. If the reflected ball is rolling towards you the 'real' ball will be rolling away from you. This creates the illusion of a real reflection.

After positioning and rotating the ball, we draw the 'real' ball by calling DrawObject().

 glEnable(GL_LIGHTING); // Enable Lighting

 glDisable(GL_BLEND); // Disable Blending

 glTranslatef(0.0f, height, 0.0f); // Position The Ball At Proper Height

 glRotatef(xrot, 1.0f, 0.0f, 0.0f); // Rotate On The X Axis

 glRotatef(yrot, 0.0f, 1.0f, 0.0f); // Rotate On The Y Axis

 DrawObject(); // Draw The Ball

The following code rotates the ball on the x and y axis. By increasing xrot by xrotspeed we rotate the ball on the x-axis. By increasing yrot by yrotspeed we spin the ball on the y-axis. If xrotspeed is a very high value in the positive or negative direction the ball will spin quicker than if xrotspeed was a low value, closer to 0.0f. Same goes for yrotspeed. The higher the value, the faster the ball spins on the y-axis.

Before we return TRUE, we do a glFlush(). This tells OpenGL to render everything left in the GL pipeline before continuing, and can help prevent flickering on slower video cards.

 xrot += xrotspeed; // Update X Rotation Angle By xrotspeed

 yrot += yrotspeed; // Update Y Rotation Angle By yrotspeed

 glFlush(); // Flush The GL Pipeline

 return TRUE; // Everything Went OK

}

The following code will watch for key presses. The first 4 lines check to see if you are pressing one of the 4 arrow keys. If you are, the ball is spun right, left, down or up.

The next 2 lines check to see if you are pressing the 'A' or 'Z' keys. Pressing 'A' will zoom you in closer to the ball and pressing 'Z' will zoom you away from the ball.

Pressing 'PAGE UP' will increase the value of height moving the ball up, and pressing 'PAGE DOWN' will decrease the value of height moving the ball down (closer to the floor).

void ProcessKeyboard() // Process Keyboard Results

{

 if (keys[VK_RIGHT]) yrotspeed += 0.08f; // Right Arrow Pressed (Increase yrotspeed)

 if (keys[VK_LEFT]) yrotspeed –= 0.08f; // Left Arrow Pressed (Decrease yrotspeed)

 if (keys[VK_DOWN]) xrotspeed += 0.08f; // Down Arrow Pressed (Increase xrotspeed)

 if (keys[VK_UP]) xrotspeed –= 0.08f; // Up Arrow Pressed (Decrease xrotspeed)

 if (keys['A']) zoom +=0.05f; // 'A' Key Pressed … Zoom In

 if (keys['Z']) zoom –=0.05f; // 'Z' Key Pressed … Zoom Out

 if (keys[VK_PRIOR]) height +=0.03f; // Page Up Key Pressed Move Ball Up

 if (keys[VK_NEXT]) height –=0.03f; // Page Down Key Pressed Move Ball Down

}

The KillGLWindow() code hasn't changed, so I'll skip over it.

GLvoid KillGLWindow(GLvoid) // Properly Kill The Window

You can skim through the following code. Even though only one line of code has changed in CreateGLWindow(), I have included all of the code so it's easier to follow through the tutorial.

BOOL CreateGLWindow(char* title, int width, int height, int bits, bool fullscreenflag) {

 GLuint PixelFormat; // Holds The Results After Searching For A Match

 WNDCLASS wc; // Windows Class Structure

 DWORD dwExStyle; // Window Extended Style

 DWORD dwStyle; // Window Style

 fullscreen=fullscreenflag; // Set The Global Fullscreen Flag

 hInstance = GetModuleHandle(NULL); // Grab An Instance For Our Window

 wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; // Redraw On Size, And Own DC For Window

 wc.lpfnWndProc = (WNDPROC) WndProc; // WndProc Handles Messages

 wc.cbClsExtra = 0; // No Extra Window Data

 wc.cbWndExtra = 0; // No Extra Window Data

 wc.hInstance = hInstance; // Set The Instance

 wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); // Load The Default Icon

 wc.hCursor = LoadCursor(NULL, IDC_ARROW); // Load The Arrow Pointer

 wc.hbrBackground = NULL; // No Background Required For GL

 wc.lpszMenuName = NULL; // We Don't Want A Menu

 wc.lpszClassName = "OpenGL"; // Set The Class Name

 if (!RegisterClass(&wc)) // Attempt To Register The Window Class

 {

  MessageBox(NULL, "Failed To Register The Window Class.", "ERROR", MB_OK|MB_ICONEXCLAMATION);

  return FALSE; // Return FALSE

 }

 if (fullscreen) // Attempt Fullscreen Mode?

 {

  DEVMODE dmScreenSettings; // Device Mode

  memset(&dmScreenSettings, 0, sizeof(dmScreenSettings)); // Makes Sure Memory's Cleared

  dmScreenSettings.dmSize = sizeof(dmScreenSettings); // Size Of The Devmode Structure

  dmScreenSettings.dmPelsWidth = width; // Selected Screen Width

  dmScreenSettings.dmPelsHeight = height; // Selected Screen Height

  dmScreenSettings.dmBitsPerPel = bits; // Selected Bits Per Pixel

  dmScreenSettings.dmFields = DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;

  // Try To Set Selected Mode And Get Results. NOTE: CDS_FULLSCREEN Gets Rid Of Start Bar

  if (ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) {

   // If The Mode Fails, Offer Two Options. Quit Or Use Windowed Mode

   if (MessageBox(NULL, "The Requested Fullscreen Mode Is Not Supported By\nYour Video Card. Use Windowed Mode Instead?", "NeHe GL", MB_YESNO | MB_ICONEXCLAMATION) == IDYES) {

    fullscreen=FALSE; // Windowed Mode Selected. Fullscreen = FALSE

   } else

   {

    // Pop Up A Message Box Letting User Know The Program Is Closing

    MessageBox(NULL, "Program Will Now Close.", "ERROR", MB_OK|MB_ICONSTOP);

    return FALSE; // Return FALSE

   }

  }

 }

 if (fullscreen) // Are We Still In Fullscreen Mode?

 {

  dwExStyle=WS_EX_APPWINDOW; // Window Extended Style

  dwStyle=WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN; // Windows Style

  ShowCursor(FALSE); // Hide Mouse Pointer

 } else

 {

  dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; // Window Extended Style

  dwStyle=WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;// Windows Style

 }

 // Create The Window

 if (!(hWnd=CreateWindowEx( dwExStyle, // Extended Style For The Window

  "OpenGL", // Class Name

  title, // Window Title

  dwStyle, // Window Style

  0, 0, // Window Position

  width, height, // Selected Width And Height

  NULL, // No Parent Window

  NULL, // No Menu