Configurando o Ambiente
Na semana passada vimos um pouco do OpenGL, mas não colocamos a mão na massa! Nesse post vou fazer a configuração de ambiente, e no próximo post embarcamos então a nossa aplicação em OpenGL.
Eu disse que gosto de fazer as coisas do jeito mais difícil não é, o meu setup para esse estudo é Neovim + Cmake + VSCPP Compiler. Você não precisa seguir nesse setup, o mais comum é Usar o Visual Studio e configurar tudo nele ~se estiver no Windows claro~.
CMake
CMake é uma família de ferramentas para build, testes e “empacotamento” de aplicações.1
Eu vejo duas grandes vantagens em usar o CMake, primeiro ele é cross-platform o que significa que eu posso carregar as configurações para “qualquer” plataforma que estiver usando, e assim o CMake gera um projeto que eu consigo trabalhar naquela plataforma em específico.
E também o arquivo de configuração dele ser um simples arquivo de texto, fácil de ler e com todas as informações necessárias em um lugar só (se o projeto for muito complexo pode ser que existam configurações específicas em mais de um lugar, mas eu prefiro isso a ter que ficar decorando onde ficam as configurações da IDE x, y ou z)
Bibliotecas externas
Além de utilizarmos o CMake para gerenciar a criação do projeto e builds, como explicado no primeiro post dessa serie precisamos de algumas bibliotecas externas para trabalhar com o OpenGL, e serão:
GLFW para gerenciar contextos, janelas e a I/O.2
GLEW para fazer o carregamento dos módulos OpenGL.3
Estrutura do Projeto
Estou utilizando uma estrutura de pastas comum quando trabalhamos com CMake
📂 Projeto
+--📂Source
+--📂Build
Dentro da pasta Soure ainda criei uma pasta ExternalLibs
, e é nesta pasta
que colocarei as bibliotecas que iremos utilizar.
Você pode encontra os pré-compilados das GLFW e GLEW em seus respectivos
sites, apenas fique atento para fazer o download para a plataforma que estiver
trabalhando.
Dentro de ExternalLibs
Crio uma pasta para cada uma das bibliotecas e extraio
o arquivo zip delas em suas respectivas pastas.
Algumas bibliotecas são especificas para a versão do compilador que você estiver
utilizando, fique atento para extrair a pasta lib correta
No caso do meu
projeto estou usando o compilador do Visual Studio 2019
Feito tudo isso, o projeto deve ter ficado como abaixo
📂 Projeto
+--📂 Source
| +--📂 ExternalLibs
| +--📂 GLEW
| | +--📂 bin
| | +--📂 include
| | +--📂 lib
| |
| +--📂 GLFW
| +--📂 include
| +--📂 lib_vc2019
|
+--📂 Build
CMakeLists.txt
Para gerar os os arquivos de projeto, com as configurações necessárias para o
compilador precisamos escrever um arquivo CmakeLists.txt
que é o arquivo que o
CMake vai ler e montar o projeto.
Crie um arquivo CMakeLists.txt
na sua pasta Source
# Defino qual versão mínima do CMake necessária
CMAKE_MINIMUM_REQUIRED(VERSION 3.20 FATAL_ERROR)
# Defino o nome do projeto e linguagem utilizada
# Depois do Build o executável será LeOpenGL nesse caso
PROJECT(LeOpenGL LANGUAGES CXX)
# Crio uma variável ExternalLibs
SET(ExternalLibs ${CMAKE_CURRENT_SOURCE_DIR}/ExternalLibs)
# Adiciono os diretórios para o linker procurar os arquivos
# necessários de ambas as bibliotecas
LINK_DIRECTORIES(${ExternalLibs}/GLFW/lib_vc2019)
INCLUDE_DIRECTORIES(${ExternalLibs}/GLFW/include)
LINK_DIRECTORIES(${ExternalLibs}/GLEW/lib/release/x64)
INCLUDE_DIRECTORIES(${ExternalLibs}/GLEW/include)
# O CMake consegue achar a biblioteca do OpenGL nas configurações padrões da máquina
FIND_PACKAGE(OPENGL REQUIRED)
# Adiciono um arquivo Hello.cpp ao projeto
ADD_EXECUTABLE(LeOpenGL Hello.cpp)
# Adiciono o Link para as bibliotecas necessárias
TARGET_LINK_LIBRARIES(LeOpenGL glfw3 ${GLFW_LIBRARIES})
TARGET_LINK_LIBRARIES(LeOpenGL glew32 ${GLEW_LIBRARIES})
TARGET_LINK_LIBRARIES(LeOpenGL ${OPENGL_LIBRARIES})
Feito isso vamos criar o arquivo Hello.cpp
apenas para verifica se nossas
configurações estão corretas.
#include <iostream>
int main(void){
std::cout << "Olar OpenGL" << std::endl;
return EXIT_SUCCESS;
}
Assim podemos executar o seguinte comando na pasta raiz do projeto.
$ cmake -S Source -B Build
Ele que irá criar as configurações necessárias para executar o Build de nosso projeto.
E caso não haja nenhuma mensagem de erro podemos executar então
$ cmake --build Build\
E se tudo estiver certo podemos executar nosso arquivo de teste.
$ .\Build\Debug\LeOpenGL.exe
E se tudo deu certo teremos um programa do terminal que escreve Olar OpenGL no terminal
Neste post criamos a infra que iremos utilizar durante os estudos, no próximo post iremos criar uma janela com o GLFW
GLFW
Agora que sabemos que nosso ambiente está configurado e compilando, vamos utilizar o GLFW para criar uma janela. Como quero apenas fazer um teste para ver se está ok, vou copiar descaradamente o código da documentação do GLFW2
#include <iostream>
#include <GLFW/glfw3.h>
int main(void){
GLFWwindow* window;
if(!glfwInit()){
return EXIT_FAILURE;
}
window = glfwCreateWindow(400, 300, "Hello GLFW", NULL, NULL);
if(!window){
glfwTerminate();
return EXIT_FAILURE;
}
glfwMakeContextCurrent(window);
while(!glfwWindowShouldClose(window))
{
glClear(GL_COLOR_BUFFER_BIT);
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
return EXIT_SUCCESS;
}
Se tudo deu certo, ao compilar e executar esse código teremos uma janela aberta no tamanho que definimos.
Vamos entender linha a linha o que está acontecendo no código que acabamos de fazer:
GLFWwindow* window;
Criamos uma referência (ponteiro) para a estrutura GLFWwindow
do GLFW, esse
objeto encapsula as operações de janela e de contexto do OpenGl em uma unica
abstração.
if(!glfwInit()){
Antes de utilizarmos as funções do GLFW precisamos garantir sua inicialização
correta. Se algum erro occorrer irá retornar GLFW_FALSE
e caso isso ocorra
finalizamos o programa.
window = glfwCreateWindow(400, 300, "Hello GLFW", NULL, NULL);
Aqui criamos uma Janela e um Contexto OpenGL, seus parametros são largura
(width) em pixels, altura(height) em pixels e título da janela. Os dois
ultimos parametros ficarão nulos (NULL), e não entraremos em detalhes pois
são opções mais avançasdas. Mas são os parametros de Tela GLFWmonitor
e o
ultimo outro GLFWwindow
.
As proximas duas linhas basicamente verificam se a janela conseguiu ser criada e
caso contrario finaliza o GLFW glfwTerminate()
, ou seja, libera os recursos
que foram alocados pela glfwInit()
;