#include "render.h" #include "GLFW/glfw3.h" #include #include #include char* file_read(const char* path) { FILE* f = fopen(path, "r"); char* buf = NULL; if (!f) { char data[512]; snprintf(data, 512, "Failed to open file at path '%s' (%i)", path, errno); ERROR(data); return buf; } fseek(f, 0, SEEK_END); size_t length = ftell(f); fseek(f, 0, SEEK_SET); buf = malloc(length); if (buf == NULL) return buf; fread(buf, 1, length, f); fclose(f); return buf; } static float halfScreenTop[4 * 5] = { 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 1.0f, -1.0f, -1.0f, 0.0f, 1.0f, 0.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f }; static unsigned int indices[6] = { 0, 1, 3, 1, 2, 3 }; void fb_resize(GLFWwindow* win, int w, int h) { (void)win; glViewport(0, 0, w, h); } renderer_t renderer_create(const char* title, u16 x, u16 y) { if (glfwInit() == GL_FALSE) { // i.e. init. failed const char* msg; glfwGetError(&msg); ERROR(msg); exit(1); } INFO("GLFW ready!"); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); #ifdef __APPLE__ glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); #endif GLFWwindow* win = glfwCreateWindow(x, y, title, NULL, NULL); if (win == NULL) { const char* msg; glfwGetError(&msg); ERROR("Could not create a window handle:"); ERROR(msg); glfwTerminate(); exit(1); } glfwSetFramebufferSizeCallback(win, fb_resize); glfwMakeContextCurrent(win); glfwSwapInterval(1); int loadedVersion = gladLoadGL(glfwGetProcAddress); if (loadedVersion == 0) { const char* msg; glfwGetError(&msg); ERROR("GLAD could not initialise OpenGL function pointers."); if (msg != NULL) { WARN(msg); } WARN("Do you have an OpenGL-3.3-core compatible card and/or drivers?"); glfwTerminate(); exit(1); } INFO("GLAD Successfully loaded OpenGL-3.3-core"); int w, h; glfwGetFramebufferSize(win, &w, &h); glViewport(0, 0, w, h); GLuint vao; GLuint bufs[2]; glGenVertexArrays(1, &vao); glGenBuffers(2, bufs); glBindVertexArray(vao); glBindBuffer(GL_ARRAY_BUFFER, bufs[0]); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufs[1]); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, sizeof(halfScreenTop), halfScreenTop, GL_STATIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 5, (void*)0); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 5, (void*)(sizeof(float) * 3)); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); GLuint text = 0; // doc: glGenTextures is not documented as faillable anywhere so fuck it we ball :) glGenTextures(0, &text); glBindTexture(GL_TEXTURE_2D, text); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, placeholderTexture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); GLint vertS, fragS; char* const pres_vs = file_read("present.vs"); char* const pres_fs = file_read("present.fs"); vertS = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vertS, 1, (const char* const*)(&pres_vs), NULL); glCompileShader(vertS); GLint shaderOK = 1; glGetShaderiv(vertS, GL_COMPILE_STATUS, &shaderOK); if (!shaderOK) { char err[512]; glGetShaderInfoLog(vertS, 512, NULL, err); ERROR("Vertex shader compile failed! GL Reports:"); ERROR(err); } fragS = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragS, 1, (const char* const*)(&pres_fs), NULL); glCompileShader(fragS); shaderOK = 1; glGetShaderiv(fragS, GL_COMPILE_STATUS, &shaderOK); if (!shaderOK) { char err[512]; glGetShaderInfoLog(fragS, 512, NULL, err); ERROR("Fragment shader compile failed! GL Reports:"); ERROR(err); } GLuint program = glCreateProgram(); glAttachShader(program, vertS); glAttachShader(program, fragS); glLinkProgram(program); GLint programOK = 1; glGetProgramiv(program, GL_LINK_STATUS, &programOK); if (!programOK) { char err[512]; glGetProgramInfoLog(program, 512, NULL, err); ERROR("Failed to link shader program, GL Reports:"); ERROR(err); } glDeleteShader(fragS); glDeleteShader(vertS); free(pres_vs); free(pres_fs); return (renderer_t){ .win = win, .backingTexture = text, .shaders = program, .vao = vao, .bufs = bufs, }; } int renderer_healthy(const renderer_t* self) { glfwPollEvents(); return !glfwWindowShouldClose(self->win); } void renderer_present(const renderer_t* self, const canvas_t* canvas) { glBindTexture(GL_TEXTURE_2D, self->backingTexture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, canvas->w, canvas->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, canvas->data); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, self->backingTexture); glUseProgram(self->shaders); glBindVertexArray(self->vao); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); glfwSwapBuffers(self->win); } void renderer_destroy(renderer_t* self) { glDeleteTextures(1, &self->backingTexture); glDeleteProgram(self->shaders); glDeleteBuffers(2, self->bufs); glDeleteVertexArrays(1, &(self->vao)); glfwDestroyWindow(self->win); glfwTerminate(); }