247 lines
8.3 KiB
C++
247 lines
8.3 KiB
C++
/*
|
|
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 <https://www.gnu.org/licenses/>.
|
|
*/
|
|
#define STB_IMAGE_IMPLEMENTATION
|
|
#include <stb_image.h>
|
|
#include <mesh.h>
|
|
#include <GLFW/glfw3.h>
|
|
#include <shader.h>
|
|
#include <cstring>
|
|
#include <cassert>
|
|
#include <iostream>
|
|
|
|
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 <fstream>
|
|
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<Vertex, GL_ARRAY_BUFFER> vertexBuffer(squareVertices, sizeof(squareVertices), GL_STATIC_DRAW);
|
|
Buffer::Specialized<Element, GL_ELEMENT_ARRAY_BUFFER> 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);
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
const float increment = -1.0f/30.0f;
|
|
float offset = 0;
|
|
while (!glfwWindowShouldClose(window)) {
|
|
glUniform1f(glGetUniformLocation(shader.id, "aHorizontalOffset"), offset);
|
|
offset += increment;
|
|
if (offset <= -1)
|
|
offset = 0;
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
|
|
glUniform1f(glGetUniformLocation(shader.id, "aTexCoordYScale"), -1);
|
|
glActiveTexture(GL_TEXTURE0);
|
|
glBindTexture(GL_TEXTURE_2D, texture);
|
|
square.draw();
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
|
glUniform1f(glGetUniformLocation(shader.id, "aTexCoordYScale"), 1);
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
glActiveTexture(GL_TEXTURE0);
|
|
glBindTexture(GL_TEXTURE_2D, colorBuffer);
|
|
square.draw();
|
|
glfwSwapBuffers(window);
|
|
glfwPollEvents();
|
|
}
|
|
}
|