mirror of
https://git.shylie.info/shylie/glerminal.git
synced 2024-11-12 21:10:04 +00:00
231 lines
5.1 KiB
C++
231 lines
5.1 KiB
C++
#include "glerminal-private.h"
|
|
|
|
#include <iostream>
|
|
|
|
namespace
|
|
{
|
|
glerminal::glerminal* GLERMINAL_G = nullptr;
|
|
|
|
constexpr float VBO_VERTICES[] =
|
|
{
|
|
// first triangle
|
|
0.5f, 0.5f, // top right
|
|
0.5f, -0.5f, // bottom right
|
|
-0.5f, 0.5f, // top left
|
|
|
|
// second triangle
|
|
0.5f, -0.5f, // bottom right
|
|
-0.5f, -0.5f, // bottom left
|
|
-0.5f, 0.5f // top left
|
|
};
|
|
|
|
constexpr char* VERTEX_SHADER_SOURCE =
|
|
"#version 330 core\n"
|
|
"layout (location = 0) in vec2 pos;\n"
|
|
"void main()\n"
|
|
"{\n"
|
|
" gl_Position = vec4(pos.x, pos.y, 0, 1);\n"
|
|
"}";
|
|
|
|
constexpr char* FRAGMENT_SHADER_SOURCE =
|
|
"#version 330 core\n"
|
|
"out vec4 FragColor;\n"
|
|
"\n"
|
|
"void main()\n"
|
|
"{\n"
|
|
" FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
|
|
"}";
|
|
}
|
|
|
|
namespace glerminal
|
|
{
|
|
glerminal::glerminal(glerminal_main_cb main) :
|
|
m_main(main)
|
|
{
|
|
if (GLERMINAL_G)
|
|
{
|
|
throw std::runtime_error("glerminal is already running.");
|
|
}
|
|
|
|
// unsure if this should be an error
|
|
if (!m_main)
|
|
{
|
|
throw std::runtime_error("No main callback provided.");
|
|
}
|
|
|
|
init_glfw();
|
|
init_gl();
|
|
|
|
GLERMINAL_G = this;
|
|
}
|
|
|
|
glerminal::~glerminal()
|
|
{
|
|
deinit_gl();
|
|
deinit_glfw();
|
|
|
|
GLERMINAL_G = nullptr;
|
|
}
|
|
|
|
void glerminal::run()
|
|
{
|
|
while (!glfwWindowShouldClose(m_window))
|
|
{
|
|
glfwPollEvents();
|
|
|
|
m_main();
|
|
}
|
|
}
|
|
|
|
void glerminal::flush()
|
|
{
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
glUseProgram(m_program);
|
|
glBindVertexArray(m_vao);
|
|
glDrawArrays(GL_TRIANGLES, 0, 6);
|
|
|
|
glfwSwapBuffers(m_window);
|
|
}
|
|
|
|
void glerminal::init_glfw()
|
|
{
|
|
glfwInit();
|
|
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
|
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
|
// not resizable for now.
|
|
//
|
|
// need to think about how to handle resizing to ensure
|
|
// that the window stays an integer number of "tiles" large
|
|
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
|
|
|
|
// non-adjustable size for the same reason as above
|
|
m_window = glfwCreateWindow(1280, 800, "glerminal", nullptr, nullptr);
|
|
|
|
if (!m_window)
|
|
{
|
|
throw std::runtime_error("Failed to create glerminal window.");
|
|
}
|
|
}
|
|
|
|
void glerminal::init_gl()
|
|
{
|
|
glfwMakeContextCurrent(m_window);
|
|
glfwSwapInterval(1);
|
|
|
|
if (!gladLoadGLLoader(reinterpret_cast<GLADloadproc>(glfwGetProcAddress)))
|
|
{
|
|
throw std::runtime_error("Failed to initialize GLAD.");
|
|
}
|
|
|
|
glViewport(0, 0, 1280, 800);
|
|
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
|
|
|
// -- setup vertex data --
|
|
// create vertex buffer object
|
|
glGenBuffers(1, &m_vbo);
|
|
|
|
// create vertex array object
|
|
glGenVertexArrays(1, &m_vao);
|
|
glBindVertexArray(m_vao);
|
|
|
|
// bind buffer and copy data
|
|
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
|
|
glBufferData(GL_ARRAY_BUFFER, sizeof(VBO_VERTICES), VBO_VERTICES, GL_STATIC_DRAW);
|
|
|
|
// set up vertex attributes
|
|
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), reinterpret_cast<void*>(0));
|
|
glEnableVertexAttribArray(0);
|
|
|
|
|
|
// -- setup shader program --
|
|
// compile
|
|
const unsigned int vertex_shader = glCreateShader(GL_VERTEX_SHADER);
|
|
glShaderSource(vertex_shader, 1, &VERTEX_SHADER_SOURCE, nullptr);
|
|
glCompileShader(vertex_shader);
|
|
|
|
const unsigned int fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
|
|
glShaderSource(fragment_shader, 1, &FRAGMENT_SHADER_SOURCE, nullptr);
|
|
glCompileShader(fragment_shader);
|
|
|
|
int success;
|
|
char info_log[512] = {};
|
|
|
|
// verify
|
|
glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success);
|
|
if (!success)
|
|
{
|
|
glGetShaderInfoLog(vertex_shader, sizeof(info_log) / sizeof(*info_log), nullptr, info_log);
|
|
glDeleteShader(vertex_shader);
|
|
glDeleteShader(fragment_shader);
|
|
|
|
using namespace std::string_literals;
|
|
throw std::runtime_error("Could not compile vertex shader: "s + info_log);
|
|
}
|
|
|
|
glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success);
|
|
if (!success)
|
|
{
|
|
glGetShaderInfoLog(fragment_shader, sizeof(info_log) / sizeof(*info_log), nullptr, info_log);
|
|
glDeleteShader(vertex_shader);
|
|
glDeleteShader(fragment_shader);
|
|
|
|
using namespace std::string_literals;
|
|
throw std::runtime_error("Could not compile fragment shader: "s + info_log);
|
|
}
|
|
|
|
// link
|
|
m_program = glCreateProgram();
|
|
glAttachShader(m_program, vertex_shader);
|
|
glAttachShader(m_program, fragment_shader);
|
|
glLinkProgram(m_program);
|
|
glDeleteShader(vertex_shader);
|
|
glDeleteShader(fragment_shader);
|
|
|
|
// verify again
|
|
glGetProgramiv(m_program, GL_LINK_STATUS, &success);
|
|
if (!success)
|
|
{
|
|
glGetProgramInfoLog(m_program, sizeof(info_log) / sizeof(*info_log), nullptr, info_log);
|
|
glDeleteProgram(m_program);
|
|
|
|
using namespace std::string_literals;
|
|
throw std::runtime_error("Could not link shader program: "s + info_log);
|
|
}
|
|
}
|
|
|
|
void glerminal::deinit_glfw()
|
|
{
|
|
glDeleteProgram(m_program);
|
|
|
|
glfwDestroyWindow(m_window);
|
|
|
|
glfwTerminate();
|
|
}
|
|
|
|
void glerminal::deinit_gl()
|
|
{
|
|
glDeleteProgram(m_program);
|
|
}
|
|
}
|
|
|
|
void glerminal_run(glerminal_main_cb main)
|
|
{
|
|
try
|
|
{
|
|
glerminal::glerminal(main).run();
|
|
}
|
|
catch (const std::runtime_error& e)
|
|
{
|
|
std::cout << "[glerminal] " << e.what() << std::endl;
|
|
}
|
|
}
|
|
|
|
void glerminal_flush()
|
|
{
|
|
if (!GLERMINAL_G) { return; }
|
|
|
|
GLERMINAL_G->flush();
|
|
} |