上一篇我们在Linux系统上用OpenGL绘制了一个基本的空间矩形。本篇我们看看在Windows平台上如何使用OpenGL,并且看一下高版本(4.0)的OpenGL的使用方法。
注意无论是DX还是OpenGL,都需要硬件(GPU)的支持。不同版本的显卡能够支持的图形API版本也是不一样的。因此可能存在部分机器无法运行接下来的代码的情况。特别是在远程登录的情况下,或者在X forwarding情况下,不通过一些特别的技巧,一般是无法正确运行需要GPU加速的应用的。
另外纠正前面的文章的一个错误。vmware workstation player的免费版,是无法手动打开GPU加速的。
OpenGL API是由显卡的驱动程序实现的。所以我们的程序实际上并不会链接到这些API,而是在运行的时候去查找这些API的入口地址。这个用于查找API入口地址的API,一般就是gl.h和libGL(在windows当中为opengl32.lib)所提供的内容,但也是因系统不同而不同的。
由于OpenGL和DX是并行的关系,所以我们选择helloengine_win.c作为我们的起点,而不是helloengine_d*d.cpp。拷贝helloengine_win.c到helloengine_opengl.cpp,开始我们的编辑。
(本文大部分代码参考 http://www.rastertek.com/gl40tut03.html 编写。本文的目的是探查在Windows上使用OpenGL的方法。本文的代码并不会直接成为我们引擎的正式代码。)[*1]
#include <windows.h>
#include <windowsx.h>
#include <tchar.h>
+#include <GL/gl.h>
+#include <fstream>
+
+#include "math.h"
+
+using namespace std;
+
+/////////////
+// 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);
+
+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;
+
+PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB;
+PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB;
+PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT;
+
+typedef struct VertexType
+{
+ VectorType position;
+ VectorType color;
+} VertexType;
+
+HDC g_deviceContext = 0;
+HGLRC g_renderingContext = 0;
+char g_videoCardDescription[128];
+
+const bool VSYNC_ENABLED = true;
+const float SCREEN_DEPTH = 1000.0f;
+const float SCREEN_NEAR = 0.1f;
+
+int g_vertexCount, g_indexCount;
+unsigned int g_vertexArrayId, g_vertexBufferId, g_indexBufferId;
+
+unsigned int g_vertexShader;
+unsigned int g_fragmentShader;
+unsigned int g_shaderProgram;
+
+const char VS_SHADER_SOURCE_FILE[] = "color.vs";
+const char PS_SHADER_SOURCE_FILE[] = "color.ps";
+
+float g_positionX = 0, g_positionY = 0, g_positionZ = -10;
+float g_rotationX = 0, g_rotationY = 0, g_rotationZ = 0;
+float g_worldMatrix[16];
+float g_viewMatrix[16];
+float g_projectionMatrix[16];
+
+bool 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;
+
+
+ // Get the device context for this window.
+ g_deviceContext = GetDC(hwnd);
+ if(!g_deviceContext)
+ {
+ return false;
+ }
+
+ // Support for OpenGL rendering.
+ attributeListInt[0] = WGL_SUPPORT_OPENGL_ARB;
+ attributeListInt[1] = TRUE;
+
+ // Support for rendering to a window.
+ attributeListInt[2] = WGL_DRAW_TO_WINDOW_ARB;
+ attributeListInt[3] = TRUE;
+
+ // Support for hardware acceleration.
+ attributeListInt[4] = WGL_ACCELERATION_ARB;
+ attributeListInt[5] = WGL_FULL_ACCELERATION_ARB;
+
+ // Support for 24bit color.
+ attributeListInt[6] = WGL_COLOR_BITS_ARB;
+ attributeListInt[7] = 24;
+
+ // Support for 24 bit depth buffer.
+ attributeListInt[8] = WGL_DEPTH_BITS_ARB;
+ attributeListInt[9] = 24;
+
+ // Support for double buffer.
+ attributeListInt[10] = WGL_DOUBLE_BUFFER_ARB;
+ attributeListInt[11] = TRUE;
+
+ // Support for swapping front and back buffer.
+ attributeListInt[12] = WGL_SWAP_METHOD_ARB;
+ attributeListInt[13] = WGL_SWAP_EXCHANGE_ARB;
+
+ // Support for the RGBA pixel type.
+ attributeListInt[14] = WGL_PIXEL_TYPE_ARB;
+ attributeListInt[15] = WGL_TYPE_RGBA_ARB;
+
+ // Support for a 8 bit stencil buffer.
+ attributeListInt[16] = WGL_STENCIL_BITS_ARB;
+ attributeListInt[17] = 8;
+
+ // Null terminate the attribute list.
+ attributeListInt[18] = 0;
+
+
+ // Query for a pixel format that fits the attributes we want.
+ result = wglChoosePixelFormatARB(g_deviceContext, attributeListInt, NULL, 1, pixelFormat, &formatCount);
+ if(result != 1)
+ {
+ return false;
+ }
+
+ // If the video card/display can handle our desired pixel format then we set it as the current one.
+ result = SetPixelFormat(g_deviceContext, pixelFormat[0], &pixelFormatDescriptor);
+ if(result != 1)
+ {
+ return false;
+ }
+
+ // Set the 4.0 version of OpenGL in the attribute list.
+ attributeList[0] = WGL_CONTEXT_MAJOR_VERSION_ARB;
+ attributeList[1] = 4;
+ attributeList[2] = WGL_CONTEXT_MINOR_VERSION_ARB;
+ attributeList[3] = 0;
+
+ // Null terminate the attribute list.
+ attributeList[4] = 0;
+
+ // Create a OpenGL 4.0 rendering context.
+ g_renderingContext = wglCreateContextAttribsARB(g_deviceContext, 0, attributeList);
+ if(g_renderingContext == NULL)
+ {
+ return false;
+ }
+
+ // Set the rendering context to active.
+ result = wglMakeCurrent(g_deviceContext, g_renderingContext);
+ if(result != 1)
+ {
+ return false;
+ }
+
+ // Set the depth buffer to be entirely cleared to 1.0 values.
+ glClearDepth(1.0f);
+
+ // Enable depth testing.
+ glEnable(GL_DEPTH_TEST);
+
+ // Set the polygon winding to front facing for the left handed system.
+ glFrontFace(GL_CW);
+
+ // Enable back face culling.
+ glEnable(GL_CULL_FACE);
+ glCullFace(GL_BACK);
+
+ // Initialize the world/model matrix to the identity matrix.
+ BuildIdentityMatrix(g_worldMatrix);
+
+ // Set the field of view and screen aspect ratio.
+ fieldOfView = PI / 4.0f;
+ screenAspect = (float)screenWidth / (float)screenHeight;
+
+ // Build the perspective projection matrix.
+ BuildPerspectiveFovLHMatrix(g_projectionMatrix, fieldOfView, screenAspect, screenNear, screenDepth);
+
+ // Get the name of the video card.
+ vendorString = (char*)glGetString(GL_VENDOR);
+ rendererString = (char*)glGetString(GL_RENDERER);
+ // Store the video card name in a class member variable so it can be retrieved later.
+ strcpy_s(g_videoCardDescription, vendorString);
+ strcat_s(g_videoCardDescription, " - ");
+ strcat_s(g_videoCardDescription, rendererString);
+
+ // Turn on or off the vertical sync depending on the input bool value.
+ if(vsync)
+ {
+ result = wglSwapIntervalEXT(1);
+ }
+ else
+ {
+ result = wglSwapIntervalEXT(0);
+ }
+
+ // Check if vsync was set correctly.
+ if(result != 1)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+bool LoadExtensionList()
+{
+ // Load the OpenGL extensions that this application will be using.
+ 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 FinalizeOpenGL(HWND hwnd)
+{
+ // Release the rendering context.
+ if(g_renderingContext)
+ {
+ wglMakeCurrent(NULL, NULL);
+ wglDeleteContext(g_renderingContext);
+ g_renderingContext = 0;
+ }
+
+ // Release the device context.
+ if(g_deviceContext)
+ {
+ ReleaseDC(hwnd, g_deviceContext);
+ g_deviceContext = 0;
+ }
+}
+
+void GetVideoCardInfo(char* cardName)
+{
+ strcpy_s(cardName, 128, g_videoCardDescription);
+ return;
+}
+
+bool InitializeExtensions(HWND hwnd)
+{
+ HDC deviceContext;
+ PIXELFORMATDESCRIPTOR pixelFormat;
+ int error;
+ HGLRC renderContext;
+ bool result;
+
+
+ // Get the device context for this window.
+ deviceContext = GetDC(hwnd);
+ if(!deviceContext)
+ {
+ return false;
+ }
+
+ // Set a temporary default pixel format.
+ error = SetPixelFormat(deviceContext, 1, &pixelFormat);
+ if(error != 1)
+ {
+ return false;
+ }
+
+ // Create a temporary rendering context.
+ renderContext = wglCreateContext(deviceContext);
+ if(!renderContext)
+ {
+ return false;
+ }
+
+ // Set the temporary rendering context as the current rendering context for this window.
+ error = wglMakeCurrent(deviceContext, renderContext);
+ if(error != 1)
+ {
+ return false;
+ }
+
+ // Initialize the OpenGL extensions needed for this application. Note that a temporary rendering context was needed to do so.
+ result = LoadExtensionList();
+ if(!result)
+ {
+ return false;
+ }
+
+ // Release the temporary rendering context now that the extensions have been loaded.
+ wglMakeCurrent(NULL, NULL);
+ wglDeleteContext(renderContext);
+ renderContext = NULL;
+
+ // Release the device context for this window.
+ ReleaseDC(hwnd, deviceContext);
+ deviceContext = 0;
+
+ return true;
+}
+
+void OutputShaderErrorMessage(HWND hwnd, unsigned int shaderId, const char* shaderFilename)
+{
+ int logSize, i;
+ char* infoLog;
+ ofstream fout;
+ wchar_t newString[128];
+ unsigned int error;
+ size_t convertedChars;
+
+
+ // Get the size of the string containing the information log for the failed shader compilation message.
+ glGetShaderiv(shaderId, GL_INFO_LOG_LENGTH, &logSize);
+
+ // Increment the size by one to handle also the null terminator.
+ logSize++;
+
+ // Create a char buffer to hold the info log.
+ infoLog = new char[logSize];
+ if(!infoLog)
+ {
+ return;
+ }
+
+ // Now retrieve the info log.
+ glGetShaderInfoLog(shaderId, logSize, NULL, infoLog);
+
+ // Open a file to write the error message to.
+ fout.open("shader-error.txt");
+
+ // Write out the error message.
+ for(i=0; i<logSize; i++)
+ {
+ fout << infoLog[i];
+ }
+
+ // Close the file.
+ fout.close();
+
+ // Convert the shader filename to a wide character string.
+ error = mbstowcs_s(&convertedChars, newString, 128, shaderFilename, 128);
+ if(error != 0)
+ {
+ return;
+ }
+
+ // Pop a message up on the screen to notify the user to check the text file for compile errors.
+ MessageBoxW(hwnd, L"Error compiling shader. Check shader-error.txt for message.", newString, MB_OK);
+
+ return;
+}
+
+void OutputLinkerErrorMessage(HWND hwnd, unsigned int programId)
+{
+ int logSize, i;
+ char* infoLog;
+ ofstream fout;
+
+
+ // Get the size of the string containing the information log for the failed shader compilation message.
+ glGetProgramiv(programId, GL_INFO_LOG_LENGTH, &logSize);
+
+ // Increment the size by one to handle also the null terminator.
+ logSize++;
+
+ // Create a char buffer to hold the info log.
+ infoLog = new char[logSize];
+ if(!infoLog)
+ {
+ return;
+ }
+
+ // Now retrieve the info log.
+ glGetProgramInfoLog(programId, logSize, NULL, infoLog);
+
+ // Open a file to write the error message to.
+ fout.open("linker-error.txt");
+
+ // Write out the error message.
+ for(i=0; i<logSize; i++)
+ {
+ fout << infoLog[i];
+ }
+
+ // Close the file.
+ fout.close();
+
+ // Pop a message up on the screen to notify the user to check the text file for linker errors.
+ MessageBox(hwnd, _T("Error compiling linker. Check linker-error.txt for message."), _T("Linker Error"), MB_OK);
+}
+
+char* LoadShaderSourceFile(const char* filename)
+{
+ ifstream fin;
+ int fileSize;
+ char input;
+ char* buffer;
+
+
+ // Open the shader source file.
+ fin.open(filename);
+
+ // If it could not open the file then exit.
+ if(fin.fail())
+ {
+ return 0;
+ }
+
+ // Initialize the size of the file.
+ fileSize = 0;
+
+ // Read the first element of the file.
+ fin.get(input);
+
+ // Count the number of elements in the text file.
+ while(!fin.eof())
+ {
+ fileSize++;
+ fin.get(input);
+ }
+
+ // Close the file for now.
+ fin.close();
+
+ // Initialize the buffer to read the shader source file into.
+ buffer = new char[fileSize+1];
+ if(!buffer)
+ {
+ return 0;
+ }
+
+ // Open the shader source file again.
+ fin.open(filename);
+
+ // Read the shader text file into the buffer as a block.
+ fin.read(buffer, fileSize);
+
+ // Close the file.
+ fin.close();
+
+ // Null terminate the buffer.
+ buffer[fileSize] = '';
+
+ return buffer;
+}
+
+bool InitializeShader(HWND hwnd, const char* vsFilename, const char* fsFilename)
+{
+ const char* vertexShaderBuffer;
+ const char* fragmentShaderBuffer;
+ int status;
+
+ // Load the vertex shader source file into a text buffer.
+ vertexShaderBuffer = LoadShaderSourceFile(vsFilename);
+ if(!vertexShaderBuffer)
+ {
+ return false;
+ }
+
+ // Load the fragment shader source file into a text buffer.
+ fragmentShaderBuffer = LoadShaderSourceFile(fsFilename);
+ if(!fragmentShaderBuffer)
+ {
+ return false;
+ }
+
+ // Create a vertex and fragment shader object.
+ g_vertexShader = glCreateShader(GL_VERTEX_SHADER);
+ g_fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
+
+ // Copy the shader source code strings into the vertex and fragment shader objects.
+ glShaderSource(g_vertexShader, 1, &vertexShaderBuffer, NULL);
+ glShaderSource(g_fragmentShader, 1, &fragmentShaderBuffer, NULL);
+
+ // Release the vertex and fragment shader buffers.
+ delete [] vertexShaderBuffer;
+ vertexShaderBuffer = 0;
+
+ delete [] fragmentShaderBuffer;
+ fragmentShaderBuffer = 0;
+
+ // Compile the shaders.
+ glCompileShader(g_vertexShader);
+ glCompileShader(g_fragmentShader);
+
+ // Check to see if the vertex shader compiled successfully.
+ glGetShaderiv(g_vertexShader, GL_COMPILE_STATUS, &status);
+ if(status != 1)
+ {
+ // If it did not compile then write the syntax error message out to a text file for review.
+ OutputShaderErrorMessage(hwnd, g_vertexShader, vsFilename);
+ return false;
+ }
+
+ // Check to see if the fragment shader compiled successfully.
+ glGetShaderiv(g_fragmentShader, GL_COMPILE_STATUS, &status);
+ if(status != 1)
+ {
+ // If it did not compile then write the syntax error message out to a text file for review.
+ OutputShaderErrorMessage(hwnd, g_fragmentShader, fsFilename);
+ return false;
+ }
+
+ // Create a shader program object.
+ g_shaderProgram = glCreateProgram();
+
+ // Attach the vertex and fragment shader to the program object.
+ glAttachShader(g_shaderProgram, g_vertexShader);
+ glAttachShader(g_shaderProgram, g_fragmentShader);
+
+ // Bind the shader input variables.
+ glBindAttribLocation(g_shaderProgram, 0, "inputPosition");
+ glBindAttribLocation(g_shaderProgram, 1, "inputColor");
+
+ // Link the shader program.
+ glLinkProgram(g_shaderProgram);
+
+ // Check the status of the link.
+ glGetProgramiv(g_shaderProgram, GL_LINK_STATUS, &status);
+ if(status != 1)
+ {
+ // If it did not link then write the syntax error message out to a text file for review.
+ OutputLinkerErrorMessage(hwnd, g_shaderProgram);
+ return false;
+ }
+
+ return true;
+}
+
+void ShutdownShader()
+{
+ // Detach the vertex and fragment shaders from the program.
+ glDetachShader(g_shaderProgram, g_vertexShader);
+ glDetachShader(g_shaderProgram, g_fragmentShader);
+
+ // Delete the vertex and fragment shaders.
+ glDeleteShader(g_vertexShader);
+ glDeleteShader(g_fragmentShader);
+
+ // Delete the shader program.
+ glDeleteProgram(g_shaderProgram);
+}
+
+bool SetShaderParameters(float* worldMatrix, float* viewMatrix, float* projectionMatrix)
+{
+ unsigned int location;
+
+ // Set the world matrix in the vertex shader.
+ location = glGetUniformLocation(g_shaderProgram, "worldMatrix");
+ if(location == -1)
+ {
+ return false;
+ }
+ glUniformMatrix4fv(location, 1, false, worldMatrix);
+
+ // Set the view matrix in the vertex shader.
+ location = glGetUniformLocation(g_shaderProgram, "viewMatrix");
+ if(location == -1)
+ {
+ return false;
+ }
+ glUniformMatrix4fv(location, 1, false, viewMatrix);
+
+ // Set the projection matrix in the vertex shader.
+ location = glGetUniformLocation(g_shaderProgram, "projectionMatrix");
+ if(location == -1)
+ {
+ return false;
+ }
+ glUniformMatrix4fv(location, 1, false, projectionMatrix);
+
+ return true;
+}
+
+bool InitializeBuffers()
+{
+ VertexType vertices[] = {
+ {{ 1.0f, 1.0f, 1.0f }, { 1.0f, 0.0f, 0.0f }},
+ {{ 1.0f, 1.0f, -1.0f }, { 0.0f, 1.0f, 0.0f }},
+ {{ -1.0f, 1.0f, -1.0f }, { 0.0f, 0.0f, 1.0f }},
+ {{ -1.0f, 1.0f, 1.0f }, { 1.0f, 1.0f, 0.0f }},
+ {{ 1.0f, -1.0f, 1.0f }, { 1.0f, 0.0f, 1.0f }},
+ {{ 1.0f, -1.0f, -1.0f }, { 0.0f, 1.0f, 1.0f }},
+ {{ -1.0f, -1.0f, -1.0f }, { 0.5f, 1.0f, 0.5f }},
+ {{ -1.0f, -1.0f, 1.0f }, { 1.0f, 0.5f, 1.0f }},
+ };
+ uint16_t indices[] = { 1, 2, 3, 3, 2, 6, 6, 7, 3, 3, 0, 1, 0, 3, 7, 7, 6, 4, 4, 6, 5, 0, 7, 4, 1, 0, 4, 1, 4, 5, 2, 1, 5, 2, 5, 6 };
+
+ // Set the number of vertices in the vertex array.
+ g_vertexCount = sizeof(vertices) / sizeof(VertexType);
+
+ // Set the number of indices in the index array.
+ g_indexCount = sizeof(indices) / sizeof(uint16_t);
+
+ // Allocate an OpenGL vertex array object.
+ glGenVertexArrays(1, &g_vertexArrayId);
+
+ // Bind the vertex array object to store all the buffers and vertex attributes we create here.
+ glBindVertexArray(g_vertexArrayId);
+
+ // Generate an ID for the vertex buffer.
+ glGenBuffers(1, &g_vertexBufferId);
+
+ // Bind the vertex buffer and load the vertex (position and color) data into the vertex buffer.
+ glBindBuffer(GL_ARRAY_BUFFER, g_vertexBufferId);
+ glBufferData(GL_ARRAY_BUFFER, g_vertexCount * sizeof(VertexType), vertices, GL_STATIC_DRAW);
+
+ // Enable the two vertex array attributes.
+ glEnableVertexAttribArray(0); // Vertex position.
+ glEnableVertexAttribArray(1); // Vertex color.
+
+ // Specify the location and format of the position portion of the vertex buffer.
+ glBindBuffer(GL_ARRAY_BUFFER, g_vertexBufferId);
+ glVertexAttribPointer(0, 3, GL_FLOAT, false, sizeof(VertexType), 0);
+
+ // Specify the location and format of the color portion of the vertex buffer.
+ glBindBuffer(GL_ARRAY_BUFFER, g_vertexBufferId);
+ glVertexAttribPointer(1, 3, GL_FLOAT, false, sizeof(VertexType), (char*)NULL + (3 * sizeof(float)));
+
+ // Generate an ID for the index buffer.
+ glGenBuffers(1, &g_indexBufferId);
+
+ // Bind the index buffer and load the index data into it.
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_indexBufferId);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, g_indexCount* sizeof(uint16_t), indices, GL_STATIC_DRAW);
+
+ return true;
+}
+
+void ShutdownBuffers()
+{
+ // Disable the two vertex array attributes.
+ glDisableVertexAttribArray(0);
+ glDisableVertexAttribArray(1);
+
+ // Release the vertex buffer.
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glDeleteBuffers(1, &g_vertexBufferId);
+
+ // Release the index buffer.
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ glDeleteBuffers(1, &g_indexBufferId);
+
+ // Release the vertex array object.
+ glBindVertexArray(0);
+ glDeleteVertexArrays(1, &g_vertexArrayId);
+
+ return;
+}
+
+void RenderBuffers()
+{
+ // Bind the vertex array object that stored all the information about the vertex and index buffers.
+ glBindVertexArray(g_vertexArrayId);
+
+ // Render the vertex buffer using the index buffer.
+ glDrawElements(GL_TRIANGLES, g_indexCount, GL_UNSIGNED_SHORT, 0);
+
+ return;
+}
+
+void CalculateCameraPosition()
+{
+ VectorType up, position, lookAt;
+ float yaw, pitch, roll;
+ float rotationMatrix[9];
+
+
+ // Setup the vector that points upwards.
+ up.x = 0.0f;
+ up.y = 1.0f;
+ up.z = 0.0f;
+
+ // Setup the position of the camera in the world.
+ position.x = g_positionX;
+ position.y = g_positionY;
+ position.z = g_positionZ;
+
+ // Setup where the camera is looking by default.
+ lookAt.x = 0.0f;
+ lookAt.y = 0.0f;
+ lookAt.z = 1.0f;
+
+ // Set the yaw (Y axis), pitch (X axis), and roll (Z axis) rotations in radians.
+ pitch = g_rotationX * 0.0174532925f;
+ yaw = g_rotationY * 0.0174532925f;
+ roll = g_rotationZ * 0.0174532925f;
+
+ // Create the rotation matrix from the yaw, pitch, and roll values.
+ MatrixRotationYawPitchRoll(rotationMatrix, yaw, pitch, roll);
+
+ // Transform the lookAt and up vector by the rotation matrix so the view is correctly rotated at the origin.
+ TransformCoord(lookAt, rotationMatrix);
+ TransformCoord(up, rotationMatrix);
+
+ // Translate the rotated camera position to the location of the viewer.
+ lookAt.x = position.x + lookAt.x;
+ lookAt.y = position.y + lookAt.y;
+ lookAt.z = position.z + lookAt.z;
+
+ // Finally create the view matrix from the three updated vectors.
+ BuildViewMatrix(position, lookAt, up, g_viewMatrix);
+}
+
+void Draw()
+{
+ static float rotateAngle = 0.0f;
+
+ // Set the color to clear the screen to.
+ glClearColor(0.2f, 0.3f, 0.4f, 1.0f);
+ // Clear the screen and depth buffer.
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ // Update world matrix to rotate the model
+ rotateAngle += PI / 120;
+ float rotationMatrixY[16];
+ float rotationMatrixZ[16];
+ MatrixRotationY(rotationMatrixY, rotateAngle);
+ MatrixRotationZ(rotationMatrixZ, rotateAngle);
+ MatrixMultiply(g_worldMatrix, rotationMatrixZ, rotationMatrixY);
+
+ // Generate the view matrix based on the camera's position.
+ CalculateCameraPosition();
+
+ // Set the color shader as the current shader program and set the matrices that it will use for rendering.
+ glUseProgram(g_shaderProgram);
+ SetShaderParameters(g_worldMatrix, g_viewMatrix, g_projectionMatrix);
+
+ // Render the model using the color shader.
+ RenderBuffers();
+
+ // Present the back buffer to the screen since rendering is complete.
+ SwapBuffers(g_deviceContext);
+}
// the WindowProc function prototype
LRESULT CALLBACK WindowProc(HWND hWnd,
@@ -25,32 +1049,75 @@ int WINAPI WinMain(HINSTANCE hInstance,
// fill in the struct with the needed information
wc.cbSize = sizeof(WNDCLASSEX);
- wc.style = CS_HREDRAW | CS_VREDRAW;
+ wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
+ wc.lpfnWndProc = DefWindowProc;
+ wc.hInstance = hInstance;
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
+ wc.lpszClassName = _T("Temporary");
+
+ // register the window class
+ RegisterClassEx(&wc);
+
+ // create the temporary window for OpenGL extension setup.
+ hWnd = CreateWindowEx(WS_EX_APPWINDOW,
+ _T("Temporary"), // name of the window class
+ _T("Temporary"), // title of the window
+ WS_OVERLAPPEDWINDOW, // window style
+ 0, // x-position of the window
+ 0, // y-position of the window
+ 640, // width of the window
+ 480, // height of the window
+ NULL, // we have no parent window, NULL
+ NULL, // we aren't using menus, NULL
+ hInstance, // application handle
+ NULL); // used with multiple windows, NULL
+
+ // Don't show the window.
+ ShowWindow(hWnd, SW_HIDE);
+
+ InitializeExtensions(hWnd);
+
+ DestroyWindow(hWnd);
+ hWnd = NULL;
+
+ // clear out the window class for use
+ ZeroMemory(&wc, sizeof(WNDCLASSEX));
+
+ // fill in the struct with the needed information
+ wc.cbSize = sizeof(WNDCLASSEX);
+ wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
- wc.lpszClassName = _T("WindowClass1");
+ wc.lpszClassName = _T("Hello, Engine!");
// register the window class
RegisterClassEx(&wc);
// create the window and use the result as the handle
- hWnd = CreateWindowEx(0,
- _T("WindowClass1"), // name of the window class
+ hWnd = CreateWindowEx(WS_EX_APPWINDOW,
+ _T("Hello, Engine!"), // name of the window class
_T("Hello, Engine!"), // title of the window
WS_OVERLAPPEDWINDOW, // window style
300, // x-position of the window
300, // y-position of the window
- 500, // width of the window
- 400, // height of the window
+ 960, // width of the window
+ 540, // height of the window
NULL, // we have no parent window, NULL
NULL, // we aren't using menus, NULL
hInstance, // application handle
NULL); // used with multiple windows, NULL
+ InitializeOpenGL(hWnd, 960, 540, SCREEN_DEPTH, SCREEN_NEAR, true);
+
// display the window on the screen
ShowWindow(hWnd, nCmdShow);
+ SetForegroundWindow(hWnd);
+
+ InitializeShader(hWnd, VS_SHADER_SOURCE_FILE, PS_SHADER_SOURCE_FILE);
+ InitializeBuffers();
// enter the main loop:
@@ -67,6 +1134,10 @@ int WINAPI WinMain(HINSTANCE hInstance,
DispatchMessage(&msg);
}
+ ShutdownBuffers();
+ ShutdownShader();
+ FinalizeOpenGL(hWnd);
+
// return this part of the WM_QUIT message to Windows
return msg.wParam;
}
@@ -79,14 +1150,8 @@ LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lPara
{
case WM_PAINT:
{
- PAINTSTRUCT ps;
- HDC hdc = BeginPaint(hWnd, &ps);
- RECT rec = { 20, 20, 60, 80 };
- HBRUSH brush = (HBRUSH) GetStockObject(BLACK_BRUSH);
-
- FillRect(hdc, &rec, brush);
-
- EndPaint(hWnd, &ps);
+ Draw();
+ return 0;
} break;
// this message is read when the window is closed
case WM_DESTROY:
另外新增一个数学头文件(math.h),用以实现一些基本的线性代数计算:
#include <math.h>
#ifndef PI
#define PI 3.14159265358979323846f
#endif
#ifndef TWO_PI
#define TWO_PI 3.14159265358979323846f * 2.0f
#endif
typedef struct VectorType
{
union {
struct { float x, y, z; };
struct { float r, g, b; };
};
} VectorType;
void MatrixRotationYawPitchRoll(float* matrix, float yaw, float pitch, float roll)
{
float cYaw, cPitch, cRoll, sYaw, sPitch, sRoll;
// Get the cosine and sin of the yaw, pitch, and roll.
cYaw = cosf(yaw);
cPitch = cosf(pitch);
cRoll = cosf(roll);
sYaw = sinf(yaw);
sPitch = sinf(pitch);
sRoll = sinf(roll);
// Calculate the yaw, pitch, roll rotation matrix.
matrix[0] = (cRoll * cYaw) + (sRoll * sPitch * sYaw);
matrix[1] = (sRoll * cPitch);
matrix[2] = (cRoll * -sYaw) + (sRoll * sPitch * cYaw);
matrix[3] = (-sRoll * cYaw) + (cRoll * sPitch * sYaw);
matrix[4] = (cRoll * cPitch);
matrix[5] = (sRoll * sYaw) + (cRoll * sPitch * cYaw);
matrix[6] = (cPitch * sYaw);
matrix[7] = -sPitch;
matrix[8] = (cPitch * cYaw);
return;
}
void TransformCoord(VectorType& vector, float* matrix)
{
float x, y, z;
// Transform the vector by the 3x3 matrix.
x = (vector.x * matrix[0]) + (vector.y * matrix[3]) + (vector.z * matrix[6]);
y = (vector.x * matrix[1]) + (vector.y * matrix[4]) + (vector.z * matrix[7]);
z = (vector.x * matrix[2]) + (vector.y * matrix[5]) + (vector.z * matrix[8]);
// Store the result in the reference.
vector.x = x;
vector.y = y;
vector.z = z;
return;
}
void BuildViewMatrix(VectorType position, VectorType lookAt, VectorType up, float* result)
{
VectorType zAxis, xAxis, yAxis;
float length, result1, result2, result3;
// zAxis = normal(lookAt - position)
zAxis.x = lookAt.x - position.x;
zAxis.y = lookAt.y - position.y;
zAxis.z = lookAt.z - position.z;
length = sqrt((zAxis.x * zAxis.x) + (zAxis.y * zAxis.y) + (zAxis.z * zAxis.z));
zAxis.x = zAxis.x / length;
zAxis.y = zAxis.y / length;
zAxis.z = zAxis.z / length;
// xAxis = normal(cross(up, zAxis))
xAxis.x = (up.y * zAxis.z) - (up.z * zAxis.y);
xAxis.y = (up.z * zAxis.x) - (up.x * zAxis.z);
xAxis.z = (up.x * zAxis.y) - (up.y * zAxis.x);
length = sqrt((xAxis.x * xAxis.x) + (xAxis.y * xAxis.y) + (xAxis.z * xAxis.z));
xAxis.x = xAxis.x / length;
xAxis.y = xAxis.y / length;
xAxis.z = xAxis.z / length;
// yAxis = cross(zAxis, xAxis)
yAxis.x = (zAxis.y * xAxis.z) - (zAxis.z * xAxis.y);
yAxis.y = (zAxis.z * xAxis.x) - (zAxis.x * xAxis.z);
yAxis.z = (zAxis.x * xAxis.y) - (zAxis.y * xAxis.x);
// -dot(xAxis, position)
result1 = ((xAxis.x * position.x) + (xAxis.y * position.y) + (xAxis.z * position.z)) * -1.0f;
// -dot(yaxis, eye)
result2 = ((yAxis.x * position.x) + (yAxis.y * position.y) + (yAxis.z * position.z)) * -1.0f;
// -dot(zaxis, eye)
result3 = ((zAxis.x * position.x) + (zAxis.y * position.y) + (zAxis.z * position.z)) * -1.0f;
// Set the computed values in the view matrix.
result[0] = xAxis.x;
result[1] = yAxis.x;
result[2] = zAxis.x;
result[3] = 0.0f;
result[4] = xAxis.y;
result[5] = yAxis.y;
result[6] = zAxis.y;
result[7] = 0.0f;
result[8] = xAxis.z;
result[9] = yAxis.z;
result[10] = zAxis.z;
result[11] = 0.0f;
result[12] = result1;
result[13] = result2;
result[14] = result3;
result[15] = 1.0f;
}
void 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;
}
void 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;
}
void 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 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;
}
void MatrixRotationZ(float* matrix, float angle)
{
matrix[0] = cosf(angle);
matrix[1] = -sinf(angle);
matrix[2] = 0.0f;
matrix[3] = 0.0f;
matrix[4] = sinf(angle);
matrix[5] = cosf(angle);
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;
}
void 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;
}
编译方法(使用Visual Studio编译工具包):
D:wenliSourceReposGameEngineFromScratchPlatformWindows>cl /EHsc /Z7 opengl32.lib user32.lib gdi32.lib helloengine_opengl.cpp
编译方法(使用Clang-cl):
D:wenliSourceReposGameEngineFromScratchPlatformWindows>clang-cl /EHsc -o helloengine_opengl helloengine_opengl.cpp user32.lib gdi32.lib opengl32.lib
编译方法(使用Clang):
D:wenliSourceReposGameEngineFromScratchPlatformWindows>clang -o helloengine_opengl helloengine_opengl.cpp -luser32 -lgdi32 -lopengl32
helloengine_opengl-99755a.o : warning LNK4217: 本地定义的符号 ___std_terminate 在函数 "int `public: virtual __thiscall std::basic_filebuf<char,struct std::char_traits<char> >::~basic_filebuf<char,struct std::char_traits<char> >(void)'::`1'::dtor$8" (?dtor$8@?0???1?$basic_filebuf@DU?$char_traits@D@std@@@std@@UAE@XZ@4HA) 中导入
helloengine_opengl-99755a.o : warning LNK4217: 本地定义的符号 __CxxThrowException@8 在函数 "class std::codecvt<char,char,struct _Mbstatet> const & __cdecl std::use_facet<class std::codecvt<char,char,struct _Mbstatet> >(class std::locale const &)" (??$use_facet@V?$codecvt@DDU_Mbstatet@@@std@@@std@@YAABV?$codecvt@DDU_Mbstatet@@@0@ABVlocale@0@@Z) 中导入
会出两个warning,这是因为我们目前这个代码是Windows平台专用的,在C++的异常模式方面,有一些Clang的小小兼容问题(用Clang-cl /EHsc可以解决这个问题),但是可以无视。
Shader程序(需要放在和源代码一个目录):
color.vs
////////////////////////////////////////////////////////////////////////////////
// Filename: color.vs
////////////////////////////////////////////////////////////////////////////////
#version 400
/////////////////////
// INPUT VARIABLES //
/////////////////////
in vec3 inputPosition;
in vec3 inputColor;
//////////////////////
// OUTPUT VARIABLES //
//////////////////////
out vec3 color;
///////////////////////
// UNIFORM VARIABLES //
///////////////////////
uniform mat4 worldMatrix;
uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;
////////////////////////////////////////////////////////////////////////////////
// Vertex Shader
////////////////////////////////////////////////////////////////////////////////
void main(void)
{
// Calculate the position of the vertex against the world, view, and projection matrices.
gl_Position = worldMatrix * vec4(inputPosition, 1.0f);
gl_Position = viewMatrix * gl_Position;
gl_Position = projectionMatrix * gl_Position;
// Store the input color for the pixel shader to use.
color = inputColor;
}
////////////////////////////////////////////////////////////////////////////////
// Filename: color.ps
////////////////////////////////////////////////////////////////////////////////
#version 400
/////////////////////
// INPUT VARIABLES //
/////////////////////
in vec3 color;
//////////////////////
// OUTPUT VARIABLES //
//////////////////////
out vec4 outputColor;
////////////////////////////////////////////////////////////////////////////////
// Pixel Shader
////////////////////////////////////////////////////////////////////////////////
void main(void)
{
outputColor = vec4(color, 1.0f);
}
最后的运行效果如下图:
截图工具的关系,动画的颜色比较少,出现明显的色阶:
篇幅关系,代码的说明在后面的文章进行。