本教程将是使用OpenGL 4.0的第一个真正的介绍。我们将解决三个主要问题,分别是初始化OpenGL 4.0,关闭它以及使用它进行基本渲染。本教程使用与上一教程相同的类,不同之处在于,我们将为每个类添加更多代码,以利于使用OpenGL 4.0进行渲染。
我们将通过查看填写好的OpenGLClass来开始本教程:
Openglclass
头文件中,OpenGL 4.0要求您在opengl32.lib库中进行链接。您可以在IDE中或直接在代码中执行此操作。我已将链接放入代码中,因为这是我的偏爱:
#pragma comment(lib,“ opengl32.lib”)
OpenGL 4.0还需要windows.h和gl.h头文件。我还包括了math.h,因为我们将需要编写一些数学函数来协助使用OpenGL进行渲染。
首先开始填充OpenGLClass来开始本教程:
OpenGL 4.0要求您在opengl32.lib库中进行链接。您可以在IDE中或直接在代码中执行此操作。我已将链接放入代码中,因为这是我的偏爱。
/
//链接//
/
#pragma comment(lib,“ opengl32.lib”)
如果找不到这些文件,就查看一下包含路径是否可靠:
我用的vs2019.
//
//包含//
//
#include <windows.h>
#include <gl \ gl.h>
#include <math.h>
在Windows中,gl.h标头仅包含OpenGL 1.0和OpenGL 1.1的定义,函数和函数指针。实际上,所有新的OpenGL功能都以扩展名的形式在您的显卡的显示驱动程序中实现。您可以在OpenGL 4.0文档中找到Khronos Group在其网站上维护的OpenGL 4.0规范中所有扩展的名称。您还可以下载wglext.h和glext.h之类的文件,其中也包含大量文件。对于这些教程,我们只需要所有函数的子集,因此我包括了将在此头文件中使用的定义,类型定义和函数指针。
以下是我们将使用的定义:
/
// DEFINES //
/
#define WGL_DRAW_TO_WINDOW_ARB 0x2001
#define WGL_ACCELERATION_ARB 0x2003
#define WGL_SWAP_METHOD_ARB 0x2007
#define WGL_SUPPORT_OPENGL_ARB 0x2010
#define WGL_DOUBLE_BUFFER_ARB 0x2011
#define WGL_PIXEL_TYPE_ARB 0x2013
#define WGL_COLOR_BITS_ARB 0x2014
#define WGL_DEPTH_BITS_ARB 0x2022
#define WGL_STENCIL_BITS_ARB 0x2023
#define WGL_FULL_ACCELERATION_ARB 0x2027
#define WGL_SWAP_EXCHANGE_ARB 0x2028
#define WGL_TYPE_RGBA_ARB 0x202B
#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
#define GL_ARRAY_BUFFER 0x8892
#define GL_STATIC_DRAW 0x88E4
#define GL_FRAGMENT_SHADER 0x8B30
#define GL_VERTEX_SHADER 0x8B31
#define GL_COMPILE_STATUS 0x8B81
#define GL_LINK_STATUS 0x8B82
#define GL_INFO_LOG_LENGTH 0x8B84
#define GL_TEXTURE0 0x84C0
#define GL_BGRA 0x80E1
#define GL_ELEMENT_ARRAY_BUFFER 0x8893
//
// TYPEDEFS //
//
typedef BOOL(WINAPI* PFNWGLCHOOSEPIXELFORMATARBPROC) (HDC hdc, const int* piAttribIList, const FLOAT* pfAttribFList, UINT nMaxFormats,
int* piFormats, UINT* nNumFormats);
typedef HGLRC(WINAPI* PFNWGLCREATECONTEXTATTRIBSARBPROC) (HDC hDC, HGLRC hShareContext, const int* attribList);
typedef BOOL(WINAPI* PFNWGLSWAPINTERVALEXTPROC) (int interval);
typedef void (APIENTRY* PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader);
typedef void (APIENTRY* PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer);
typedef void (APIENTRY* PFNGLBINDVERTEXARRAYPROC) (GLuint array);
typedef void (APIENTRY* PFNGLBUFFERDATAPROC) (GLenum target, ptrdiff_t size, const GLvoid* data, GLenum usage);
typedef void (APIENTRY* PFNGLCOMPILESHADERPROC) (GLuint shader);
typedef GLuint(APIENTRY* PFNGLCREATEPROGRAMPROC) (void);
typedef GLuint(APIENTRY* PFNGLCREATESHADERPROC) (GLenum type);
typedef void (APIENTRY* PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint* buffers);
typedef void (APIENTRY* PFNGLDELETEPROGRAMPROC) (GLuint program);
typedef void (APIENTRY* PFNGLDELETESHADERPROC) (GLuint shader);
typedef void (APIENTRY* PFNGLDELETEVERTEXARRAYSPROC) (GLsizei n, const GLuint* arrays);
typedef void (APIENTRY* PFNGLDETACHSHADERPROC) (GLuint program, GLuint shader);
typedef void (APIENTRY* PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index);
typedef void (APIENTRY* PFNGLGENBUFFERSPROC) (GLsizei n, GLuint* buffers);
typedef void (APIENTRY* PFNGLGENVERTEXARRAYSPROC) (GLsizei n, GLuint* arrays);
typedef GLint(APIENTRY* PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const char* name);
typedef void (APIENTRY* PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei* length, char* infoLog);
typedef void (APIENTRY* PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint* params);
typedef void (APIENTRY* PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei* length, char* infoLog);
typedef void (APIENTRY* PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint* params);
typedef void (APIENTRY* PFNGLLINKPROGRAMPROC) (GLuint program);
typedef void (APIENTRY* PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const char** string, const GLint* length);
typedef void (APIENTRY* PFNGLUSEPROGRAMPROC) (GLuint program);
typedef void (APIENTRY* PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride,
const GLvoid* pointer);
typedef void (APIENTRY* PFNGLBINDATTRIBLOCATIONPROC) (GLuint program, GLuint index, const char* name);
typedef GLint(APIENTRY* PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const char* name);
typedef void (APIENTRY* PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
typedef void (APIENTRY* PFNGLACTIVETEXTUREPROC) (GLenum texture);
typedef void (APIENTRY* PFNGLUNIFORM1IPROC) (GLint location, GLint v0);
typedef void (APIENTRY* PFNGLGENERATEMIPMAPPROC) (GLenum target);
typedef void (APIENTRY* PFNGLDISABLEVERTEXATTRIBARRAYPROC) (GLuint index);
typedef void (APIENTRY* PFNGLUNIFORM3FVPROC) (GLint location, GLsizei count, const GLfloat* value);
typedef void (APIENTRY* PFNGLUNIFORM4FVPROC) (GLint location, GLsizei count, const GLfloat* value);
OpenGLClass的类定义在此保持尽可能简单。它具有常规构造函数,复制构造函数和析构函数。然后更重要的是它具有InitializeExtensions,InitializeOpenGL和Shutdown函数。这将是我们在本教程中重点关注的内容。除此之外,我还有许多对本教程并不重要的帮助函数,以及许多私有成员变量,当我们检查openglclass.cpp文件时,它们会被查看。目前,我们只需要了解初始化和关闭功能即可。
// Class name: OpenGLClass
class OpenGLClass
{
public:
OpenGLClass();
OpenGLClass(const OpenGLClass&);
~OpenGLClass();
bool InitializeExtensions(HWND);
bool InitializeOpenGL(HWND, int, int, float, float, bool);
void Shutdown(HWND);
void BeginScene(float, float, float, float);
void EndScene();
void GetWorldMatrix(float*);
void GetProjectionMatrix(float*);
void GetVideoCardInfo(char*);
void BuildIdentityMatrix(float*);
void BuildPerspectiveFovLHMatrix(float*, float, float, float, float);
void MatrixRotationY(float*, float);
void MatrixTranslation(float*, float, float, float);
void MatrixMultiply(float*, float*, float*);
private:
bool LoadExtensionList();
private:
HDC m_deviceContext;
HGLRC m_renderingContext;
//以下三个OpenGL函数指针用于与Windows接口:
PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB;
PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB;
PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT;
float m_worldMatrix[16];
float m_projectionMatrix[16];
char m_videoCardDescription[128];
//这些是用于与OpenGL接口的其余函数指针。我已经将它们公开,因此我们可以仅使用指向此类的指针来轻松调用它们。
public:
PFNGLATTACHSHADERPROC glAttachShader;
PFNGLBINDBUFFERPROC glBindBuffer;
PFNGLBINDVERTEXARRAYPROC glBindVertexArray;
PFNGLBUFFERDATAPROC glBufferData;
PFNGLCOMPILESHADERPROC glCompileShader;
PFNGLCREATEPROGRAMPROC glCreateProgram;
PFNGLCREATESHADERPROC glCreateShader;
PFNGLDELETEBUFFERSPROC glDeleteBuffers;
PFNGLDELETEPROGRAMPROC glDeleteProgram;
PFNGLDELETESHADERPROC glDeleteShader;
PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays;
PFNGLDETACHSHADERPROC glDetachShader;
PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray;
PFNGLGENBUFFERSPROC glGenBuffers;
PFNGLGENVERTEXARRAYSPROC glGenVertexArrays;
PFNGLGETATTRIBLOCATIONPROC glGetAttribLocation;
PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog;
PFNGLGETPROGRAMIVPROC glGetProgramiv;
PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog;
PFNGLGETSHADERIVPROC glGetShaderiv;
PFNGLLINKPROGRAMPROC glLinkProgram;
PFNGLSHADERSOURCEPROC glShaderSource;
PFNGLUSEPROGRAMPROC glUseProgram;
PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer;
PFNGLBINDATTRIBLOCATIONPROC glBindAttribLocation;
PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation;
PFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv;
PFNGLACTIVETEXTUREPROC glActiveTexture;
PFNGLUNIFORM1IPROC glUniform1i;
PFNGLGENERATEMIPMAPPROC glGenerateMipmap;
PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray;
PFNGLUNIFORM3FVPROC glUniform3fv;
PFNGLUNIFORM4FVPROC glUniform4fv;
};
#endif
Openglclass.cpp
我们首先将两个成员句柄初始化为null。
OpenGLClass :: OpenGLClass()
{
m_deviceContext = 0;
m_renderingContext = 0;
}
InitializeExtensions函数使我们能够获取视频卡驱动程序中可用的所有OpenGL函数的指针。请注意,除非已经创建了一个窗口,否则无法调用此函数,因此SystemClass :: InitializeWindows函数中创建临时窗口,调用此函数以获取扩展,然后销毁该临时窗口并创建一个新窗口的原因。
在此函数中,我们将设置临时设备上下文,像素格式和渲染上下文,以便我们可以调用LoadExtensionList函数,该函数然后为我们获取所需的所有函数指针。完成后,我们将释放临时上下文。
//获取显卡驱动程序中可用的所有的OpenGL函数的指针。前提是已经创建了一个窗口
//一般在InitializeWindows函数中创建临时窗口,调用此函数以获取扩展,然后销毁临时窗口并创建一个新窗口
//InitializeExtensions函数:设置临时设备上下文,像素格式和渲染上下文,
bool OpenGLClass::InitializeExtensions(HWND hwnd)
{
HDC deviceContext;
PIXELFORMATDESCRIPTOR pixelFormat;
int error;
HGLRC renderContext;
bool result;
// 获取此窗口的设备上下文
deviceContext = GetDC(hwnd);
if (!deviceContext)
{
return false;
}
// 设置临时的默认像素格式
error = SetPixelFormat(deviceContext, 1, &pixelFormat);
if (error != 1)
{
return false;
}
// 创建一个临时渲染上下文
renderContext = wglCreateContext(deviceContext);
if (!renderContext)
{
return false;
}
// 将临时渲染上下文设置为此窗口的当前渲染上下文
error = wglMakeCurrent(deviceContext, renderContext);
if (error != 1)
{
return false;
}
// 初始化此应用程序所需的OpenGL扩展。注意,需要一个临时的渲染上下文
result = LoadExtensionList();
if (!result)
{
return false;
}
// 既然已经加载了扩展,就释放临时渲染上下文
wglMakeCurrent(NULL, NULL);
wglDeleteContext(renderContext);
renderContext = NULL;
// 释放该窗口的设备上下文。
ReleaseDC(hwnd, deviceContext);
deviceContext = 0;
return true;
}
InitializeOpenGL设置OpenGL 4.0。在调用此函数之前,必须从InitializeExtensions函数加载扩展。同样,需要创建正确的窗口,这是在SystemClass :: InitializeWindows中完成的。一旦这两件事到位,就可以调用此函数。
然后,此函数将创建OpenGL 4.0渲染上下文和适当的像素格式。设置好之后,此功能将设置一些额外的内容,例如背面剔除,垂直同步,深度缓冲区以及我们将需要渲染的一些矩阵。
bool OpenGLClass::InitializeOpenGL(HWND hwnd, int screenWidth, int screenHeight, float screenDepth, float screenNear, bool vsync)
{
int attributeListInt[19];
int pixelFormat[1];
unsigned int formatCount;
int result;
PIXELFORMATDESCRIPTOR pixelFormatDescriptor;
int attributeList[5];
float fieldOfView, screenAspect;
char* vendorString, * rendererString;
//获取此窗口的设备上下文。
m_deviceContext = GetDC(hwnd);
if (!m_deviceContext)
{
return false;
}
// 支持OpenGL渲染。
attributeListInt[0] = WGL_SUPPORT_OPENGL_ARB;
attributeListInt[1] = TRUE;
// 支持渲染到窗口。
attributeListInt[2] = WGL_DRAW_TO_WINDOW_ARB;
attributeListInt[3] = TRUE;
// 支持硬件加速
attributeListInt[4] = WGL_ACCELERATION_ARB;
attributeListInt[5] = WGL_FULL_ACCELERATION_ARB;
// 支持24位彩色
attributeListInt[6] = WGL_COLOR_BITS_ARB;
attributeListInt[7] = 24;
// /支持24位深度的缓冲区。
attributeListInt[8] = WGL_DEPTH_BITS_ARB;
attributeListInt[9] = 24;
// 支持双缓冲区.
attributeListInt[10] = WGL_DOUBLE_BUFFER_ARB;
attributeListInt[11] = TRUE;
// 支持交换前缓冲区和后缓冲区.
attributeListInt[12] = WGL_SWAP_METHOD_ARB;
attributeListInt[13] = WGL_SWAP_EXCHANGE_ARB;
// 支持RGBA像素类型.
attributeListInt[14] = WGL_PIXEL_TYPE_ARB;
attributeListInt[15] = WGL_TYPE_RGBA_ARB;
// 支持8位模板缓冲区.
attributeListInt[16] = WGL_STENCIL_BITS_ARB;
attributeListInt[17] = 8;
// Null终止属性列表.
attributeListInt[18] = 0;
// 查询适合我们所需属性的像素格式.
result = wglChoosePixelFormatARB(m_deviceContext, attributeListInt, NULL, 1, pixelFormat, &formatCount);
if (result != 1)
{
return false;
}
// 如果显卡/显示器可以处理所需的像素格式,则将其设置为当前像素格式。
result = SetPixelFormat(m_deviceContext, pixelFormat[0], &pixelFormatDescriptor);
if (result != 1)
{
return false;
}
// 在属性列表中设置OpenGL的4.0版本.
attributeList[0] = WGL_CONTEXT_MAJOR_VERSION_ARB;
attributeList[1] = 4;
attributeList[2] = WGL_CONTEXT_MINOR_VERSION_ARB;
attributeList[3] = 0;
// Null终止属性列表。.
attributeList[4] = 0;
// 创建OpenGL 4.0渲染上下文.
m_renderingContext = wglCreateContextAttribsARB(m_deviceContext, 0, attributeList);
if (m_renderingContext == NULL)
{
return false;
}
// 将渲染上下文设置为活动状态.
result = wglMakeCurrent(m_deviceContext, m_renderingContext);
if (result != 1)
{
return false;
}
// 将深度缓冲区设置为完全清除为1.0值.
glClearDepth(1.0f);
//启用深度测试.
glEnable(GL_DEPTH_TEST);
// 将多边形绕组设置为左手系统的正面.
glFrontFace(GL_CW);
// 启用背面剔除.
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
// 将世界/模型矩阵初始化为恒等矩阵.
BuildIdentityMatrix(m_worldMatrix);
// 设置视野和屏幕纵横比.
fieldOfView = 3.14159265358979323846f / 4.0f;
screenAspect = (float)screenWidth / (float)screenHeight;
//建立透视投影矩阵.
BuildPerspectiveFovLHMatrix(m_projectionMatrix, fieldOfView, screenAspect, screenNear, screenDepth);
//获取显卡的名称.
vendorString = (char*)glGetString(GL_VENDOR);
rendererString = (char*)glGetString(GL_RENDERER);
//将显卡名称存储在类成员变量中,以便以后检索.
strcpy_s(m_videoCardDescription, vendorString);
strcat_s(m_videoCardDescription, " - ");
strcat_s(m_videoCardDescription, rendererString);
// 根据输入的bool值打开或关闭垂直同步.
if (vsync)
{
result = wglSwapIntervalEXT(1);
}
else
{
result = wglSwapIntervalEXT(0);
}
// /检查vsync设置是否正确.
if (result != 1)
{
return false;
}
return true;
}
关机功能将释放用于OpenGL 4.0渲染的两个上下文句柄。
void OpenGLClass::Shutdown(HWND hwnd)
{
// 释放渲染上下文.
if (m_renderingContext)
{
wglMakeCurrent(NULL, NULL);
wglDeleteContext(m_renderingContext);
m_renderingContext = 0;
}
// 释放设备上下文.
if (m_deviceContext)
{
ReleaseDC(hwnd, m_deviceContext);
m_deviceContext = 0;
}
return;
}
当我们要在每个帧的开头绘制一个新的3D场景时,就会调用BeginScene。初始化缓冲区,使它们为空白并准备好被绘制
void OpenGLClass::BeginScene(float red, float green, float blue, float alpha)
{
//设置颜色以清除屏幕。
glClearColor(red, green, blue, alpha);
// 清除屏幕和深度缓冲区.
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
return;
}
每帧结束时所有绘图都完成后,将后缓冲区交换到前缓冲区,从而显示3D场景
void OpenGLClass::EndScene()
{
// 由于渲染完成,因此将后缓冲区显示在屏幕上
SwapBuffers(m_deviceContext);
return;
}
加载我们将用于与OpenGL 4.0接口的所有扩展,每个函数指针都通过调用wglGetProcAddress函数来获取函数的地址
bool OpenGLClass::LoadExtensionList()
{
//加载此应用程序将使用的OpenGL扩展
wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB");
if (!wglChoosePixelFormatARB)
{
return false;
}
wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB");
if (!wglCreateContextAttribsARB)
{
return false;
}
wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT");
if (!wglSwapIntervalEXT)
{
return false;
}
glAttachShader = (PFNGLATTACHSHADERPROC)wglGetProcAddress("glAttachShader");
if (!glAttachShader)
{
return false;
}
glBindBuffer = (PFNGLBINDBUFFERPROC)wglGetProcAddress("glBindBuffer");
if (!glBindBuffer)
{
return false;
}
glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC)wglGetProcAddress("glBindVertexArray");
if (!glBindVertexArray)
{
return false;
}
glBufferData = (PFNGLBUFFERDATAPROC)wglGetProcAddress("glBufferData");
if (!glBufferData)
{
return false;
}
glCompileShader = (PFNGLCOMPILESHADERPROC)wglGetProcAddress("glCompileShader");
if (!glCompileShader)
{
return false;
}
glCreateProgram = (PFNGLCREATEPROGRAMPROC)wglGetProcAddress("glCreateProgram");
if (!glCreateProgram)
{
return false;
}
glCreateShader = (PFNGLCREATESHADERPROC)wglGetProcAddress("glCreateShader");
if (!glCreateShader)
{
return false;
}
glDeleteBuffers = (PFNGLDELETEBUFFERSPROC)wglGetProcAddress("glDeleteBuffers");
if (!glDeleteBuffers)
{
return false;
}
glDeleteProgram = (PFNGLDELETEPROGRAMPROC)wglGetProcAddress("glDeleteProgram");
if (!glDeleteProgram)
{
return false;
}
glDeleteShader = (PFNGLDELETESHADERPROC)wglGetProcAddress("glDeleteShader");
if (!glDeleteShader)
{
return false;
}
glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC)wglGetProcAddress("glDeleteVertexArrays");
if (!glDeleteVertexArrays)
{
return false;
}
glDetachShader = (PFNGLDETACHSHADERPROC)wglGetProcAddress("glDetachShader");
if (!glDetachShader)
{
return false;
}
glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)wglGetProcAddress("glEnableVertexAttribArray");
if (!glEnableVertexAttribArray)
{
return false;
}
glGenBuffers = (PFNGLGENBUFFERSPROC)wglGetProcAddress("glGenBuffers");
if (!glGenBuffers)
{
return false;
}
glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC)wglGetProcAddress("glGenVertexArrays");
if (!glGenVertexArrays)
{
return false;
}
glGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC)wglGetProcAddress("glGetAttribLocation");
if (!glGetAttribLocation)
{
return false;
}
glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)wglGetProcAddress("glGetProgramInfoLog");
if (!glGetProgramInfoLog)
{
return false;
}
glGetProgramiv = (PFNGLGETPROGRAMIVPROC)wglGetProcAddress("glGetProgramiv");
if (!glGetProgramiv)
{
return false;
}
glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)wglGetProcAddress("glGetShaderInfoLog");
if (!glGetShaderInfoLog)
{
return false;
}
glGetShaderiv = (PFNGLGETSHADERIVPROC)wglGetProcAddress("glGetShaderiv");
if (!glGetShaderiv)
{
return false;
}
glLinkProgram = (PFNGLLINKPROGRAMPROC)wglGetProcAddress("glLinkProgram");
if (!glLinkProgram)
{
return false;
}
glShaderSource = (PFNGLSHADERSOURCEPROC)wglGetProcAddress("glShaderSource");
if (!glShaderSource)
{
return false;
}
glUseProgram = (PFNGLUSEPROGRAMPROC)wglGetProcAddress("glUseProgram");
if (!glUseProgram)
{
return false;
}
glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)wglGetProcAddress("glVertexAttribPointer");
if (!glVertexAttribPointer)
{
return false;
}
glBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC)wglGetProcAddress("glBindAttribLocation");
if (!glBindAttribLocation)
{
return false;
}
glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)wglGetProcAddress("glGetUniformLocation");
if (!glGetUniformLocation)
{
return false;
}
glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC)wglGetProcAddress("glUniformMatrix4fv");
if (!glUniformMatrix4fv)
{
return false;
}
glActiveTexture = (PFNGLACTIVETEXTUREPROC)wglGetProcAddress("glActiveTexture");
if (!glActiveTexture)
{
return false;
}
glUniform1i = (PFNGLUNIFORM1IPROC)wglGetProcAddress("glUniform1i");
if (!glUniform1i)
{
return false;
}
glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC)wglGetProcAddress("glGenerateMipmap");
if (!glGenerateMipmap)
{
return false;
}
glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC)wglGetProcAddress("glDisableVertexAttribArray");
if (!glDisableVertexAttribArray)
{
return false;
}
glUniform3fv = (PFNGLUNIFORM3FVPROC)wglGetProcAddress("glUniform3fv");
if (!glUniform3fv)
{
return false;
}
glUniform4fv = (PFNGLUNIFORM4FVPROC)wglGetProcAddress("glUniform4fv");
if (!glUniform4fv)
{
return false;
}
return true;
}
以下函数仅将此类已构建的矩阵返回给调用函数。这些矩阵对于渲染很重要。
void OpenGLClass::GetWorldMatrix(float* matrix)
{
matrix[0] = m_worldMatrix[0];
matrix[1] = m_worldMatrix[1];
matrix[2] = m_worldMatrix[2];
matrix[3] = m_worldMatrix[3];
matrix[4] = m_worldMatrix[4];
matrix[5] = m_worldMatrix[5];
matrix[6] = m_worldMatrix[6];
matrix[7] = m_worldMatrix[7];
matrix[8] = m_worldMatrix[8];
matrix[9] = m_worldMatrix[9];
matrix[10] = m_worldMatrix[10];
matrix[11] = m_worldMatrix[11];
matrix[12] = m_worldMatrix[12];
matrix[13] = m_worldMatrix[13];
matrix[14] = m_worldMatrix[14];
matrix[15] = m_worldMatrix[15];
return;
}
void OpenGLClass::GetProjectionMatrix(float* matrix)
{
matrix[0] = m_projectionMatrix[0];
matrix[1] = m_projectionMatrix[1];
matrix[2] = m_projectionMatrix[2];
matrix[3] = m_projectionMatrix[3];
matrix[4] = m_projectionMatrix[4];
matrix[5] = m_projectionMatrix[5];
matrix[6] = m_projectionMatrix[6];
matrix[7] = m_projectionMatrix[7];
matrix[8] = m_projectionMatrix[8];
matrix[9] = m_projectionMatrix[9];
matrix[10] = m_projectionMatrix[10];
matrix[11] = m_projectionMatrix[11];
matrix[12] = m_projectionMatrix[12];
matrix[13] = m_projectionMatrix[13];
matrix[14] = m_projectionMatrix[14];
matrix[15] = m_projectionMatrix[15];
return;
}
GetVideoCardInfo函数以字符串形式将显卡的名称和制造商返回给此函数的调用方。
void OpenGLClass::GetVideoCardInfo(char* cardName)
{
strcpy_s(cardName, 128, m_videoCardDescription);
return;
}
该功能建立一个基本的身份矩阵
void OpenGLClass::BuildIdentityMatrix(float* matrix)
{
matrix[0] = 1.0f;
matrix[1] = 0.0f;
matrix[2] = 0.0f;
matrix[3] = 0.0f;
matrix[4] = 0.0f;
matrix[5] = 1.0f;
matrix[6] = 0.0f;
matrix[7] = 0.0f;
matrix[8] = 0.0f;
matrix[9] = 0.0f;
matrix[10] = 1.0f;
matrix[11] = 0.0f;
matrix[12] = 0.0f;
matrix[13] = 0.0f;
matrix[14] = 0.0f;
matrix[15] = 1.0f;
return;
}
此函数将建立一个左手投影矩阵 4*4
void OpenGLClass::BuildPerspectiveFovLHMatrix(float* matrix, float fieldOfView, float screenAspect, float screenNear, float screenDepth)
{
matrix[0] = 1.0f / (screenAspect * tan(fieldOfView * 0.5f));
matrix[1] = 0.0f;
matrix[2] = 0.0f;
matrix[3] = 0.0f;
matrix[4] = 0.0f;
matrix[5] = 1.0f / tan(fieldOfView * 0.5f);
matrix[6] = 0.0f;
matrix[7] = 0.0f;
matrix[8] = 0.0f;
matrix[9] = 0.0f;
matrix[10] = screenDepth / (screenDepth - screenNear);
matrix[11] = 1.0f;
matrix[12] = 0.0f;
matrix[13] = 0.0f;
matrix[14] = (-screenNear * screenDepth) / (screenDepth - screenNear);
matrix[15] = 0.0f;
return;
}
此函数基于Y轴构建旋转矩阵。
void OpenGLClass::MatrixRotationY(float* matrix, float angle)
{
matrix[0] = cosf(angle);
matrix[1] = 0.0f;
matrix[2] = -sinf(angle);
matrix[3] = 0.0f;
matrix[4] = 0.0f;
matrix[5] = 1.0f;
matrix[6] = 0.0f;
matrix[7] = 0.0f;
matrix[8] = sinf(angle);
matrix[9] = 0.0f;
matrix[10] = cosf(angle);
matrix[11] = 0.0f;
matrix[12] = 0.0f;
matrix[13] = 0.0f;
matrix[14] = 0.0f;
matrix[15] = 1.0f;
return;
}
//此函数构建基本的转换矩阵,也是位移矩阵
void OpenGLClass::MatrixTranslation(float* matrix, float x, float y, float z)
{
matrix[0] = 1.0f;
matrix[1] = 0.0f;
matrix[2] = 0.0f;
matrix[3] = 0.0f;
matrix[4] = 0.0f;
matrix[5] = 1.0f;
matrix[6] = 0.0f;
matrix[7] = 0.0f;
matrix[8] = 0.0f;
matrix[9] = 0.0f;
matrix[10] = 1.0f;
matrix[11] = 0.0f;
matrix[12] = x;
matrix[13] = y;
matrix[14] = z;
matrix[15] = 1.0f;
return;
}
//此函数将两个4x4矩阵相乘并返回结果
void OpenGLClass::MatrixMultiply(float* result, float* matrix1, float* matrix2)
{
result[0] = (matrix1[0] * matrix2[0]) + (matrix1[1] * matrix2[4]) + (matrix1[2] * matrix2[8]) + (matrix1[3] * matrix2[12]);
result[1] = (matrix1[0] * matrix2[1]) + (matrix1[1] * matrix2[5]) + (matrix1[2] * matrix2[9]) + (matrix1[3] * matrix2[13]);
result[2] = (matrix1[0] * matrix2[2]) + (matrix1[1] * matrix2[6]) + (matrix1[2] * matrix2[10]) + (matrix1[3] * matrix2[14]);
result[3] = (matrix1[0] * matrix2[3]) + (matrix1[1] * matrix2[7]) + (matrix1[2] * matrix2[11]) + (matrix1[3] * matrix2[15]);
result[4] = (matrix1[4] * matrix2[0]) + (matrix1[5] * matrix2[4]) + (matrix1[6] * matrix2[8]) + (matrix1[7] * matrix2[12]);
result[5] = (matrix1[4] * matrix2[1]) + (matrix1[5] * matrix2[5]) + (matrix1[6] * matrix2[9]) + (matrix1[7] * matrix2[13]);
result[6] = (matrix1[4] * matrix2[2]) + (matrix1[5] * matrix2[6]) + (matrix1[6] * matrix2[10]) + (matrix1[7] * matrix2[14]);
result[7] = (matrix1[4] * matrix2[3]) + (matrix1[5] * matrix2[7]) + (matrix1[6] * matrix2[11]) + (matrix1[7] * matrix2[15]);
result[8] = (matrix1[8] * matrix2[0]) + (matrix1[9] * matrix2[4]) + (matrix1[10] * matrix2[8]) + (matrix1[11] * matrix2[12]);
result[9] = (matrix1[8] * matrix2[1]) + (matrix1[9] * matrix2[5]) + (matrix1[10] * matrix2[9]) + (matrix1[11] * matrix2[13]);
result[10] = (matrix1[8] * matrix2[2]) + (matrix1[9] * matrix2[6]) + (matrix1[10] * matrix2[10]) + (matrix1[11] * matrix2[14]);
result[11] = (matrix1[8] * matrix2[3]) + (matrix1[9] * matrix2[7]) + (matrix1[10] * matrix2[11]) + (matrix1[11] * matrix2[15]);
result[12] = (matrix1[12] * matrix2[0]) + (matrix1[13] * matrix2[4]) + (matrix1[14] * matrix2[8]) + (matrix1[15] * matrix2[12]);
result[13] = (matrix1[12] * matrix2[1]) + (matrix1[13] * matrix2[5]) + (matrix1[14] * matrix2[9]) + (matrix1[15] * matrix2[13]);
result[14] = (matrix1[12] * matrix2[2]) + (matrix1[13] * matrix2[6]) + (matrix1[14] * matrix2[10]) + (matrix1[15] * matrix2[14]);
result[15] = (matrix1[12] * matrix2[3]) + (matrix1[13] * matrix2[7]) + (matrix1[14] * matrix2[11]) + (matrix1[15] * matrix2[15]);
return;
}
systemclass.cpp
这里增加的东西不多,为OpenGL对象调用shutdown函数
// 释放Opengl对象
if(m_OpenGL)
{
m_OpenGL->Shutdown(m_hwnd);
delete m_OpenGL;
m_OpenGL = 0;
}
// 关闭窗口
ShutdownWindows();
return;
}
之后,为OpenGL对象加载扩展
使用扩展名之后,我们可以正确地初始化OpenGL 4.0渲染上下文。
bool SystemClass::InitializeWindows(OpenGLClass* OpenGL, int& screenWidth, int& screenHeight)
{
WNDCLASSEX wc;
DEVMODE dmScreenSettings;
int posX, posY;
bool result;
// 获取指向该对象的外部指针。
ApplicationHandle = this;
// 获取此应用程序的实例
m_hinstance = GetModuleHandle(NULL);
// 为应用程序命名
m_applicationName = L"Engine";
// 使用默认设置设置Windows类。
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);
// 注册窗口类.
RegisterClassEx(&wc);
// 为OpenGL扩展程序创建一个临时窗口
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;
}
// 不显示窗口。
ShowWindow(m_hwnd, SW_HIDE);
//现在我们使用OpenGL对象扩展窗口
//初始化一个临时OpenGL窗口并加载opengl扩展
result = OpenGL->InitializeExtensions(m_hwnd);
if (!result)
{
MessageBox(m_hwnd, L"Could not initialize the OpenGL extensions.", L"Error", MB_OK);
return false;
}
// 扩展已初始化,请释放临时窗口。
DestroyWindow(m_hwnd);
m_hwnd = NULL;
// 确定客户端桌面屏幕的分辨率
screenWidth = GetSystemMetrics(SM_CXSCREEN);
screenHeight = GetSystemMetrics(SM_CYSCREEN);
// 根据是以全屏模式还是以窗口模式运行而设置屏幕设置。.
if(FULL_SCREEN)
{
// 如果全屏,则将屏幕设置为用户桌面的最大尺寸和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;
// 将显示设置更改为全屏
ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN);
// /将窗口的位置设置为左上角。
posX = posY = 0;
}
else
{
// 如果使用窗口,则将其设置为800x600分辨率。
screenWidth = 800;
screenHeight = 600;
// 将窗口放在屏幕中间。
posX = (GetSystemMetrics(SM_CXSCREEN) - screenWidth) / 2;
posY = (GetSystemMetrics(SM_CYSCREEN) - screenHeight) / 2;
}
// /使用屏幕设置创建窗口并获取其句柄。
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;
}
//使用扩展名后,可以正确的初始化OpenGL4.0渲染上下文
//创建窗口后,初始化OpenGL
result = m_OpenGL->InitializeOpenGL(m_hwnd, screenWidth, screenHeight, SCREEN_DEPTH, SCREEN_NEAR, VSYNC_ENABLED);
if (!result)
{
MessageBox(m_hwnd, L"Could not initialize OpenGL, check if video card supports OpenGL 4.0.", L"Error", MB_OK);
return false;
}
// 在屏幕上打开窗口并将其设置为主要焦点。
ShowWindow(m_hwnd, SW_SHOW);
SetForegroundWindow(m_hwnd);
SetFocus(m_hwnd);
///隐藏鼠标光标。
ShowCursor(false);
return true;
}
完整代码如下
// Filename: systemclass.cpp
#include "systemclass.h"
SystemClass::SystemClass()
{
m_OpenGL = 0;
m_Input = 0;
m_Graphics = 0;
}
SystemClass::SystemClass(const SystemClass& other)
{
}
SystemClass::~SystemClass()
{
}
bool SystemClass::Initialize()
{
int screenWidth, screenHeight;
bool result;
// 将屏幕的宽度和高度初始化为零
screenWidth = 0;
screenHeight = 0;
// 创建OpenGL对象.
m_OpenGL = new OpenGLClass;
if(!m_OpenGL)
{
return false;
}
// 创建应用程序将使用的窗口,并初始化OpenGL.
result = InitializeWindows(m_OpenGL, screenWidth, screenHeight);
if(!result)
{
MessageBox(m_hwnd, L"Could not initialize the window.", L"Error", MB_OK);
return false;
}
//创建输入对象。该对象将用于处理从用户读取输入.
m_Input = new InputClass;
if(!m_Input)
{
return false;
}
// 初始化输入对象
m_Input->Initialize();
// 创建图形对象。该对象将处理渲染此应用程序的所有图形。
m_Graphics = new GraphicsClass;
if(!m_Graphics)
{
return false;
}
// 初始化图形对象。
result = m_Graphics->Initialize(m_OpenGL, m_hwnd);
if(!result)
{
return false;
}
return true;
}
void SystemClass::Shutdown()
{
// 释放图形对象
if(m_Graphics)
{
m_Graphics->Shutdown();
delete m_Graphics;
m_Graphics = 0;
}
// 释放输入对象
if(m_Input)
{
delete m_Input;
m_Input = 0;
}
//为OpenGL对象调用shutdown函数
// 释放Opengl对象
if(m_OpenGL)
{
m_OpenGL->Shutdown(m_hwnd);
delete m_OpenGL;
m_OpenGL = 0;
}
// 关闭窗口
ShutdownWindows();
return;
}
void SystemClass::Run()
{
MSG msg;
bool done, result;
// 初始化消息结构。
ZeroMemory(&msg, sizeof(MSG));
// 循环播放,直到窗口或用户发出退出消息为止。
done = false;
while(!done)
{
// 循环播放,直到窗口或用户发出退出消息为止。
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// 如果Windows发出结束应用程序的信号,则退出。
if(msg.message == WM_QUIT)
{
done = true;
}
else
{
// 否则进行帧处理.
result = Frame();
if(!result)
{
done = true;
}
}
}
return;
}
bool SystemClass::Frame()
{
bool result;
// 检查用户是否按了转义键并想退出该应用程序。
if(m_Input->IsKeyDown(VK_ESCAPE))
{
return false;
}
// 对图形对象进行帧处理。
result = m_Graphics->Frame();
if(!result)
{
return false;
}
return true;
}
LRESULT CALLBACK SystemClass::MessageHandler(HWND hwnd, UINT umsg, WPARAM wparam, LPARAM lparam)
{
switch(umsg)
{
// 检查是否在键盘上按下了键.
case WM_KEYDOWN:
{
// 如果释放了一个键,则将其发送到输入对象,以便它可以取消设置该键的状态。
m_Input->KeyDown((unsigned int)wparam);
return 0;
}
// 检查键盘上的键是否已释放。
case WM_KEYUP:
{
//如果释放了一个键,则将其发送到输入对象,以便它可以取消设置该键的状态。
m_Input->KeyUp((unsigned int)wparam);
return 0;
}
// 其他任何发送到默认消息处理程序的消息,因为我们的应用程序将不会使用它们
default:
{
return DefWindowProc(hwnd, umsg, wparam, lparam);
}
}
}
bool SystemClass::InitializeWindows(OpenGLClass* OpenGL, int& screenWidth, int& screenHeight)
{
WNDCLASSEX wc;
DEVMODE dmScreenSettings;
int posX, posY;
bool result;
// 获取指向该对象的外部指针。
ApplicationHandle = this;
// 获取此应用程序的实例
m_hinstance = GetModuleHandle(NULL);
// 为应用程序命名
m_applicationName = L"Engine";
// 使用默认设置设置Windows类。
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);
// 注册窗口类.
RegisterClassEx(&wc);
// 为OpenGL扩展程序创建一个临时窗口
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;
}
// 不显示窗口。
ShowWindow(m_hwnd, SW_HIDE);
//现在我们使用OpenGL对象扩展窗口
//初始化一个临时OpenGL窗口并加载opengl扩展
result = OpenGL->InitializeExtensions(m_hwnd);
if (!result)
{
MessageBox(m_hwnd, L"Could not initialize the OpenGL extensions.", L"Error", MB_OK);
return false;
}
// 扩展已初始化,请释放临时窗口。
DestroyWindow(m_hwnd);
m_hwnd = NULL;
// 确定客户端桌面屏幕的分辨率
screenWidth = GetSystemMetrics(SM_CXSCREEN);
screenHeight = GetSystemMetrics(SM_CYSCREEN);
// 根据是以全屏模式还是以窗口模式运行而设置屏幕设置。.
if(FULL_SCREEN)
{
// 如果全屏,则将屏幕设置为用户桌面的最大尺寸和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;
// 将显示设置更改为全屏
ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN);
// /将窗口的位置设置为左上角。
posX = posY = 0;
}
else
{
// 如果使用窗口,则将其设置为800x600分辨率。
screenWidth = 800;
screenHeight = 600;
// 将窗口放在屏幕中间。
posX = (GetSystemMetrics(SM_CXSCREEN) - screenWidth) / 2;
posY = (GetSystemMetrics(SM_CYSCREEN) - screenHeight) / 2;
}
// /使用屏幕设置创建窗口并获取其句柄。
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;
}
//使用扩展名后,可以正确的初始化OpenGL4.0渲染上下文
//创建窗口后,初始化OpenGL
result = m_OpenGL->InitializeOpenGL(m_hwnd, screenWidth, screenHeight, SCREEN_DEPTH, SCREEN_NEAR, VSYNC_ENABLED);
if (!result)
{
MessageBox(m_hwnd, L"Could not initialize OpenGL, check if video card supports OpenGL 4.0.", L"Error", MB_OK);
return false;
}
// 在屏幕上打开窗口并将其设置为主要焦点。
ShowWindow(m_hwnd, SW_SHOW);
SetForegroundWindow(m_hwnd);
SetFocus(m_hwnd);
///隐藏鼠标光标。
ShowCursor(false);
return true;
}
void SystemClass::ShutdownWindows()
{
// 显示鼠标光标.
ShowCursor(true);
// 如果退出全屏模式,请修复显示设置。
if(FULL_SCREEN)
{
ChangeDisplaySettings(NULL, 0);
}
//删除窗口。
DestroyWindow(m_hwnd);
m_hwnd = NULL;
// 删除应用程序实例
UnregisterClass(m_applicationName, m_hinstance);
m_hinstance = NULL;
// 释放指向此类的指针。
ApplicationHandle = NULL;
return;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
{
switch(umessage)
{
// 检查窗口是否关闭。
case WM_CLOSE:
{
PostQuitMessage(0);
return 0;
}
// 所有其他消息都传递给系统类中的消息处理程序。
default:
{
return ApplicationHandle->MessageHandler(hwnd, umessage, wparam, lparam);
}
}
}
Graphicsclass.h
在本教程中,我们现在还填写了GraphicsClass,以便它可以执行一些基本的OpenGL渲染。
添加私有变量,
OpenGLClass * m_OpenGL;
Graphicsclass.cpp
在上一教程中,该类完全是空的,根本没有任何代码。现在我们有了OpenGLClass成员,我们将开始在GraphicsClass中填充一些代码以初始化和关闭OpenGLClass对象。我们还将在Render函数中添加对BeginScene和EndScene的调用,以便现在使用OpenGL绘制到窗口。
因此,第一个更改是在类构造函数中。在这里,出于安全原因,我们将OpenGLClass对象指针初始化为null,就像处理所有类指针一样。
GraphicsClass :: GraphicsClass()
{
m_OpenGL = 0;
}
第二个变化是GraphicsClass内的Initialize函数。在这里,我们发送一个指向OpenGLClass对象的指针,以便GraphicsClass可以仅使用单个指针进行OpenGL系统调用。
bool GraphicsClass::Initialize(OpenGLClass* OpenGL, HWND hwnd)
{
// 存储指向OpenGL类对象的指针
m_OpenGL = OpenGL;
return true;
}
下一个更改是GraphicsClass中的Shutdown函数。在这里,我们在关闭过程中释放指向OpenGLClass对象的指针。
void GraphicsClass::Shutdown()
{
//释放指向OpenGL类对象的指针
m_OpenGL = 0;
return;
}
帧函数已经更新,现在可以在每个帧上调用渲染函数。
bool GraphicsClass::Frame()
{
bool result;
// Render the graphics scene.
result = Render();
if(!result)
{
return false;
}
return true;
}
对此类的最后更改是在Render函数中。我们将OpenGL对象称为将屏幕清除为灰色。之后,我们调用EndScene,以便将灰色呈现给窗口。
bool GraphicsClass::Render()
{
// Clear the buffers to begin the scene.
m_OpenGL->BeginScene(0.5f, 0.5f, 0.5f, 1.0f);
// Present the rendered scene to the screen.
m_OpenGL->EndScene();
return true;
}
// Filename: graphicsclass.cpp
#include "graphicsclass.h"
GraphicsClass::GraphicsClass()
{
m_OpenGL = 0;
}
GraphicsClass::GraphicsClass(const GraphicsClass& other)
{
}
GraphicsClass::~GraphicsClass()
{
}
bool GraphicsClass::Initialize(OpenGLClass* OpenGL, HWND hwnd)
{
// 存储指向OpenGL类对象的指针
m_OpenGL = OpenGL;
return true;
}
void GraphicsClass::Shutdown()
{
//释放指向OpenGL类对象的指针
m_OpenGL = 0;
return;
}
//帧函数已更新,可以在每个框架上调用渲染函数
bool GraphicsClass::Frame()
{
bool result;
// 渲染图形场景.
result = Render();
if (!result)
{
return false;
}
return true;
}
//OpenGL对象将屏幕清除为灰色,调用EndScene,将灰色呈现给窗口
bool GraphicsClass::Render()
{
// 清除缓冲区,开始场景
m_OpenGL->BeginScene(0.5f, 0.5f, 0.5f, 1.0f);
// 将渲染的场景呈现到屏幕上.
m_OpenGL->EndScene();
return true;
}
概要
现在我们终于可以初始化和关闭OpenGL 4.0。编译和运行代码将产生与上一教程相同的窗口,但是OpenGL现在已初始化,并且为我们清除了该窗口为灰色。编译和运行代码还将显示您的视频卡驱动程序是否可以正确获取我们将使用的所有OpenGL 4.0扩展。
练习
1.重新编译代码并运行程序,以确保OpenGL正常工作。窗口显示后,按退出键退出。
2.将graphicsclass.h中的global更改为全屏,然后重新编译/运行。
3.将GraphicsClass :: Render中的清除颜色更改为黄色。
4.将显卡名称写出到文本文件中。