chapter4.cpp

来自「一本关于OPenGL的很好的电子书」· C++ 代码 · 共 886 行 · 第 1/2 页

CPP
886
字号
                          g_hInstance,        // application instance
                          NULL);              // no extra params

  // see if our window handle is valid
  if (!g_hwnd)
	{
    // reset the display
		KillWindow();
		MessageBox(NULL, "Unable to create window", "Error", MB_OK | MB_ICONEXCLAMATION);
		return FALSE;
	}

  // get a device context
	if (!(g_hdc = GetDC(g_hwnd)))
	{
    // reset the display
		KillWindow();
		MessageBox(NULL,"Unable to create device context", "Error", MB_OK | MB_ICONEXCLAMATION);
		return FALSE;
	}

  // set the pixel format we want
  PIXELFORMATDESCRIPTOR pfd = {
    sizeof(PIXELFORMATDESCRIPTOR),	// size of structure
    1,                              // default version
    PFD_DRAW_TO_WINDOW |            // window drawing support
    PFD_SUPPORT_OPENGL |            // OpenGL support
    PFD_DOUBLEBUFFER,               // double buffering support
    PFD_TYPE_RGBA,                  // RGBA color mode
    bits,                           // 32 bit color mode
    0, 0, 0, 0, 0, 0,               // ignore color bits, non-palettized mode
    0,                              // no alpha buffer
    0,                              // ignore shift bit
    0,                              // no accumulation buffer
    0, 0, 0, 0,                     // ignore accumulation bits
    16,                             // 16 bit z-buffer size
    0,                              // no stencil buffer
    0,                              // no auxiliary buffer
    PFD_MAIN_PLANE,                 // main drawing plane
    0,                              // reserved
    0, 0, 0 };                      // layer masks ignored
      
	GLuint  pixelFormat;

	// choose best matching pixel format
	if (!(pixelFormat = ChoosePixelFormat(g_hdc, &pfd)))
	{
    // reset the display
		KillWindow();
		MessageBox(NULL, "Can't find an appropriate pixel format", "Error", MB_OK | MB_ICONEXCLAMATION);
		return FALSE;
	}

	// set pixel format to device context
  if(!SetPixelFormat(g_hdc, pixelFormat,&pfd))
	{
    // reset the display
		KillWindow();
		MessageBox(NULL, "Unable to set pixel format", "Error", MB_OK | MB_ICONEXCLAMATION);
		return FALSE;
  }

  // create the OpenGL rendering context
  if (!(g_hrc = wglCreateContext(g_hdc)))
	{
    // reset the display
		KillWindow();
		MessageBox(NULL, "Unable to create OpenGL rendering context", "Error",MB_OK | MB_ICONEXCLAMATION);
		return FALSE;
	}

  // now make the rendering context the active one
  if(!wglMakeCurrent(g_hdc, g_hrc))
	{
    // reset the display
		KillWindow();
		MessageBox(NULL,"Unable to activate OpenGL rendering context", "ERROR", MB_OK | MB_ICONEXCLAMATION);
		return FALSE;
	}

  // show the window in the forground, and set the keyboard focus to it
  ShowWindow(g_hwnd, SW_SHOW);
	SetForegroundWindow(g_hwnd);
	SetFocus(g_hwnd);

  // set up the perspective for the current screen size
	ResizeScene(width, height);

  // do one-time initialization
  if (!InitializeScene())
	{
    // reset the display
		KillWindow();
		MessageBox(NULL, "Initialization failed", "Error", MB_OK | MB_ICONEXCLAMATION);
		return FALSE;
	}

  return TRUE;
} // end SetupWindow()


/****************************************************************************
 InitializeScene()

 Sets up everything for our scene that only needs to be done once.
*****************************************************************************/
BOOL InitializeScene()
{
  // use Gouraud shading
  glShadeModel(GL_SMOOTH);

  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

  // tell OpenGL to use the nicest built-in antialiasing possible
  glHint(GL_POINT_SMOOTH, GL_NICEST);
  glHint(GL_LINE_SMOOTH, GL_NICEST);
  glHint(GL_POLYGON_SMOOTH, GL_NICEST);

  // get the min and max point sizes and the step size
  glGetFloatv(GL_POINT_SIZE_RANGE, g_pointSizeMinMax);
  glGetFloatv(GL_POINT_SIZE_GRANULARITY, &g_pointSizeStep);

  // get the min and max line widths and the step size
  glGetFloatv(GL_LINE_WIDTH_RANGE, g_lineWidthMinMax);
  glGetFloatv(GL_LINE_WIDTH_GRANULARITY, &g_lineWidthStep);

  // set a line stipple pattern, setting each bit to repeat 3 times
  GLushort lineStipple = 0xEB32;
  glLineStipple(3, lineStipple);

  // specify a polygon mask for stippling. This is a rough copy of the
  // OpenGL logo
  GLubyte mask[] = {
    0x0, 0x0, 0x0, 0x0,
    0x0, 0x0, 0x0, 0x0,
    0x0, 0x0, 0x0, 0x0,
    0x0, 0x0, 0x0, 0x0,
    0x0, 0x0, 0x0, 0x0,
    0x0, 0x0, 0x0, 0x0,
    0x0, 0x0, 0x0, 0x0,
    0x0, 0x0, 0x0, 0x0,
    0x0, 0x0, 0x0, 0x0,
    0x7, 0xFF, 0xF0, 0x0,
    0x1F, 0xE0, 0x1E, 0x0,
    0x7E, 0x20, 0x01, 0x0,
    0x7F, 0x39, 0xAB, 0x6F,
    0xFC, 0xA6, 0xAB, 0x6F,
    0xF8, 0x66, 0x6E, 0xEC,
    0xF8, 0x6A, 0x2A, 0x6C,
    0xFC, 0x80, 0x02, 0x2C,
    0x7F, 0x0, 0x1, 0xC8,
    0x7F, 0x0, 0x1, 0xC8,
    0x1F, 0xC0, 0x0C, 0x0,
    0x07, 0xFF, 0xF0, 0x0,
    0x03, 0xFF, 0xE0, 0x0,
    0x0, 0x1C, 0x0, 0x0,
    0x0, 0x0, 0x0, 0x0,
    0x0, 0x0, 0x0, 0x0,
    0x0, 0x0, 0x0, 0x0,
    0x0, 0x0, 0x0, 0x0,
    0x0, 0x0, 0x0, 0x0,
    0x0, 0x0, 0x0, 0x0,
    0x0, 0x0, 0x0, 0x0,
    0x0, 0x0, 0x0, 0x0,
    0x0, 0x0, 0x0, 0x0
  };

  // tell OpenGL to use this mask for stippling
  glPolygonStipple(mask);

  return TRUE;
} // end InitializeScene()


/****************************************************************************
 Resize()

 Sets up the correct perspective based on the current screen size.
*****************************************************************************/
GLvoid ResizeScene(GLsizei width, GLsizei height)
{
  // reset the viewport to the new dimensions
  glViewport(100, 100, width-100, height-100);

  // set our globals to match the (possibly new) values
  g_width = width;
  g_height = height;

  // select the projection matrix and clear it out
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();

  // set the perspective
  gluOrtho2D(0, width, 0, height);

  // select modelview matrix and clear it out
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
} // end ResizeScene()


/****************************************************************************
 DisplayScene()

 Actually draw our scene. This will be called every frame.
*****************************************************************************/
BOOL DisplayScene()
{
  // clear the screen
  glClear(GL_COLOR_BUFFER_BIT);

  // we're using random numbers for most of the colors and primitive
  // positions. Because we want to have the random numbers chosen every frame,
  // we need to seed the random number generator with the same number every
  // frame. Try commenting this line out to see what happens.
  srand(g_currentPrimitive);

  // only draw the currently selected primitive
  switch(g_currentPrimitive)
  {
  case PT_POINT:
    {
      // draw 40 random points. Note that we're only making a single call to
      // glBegin().
      glBegin(GL_POINTS);
        for (int n = 0; n < 40; n++)
        {
          glColor3ub(rand() % 256, rand() % 256, rand() % 256);
          glVertex2i(rand() % g_width, rand() % g_height);
        }
      glEnd();

    } break;
  case PT_LINE:
    {
      // draw 10 random lines. Each pair of vertices specifies a new line
      glBegin(GL_LINES);
        for (int n = 0; n < 10; n++)
        {
          glColor3ub(rand() % 256, rand() % 256, rand() % 256);
          glVertex2i(rand() % g_width, rand() % g_height);
          glColor3ub(rand() % 256, rand() % 256, rand() % 256);
          glVertex2i(rand() % g_width, rand() % g_height);
        }
      glEnd();
    } break;
  case PT_TRIANGLE:
    {
      // draw 3 random triangles
      glBegin(GL_TRIANGLES);
        for (int n = 0; n < 3; n++)
        {
          glColor3ub(255, rand() % 256, rand() % 256);
          glVertex2i(rand() % g_width, rand() % g_height);
          glColor3ub(rand() % 256, 255, rand() % 256);
          glVertex2i(rand() % g_width, rand() % g_height);
          glColor3ub(rand() % 256, rand() % 256, 255);
          glVertex2i(rand() % g_width, rand() % g_height);
        }
      glEnd();

    } break;
  case PT_TRIANGLE_STRIP:
    {
      // draw a single triangle strip
      glBegin(GL_TRIANGLE_STRIP);
        glColor3ub(255, 0, 0);
        glVertex2i(10, 10);
        glColor3ub(0, 255, 0);
        glVertex2i(100, 50);
        glColor3ub(0, 0, 255);
        glVertex2i(75, 120);
        glColor3ub(255, 0, 0);
        glVertex2i(150, 110);
        glColor3ub(0, 255, 0);
        glVertex2i(200, 180);
        glColor3ub(0, 0, 255);
        glVertex2i(400, 300);
        glColor3ub(255, 0, 0);
        glVertex2i(350, 400);
        glColor3ub(0, 255, 0);
        glVertex2i(470, 275);
        glColor3ub(0, 0, 255);
        glVertex2i(600, 480);
      glEnd();
    } break;
  case PT_TRIANGLE_FAN:
    {
      // draw a single triangle fan. Notice that this one is closed
      // (the last vertex is the same as the second) but it doesn't
      // have to be
      glBegin(GL_TRIANGLE_FAN);
        glColor3ub(255, 255, 255);
        glVertex2i(400, 300);
        glColor3ub(255, 0, 0);
        glVertex2i(320, 310);
        glColor3ub(0, 255, 0);
        glVertex2i(300, 250);
        glColor3ub(0, 0, 255);
        glVertex2i(330, 220);
        glColor3ub(255, 0, 0);
        glVertex2i(340, 190);
        glColor3ub(0, 255, 0);
        glVertex2i(390, 180);
        glColor3ub(0, 0, 255);
        glVertex2i(430, 200);
        glColor3ub(255, 0, 0);
        glVertex2i(475, 285);
        glColor3ub(0, 255, 0);
        glVertex2i(510, 330);
        glColor3ub(0, 0, 255);
        glVertex2i(460, 380);
        glColor3ub(255, 0, 0);
        glVertex2i(405, 415);
        glColor3ub(0, 255, 0);
        glVertex2i(375, 375);
        glColor3ub(0, 0, 255);
        glVertex2i(350, 365);
        glColor3ub(255, 0, 0);
        glVertex2i(320, 310);
      glEnd();
    } break;
  case PT_QUAD:
    {
      // draw 3 quads. I'm not doing these randomly because it'd be
      // difficult to ensure that the polygons are convex and that
      // edges don't cross
      glBegin(GL_QUADS);
        glColor3ub(rand() % 256, rand() % 256, rand() % 256);
        glVertex2i(60, 60);
        glColor3ub(rand() % 256, rand() % 256, rand() % 256);
        glVertex2i(200, 80);
        glColor3ub(rand() % 256, rand() % 256, rand() % 256);
        glVertex2i(210, 190);
        glColor3ub(rand() % 256, rand() % 256, rand() % 256);
        glVertex2i(70, 200);
        glColor3ub(rand() % 256, rand() % 256, rand() % 256);
        glVertex2i(500, 420);
        glColor3ub(rand() % 256, rand() % 256, rand() % 256);
        glVertex2i(630, 450);
        glColor3ub(rand() % 256, rand() % 256, rand() % 256);
        glVertex2i(635, 460);
        glColor3ub(rand() % 256, rand() % 256, rand() % 256);
        glVertex2i(495, 500);
        glColor3ub(rand() % 256, rand() % 256, rand() % 256);
        glVertex2i(190, 180);
        glColor3ub(rand() % 256, rand() % 256, rand() % 256);
        glVertex2i(500, 190);
        glColor3ub(rand() % 256, rand() % 256, rand() % 256);
        glVertex2i(400, 350);
        glColor3ub(rand() % 256, rand() % 256, rand() % 256);
        glVertex2i(300, 300);
      glEnd();
    } break;
  case PT_POLYGON:
    {
      // draw a single polygon. I'm not doing this randomly for
      // the same reason quads aren't done randomly.
      glBegin(GL_POLYGON);
        glColor3ub(rand() % 256, rand() % 256, rand() % 256);
        glVertex2i(390, 420);
        glColor3ub(rand() % 256, rand() % 256, rand() % 256);
        glVertex2i(300, 400);
        glColor3ub(rand() % 256, rand() % 256, rand() % 256);
        glVertex2i(240, 300);
        glColor3ub(rand() % 256, rand() % 256, rand() % 256);
        glVertex2i(250, 250);
        glColor3ub(rand() % 256, rand() % 256, rand() % 256);
        glVertex2i(370, 200);
        glColor3ub(rand() % 256, rand() % 256, rand() % 256);
        glVertex2i(480, 220);
        glColor3ub(rand() % 256, rand() % 256, rand() % 256);
        glVertex2i(500, 290);
        glColor3ub(rand() % 256, rand() % 256, rand() % 256);
        glVertex2i(520, 400);
      glEnd();
    } break;
  }

  return TRUE;
} // end DisplayScene()


/****************************************************************************
 KillWindow()

 Restore the original display and dispose of the window, device context, and
 rendering context properly.
*****************************************************************************/
BOOL KillWindow()
{
  // restore the original display if we're in fullscreen mode
  if (g_isFullscreen)
  {
    ChangeDisplaySettings(NULL, 0);
    ShowCursor(TRUE);
  }

  // if we have an RC, release it
  if (g_hrc)
  {
    // release the RC
    if (!wglMakeCurrent(NULL,NULL))
    {
      MessageBox(NULL, "Unable to release rendering context", "Error", MB_OK | MB_ICONINFORMATION);
    }

    // delete the RC
    if (!wglDeleteContext(g_hrc))
    {
      MessageBox(NULL, "Unable to delete rendering context", "Error", MB_OK | MB_ICONINFORMATION);
    }

    g_hrc = NULL;
  }

  // release the DC if we have one
  if (g_hdc && !ReleaseDC(g_hwnd, g_hdc))
  {
    MessageBox(NULL, "Unable to release device context", "Error", MB_OK | MB_ICONINFORMATION);
    g_hdc = NULL;
  }

  // destroy the window if we have a valid handle
  if (g_hwnd && !DestroyWindow(g_hwnd))
  {
    MessageBox(NULL, "Unable to destroy window", "Error", MB_OK | MB_ICONINFORMATION);
    g_hwnd = NULL;
  }

  // unregister our class so we can create a new one if we need to
  if (!UnregisterClass(WND_CLASS_NAME, g_hInstance))
  {
    MessageBox(NULL, "Unable to unregister window class", "Error", MB_OK | MB_ICONINFORMATION);
    g_hInstance = NULL;
  }

  return TRUE;
} // end KillWindow()


⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?