首页 > 代码库 > outdated: 45.Vertex Buffer Objects

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 memoryvoid 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 applicationvoid ToggleFullscreen(GL_Window* window);          // Toggle fullscreen / Windowed modeBOOL Initialize(GL_Window* window, Keys* keys);void Deinitialize(void);void Update(DWORD milliseconds);void Draw(void);#endif
Previous.h
技术分享
#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 modestatic BOOL g_isProgramLooping;                           // Window creation loop, for fullscreen / windowed modestatic BOOL g_createFullScreen;                           // If true, then create windowvoid 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 callbackLRESULT 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;}
Previous.cpp
技术分享
#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 0x88E4typedef 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 pointersPFNGLGENBUFFERSARBPROC glGenBuffersARB = NULL;                  // VBO name generation procedurePFNGLBINDBUFFERARBPROC glBindBufferARB = NULL;                  // VBO bind procedurePFNGLBUFFERDATAARBPROC glBufferDataARB = NULL;                  // VBO data loading procedurePFNGLDELETEBUFFERSARBPROC glDeleteBuffersARB = NULL;                // VBO deletion procedureclass CVert {       // Vertexpublic:    float x;    float y;    float z;};class CTexCoord {     // Texture coordinatepublic:    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 datapublic:    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 datafloat g_flYRot = 0.0f;         // Rotationfloat g_flXRot = 0.0f;float DisX = 0.0f;float DisZ = 0.0f;int g_nFPS = 0, g_nFrames = 0;     // FPS and FPS counterDWORD g_dwLastFPS = 0;            // Last FPS check timeGL_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 memoryvoid 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);}
Main.cpp

Thanks for Nehe‘s tutorials, this is his home.

outdated: 45.Vertex Buffer Objects