#define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <string>
#include <SOIL/SOIL.h>
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include "utils.h"
struct GLFW {
GLFW() {
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_SAMPLES, 1);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
}
~GLFW() {
glfwTerminate();
}
};
struct Window {
GLFWwindow* id;
int width, height;
Window(int _width, int _heigth, GLFWwindow* reference) {
width = _width, height = _heigth;
id = glfwCreateWindow(width, height, "rfoegl", nullptr, reference);
glewExperimental = GL_TRUE;
glfwMakeContextCurrent(id);
if(!id) {
puts("Failed to create GLFW window\n");
glfwTerminate();
exit(-1);
}
if(glewInit() != GLEW_OK) {
puts("Failed to initialize GLEW\n");
exit(-1);
}
glfwGetFramebufferSize(id, &width, &height);
glViewport(0, 0, width, height);
}
~Window() {
glfwDestroyWindow(id);
}
};
bool pressed_keys[1024] = {false};
void default_key_callback(GLFWwindow* window, int key, int scancode, int action, int mode) {
if(action == GLFW_PRESS) {
pressed_keys[key] = true;
} else if(action == GLFW_RELEASE) {
pressed_keys[key] = false;
if(key == GLFW_KEY_ESCAPE) glfwSetWindowShouldClose(window, GL_TRUE);
}
}
void set_default_key_callback(Window* w) {
glfwSetKeyCallback(w->id, default_key_callback);
}
void clear(vec3 rgb = {0.f, 0.f, 0.f}) {
glClearColor(rgb.r, rgb.g, rgb.b, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
std::string read_entire_file(const std::string& path) {
std::ifstream file(path);
if(!file) {
printf("failed to open file: %s\n", path.c_str());
exit(-1);
}
std::string content((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
return content;
}
u32 get_shader(const std::string& path, decltype(GL_VERTEX_SHADER) type) {
u32 id = glCreateShader(type);
std::string _shader_source = read_entire_file(path);
const char* shader_source = _shader_source.c_str();
glShaderSource(id, 1, &shader_source, NULL);
glCompileShader(id);
s32 succes;
s8 info_log[512];
glGetShaderiv(id, GL_COMPILE_STATUS, &succes);
if(!succes) {
glGetShaderInfoLog(id, 512, NULL, (GLchar*)info_log);
printf("failed to compile shader (path: %s): %s\n", path.c_str(), info_log);
exit(-1);
}
printf("shader compiled succesfully (path: %s)\n", path.c_str());
return id;
}
u32 get_shader_program_VF(const std::string& path_vert, const std::string& path_frag) {
u32 vertex_shader = get_shader(path_vert, GL_VERTEX_SHADER);
u32 fragment_shader = get_shader(path_frag, GL_FRAGMENT_SHADER);
u32 id = glCreateProgram();
glAttachShader(id, vertex_shader);
glAttachShader(id, fragment_shader);
glLinkProgram(id);
glDeleteShader(vertex_shader);
glDeleteShader(fragment_shader);
puts("shader linked succesfully");
return id;
}
#define ADD_ATTRIB(id, struct_name, field_name)\
glVertexAttribPointer(id, sizeof(std::declval<struct_name>().field_name) / sizeof(float), GL_FLOAT, GL_FALSE, sizeof(struct_name), (void*)offsetof(struct_name, field_name));\
glEnableVertexAttribArray(id);
struct Point_UV { vec3 pos; vec2 uv; };
struct Mesh {
u32 vbo, vao, ebo, points_count, indices_count;
};
Mesh make_mesh_uv(const float *points, const u32 *indices, u32 points_count, u32 indices_count) {
Mesh mesh;
mesh.points_count = points_count, mesh.indices_count = indices_count;
//prepare
glGenVertexArrays(1, &(mesh.vao));
glGenBuffers(1, &(mesh.vbo));
glBindVertexArray(mesh.vao);
glBindBuffer(GL_ARRAY_BUFFER, mesh.vbo);
glGenBuffers(1, &(mesh.ebo));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices_count * sizeof(u32), indices, GL_STATIC_DRAW);
//link
glBufferData(GL_ARRAY_BUFFER, points_count * sizeof(Point_UV), points, GL_STATIC_DRAW);
ADD_ATTRIB(0, Point_UV, pos);
ADD_ATTRIB(1, Point_UV, uv);
//unbind
glBindVertexArray(0);
return mesh;
}
void clear(Mesh mesh) {
glDeleteVertexArrays(1, &(mesh.vao));
glDeleteBuffers(1, &(mesh.vbo));
glDeleteBuffers(1, &(mesh.ebo));
}
int main() {
GLFW glfw;
Point_UV quad_points[] = {
{{-1, -1, 0}, {0, 0}},
{{ 1, -1, 0}, {1, 0}},
{{ 1, 1, 0}, {1, 1}},
{{-1, 1, 0}, {0, 1}},
};
u32 quad_ids[] = {0, 1, 2, 0, 2, 3};
// glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
// GLFWwindow* offscreen_context = glfwCreateWindow(1200, 800, "", NULL, NULL);
// glfwMakeContextCurrent(offscreen_context);
Mesh quad_mesh;
u32 quad_shader;
{
glfwWindowHint(GLFW_VISIBLE, GLFW_TRUE);
Window win_0(1200, 800, nullptr);
quad_mesh = make_mesh_uv((float*)quad_points, quad_ids, 4, 6);
quad_shader = get_shader_program_VF("./default.vert", "./uvmap.frag");
set_default_key_callback(&win_0);
while(!glfwWindowShouldClose(win_0.id)) {
glfwPollEvents();
clear();
glUseProgram(quad_shader);
glBindVertexArray(quad_mesh.vao);
glDrawElements(GL_TRIANGLES, quad_mesh.indices_count, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
glfwSwapBuffers(win_0.id);
}
// glDeleteProgram(quad_shader);
// clear(quad_mesh);
}
{
Window win_1(1200, 800, nullptr);
set_default_key_callback(&win_1);
while(!glfwWindowShouldClose(win_1.id)) {
glfwPollEvents();
clear();
glUseProgram(quad_shader);
glBindVertexArray(quad_mesh.vao);
glDrawElements(GL_TRIANGLES, quad_mesh.indices_count, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
glfwSwapBuffers(win_1.id);
}
}
glDeleteProgram(quad_shader);
clear(quad_mesh);
return 0;
}