Поиск…


замечания

OpenGL - это открытый стандарт для рендеринга 2D и 3D-графики с использованием графического оборудования. OpenGL реализован в потрясающем массиве платформ, позволяющих приложениям, нацеленным на OpenGL, быть чрезвычайно гибкими.

Версии

Версия Дата выхода
1,1 1997-03-04
1.2 1998-03-16
1.2.1 1998-10-14
1,3 2001-08-14
1.4 2002-07-24
1,5 2003-07-29
2,0 2004-09-07
2,1 2006-07-02
3.0 2008-08-11
3,1 2009-03-24
3,2 2009-08-03
3,3 2010-03-11
4,0 2010-03-11
4,1 2010-07-26
4,2 2011-08-08
4,3 2012-08-06
4,4 2013-07-22
4.5 2014-08-11

Получение OpenGL

Одно из самых распространенных заблуждений относительно OpenGL заключается в том, что это была библиотека, которую можно было установить из сторонних источников. Это заблуждение приводит ко многим вопросам в форме «Как установить OpenGL» или «Где скачать OpenGL SDK».

Это не то, как OpenGL находит путь в компьютерную систему. OpenGL сам по себе представляет собой всего лишь набор спецификаций для команд, которым должна следовать реализация. Так важно выполнение. И пока реализация OpenGL является частью драйверов GPU. Это может измениться в будущем, когда новый интерфейс программирования GPU позволит по-настоящему реализовать OpenGL в качестве библиотеки, но на данный момент это API программирования для графических драйверов.

Когда OpenGL был впервые выпущен, API как-то нашел свой путь в контракте ABI (Application Binary Interface) Windows, Solaris и Linux (LSB-4 Desktop) в дополнение к его происхождению Sun Irix. Apple следовала и фактически интегрировала OpenGL так глубоко в MacOS X, что доступная версия OpenGL тесно связана с установленной версией MacOS X. Это имеет заметный эффект, что среды системного программирования для этих операционных систем (т.е. компилятор и компоновщик ссылок, которые ориентированы на эти системы) должны также предоставлять определения API OpenGL. Такого нет необходимости фактически устанавливать SDK для OpenGL. Технически возможно программировать OpenGL в этих операционных системах без необходимости установки выделенного SDK, предполагая, что установлена ​​среда сборки после целевого ABI.

Побочным эффектом этих строгих правил ABI является то, что версия OpenGL, открытая через интерфейс привязки, является самым низким общим знаменателем, который может ожидать, что программы, запущенные на целевой платформе, могут быть доступны. Следовательно, современные функции OpenGL должны быть доступны через механизм расширения, который подробно описывается отдельно.

Linux

В Linux довольно распространено разделение пакетов разработки для различных аспектов системы, чтобы их можно было обновлять индивидуально. В большинстве дистрибутивов Linux файлы разработки для OpenGL содержатся в выделенном пакете, который обычно зависит от мета-пакета разработки приложений для настольных приложений. Поэтому для установки файлов разработки OpenGL для Linux, как правило, позаботятся об установке мета-пакета /

Майкрософт Виндоус

Библиотека привязки API opengl32.dll (названная так для 32-разрядных и 64-разрядных версий Windows) поставляется по умолчанию с каждой версией Windows с Windows NT-4 и Windows 95B (оба около 1997 года). Однако эта DLL не обеспечивает фактическую реализацию OpenGL (кроме программной резервной копии, единственной целью которой является обеспечение безопасности программ, если другая реализация OpenGL не установлена). Эта DLL принадлежит Windows и не может быть изменена или перемещена! Современные версии OpenGL поставляются как часть так называемого Installable Client Driver (ICD) и доступны через opengl32.dll по умолчанию, который поставляется с предустановленной версией каждой версии Windows. Однако корпорация Microsoft решила, что графические драйверы, установленные с помощью Центра обновления Windows , не будут устанавливать / обновлять OpenGL ICD. Поскольку в таких новых установках Windows с установленными драйверами автоматически отсутствует поддержка современных функций OpenGL. Чтобы получить OpenGL ICD с современными функциями, графические драйверы должны быть загружены непосредственно с веб-сайта поставщика графического процессора и установлены вручную.

Что касается разработки, никаких дополнительных шагов не следует предпринимать. Все компиляторы C / C ++, следующие спецификациям Windows ABI, поставляются с заголовками и заглушкой компоновщика (opengl32.lib), необходимыми для сборки и связывания исполняемых файлов, которые используют OpenGL.

Ручная настройка OpenGL в Windows

Полный код примера, включенный в конце

Компоненты Windows для OpenGL

WGL

WGL (может быть выражен wiggle ) означает «Windows-GL», как в «интерфейсе между Windows и OpenGL» - набор функций из Windows API для связи с OpenGL. Функции WGL имеют префикс wgl, а его маркеры имеют префикс WGL_ .

Версия OpenGL по умолчанию, поддерживаемая в системах Microsoft, составляет 1,1. Это очень старая версия (последняя - 4.5). Способ получения последних версий - обновить графические драйверы, но ваша видеокарта должна поддерживать эти новые версии.

Полный список функций WGL можно найти здесь .

Интерфейс графического устройства (GDI)

GDI (сегодня обновленный до GDI +) - это 2D-интерфейс рисования, который позволяет рисовать окно в Windows. Вам нужно, чтобы GDI инициализировал OpenGL и разрешил ему взаимодействовать с ним (но фактически не использует GDI).

В GDI каждое окно имеет контекст устройства (DC), который используется для идентификации цели рисования при вызове функций (вы передаете его как параметр). Однако OpenGL использует свой собственный контекст рендеринга (RC) . Таким образом, DC будет использоваться для создания RC.


Основные настройки

Создание окна

Итак, для того, чтобы делать вещи в OpenGL, нам нужен RC, и чтобы получить RC, нам нужен DC, и для получения DC нам нужно окно. Создание окна с использованием Windows API требует нескольких шагов. Это базовая процедура, поэтому для более подробного объяснения вам следует проконсультироваться с другой документацией, потому что речь идет не об использовании Windows API.

Это настройка Windows, поэтому необходимо включить Windows.h , а точкой входа программы должна быть процедура WinMain с ее параметрами. Программа также должна быть связана с opengl32.dll и с gdi32.dll (независимо от того, находитесь ли вы в 64 или 32-битной системе).

Сначала нам нужно описать наше окно, используя структуру WNDCLASS . Он содержит информацию о окне, которое мы хотим создать:

/* REGISTER WINDOW */
WNDCLASS window_class;

// Clear all structure fields to zero first
ZeroMemory(&window_class, sizeof(window_class));

// Define fields we need (others will be zero)
window_class.style = CS_OWNDC;
window_class.lpfnWndProc = window_procedure; // To be introduced later
window_class.hInstance = instance_handle;
window_class.lpszClassName = TEXT("OPENGL_WINDOW");

// Give our class to Windows
RegisterClass(&window_class);
/* *************** */

Для точного объяснения значения каждого поля (и для полного списка полей) обратитесь к документации MSDN.

Затем мы можем создать окно с помощью CreateWindowEx . После создания окна мы можем получить DC:

/* CREATE WINDOW */
HWND window_handle = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,
                                    TEXT("OPENGL_WINDOW"),
                                    TEXT("OpenGL window"),
                                    WS_OVERLAPPEDWINDOW,
                                    0, 0,
                                    800, 600,
                                    NULL,
                                    NULL,
                                    instance_handle,
                                    NULL);

HDC dc = GetDC(window_handle);

ShowWindow(window_handle, SW_SHOW);
/* ************* */

Наконец, нам нужно создать цикл сообщений, который принимает события окна из ОС:

/* EVENT PUMP */
MSG msg;

while (true) {
    if (PeekMessage(&msg, window_handle, 0, 0, PM_REMOVE)) {
        if (msg.message == WM_QUIT)
            break;
        
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    
    // draw(); <- there goes your drawing

    SwapBuffers(dc); // To be mentioned later
}
/* ********** */

Формат пикселей

OpenGL должен знать некоторую информацию о нашем окне, такую ​​как цветовая битность, метод буферизации и т. Д. Для этого мы используем формат пикселей . Однако мы можем только предложить ОС, какой формат пикселя нам нужен, и ОС будет поставлять наиболее похожие поддерживаемые , мы не имеем прямого контроля над ним. Вот почему он называется только дескриптором .

/* PIXEL FORMAT */
PIXELFORMATDESCRIPTOR descriptor;

// Clear all structure fields to zero first
ZeroMemory(&descriptor, sizeof(descriptor));

// Describe our pixel format
descriptor.nSize = sizeof(descriptor);
descriptor.nVersion = 1;
descriptor.dwFlags = PFD_DRAW_TO_WINDOW | PFD_DRAW_TO_BITMAP | PFD_SUPPORT_OPENGL | PFD_GENERIC_ACCELERATED | PFD_DOUBLEBUFFER | PFD_SWAP_LAYER_BUFFERS;
descriptor.iPixelType = PFD_TYPE_RGBA;
descriptor.cColorBits = 32;
descriptor.cRedBits = 8;
descriptor.cGreenBits = 8;
descriptor.cBlueBits = 8;
descriptor.cAlphaBits = 8;
descriptor.cDepthBits = 32;
descriptor.cStencilBits = 8;

// Ask for a similar supported format and set it
int pixel_format = ChoosePixelFormat(dc, &descriptor);
SetPixelFormat(dc, pixel_format, &descriptor);
/* *********************** */

Мы включили двойную буферизацию в поле dwFlags , поэтому мы должны вызвать SwapBuffers , чтобы видеть вещи после рисования.

Рендеринг контекста

После этого мы можем просто создать наш контекст рендеринга:

/* RENDERING CONTEXT */
HGLRC rc = wglCreateContext(dc);
wglMakeCurrent(dc, rc);
/* ***************** */

Обратите внимание, что только один поток может использовать RC за раз. Если вы хотите использовать его из другого потока позже, вы должны вызвать wglMakeCurrent чтобы снова активировать его (это отключит его в текущем потоке и так далее).

Получение функций OpenGL

Функции OpenGL получаются с помощью указателей функций. Общая процедура:

  1. Как-то получить типы указателей функций (по существу, прототипы функций)
  2. Объявите каждую функцию, которую мы хотели бы использовать (с ее указателем на функцию)
  3. Получить фактическую функцию

Например, рассмотрим glBegin:

// We need to somehow find something that contains something like this,
// as we can't know all the OpenGL function prototypes
typedef void (APIENTRY *PFNGLBEGINPROC)(GLenum);

// After that, we need to declare the function in order to use it
PFNGLBEGINPROC glBegin;

// And finally, we need to somehow make it an actual function

(«PFN» означает «указатель на функцию», затем следует имя функции OpenGL и «PROC» в конце - это обычное имя типа указателя функции OpenGL.)

Вот как это делается в Windows. Как упоминалось ранее, Microsoft только отправляет OpenGL 1.1. Во-первых, типы указателей функций для этой версии можно найти, включив GL/gl.h После этого мы объявляем все функции, которые мы намерены использовать, как показано выше (выполнение этого в файле заголовка и объявление их «extern» позволит нам использовать их все после их загрузки один раз, просто включив его). Наконец, загрузка функций OpenGL 1.1 выполняется путем открытия библиотеки DLL:

HMODULE gl_module = LoadLibrary(TEXT("opengl32.dll"));

/* Load all the functions here */
glBegin = (PFNGLBEGINPROC)GetProcAddress("glBegin");
// ...
/* *************************** */

FreeLibrary(gl_module);

Однако мы, вероятно, хотим немного больше, чем OpenGL 1.1. Но Windows не дает нам прототипов функций или экспортированных функций для чего-либо выше этого. Прототипы должны быть приобретены из реестра OpenGL . Есть три интересующих нас файла: GL/glext.h , GL/glcorearb.h и GL/wglext.h .

Чтобы завершить GL/gl.h предоставленный Windows, нам нужен GL/glext.h . Он содержит (как описано в реестре) «OpenGL 1.2 и выше профили совместимости и интерфейсы расширений» (подробнее о профилях и расширениях позже, где мы увидим, что на самом деле не рекомендуется использовать эти два файла ).

Фактические функции должны быть получены с помощью wglGetProcAddress (нет необходимости открывать DLL для этого парня, их там нет, просто используйте функцию). С его помощью мы можем получить все функции из OpenGL 1.2 и выше (но не 1.1). Обратите внимание, что для правильной работы контекста рендеринга OpenGL необходимо создать и сделать текущим . Так, например, glClear :

// Include the header from the OpenGL registry for function pointer types

// Declare the functions, just like before
PFNGLCLEARPROC glClear;
// ...

// Get the function
glClear = (PFNGLCLEARPROC)wglGetProcAddress("glClear");

Мы можем создать процедуру get_proc для обёртки, которая использует как wglGetProcAddress и GetProcAddress :

// Get function pointer
void* get_proc(const char *proc_name)
{
    void *proc = (void*)wglGetProcAddress(proc_name);
    if (!proc) proc = (void*)GetProcAddress(gl_module, proc_name); // gl_module must be somewhere in reach

    return proc;
}

Итак, чтобы завершить, мы создали бы заголовочный файл с объявлениями указателей функций следующим образом:

extern PFNGLCLEARCOLORPROC glClearColor;
extern PFNGLCLEARDEPTHPROC glClearDepth;
extern PFNGLCLEARPROC glClear;
extern PFNGLCLEARBUFFERIVPROC glClearBufferiv;
extern PFNGLCLEARBUFFERFVPROC glClearBufferfv;
// And so on...

Затем мы можем создать такую ​​процедуру, как load_gl_functions которую мы вызываем только один раз, и работает так:

glClearColor = (PFNGLCLEARCOLORPROC)get_proc("glClearColor");
glClearDepth = (PFNGLCLEARDEPTHPROC)get_proc("glClearDepth");
glClear = (PFNGLCLEARPROC)get_proc("glClear");
glClearBufferiv = (PFNGLCLEARBUFFERIVPROC)get_proc("glClearBufferiv");
glClearBufferfv = (PFNGLCLEARBUFFERFVPROC)get_proc("glClearBufferfv");

И ты все настроен! Просто включите заголовок с указателями функций и GL.


Лучшая настройка

Профили OpenGL

OpenGL находится в разработке более 20 лет, и разработчики всегда были строгими относительно обратной совместимости (BC) . Из-за этого очень сложно добавить новую функцию. Таким образом, в 2008 году он был разделен на два «профиля». Ядро и совместимость . Основной профиль ломает BC в пользу улучшения производительности и некоторых новых функций. Он даже полностью удаляет некоторые устаревшие функции. Профиль совместимости поддерживает BC со всеми версиями до 1.0, а некоторые новые функции недоступны на нем. Он предназначен только для старых, устаревших систем, все новые приложения должны использовать основной профиль.

Из-за этого возникает проблема с нашей базовой настройкой - она ​​предоставляет только контекст, который обратно совместим с OpenGL 1.0. Формат пикселей также ограничен. Существует лучший подход, используя расширения.

Расширения OpenGL

Любое дополнение к исходной функциональности OpenGL называется расширением. Как правило, они могут либо сделать некоторые вещи законными, которые раньше не были, расширить диапазон значений параметров, расширить GLSL и даже добавить совершенно новые функции.

Существуют три основные группы расширений: поставщик, EXT и ARB. Расширения поставщиков исходят от конкретного поставщика, и у них есть определенная производителем марка, например AMD или NV. Расширения EXT производятся несколькими поставщиками, работающими вместе. Через некоторое время они могут стать расширениями ARB, которые являются официально поддерживаемыми и одобрены ARB.

Чтобы получить типы указателей функций и прототипы функций всех расширений и, как упоминалось ранее, все типы указателей функций из OpenGL 1.2 и выше , необходимо загрузить файлы заголовков из реестра OpenGL . Как обсуждалось, для новых приложений лучше использовать основной профиль, поэтому было бы GL/glcorearb.h включить GL/glcorearb.h вместо GL/gl.h и GL/glext.h (если вы используете GL/glcorearb.h тогда GL/glcorearb.h Включить GL/gl.h ).

Существуют также расширения для WGL, в GL/wglext.h . Например, функция для получения списка всех поддерживаемых расширений фактически является самим расширением wglGetExtensionsStringARB (она возвращает большую строку с разделенным пробелом списком всех поддерживаемых расширений).

Получение расширений также осуществляется через wglGetProcAddress , поэтому мы можем просто использовать наш обертку, как раньше.

Расширенный формат пикселей и создание контекста

Расширение WGL_ARB_pixel_format позволяет нам создавать расширенные форматы пикселей. В отличие от ранее, мы не используем struct. Вместо этого мы передаем список желаемых атрибутов.

int pixel_format_arb;
UINT pixel_formats_found;

int pixel_attributes[] = {
    WGL_SUPPORT_OPENGL_ARB, 1,
    WGL_DRAW_TO_WINDOW_ARB, 1,
    WGL_DRAW_TO_BITMAP_ARB, 1,
    WGL_DOUBLE_BUFFER_ARB, 1,
    WGL_SWAP_LAYER_BUFFERS_ARB, 1,
    WGL_COLOR_BITS_ARB, 32,
    WGL_RED_BITS_ARB, 8,
    WGL_GREEN_BITS_ARB, 8,
    WGL_BLUE_BITS_ARB, 8,
    WGL_ALPHA_BITS_ARB, 8,
    WGL_DEPTH_BITS_ARB, 32,
    WGL_STENCIL_BITS_ARB, 8,
    WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
    WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
    0
};

BOOL result = wglChoosePixelFormatARB(dc, pixel_attributes, NULL, 1, &pixel_format_arb, &pixel_formats_found);

Аналогично, расширение WGL_ARB_create_context позволяет нам создавать расширенные контексты:

GLint context_attributes[] = {
    WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
    WGL_CONTEXT_MINOR_VERSION_ARB, 3,
    WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
    0
};

HGLRC new_rc = wglCreateContextAttribsARB(dc, 0, context_attributes);

Для точного объяснения параметров и функций обратитесь к спецификации OpenGL.

Почему мы не начали с них? Ну, это потому, что расширения позволяют нам это делать, и для получения расширений нам нужен wglGetProcAddress , но это работает только с активным допустимым контекстом. Поэтому, по сути, прежде чем мы сможем создать необходимый нам контекст, нам нужно уже иметь некоторый контекст, и его обычно называют фиктивным контекстом .

Однако Windows не позволяет устанавливать формат пикселя окна более одного раза. Из-за этого окно необходимо уничтожить и воссоздать, чтобы применить новые вещи:

wglMakeCurrent(dc, NULL);
wglDeleteContext(rc);
ReleaseDC(window_handle, dc);
DestroyWindow(window_handle);

// Recreate the window...

Полный пример кода:

/* We want the core profile, so we include GL/glcorearb.h. When including that, then
   GL/gl.h should not be included.

   If using compatibility profile, the GL/gl.h and GL/glext.h need to be included.

   GL/wglext.h gives WGL extensions.

   Note that Windows.h needs to be included before them. */

#include <cstdio>
#include <Windows.h>
#include <GL/glcorearb.h>
#include <GL/wglext.h>

LRESULT CALLBACK window_procedure(HWND, UINT, WPARAM, LPARAM);
void* get_proc(const char*);

/* gl_module is for opening the DLL, and the quit flag is here to prevent
   quitting when recreating the window (see the window_procedure function) */

HMODULE gl_module;
bool quit = false;

/* OpenGL function declarations. In practice, we would put these in a
   separate header file and add "extern" in front, so that we can use them
   anywhere after loading them only once. */

PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB;
PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB;
PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB;
PFNGLGETSTRINGPROC glGetString;

int WINAPI WinMain(HINSTANCE instance_handle, HINSTANCE prev_instance_handle, PSTR cmd_line, int cmd_show) {
    /* REGISTER WINDOW */
    WNDCLASS window_class;

    // Clear all structure fields to zero first
    ZeroMemory(&window_class, sizeof(window_class));

    // Define fields we need (others will be zero)
    window_class.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
    window_class.lpfnWndProc = window_procedure;
    window_class.hInstance = instance_handle;
    window_class.lpszClassName = TEXT("OPENGL_WINDOW");

    // Give our class to Windows
    RegisterClass(&window_class);
    /* *************** */
        
    /* CREATE WINDOW */
    HWND window_handle = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,
                                        TEXT("OPENGL_WINDOW"),
                                        TEXT("OpenGL window"),
                                        WS_OVERLAPPEDWINDOW,
                                        0, 0,
                                        800, 600,
                                        NULL,
                                        NULL,
                                        instance_handle,
                                        NULL);
        
    HDC dc = GetDC(window_handle);
        
    ShowWindow(window_handle, SW_SHOW);
    /* ************* */
        
    /* PIXEL FORMAT */
    PIXELFORMATDESCRIPTOR descriptor;
        
    // Clear all structure fields to zero first
    ZeroMemory(&descriptor, sizeof(descriptor));
        
    // Describe our pixel format
    descriptor.nSize = sizeof(descriptor);
    descriptor.nVersion = 1;
    descriptor.dwFlags = PFD_DRAW_TO_WINDOW | PFD_DRAW_TO_BITMAP | PFD_SUPPORT_OPENGL | PFD_GENERIC_ACCELERATED | PFD_DOUBLEBUFFER | PFD_SWAP_LAYER_BUFFERS;
    descriptor.iPixelType = PFD_TYPE_RGBA;
    descriptor.cColorBits = 32;
    descriptor.cRedBits = 8;
    descriptor.cGreenBits = 8;
    descriptor.cBlueBits = 8;
    descriptor.cAlphaBits = 8;
    descriptor.cDepthBits = 32;
    descriptor.cStencilBits = 8;
        
    // Ask for a similar supported format and set it
    int pixel_format = ChoosePixelFormat(dc, &descriptor);
    SetPixelFormat(dc, pixel_format, &descriptor);
    /* *********************** */
        
    /* RENDERING CONTEXT */
    HGLRC rc = wglCreateContext(dc);
    wglMakeCurrent(dc, rc);
    /* ***************** */

    /* LOAD FUNCTIONS (should probably be put in a separate procedure) */
    gl_module = LoadLibrary(TEXT("opengl32.dll"));

    wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)get_proc("wglGetExtensionsStringARB");
    wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)get_proc("wglChoosePixelFormatARB");
    wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)get_proc("wglCreateContextAttribsARB");
    glGetString = (PFNGLGETSTRINGPROC)get_proc("glGetString");
    
    FreeLibrary(gl_module);
    /* ************** */

    /* PRINT VERSION */
    const GLubyte *version = glGetString(GL_VERSION);
    printf("%s\n", version);
    fflush(stdout);
    /* ******* */

    /* NEW PIXEL FORMAT*/
    int pixel_format_arb;
    UINT pixel_formats_found;
    
    int pixel_attributes[] = {
        WGL_SUPPORT_OPENGL_ARB, 1,
        WGL_DRAW_TO_WINDOW_ARB, 1,
        WGL_DRAW_TO_BITMAP_ARB, 1,
        WGL_DOUBLE_BUFFER_ARB, 1,
        WGL_SWAP_LAYER_BUFFERS_ARB, 1,
        WGL_COLOR_BITS_ARB, 32,
        WGL_RED_BITS_ARB, 8,
        WGL_GREEN_BITS_ARB, 8,
        WGL_BLUE_BITS_ARB, 8,
        WGL_ALPHA_BITS_ARB, 8,
        WGL_DEPTH_BITS_ARB, 32,
        WGL_STENCIL_BITS_ARB, 8,
        WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
        WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
        0
    };

    BOOL result = wglChoosePixelFormatARB(dc, pixel_attributes, NULL, 1, &pixel_format_arb, &pixel_formats_found);

    if (!result) {
        printf("Could not find pixel format\n");
        fflush(stdout);
        return 0;
    }
    /* **************** */

    /* RECREATE WINDOW */
    wglMakeCurrent(dc, NULL);
    wglDeleteContext(rc);
    ReleaseDC(window_handle, dc);
    DestroyWindow(window_handle);
    
    window_handle = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,
                                        TEXT("OPENGL_WINDOW"),
                                        TEXT("OpenGL window"),
                                        WS_OVERLAPPEDWINDOW,
                                        0, 0,
                                        800, 600,
                                        NULL,
                                        NULL,
                                        instance_handle,
                                        NULL);
        
    dc = GetDC(window_handle);
        
    ShowWindow(window_handle, SW_SHOW);
    /* *************** */

    /* NEW CONTEXT */
    GLint context_attributes[] = {
        WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
        WGL_CONTEXT_MINOR_VERSION_ARB, 3,
        WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
        0
    };

    rc = wglCreateContextAttribsARB(dc, 0, context_attributes);
    wglMakeCurrent(dc, rc);
    /* *********** */
        
    /* EVENT PUMP */
    MSG msg;
        
    while (true) {
        if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
            if (msg.message == WM_QUIT) 
                break;
                
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
            
        // draw(); <- there goes your drawing
            
        SwapBuffers(dc);
    }
    /* ********** */
        
    return 0;
}

// Procedure that processes window events
LRESULT CALLBACK window_procedure(HWND window_handle, UINT message, WPARAM param_w, LPARAM param_l)
{
    /* When destroying the dummy window, WM_DESTROY message is going to be sent,
       but we don't want to quit the application then, and that is controlled by
       the quit flag. */

    switch(message) {
    case WM_DESTROY:
        if (!quit) quit = true;
        else PostQuitMessage(0);
        return 0;
    }

    return DefWindowProc(window_handle, message, param_w, param_l);
}

/* A procedure for getting OpenGL functions and OpenGL or WGL extensions.
   When looking for OpenGL 1.2 and above, or extensions, it uses wglGetProcAddress,
   otherwise it falls back to GetProcAddress. */
void* get_proc(const char *proc_name)
{
    void *proc = (void*)wglGetProcAddress(proc_name);
    if (!proc) proc = (void*)GetProcAddress(gl_module, proc_name);

    return proc;
}

Скомпилирован с g++ GLExample.cpp -lopengl32 -lgdi32 с MinGW / Cygwin или cl GLExample.cpp opengl32.lib gdi32.lib user32.lib с компилятором MSVC. Убедитесь, однако, что заголовки из реестра OpenGL находятся в пути include. Если нет, используйте флаг -I для g++ или /I для cl , чтобы сообщить компилятору, где они находятся.

Создание OpenGL 4.1 с C ++ и Cocoa

Примечание. В этом примере будет некоторый Objective-c. В этом примере мы создадим оболочку для C ++. Поэтому не беспокойтесь об этом.

Сначала запустите Xcode и создайте проект.

введите описание изображения здесь

И выберите приложение Cocoa введите описание изображения здесь

Удалите все источники, кроме файла Info.plist (ваше приложение не будет работать без него)

Создайте 4 новых исходных файла: файл и заголовок Objective-c ++ (я назвал мой MacApp). Класс C ++ (я назвал my (Application)

В левом верхнем углу (с именем проекта) щелкните по нему и добавьте связанные фреймворки и библиотеки. Добавить: OpenGL.Framework AppKit.Framework GLKit.Framework

Вероятно, ваш проект будет выглядеть следующим образом:

введите описание изображения здесь

NSApplication - основной класс, который вы используете при создании приложения MacOS. Это позволяет вам регистрировать окна и захватывать события.

Мы хотим зарегистрировать (наше) окно в NSApplication. Сначала создайте в своем объектно-c ++-заголовке объект-c-класс, который наследует NSWindow и реализует NSApplicationDelegate. NSWindow нуждается в указателе на приложение C ++, OpenGL View и таймер для цикла рисования

//Mac_App_H
#import <Cocoa/Cocoa.h>
#import "Application.hpp"
#import <memory>
NSApplication* application;

@interface MacApp : NSWindow <NSApplicationDelegate>{
    std::shared_ptr<Application> appInstance;
}
@property (nonatomic, retain) NSOpenGLView* glView;
-(void) drawLoop:(NSTimer*) timer;
@end

Мы называем это основным

int main(int argc, const char * argv[]) {
    MacApp* app;
    application = [NSApplication sharedApplication];
    [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; 
    //create a window with the size of 600 by 600   
    app = [[MacApp alloc] initWithContentRect:NSMakeRect(0, 0, 600, 600)              styleMask:NSTitledWindowMask | NSClosableWindowMask |  NSMiniaturizableWindowMask   backing:NSBackingStoreBuffered defer:YES];    
    [application setDelegate:app];
    [application run];
}

Реализация нашего окна на самом деле довольно просто. Сначала мы объявляем с синтезом нашего glview и добавляем глобальную цель-c булевым, когда окно должно закрываться.

#import "MacApp.h"

@implementation MacApp

@synthesize glView;

BOOL shouldStop = NO;

Теперь для конструктора. Я предпочитаю использовать initWithContentRect.

-(id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag{
if(self = [super initWithContentRect:contentRect styleMask:aStyle backing:bufferingType defer:flag]){
    //sets the title of the window (Declared in Plist)
    [self setTitle:[[NSProcessInfo processInfo] processName]];
 
    //This is pretty important.. OS X starts always with a context that only supports openGL 2.1
    //This will ditch the classic OpenGL and initialises openGL 4.1
    NSOpenGLPixelFormatAttribute pixelFormatAttributes[] ={
        NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
            NSOpenGLPFAColorSize    , 24                           ,
            NSOpenGLPFAAlphaSize    , 8                            ,
            NSOpenGLPFADoubleBuffer ,
            NSOpenGLPFAAccelerated  ,
            NSOpenGLPFANoRecovery   ,
            0
    };

    NSOpenGLPixelFormat* format = [[NSOpenGLPixelFormat alloc]initWithAttributes:pixelFormatAttributes];
    //Initialize the view 
    glView = [[NSOpenGLView alloc]initWithFrame:contentRect pixelFormat:format];
    
    //Set context and attach it to the window
    [[glView openGLContext]makeCurrentContext];
  
    //finishing off
    [self setContentView:glView];
    [glView prepareOpenGL];
    [self makeKeyAndOrderFront:self];
    [self setAcceptsMouseMovedEvents:YES];
    [self makeKeyWindow];
    [self setOpaque:YES];

    //Start the c++ code
    appInstance = std::shared_ptr<Application>(new Application());

}
return self;
}

Хорошо ... теперь у нас действительно запущенное приложение. Возможно, вы видите черный экран или мерцание.

Давайте начнем рисовать удивительный треугольник. (В c ++)

Мой заголовок приложения

#ifndef Application_hpp
#define Application_hpp
#include <iostream>
#include <OpenGL/gl3.h>
class Application{
private:
    GLuint          program;
    GLuint          vao;
public:
    Application();
    void update();
    ~Application();

};

#endif /* Application_hpp */

Реализация:

Application::Application(){
 static const char * vs_source[] =
    {
        "#version 410 core                                                 \n"
        "                                                                  \n"
        "void main(void)                                                   \n"
        "{                                                                 \n"
        "    const vec4 vertices[] = vec4[](vec4( 0.25, -0.25, 0.5, 1.0),  \n"
        "                                   vec4(-0.25, -0.25, 0.5, 1.0),  \n"
        "                                   vec4( 0.25,  0.25, 0.5, 1.0)); \n"
        "                                                                  \n"
        "    gl_Position = vertices[gl_VertexID];                          \n"
        "}                                                                 \n"
    };

    static const char * fs_source[] =
    {
        "#version 410 core                                                 \n"
        "                                                                  \n"
        "out vec4 color;                                                   \n"
        "                                                                  \n"
        "void main(void)                                                   \n"
        "{                                                                 \n"
        "    color = vec4(0.0, 0.8, 1.0, 1.0);                             \n"
        "}                                                                 \n"
    };

    program = glCreateProgram();
    GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fs, 1, fs_source, NULL);
    glCompileShader(fs);

    GLuint vs = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vs, 1, vs_source, NULL);
    glCompileShader(vs);

    glAttachShader(program, vs);
    glAttachShader(program, fs);

    glLinkProgram(program);

    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);
}

void Application::update(){
    static const GLfloat green[] = { 0.0f, 0.25f, 0.0f, 1.0f };
    glClearBufferfv(GL_COLOR, 0, green);

    glUseProgram(program);
    glDrawArrays(GL_TRIANGLES, 0, 3);
}


Application::~Application(){
    glDeleteVertexArrays(1, &vao);
    glDeleteProgram(program);
}

Теперь нам нужно снова и снова вызывать обновление (если вы хотите что-то переместить). Внедрите в свой класс object-c

-(void) drawLoop:(NSTimer*) timer{

if(shouldStop){
    [self close];
    return;
}
if([self isVisible]){
  
       appInstance->update();
    [glView update];
    [[glView openGLContext] flushBuffer];
}

}

И добавьте этот метод в реализацию вашего класса object-c:

- (void)applicationDidFinishLaunching:(NSNotification *)notification {
    [NSTimer scheduledTimerWithTimeInterval:0.000001 target:self selector:@selector(drawLoop:) userInfo:nil repeats:YES];
}

это вызовет функцию обновления вашего класса c ++ снова и снова (каждые 0,000001 секунд, чтобы быть точным)

Чтобы закончить, мы закрываем окно при нажатии кнопки закрытия:

- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication     *)theApplication{
    return YES;
}

- (void)applicationWillTerminate:(NSNotification *)aNotification{
    shouldStop = YES;
}

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

Создание контекста OpenGL в Cross Platform (с использованием SDL2)

Создание окна с контекстом OpenGL (добавление нагрузки через GLEW ):

#define GLEW_STATIC

#include <GL/glew.h>
#include <SDL2/SDL.h>

int main(int argc, char* argv[])
{
    SDL_Init(SDL_INIT_VIDEO); /* Initialises Video Subsystem in SDL */

    /* Setting up OpenGL version and profile details for context creation */
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
    
    /* A 800x600 window. Pretty! */
    SDL_Window* window = SDL_CreateWindow
        (
        "SDL Context",
        SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
        800, 600,
        SDL_WINDOW_OPENGL
        );
    
    /* Creating OpenGL Context */
    SDL_GLContext gl_context = SDL_GL_CreateContext(window);

    /* Loading Extensions */
    glewExperimental = GL_TRUE;
    glewInit();

    /* The following code is for error checking. 
    *  If OpenGL has initialised properly, this should print 1.
    *  Remove it in production code.
    */
    GLuint vertex_buffer;
    glGenBuffers(1, &vertex_buffer);
    printf("%u\n", vertex_buffer);
    /* Error checking ends here */

    /* Main Loop */
    SDL_Event window_event;
    while(1) {
        if (SDL_PollEvent(&window_event)) {
            if (window_event.type == SDL_QUIT) {
                /* If user is exiting the application */
                break;
            }
        }
        /* Swap the front and back buffer for flicker-free rendering */
        SDL_GL_SwapWindow(window);
    }
    
    /* Freeing Memory */
    glDeleteBuffers(1, &vertex_buffer);
    SDL_GL_DeleteContext(gl_context);
    SDL_Quit();

    return 0;
}

Настройка современного OpenGL 4.1 на macOS (Xcode, GLFW и GLEW)

1. Установите GLFW

Первый шаг - создать окно OpenGL. GLFW - это библиотека с открытым исходным кодом, многоплатформенная библиотека для создания окон с OpenGL, для установки GLFW сначала загружайте свои файлы с сайта www.glfw.org

Веб-страница GLFW

Извлеките папку GLFW, и ее содержимое будет выглядеть следующим образом:

Содержимое папки GLFW

Загрузите и установите CMake для сборки GLFW. Перейти на www.cmake.org/download/ , загрузить CMake и установить для MAC OS X

Веб-страница загрузки

Если Xcode не установлен. Загрузите и установите Xcode из Mac App Store.

Xcode из Mac App Store

Создание новой папки Создание внутри папки GLFW

Папка GLFW после создания папки «Build»

Откройте CMake, нажмите кнопку « Обзор источника» , чтобы выбрать папку GLFW (убедитесь, что CMakeLists.txt) находится внутри этой папки. После этого нажмите кнопку « Обзор сборки» и выберите новую созданную папку « Создать » на предыдущем шаге.

Пути CMake

Теперь нажмите кнопку « Настроить» и выберите «Генератор Xcode как генератор» с параметром « Использовать стандартные компиляторы» и нажмите « Готово» .

Makefile для Xcode

Отметьте опцию BUILD_SHARED_LIBS, а затем снова нажмите кнопку « Настроить» и, наконец, нажмите кнопку « Создать» .

Выберите BUILD_SHARED_LIBS

После поколения CMake должно выглядеть так

Заключительный CMake

Теперь Open Finder и goto / usr , создайте локальное имя папки, если оно еще не существует. Откройте локальную папку и создать две папки включают в себя и Lib , если уже не там.

Теперь откройте папку GLFW и goto Build (где CMake создал файлы). Откройте файл GLFW.xcodeproj в Xcode.

Файл проекта Xcode

Выберите « Установить»> «Мой Mac», а затем нажмите « Запустить» (кнопка «Форма игры»).

Установка GLFW

Теперь он успешно установлен (игнорируйте предупреждения).

Чтобы убедиться, что Open Finder и папка goto / usr / local / lib и три библиотеки библиотеки GLFW уже присутствуют там (если нет, то откройте папку « Сборка » внутри папки GLFW и перейдите в src / Debug, скопируйте все файлы в / usr / local / lib )

Файлы GLFW Lib

Open Finder и goto / usr / local / include и папка GLFW будут присутствовать там с двумя файлами заголовков внутри него по имени glfw3.h и glfw3native.h

Файлы заголовков GLFW

2. Установите GLEW

GLEW - это кросс-платформенная библиотека, которая помогает в поиске и загрузке расширений OpenGL. Он предоставляет механизмы времени выполнения для определения, какие расширения OpenGL поддерживаются на целевой платформе. Это только для современного OpenGL (OpenGL версии 3.2 и выше, который требует определения функций во время выполнения). Чтобы установить первую загрузку своих файлов с glew.sourceforge.net

Веб-страница GLEW

Извлеките папку GLFW, и ее содержимое будет выглядеть так.

Содержимое папки GLEW

Теперь откройте терминал, перейдите в папку GLEW и введите следующие команды

make
sudo make install 
make clean

Теперь GLEW успешно установлен. Чтобы убедиться, что его установленный, Open Finder, перейдите в каталог / usr / local / include, и в нем будет присутствовать папка GL с тремя файлами заголовков внутри нее по имени glew.h , glxew.h и wglew.h

Файлы заголовков GLEW

Откройте Finder и перейдите в / usr / local / lib, и файлы библиотеки GLEW будут уже присутствовать там

Файлы библиотеки GLEW

3. Тестирование и запуск

Теперь мы успешно установили GLFW и GLEW. Его время кодировать. Откройте Xcode и создайте новый проект Xcode. Выберите « Инструмент командной строки», затем выполните следующие действия и выберите язык C ++ .

Проект Xcode

Xcode создаст новый проект командной строки.

Нажмите на название проекта, а на вкладке « Параметры сборки» выберите « Базовый для всех» в разделе « Пути поиска », добавьте / usr / local / include в пути поиска заголовков и добавьте / usr / local / lib в пути поиска библиотеки

Пути поиска

Нажмите на название проекта, а на вкладке « Сборка фаз » и в разделе « Связывание с бинарными библиотеками» добавьте OpenGL.framework, а также добавьте недавно созданные библиотеки GLFW и GLEW из / usr / local / lib

Связать бинарники

Теперь мы готовы кодировать в Modern Open GL 4.1 на macOS, используя C ++ и Xcode. Следующий код создаст окно OpenGL, используя GLFW с выводом пустого экрана.

#include <GL/glew.h> 
#include <GLFW/glfw3.h>

// Define main function
int main() 
{
    // Initialize GLFW
    glfwInit();

    // Define version and compatibility settings
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); 
    glfwWindowHint(GLFW_OPENGL_PROFILE,GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); 
    glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);

    // Create OpenGL window and context
    GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL", NULL, NULL);
    glfwMakeContextCurrent(window);

    // Check for window creation failure
    if (!window) 
    {
        // Terminate GLFW
        glfwTerminate();
        return 0; 
    }

    // Initialize GLEW
    glewExperimental = GL_TRUE; glewInit();

    // Event loop
    while(!glfwWindowShouldClose(window)) 
    {
        // Clear the screen to black
        glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT);
        glfwSwapBuffers(window);
        glfwPollEvents(); 
    }

    // Terminate GLFW
    glfwTerminate(); return 0;
}

Пустое окно OpenGL

Создать контекст Opengl с Java и LWJGL 3.0

В этом примере кода мы создадим пустое окно Opengl с использованием LWJGL 3.0+, это не содержит шагов для создания проекта в вашей среде IDE

введите описание изображения здесь

  1. Создайте имя класса WindowManager, который будет содержать весь код плиты котла для создания окна контекста opengl на экране

WindowManager.java

import org.lwjgl.glfw.*;
import static org.lwjgl.glfw.Callbacks.*;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.system.MemoryUtil.*;

/**
 * Class Containing code related to inflating Opengl Window
 */
public class Displaymanager {

    private static long window;

    public static void createDisplay(){
        // Setup an error callback. The default implementation
        // will print the error message in System.err.
        GLFWErrorCallback.createPrint(System.err).set();

        // Initialize GLFW. Most GLFW functions will not work before doing this.
        if ( !glfwInit() )
            throw new IllegalStateException("Unable to initialize GLFW");

        // Configure our window
        glfwDefaultWindowHints(); // optional, the current window hints are already the default
        glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); // the window will stay hidden after creation
        glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); // the window will be resizable

        int WIDTH = 300;
        int HEIGHT = 300;

        // Create the window
        window = glfwCreateWindow(WIDTH, HEIGHT, "Hello World!", NULL, NULL);
        if ( window == NULL )
            throw new RuntimeException("Failed to create the GLFW window");

        // Setup a key callback. It will be called every time a key is pressed, repeated or released.
        glfwSetKeyCallback(window, (window, key, scancode, action, mods) -> {
            if ( key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE )
                glfwSetWindowShouldClose(window, true); // We will detect this in our rendering loop
        });

        // Get the resolution of the primary monitor
        GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
        // Center our window
        glfwSetWindowPos(
                window,
                (vidmode.width() - WIDTH) / 2,
                (vidmode.height() - HEIGHT) / 2
        );

        // Make the OpenGL context current
        glfwMakeContextCurrent(window);
        // Enable v-sync
        glfwSwapInterval(1);

        // Make the window visible
        glfwShowWindow(window);
    }

    public static boolean isCloseRequested(){
        return glfwWindowShouldClose(window);
    }

    public static void updateDisplay(){
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear the framebuffer

        glfwSwapBuffers(window); // swap the color buffers

        // Poll for window events. The key callback above will only be
        // invoked during this call.
        glfwPollEvents();
    }

    public static void destroyDisplay(){
        // Terminate GLFW and free the error callback
        cleanUp();
        glfwTerminate();
        glfwSetErrorCallback(null).free();
    }

    private static void cleanUp() {
        // Free the window callbacks and destroy the window
        glfwFreeCallbacks(window);
        glfwDestroyWindow(window);
    }
}
  1. Затем создайте класс, содержащий основной цикл рендеринга, который вызовет все указанные выше функции

OpenGlMain.java

import org.lwjgl.opengl.GL;
import renderEngine.Displaymanager;
import static org.lwjgl.opengl.GL11.glClearColor;


/**
 * Class to test the opengl Window
 */
public class OpenGlMain {

    public static void main(String[] args) {

        Displaymanager.createDisplay();

        // This line is critical for LWJGL's interoperation with GLFW's
        // OpenGL context, or any context that is managed externally.
        // LWJGL detects the context that is current in the current thread,
        // creates the GLCapabilities instance and makes the OpenGL
        // bindings available for use.
        GL.createCapabilities();

        while (!Displaymanager.isCloseRequested()){

            // Set the clear color
            glClearColor(1.0f, 0.0f, 0.0f, 0.0f);

            Displaymanager.updateDisplay();
        }

        Displaymanager.destroyDisplay();
    }
}

Для получения дополнительной информации официальный представитель LWJGL Guide



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow