首页 > 代码库 > 第二章:创建框架和窗体

第二章:创建框架和窗体

没有翻译第一章是由于第一章仅仅介绍了怎样设置IDE。这方面网上文章非常多,我就没有翻译,直接从第二章開始。

以下是原文链接。翻译有不正确的地方请朋友们指正。

http://www.rastertek.com/gl40tut02.html

Tutorial 2: Creating a Framework and Window
第二章:创建框架和窗体

This OpenGL 4.0 tutorial will cover setting up a basic frame work and window.
这一章涵盖了创建基本框架和窗体的内容。

The Framework
框架

The frame work will begin with five items. It will have a WinMain function to handle the entry point of the application. It will also have a system class that encapsulates the entire application that will be called from within the WinMain function. Inside the system class we will have an opengl class for opengl system calls, a input class for handling user input, and a graphics class for handling the OpenGL graphics code. Here is a diagram of the framework setup:
本章的框架包括了5个部分。

当中有一个WinMain方法用来作为程序的入口。还有system类,封装了所有程序,并在WinMain方法中调用。在system类中包括了用来处理opengl系统的opengl类,处理用户输入的input类和处理OpenGL图形的graphics类。以下是这个框架的结构图:

技术分享

Now that we see how the framework will be setup lets start by looking at the WinMain function inside the main.cpp file.
以下将介绍框架是怎样建立的,首先从main.cpp中的WinMain方法開始。


WinMain
////////////////////////////////////////////////////////////////////////////////
// Filename: main.cpp
////////////////////////////////////////////////////////////////////////////////
#include "systemclass.h"


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR pScmdline, int iCmdshow)
{
 SystemClass* System;
 bool result; 
 
 // Create the system object.
 // 创建system对象
 System = new SystemClass;
 if(!System)
 {
  return 0;
 }

 // Initialize and run the system object.
 // 初始化并执行system对象
 result = System->Initialize();
 if(result)
 {
  System->Run();
 }

 // Shutdown and release the system object.
 // 关闭并释放system对象
 System->Shutdown();
 delete System;
 System = 0;

 return 0;
}

As you can see we kept the WinMain function fairly simple. We create the system class and then initialize it. If it initializes with no problems then we call the system class Run function. The Run function will run its own loop and do all the application code until it completes. After the Run function finishes we then shut down the system object and do the clean up of the system object. So we have kept it very simple and encapsulated the entire application inside the system class. Now lets take a look at the system class header file.
WinMain方法很easy。

我们创建了system类的对象然后对它进行初始化。假设没有出错就调用system对象的Run方法。Run方法将循环执行所有程序代码。

Run方法执行结束后我们将关闭并清理system对象。我们将所有的程序逻辑都放在system类中。这样就保证了WinMain方法很简洁。

以下是system类的头文件。


Systemclass.h
////////////////////////////////////////////////////////////////////////////////
// Filename: systemclass.h
////////////////////////////////////////////////////////////////////////////////
#ifndef _SYSTEMCLASS_H_
#define _SYSTEMCLASS_H_

Here we define WIN32_LEAN_AND_MEAN. We do this to speed up the build process, it reduces the size of the Win32 header files by excluding some of the less used APIs.
我们定义了宏WIN32_LEAN_AND_MEAN。这样能够加快编译速度。它通过排除一些不经常使用的API减小了Win32头文件的大小。
///////////////////////////////
// PRE-PROCESSING DIRECTIVES //
///////////////////////////////
#define WIN32_LEAN_AND_MEAN

Windows.h is included so that we can call the functions to create/destroy windows and be able to use the other useful win32 functions.
通过包括Windows.h文件我们能够创建和销毁窗体而且能够使用其它的win32方法。
///////////////////////
// MY CLASS INCLUDES //
///////////////////////
#include "openglclass.h"
#include "inputclass.h"
#include "graphicsclass.h"

The definition of the class is fairly simple. We see the Initialize, Shutdown, and Run function that was called in WinMain defined here. There are also some private functions that will be called inside those functions. We have also put a MessageHandler function in the class to handle the windows system messages that will get sent to the application while it is running. And finally we have some private variables m_OpenGL, m_Input, and m_Graphics which will be pointers to the three objects that will handle opengl, input, and graphics.
类的定义非常easy。

我们在WinMain方法里调用的Initialize、Shutdown和Run方法都在这里定义。同一时候这里也定义了将被用到的私有方法。同一时候,我们将处理系统窗体消息的MessageHandler方法也放在这个类里。最后。另一些私有变量m_OpenGL、m_Input和m_Graphics分别指向opengl、输入和图像的3个对象。

////////////////////////////////////////////////////////////////////////////////
// Class name: SystemClass
////////////////////////////////////////////////////////////////////////////////
class SystemClass
{
public:
 SystemClass();
 SystemClass(const SystemClass&);
 ~SystemClass();

 bool Initialize();
 void Shutdown();
 void Run();

 LRESULT CALLBACK MessageHandler(HWND, UINT, WPARAM, LPARAM);

private:
 bool Frame();
 bool InitializeWindows(OpenGLClass*, int&, int&);
 void ShutdownWindows();

private:
 LPCWSTR m_applicationName;
 HINSTANCE m_hinstance;
 HWND m_hwnd;

 OpenGLClass* m_OpenGL;
 InputClass* m_Input;
 GraphicsClass* m_Graphics;
};

/////////////////////////
// FUNCTION PROTOTYPES //
/////////////////////////
static LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

/////////////
// GLOBALS //
/////////////
static SystemClass* ApplicationHandle = 0;

#endif

The WndProc function and ApplicationHandle pointer are also included in this class file so we can re-direct the windows system messaging into our MessageHandler function inside the system class.
这个类中还包括了WndProc方法和ApplicationHandle指针。这样,我们就能够将windows系统消息转发到system类中的MessageHandler方法。

Now lets take a look at the system class source file:
以下是system类的代码:

Systemclass.cpp
////////////////////////////////////////////////////////////////////////////////
// Filename: systemclass.cpp
////////////////////////////////////////////////////////////////////////////////
#include "systemclass.h"

Here I create an empty copy constructor and empty class destructor. In this class I don‘t have need of them but if not defined some compilers will generate them for you, and in which case I‘d rather they be empty.
这里创建了一个空的复制构造函数和一个空的构造函数。

本来这个类不须要这些函数。可是某些编译器会自己主动帮你生成他们。所以我宁愿放两个空函数在这。


You will also notice I don‘t do any object clean up in the class destructor. I instead do all my object clean up in the Shutdown function you will see further down. The reason being is that I don‘t trust it to be called. Certain windows functions like ExitThread() are known for not calling your class destructors resulting in memory leaks. You can of course call safer versions of these functions now but I‘m just being careful when programming on windows.
你会发现我在析构函数里什么清理工作都没有做。我使用Shutdown方法来清理对象。

这样做的原因是我并不信任析构函数。

某些windows函数,比方ExitThread(),周所周知在类的析构时没有调用而引发了内存泄漏。你也能够调用这些方法的安全版本号。可是我会在windows编程上多加小心。

SystemClass::SystemClass(const SystemClass& other)
{
}

SystemClass::~SystemClass()
{
}

The following Initialize function does all the setup for the application. It first calls InitializeWindows which will create the window for our application to use and will initialize OpenGL. This function also creates and initializes both the input and graphics objects that the application will use for handling user input and rendering graphics to the screen.
以下的Initialize方法对程序进行了初始化。首先,它调用InitializeWindows为我们的程序创建用来初始化OpenGL的窗体。

这种方法同一时候创建和初始化了程序用来处理用户输入和渲染的输入和图形对象。

bool SystemClass::Initialize()
{
 int screenWidth, screenHeight;
 bool result;

 // Initialize the width and height of the screen to zero.
 screenWidth = 0;
 screenHeight = 0;

 // Create the OpenGL object.
 m_OpenGL = new OpenGLClass;
 if(!m_OpenGL)
 {
  return false;
 }

 // Create the window the application will be using and also initialize OpenGL.
 // 创建程序用的窗体并初始化OpenGL
 result = InitializeWindows(m_OpenGL, screenWidth, screenHeight);
 if(!result)
 {
  MessageBox(m_hwnd, L"Could not initialize the window.", L"Error", MB_OK);
  return false;
 }
 
 // Create the input object.  This object will be used to handle reading the input from the user.
 m_Input = new InputClass;
 if(!m_Input)
 {
  return false;
 }

 // Initialize the input object.
 m_Input->Initialize();

 // Create the graphics object.  This object will handle rendering all the graphics for this application.
 m_Graphics = new GraphicsClass;
 if(!m_Graphics)
 {
  return false;
 }

 // Initialize the graphics object.
 result = m_Graphics->Initialize(m_OpenGL, m_hwnd);
 if(!result)
 {
  return false;
 }

 return true;
}

The Shutdown function does the clean up. It shuts down and releases everything associated with the opengl, graphics, and input objects. As well it also shuts down the window and cleans up the handles associated with it.
Shutdown方法用来清理对象。它负责关闭和释放全部和opengl、输入、图形有关联的对象。

同一时候它也负责关闭窗体并清理和窗体相关联的句柄。

void SystemClass::Shutdown()
{
 // Release the graphics object.
 if(m_Graphics)
 {
  m_Graphics->Shutdown();
  delete m_Graphics;
  m_Graphics = 0;
 }

 // Release the input object.
 if(m_Input)
 {
  delete m_Input;
  m_Input = 0;
 }

 // Release the OpenGL object.
 if(m_OpenGL)
 {
  delete m_OpenGL;
  m_OpenGL = 0;
 }

 // Shutdown the window.
 ShutdownWindows();
 
 return;
}

The Run function is where our application will loop and do all the application processing until we decide to quit. The application processing is done in the Frame function which is called each loop. This is an important concept to understand as now the rest of our application must be written with this in mind. The pseudo code looks like the following:
Run方法将循环执行程序直到我们选择退出。每次循环都将调用Frame方法。这里是程序的核心概念。以下是这部分的伪代码:

while not done
    check for windows system messages
    process system messages
    process application loop
    check if user wanted to quit during the frame processing
void SystemClass::Run()
{
 MSG msg;
 bool done, result;

 // Initialize the message structure.
 ZeroMemory(&msg, sizeof(MSG));
 
 // Loop until there is a quit message from the window or the user.
 done = false;
 while(!done)
 {
  // Handle the windows messages.
  if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  {
   TranslateMessage(&msg);
   DispatchMessage(&msg);
  }

  // If windows signals to end the application then exit out.
  if(msg.message == WM_QUIT)
  {
   done = true;
  }
  else
  {
   // Otherwise do the frame processing.
   result = Frame();
   if(!result)
   {
    done = true;
   }
  }

 }

 return;
}

The following Frame function is where all the processing for our application is done. So far it is fairly simple, we check the input object to see if the user has pressed escape and wants to quit. If they don‘t want to quit then we call the graphics object to do its frame processing which will render the graphics for that frame. As the application grows we‘ll place more code inside here.
以下的Frame方法就是我们程序的所有。眼下它还非常easy,我们检查输入对象是否按下了ESC键来退出。

然后我们调用图形对象来渲染一帧。

后面我们还会在此加入很多其它的代码

bool SystemClass::Frame()
{
 bool result;

 // Check if the user pressed escape and wants to exit the application.
 if(m_Input->IsKeyDown(VK_ESCAPE))
 {
  return false;
 }

 // Do the frame processing for the graphics object.
 result = m_Graphics->Frame();
 if(!result)
 {
  return false;
 }

 return true;
}

The MessageHandler function is where we direct the windows system messages into. This way we can listen for certain information that we are interested in. Currently we will just read if a key is pressed or if a key is released and pass that information on to the input object. All other information we will pass back to the windows default message handler.
我们将windows系统消息传入MessageHandler方法。这样我们就能够监听我们关心的事件。眼下我们仅仅读取按键按下和抬起的事件并将消息传递给输入对象。其它的windows都会被过滤掉。
LRESULT CALLBACK SystemClass::MessageHandler(HWND hwnd, UINT umsg, WPARAM wparam, LPARAM lparam)
{
 switch(umsg)
 {
  // Check if a key has been pressed on the keyboard.
  case WM_KEYDOWN:
  {
   // If a key is pressed send it to the input object so it can record that state.
   m_Input->KeyDown((unsigned int)wparam);
   return 0;
  }

  // Check if a key has been released on the keyboard.
  case WM_KEYUP:
  {
   // If a key is released then send it to the input object so it can unset the state for that key.
   m_Input->KeyUp((unsigned int)wparam);
   return 0;
  }

  // Any other messages send to the default message handler as our application won‘t make use of them.
  default:
  {
   return DefWindowProc(hwnd, umsg, wparam, lparam);
  }
 }
}

The InitializeWindows function is where we put the code to build the window we will use to render to. It returns screenWidth and screenHeight back to the calling function so we can make use of them throughout the application. We create the window using some default settings to initialize a plain black window with no borders. The function will make either a small window or make a full screen window depending on a global variable called FULL_SCREEN. If this is set to true then we make the screen cover the entire users desktop window. If it is set to false we just make a 800x600 window in the middle of the screen. I placed the FULL_SCREEN global variable at the top of the graphicsclass.h file in case you want to modify it. It will make sense later why I placed the global in that file instead of the header for this file.
InitializeWindows方法的作用是用来构造渲染用的窗体。

通过调用该方法,返回能够在程序全局使用的screenWidth和screenHeight。我们使用默认的设置创建了一个简单的没有边框的窗体。

这种方法能够通过FULL_SCREEN变量来决定程序是窗体模式还是全屏。

假设它的值为true将创建全屏窗体。假设为false将在桌面中部创建一个800x600的窗体。FULL_SCREEN变量是在graphicsclass.h文件头部的一个能够随时设置值的全局变量。(后面的不懂)


Now this function is also where we initialize OpenGL. The reason for this is because it is completely tied into the creation of the window. The process is that first we create a temporary window so we can talk to OpenGL. Next we get the extensions for opengl and then release the temporary window. With the opengl extensions we can now create the proper window needed for rendering with the latest version of OpenGL. However note that we won‘t cover OpenGL initialization in this tutorial, just the basic windows initialization. Setting up OpenGL will be the entire topic of the next tutorial.
由于OpenGL和创建窗体关系紧密,所以这种方法也初始化了OpenGL。这段程序首先创建了一个能够和opengl交互的暂时窗体。其次,我们获取opengl的扩展然后释放暂时窗体。通过opengl扩展。我们创建用来渲染硬件支持的最新版本号的OpenGL窗体。可是。本章并没有初始化OpenGL的内容。仅仅包括了基本窗体的初始化。设置OpenGL将在下一章介绍。
bool SystemClass::InitializeWindows(OpenGLClass* OpenGL, int& screenWidth, int& screenHeight)
{
 WNDCLASSEX wc;
 DEVMODE dmScreenSettings;
 int posX, posY;

 // Get an external pointer to this object.
 ApplicationHandle = this;

 // Get the instance of this application.
 m_hinstance = GetModuleHandle(NULL);

 // Give the application a name.
 m_applicationName = L"Engine";

 // Setup the windows class with default settings.
 wc.style         = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
 wc.lpfnWndProc   = WndProc;
 wc.cbClsExtra    = 0;
 wc.cbWndExtra    = 0;
 wc.hInstance     = m_hinstance;
 wc.hIcon         = LoadIcon(NULL, IDI_WINLOGO);
 wc.hIconSm       = wc.hIcon;
 wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
 wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
 wc.lpszMenuName  = NULL;
 wc.lpszClassName = m_applicationName;
 wc.cbSize        = sizeof(WNDCLASSEX);
 
 // Register the window class.
 RegisterClassEx(&wc);

As stated earlier this is where we create a temporary window for opengl to get extensions. We won‘t setup OpenGL in this tutorial however, that will be done in the next tutorial. This tutorial is just focused on creating a frame work and getting a basic window on the screen.
我们先创建一个暂时的窗体用来获取opengl扩展。本章我们不会设置OpenGL。这些将会放在下章介绍。本章的焦点是创建框架和屏幕上的基本窗体。
 // Create a temporary window for the OpenGL extension setup.
 m_hwnd = CreateWindowEx(WS_EX_APPWINDOW, m_applicationName, m_applicationName, WS_POPUP,
    0, 0, 640, 480, NULL, NULL, m_hinstance, NULL);
 if(m_hwnd == NULL)
 {
  return false;
 }

 // Don‘t show the window.
 ShowWindow(m_hwnd, SW_HIDE);

 // Release the temporary window now that the extensions have been initialized.
 DestroyWindow(m_hwnd);
 m_hwnd = NULL;

This is where we proceed with the regular window creation.

// Determine the resolution of the clients desktop screen.
 screenWidth  = GetSystemMetrics(SM_CXSCREEN);
 screenHeight = GetSystemMetrics(SM_CYSCREEN);

 // Setup the screen settings depending on whether it is running in full screen or in windowed mode.
 if(FULL_SCREEN)
 {
  // If full screen set the screen to maximum size of the users desktop and 32bit.
  memset(&dmScreenSettings, 0, sizeof(dmScreenSettings));
  dmScreenSettings.dmSize       = sizeof(dmScreenSettings);
  dmScreenSettings.dmPelsWidth  = (unsigned long)screenWidth;
  dmScreenSettings.dmPelsHeight = (unsigned long)screenHeight;
  dmScreenSettings.dmBitsPerPel = 32;
  dmScreenSettings.dmFields     = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;

  // Change the display settings to full screen.
  ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN);

  // Set the position of the window to the top left corner.
  posX = posY = 0;
 }
 else
 {
  // If windowed then set it to 800x600 resolution.
  screenWidth  = 800;
  screenHeight = 600;

  // Place the window in the middle of the screen.
  posX = (GetSystemMetrics(SM_CXSCREEN) - screenWidth)  / 2;
  posY = (GetSystemMetrics(SM_CYSCREEN) - screenHeight) / 2;
 }

 // Create the window with the screen settings and get the handle to it.
 m_hwnd = CreateWindowEx(WS_EX_APPWINDOW, m_applicationName, m_applicationName, WS_POPUP,
    posX, posY, screenWidth, screenHeight, NULL, NULL, m_hinstance, NULL);
 if(m_hwnd == NULL)
 {
  return false;
 }

 // Bring the window up on the screen and set it as main focus.
 ShowWindow(m_hwnd, SW_SHOW);
 SetForegroundWindow(m_hwnd);
 SetFocus(m_hwnd);

 // Hide the mouse cursor.
 ShowCursor(false);

 return true;
}

ShutdownWindows does just that. It returns the screen settings back to normal and releases the window and the handles associated with it.
ShutdownWindows方法将屏幕设置回初始状态。并释放全部与窗体相关的句柄。

void SystemClass::ShutdownWindows()
{
 // Show the mouse cursor.
 ShowCursor(true);

 // Fix the display settings if leaving full screen mode.
 if(FULL_SCREEN)
 {
  ChangeDisplaySettings(NULL, 0);
 }

 // Remove the window.
 DestroyWindow(m_hwnd);
 m_hwnd = NULL;

 // Remove the application instance.
 UnregisterClass(m_applicationName, m_hinstance);
 m_hinstance = NULL;

 // Release the pointer to this class.
 ApplicationHandle = NULL;

 return;
}

The WndProc function is where windows sends its messages to. You‘ll notice we tell windows the name of it when we initialize the window class with wc.lpfnWndProc = WndProc in the InitializeWindows function above. I included it in this class file since we tie it directly into the system class by having it send all the messages to the MessageHandler function defined inside SystemClass. This allows us to hook the messaging functionality straight into our class and keep the code clean.
WndProc方法接收窗体发送的消息。在InitializeWindows方法中,我们通过wc.lpfnWndProc = WndProc语句来设置窗体消息回调函数。通过SystemClass的MessageHandler方法将消息转发到system类。这样处理消息能够保持代码简洁。
LRESULT CALLBACK WndProc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
{
 switch(umessage)
 {
  // Check if the window is being closed.
  case WM_CLOSE:
  {
   PostQuitMessage(0);
   return 0;
  }

  // All other messages pass to the message handler in the system class.
  default:
  {
   return ApplicationHandle->MessageHandler(hwnd, umessage, wparam, lparam);
  }
 }
}

Inputclass.h

To keep the tutorials simple I used the windows input for the time being until I do a tutorial on DirectInput (which is far superior). The input class handles the user input from the keyboard. This class is given input from the SystemClass::MessageHandler function. The input object will store the state of each key in a keyboard array. When queried it will tell the calling functions if a certain key is pressed. Here is the header:
在介绍DirectInput(更高级的输入)之前。临时使用windows输入来保持代码简洁。input类处理用户键盘输入。此类通过SystemClass::MessageHandler方法获取输入。

input对象用键盘数组保存每个输入值的状态。

我们能够通过查询来推断某个键是否被按下。以下是头文件:

////////////////////////////////////////////////////////////////////////////////
// Filename: inputclass.h
////////////////////////////////////////////////////////////////////////////////
#ifndef _INPUTCLASS_H_
#define _INPUTCLASS_H_

////////////////////////////////////////////////////////////////////////////////
// Class name: InputClass
////////////////////////////////////////////////////////////////////////////////
class InputClass
{
public:
 InputClass();
 InputClass(const InputClass&);
 ~InputClass();

 void Initialize();

 void KeyDown(unsigned int);
 void KeyUp(unsigned int);

 bool IsKeyDown(unsigned int);

private:
 bool m_keys[256];
};

#endif

Inputclass.cpp

////////////////////////////////////////////////////////////////////////////////
// Filename: inputclass.cpp
////////////////////////////////////////////////////////////////////////////////
#include "inputclass.h"

InputClass::InputClass()
{
}

InputClass::InputClass(const InputClass& other)
{
}

InputClass::~InputClass()
{
}

void InputClass::Initialize()
{
 int i; 

 // Initialize all the keys to being released and not pressed.
 for(i=0; i<256; i++)
 {
  m_keys[i] = false;
 }

 return;
}

void InputClass::KeyDown(unsigned int input)
{
 // If a key is pressed then save that state in the key array.
 m_keys[input] = true;
 return;
}

void InputClass::KeyUp(unsigned int input)
{
 // If a key is released then clear that state in the key array.
 m_keys[input] = false;
 return;
}

bool InputClass::IsKeyDown(unsigned int key)
{
 // Return what state the key is in (pressed/not pressed).
 return m_keys[key];
}

Graphicsclass.h

The graphics class is another object that is created by the system class. All the graphics functionality in this application will be encapsulated in this class. I will also use the header in this file for all the graphics related global settings that we may want to change such as full screen or windowed mode. Currently this class will be empty but in future tutorials will contain all the graphics objects.
system类会创建graphics类的对象。

所有的图形方法都被封装在这个类中。用来设置全屏和窗体模式的全局变量放在了文件头部。眼下类的方法留空。以后的教程会进行填充。

////////////////////////////////////////////////////////////////////////////////
// Filename: graphicsclass.h
////////////////////////////////////////////////////////////////////////////////
#ifndef _GRAPHICSCLASS_H_
#define _GRAPHICSCLASS_H_

///////////////////////
// MY CLASS INCLUDES //
///////////////////////
#include "openglclass.h"

We‘ll need these four globals to start with.
这里须要4个全局变量。

/////////////
// GLOBALS //
/////////////
const bool FULL_SCREEN = false;
const bool VSYNC_ENABLED = true;
const float SCREEN_DEPTH = 1000.0f;
const float SCREEN_NEAR = 0.1f;

////////////////////////////////////////////////////////////////////////////////
// Class name: GraphicsClass
////////////////////////////////////////////////////////////////////////////////
class GraphicsClass
{
public:
 GraphicsClass();
 GraphicsClass(const GraphicsClass&);
 ~GraphicsClass();

 bool Initialize(OpenGLClass*, HWND);
 void Shutdown();
 bool Frame();

private:
 bool Render();

private:

};

#endif

Graphicsclass.cpp

I have kept this class entirely empty for now as we are just building the framework for this tutorial.
这里保持类的方法为空。

本章仅仅是为了构造框架。

////////////////////////////////////////////////////////////////////////////////
// Filename: graphicsclass.cpp
////////////////////////////////////////////////////////////////////////////////
#include "graphicsclass.h"

GraphicsClass::GraphicsClass()
{
}

GraphicsClass::GraphicsClass(const GraphicsClass& other)
{
}

GraphicsClass::~GraphicsClass()
{
}

bool GraphicsClass::Initialize(OpenGLClass* OpenGL, HWND hwnd)
{
 return true;
}

void GraphicsClass::Shutdown()
{
 return;
}

bool GraphicsClass::Frame()
{
 return true;
}

bool GraphicsClass::Render()
{
 return true;
}

Openglclass.h

Just like the GraphicsClass we have created an empty OpenGLClass that will be used for future tutorials but is required for the basic frame work.
类似于GraphicsClass我们创建一个空的OpenGLClass。
////////////////////////////////////////////////////////////////////////////////
// Filename: openglclass.h
////////////////////////////////////////////////////////////////////////////////
#ifndef _OPENGLCLASS_H_
#define _OPENGLCLASS_H_

//////////////
// INCLUDES //
//////////////
#include <windows.h>

////////////////////////////////////////////////////////////////////////////////
// Class name: OpenGLClass
////////////////////////////////////////////////////////////////////////////////
class OpenGLClass
{
public:
 OpenGLClass();
 OpenGLClass(const OpenGLClass&);
 ~OpenGLClass();

private:

};

#endif

Openglclass.h

////////////////////////////////////////////////////////////////////////////////
// Filename: openglclass.cpp
////////////////////////////////////////////////////////////////////////////////
#include "openglclass.h"

OpenGLClass::OpenGLClass()
{
}

OpenGLClass::OpenGLClass(const OpenGLClass& other)
{
}

OpenGLClass::~OpenGLClass()
{
}

Summary
总结

So now we have a framework and a window that will pop up on the screen. This frame work will now be the base for all future tutorials so understanding this frame work is fairly important. Please try the To Do exercise to make sure the code compiles and is working for you before moving on to the next tutorial. If you don‘t understand this frame work you should still be fine to move onto the other tutorials and they may make more sense to you later once the frame work is filled out more.
如今我们创建好了框架和一个窗体。以后的教程都会用到这个框架。所以一定要理解框架是怎样工作的。在继续下一章之前请试一试后面的练习来确保代码能够编译并能正常执行。假设你不理解这个框架。你仍然能够去看其它的教程。也许它们能够给你比这个框架很多其它的东西。

To Do Exercises
练习

1. Change the FULL_SCREEN parameter to true in the graphicsclass.h header then recompile and run the program. Press the escape key to quit after the window displays.
1. 改动graphicsclass.h文件里FULL_SCREEN变量为true。然后又一次编译并执行程序。

窗体显示后。按ESC键退出。



Source Code
源码
http://www.rastertek.com/gl40src02.zip

第二章:创建框架和窗体