Começando com opengl
Configuração manual do OpenGL no Windows
Código de exemplo completo incluído no final
Componentes do Windows para OpenGL
WGL
WGL (pode ser pronunciado wiggle) significa “Windows-GL”, como em “uma interface entre Windows e OpenGL” - um conjunto de funções da API do Windows para se comunicar com o OpenGL. As funções WGL têm um prefixo wgl e seus tokens têm um prefixo WGL_.
A versão padrão do OpenGL com suporte em sistemas Microsoft é 1.1. Essa é uma versão muito antiga (a mais recente é a 4.5). A maneira de obter as versões mais recentes é atualizar seus drivers gráficos, mas sua placa gráfica deve suportar essas novas versões.
A lista completa de funções WGL pode ser encontrada aqui.
Interface do dispositivo gráfico (GDI)
GDI (hoje atualizado para GDI+) é uma interface de desenho 2D que permite desenhar em uma janela no Windows. Você precisa do GDI para inicializar o OpenGL e permitir que ele interaja com ele (mas não usará o próprio GDI).
No GDI, cada janela tem um contexto de dispositivo (DC) que é usado para identificar o destino do desenho ao chamar funções (você o passa como parâmetro). No entanto, o OpenGL usa seu próprio contexto de renderização (RC). Então, DC será usado para criar RC.
Configuração básica
Criando uma janela
Então, para fazer coisas em OpenGL, precisamos de RC, e para obter RC, precisamos de DC, e para obter DC precisamos de uma janela. A criação de uma janela usando a API do Windows requer várias etapas. Esta é uma rotina básica, portanto, para uma explicação mais detalhada, você deve consultar outra documentação, pois não se trata de usar a API do Windows.
Esta é uma configuração do Windows, portanto, Windows.h
deve ser incluído, e o ponto de entrada do programa deve ser o procedimento WinMain
com seus parâmetros. O programa também precisa estar vinculado ao opengl32.dll
e ao gdi32.dll
(independentemente de você estar em um sistema de 64 ou 32 bits).
Primeiro precisamos descrever nossa janela usando a estrutura WNDCLASS
. Ele contém informações sobre a janela que queremos criar:
/* 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 uma explicação precisa do significado de cada campo (e para uma lista completa de campos), consulte a documentação do MSDN.
Então, podemos criar uma janela usando CreateWindowEx
. Após a criação da janela, podemos adquirir seu 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);
/* ************* */
Por fim, precisamos criar um loop de mensagens que receba eventos de janela do SO:
/* 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 pixel
O OpenGL precisa saber algumas informações sobre nossa janela, como bitness de cor, método de buffer e assim por diante. Para isso, usamos um formato de pixel. No entanto, só podemos sugerir ao sistema operacional que tipo de formato de pixel precisamos, e o sistema operacional fornecerá o mais semelhante suportado, não temos controle direto sobre ele. É por isso que é chamado apenas de descritor.
/* 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);
/* *********************** */
Habilitamos o buffer duplo no campo dwFlags
, então devemos chamar SwapBuffers
para ver as coisas após o desenho.
Contexto de renderização
Depois disso, podemos simplesmente criar nosso contexto de renderização:
/* RENDERING CONTEXT */
HGLRC rc = wglCreateContext(dc);
wglMakeCurrent(dc, rc);
/* ***************** */
Observe que apenas um thread pode usar o RC por vez. Se você deseja usá-lo de outro thread mais tarde, você deve chamar wglMakeCurrent
lá para ativá-lo novamente (isso irá desativá-lo no thread que está ativo no momento e assim por diante).
Obtendo funções do OpenGL
As funções OpenGL são obtidas usando ponteiros de função. O procedimento geral é:
- De alguma forma, obtenha tipos de ponteiro de função (essencialmente os protótipos de função)
- Declare cada função que gostaríamos de usar (com seu tipo de ponteiro de função)
- Obtenha a função real
Por exemplo, 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 “ponteiro para função”, depois segue o nome de uma função OpenGL e “PROC” no final - esse é o nome do tipo de ponteiro de função OpenGL usual.)
Veja como isso é feito no Windows. Como mencionado anteriormente, a Microsoft fornece apenas OpenGL 1.1. Primeiro, os tipos de ponteiro de função para essa versão podem ser encontrados incluindo GL/gl.h
. Depois disso, declaramos todas as funções que pretendemos usar conforme mostrado acima (fazendo isso em um arquivo de cabeçalho e declará-las “externas” nos permitiria usá-las depois de carregá-las uma vez, apenas incluindo-a). Por fim, o carregamento das funções do OpenGL 1.1 é feito abrindo a DLL:
HMODULE gl_module = LoadLibrary(TEXT("opengl32.dll"));
/* Load all the functions here */
glBegin = (PFNGLBEGINPROC)GetProcAddress("glBegin");
// ...
/* *************************** */
FreeLibrary(gl_module);
No entanto, provavelmente queremos um pouco mais do que o OpenGL 1.1. Mas o Windows não nos fornece os protótipos de funções ou funções exportadas para nada acima disso. Os protótipos precisam ser adquiridos do registro OpenGL. Existem três arquivos de nosso interesse: GL/glext.h
, GL/glcorearb.h
e GL/wglext.h
.
Para completar o GL/gl.h
fornecido pelo Windows, precisamos de GL/glext.h
. Ele contém (conforme descrito pelo registro) “Perfil de compatibilidade OpenGL 1.2 e superior e interfaces de extensão” (mais sobre perfis e extensões posteriormente, onde veremos que na verdade não é uma boa ideia usar esses dois arquivos) .
As funções reais precisam ser obtidas por wglGetProcAddress
(não há necessidade de abrir a DLL para esse cara, elas não estão lá, apenas use a função). Com ele, podemos buscar todas as funções do OpenGL 1.2 e superior (mas não 1.1). Observe que, para que funcione corretamente, o contexto de renderização do OpenGL deve ser criado e atualizado. Assim, por exemplo, 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");
Na verdade, podemos construir um procedimento wrapper get_proc
que usa tanto wglGetProcAddress
quanto 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;
}
Então, para encerrar, criaríamos um arquivo de cabeçalho cheio de declarações de ponteiro de função como esta:
extern PFNGLCLEARCOLORPROC glClearColor;
extern PFNGLCLEARDEPTHPROC glClearDepth;
extern PFNGLCLEARPROC glClear;
extern PFNGLCLEARBUFFERIVPROC glClearBufferiv;
extern PFNGLCLEARBUFFERFVPROC glClearBufferfv;
// And so on...
Podemos então criar um procedimento como load_gl_functions
que chamamos apenas uma vez e funciona assim:
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 está tudo pronto! Basta incluir o cabeçalho com os ponteiros de função e GL afastado.
Melhor configuração
Perfis OpenGL
O OpenGL está em desenvolvimento há mais de 20 anos, e os desenvolvedores sempre foram rigorosos quanto à compatibilidade com versões anteriores (BC). Adicionar um novo recurso é muito difícil por causa disso. Assim, em 2008, foi separado em dois “perfis”. Núcleo e compatibilidade. O perfil do núcleo quebra o BC em favor de melhorias de desempenho e alguns dos novos recursos. Ele até remove completamente alguns recursos herdados. O perfil de compatibilidade mantém o BC com todas as versões até 1.0, e alguns novos recursos não estão disponíveis nele. Ele deve ser usado apenas para sistemas legados antigos, todos os novos aplicativos devem usar o perfil principal.
Por causa disso, há um problema com nossa configuração básica - ela fornece apenas o contexto que é compatível com versões anteriores do OpenGL 1.0. O formato de pixel também é limitado. Existe uma abordagem melhor, usando extensões.
Extensões OpenGL
Qualquer adição à funcionalidade original do OpenGL é chamada de extensões. Geralmente, eles podem tornar algumas coisas legais que não eram antes, estender o intervalo de valores dos parâmetros, estender o GLSL e até mesmo adicionar funcionalidades completamente novas.
Existem três grupos principais de extensões: fornecedor, EXT e ARB. As extensões de fornecedor vêm de um fornecedor específico e têm uma marca específica do fornecedor, como AMD ou NV. As extensões EXT são feitas por vários fornecedores trabalhando juntos. Depois de algum tempo, eles podem se tornar extensões ARB, que são todas as oficialmente suportadas e aprovadas pela ARB.
Para adquirir tipos de ponteiros de função e protótipos de função de todas as extensões e como mencionado anteriormente, todos os tipos de ponteiros de função do OpenGL 1.2 e superior, deve-se baixar os arquivos de cabeçalho do registro OpenGL. Conforme discutido, para novos aplicativos é melhor usar o perfil principal, então seria preferível incluir GL/glcorearb.h
em vez de GL/gl.h
e GL/glext.h
(se você estiver usando GL/glcorearb.h
, não inclua GL/gl.h
).
Existem também extensões para o WGL, em GL/wglext.h
. Por exemplo, a função para obter a lista de todas as extensões suportadas é na verdade uma própria extensão, a wglGetExtensionsStringARB
(ela retorna uma string grande com uma lista separada por espaços de todas as extensões suportadas).
A obtenção de extensões também é tratada via wglGetProcAddress
, então podemos usar nosso wrapper como antes.
Formato de pixel avançado e criação de contexto
A extensão WGL_ARB_pixel_format
nos permite a criação avançada de formatos de pixel. Ao contrário de antes, não usamos uma estrutura. Em vez disso, passamos a lista de atributos desejados.
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);
Da mesma forma, a extensão WGL_ARB_create_context
nos permite a criação avançada de contexto:
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 uma explicação precisa dos parâmetros e funções, consulte a especificação OpenGL.
Por que não começamos com eles? Bem, isso é porque as extensões nos permitem fazer isso, e para obter extensões precisamos de wglGetProcAddress
, mas isso só funciona com um contexto válido ativo. Então, em essência, antes de podermos criar o contexto que queremos, precisamos já ter algum contexto ativo, e geralmente é chamado de contexto fictício.
No entanto, o Windows não permite definir o formato de pixel de uma janela mais de uma vez. Por isso, a janela precisa ser destruída e recriada para aplicar coisas novas:
wglMakeCurrent(dc, NULL);
wglDeleteContext(rc);
ReleaseDC(window_handle, dc);
DestroyWindow(window_handle);
// Recreate the window...
Código de exemplo 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 com g++ GLExample.cpp -lopengl32 -lgdi32
com MinGW/Cygwin ou cl GLExample.cpp opengl32.lib gdi32.lib user32.lib
com compilador MSVC. Certifique-se, no entanto, de que os cabeçalhos do registro OpenGL estejam no caminho de inclusão. Caso contrário, use o sinalizador -I
para g++
ou /I
para cl
para informar ao compilador onde eles são.
Configure o Modern OpenGL 4.1 no macOS (Xcode, GLFW e GLEW)
1. Instalar GLFW
O primeiro passo é criar uma janela OpenGL. GLFW é uma biblioteca multiplataforma de código aberto para criação de janelas com OpenGL, para instalar o GLFW primeiro baixe seus arquivos de www.glfw.org
Extraia a pasta GLFW e seu conteúdo ficará assim
Baixe e instale o CMake para compilar o GLFW. Vá para www.cmake.org/download/, baixe o CMake e instale para MAC OS X
Se o Xcode não estiver instalado. Baixe e instale o Xcode da Mac App Store.
Crie uma nova pasta Build dentro da pasta GLFW
Abra o CMake, clique no botão Browse Source para selecionar a pasta GLFW (certifique-se de que CMakeLists.txt) esteja localizado dentro dessa pasta. Depois disso, clique no botão Browse Build e selecione a pasta Build recém-criada na etapa anterior.
Agora clique no botão Configurar e selecione Xcode como gerador com Usar opção de compiladores nativos padrão e clique em Concluído.
Marque a opção BUILD_SHARED_LIBS e clique no botão Configurar novamente e, finalmente, clique no botão Gerar.
Após a geração, o CMake deve ficar assim
Agora abra o Finder e vá para /usr, crie um nome de pasta local se ainda não estiver lá. Abra a pasta local e crie duas pastas include e lib, caso ainda não existam.
Agora abra a pasta GLFW e vá para Build (onde o CMake construiu os arquivos). Abra o arquivo GLFW.xcodeproj no Xcode.
Selecione instalar > Meu Mac e clique em executar (botão Reproduzir em forma).
Agora está instalado com sucesso (ignore os avisos).
Para garantir que abra o Finder e vá para a pasta /usr/local/lib e três arquivos de biblioteca GLFW já estarão presentes lá (se não, abra a pasta Build dentro da pasta GLFW e vá para **src/Debug ** copie todos os arquivos para /usr/local/lib)
Abra o Finder e vá para /usr/local/include e uma pasta GLFW já estará presente lá com dois arquivos de cabeçalho dentro dela com o nome de glfw3.h e glfw3native.h
2. Instale o GLEW
GLEW é uma biblioteca multiplataforma que ajuda na consulta e carregamento de extensões OpenGL. Ele fornece mecanismos de tempo de execução para determinar quais extensões OpenGL são suportadas na plataforma de destino. É apenas para OpenGL moderno (OpenGL versão 3.2 e superior que requer que as funções sejam determinadas em tempo de execução). Para instalar primeiro baixe seus arquivos de glew.sourceforge.net
Extraia a pasta GLFW e seu conteúdo ficará assim.
Agora abra o Terminal, navegue até a pasta GLEW e digite os seguintes comandos
make
sudo make install
make clean
Agora o GLEW foi instalado com sucesso. Para ter certeza de que está instalado, abra o Finder, vá para /usr/local/include e uma pasta GL já estará presente lá com três arquivos de cabeçalho dentro dela com o nome de glew.h, glxew .h e wglew.h
Abra o Finder e vá para /usr/local/lib e os arquivos da biblioteca GLEW já estarão presentes lá
3. Teste e execute
Agora instalamos com sucesso GLFW e GLEW. É hora de codificar. Abra o Xcode e crie um novo projeto Xcode. Selecione Command Line Tool, prossiga em seguida e selecione C++ como idioma.
O Xcode criará um novo projeto de linha de comando.
Clique no nome do projeto e, na guia Build Settings, alterne de Basic to All, na seção Search Paths, adicione /usr/local/include em Header Search Paths e adicione /usr/local/lib nos caminhos de pesquisa da biblioteca
Clique no nome do projeto e, na guia Build Phases e em Link With Binary Libraries, adicione OpenGL.framework e também adicione as bibliotecas GLFW e GLEW criadas recentemente de /usr/local/lib
Agora estamos prontos para codificar no Modern Open GL 4.1 no macOS usando C++ e Xcode. O código a seguir criará uma janela OpenGL usando GLFW com saída de tela em branco.
#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;
}
Criação de contexto OpenGL de plataforma cruzada (usando SDL2)
Criando uma janela com contexto OpenGL (carregamento de extensão atravé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;
}
Criando OpenGL 4.1 com C++ e Cocoa
Obtendo OpenGL
Um dos equívocos mais comuns sobre o OpenGL é que era uma biblioteca que poderia ser instalada a partir de fontes de terceiros. Esse equívoco leva a muitas perguntas na forma de “como instalar o OpenGL” ou “onde baixar o SDK do OpenGL”.
Não é assim que o OpenGL encontra o caminho para o sistema de computador. O OpenGL por si só é meramente um conjunto de especificações sobre quais comandos uma implementação deve seguir. Portanto, é a implementação que importa. E, por enquanto, as implementações do OpenGL fazem parte dos drivers da GPU. Isso pode mudar no futuro, quando a nova interface de programação da GPU permitir realmente implementar o OpenGL como uma biblioteca, mas por enquanto é uma API de programação para os drivers gráficos.
Quando o OpenGL foi lançado pela primeira vez, a API de alguma forma encontrou seu caminho para o contrato ABI (Application Binary Interface) do Windows, Solaris e Linux (LSB-4 Desktop), além de sua origem Sun Irix. A Apple seguiu e de fato integrou o OpenGL tão profundamente no MacOS X, que a versão do OpenGL disponível está fortemente acoplada à versão do MacOS X instalada. Isso tem o efeito notável de que os ambientes de programação de sistema para esses sistemas operacionais (ou seja, a cadeia de ferramentas do compilador e do vinculador que visam nativamente esses sistemas) devem fornecer também definições de API OpenGL. Assim, não é necessário instalar um SDK para OpenGL. É tecnicamente possível programar OpenGL nesses sistemas operacionais sem a necessidade de instalar um SDK dedicado, supondo que um ambiente de compilação seguindo a ABI alvo esteja instalado.
Um efeito colateral dessas regras rígidas da ABI é que a versão OpenGL exposta por meio da interface de vinculação é o menor denominador comum que os programas executados na plataforma de destino podem esperar que estejam disponíveis. Portanto, os recursos modernos do OpenGL devem ser acessados por meio do mecanismo de extensão, que é descrito detalhadamente separadamente.
##Linux No Linux é bastante comum compartimentar os pacotes de desenvolvimento para diferentes aspectos do sistema, para que estes possam ser atualizados individualmente. Na maioria das distribuições Linux, os arquivos de desenvolvimento para OpenGL estão contidos em um pacote dedicado, que geralmente é uma dependência de um meta-pacote de desenvolvimento de aplicativos de desktop. Portanto, a instalação dos arquivos de desenvolvimento OpenGL para Linux geralmente é feita com a instalação do(s) metapacote(s) de desenvolvimento para desktop.*
Microsoft Windows
A biblioteca de ligação da API opengl32.dll
(chamada assim para as versões de 32 e 64 bits do Windows) é fornecida por padrão com todas as versões do Windows desde o Windows NT-4 e Windows 95B (ambos ca. 1997). No entanto, esta DLL não fornece uma implementação OpenGL real (além de um fallback de software cujo único objetivo é atuar como uma rede de segurança para programas se nenhuma outra implementação OpenGL estiver instalada). Esta DLL pertence ao Windows e não deve ser alterada ou movida! As versões modernas do OpenGL são enviadas como parte do chamado Installable Client Driver (ICD) e acessadas através do opengl32.dll
padrão que vem pré-instalado com todas as versões do Windows. Foi decidido internamente pela Microsoft, no entanto, que os drivers gráficos instalados através do Windows Update não instalariam/atualizariam um ICD OpenGL. Como essas novas instalações do Windows com drivers instalados automaticamente não têm suporte para recursos modernos do OpenGL. Para obter um ICD OpenGL com recursos modernos, os drivers gráficos devem ser baixados diretamente do site do fornecedor da GPU e instalados manualmente.
Em relação ao desenvolvimento, nenhuma etapa extra deve ser tomada em si. Todos os compiladores C/C++ que seguem as especificações da ABI do Windows são fornecidos com cabeçalhos e o stub do vinculador (opengl32.lib) necessários para compilar e vincular executáveis que usam OpenGL.
Criar contexto Opengl com Java e LWJGL 3.0
Neste código de exemplo, criaremos uma janela Opengl em branco usando LWJGL 3.0+, isso não contém etapas para criar o projeto em seu IDE
- Crie um nome de classe WindowManager que conterá toda a caldeira 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);
}
}
- Em seguida, crie uma classe que contenha o loop de renderização principal, que chamará todas as funções acima criadas
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 mais detalhes, confira oficial Guia LWJGL