Здравствуйте, как давно меня здесь не было... Наверное не было ещё такой темы ради которой стоило бы Вас, дорогие читатели моих опусов, беспокоить.
Решил я познакомится поближе с OpenGL. Единственный доступный инструмент для написания программ и их компиляции, оказался NetBeans IDE 8.2, установочный файл netbeans-8.2-windows.exe размером 225 472 кб. и jdk-8u144-windows-x64 установочный файл jdk-8u144-windows-x64.exe размером 202 523 кб.
Размеры файлов и названия пишу точно, поскольку их размер зависит от их комплектации, а комплектация, насколько могу быть точным от конечной функциональности. После установки получаем вот такой инструмент разработки:
Использую компилятор CLang. Все инструменты скачаны при помощи утилиты MSYS которую можно скачать по ссылке https://www.msys2.org. Упор был сделан на инструменты UCRT64. MinGW не пользуюсь совсем.
Об инструментах поговорили и перейдём к OpenGL.
Проблема состояла в том, как тот код, который из интернета, запихать в конструкцию из GLFW + GLAD и получить OpenGL графику с шейдерами.
Первая проблема была с тем, как инициализировать GLAD? С glad.h проблем не было, а вот с glad.c возникли. Поиски решения оказались успешными и её реализацию вы увидите в коде, который я приведу ниже.
Вторая проблема в том, что часто можно увидеть конструкцию GLFW+GLEW, но я от неё отказался поскольку хотел реализовать конструкцию GLFW+GLAD.
Третья проблема, что везде в "туториалах" даётся множество примеров, которые отвязаны от цельного кода, куда писать, как встраивать код в программу, где искать дополнительные файлы, не понятно.
Я новичок в программировании, поэтому пишу с позиции именно новичка, так что не нападайте :)
main.cpp
//#define GLAD_GL_IMPLEMENTATION
#include <GLAD/glad Core v.3.3/include/glad/glad.h>
#include <GLAD/glad Core v.3.3/src/glad.c>
#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
using namespace std;
//GLFWwindow *window;
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GLFW_TRUE);
switch (key)
{
case GLFW_KEY_ESCAPE:
glfwSetWindowShouldClose(window, GLFW_TRUE);
break;
/* case GLFW_KEY_SPACE:
cur_icon_color = (cur_icon_color + 1) % 5;
set_icon(window, cur_icon_color);
break;
case GLFW_KEY_X:
glfwSetWindowIcon(window, 0, NULL);
break;*/
}
}
void triang()
{
GLuint vbo = 0;
GLuint vao = 0;
float points[] = {
0.0f, 0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
-0.5f, -0.5f, 0.0f
};
const char* vertex_shader =
"#version 400\n"
"in vec3 vp;"
"void main() {"
" gl_Position = vec4(vp, 1.0);"
"}";
const char* fragment_shader =
"#version 400\n"
"out vec4 frag_colour;"
"void main() {"
" frag_colour = vec4(0.2, 0.0, 0.5, 1.0);"
"}";
GLuint vs = glCreateShader(GL_VERTEX_SHADER);
GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
GLuint shader_programme = glCreateProgram();
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, 9 * sizeof(float), points, GL_STATIC_DRAW);
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glShaderSource(vs, 1, &vertex_shader, NULL);
glCompileShader(vs);
glShaderSource(fs, 1, &fragment_shader, NULL);
glCompileShader(fs);
glAttachShader(shader_programme, fs);
glAttachShader(shader_programme, vs);
glLinkProgram(shader_programme);
glUseProgram(shader_programme);
glBindVertexArray(vao);
// draw points 0-3 from the currently bound VAO with current in-use shader
glDrawArrays(GL_TRIANGLES, 0, 3);
// update other events like input handling
}
// Когда пользователь меняет размер окна, окно просмотра также должно быть скорректировано, требуя функцию обратного вызова
void framebuffer_size_callback(GLFWwindow* window,int width,int height){
// Первые два параметра функции glViewport управляют положением нижнего левого угла окна, а третий и четвертый параметры контролируют ширину и высоту окна рендеринга
glfwSetKeyCallback(window, key_callback);
glfwGetFramebufferSize(window, &width, &height);
glViewport(0,0,width,height);
}
// Объявляем функцию, чтобы определить, нажата ли конкретная клавиша
void processInput(GLFWwindow * window){
// Проверка, нажимает ли пользователь клавишу возврата (Esc) (если не нажата, glfwGetKey вернет GLFW_RELEASE, если нажата, GLFW_PRESS)
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
glfwSetWindowShouldClose(window, true);
}
}
int main(int argc, char** argv)
{ // Инициализация GLFW
glfwInit();
// Установить номер основной версии OpenGL (Major) и номер вспомогательной версии (Minor) в 3
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
// Использование режима ядра (Core-profile)
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// Если это система MacOS, вам понадобится следующая строка кода для работы конфигурации
//glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
// Создать объект окна
GLFWwindow * window = glfwCreateWindow(800, 600, "GLFW + GLAD", NULL, NULL);
if (window == NULL){
cout << "Failed to create GLFW window" << endl;
glfwTerminate();
return -1;
}
// Уведомить GLFW, чтобы установить контекст нашего окна в качестве основного контекста текущего потока
glfwMakeContextCurrent(window);
// GLAD используется для управления указателем функции OpenGL, нам нужно инициализировать GLAD перед вызовом любой функции OpenGL
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){
cout << "Failed to initialize GLAD" << endl;
return -1;
}
// Зарегистрируем определенную функцию обратного вызова и сообщаем GLFW вызывать эту функцию при каждом изменении размера окна
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
// Визуализация цикла
while (!glfwWindowShouldClose(window)) {
// Проверить, нажата ли конкретная клавиша, и обрабатывать ее каждый кадр
processInput(window);
// функция glClearColor - это функция установки состояния, используемая для установки цвета, используемого для очистки экрана
glClearColor(0.2f,0.3f,0.3f,1.0f);
// Функция glClear - это функция использования состояния, которая использует текущее состояние для очистки экрана с указанным цветом
glClear(GL_COLOR_BUFFER_BIT);
//triang(); - запускаем отрисовку треугольника. Работает именно в этом месте!
triang();
// Функция glfwSwapBuffers будет обмениваться цветовыми буферами
glfwSwapBuffers(window);
// Функция glfwPollEvents проверяет, запущены ли какие-либо события
glfwPollEvents();
}
// Освободить все ресурсы, выделенные ранее
glfwTerminate();
return 0;
}
результат работы программы:
В этом коде я собрал много разных идей, здесь нет ни чего моего, кроме компоновки кода.
Да. Программа не ахти какая, но как видно из примера, работать в этой конструкции можно и вполне себе успешно. Можно выдернуть код, удалив всего одну функцию не разрушив целость структуры и так же вставить другой код. Какие перспективы у данной реализации? Наверно ограничиваются только фантазией.
Всем творческих успехов.