OpenGL 4 со стандартного Windows SDK

157
28 апреля 2019, 20:30

хотел подключить OpenGL 4 стандартными средствами Windows SDK ко своему проекту на С++, не используя сторонние библиотеки на подобии glut, glfw и т.д.. Opengl 1 подключался прекрасно, когда я использовал следующее:

// В файлах проекта:
#include <Windows.h>
#include <gl/GL.h>
#include <gl/GLU.h>
// в CMake
target_link_libraries (ProjectName opengl32.lib glu32.lib)

Но а вот когда я решил использовать функции шейдеров, VAO, VBO, то их просто не оказалось, но думаю старая версия OpenGL стоит на винде... Скачал OpenGL Extension Viewer и как оказалось, была у меня установлена OpenGL 1.1. После чего я обновил OpenGL до версии 4.4, но у меня так и не получается использовать функции шейдеров, VAO, VBO. Хотел спросить может каких хедеров не хватает или стоит еще дополнительные библиотеки прилинковать или что-то я не дообновил?

Answer 1

Дело в том, что системная библиотека opengl32.dll предоставляет только базовые функции, существовавшие во время OpenGL 1.1.

Доступ к более новым возможностям можно получить с помощью функции wglGetProcAddress(). В качестве параметра ей необходимо передать имя требуемой функции, а возвращаемый указатель — преобразовать в тип PFNИМЯФУНКЦИИPROC (типы объявлены в <GL/glext.h>). Пример:

const PFNGLCOMPILESHADERPROC _glCompileShader =
     reinterpret_cast<PFNGLCOMPILESHADERPROC>(wglGetProcAddress("glCompileShader"));

Примечание: для работы с OpenGL таким способом требуется наличие трёх заголовочных файлов, отсутствующих в стандартной поставке Windows SDK. Эти файлы необходимо скачать с сайта компании-создателя OpenGL и разместить в папке проекта следующим рекомендуемым образом:

  • https://www.khronos.org/registry/OpenGL/api/GL/glext.h → папка_проекта/include/GL/glext.h
  • https://www.khronos.org/registry/OpenGL/api/GL/wglext.h → папка_проекта/include/GL/wglext.h
  • https://www.khronos.org/registry/EGL/api/KHR/khrplatform.h → папка_проекта/include/KHR/khrplatform.h

При этом необходимо указать CMake на наличие этих файлов:

target_include_directories (ProjectName include)

Также необходимо вручную создать контекст, поддерживающий OpenGL 4. Создание OpenGL-контекста происходит в два этапа:

  1. Сначала создаём контекст версии 1.1 для корректной работы wglGetProcAddress().
  2. Затем получаем указатель на функцию wglCreateContextAttribsARB() и используем её для создания уже нужного нам контекста.

Ниже приведены функции создания и уничтожения контекста:

#include <windows.h>
#include <GL/gl.h>
#define WGL_WGLEXT_PROTOTYPES
#include <GL/wglext.h>
// Параметры начального контекста
static const PIXELFORMATDESCRIPTOR pfd =
{
    /* nSize          */ sizeof(PIXELFORMATDESCRIPTOR),
    /* nVersion       */ 1,
    /* dwFlags        */ PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
    /* iPixelType     */ PFD_TYPE_RGBA,
    /* cColorBits     */ 32,
    /* c...Bits|Shift */ 0, 0, 0, 0, 0, 0, 0, 0,
    /* cAccum...Bits  */ 0, 0, 0, 0, 0,
    /* cDepthBits     */ 16,
    /* cStencilBits   */ 0,
    /* cAuxBuffers    */ 0,
    /* iLayerType     */ PFD_MAIN_PLANE,
    /* bReserved      */ 0,
    /* dw...Mask      */ 0, 0, 0
};
// Параметры конечного контекста (OpenGL 4.0 Core)
static const int context_attributes[] = {
    WGL_CONTEXT_MAJOR_VERSION_ARB, 4,
    WGL_CONTEXT_MINOR_VERSION_ARB, 0,
    WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
    0
};
// Функция для создания контекста OpenGL 4. Принимает HWND окна вывода, возвращает
// дескриптор GL-контекста.
HGLRC gl_init(HWND default_output)
{
    const HDC canvas = GetDC(default_output);
    // Этап 1
    HGLRC gl = NULL;
    const int format = ChoosePixelFormat(canvas, &pfd);
    if (format != 0) {
        SetPixelFormat(canvas, format, &pfd);
        const HGLRC gl_boostrap = wglCreateContext(canvas);
        wglMakeCurrent(canvas, gl_boostrap);
        // Этап 2
        gl = reinterpret_cast<PFNWGLCREATECONTEXTATRIBSARBPROC>
            (wglGetProcAddress("wglCreateContextAttribsARB"))
            (canvas, NULL, context_attributes);
        wglMakeCurrent(canvas, gl);
        wglDeleteContext(gl_boostrap);
    }
    // Удаляем более не требуемый начальный контекст и возвращаем конечный
    ReleaseDC(default_output, canvas);
    return gl;
}
// Функция для уничтожения GL контекста. Принимает HWND окна вывода и дескриптор
// GL-контекста. Можно было бы ограничиться и HWND, но у некоторых драйверов для 
// интегрированной графики Intel функция wglMakeCurrent() не работает при нулевом
// значении параметра с GL-дескриптором.
void gl_release(HWND default_output, HGLRC gl)
{
    const HDC hdc = GetDC(default_output);
    wglMakeCurrent(hdc, NULL);
    ReleaseDC(default_output, hdc);
    wglDeleteContext(gl);
}
READ ALSO
Stack overflow c++ (где моя память?)

Stack overflow c++ (где моя память?)

Пишу программу для реверса символов в предложении (с помощью рекурсивной функции, обязательно)При первом же входе в функцию VS начинает орать...

152
нагрузка на CPU из-за потоков в dll c++

нагрузка на CPU из-за потоков в dll c++

есть такого типа код:

136
Как использовать glm::ortho?

Как использовать glm::ortho?

Хочу получить результат, как, например, в Blender, в ортогональном режиме

145
Не создаются значения в реестре

Не создаются значения в реестре

У меня есть два QSettings в разных файлах, у одного все значения передаются в реестр, а другого - нет

170