/* Copyright (C) 2021 hiimgoodpack This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #define STB_IMAGE_IMPLEMENTATION #include #include #include #include #include #include #include typedef struct { linalg::aliases::float2 position; } Vertex; typedef unsigned int Element; const Mesh::Attribute VERTEX_ATTRIBUTES[] = { { .index = 0, .size = 2, .type = GL_FLOAT, .stride = sizeof(Vertex), .pointer = (void*)offsetof(Vertex, position) } }; #include std::string readExternalFile(const char* name) { std::string contents; std::ifstream file; file.open(name, std::fstream::in); if (!file.is_open()) std::cerr << "Failed to load file " << name << ": " << strerror(errno) << "\n"; std::string line; while (getline(file, line)) { contents += line; contents += "\n"; } file.close(); return std::string(contents); } void onDebugOutput(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const char* message, const void* /* userParam */) { std::cerr << "OpenGL "; switch (severity) { case GL_DEBUG_SEVERITY_HIGH: std::cerr << "high severity"; break; case GL_DEBUG_SEVERITY_MEDIUM: std::cerr << "moderately severity"; break; case GL_DEBUG_SEVERITY_LOW: std::cerr << "low severity"; break; case GL_DEBUG_SEVERITY_NOTIFICATION: std::cerr << "notification"; break; default: std::cerr << "[unknown severity " << severity << "]"; break; } std::cerr << " "; switch (type) { case GL_DEBUG_TYPE_ERROR: std::cerr << "error"; break; case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: std::cerr << "deprecation warning"; break; case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: std::cerr << "undefined behavior warning"; break; case GL_DEBUG_TYPE_PORTABILITY: std::cerr << "portability warning"; break; case GL_DEBUG_TYPE_PERFORMANCE: std::cerr << "performance warning"; break; case GL_DEBUG_TYPE_MARKER: std::cerr << "debug marker"; break; case GL_DEBUG_TYPE_PUSH_GROUP: std::cerr << "pushed group"; break; case GL_DEBUG_TYPE_POP_GROUP: std::cerr << "popped group"; break; case GL_DEBUG_TYPE_OTHER: std::cerr << "debug message"; break; default: std::cerr << "[unknown message type " << type << "]"; break; } std::cerr << " from "; switch (source) { case GL_DEBUG_SOURCE_API: std::cerr << "API"; break; case GL_DEBUG_SOURCE_WINDOW_SYSTEM: std::cerr << "window system"; break; case GL_DEBUG_SOURCE_SHADER_COMPILER: std::cerr << "shader compiler"; break; case GL_DEBUG_SOURCE_THIRD_PARTY: std::cerr << "third party"; break; case GL_DEBUG_SOURCE_APPLICATION: std::cerr << "application"; break; case GL_DEBUG_SOURCE_OTHER: std::cerr << "unknown source"; break; default: std::cerr << "[unknown source type " << source << "]"; break; } std::cerr << ": "; if (length < 0) std::cerr << message; else std::cerr << std::string(message, length); std::cerr << " (message id: " << id << ")\n"; } void onGLFWError(int errorCode, const char* error) { std::cerr << "GLFW error: " << error << " (error code: " << errorCode << ")\n"; } Shader::Program shader; const unsigned int resultLength = 350; int main() { // Get a context glfwSetErrorCallback(onGLFWError); glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, 1); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, true); glfwWindowHint(GLFW_SAMPLES, 4); //glfwWindowHint(GLFW_VISIBLE, false); GLFWwindow* window = glfwCreateWindow(resultLength, resultLength, "You aren't supposed to see this", NULL, NULL); glfwMakeContextCurrent(window); int contextFlags; glGetIntegerv(GL_CONTEXT_FLAGS, &contextFlags); if (contextFlags & GL_CONTEXT_FLAG_DEBUG_BIT) { glEnable(GL_DEBUG_OUTPUT); glDebugMessageCallback(onDebugOutput, NULL); glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE); } else { std::cerr << "Warning: Debug context could not be created.\n"; } // Load a square /* 0--1 | | 3--2 */ const Vertex squareVertices[] = { { .position = {-1, 1} }, { .position = {1, 1} }, { .position = {1, -1} }, { .position = {-1, -1} } }; const Element squareElements[] = {0, 1, 3, 1, 2, 3}; Buffer::Specialized vertexBuffer(squareVertices, sizeof(squareVertices), GL_STATIC_DRAW); Buffer::Specialized elementBuffer(squareElements, sizeof(squareElements), GL_STATIC_DRAW); Mesh::Buffer buffers[2] = { { .buffer = vertexBuffer, .attributes = VERTEX_ATTRIBUTES, .attributeCount = sizeof(VERTEX_ATTRIBUTES)/sizeof(Mesh::Attribute) }, { .buffer = elementBuffer } }; Mesh::InstancedElements square(buffers, 2, sizeof(squareElements)/sizeof(Element), 1, GL_UNSIGNED_INT); // Load shaders { std::string vertexCode = readExternalFile("../shaders/vertex.glsl"); assert(shader.add(vertexCode.c_str(), -1, GL_VERTEX_SHADER) == Shader::Error::NONE); std::string fragmentCode = readExternalFile("../shaders/fragment.glsl"); assert(shader.add(fragmentCode.c_str(), -1, GL_FRAGMENT_SHADER) == Shader::Error::NONE); } shader.link(); shader.use(); // Set up a framebuffer unsigned int frameBuffer; glGenFramebuffers(1, &frameBuffer); glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer); unsigned int colorBuffer; glGenTextures(1, &colorBuffer); glBindTexture(GL_TEXTURE_2D, colorBuffer); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, resultLength, resultLength, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorBuffer, 0); unsigned int renderBuffer; glGenRenderbuffers(1, &renderBuffer); glBindRenderbuffer(GL_RENDERBUFFER, renderBuffer); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, resultLength, resultLength); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, renderBuffer); assert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE && "Generated framebuffer is incomplete"); unsigned int texture, normal; // Load the image { int width, height; unsigned char* data = stbi_load("../test.png", &width, &height, nullptr, 0); glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); glGenerateMipmap(GL_TEXTURE_2D); stbi_image_free(data); glUniform1i(glGetUniformLocation(shader.id, "aTexture"), 0); } glClearColor(0.25, 0.25, 0.25, 1); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer); glClear(GL_COLOR_BUFFER_BIT); const float increment = -1.0f/60.0f; float globe0Offset = 0; float globe1Offset = 0; while (!glfwWindowShouldClose(window)) { glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer); glUniform1f(glGetUniformLocation(shader.id, "aTexCoordYScale"), 1); glUniform1f(glGetUniformLocation(shader.id, "aHorizontalOffset"), globe0Offset); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texture); square.draw(); glBindFramebuffer(GL_FRAMEBUFFER, 0); glClear(GL_COLOR_BUFFER_BIT); glUniform1f(glGetUniformLocation(shader.id, "aTexCoordYScale"), -1); glUniform1f(glGetUniformLocation(shader.id, "aHorizontalOffset"), globe1Offset); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, colorBuffer); square.draw(); globe0Offset += increment; if (globe0Offset <= -2) globe0Offset = 0; globe1Offset = globe0Offset * 0.5f; glfwSwapBuffers(window); glfwPollEvents(); } }