Comenzando con opengl

Configuración manual de OpenGL en Windows

Código de ejemplo completo incluido al final

Componentes de Windows para OpenGL

WGL

WGL (se puede pronunciar wiggle) significa “Windows-GL”, como en “una interfaz entre Windows y OpenGL”, un conjunto de funciones de la API de Windows para comunicarse con OpenGL. Las funciones WGL tienen un prefijo wgl y sus tokens tienen un prefijo WGL_.

La versión predeterminada de OpenGL admitida en los sistemas de Microsoft es 1.1. Esa es una versión muy antigua (la más reciente es la 4.5). La forma de obtener las versiones más recientes es actualizar los controladores de gráficos, pero su tarjeta gráfica debe ser compatible con esas nuevas versiones.

La lista completa de funciones WGL se puede encontrar aquí.

Interfaz de dispositivo gráfico (GDI)

GDI (hoy actualizado a GDI+) es una interfaz de dibujo 2D que le permite dibujar en una ventana en Windows. Necesita GDI para inicializar OpenGL y permitirle interactuar con él (pero en realidad no usará GDI).

En GDI, cada ventana tiene un contexto de dispositivo (DC) que se usa para identificar el objetivo del dibujo cuando se llama a funciones (usted lo pasa como un parámetro). Sin embargo, OpenGL usa su propio contexto de representación (RC). Entonces, DC se usará para crear RC.


Configuración básica

Crear una ventana

Entonces, para hacer cosas en OpenGL, necesitamos RC, y para obtener RC, necesitamos DC, y para obtener DC necesitamos una ventana. La creación de una ventana con la API de Windows requiere varios pasos. Esta es una rutina básica, por lo que para una explicación más detallada, debe consultar otra documentación, porque no se trata de usar la API de Windows.

Esta es una configuración de Windows, por lo que se debe incluir Windows.h y el punto de entrada del programa debe ser el procedimiento WinMain con sus parámetros. El programa también debe estar vinculado a opengl32.dll y a gdi32.dll (independientemente de si está en un sistema de 64 o 32 bits).

Primero necesitamos describir nuestra ventana usando la estructura WNDCLASS. Contiene información sobre la ventana que queremos crear:

/* 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);
/* *************** */

Para obtener una explicación precisa del significado de cada campo (y una lista completa de campos), consulte la documentación de MSDN.

Luego, podemos crear una ventana usando CreateWindowEx. Después de crear la ventana, podemos adquirir su 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);
/* ************* */

Finalmente, necesitamos crear un bucle de mensajes que reciba eventos de ventana del sistema operativo:

/* 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
}
/* ********** */

Formato de píxeles

OpenGL necesita conocer cierta información sobre nuestra ventana, como el bitness del color, el método de almacenamiento en búfer, etc. Para ello, utilizamos un formato de píxel. Sin embargo, solo podemos sugerirle al sistema operativo qué tipo de formato de píxel necesitamos, y el sistema operativo proporcionará el compatible más similar, no tenemos control directo sobre él. Es por eso que solo se llama un descriptor.

/* 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);
/* *********************** */

Hemos habilitado el almacenamiento en búfer doble en el campo dwFlags, por lo que debemos llamar a SwapBuffers para ver las cosas después de dibujar.

Contexto de representación

Después de eso, simplemente podemos crear nuestro contexto de representación:

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

Tenga en cuenta que solo un subproceso puede usar el RC a la vez. Si desea usarlo desde otro subproceso más tarde, debe llamar a wglMakeCurrent allí para activarlo nuevamente (esto lo desactivará en el subproceso en el que está actualmente activo, y así sucesivamente).

Obteniendo funciones OpenGL

Las funciones de OpenGL se obtienen utilizando punteros de función. El procedimiento general es:

  1. De alguna manera obtener tipos de punteros de funciones (esencialmente los prototipos de funciones)
  2. Declarar cada función que nos gustaría usar (con su tipo de puntero de función)
  3. Obtenga la función real

Por ejemplo, considere 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” significa “puntero a función”, luego sigue el nombre de una función OpenGL y “PROC” al final; ese es el nombre habitual del tipo de puntero de función OpenGL).

Así es como se hace en Windows. Como se mencionó anteriormente, Microsoft solo distribuye OpenGL 1.1. Primero, los tipos de punteros de función para esa versión se pueden encontrar incluyendo GL/gl.h. Después de eso, declaramos todas las funciones que pretendemos usar como se muestra arriba (hacer eso en un archivo de encabezado y declararlas “externas” nos permitiría usarlas todas después de cargarlas una vez, simplemente incluyéndolas). Finalmente, la carga de las funciones de OpenGL 1.1 se realiza abriendo la DLL:

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

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

FreeLibrary(gl_module);

Sin embargo, probablemente queramos un poco más que OpenGL 1.1. Pero Windows no nos da los prototipos de funciones o las funciones exportadas para nada por encima de eso. Los prototipos deben adquirirse del registro OpenGL. Hay tres archivos de interés para nosotros: GL/glext.h, GL/glcorearb.h y GL/wglext.h.

Para completar GL/gl.h proporcionado por Windows, necesitamos GL/glext.h. Contiene (como lo describe el registro) “Perfil de compatibilidad OpenGL 1.2 y superior e interfaces de extensión” (más sobre perfiles y extensiones más adelante, donde veremos que en realidad no es una buena idea usar esos dos archivos) .

Las funciones reales deben obtenerse mediante wglGetProcAddress (no es necesario abrir la DLL para este tipo, no están allí, solo use la función). Con él, podemos obtener todas las funciones de OpenGL 1.2 y superior (pero no 1.1). Tenga en cuenta que, para que funcione correctamente, el contexto de representación de OpenGL debe crearse y actualizarse. Entonces, por ejemplo, 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");

De hecho, podemos construir un procedimiento contenedor get_proc que use tanto wglGetProcAddress como 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;
}

Entonces, para concluir, crearíamos un archivo de encabezado lleno de declaraciones de puntero de función como esta:

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

Luego podemos crear un procedimiento como load_gl_functions al que llamamos solo una vez y funciona así:

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");

¡Y ya está todo listo! Simplemente incluya el encabezado con los punteros de función y GL de distancia.


Mejor configuración

Perfiles OpenGL

OpenGL ha estado en desarrollo durante más de 20 años, y los desarrolladores siempre fueron estrictos con respecto a la compatibilidad con versiones anteriores (BC). Agregar una nueva característica es muy difícil debido a eso. Así, en 2008, se separó en dos “perfiles”. Núcleo y compatibilidad. El perfil central rompe BC a favor de las mejoras de rendimiento y algunas de las nuevas características. Incluso elimina por completo algunas características heredadas. El perfil de compatibilidad mantiene BC con todas las versiones hasta la 1.0 y algunas características nuevas no están disponibles en él. Solo debe usarse para sistemas heredados antiguos, todas las aplicaciones nuevas deben usar el perfil principal.

Por eso, hay un problema con nuestra configuración básica: solo proporciona el contexto que es compatible con versiones anteriores de OpenGL 1.0. El formato de píxel también está limitado. Hay un mejor enfoque, usando extensiones.

Extensiones OpenGL

Cualquier adición a la funcionalidad original de OpenGL se denominan extensiones. En general, pueden hacer que algunas cosas sean legales que antes no lo eran, extender el rango de valores de los parámetros, extender GLSL e incluso agregar una funcionalidad completamente nueva.

Hay tres grupos principales de extensiones: proveedor, EXT y ARB. Las extensiones de proveedor provienen de un proveedor específico y tienen una marca específica de proveedor, como AMD o NV. Las extensiones EXT están hechas por varios proveedores que trabajan juntos. Después de un tiempo, pueden convertirse en extensiones de ARB, que son todas las que tienen soporte oficial y están aprobadas por ARB.

Para adquirir tipos de punteros de funciones y prototipos de funciones de todas las extensiones y, como se mencionó anteriormente, todos los tipos de punteros de funciones de OpenGL 1.2 y posteriores, se deben descargar los archivos de encabezado del registro de OpenGL. Como se mencionó, para las nuevas aplicaciones es mejor usar el perfil central, por lo que sería preferible incluir GL/glcorearb.h en lugar de GL/gl.h y GL/glext.h (si está utilizando GL/glcorearb.h entonces no incluya GL/gl.h).

También hay extensiones para WGL, en GL/wglext.h. Por ejemplo, la función para obtener la lista de todas las extensiones admitidas es en realidad una extensión en sí misma, wglGetExtensionsStringARB (devuelve una cadena grande con una lista separada por espacios de todas las extensiones admitidas).

La obtención de extensiones también se maneja a través de wglGetProcAddress, por lo que podemos usar nuestro contenedor como antes.

Creación avanzada de contexto y formato de píxeles

La extensión WGL_ARB_pixel_format nos permite la creación de formatos de píxeles avanzados. A diferencia de antes, no usamos una estructura. En su lugar, pasamos la lista de atributos buscados.

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);

De igual forma, la extensión WGL_ARB_create_context nos permite la creación avanzada de contextos:

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);

Para una explicación precisa de los parámetros y funciones, consulte la especificación de OpenGL.

¿Por qué no empezamos con ellos? Bueno, eso es porque las extensiones nos permiten hacer esto, y para obtener extensiones necesitamos wglGetProcAddress, pero eso solo funciona con un contexto válido activo. Entonces, en esencia, antes de que podamos crear el contexto que queremos, necesitamos tener algún contexto activo, y generalmente se lo conoce como contexto ficticio.

Sin embargo, Windows no permite configurar el formato de píxeles de una ventana más de una vez. Por eso, la ventana necesita ser destruida y recreada para poder aplicar cosas nuevas:

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

// Recreate the window...

Código de ejemplo completo:

/* 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;
}

Compilado con g++ GLExample.cpp -lopengl32 -lgdi32 con MinGW/Cygwin o cl GLExample.cpp opengl32.lib gdi32.lib user32.lib con el compilador MSVC. Sin embargo, asegúrese de que los encabezados del registro de OpenGL estén en la ruta de inclusión. Si no, use el indicador -I para g++ o /I para cl para decirle al compilador dónde son.

Configure Modern OpenGL 4.1 en macOS (Xcode, GLFW y GLEW)

1. Instalar GLFW

El primer paso es crear una ventana OpenGL. GLFW es una biblioteca multiplataforma de código abierto para crear ventanas con OpenGL. Para instalar GLFW, primero descargue sus archivos de www.glfw.org

Página web de GLFW

Extraiga la carpeta GLFW y su contenido se verá así

Contenido de la carpeta GLFW

Descargue e instale CMake para compilar GLFW. Vaya a www.cmake.org/download/, descargue CMake e instálelo para MAC OS X

Página web de descargas de CMake

Si Xcode no está instalado. Descargue e instale Xcode desde Mac App Store.

Xcode de Mac App Store

Cree una nueva carpeta Build dentro de la carpeta GLFW

Carpeta GLFW después de crear la carpeta &ldquo;Build&rdquo;

Abra CMake, haga clic en el botón Examinar fuente para seleccionar la carpeta GLFW (asegúrese de que CMakeLists.txt) se encuentra dentro de esa carpeta. Después de eso, haga clic en el botón Examinar compilación y seleccione la carpeta Creación recién creada en el paso anterior.

CMake Paths

Ahora haga clic en el botón Configurar y seleccione Xcode como generador con la opción Usar compiladores nativos predeterminados y haga clic en Listo.

Archivo Make para Xcode

Marque la opción BUILD_SHARED_LIBS y luego haga clic en el botón Configurar nuevamente y finalmente haga clic en el botón Generar.

Seleccione BUILD_SHARED_LIBS

Después de la generación, CMake debería verse así

CMake final

Ahora abra Finder y vaya a /usr, cree un nombre de carpeta local si aún no está allí. Abra la carpeta local y cree dos carpetas include y lib si aún no están allí.

Ahora abra la carpeta GLFW y vaya a Crear (donde CMake había creado los archivos). Abra el archivo GLFW.xcodeproj en Xcode.

Archivo de proyecto Xcode

Seleccione instalar > Mi Mac y luego haga clic en ejecutar (botón con forma de Reproducir).

Instalar GLFW

Ahora se instaló correctamente (ignore las advertencias).

Para asegurarse de que Open Finder e ir a la carpeta /usr/local/lib y tres archivos de la biblioteca GLFW ya estarán presentes allí (si no es así, abra la carpeta Build dentro de la carpeta GLFW y vaya a **src/Debug ** copiar todos los archivos a /usr/local/lib)

Archivos de biblioteca GLFW

Abra el Finder y vaya a /usr/local/include y una carpeta GLFW ya estará presente allí con dos archivos de encabezado dentro con el nombre de glfw3.h y glfw3native.h

Archivos de encabezado GLFW

2. Instalar GLEW

GLEW es una biblioteca multiplataforma que ayuda a consultar y cargar extensiones OpenGL. Proporciona mecanismos de tiempo de ejecución para determinar qué extensiones de OpenGL son compatibles con la plataforma de destino. Es solo para OpenGL moderno (OpenGL versión 3.2 y superior que requiere que las funciones se determinen en tiempo de ejecución). Para instalar primero descargue sus archivos desde glew.sourceforge.net

Página web de GLEW

Extraiga la carpeta GLFW y su contenido se verá así.

Contenido de la carpeta GLEW

Ahora abra la Terminal, navegue hasta la Carpeta GLEW y escriba los siguientes comandos

make
sudo make install 
make clean

Ahora GLEW se instaló con éxito. Para asegurarse de que esté instalado, abra Finder, vaya a /usr/local/include y ya estará presente una carpeta GL con tres archivos de encabezado dentro con el nombre de glew.h, glxew .h y wglew.h

Archivos de encabezado GLEW

Abra Finder y vaya a /usr/local/lib y los archivos de la biblioteca GLEW ya estarán presentes allí

Archivos de la biblioteca GLEW

3. Probar y ejecutar

Ahora hemos instalado con éxito GLFW y GLEW. Es hora de codificar. Abra Xcode y cree un nuevo proyecto Xcode. Seleccione Herramienta de línea de comandos y luego continúe y seleccione C++ como idioma.

Proyecto Xcode

Xcode creará un nuevo proyecto de línea de comandos.

Haga clic en el nombre del proyecto y, en la pestaña Configuración de compilación, cambie de Básico a Todo, en la sección Rutas de búsqueda, agregue /usr/local/include en Rutas de búsqueda de encabezado y agregue /usr/local/lib en rutas de búsqueda de biblioteca

Rutas de búsqueda

Haga clic en el nombre del proyecto y, en la pestaña Fases de compilación y en Enlace con bibliotecas binarias, agregue OpenGL.framework y también agregue las bibliotecas GLFW y GLEW recientemente creadas de /usr/local/lib

Binarios de enlace

Ahora estamos listos para codificar en Modern Open GL 4.1 en macOS usando C++ y Xcode. El siguiente código creará una ventana OpenGL utilizando GLFW con salida de pantalla en blanco.

#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;
}

Ventana OpenGL en blanco

Creación de contexto Cross Platform OpenGL (usando SDL2)

Creación de una ventana con contexto OpenGL (carga de la extensión a través de 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;
}

Creando OpenGL 4.1 con C++ y Cocoa

Obteniendo OpenGL

Uno de los conceptos erróneos más comunes sobre OpenGL es que se trata de una biblioteca que se puede instalar desde fuentes de terceros. Este concepto erróneo genera muchas preguntas en forma de “cómo instalo OpenGL” o “dónde descargar el SDK de OpenGL”.

No es así como OpenGL encuentra el camino hacia el sistema informático. OpenGL en sí mismo es simplemente un conjunto de especificaciones sobre qué comandos debe seguir una implementación. Así que es la implementación lo que importa. Y por el momento, las implementaciones de OpenGL son parte de los controladores de GPU. Esto podría cambiar en el futuro, cuando la nueva interfaz de programación de la GPU permita realmente implementar OpenGL como una biblioteca, pero por ahora es una API de programación para los controladores de gráficos.

Cuando OpenGL se lanzó por primera vez, la API de alguna manera encontró su camino en el contrato ABI (Application Binary Interface) de Windows, Solaris y Linux (LSB-4 Desktop), además de su origen Sun Irix. Apple siguió y, de hecho, integró OpenGL tan profundamente en MacOS X, que la versión de OpenGL disponible está estrechamente relacionada con la versión de MacOS X instalada. Esto tiene el efecto notable de que los entornos de programación del sistema para estos sistemas operativos (es decir, la cadena de herramientas del compilador y del enlazador que se dirige de forma nativa a estos sistemas) deben entregar también definiciones de API de OpenGL. Por lo tanto, no es necesario instalar un SDK para OpenGL. Es técnicamente posible programar OpenGL en estos sistemas operativos sin el requisito de instalar un SDK dedicado, suponiendo que esté instalado un entorno de compilación que siga la ABI de destino.

Un efecto secundario de estas reglas estrictas de ABI es que la versión de OpenGL expuesta a través de la interfaz de enlace es el mínimo común denominador que los programas que se ejecutan en la plataforma de destino pueden esperar que esté disponible. Por lo tanto, se debe acceder a las funciones modernas de OpenGL a través del mecanismo de extensión, que se describe en profundidad por separado.

##Linux En Linux es bastante común compartimentar los paquetes de desarrollo para diferentes aspectos del sistema, de modo que estos puedan actualizarse individualmente. En la mayoría de las distribuciones de Linux, los archivos de desarrollo para OpenGL están contenidos en un paquete dedicado, que suele ser una dependencia para un metapaquete de desarrollo de aplicaciones de escritorio. Por lo tanto, la instalación de los archivos de desarrollo de OpenGL para Linux generalmente se realiza con la instalación de los metapaquetes de desarrollo de escritorio.*

Microsoft Windows

La biblioteca de enlaces API opengl32.dll (llamada así para las versiones de Windows de 32 y 64 bits) se envía de forma predeterminada con todas las versiones de Windows desde Windows NT-4 y Windows 95B (ambas de 1997). Sin embargo, esta DLL no proporciona una implementación real de OpenGL (aparte de un respaldo de software cuyo único propósito es actuar como una red de seguridad para los programas si no se instala ninguna otra implementación de OpenGL). ¡Esta DLL pertenece a Windows y no debe modificarse ni moverse! Las versiones modernas de OpenGL se envían como parte del llamado Controlador de cliente instalable (ICD) y se accede a través del opengl32.dll predeterminado que viene preinstalado con cada versión de Windows. Sin embargo, Microsoft decidió internamente que los controladores de gráficos instalados a través de Windows Update no instalarían/actualizarían un OpenGL ICD. Como tales instalaciones nuevas de Windows con controladores instalados automáticamente carecen de soporte para las características modernas de OpenGL. Para obtener un ICD de OpenGL con funciones modernas, los controladores de gráficos deben descargarse directamente del sitio web del proveedor de la GPU e instalarse manualmente.

En cuanto al desarrollo, no se deben tomar medidas adicionales per-se. Todos los compiladores de C/C++ que siguen las especificaciones ABI de Windows se envían con encabezados y el código auxiliar del vinculador (opengl32.lib) necesarios para compilar y vincular ejecutables que utilizan OpenGL.

Crear contexto Opengl con Java y LWJGL 3.0

En este código de ejemplo, crearemos una ventana Opengl en blanco usando LWJGL 3.0+, esto no contiene pasos para crear el proyecto en su IDE

ingrese la descripción de la imagen aquí

  1. Cree un nombre de clase WindowManager que contendrá toda la caldera plate code for creating a opengl context window on screen

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. A continuación, cree una clase que contenga el bucle de representación principal, que llamará a todas las funciones anteriores creadas

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();
    }
}

Para obtener más detalles, consulta la Guía LWJGL oficial