基於OpenGL編寫一個簡易的2D渲染框架-02 搭建OpenGL環境


由於沒有使用GLFW庫,接下來得費一番功夫。

閱讀這篇文章前請看一下這個網頁:https://learnopengl-cn.github.io/01%20Getting%20started/02%20Creating%20a%20window/

 

以下,我摘取了一點片段

 

Windows上的OpenGL庫

  如果你是Windows平台,opengl32.lib已經包含在Microsoft SDK里了,它在Visual Studio安裝的時候就默認安裝了。由於這篇教程用的是VS編譯器,並且是在Windows操作系統上,我們只需將opengl32.lib添加進連接器設置里就行了。

GLEW

到這里,我們仍然有一件事要做。因為OpenGL只是一個標准/規范,具體的實現是由驅動開發商針對特定顯卡實現的。由於OpenGL驅動版本眾多,它大多數函數的位置都無法在編譯時確定下來,需要在運行時查詢。任務就落在了開發者身上,開發者需要在運行時獲取函數地址並將其保存在一個函數指針中供以后使用。取得地址的方法因平台而異,在Windows上會是類似這樣:

// 定義函數原型
typedef void (*GL_GENBUFFERS) (GLsizei, GLuint*);
// 找到正確的函數並賦值給函數指針
GL_GENBUFFERS glGenBuffers  = (GL_GENBUFFERS)wglGetProcAddress("glGenBuffers");
// 現在函數可以被正常調用了
GLuint buffer;
glGenBuffers(1, &buffer);

你可以看到代碼非常復雜,而且很繁瑣,我們需要對每個可能使用的函數都要重復這個過程。幸運的是,有些庫能簡化此過程,其中GLEW是目前最新,也是最流行的庫。

編譯和鏈接GLEW

  GLEW是OpenGL Extension Wrangler Library的縮寫,它能解決我們上面提到的那個繁瑣的問題。因為GLEW也是一個庫,我們同樣需要構建並將其鏈接進工程。GLEW可以從這里下載,你同樣可以選擇下載二進制版本,如果你的目標平台列在上面的話,或者下載源碼編譯,步驟和編譯GLFW時差不多。記住,如果不確定的話,選擇32位的二進制版本。

  我們使用GLEW的靜態版本glew32s.lib(注意這里的“s”),將庫文件添加到你的庫目錄,將include內容添加到你的include目錄。接下來,在VS的鏈接器選項里加上glew32s.lib。注意GLFW3(默認)也是編譯成了一個靜態庫。

  如果你希望靜態鏈接GLEW,必須在包含GLEW頭文件之前定義預處理器宏GLEW_STATIC

#define GLEW_STATIC
#include <GL/glew.h>

如果你希望動態鏈接,那么你可以省略這個宏。但是記住使用動態鏈接的話你需要拷貝一份.DLL文件到你的應用程序目錄。

接下來要做的是鏈接 opengl32.lib 和 glew32s.lib這 兩個庫進工程

在Windows中,OpenGL命令是通過OpenGL Render Context(以下簡稱RC)來執行的。這個RC是OpenGL和Windows之間的紐帶。

每個RC創建時,必須指定一個DC(Windows Device Context 也就是那個通常用於GDI的設備環境DC)。RC的繪制目標,就是這個DC所對應的窗口。

每次RC創建時,應該設置一下DC的像素格式。

 

添加一個新類 GraphicsContext 頭文件

#pragma once
#define GLEW_STATIC

#include "Common.h"
#include <Windows.h>
#include "GLEW\glew.h"

namespace Simple2D
{
    class RenderWindow;

    class DLL_export GraphicsContext
    {
    public:
        GraphicsContext(RenderWindow* renderWindow);
        ~GraphicsContext();

        void createOpenGLContext();
        void flip();

    private:
        RenderWindow* pRenderWindow;

        HGLRC openglContext;
        HDC deviceContext;
    };
}

注意代碼中的這個宏  #define GLEW_STATIC,沒有它你可能編譯錯誤。

它的實現

#include "GraphicsContext.h"
#include "RenderWindow.h"

namespace Simple2D
{
    GraphicsContext::GraphicsContext(RenderWindow* renderWindow)
        : pRenderWindow(renderWindow)
        , openglRenderContext(0)
        , deviceContext(0)
    {
        this->createOpenGLContext();
    }

    GraphicsContext::~GraphicsContext()
    {
        wglDeleteContext(openglRenderContext);
        ReleaseDC(pRenderWindow->getHwnd(), deviceContext);
    }

    void GraphicsContext::createOpenGLContext()
    {
        if ( openglRenderContext == 0 ) {
            deviceContext = GetDC(pRenderWindow->getHwnd());

            PIXELFORMATDESCRIPTOR pfd = { 0 };
            int color_deep = GetDeviceCaps(deviceContext, BITSPIXEL);

            pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
            pfd.nVersion = 1;
            pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
            pfd.iPixelType = PFD_TYPE_RGBA;
            pfd.cColorBits = color_deep;
            pfd.cDepthBits = 0;
            pfd.cStencilBits = 0;
            pfd.iLayerType = PFD_MAIN_PLANE;

            int pixle_format = ChoosePixelFormat(deviceContext, &pfd);
            SetPixelFormat(deviceContext, pixle_format, &pfd);

            /* 創建 OpenGL 渲染上下文 */
            openglRenderContext = wglCreateContext(deviceContext);
            if ( openglRenderContext == 0 ) exit(0);

            /* 選擇 openglRenderContext 作為當前線程的 openglRenderContext */
            if ( wglMakeCurrent(deviceContext, openglRenderContext) == 0 ) exit(1);

            /* GLEW 是用來管理 OpenGL 的函數指針的,所以在調用任何 OpenGL 的函數之前我們需要初始化GLEW */
            if ( glewInit() != GLEW_OK ) exit(1);

            /* 設置視口,大小為客戶區大小 */
            SIZE size = pRenderWindow->getClientSize();
            glViewport(0, 0, size.cx, size.cy);
        }
    }

    void GraphicsContext::flip()
    {
        /* 使用一個自定義的顏色清空屏幕,這里使用紅色 */
        glClearColor(1.0f, 0, 0, 1.0f);

        /* 調用glClear函數來清空屏幕的顏色緩沖 */
        glClear(GL_COLOR_BUFFER_BIT);

        // 交換當前緩沖區和后台緩沖區
        SwapBuffers(deviceContext);
    }
}

 

最后在主函數中創建 GraphicsContext

#pragma once

#include <Windows.h>
#include "RenderWindow.h"
#include "GraphicsContext.h"

using namespace Simple2D;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    RenderWindow window(DEFAULT_WIN_W, DEFAULT_WIN_H);
    GraphicsContext graphicsContext(&window);

    MSG msg = { 0 };
    while ( msg.message != WM_QUIT ) {
        if ( PeekMessage(&msg, 0, 0, 0, PM_REMOVE) ) {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        else {
            graphicsContext.flip();
        }
    }

    return 0;
}

 

編譯代碼,如果出現以下錯誤

可以在項目中忽略這個庫

運行后出現這個窗口,顯示為紅色,證明搭建成功了

需要源碼的可以點擊這個鏈接:http://files.cnblogs.com/files/ForEmail5/Simple2D-02.rar


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM