Ricerca…


Osservazioni

OpenGL è uno standard aperto per il rendering di grafica 2D e 3D sfruttando l'hardware grafico. OpenGL è stato implementato attraverso una straordinaria gamma di piattaforme che consentono alle app di targeting di OpenGL di essere estremamente flessibili.

Versioni

Versione Data di rilascio
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

Ottenere OpenGL

Uno dei malintesi più comuni su OpenGL è che si trattava di una libreria che poteva essere installata da fonti di terze parti. Questo equivoco porta a molte domande nella forma "come installare OpenGL" o "dove scaricare OpenGL SDK".

Non è così che OpenGL trova la strada nel sistema informatico. OpenGL di per sé è semplicemente un insieme di specifiche su quali comandi deve seguire un'implementazione. Quindi è l'implementazione che conta. E per il momento, le implementazioni OpenGL fanno parte dei driver GPU. Questo potrebbe cambiare in futuro, quando la nuova interfaccia di programmazione della GPU permetterà di implementare veramente OpenGL come libreria, ma per ora è un'API di programmazione verso i driver grafici.

Quando OpenGL è stato rilasciato, l'API ha trovato la sua strada nel contratto ABI (Application Binary Interface) di Windows, Solaris e Linux (LSB-4 Desktop) oltre alla sua origine Sun Irix. Apple ha seguito e integrato OpenGL così profondamente in MacOS X, che la versione OpenGL disponibile è strettamente accoppiata alla versione di MacOS X installata. Ciò ha l'effetto notevole, che gli ambienti di programmazione di sistema per questi sistemi operativi (ovvero il toolchain del compilatore e del linker che ha come target questi sistemi) devono fornire anche le definizioni API OpenGL. Tale non è necessario per installare effettivamente un SDK per OpenGL. È tecnicamente possibile programmare OpenGL su questi sistemi operativi senza l'obbligo di installare un SDK dedicato, presupponendo che sia installato un ambiente di costruzione che segue l'ABI di destinazione.

Un effetto collaterale di queste rigide regole ABI è che la versione OpenGL esposta attraverso l'interfaccia vincolante è un minimo comune denominatore che i programmi in esecuzione sulla piattaforma di destinazione potrebbero aspettarsi di essere disponibili. Quindi le moderne funzionalità OpenGL sono accessibili tramite il meccanismo di estensione, che viene descritto separatamente in profondità.

Linux

In Linux è piuttosto comune compartimentare i pacchetti di sviluppo per diversi aspetti del sistema, in modo che questi possano essere aggiornati individualmente. Nella maggior parte delle distribuzioni Linux i file di sviluppo per OpenGL sono contenuti in un pacchetto dedicato, che di solito è una dipendenza per un meta-pacchetto di sviluppo di applicazioni desktop. Di conseguenza, l'installazione dei file di sviluppo OpenGL per Linux viene normalmente eseguita con l'installazione dei pacchetti meta di sviluppo desktop *.

Microsoft Windows

La libreria di collegamento API opengl32.dll (chiamata così per entrambe le versioni a 32 e 64 bit di Windows) viene fornita di default con ogni versione di Windows da Windows NT-4 e Windows 95B (entrambi circa 1997). Tuttavia questa DLL non fornisce una vera implementazione OpenGL (a parte un fallback del software il cui unico scopo è quello di fungere da rete di sicurezza per i programmi se non è installata nessuna altra implementazione OpenGL). Questa DLL appartiene a Windows e non deve essere modificata o spostata! Le versioni moderne di OpenGL vengono fornite come parte del cosiddetto Installable Client Driver (ICD) e sono accessibili tramite il file opengl32.dll predefinito preinstallato con tutte le versioni di Windows. Tuttavia, è stato deciso internamente da Microsoft, tuttavia, che i driver grafici installati tramite Windows Update non installassero / aggiornassero un ICD OpenGL. Poiché tali nuove installazioni di Windows con driver installati automaticamente mancano di supporto per le moderne funzionalità OpenGL. Per ottenere un ICD OpenGL con funzionalità moderne, i driver grafici devono essere scaricati direttamente dal sito Web del fornitore della GPU e installati manualmente.

Per quanto riguarda lo sviluppo, non è necessario adottare ulteriori passaggi. Tutti i compilatori C / C ++ che seguono le specifiche ABI di Windows vengono forniti con intestazioni e lo stub del linker (opengl32.lib) necessari per creare e collegare i file eseguibili che fanno uso di OpenGL.

Impostazione OpenGL manuale su Windows

Completo codice di esempio incluso alla fine

Componenti di Windows per OpenGL

WGL

WGL (può essere pronunciato wiggle ) sta per "Windows-GL", come in "un'interfaccia tra Windows e OpenGL" - un insieme di funzioni dell'API di Windows per comunicare con OpenGL. Le funzioni WGL hanno un prefisso wgl e i suoi token hanno un prefisso WGL_ .

La versione OpenGL predefinita supportata sui sistemi Microsoft è 1.1. Questa è una versione molto vecchia (la più recente è 4.5). Il modo per ottenere le versioni più recenti è aggiornare i driver grafici, ma la tua scheda grafica deve supportare quelle nuove versioni.

L'elenco completo delle funzioni WGL può essere trovato qui .

Interfaccia dispositivo grafica (GDI)

GDI (oggi aggiornato a GDI +) è un'interfaccia di disegno 2D che consente di disegnare su una finestra in Windows. È necessario GDI per inizializzare OpenGL e consentirgli di interagire con esso (ma in realtà non utilizzerà GDI stesso).

In GDI, ogni finestra ha un contesto del dispositivo (DC) che viene utilizzato per identificare il target del disegno quando si chiamano le funzioni (lo si passa come parametro). Tuttavia, OpenGL utilizza il proprio contesto di rendering (RC) . Quindi, DC verrà utilizzato per creare RC.


Impostazione di base

Creare una finestra

Quindi per fare cose in OpenGL, abbiamo bisogno di RC, e per ottenere RC, abbiamo bisogno di DC, e per ottenere DC abbiamo bisogno di una finestra. La creazione di una finestra utilizzando l'API di Windows richiede diversi passaggi. Questa è una routine di base, quindi per una spiegazione più dettagliata, dovresti consultare altra documentazione, perché non si tratta dell'utilizzo dell'API di Windows.

Questa è un'installazione di Windows, quindi è necessario includere Windows.h e il punto di ingresso del programma deve essere la procedura WinMain con i relativi parametri. Il programma deve anche essere collegato a opengl32.dll ea gdi32.dll (indipendentemente dal fatto che si sia sul sistema a 64 o 32 bit).

Per prima cosa dobbiamo descrivere la nostra finestra usando la struttura WNDCLASS . Contiene informazioni sulla finestra che vogliamo creare:

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

Per una spiegazione precisa del significato di ciascun campo (e per un elenco completo di campi), consultare la documentazione di MSDN.

Quindi, possiamo creare una finestra usando CreateWindowEx . Dopo aver creato la finestra, possiamo acquisire la sua 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);
/* ************* */

Infine, dobbiamo creare un loop di messaggi che accolga gli eventi della finestra dal 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 pixel

OpenGL ha bisogno di conoscere alcune informazioni sulla nostra finestra, come ad esempio color bitness, metodo di buffering e così via. Per questo, usiamo un formato pixel . Tuttavia, possiamo solo suggerire al sistema operativo che tipo di formato pixel abbiamo bisogno e il sistema operativo fornirà il supporto più simile , non ne abbiamo il controllo diretto. Questo è il motivo per cui è chiamato solo un descrittore .

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

Abbiamo attivato il doppio buffering nel campo dwFlags , quindi dobbiamo chiamare SwapBuffers per vedere le cose dopo il disegno.

Contesto di rendering

Dopodiché, possiamo semplicemente creare il nostro contesto di rendering:

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

Nota che solo un thread può usare l'RC alla volta. Se desideri utilizzarlo da un altro thread in un secondo momento, devi chiamarlo wglMakeCurrent per attivarlo di nuovo (questo lo disattiverà sul thread al momento attivo e così via).

Ottenere le funzioni OpenGL

Le funzioni OpenGL si ottengono utilizzando i puntatori di funzione. La procedura generale è:

  1. In qualche modo ottenere i tipi di puntatore di funzione (essenzialmente i prototipi di funzione)
  2. Dichiara ogni funzione che vorremmo usare (con il suo tipo di puntatore di funzione)
  3. Ottieni la funzione attuale

Ad esempio, considera 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 "puntatore alla funzione", quindi segue il nome di una funzione OpenGL e "PROC" alla fine, ovvero il solito nome del tipo di puntatore della funzione OpenGL.)

Ecco come è fatto su Windows. Come accennato in precedenza, Microsoft spedisce solo OpenGL 1.1. Innanzitutto, i tipi di puntatore a funzione per quella versione possono essere trovati includendo GL/gl.h Dopodiché, dichiariamo tutte le funzioni che intendiamo usare come mostrato sopra (facendo ciò in un file di intestazione e dichiarandole "extern" ci permetterebbe di usarle tutte dopo averle caricate una volta, includendolo semplicemente). Infine, il caricamento delle funzioni di OpenGL 1.1 viene effettuato aprendo la DLL:

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

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

FreeLibrary(gl_module);

Tuttavia, probabilmente vogliamo un po 'più di OpenGL 1.1. Ma Windows non ci fornisce i prototipi di funzioni o le funzioni esportate per qualcosa al di sopra di questo. I prototipi devono essere acquisiti dal registro OpenGL . Ci sono tre file di interesse: GL/glext.h , GL/glcorearb.h e GL/wglext.h .

Per completare GL/gl.h fornito da Windows, abbiamo bisogno di GL/glext.h . Contiene (come descritto dal registro) "OpenGL 1.2 e versioni successive del profilo di compatibilità e delle interfacce di estensione" (ulteriori informazioni sui profili e le estensioni in seguito, dove vedremo che in realtà non è una buona idea usare questi due file ).

Le funzioni effettive devono essere ottenute da wglGetProcAddress (non è necessario aprire la DLL per questo tipo, non sono lì, basta usare la funzione). Con esso, possiamo recuperare tutte le funzioni da OpenGL 1.2 e versioni successive (ma non da 1.1). Si noti che, affinché funzioni correttamente, il contesto di rendering OpenGL deve essere creato e reso aggiornato . Quindi, ad esempio, 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");

Possiamo effettivamente costruire una procedura get_proc wrapper che utilizza sia wglGetProcAddress che 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;
}

Quindi, per concludere, creeremo un file di intestazione pieno di dichiarazioni di puntatori a funzioni come questa:

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

Possiamo quindi creare una procedura come load_gl_functions che chiamiamo una sola volta, e funziona così:

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

E sei tutto pronto! Basta includere l'intestazione con i puntatori di funzione e GL lontano.


Migliore configurazione

Profili OpenGL

OpenGL è in fase di sviluppo da oltre 20 anni e gli sviluppatori sono sempre stati severi riguardo alla retrocompatibilità (BC) . L'aggiunta di una nuova funzionalità è molto difficile a causa di ciò. Così, nel 2008, è stato separato in due "profili". Core e compatibilità . Il profilo principale interrompe BC a favore di miglioramenti delle prestazioni e alcune delle nuove funzionalità. Rimuove anche completamente alcune funzionalità legacy. Il profilo di compatibilità mantiene BC con tutte le versioni fino a 1.0 e alcune nuove funzionalità non sono disponibili su di esso. È solo da utilizzare per vecchi sistemi legacy, tutte le nuove applicazioni dovrebbero utilizzare il profilo principale.

Per questo motivo, c'è un problema con la nostra configurazione di base: fornisce solo il contesto retrocompatibile con OpenGL 1.0. Anche il formato pixel è limitato. C'è un approccio migliore, usando le estensioni.

Estensioni OpenGL

Qualsiasi aggiunta alla funzionalità originale di OpenGL è chiamata estensioni. In generale, possono rendere alcune cose legali che non erano precedenti, estendere la gamma di valori dei parametri, estendere GLSL e persino aggiungere funzionalità completamente nuove.

Esistono tre principali gruppi di estensioni: vendor, EXT e ARB. Le estensioni fornitore provengono da un fornitore specifico e hanno un marchio specifico del venditore, come AMD o NV. Le estensioni EXT sono realizzate da diversi fornitori che lavorano insieme. Dopo un po 'di tempo, potrebbero diventare estensioni ARB, che sono tutte ufficialmente supportate e approvate dall'ARB.

Per acquisire i tipi di puntatori di funzione e i prototipi di funzione di tutte le estensioni e come menzionato in precedenza, tutti i tipi di puntatore di funzione da OpenGL 1.2 e successivi , è necessario scaricare i file di intestazione dal registro OpenGL . Come discusso, per le nuove applicazioni è preferibile utilizzare il profilo principale, quindi sarebbe preferibile includere GL/glcorearb.h invece di GL/gl.h e GL/glext.h (se si utilizza GL/glcorearb.h quindi non indossare includere GL/gl.h ).

Esistono anche estensioni per WGL, in GL/wglext.h . Ad esempio, la funzione per ottenere l'elenco di tutte le estensioni supportate è in realtà un'estensione stessa, il wglGetExtensionsStringARB (restituisce una stringa grande con un elenco separato da spazi di tutte le estensioni supportate).

Anche ottenere le estensioni è gestito tramite wglGetProcAddress , quindi possiamo semplicemente usare il nostro wrapper come prima.

Formato pixel avanzato e creazione del contesto

L'estensione WGL_ARB_pixel_format ci consente la creazione avanzata di formati di pixel. Diversamente da prima, non usiamo una struttura. Invece, passiamo la lista degli attributi ricercati.

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

Allo stesso modo, l'estensione WGL_ARB_create_context ci consente la creazione di un contesto avanzato:

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

Per una spiegazione precisa dei parametri e delle funzioni, consultare le specifiche OpenGL.

Perché non abbiamo appena iniziato con loro? Bene, questo perché le estensioni ci permettono di farlo, e per ottenere le estensioni abbiamo bisogno di wglGetProcAddress , ma funziona solo con un contesto valido attivo. Quindi, in sostanza, prima di essere in grado di creare il contesto che vogliamo, è necessario avere già alcuni contesti attivi e in genere viene definito un contesto fittizio .

Tuttavia, Windows non consente di impostare il formato pixel di una finestra più di una volta. Per questo motivo, la finestra deve essere distrutta e ricreata per applicare nuove cose:

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

// Recreate the window...

Codice di esempio 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;
}

Compilato con g++ GLExample.cpp -lopengl32 -lgdi32 con MinGW / Cygwin o cl GLExample.cpp opengl32.lib gdi32.lib user32.lib con compilatore MSVC. Assicurarsi tuttavia che le intestazioni dal registro OpenGL siano nel percorso di inclusione. In caso contrario, utilizzare flag -I per g++ o /I per cl per indicare al compilatore dove si trovano.

Creazione di OpenGL 4.1 con C ++ e Cocoa

Nota: in questo esempio ci saranno alcuni Objective-c. In questo esempio creeremo un wrapper per C ++, quindi non preoccuparti di questo.

Innanzitutto avvia Xcode e crea un progetto.

inserisci la descrizione dell'immagine qui

E seleziona un'applicazione Cocoa inserisci la descrizione dell'immagine qui

Elimina tutte le fonti tranne il file Info.plist. (La tua app non funzionerà senza di essa)

Crea 4 nuovi file sorgente: un file Objective-c ++ e un'intestazione (ho chiamato il mio MacApp) Una classe C ++ (ho chiamato il mio (Applicazione)

In alto a sinistra (con il nome del progetto) fai clic su di esso e aggiungi strutture e librerie collegate. Aggiungi: OpenGL.Framework AppKit.Framework GLKit.Framework

Il tuo progetto avrà probabilmente questo aspetto:

inserisci la descrizione dell'immagine qui

NSApplication è la classe principale che si utilizza durante la creazione di un'app MacOS. Ti permette di registrare finestre e prendere eventi.

Vogliamo registrare (la nostra) finestra per l'applicazione NSA. Prima crea nell'header obiettivo-c ++ una classe obiettivo-c che erediti da NSWindow e implementa NSApplicationDelegate NSWindow ha bisogno di un puntatore all'applicazione C ++, una OpenGL View e un timer per il ciclo di disegno

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

Chiamiamo questo dal principale con

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

L'implementazione della nostra finestra è in realtà abbastanza semplice. Prima dichiariamo sintetizzando la nostra glview e aggiungiamo un obiettivo globale-c booleano quando la finestra dovrebbe chiudersi.

#import "MacApp.h"

@implementation MacApp

@synthesize glView;

BOOL shouldStop = NO;

Ora per il costruttore. La mia preferenza è usare 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;
}

Bene ... ora abbiamo un'app eseguibile. Potresti vedere uno schermo nero o uno sfarfallio.

Iniziamo a disegnare un triangolo fantastico (in c ++)

La mia intestazione dell'applicazione

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

L'implemento:

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

Ora dobbiamo solo richiamare l'aggiornamento più e più volte (se vuoi che qualcosa si muova) Implementa nella tua classe obiettivo-c

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

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

}

E aggiungi questo metodo nell'implementazione della tua classe obiettivo-c:

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

questo chiamerà più e più volte la funzione di aggiornamento della tua classe c ++ (ogni 0,000001 secondi per essere precisi)

Per finire chiudiamo la finestra quando viene premuto il pulsante di chiusura:

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

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

Congratulazioni, ora hai una finestra fantastica con un triangolo OpenGL senza alcun framework di terze parti. risultato finale

Creazione del contesto OpenGL di Cross Platform (utilizzando SDL2)

Creazione di una finestra con contesto OpenGL (estensione caricamento tramite 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;
}

Setup Modern OpenGL 4.1 su macOS (Xcode, GLFW e GLEW)

1. Installare GLFW

Il primo passo è creare una finestra OpenGL. GLFW è una libreria open source, multi-piattaforma per la creazione di finestre con OpenGL, per installare GLFW prima scaricare i suoi file da www.glfw.org

GLFW Pagina web

Estrai la cartella GLFW e il suo contenuto sarà simile a questo

Contenuto della cartella GLFW

Scarica e installa CMake per creare GLFW. Vai su www.cmake.org/download/ , scarica CMake e installa per MAC OS X

Scarica la pagina Web di CMake

Se Xcode non è installato. Scarica e installa Xcode dal Mac App Store.

Xcode dal Mac App Store

Crea una nuova cartella Crea all'interno della cartella GLFW

Cartella GLFW dopo aver creato la cartella "Build"

Apri CMake, fai clic sul pulsante Sfoglia sorgente per selezionare la cartella GLFW (assicurati che CMakeLists.txt) si trovi all'interno di quella cartella. Successivamente, fai clic sul pulsante Cerca , quindi seleziona la cartella Crea appena creata nel passaggio precedente.

Percorsi di CMake

Ora fai clic sul pulsante Configura e seleziona Xcode come generatore con l' opzione Usa compilatori nativi predefiniti e fai clic su Fine .

Makefile per Xcode

Spunta l'opzione BUILD_SHARED_LIBS e quindi fai nuovamente clic sul pulsante Configura e infine fai clic sul pulsante Genera .

Seleziona BUILD_SHARED_LIBS

Dopo la generazione, CMake dovrebbe assomigliare a questo

CMake finale

Ora Apri Finder e goto / usr , crea un nome di cartella locale se non già presente. Aprire la cartella locale e creare due cartelle include e lib se non già presenti.

Ora apri la cartella GLFW e vai a Build (dove CMake ha creato i file). Aprire il file GLFW.xcodeproj in Xcode.

Xcode Project File

Seleziona Installa> My Mac e quindi fai clic su run (pulsante Play a forma di).

Installa GLFW

Ora è installato correttamente (ignora gli avvisi).

Per assicurarti che Open Finder e la cartella goto / usr / local / lib e i tre file della libreria GLFW siano già presenti (Se non lo sono, apri la cartella Build nella cartella GLFW e vai a src / Debug copia tutti i file in / usr / local / lib )

GLFW Lib Files

Apri Finder e goto / usr / local / include e una cartella GLFW sarà già presente con due file di intestazione al suo interno per nome di glfw3.h e glfw3native.h

File di intestazione GLFW

2. Installa GLEW

GLEW è una libreria multipiattaforma che aiuta a interrogare e caricare le estensioni OpenGL. Fornisce meccanismi di runtime per determinare quali estensioni OpenGL sono supportate sulla piattaforma di destinazione. È solo per la moderna OpenGL (OpenGL versione 3.2 e successive che richiede funzioni da determinare in fase di runtime). Per installare prima scarica i suoi file da glew.sourceforge.net

GLEW Pagina web

Estrai la cartella GLFW e il suo contenuto sarà simile a questo.

GLEW Contenuto della cartella

Ora apri Terminale, vai a GLEW Folder e digita i seguenti comandi

make
sudo make install 
make clean

Adesso GLEW è stato installato con successo. Per assicurarti che sia installato, Apri Finder, vai su / usr / local / include e una cartella GL sarà già presente con tre file di header al suo interno per nome di glew.h , glxew.h e wglew.h

GLEW Header Files

Apri Finder e vai a / usr / local / lib e i file della libreria GLEW saranno già presenti lì

GLEW Library Files

3. Test ed esecuzione

Ora abbiamo installato correttamente GLFW e GLEW. È tempo di programmare. Apri Xcode e crea un nuovo progetto Xcode. Seleziona lo strumento della riga di comando, quindi procedi e seleziona C ++ come lingua.

Progetto Xcode

Xcode creerà un nuovo progetto da riga di comando.

Fare clic sul nome del progetto e, nella scheda Impostazioni di configurazione, passare da Base a Tutti , nella sezione Percorsi di ricerca , aggiungere / usr / local / include nei Percorsi di ricerca dell'intestazione e aggiungere / usr / local / lib nei percorsi di ricerca della libreria

Percorsi di ricerca

Fare clic sul nome del progetto, e nella scheda Fasi di creazione e sotto Collega con librerie binarie aggiungere OpenGL.framework e aggiungere anche le librerie GLFW e GLEW create di recente da / usr / local / lib

Link Binari

Ora siamo pronti per programmare in Modern Open GL 4.1 su macOS usando C ++ e Xcode. Il codice seguente creerà una finestra OpenGL usando GLFW con Output schermo vuoto.

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

Finestra OpenGL vuota

Creare il contesto Opengl con Java e LWJGL 3.0

In questo codice di esempio creeremo una finestra Opengl vuota usando LWJGL 3.0+, questo non contiene passaggi per creare il progetto nel tuo IDE

inserisci la descrizione dell'immagine qui

  1. Crea un nome di classe WindowManager che conterrà tutto il codice della piastra della caldaia per creare una finestra di contesto opengl sullo schermo

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. Quindi crea una classe che contiene il ciclo di rendering principale, che chiamerà tutte le funzioni sopra create

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

Per ulteriori dettagli, consultare la guida ufficiale LWJGL



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow