outdated: 45.Vertex Buffer Objects
这一节主要说的是VBO.
VBO初始化时的代码,
// Check for VBOs supported #ifndef NO_VBOS g_fVBOSupported = IsExtensionSupported("GL_ARB_vertex_buffer_object"); if (g_fVBOSupported) { // Get pointer glGenBuffersARB = (PFNGLGENBUFFERSARBPROC)wglGetProcAddress("glGenBuffersARB"); glBindBufferARB = (PFNGLBINDBUFFERARBPROC)wglGetProcAddress("glBindBufferARB"); glBufferDataARB = (PFNGLBUFFERDATAARBPROC)wglGetProcAddress("glBufferDataARB"); glDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC)wglGetProcAddress("glDeleteBuffersARB"); // Load vertex data into the graphics card memory g_pMesh->BuildVBOs(); } #else g_fVBOSupported = false; #endif // !NO_VBOS
BuildVBOs()函数,
// VBO: Vertex Buffer Objects use high-performance graphics card memory // instead of your standard, ram-allocated memory void CMesh::BuildVBOs() { // Generate and bind the vertex buffer glGenBuffersARB(1, &m_nVBOVertices); glBindBufferARB(GL_ARRAY_BUFFER_ARB, m_nVBOVertices); // Load data glBufferDataARB(GL_ARRAY_BUFFER_ARB, m_nVertexCount * 3 * sizeof(float), m_pVertices, GL_STATIC_DRAW_ARB); // Generate and bind the texture coordinate buffer glGenBuffersARB(1, &m_nVBOTexCoords); glBindBufferARB(GL_ARRAY_BUFFER_ARB, m_nVBOTexCoords); // Load data glBufferDataARB(GL_ARRAY_BUFFER_ARB, m_nVertexCount * 2 * sizeof(float), m_pTexCoords, GL_STATIC_DRAW_ARB); delete[] m_pVertices; m_pVertices = NULL; delete[] m_pTexCoords; m_pTexCoords = NULL; }
下面为代码,顺便改了下方向键,W/S/A/D/UP/DOWN/LEFT/RIGHT。
#ifndef GL_FRAMEWORK_INCLUDED #define GL_FRAMEWORK_INCLUDED #include <windows.h> typedef struct { // Structure for keyboard stuff BOOL keyDown[256]; } Keys; typedef struct { // Contains information vital to applications HMODULE hInstance; // Application Instance const char* className; } Application; typedef struct { // Window creation info Application* application; char* title; int width; int height; int bitsPerPixel; BOOL isFullScreen; } GL_WindowInit; typedef struct { // Contains information vital to a window Keys* keys; HWND hWnd; // Windows handle HDC hDC; // Device context HGLRC hRC; // Rendering context GL_WindowInit init; BOOL isVisible; // Window visiable? DWORD lastTickCount; // Tick counter } GL_Window; void TerminateApplication(GL_Window* window); // Terminate the application void ToggleFullscreen(GL_Window* window); // Toggle fullscreen / Windowed mode BOOL Initialize(GL_Window* window, Keys* keys); void Deinitialize(void); void Update(DWORD milliseconds); void Draw(void); #endif
#include <Windows.h> #include <GL\glew.h> #include <GL\glut.h> #include "Previous.h" #define WM_TOGGLEFULLSCREEN (WM_USER+1) // Application define message for toggling // between fulscreen / windowed mode static BOOL g_isProgramLooping; // Window creation loop, for fullscreen / windowed mode static BOOL g_createFullScreen; // If true, then create window void TerminateApplication(GL_Window* window) // Terminate the application { PostMessage(window->hWnd, WM_QUIT, 0, 0); // Send a WM_QUIT message g_isProgramLooping = FALSE; // Stop looping of the program } void ToggleFullscreen(GL_Window* window) // Toggle fullscreen /windowed mode { PostMessage(window->hWnd, WM_TOGGLEFULLSCREEN, 0, 0); // Send a WM_TOGGLEFULLSCREEN message } void ReshapeGL(int width, int height) // Reshape the window when it's moved or resized { glViewport(0, 0, (GLsizei)(width), (GLsizei)(height)); // Reset the current viewport glMatrixMode(GL_PROJECTION); glLoadIdentity(); // Calcutate the aspect ratio of the window gluPerspective(45.0f, (GLfloat)(width) / (GLfloat)(height), 1.0, 1000.0f); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } BOOL ChangeScreenResolution(int width, int height, int bitsPerPixel) // Change the screen resolution { DEVMODE dmScreenSettings; // Device mode ZeroMemory(&dmScreenSettings, sizeof(DEVMODE)); // Make sure memory is cleared dmScreenSettings.dmSize = sizeof(DEVMODE); // Size of the devmode structure dmScreenSettings.dmPelsWidth = width; dmScreenSettings.dmPelsHeight = height; dmScreenSettings.dmBitsPerPel = bitsPerPixel; dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; if (ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) { return FALSE; // Display change failed } return TRUE; } BOOL CreateWindowGL(GL_Window* window) { DWORD windowStyle = WS_OVERLAPPEDWINDOW; // Define window style DWORD windowExtendedStyle = WS_EX_APPWINDOW; // Define the window's extended style PIXELFORMATDESCRIPTOR pdf = { sizeof(PIXELFORMATDESCRIPTOR), // Size of this pixel format descriptor 1, // Version Number PFD_DRAW_TO_WINDOW | // Format must support window PFD_SUPPORT_OPENGL | // Format must support openGL PFD_DOUBLEBUFFER, // Must support double buffering PFD_TYPE_RGBA, // Request an RGBA format window->init.bitsPerPixel, // Select color depth 0, 0, 0, 0, 0, 0, // Color bits ignored 0, // No alpha buffer 0, // Shift bit ignored 0, // No accumulation buffer 0, 0, 0, 0, // Accumulation bits ignored 16, // 16bits Z-buffer (depth buffer) 0, // No stencil buffer 0, // No auxiliary buffer PFD_MAIN_PLANE, // Main drawing layer 0, // Reserved 0, 0, 0 // Layer masks ignored }; RECT windowRect = { 0, 0, window->init.width, window->init.height }; // Window coordiantes GLuint PixelFormat; if (window->init.isFullScreen == TRUE) { if (ChangeScreenResolution(window->init.width, window->init.height, window->init.bitsPerPixel) == FALSE) { // Fullscreen mode failed, run in windowed mode instead MessageBox(HWND_DESKTOP, "Mode Switch Failed.\nRuning In Windowed Mode.", "Error", MB_OK | MB_ICONEXCLAMATION); window->init.isFullScreen = FALSE; } else { ShowCursor(FALSE); windowStyle = WS_POPUP; // Popup window windowExtendedStyle |= WS_EX_TOPMOST; } } else { // Adjust window, account for window borders AdjustWindowRectEx(&windowRect, windowStyle, 0, windowExtendedStyle); } // Create Opengl window window->hWnd = CreateWindowEx(windowExtendedStyle, // Extended style window->init.application->className, // Class name window->init.title, // Window title windowStyle, // Window style 0, 0, // Window X,Y position windowRect.right - windowRect.left, // Window width windowRect.bottom - windowRect.top, // Window height HWND_DESKTOP, // Desktop is window's parent 0, // No menu window->init.application->hInstance, // Pass the window instance window); if (window->hWnd == 0) { // Was window creation a success? return FALSE; } window->hDC = GetDC(window->hWnd); if (window->hDC == 0) { DestroyWindow(window->hWnd); window->hWnd = 0; return FALSE; } PixelFormat = ChoosePixelFormat(window->hDC, &pdf); // Find a compatible pixel format if (PixelFormat == 0) { ReleaseDC(window->hWnd, window->hDC); // Release device context window->hDC = 0; DestroyWindow(window->hWnd); window->hWnd = 0; return FALSE; } if (SetPixelFormat(window->hDC, PixelFormat, &pdf) == FALSE) { // Try to set the pixel format ReleaseDC(window->hWnd, window->hDC); window->hDC = 0; DestroyWindow(window->hWnd); window->hWnd = 0; return FALSE; } window->hRC = wglCreateContext(window->hDC); // Try to get a rendering context if (window->hRC == 0) { ReleaseDC(window->hWnd, window->hDC); window->hDC = 0; DestroyWindow(window->hWnd); window->hWnd = 0; return FALSE; } // Make the rendering context our current rendering context if (wglMakeCurrent(window->hDC, window->hRC) == FALSE) { wglDeleteContext(window->hRC); // Delete the rendering context window->hRC = 0; ReleaseDC(window->hWnd, window->hDC); window->hDC = 0; DestroyWindow(window->hWnd); window->hWnd = 0; return FALSE; } ShowWindow(window->hWnd, SW_NORMAL); // Make the window visiable window->isVisible = TRUE; ReshapeGL(window->init.width, window->init.height); // Reshape our GL window ZeroMemory(window->keys, sizeof(Keys)); // Clear all keys window->lastTickCount = GetTickCount(); return TRUE; } BOOL DestroyWindowGL(GL_Window* window) { if (window->hWnd != 0) { if (window->hDC != 0) { wglMakeCurrent(window->hDC, 0); // Setting current active rendering context to zero if (window->hRC != 0) { wglDeleteContext(window->hRC); window->hRC = 0; } ReleaseDC(window->hWnd, window->hDC); window->hDC = 0; } DestroyWindow(window->hWnd); window->hWnd = 0; } if (window->init.isFullScreen) { ChangeDisplaySettings(NULL, 0); // Switch back to desktop resolution ShowCursor(TRUE); } return TRUE; } // Process window message callback LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { // Get the window context GL_Window* window = (GL_Window*)(GetWindowLong(hWnd, GWL_USERDATA)); switch (uMsg) { // Evaluate window message case WM_SYSCOMMAND: // Intercept system commands { switch (wParam) { // Check system calls case SC_SCREENSAVE: // Screensaver trying to start? case SC_MONITORPOWER: // Mointer trying to enter powersave? return 0; // Prevent form happening } break; } return 0; case WM_CREATE: { CREATESTRUCT* creation = (CREATESTRUCT*)(lParam); // Store window structure pointer window = (GL_Window*)(creation->lpCreateParams); SetWindowLong(hWnd, GWL_USERDATA, (LONG)(window)); } return 0; case WM_CLOSE: TerminateApplication(window); return 0; case WM_SIZE: switch (wParam) { case SIZE_MINIMIZED: // Was window minimized? window->isVisible = FALSE; return 0; case SIZE_MAXIMIZED: window->isVisible = TRUE; ReshapeGL(LOWORD(lParam), HIWORD(lParam)); return 0; case SIZE_RESTORED: window->isVisible = TRUE; ReshapeGL(LOWORD(lParam), HIWORD(lParam)); return 0; } break; case WM_KEYDOWN: if ((wParam >= 0) && (wParam <= 255)) { window->keys->keyDown[wParam] = TRUE; // Set the selected key(wParam) to true return 0; } break; case WM_KEYUP: if ((wParam >= 0) && (wParam <= 255)) { window->keys->keyDown[wParam] = FALSE; return 0; } break; case WM_TOGGLEFULLSCREEN: g_createFullScreen = (g_createFullScreen == TRUE) ? FALSE : TRUE; PostMessage(hWnd, WM_QUIT, 0, 0); break; } return DefWindowProc(hWnd, uMsg, wParam, lParam); // Pass unhandle message to DefWindowProc } BOOL RegisterWindowClass(Application* application) { WNDCLASSEX windowClass; ZeroMemory(&windowClass, sizeof(WNDCLASSEX)); // Make sure memory is cleared windowClass.cbSize = sizeof(WNDCLASSEX); // Size of the windowClass structure windowClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; // Redraws the window for any movement / resizing windowClass.lpfnWndProc = (WNDPROC)(WindowProc); // WindowProc handles message windowClass.hInstance = application->hInstance; // Set the instance windowClass.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE);// Class background brush color windowClass.hCursor = LoadCursor(NULL, IDC_ARROW); // Load the arrow pointer windowClass.lpszClassName = application->className; // Sets the application className if (RegisterClassEx(&windowClass) == 0) { MessageBox(HWND_DESKTOP, "RegisterClassEx Failed!", "Error", MB_OK | MB_ICONEXCLAMATION); return FALSE; } return TRUE; } int WINAPI WinMain(HINSTANCE hIstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { Application application; GL_Window window; Keys keys; BOOL isMessagePumpActive; MSG msg; DWORD tickCount; application.className = "OpenGL"; application.hInstance = hIstance; ZeroMemory(&window, sizeof(GL_Window)); window.keys = &keys; // Window key structure window.init.application = &application; // Window application window.init.title = "Resource File"; // Window title window.init.width = 640; // Window width window.init.height = 480; // Window height window.init.bitsPerPixel = 16; // Bits per pixel window.init.isFullScreen = TRUE; // Fullscreen? (set to TRUE) ZeroMemory(&keys, sizeof(Keys)); if (MessageBox(HWND_DESKTOP, "Would You Like To Run In Fullscreen Mode?", "Start FullScreen?", MB_YESNO | MB_ICONQUESTION) == IDNO) { window.init.isFullScreen = FALSE; } if (RegisterWindowClass(&application) == FALSE) { MessageBox(HWND_DESKTOP, "Error Registering Window Class!", "Error", MB_OK | MB_ICONEXCLAMATION); return -1; } g_isProgramLooping = TRUE; g_createFullScreen = window.init.isFullScreen; while (g_isProgramLooping) { // Loop until WM_QUIT is received window.init.isFullScreen = g_createFullScreen; // Set init param of window creation to fullscreen? if (CreateWindowGL(&window) == TRUE) { // Was window creation successful? // At this point we should have a window that is setup to render OpenGL if (Initialize(&window, &keys) == FALSE) { TerminateApplication(&window); // Close window, this will handle the shutdown } else { isMessagePumpActive = TRUE; while (isMessagePumpActive == TRUE) { // Success creating window. Check for window messages if (PeekMessage(&msg, window.hWnd, 0, 0, PM_REMOVE) != 0) { if (msg.message != WM_QUIT) { DispatchMessage(&msg); } else { isMessagePumpActive = FALSE; // Terminate the message pump } } else { if (window.isVisible == FALSE) { WaitMessage(); // Application is minimized wait for a message } else { // Process application loop tickCount = GetTickCount(); // Get the tick count Update(tickCount - window.lastTickCount); // Update the counter window.lastTickCount = tickCount;// Set last count to current count Draw(); // Draw screen SwapBuffers(window.hDC); } } } } // Application is finished Deinitialize(); DestroyWindowGL(&window); } else { MessageBox(HWND_DESKTOP, "Error Creating OpenGL Window", "Error", MB_OK | MB_ICONEXCLAMATION); g_isProgramLooping = FALSE; } } UnregisterClass(application.className, application.hInstance); // UnRegister window class return 0; }
#include <windows.h> #include <stdio.h> #include <math.h> #include <gl/glew.h> #include <gl/glut.h> #include <GL/GLUAX.H> #include <mmsystem.h> #include "Previous.h" #pragma comment(lib, "legacy_stdio_definitions.lib") #ifndef CDS_FULLSCREEN #define CDS_FULLSCREEN 4 #endif #define MESH_RESOLUTION 4.0f // Pixels per vertex #define MESH_HEIGHTSCALE 1.0f // Mesh height scale #define GL_ARRAY_BUFFER_ARB 0x8892 // VBO extension definitions #define GL_STATIC_DRAW_ARB 0x88E4 typedef void (APIENTRY * PFNGLBINDBUFFERARBPROC) (GLenum target, GLuint buffer); typedef void (APIENTRY * PFNGLDELETEBUFFERSARBPROC) (GLsizei n, const GLuint *buffers); typedef void (APIENTRY * PFNGLGENBUFFERSARBPROC) (GLsizei n, GLuint *buffers); typedef void (APIENTRY * PFNGLBUFFERDATAARBPROC) (GLenum target, int size, const GLvoid *data, GLenum usage); // VBO extension function pointers PFNGLGENBUFFERSARBPROC glGenBuffersARB = NULL; // VBO name generation procedure PFNGLBINDBUFFERARBPROC glBindBufferARB = NULL; // VBO bind procedure PFNGLBUFFERDATAARBPROC glBufferDataARB = NULL; // VBO data loading procedure PFNGLDELETEBUFFERSARBPROC glDeleteBuffersARB = NULL; // VBO deletion procedure class CVert { // Vertex public: float x; float y; float z; }; class CTexCoord { // Texture coordinate public: float u; float v; }; class CMesh { public: // Mesh data int m_nVertexCount; // Vertex count CVert* m_pVertices; // Vertex data CTexCoord* m_pTexCoords; // Texture coordinate unsigned int m_nTextureId; // Texture ID // Vertex buffer object name unsigned int m_nVBOVertices; // Vertex VBO name unsigned int m_nVBOTexCoords; // Texture coordinate VBO name // Temporary data AUX_RGBImageRec* m_pTextureImage; // Heightmap data public: CMesh(); ~CMesh(); bool LoadHeightmap(char* szPath, float flHeightScale, float flResolution); float PtHeight(int nX, int nY); // Single point height void BuildVBOs(); // Build function }; bool g_fVBOSupported = false; CMesh* g_pMesh = NULL; // Mesh data float g_flYRot = 0.0f; // Rotation float g_flXRot = 0.0f; float DisX = 0.0f; float DisZ = 0.0f; int g_nFPS = 0, g_nFrames = 0; // FPS and FPS counter DWORD g_dwLastFPS = 0; // Last FPS check time GL_Window* g_window; Keys* g_keys; CMesh::CMesh() { m_pTextureImage = NULL; m_pVertices = NULL; m_pTexCoords = NULL; m_nVertexCount = 0; m_nVBOVertices = m_nVBOTexCoords = m_nTextureId = 0; } CMesh :: ~CMesh() { // Delete VBOs if (g_fVBOSupported) { unsigned int nBuffers[2] = { m_nVBOVertices, m_nVBOTexCoords }; glDeleteBuffersARB(2, nBuffers); } if (m_pVertices) { delete[] m_pVertices; } m_pVertices = NULL; if (m_pTexCoords) { delete[] m_pTexCoords; } m_pTexCoords = NULL; } bool CMesh::LoadHeightmap(char* szPath, float flHeightScale, float flResolution) { FILE* fTest = fopen(szPath, "r"); if (!fTest) { return false; } fclose(fTest); m_pTextureImage = auxDIBImageLoad(szPath); // (( Terrain Width / Resolution ) * ( Terrain Length / Resolution ) * // 3 Vertices in a Triangle * 2 Triangles in a Square ) m_nVertexCount = (int)(m_pTextureImage->sizeX * m_pTextureImage->sizeY * 6 / (flResolution * flResolution)); m_pVertices = new CVert[m_nVertexCount]; // Vertex data m_pTexCoords = new CTexCoord[m_nVertexCount]; // Tex coord data int nX, nZ, nTri, nIndex = 0; float flX, flZ; for (nZ = 0; nZ < m_pTextureImage->sizeY; nZ += (int)flResolution) { for (nX = 0; nX < m_pTextureImage->sizeX; nX += (int)flResolution) { for (nTri = 0; nTri < 6; ++nTri) { flX = (float)nX + ((nTri == 1 || nTri == 2 || nTri == 5) ? flResolution : 0.0f); flZ = (float)nZ + ((nTri == 2 || nTri == 4 || nTri == 5) ? flResolution : 0.0f); // Using PtHeight to obtain the Y value m_pVertices[nIndex].x = flX - (m_pTextureImage->sizeX / 2); m_pVertices[nIndex].y = PtHeight((int)flX, (int)flZ) * flHeightScale; m_pVertices[nIndex].z = flZ - (m_pTextureImage->sizeY / 2); // Texture coordinate m_pTexCoords[nIndex].u = flX / m_pTextureImage->sizeX; m_pTexCoords[nIndex].v = flZ / m_pTextureImage->sizeY; nIndex++; } } } glGenTextures(1, &m_nTextureId); glBindTexture(GL_TEXTURE_2D, m_nTextureId); glTexImage2D(GL_TEXTURE_2D, 0, 3, m_pTextureImage->sizeX, m_pTextureImage->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, m_pTextureImage->data); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); if (m_pTextureImage) { if (m_pTextureImage->data) { delete[] m_pTextureImage->data; } delete[] m_pTextureImage; } return true; } float CMesh::PtHeight(int nX, int nY) { // Calculate the position in the texture int nPos = ((nX % m_pTextureImage->sizeX) + ((nY % m_pTextureImage->sizeY) * m_pTextureImage->sizeX)) * 3; float flR = (float)m_pTextureImage->data[nPos]; float flG = (float)m_pTextureImage->data[nPos + 1]; float flB = (float)m_pTextureImage->data[nPos + 2]; // Calculate the height using the luminance algorithm return (0.229f * flR + 0.587f * flG + 0.114f * flB); } // VBO: Vertex Buffer Objects use high-performance graphics card memory // instead of your standard, ram-allocated memory void CMesh::BuildVBOs() { // Generate and bind the vertex buffer glGenBuffersARB(1, &m_nVBOVertices); glBindBufferARB(GL_ARRAY_BUFFER_ARB, m_nVBOVertices); // Load data glBufferDataARB(GL_ARRAY_BUFFER_ARB, m_nVertexCount * 3 * sizeof(float), m_pVertices, GL_STATIC_DRAW_ARB); // Generate and bind the texture coordinate buffer glGenBuffersARB(1, &m_nVBOTexCoords); glBindBufferARB(GL_ARRAY_BUFFER_ARB, m_nVBOTexCoords); // Load data glBufferDataARB(GL_ARRAY_BUFFER_ARB, m_nVertexCount * 2 * sizeof(float), m_pTexCoords, GL_STATIC_DRAW_ARB); delete[] m_pVertices; m_pVertices = NULL; delete[] m_pTexCoords; m_pTexCoords = NULL; } bool IsExtensionSupported(char* szTargetExtension) { const unsigned char* pszExtensions = NULL; const unsigned char* pszStart; unsigned char* pszWhere; unsigned char* pszTerminator; // Extension names should not have spaces pszWhere = (unsigned char*)strchr(szTargetExtension, ' '); if (!pszWhere || *szTargetExtension == '\0') { return false; } // Get extension string pszExtensions = glGetString(GL_EXTENSIONS); // Search the extensions string for an exact copy pszStart = pszExtensions; for (;;) { pszWhere = (unsigned char*)strstr((const char*)pszStart, szTargetExtension); if (!pszWhere) { break; } pszTerminator = pszWhere + strlen(szTargetExtension); if (pszWhere == pszStart || *(pszWhere - 1) == ' ') { if (*pszTerminator == ' ' || *pszTerminator == '\0') { return true; } } pszStart = pszTerminator; } return false; } BOOL Initialize(GL_Window* window, Keys* keys) { g_window = window; g_keys = keys; g_pMesh = new CMesh(); if (!g_pMesh->LoadHeightmap("Data/terrain.bmp", MESH_HEIGHTSCALE, MESH_RESOLUTION)) { MessageBox(NULL, "Error Loading Heightmap", "Error", MB_OK); return FALSE; } // Check for VBOs supported #ifndef NO_VBOS g_fVBOSupported = IsExtensionSupported("GL_ARB_vertex_buffer_object"); if (g_fVBOSupported) { // Get pointer glGenBuffersARB = (PFNGLGENBUFFERSARBPROC)wglGetProcAddress("glGenBuffersARB"); glBindBufferARB = (PFNGLBINDBUFFERARBPROC)wglGetProcAddress("glBindBufferARB"); glBufferDataARB = (PFNGLBUFFERDATAARBPROC)wglGetProcAddress("glBufferDataARB"); glDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC)wglGetProcAddress("glDeleteBuffersARB"); // Load vertex data into the graphics card memory g_pMesh->BuildVBOs(); } #else g_fVBOSupported = false; #endif // !NO_VBOS glClearColor(0.0f, 0.0f, 0.0f, 0.5f); glClearDepth(1.0f); glDepthFunc(GL_LEQUAL); glEnable(GL_DEPTH_TEST); glShadeModel(GL_SMOOTH); glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); glEnable(GL_TEXTURE_2D); glColor4f(1.0f, 1.0f, 1.0f, 1.0f); return TRUE; } void Deinitialize(void) { if (g_pMesh) { delete g_pMesh; } g_pMesh = NULL; } void Update(DWORD milliseconds) { // g_flYRot += (float)(milliseconds) / 1000.0f * 25.0f; // Consistantly rotate if (g_keys->keyDown[VK_ESCAPE] == TRUE) { TerminateApplication(g_window); } if (g_keys->keyDown[VK_F1] == TRUE) { ToggleFullscreen(g_window); } if (g_keys->keyDown[VK_UP]) { g_flXRot -= 0.1f; if (g_flXRot <= -20.0f) { g_flXRot = -20.0f; } } if (g_keys->keyDown[VK_DOWN]) { g_flXRot += 0.1f; if (g_flXRot >= 20.0f) { g_flXRot = 20.0f; } } if (g_keys->keyDown[VK_LEFT]) { g_flYRot -= 0.1f; } if (g_keys->keyDown[VK_RIGHT]) { g_flYRot += 0.1f; } if (g_keys->keyDown['W']) { DisZ += 0.1f; } if (g_keys->keyDown['S']) { DisZ -= 0.1f; } if (g_keys->keyDown['A']) { DisX += 0.1f; } if (g_keys->keyDown['D']) { DisX -= 0.1f; } } void Draw(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); if (GetTickCount() - g_dwLastFPS >= 1000) { g_dwLastFPS = GetTickCount(); // Update time virable g_nFPS = g_nFrames; // Save the FPS g_nFrames = 0; // Reset the FPS counter char szTitle[256] = { 0 }; sprintf(szTitle, "VBO - %d Triangles, %d FPS", g_pMesh->m_nVertexCount / 3, g_nFPS); if (g_fVBOSupported) { strcat(szTitle, ", Using VBOs"); } else { strcat(szTitle, ", Not Using VBOs"); } SetWindowText(g_window->hWnd, szTitle); } g_nFrames++; glTranslatef(DisX, 0, DisZ); glTranslatef(0.0f, -220.0f, 0.0f); glRotatef(g_flXRot, 1.0f, 0.0f, 0.0f); glRotatef(g_flYRot, 0.0f, 1.0f, 0.0f); // Enable pointer glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); // Set pointer to data if (g_fVBOSupported) { glBindBufferARB(GL_ARRAY_BUFFER_ARB, g_pMesh->m_nVBOVertices); glVertexPointer(3, GL_FLOAT, 0, (char*)NULL); glBindBufferARB(GL_ARRAY_BUFFER_ARB, g_pMesh->m_nVBOTexCoords); glTexCoordPointer(2, GL_FLOAT, 0, (char*)NULL); } else { glVertexPointer(3, GL_FLOAT, 0, g_pMesh->m_pVertices); glTexCoordPointer(2, GL_FLOAT, 0, g_pMesh->m_pTexCoords); } glDrawArrays(GL_TRIANGLES, 0, g_pMesh->m_nVertexCount); // Render glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); }
Thanks for Nehe's tutorials, this is his home.