From ed08b673c50b076042d8f0c49501372168142764 Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Fri, 16 Feb 2018 16:04:32 -0500 Subject: Refactored renderer Renderer is basically now more C++'y, as it makes more use of classes (a lot of GL types have been wrapped), and the renderer itself is now a class. The monitor mesh is also now indexed. Tweaked the NTSC artifacting after inadvertently fixing a bug with the way the image was loaded. --- src/algorithms.h | 12 - src/animation.h | 2 +- src/components/controllable.h | 2 +- src/components/mappable.h | 2 +- src/entity_manager.h | 2 +- src/game.cpp | 19 +- src/game.h | 11 +- src/main.cpp | 17 +- src/renderer.cpp | 862 ------------------------------------------ src/renderer.h | 37 -- src/renderer/gl.h | 7 + src/renderer/mesh.cpp | 109 ++++++ src/renderer/mesh.h | 62 +++ src/renderer/renderer.cpp | 635 +++++++++++++++++++++++++++++++ src/renderer/renderer.h | 114 ++++++ src/renderer/shader.cpp | 84 ++++ src/renderer/shader.h | 58 +++ src/renderer/texture.cpp | 124 ++++++ src/renderer/texture.h | 52 +++ src/renderer/wrappers.h | 273 +++++++++++++ src/systems/animating.cpp | 3 +- src/systems/animating.h | 2 +- src/systems/mapping.cpp | 12 +- src/util.cpp | 30 ++ src/util.h | 41 ++ 25 files changed, 1624 insertions(+), 948 deletions(-) delete mode 100644 src/algorithms.h delete mode 100644 src/renderer.cpp delete mode 100644 src/renderer.h create mode 100644 src/renderer/gl.h create mode 100644 src/renderer/mesh.cpp create mode 100644 src/renderer/mesh.h create mode 100644 src/renderer/renderer.cpp create mode 100644 src/renderer/renderer.h create mode 100644 src/renderer/shader.cpp create mode 100644 src/renderer/shader.h create mode 100644 src/renderer/texture.cpp create mode 100644 src/renderer/texture.h create mode 100644 src/renderer/wrappers.h create mode 100644 src/util.cpp create mode 100644 src/util.h (limited to 'src') diff --git a/src/algorithms.h b/src/algorithms.h deleted file mode 100644 index 80e3e27..0000000 --- a/src/algorithms.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef ALGORITHMS_H_1DDC517E -#define ALGORITHMS_H_1DDC517E - -template< typename ContainerT, typename PredicateT > -void erase_if( ContainerT& items, const PredicateT& predicate ) { - for( auto it = items.begin(); it != items.end(); ) { - if( predicate(*it) ) it = items.erase(it); - else ++it; - } -}; - -#endif /* end of include guard: ALGORITHMS_H_1DDC517E */ diff --git a/src/animation.h b/src/animation.h index 50446d0..58df616 100644 --- a/src/animation.h +++ b/src/animation.h @@ -1,7 +1,7 @@ #ifndef ANIMATION_H_74EB0901 #define ANIMATION_H_74EB0901 -#include "renderer.h" +#include "renderer/texture.h" #include #include #include diff --git a/src/components/controllable.h b/src/components/controllable.h index fa78c8b..1b12985 100644 --- a/src/components/controllable.h +++ b/src/components/controllable.h @@ -2,7 +2,7 @@ #define CONTROLLABLE_H_4E0B85B4 #include "component.h" -#include "renderer.h" +#include "renderer/gl.h" class ControllableComponent : public Component { public: diff --git a/src/components/mappable.h b/src/components/mappable.h index 7530919..2dbab77 100644 --- a/src/components/mappable.h +++ b/src/components/mappable.h @@ -3,7 +3,7 @@ #include #include "component.h" -#include "renderer.h" +#include "renderer/texture.h" #include "map.h" class MappableComponent : public Component { diff --git a/src/entity_manager.h b/src/entity_manager.h index 7fd82fc..65fa6ca 100644 --- a/src/entity_manager.h +++ b/src/entity_manager.h @@ -7,7 +7,7 @@ #include #include #include "component.h" -#include "algorithms.h" +#include "util.h" class EntityManager { private: diff --git a/src/game.cpp b/src/game.cpp index 1182689..228ff23 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -10,12 +10,11 @@ #include "systems/mapping.h" #include "systems/orienting.h" #include "animation.h" -#include "renderer.h" #include "consts.h" void key_callback(GLFWwindow* window, int key, int, int action, int) { - Game& game = *((Game*) glfwGetWindowUserPointer(window)); + Game& game = *static_cast(glfwGetWindowUserPointer(window)); if ((action == GLFW_PRESS) && (key == GLFW_KEY_ESCAPE)) { @@ -27,10 +26,7 @@ void key_callback(GLFWwindow* window, int key, int, int action, int) game.systemManager_.input(key, action); } -Game::Game( - GLFWwindow* window) : - window_(window), - world_("res/maps.xml") +Game::Game() : world_("res/maps.xml") { systemManager_.emplaceSystem(*this); systemManager_.emplaceSystem(*this); @@ -65,8 +61,8 @@ Game::Game( systemManager_.getSystem().loadMap(world_.getStartingMapId()); glfwSwapInterval(1); - glfwSetWindowUserPointer(window_, this); - glfwSetKeyCallback(window_, key_callback); + glfwSetWindowUserPointer(renderer_.getWindow().getHandle(), this); + glfwSetKeyCallback(renderer_.getWindow().getHandle(), key_callback); } void Game::execute() @@ -76,7 +72,8 @@ void Game::execute() double accumulator = 0.0; Texture texture(GAME_WIDTH, GAME_HEIGHT); - while (!(shouldQuit_ || glfwWindowShouldClose(window_))) + while (!(shouldQuit_ || + glfwWindowShouldClose(renderer_.getWindow().getHandle()))) { double currentTime = glfwGetTime(); double frameTime = currentTime - lastTime; @@ -93,8 +90,8 @@ void Game::execute() } // Render - texture.fill(texture.entirety(), 0, 0, 0); + renderer_.fill(texture, texture.entirety(), 0, 0, 0); systemManager_.render(texture); - texture.renderScreen(); + renderer_.renderScreen(texture); } } diff --git a/src/game.h b/src/game.h index 346d67e..43e08da 100644 --- a/src/game.h +++ b/src/game.h @@ -1,18 +1,23 @@ #ifndef GAME_H_1014DDC9 #define GAME_H_1014DDC9 -#include "renderer.h" #include "entity_manager.h" #include "system_manager.h" #include "world.h" +#include "renderer/renderer.h" class Game { public: - Game(GLFWwindow* window); + Game(); void execute(); + inline Renderer& getRenderer() + { + return renderer_; + } + inline EntityManager& getEntityManager() { return entityManager_; @@ -37,7 +42,7 @@ public: private: - GLFWwindow* const window_; + Renderer renderer_; EntityManager entityManager_; SystemManager systemManager_; World world_; diff --git a/src/main.cpp b/src/main.cpp index d51da7d..ddbc15f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,27 +1,14 @@ -#include -#include -#include -#include "renderer.h" #include "muxer.h" #include "game.h" int main() { - srand(time(NULL)); - - GLFWwindow* window = initRenderer(); - glfwSwapInterval(1); - initMuxer(); - // Put this in a block so game goes out of scope before we destroy the renderer - { - Game game {window}; - game.execute(); - } + Game game; + game.execute(); destroyMuxer(); - destroyRenderer(); return 0; } diff --git a/src/renderer.cpp b/src/renderer.cpp deleted file mode 100644 index f840180..0000000 --- a/src/renderer.cpp +++ /dev/null @@ -1,862 +0,0 @@ -#include "renderer.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include "consts.h" - -// include stb_image -#define STB_IMAGE_IMPLEMENTATION -#define STBI_ONLY_PNG -#define STBI_ONLY_BMP -#include "stb_image.h" - -static bool rendererInitialized = false; - -static GLFWwindow* window; - -static GLuint generic_framebuffer; // The framebuffer -static GLuint bloom_framebuffer; -static GLuint bloom_depthbuffer; -static int buffer_width = 1024; -static int buffer_height = 768; - -static GLuint ntscShader; // The NTSC shader -static GLuint finalShader; // The passthrough shader -static GLuint blitShader; // The blitting shader -static GLuint fillShader; // The fill shader -static GLuint bloom1Shader; -static GLuint bloom2Shader; - -// The buffers for the NTSC rendering process -static GLuint renderedTexBufs[2]; -static int curBuf; -static GLuint artifactsTex; -static GLuint scanlinesTex; -static GLuint preBloomTex; -static GLuint bloomPassTex1; -static GLuint bloomPassTex2; - -// The VAO -static GLuint VertexArrayID; - -// A plane that fills the renderbuffer -static GLuint quad_vertexbuffer; - -// Buffers for the mesh -static GLuint mesh_vertexbuffer; -static GLuint mesh_uvbuffer; -static GLuint mesh_normalbuffer; -static int mesh_numvertices; - -GLuint LoadShaders(const char* vertex_file_path, const char* fragment_file_path) -{ - // Create the shaders - GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER); - GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER); - - // Read the Vertex Shader code from the file - std::string VertexShaderCode; - std::ifstream VertexShaderStream(vertex_file_path, std::ios::in); - if(VertexShaderStream.is_open()) - { - std::string Line = ""; - while(getline(VertexShaderStream, Line)) - VertexShaderCode += "\n" + Line; - VertexShaderStream.close(); - } - - // Read the Fragment Shader code from the file - std::string FragmentShaderCode; - std::ifstream FragmentShaderStream(fragment_file_path, std::ios::in); - if(FragmentShaderStream.is_open()){ - std::string Line = ""; - while(getline(FragmentShaderStream, Line)) - FragmentShaderCode += "\n" + Line; - FragmentShaderStream.close(); - } - - GLint Result = GL_FALSE; - int InfoLogLength; - - // Compile Vertex Shader - printf("Compiling shader : %s\n", vertex_file_path); - char const * VertexSourcePointer = VertexShaderCode.c_str(); - glShaderSource(VertexShaderID, 1, &VertexSourcePointer , nullptr); - glCompileShader(VertexShaderID); - - // Check Vertex Shader - glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result); - glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength); - std::vector VertexShaderErrorMessage(InfoLogLength); - glGetShaderInfoLog(VertexShaderID, InfoLogLength, nullptr, &VertexShaderErrorMessage[0]); - fprintf(stdout, "%s\n", &VertexShaderErrorMessage[0]); - - // Compile Fragment Shader - printf("Compiling shader : %s\n", fragment_file_path); - char const * FragmentSourcePointer = FragmentShaderCode.c_str(); - glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer , nullptr); - glCompileShader(FragmentShaderID); - - // Check Fragment Shader - glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result); - glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength); - std::vector FragmentShaderErrorMessage(InfoLogLength); - glGetShaderInfoLog(FragmentShaderID, InfoLogLength, nullptr, &FragmentShaderErrorMessage[0]); - fprintf(stdout, "%s\n", &FragmentShaderErrorMessage[0]); - - // Link the program - fprintf(stdout, "Linking program\n"); - GLuint ProgramID = glCreateProgram(); - glAttachShader(ProgramID, VertexShaderID); - glAttachShader(ProgramID, FragmentShaderID); - glLinkProgram(ProgramID); - - // Check the program - glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result); - glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength); - std::vector ProgramErrorMessage( glm::max(InfoLogLength, int(1)) ); - glGetProgramInfoLog(ProgramID, InfoLogLength, nullptr, &ProgramErrorMessage[0]); - fprintf(stdout, "%s\n", &ProgramErrorMessage[0]); - - glDeleteShader(VertexShaderID); - glDeleteShader(FragmentShaderID); - - return ProgramID; -} - -void flipImageData(unsigned char* data, int width, int height, int comps) -{ - unsigned char* data_copy = (unsigned char*) malloc(width*height*comps*sizeof(unsigned char)); - memcpy(data_copy, data, width*height*comps); - - int row_size = width * comps; - - for (int i=0;i& out_vertices, std::vector& out_uvs, std::vector& out_normals) -{ - out_vertices.clear(); - out_uvs.clear(); - out_normals.clear(); - - FILE* file = fopen(filename, "r"); - if (file == nullptr) - { - fprintf(stderr, "Could not open mesh file %s\n", filename); - exit(1); - } - - std::vector temp_vertices; - std::vector temp_uvs; - std::vector temp_normals; - - for (;;) - { - char lineHeader[256]; - int res = fscanf(file, "%s", lineHeader); - if (res == EOF) - { - break; - } - - if (!strncmp(lineHeader, "v", 2)) - { - glm::vec3 vertex; - fscanf(file, "%f %f %f\n", &vertex.x,&vertex.y,&vertex.z); - temp_vertices.push_back(vertex); - } else if (!strncmp(lineHeader, "vt", 3)) - { - glm::vec2 uv; - fscanf(file, "%f %f\n", &uv.x, &uv.y); - temp_uvs.push_back(uv); - } else if (!strncmp(lineHeader, "vn", 3)) - { - glm::vec3 normal; - fscanf(file, "%f %f %f\n", &normal.x, &normal.y, &normal.z); - temp_normals.push_back(normal); - } else if (!strncmp(lineHeader, "f", 2)) - { - int vertexIDs[3], uvIDs[3], normalIDs[3]; - fscanf(file, "%d/%d/%d %d/%d/%d %d/%d/%d\n", &vertexIDs[0], &uvIDs[0], &normalIDs[0], &vertexIDs[1], &uvIDs[1], &normalIDs[1], &vertexIDs[2], &uvIDs[2], &normalIDs[2]); - - for (int i=0; i<3; i++) - { - out_vertices.push_back(temp_vertices[vertexIDs[i] - 1]); - out_uvs.push_back(temp_uvs[uvIDs[i] - 1]); - out_normals.push_back(temp_normals[normalIDs[i] - 1]); - } - } - } -} - -void setFramebufferSize(GLFWwindow* w, int width, int height) -{ - buffer_width = width; - buffer_height = height; - - glDeleteFramebuffers(1, &bloom_framebuffer); - glDeleteRenderbuffers(1, &bloom_depthbuffer); - - glGenFramebuffers(1, &bloom_framebuffer); - glBindFramebuffer(GL_FRAMEBUFFER, bloom_framebuffer); - GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT1}; - glDrawBuffers(1, DrawBuffers); - - glGenRenderbuffers(1, &bloom_depthbuffer); - glBindRenderbuffer(GL_RENDERBUFFER, bloom_depthbuffer); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, bloom_depthbuffer); - - glDeleteTextures(1, &preBloomTex); - glDeleteTextures(1, &bloomPassTex1); - glDeleteTextures(1, &bloomPassTex2); - - glGenTextures(1, &preBloomTex); - glBindTexture(GL_TEXTURE_2D, preBloomTex); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glGenTextures(1, &bloomPassTex1); - glBindTexture(GL_TEXTURE_2D, bloomPassTex1); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width/4, height/4, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glGenTextures(1, &bloomPassTex2); - glBindTexture(GL_TEXTURE_2D, bloomPassTex2); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width/4, height/4, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); -} - -GLFWwindow* initRenderer() -{ - if (rendererInitialized) - { - fprintf(stderr, "Renderer already initialized\n"); - exit(-1); - } - - // Initialize GLFW - if (!glfwInit()) - { - fprintf(stderr, "Failed to initialize GLFW\n"); - exit(-1); - } - - glfwWindowHint(GLFW_SAMPLES, 4); // 4x antialiasing - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // We want version 3.3 - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); - glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Mac requires this - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - - // Create a window - window = glfwCreateWindow(1024, 768, "Aromatherapy", nullptr, nullptr); - if (window == nullptr) - { - fprintf(stderr, "Failed to open GLFW window\n"); - glfwTerminate(); - exit(-1); - } - - glfwMakeContextCurrent(window); - glewExperimental = true; // Needed in core profile - if (glewInit() != GLEW_OK) - { - fprintf(stderr, "Failed to initialize GLEW\n"); - exit(-1); - } - - glfwSetFramebufferSizeCallback(window, &setFramebufferSize); - - // Set up vertex array object - glGenVertexArrays(1, &VertexArrayID); - glBindVertexArray(VertexArrayID); - - // Enable depth testing - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LESS); - - // Enable blending - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - // Set up the framebuffer - glGenFramebuffers(1, &generic_framebuffer); - glBindFramebuffer(GL_FRAMEBUFFER, generic_framebuffer); - GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0}; - glDrawBuffers(1, DrawBuffers); - - glGenFramebuffers(1, &bloom_framebuffer); - glBindFramebuffer(GL_FRAMEBUFFER, bloom_framebuffer); - GLenum DrawBuffers2[1] = {GL_COLOR_ATTACHMENT1}; - glDrawBuffers(1, DrawBuffers2); - - glfwGetFramebufferSize(window, &buffer_width, &buffer_height); - - glGenRenderbuffers(1, &bloom_depthbuffer); - glBindRenderbuffer(GL_RENDERBUFFER, bloom_depthbuffer); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, buffer_width, buffer_height); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, bloom_depthbuffer); - - // Set up the NTSC rendering buffers - glGenTextures(2, renderedTexBufs); - glBindTexture(GL_TEXTURE_2D, renderedTexBufs[0]); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, GAME_WIDTH, GAME_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glBindTexture(GL_TEXTURE_2D, renderedTexBufs[1]); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, GAME_WIDTH, GAME_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - // Set up bloom rendering buffers - glGenTextures(1, &preBloomTex); - glBindTexture(GL_TEXTURE_2D, preBloomTex); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, buffer_width, buffer_height, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glGenTextures(1, &bloomPassTex1); - glBindTexture(GL_TEXTURE_2D, bloomPassTex1); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, buffer_width/4, buffer_height/4, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glGenTextures(1, &bloomPassTex2); - glBindTexture(GL_TEXTURE_2D, bloomPassTex2); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, buffer_width/4, buffer_height/4, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - curBuf = 0; - - // Load the mesh! - std::vector mesh_vertices; - std::vector mesh_uvs; - std::vector mesh_normals; - - loadMesh("res/monitor-old.obj", mesh_vertices, mesh_uvs, mesh_normals); - - mesh_numvertices = mesh_vertices.size(); - - glGenBuffers(1, &mesh_vertexbuffer); - glBindBuffer(GL_ARRAY_BUFFER, mesh_vertexbuffer); - glBufferData(GL_ARRAY_BUFFER, mesh_vertices.size() * sizeof(glm::vec3), mesh_vertices.data(), GL_STATIC_DRAW); - - glGenBuffers(1, &mesh_uvbuffer); - glBindBuffer(GL_ARRAY_BUFFER, mesh_uvbuffer); - glBufferData(GL_ARRAY_BUFFER, mesh_uvs.size() * sizeof(glm::vec2), mesh_uvs.data(), GL_STATIC_DRAW); - - glGenBuffers(1, &mesh_normalbuffer); - glBindBuffer(GL_ARRAY_BUFFER, mesh_normalbuffer); - glBufferData(GL_ARRAY_BUFFER, mesh_normals.size() * sizeof(glm::vec3), mesh_normals.data(), GL_STATIC_DRAW); - - // Load the vertices of a flat surface - GLfloat g_quad_vertex_buffer_data[] = { - -1.0f, -1.0f, 0.0f, - 1.0f, -1.0f, 0.0f, - -1.0f, 1.0f, 0.0f, - -1.0f, 1.0f, 0.0f, - 1.0f, -1.0f, 0.0f, - 1.0f, 1.0f, 0.0f, - }; - - glGenBuffers(1, &quad_vertexbuffer); - glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer); - glBufferData(GL_ARRAY_BUFFER, sizeof(g_quad_vertex_buffer_data), g_quad_vertex_buffer_data, GL_STATIC_DRAW); - - glGenTextures(1, &artifactsTex); - glBindTexture(GL_TEXTURE_2D, artifactsTex); - int atdw, atdh; - unsigned char* artifactsTex_data = stbi_load("res/artifacts.bmp", &atdw, &atdh, 0, 3); - flipImageData(artifactsTex_data, atdw, atdh, 3); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, atdw, atdh, 0, GL_RGB, GL_UNSIGNED_BYTE, artifactsTex_data); - stbi_image_free(artifactsTex_data); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); - glGenerateMipmap(GL_TEXTURE_2D); - - glGenTextures(1, &scanlinesTex); - glBindTexture(GL_TEXTURE_2D, scanlinesTex); - int stdw, stdh; - unsigned char* scanlinesTex_data = stbi_load("res/scanlines_333.bmp", &stdw, &stdh, 0, 3); - flipImageData(scanlinesTex_data, stdw, stdh, 3); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, atdw, atdh, 0, GL_RGB, GL_UNSIGNED_BYTE, scanlinesTex_data); - stbi_image_free(scanlinesTex_data); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); - glGenerateMipmap(GL_TEXTURE_2D); - - // Load the shaders - ntscShader = LoadShaders("shaders/ntsc.vertex", "shaders/ntsc.fragment"); - finalShader = LoadShaders("shaders/final.vertex", "shaders/final.fragment"); - blitShader = LoadShaders("shaders/blit.vertex", "shaders/blit.fragment"); - fillShader = LoadShaders("shaders/fill.vertex", "shaders/fill.fragment"); - bloom1Shader = LoadShaders("shaders/bloom1.vertex", "shaders/bloom1.fragment"); - bloom2Shader = LoadShaders("shaders/bloom2.vertex", "shaders/bloom2.fragment"); - - rendererInitialized = true; - - return window; -} - -void destroyRenderer() -{ - if (!rendererInitialized) - { - fprintf(stderr, "Renderer not initialized\n"); - exit(-1); - } - - // Delete the plane buffer - glDeleteBuffers(1, &quad_vertexbuffer); - glDeleteBuffers(1, &mesh_vertexbuffer); - glDeleteBuffers(1, &mesh_uvbuffer); - glDeleteBuffers(1, &mesh_normalbuffer); - - // Delete the shaders - glDeleteProgram(ntscShader); - glDeleteProgram(finalShader); - glDeleteProgram(blitShader); - glDeleteProgram(fillShader); - glDeleteProgram(bloom1Shader); - glDeleteProgram(bloom2Shader); - - // Delete the NTSC rendering buffers - glDeleteTextures(2, renderedTexBufs); - glDeleteTextures(1, &artifactsTex); - glDeleteTextures(1, &scanlinesTex); - glDeleteTextures(1, &preBloomTex); - glDeleteTextures(1, &bloomPassTex1); - glDeleteTextures(1, &bloomPassTex2); - - // Delete the framebuffer - glDeleteRenderbuffers(1, &bloom_depthbuffer); - glDeleteFramebuffers(1, &bloom_framebuffer); - glDeleteFramebuffers(1, &generic_framebuffer); - - // Delete the VAO - glDeleteVertexArrays(1, &VertexArrayID); - - // Kill the window - glfwTerminate(); - - rendererInitialized = false; -} - -Texture::Texture(int width, int height) -{ - if (!rendererInitialized) - { - fprintf(stderr, "Renderer not initialized\n"); - exit(-1); - } - - this->width = width; - this->height = height; - - glGenTextures(1, &texID); - glBindTexture(GL_TEXTURE_2D, texID); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); -} - -Texture::Texture(const char* filename) -{ - if (!rendererInitialized) - { - fprintf(stderr, "Renderer not initialized\n"); - exit(-1); - } - - glGenTextures(1, &texID); - glBindTexture(GL_TEXTURE_2D, texID); - unsigned char* data = stbi_load(filename, &width, &height, 0, 4); - flipImageData(data, width, height, 4); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); - stbi_image_free(data); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); -} - -Texture::Texture(const Texture& tex) -{ - if (!rendererInitialized) - { - fprintf(stderr, "Renderer not initialized\n"); - exit(-1); - } - - width = tex.width; - height = tex.height; - - unsigned char* data = (unsigned char*) malloc(4 * width * height); - glBindTexture(GL_TEXTURE_2D, tex.texID); - glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); - - glGenTextures(1, &texID); - glBindTexture(GL_TEXTURE_2D, texID); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - - free(data); -} - -Texture::Texture(Texture&& tex) : Texture(0, 0) -{ - swap(*this, tex); -} - -Texture::~Texture() -{ - if (!rendererInitialized) - { - fprintf(stderr, "Renderer not initialized\n"); - exit(-1); - } - - glDeleteTextures(1, &texID); -} - -Texture& Texture::operator= (Texture tex) -{ - swap(*this, tex); - - return *this; -} - -void swap(Texture& tex1, Texture& tex2) -{ - std::swap(tex1.width, tex2.width); - std::swap(tex1.height, tex2.height); - std::swap(tex1.texID, tex2.texID); -} - -void Texture::fill(Rectangle dstrect, int r, int g, int b) -{ - if (!rendererInitialized) - { - fprintf(stderr, "Renderer not initialized\n"); - exit(-1); - } - - // Target the framebuffer - glBindFramebuffer(GL_FRAMEBUFFER, generic_framebuffer); - glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texID, 0); - - // Set up the vertex attributes - GLfloat minx = (GLfloat) dstrect.x / width * 2.0 - 1.0; - GLfloat miny = -((GLfloat) dstrect.y / height * 2.0 - 1.0); - GLfloat maxx = (GLfloat) (dstrect.x + dstrect.w) / width * 2.0 - 1.0; - GLfloat maxy = -((GLfloat) (dstrect.y + dstrect.h) / height * 2.0 - 1.0); - - GLfloat vertexbuffer_data[] = { - minx, miny, - maxx, miny, - maxx, maxy, - minx, miny, - minx, maxy, - maxx, maxy - }; - GLuint vertexbuffer; - glGenBuffers(1, &vertexbuffer); - glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer); - glBufferData(GL_ARRAY_BUFFER, sizeof(vertexbuffer_data), vertexbuffer_data, GL_STATIC_DRAW); - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)0); - - glViewport(0, 0, width, height); - glClear(GL_DEPTH_BUFFER_BIT); - glUseProgram(fillShader); - glUniform3f(glGetUniformLocation(fillShader, "vecColor"), r / 255.0, g / 255.0, b / 255.0); - - glDrawArrays(GL_TRIANGLES, 0, 6); - - glDisableVertexAttribArray(0); - glDeleteBuffers(1, &vertexbuffer); -} - -void Texture::blit(const Texture& srctex, Rectangle srcrect, Rectangle dstrect, double alpha) -{ - if (!rendererInitialized) - { - fprintf(stderr, "Renderer not initialized\n"); - exit(-1); - } - - alpha = glm::clamp(alpha, 0.0, 1.0); - - // Target the framebuffer - glBindFramebuffer(GL_FRAMEBUFFER, generic_framebuffer); - glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texID, 0); - - // Set up the vertex attributes - GLfloat minx = (GLfloat) dstrect.x / width * 2.0 - 1.0; - GLfloat miny = -((GLfloat) dstrect.y / height * 2.0 - 1.0); - GLfloat maxx = (GLfloat) (dstrect.x + dstrect.w) / width * 2.0 - 1.0; - GLfloat maxy = -((GLfloat) (dstrect.y + dstrect.h) / height * 2.0 - 1.0); - - GLfloat vertexbuffer_data[] = { - minx, miny, - maxx, miny, - minx, maxy, - maxx, maxy - }; - GLuint vertexbuffer; - glGenBuffers(1, &vertexbuffer); - glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer); - glBufferData(GL_ARRAY_BUFFER, sizeof(vertexbuffer_data), vertexbuffer_data, GL_STATIC_DRAW); - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)0); - - GLfloat minu = (GLfloat) srcrect.x / srctex.width; - GLfloat minv = 1 - ((GLfloat) srcrect.y / srctex.height); - GLfloat maxu = (GLfloat) (srcrect.x + srcrect.w) / srctex.width; - GLfloat maxv = 1 - ((GLfloat) (srcrect.y + srcrect.h) / srctex.height); - - GLfloat texcoordbuffer_data[] = { - minu, minv, - maxu, minv, - minu, maxv, - maxu, maxv - }; - GLuint texcoordbuffer; - glGenBuffers(1, &texcoordbuffer); - glBindBuffer(GL_ARRAY_BUFFER, texcoordbuffer); - glBufferData(GL_ARRAY_BUFFER, sizeof(texcoordbuffer_data), texcoordbuffer_data, GL_STATIC_DRAW); - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void*)0); - - // Set up the shader - glUseProgram(blitShader); - glClear(GL_DEPTH_BUFFER_BIT); - glViewport(0, 0, width, height); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, srctex.texID); - glUniform1i(glGetUniformLocation(blitShader, "srctex"), 0); - glUniform1f(glGetUniformLocation(blitShader, "alpha"), alpha); - - // Blit! - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - - // Unload everything - glDisableVertexAttribArray(1); - glDisableVertexAttribArray(0); - glDeleteBuffers(1, &texcoordbuffer); - glDeleteBuffers(1, &vertexbuffer); -} - -void bloomPass1(GLuint srcTex, GLuint dstTex, bool horizontal, glm::vec2 srcRes, glm::vec2 dstRes) -{ - glBindFramebuffer(GL_FRAMEBUFFER, generic_framebuffer); - glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, dstTex, 0); - glViewport(0,0,dstRes.x,dstRes.y); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glUseProgram(bloom1Shader); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, srcTex); - glUniform1i(glGetUniformLocation(bloom1Shader, "inTex"), 0); - - glm::vec2 offset = glm::vec2(0.0); - if (horizontal) - { - offset.x = 1.2/srcRes.x; - } else { - offset.y = 1.2/srcRes.y; - } - - glUniform2f(glGetUniformLocation(bloom1Shader, "offset"), offset.x, offset.y); - - glEnableVertexAttribArray(0); - glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); - glDrawArrays(GL_TRIANGLES, 0, 6); - glDisableVertexAttribArray(0); -} - -void Texture::renderScreen() const -{ - if (!rendererInitialized) - { - fprintf(stderr, "Renderer not initialized\n"); - exit(-1); - } - - // First we're going to composite our frame with the previous frame - // We start by setting up the framebuffer - glBindFramebuffer(GL_FRAMEBUFFER, generic_framebuffer); - glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, renderedTexBufs[curBuf], 0); - - // Set up the shader - glViewport(0,0,GAME_WIDTH,GAME_HEIGHT); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glUseProgram(ntscShader); - - // Use the current frame texture, nearest neighbor and clamped to edge - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, texID); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glUniform1i(glGetUniformLocation(ntscShader, "curFrameSampler"), 0); - - // Use the previous frame composite texture, nearest neighbor and clamped to edge - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, renderedTexBufs[(curBuf + 1) % 2]); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glUniform1i(glGetUniformLocation(ntscShader, "prevFrameSampler"), 1); - - // Load the NTSC artifact texture - glActiveTexture(GL_TEXTURE2); - glBindTexture(GL_TEXTURE_2D, artifactsTex); - glUniform1i(glGetUniformLocation(ntscShader, "NTSCArtifactSampler"), 2); - glUniform1f(glGetUniformLocation(ntscShader, "NTSCLerp"), curBuf * 1.0); - - if ((rand() % 60) == 0) - { - // Change the 0.0 to a 1.0 or a 10.0 for a glitchy effect! - glUniform1f(glGetUniformLocation(ntscShader, "Tuning_NTSC"), 0.0); - } else { - glUniform1f(glGetUniformLocation(ntscShader, "Tuning_NTSC"), 0.0); - } - - // Render our composition - glEnableVertexAttribArray(0); - glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); - glDrawArrays(GL_TRIANGLES, 0, 6); - glDisableVertexAttribArray(0); - - // We're going to render the screen now - glBindFramebuffer(GL_FRAMEBUFFER, bloom_framebuffer); - glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, preBloomTex, 0); - glViewport(0,0,buffer_width,buffer_height); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glUseProgram(finalShader); - - // Use the composited frame texture, linearly filtered and filling in black for the border - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, renderedTexBufs[curBuf]); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - float border_color[] = {0.0f, 0.0f, 0.0f, 1.0f}; - glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color); - glGenerateMipmap(GL_TEXTURE_2D); - glUniform1i(glGetUniformLocation(finalShader, "rendertex"), 0); - - // Use the scanlines texture - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, scanlinesTex); - glUniform1i(glGetUniformLocation(finalShader, "scanlinestex"), 1); - - // Initialize the MVP matrices - glm::mat4 p_matrix = glm::perspective(glm::radians(25.0f), (float) buffer_width / (float) buffer_height, 0.1f, 100.0f); - glm::mat4 v_matrix = glm::lookAt(glm::vec3(3.75,0,0), glm::vec3(0,0,0), glm::vec3(0,1,0)); - glm::mat4 m_matrix = glm::mat4(1.0); - glm::mat4 mvp_matrix = p_matrix * v_matrix * m_matrix; - - glUniformMatrix4fv(glGetUniformLocation(finalShader, "MVP"), 1, GL_FALSE, &mvp_matrix[0][0]); - glUniformMatrix4fv(glGetUniformLocation(finalShader, "worldMat"), 1, GL_FALSE, &m_matrix[0][0]); - glUniform2f(glGetUniformLocation(finalShader, "resolution"), buffer_width, buffer_height); - glUniform1f(glGetUniformLocation(finalShader, "iGlobalTime"), glfwGetTime()); - glUniform3f(glGetUniformLocation(finalShader, "frameColor"), 0.76f, 0.78f, 0.81f); - - glEnableVertexAttribArray(0); - glBindBuffer(GL_ARRAY_BUFFER, mesh_vertexbuffer); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); - - glEnableVertexAttribArray(1); - glBindBuffer(GL_ARRAY_BUFFER, mesh_normalbuffer); - glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); - - glEnableVertexAttribArray(2); - glBindBuffer(GL_ARRAY_BUFFER, mesh_uvbuffer); - glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, (void*)0); - - glDrawArrays(GL_TRIANGLES, 0, mesh_numvertices); - glDisableVertexAttribArray(2); - glDisableVertexAttribArray(1); - glDisableVertexAttribArray(0); - - // First pass of bloom! - glm::vec2 buffer_size = glm::vec2(buffer_width, buffer_height); - bloomPass1(preBloomTex, bloomPassTex1, true, buffer_size, buffer_size / 4.0f); - bloomPass1(bloomPassTex1, bloomPassTex2, false, buffer_size / 4.0f, buffer_size / 4.0f); - - // Do the second pass of bloom and render to screen - glBindFramebuffer(GL_FRAMEBUFFER, 0); - glViewport(0, 0, buffer_width, buffer_height); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glUseProgram(bloom2Shader); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, preBloomTex); - glUniform1i(glGetUniformLocation(bloom2Shader, "clearTex"), 0); - - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, bloomPassTex2); - glUniform1i(glGetUniformLocation(bloom2Shader, "blurTex"), 1); - - glUniform1f(glGetUniformLocation(bloom2Shader, "iGlobalTime"), glfwGetTime()); - - glEnableVertexAttribArray(0); - glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); - glDrawArrays(GL_TRIANGLES, 0, 6); - glDisableVertexAttribArray(0); - - glfwSwapBuffers(window); - - curBuf = (curBuf + 1) % 2; -} - -Rectangle Texture::entirety() const -{ - return {0, 0, width, height}; -} diff --git a/src/renderer.h b/src/renderer.h deleted file mode 100644 index 6dccf7a..0000000 --- a/src/renderer.h +++ /dev/null @@ -1,37 +0,0 @@ -#include -#include - -#ifndef RENDERER_H -#define RENDERER_H - -struct Rectangle { - int x; - int y; - int w; - int h; -}; - -class Texture { - public: - Texture(int width, int height); - Texture(const char* file); - Texture(const Texture& tex); - Texture(Texture&& tex); - ~Texture(); - Texture& operator= (Texture tex); - friend void swap(Texture& tex1, Texture& tex2); - void fill(Rectangle loc, int r, int g, int b); - void blit(const Texture& src, Rectangle srcrect, Rectangle dstrect, double alpha = 1.0); - void renderScreen() const; - Rectangle entirety() const; - - private: - GLuint texID; - int width; - int height; -}; - -GLFWwindow* initRenderer(); -void destroyRenderer(); - -#endif diff --git a/src/renderer/gl.h b/src/renderer/gl.h new file mode 100644 index 0000000..4e98c42 --- /dev/null +++ b/src/renderer/gl.h @@ -0,0 +1,7 @@ +#ifndef GL_H_3EE4A268 +#define GL_H_3EE4A268 + +#include +#include + +#endif /* end of include guard: GL_H_3EE4A268 */ diff --git a/src/renderer/mesh.cpp b/src/renderer/mesh.cpp new file mode 100644 index 0000000..b06b723 --- /dev/null +++ b/src/renderer/mesh.cpp @@ -0,0 +1,109 @@ +#include "mesh.h" +#include +#include +#include +#include +#include "util.h" + +Mesh::Mesh(std::string filename) +{ + std::ifstream meshfile(filename); + if (!meshfile.is_open()) + { + throw std::invalid_argument("Could not open mesh file"); + } + + std::vector tempVertices; + std::vector tempUvs; + std::vector tempNormals; + + std::vector outVertices; + std::vector outUvs; + std::vector outNormals; + std::map elementIds; + std::vector indices; + + while (meshfile) + { + std::string linetype; + meshfile >> linetype; + + if (linetype == "v") + { + glm::vec3 vertex; + meshfile >> vertex.x >> vertex.y >> vertex.z; + + tempVertices.push_back(std::move(vertex)); + } else if (linetype == "vt") + { + glm::vec2 uv; + meshfile >> uv.x >> uv.y; + + tempUvs.push_back(std::move(uv)); + } else if (linetype == "vn") + { + glm::vec3 normal; + meshfile >> normal.x >> normal.y >> normal.z; + + tempNormals.push_back(std::move(normal)); + } else if (linetype == "f") + { + element elements[3]; + + meshfile + >> elements[0].vertexId >> chlit('/') + >> elements[0].uvId >> chlit('/') + >> elements[0].normalId + >> elements[1].vertexId >> chlit('/') + >> elements[1].uvId >> chlit('/') + >> elements[1].normalId + >> elements[2].vertexId >> chlit('/') + >> elements[2].uvId >> chlit('/') + >> elements[2].normalId; + + for (size_t i = 0; i < 3; i++) + { + if (!elementIds.count(elements[i])) + { + elementIds[elements[i]] = outVertices.size(); + + outVertices.push_back(tempVertices[elements[i].vertexId - 1]); + outUvs.push_back(tempUvs[elements[i].uvId - 1]); + outNormals.push_back(tempNormals[elements[i].normalId - 1]); + } + + indices.push_back(elementIds[elements[i]]); + } + } + } + + glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer_.getId()); + glBufferData( + GL_ARRAY_BUFFER, + outVertices.size() * sizeof(glm::vec3), + outVertices.data(), + GL_STATIC_DRAW); + + glBindBuffer(GL_ARRAY_BUFFER, uvBuffer_.getId()); + glBufferData( + GL_ARRAY_BUFFER, + outUvs.size() * sizeof(glm::vec2), + outUvs.data(), + GL_STATIC_DRAW); + + glBindBuffer(GL_ARRAY_BUFFER, normalBuffer_.getId()); + glBufferData( + GL_ARRAY_BUFFER, + outNormals.size() * sizeof(glm::vec3), + outNormals.data(), + GL_STATIC_DRAW); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer_.getId()); + glBufferData( + GL_ELEMENT_ARRAY_BUFFER, + indices.size() * sizeof(unsigned short), + indices.data(), + GL_STATIC_DRAW); + + indexCount_ = indices.size(); +} diff --git a/src/renderer/mesh.h b/src/renderer/mesh.h new file mode 100644 index 0000000..06bf65d --- /dev/null +++ b/src/renderer/mesh.h @@ -0,0 +1,62 @@ +#ifndef MESH_H_76B72E12 +#define MESH_H_76B72E12 + +#include +#include "gl.h" +#include "wrappers.h" + +class Mesh { +public: + + Mesh(std::string filename); + + Mesh(const Mesh& other) = delete; + Mesh& operator=(const Mesh& other) = delete; + + inline GLuint getVertexBufferId() const + { + return vertexBuffer_.getId(); + } + + inline GLuint getUvBufferId() const + { + return uvBuffer_.getId(); + } + + inline GLuint getNormalBufferId() const + { + return normalBuffer_.getId(); + } + + inline GLuint getIndexBufferId() const + { + return indexBuffer_.getId(); + } + + inline size_t getIndexCount() const + { + return indexCount_; + } + +private: + + struct element { + size_t vertexId; + size_t uvId; + size_t normalId; + + bool operator<(const element& other) const + { + return std::tie(vertexId, uvId, normalId) < + std::tie(other.vertexId, other.uvId, other.normalId); + } + }; + + GLBuffer vertexBuffer_; + GLBuffer uvBuffer_; + GLBuffer normalBuffer_; + GLBuffer indexBuffer_; + size_t indexCount_; +}; + +#endif /* end of include guard: MESH_H_76B72E12 */ diff --git a/src/renderer/renderer.cpp b/src/renderer/renderer.cpp new file mode 100644 index 0000000..6eef2f3 --- /dev/null +++ b/src/renderer/renderer.cpp @@ -0,0 +1,635 @@ +#include "renderer.h" +#include "consts.h" +#include "game.h" +#include +#include "texture.h" + +// include stb_image +#define STB_IMAGE_IMPLEMENTATION +#define STBI_ONLY_PNG +#define STBI_ONLY_BMP +#include "stb_image.h" + +void setFramebufferSize(GLFWwindow* w, int width, int height) +{ + Game& game = *static_cast(glfwGetWindowUserPointer(w)); + Renderer& renderer = game.getRenderer(); + + renderer.width_ = width; + renderer.height_ = height; + + renderer.bloomFb_ = {}; + renderer.bloomDepth_ = {}; + renderer.preBloomTex_ = {}; + renderer.bloomPassTex1_ = {}; + renderer.bloomPassTex2_ = {}; + + renderer.initializeFramebuffers(); +} + +bool Renderer::singletonInitialized_ = false; + +Renderer::Window::Window() +{ + // Initialize GLFW + if (!glfwInit()) + { + throw std::runtime_error("Failed to initialize GLFW"); + } + + glfwWindowHint(GLFW_SAMPLES, 4); // 4x antialiasing + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // We want version 3.3 + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Mac requires this + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + + // Create a window + window_ = glfwCreateWindow(1024, 768, "Aromatherapy", nullptr, nullptr); + if (window_ == nullptr) + { + throw std::runtime_error("Failed to open GLFW window"); + } + + glfwMakeContextCurrent(window_); + + glewExperimental = true; // Needed in core profile + if (glewInit() != GLEW_OK) + { + throw std::runtime_error("Failed to initialize GLEW"); + } + + glfwSetFramebufferSizeCallback(window_, &setFramebufferSize); +} + +Renderer::Window::~Window() +{ + glfwTerminate(); +} + +Renderer::Renderer() : + monitor_("res/monitor-old.obj"), + ntscShader_("ntsc"), + finalShader_("final"), + blitShader_("blit"), + fillShader_("fill"), + bloom1Shader_("bloom1"), + bloom2Shader_("bloom2") +{ + if (singletonInitialized_) + { + throw std::logic_error("Singleton renderer already initialized"); + } + + singletonInitialized_ = true; + + // Set up vertex array object + glBindVertexArray(vao_.getId()); + + // Enable depth testing + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LESS); + + // Enable blending + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + // Set up the rendering buffers and textures + glfwGetFramebufferSize(window_.getHandle(), &width_, &height_); + + initializeFramebuffers(); + + // Load the vertices of a flat surface + GLfloat g_quad_vertex_buffer_data[] = { + -1.0f, -1.0f, 0.0f, + 1.0f, -1.0f, 0.0f, + -1.0f, 1.0f, 0.0f, + -1.0f, 1.0f, 0.0f, + 1.0f, -1.0f, 0.0f, + 1.0f, 1.0f, 0.0f, + }; + + glBindBuffer(GL_ARRAY_BUFFER, quadBuffer_.getId()); + glBufferData( + GL_ARRAY_BUFFER, + sizeof(GLfloat) * 18, + g_quad_vertex_buffer_data, + GL_STATIC_DRAW); + + // Load NTSC artifacts + int atdw, atdh; + unsigned char* artifactsData = + stbi_load("res/artifacts.bmp", &atdw, &atdh, 0, 3); + + flipImageData(artifactsData, atdw, atdh, 3); + + glBindTexture(GL_TEXTURE_2D, artifactsTex_.getId()); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGB, + atdw, + atdh, + 0, + GL_RGB, + GL_UNSIGNED_BYTE, + artifactsData); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri( + GL_TEXTURE_2D, + GL_TEXTURE_MIN_FILTER, + GL_NEAREST_MIPMAP_NEAREST); + + glGenerateMipmap(GL_TEXTURE_2D); + stbi_image_free(artifactsData); + + // Load NTSC scanlines + unsigned char* scanlinesData = + stbi_load("res/scanlines_333.bmp", &atdw, &atdh, 0, 3); + + flipImageData(scanlinesData, atdw, atdh, 3); + + glBindTexture(GL_TEXTURE_2D, scanlinesTex_.getId()); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGB, + atdw, + atdh, + 0, + GL_RGB, + GL_UNSIGNED_BYTE, + scanlinesData); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri( + GL_TEXTURE_2D, + GL_TEXTURE_MIN_FILTER, + GL_NEAREST_MIPMAP_NEAREST); + + glGenerateMipmap(GL_TEXTURE_2D); + stbi_image_free(scanlinesData); +} + +void Renderer::initializeFramebuffers() +{ + // Set up the framebuffer + glBindFramebuffer(GL_FRAMEBUFFER, genericFb_.getId()); + GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0}; + glDrawBuffers(1, DrawBuffers); + + // Set up the bloom framebuffer and depthbuffer + glBindFramebuffer(GL_FRAMEBUFFER, bloomFb_.getId()); + GLenum DrawBuffers2[1] = {GL_COLOR_ATTACHMENT1}; + glDrawBuffers(1, DrawBuffers2); + + glBindRenderbuffer(GL_RENDERBUFFER, bloomDepth_.getId()); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width_, height_); + glFramebufferRenderbuffer( + GL_FRAMEBUFFER, + GL_DEPTH_ATTACHMENT, + GL_RENDERBUFFER, + bloomDepth_.getId()); + + // Set up the NTSC rendering buffers + glBindTexture(GL_TEXTURE_2D, renderPages_[0].getId()); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGB, + GAME_WIDTH, + GAME_HEIGHT, + 0, + GL_RGB, + GL_UNSIGNED_BYTE, + 0); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glBindTexture(GL_TEXTURE_2D, renderPages_[1].getId()); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGB, + GAME_WIDTH, + GAME_HEIGHT, + 0, + GL_RGB, + GL_UNSIGNED_BYTE, + 0); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + // Set up bloom rendering buffers + glBindTexture(GL_TEXTURE_2D, preBloomTex_.getId()); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGB, + width_, + height_, + 0, + GL_RGB, + GL_UNSIGNED_BYTE, + 0); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glBindTexture(GL_TEXTURE_2D, bloomPassTex1_.getId()); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGB, + width_ / 4, + height_ / 4, + 0, + GL_RGB, + GL_UNSIGNED_BYTE, + 0); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glBindTexture(GL_TEXTURE_2D, bloomPassTex2_.getId()); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGB, + width_ / 4, + height_ / 4, + 0, + GL_RGB, + GL_UNSIGNED_BYTE, + 0); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); +} + +Renderer::~Renderer() +{ + singletonInitialized_ = false; +} + +void Renderer::fill(Texture& tex, Rectangle dstrect, int r, int g, int b) +{ + // Target the framebuffer + glBindFramebuffer(GL_FRAMEBUFFER, genericFb_.getId()); + glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex.getId(), 0); + + // Set up the vertex attributes + int width = tex.getWidth(); + int height = tex.getHeight(); + + GLfloat minx = (GLfloat) dstrect.x / width * 2.0 - 1.0; + GLfloat miny = -((GLfloat) dstrect.y / height * 2.0 - 1.0); + GLfloat maxx = (GLfloat) (dstrect.x + dstrect.w) / width * 2.0 - 1.0; + GLfloat maxy = -((GLfloat) (dstrect.y + dstrect.h) / height * 2.0 - 1.0); + + GLfloat vertexData[] = { + minx, miny, + maxx, miny, + maxx, maxy, + minx, miny, + minx, maxy, + maxx, maxy + }; + + GLBuffer vertexBuffer; + glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.getId()); + glBufferData( + GL_ARRAY_BUFFER, + sizeof(GLfloat) * 12, + vertexData, GL_STATIC_DRAW); + + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr); + + glViewport(0, 0, tex.getWidth(), tex.getHeight()); + glClear(GL_DEPTH_BUFFER_BIT); + + fillShader_.use(); + glUniform3f( + fillShader_.getUniformLocation("vecColor"), + r / 255.0, + g / 255.0, + b / 255.0); + + glDrawArrays(GL_TRIANGLES, 0, 6); + + glDisableVertexAttribArray(0); +} + +void Renderer::blit( + const Texture& src, + Texture& dst, + Rectangle srcrect, + Rectangle dstrect, + double alpha) +{ + alpha = glm::clamp(alpha, 0.0, 1.0); + + // Target the framebuffer + glBindFramebuffer(GL_FRAMEBUFFER, genericFb_.getId()); + glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, dst.getId(), 0); + + // Set up the vertex attributes + int width = dst.getWidth(); + int height = dst.getHeight(); + + GLfloat minx = (GLfloat) dstrect.x / width * 2.0 - 1.0; + GLfloat miny = -((GLfloat) dstrect.y / height * 2.0 - 1.0); + GLfloat maxx = (GLfloat) (dstrect.x + dstrect.w) / width * 2.0 - 1.0; + GLfloat maxy = -((GLfloat) (dstrect.y + dstrect.h) / height * 2.0 - 1.0); + + GLfloat vertexData[] = { + minx, miny, + maxx, miny, + minx, maxy, + maxx, maxy + }; + + GLBuffer vertexBuffer; + glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.getId()); + glBufferData( + GL_ARRAY_BUFFER, + sizeof(GLfloat) * 8, + vertexData, + GL_STATIC_DRAW); + + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr); + + GLfloat minu = (GLfloat) srcrect.x / src.getWidth(); + GLfloat minv = 1 - ((GLfloat) srcrect.y / src.getHeight()); + GLfloat maxu = (GLfloat) (srcrect.x + srcrect.w) / src.getWidth(); + GLfloat maxv = 1 - ((GLfloat) (srcrect.y + srcrect.h) / src.getHeight()); + + GLfloat uvData[] = { + minu, minv, + maxu, minv, + minu, maxv, + maxu, maxv + }; + + GLBuffer uvBuffer; + glBindBuffer(GL_ARRAY_BUFFER, uvBuffer.getId()); + glBufferData( + GL_ARRAY_BUFFER, + sizeof(GLfloat) * 8, + uvData, + GL_STATIC_DRAW); + + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, nullptr); + + // Set up the shader + blitShader_.use(); + glClear(GL_DEPTH_BUFFER_BIT); + glViewport(0, 0, dst.getWidth(), dst.getHeight()); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, src.getId()); + glUniform1i(blitShader_.getUniformLocation("srctex"), 0); + glUniform1f(blitShader_.getUniformLocation("alpha"), alpha); + + // Blit! + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + // Unload everything + glDisableVertexAttribArray(1); + glDisableVertexAttribArray(0); +} + +void Renderer::bloomPass1( + const GLTexture& src, + GLTexture& dst, + bool horizontal, + glm::vec2 srcRes, + glm::vec2 dstRes) +{ + glBindFramebuffer(GL_FRAMEBUFFER, genericFb_.getId()); + glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, dst.getId(), 0); + glViewport(0,0,dstRes.x,dstRes.y); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + bloom1Shader_.use(); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, src.getId()); + glUniform1i(bloom1Shader_.getUniformLocation("inTex"), 0); + + glm::vec2 offset = glm::vec2(0.0); + if (horizontal) + { + offset.x = 1.2/srcRes.x; + } else { + offset.y = 1.2/srcRes.y; + } + + glUniform2f(bloom1Shader_.getUniformLocation("offset"), offset.x, offset.y); + + glEnableVertexAttribArray(0); + glBindBuffer(GL_ARRAY_BUFFER, quadBuffer_.getId()); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr); + glDrawArrays(GL_TRIANGLES, 0, 6); + glDisableVertexAttribArray(0); +} + +void Renderer::renderScreen(const Texture& tex) +{ + // First we're going to composite our frame with the previous frame + // We start by setting up the framebuffer + glBindFramebuffer(GL_FRAMEBUFFER, genericFb_.getId()); + glFramebufferTexture( + GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + renderPages_[curBuf_].getId(), + 0); + + // Set up the shader + glViewport(0,0,GAME_WIDTH,GAME_HEIGHT); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + ntscShader_.use(); + + // Use the current frame texture, nearest neighbor and clamped to edge + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, tex.getId()); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glUniform1i(ntscShader_.getUniformLocation("curFrameSampler"), 0); + + // Use the previous frame composite texture, nearest neighbor and clamped to + // edge + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, renderPages_[(curBuf_ + 1) % 2].getId()); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glUniform1i(ntscShader_.getUniformLocation("prevFrameSampler"), 1); + + // Load the NTSC artifact texture + glActiveTexture(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_2D, artifactsTex_.getId()); + glUniform1i(ntscShader_.getUniformLocation("NTSCArtifactSampler"), 2); + glUniform1f(ntscShader_.getUniformLocation("NTSCLerp"), curBuf_ * 1.0); + + // Change the 0.0 to a 1.0 or a 10.0 for a glitchy effect! + glUniform1f(ntscShader_.getUniformLocation("Tuning_NTSC"), 0.0); + + // Render our composition + glEnableVertexAttribArray(0); + glBindBuffer(GL_ARRAY_BUFFER, quadBuffer_.getId()); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr); + glDrawArrays(GL_TRIANGLES, 0, 6); + glDisableVertexAttribArray(0); + + // We're going to render the screen now + glBindFramebuffer(GL_FRAMEBUFFER, bloomFb_.getId()); + glFramebufferTexture( + GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT1, + preBloomTex_.getId(), + 0); + + glViewport(0,0,width_,height_); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + finalShader_.use(); + + // Use the composited frame texture, linearly filtered and filling in black + // for the border + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, renderPages_[curBuf_].getId()); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + + float borderColor[] = {0.0f, 0.0f, 0.0f, 1.0f}; + glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor); + + glGenerateMipmap(GL_TEXTURE_2D); + glUniform1i(finalShader_.getUniformLocation("rendertex"), 0); + + // Use the scanlines texture + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, scanlinesTex_.getId()); + glUniform1i(finalShader_.getUniformLocation("scanlinestex"), 1); + + // Initialize the MVP matrices + glm::mat4 p_matrix = glm::perspective( + glm::radians(25.0f), + static_cast(width_) / static_cast(height_), + 0.1f, + 100.0f); + + glm::mat4 v_matrix = glm::lookAt( + glm::vec3(3.75,0,0), // Camera + glm::vec3(0,0,0), // Center + glm::vec3(0,1,0)); // Up + + glm::mat4 m_matrix = glm::mat4(1.0); + glm::mat4 mvp_matrix = p_matrix * v_matrix * m_matrix; + + glUniformMatrix4fv( + finalShader_.getUniformLocation("MVP"), + 1, + GL_FALSE, + &mvp_matrix[0][0]); + + glUniformMatrix4fv( + finalShader_.getUniformLocation("worldMat"), + 1, + GL_FALSE, + &m_matrix[0][0]); + + glUniform2f(finalShader_.getUniformLocation("resolution"), width_, height_); + glUniform1f(finalShader_.getUniformLocation("iGlobalTime"), glfwGetTime()); + + glUniform3f( + finalShader_.getUniformLocation("frameColor"), + 0.76f, + 0.78f, + 0.81f); + + glEnableVertexAttribArray(0); + glBindBuffer(GL_ARRAY_BUFFER, monitor_.getVertexBufferId()); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr); + + glEnableVertexAttribArray(1); + glBindBuffer(GL_ARRAY_BUFFER, monitor_.getNormalBufferId()); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, nullptr); + + glEnableVertexAttribArray(2); + glBindBuffer(GL_ARRAY_BUFFER, monitor_.getUvBufferId()); + glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, nullptr); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, monitor_.getIndexBufferId()); + glDrawElements( + GL_TRIANGLES, + monitor_.getIndexCount(), + GL_UNSIGNED_SHORT, + nullptr); + + glDisableVertexAttribArray(2); + glDisableVertexAttribArray(1); + glDisableVertexAttribArray(0); + + // First pass of bloom! + glm::vec2 bufferSize = glm::vec2(width_, height_); + + bloomPass1( + preBloomTex_, + bloomPassTex1_, + true, + bufferSize, + bufferSize / 4.0f); + + bloomPass1( + bloomPassTex1_, + bloomPassTex2_, + false, + bufferSize / 4.0f, + bufferSize / 4.0f); + + // Do the second pass of bloom and render to screen + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glViewport(0, 0, width_, height_); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + bloom2Shader_.use(); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, preBloomTex_.getId()); + glUniform1i(bloom2Shader_.getUniformLocation("clearTex"), 0); + + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, bloomPassTex2_.getId()); + glUniform1i(bloom2Shader_.getUniformLocation("blurTex"), 1); + + glUniform1f(bloom2Shader_.getUniformLocation("iGlobalTime"), glfwGetTime()); + + glEnableVertexAttribArray(0); + glBindBuffer(GL_ARRAY_BUFFER, quadBuffer_.getId()); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr); + glDrawArrays(GL_TRIANGLES, 0, 6); + glDisableVertexAttribArray(0); + + glfwSwapBuffers(window_.getHandle()); + + curBuf_ = (curBuf_ + 1) % 2; +} diff --git a/src/renderer/renderer.h b/src/renderer/renderer.h new file mode 100644 index 0000000..0b10af5 --- /dev/null +++ b/src/renderer/renderer.h @@ -0,0 +1,114 @@ +#ifndef RENDERER_H +#define RENDERER_H + +#include "gl.h" +#include "wrappers.h" +#include "mesh.h" +#include "shader.h" +#include + +class Texture; +struct Rectangle; + +class Renderer { +public: + + class Window { + public: + + Window(); + + Window(const Window& other) = delete; + Window& operator=(const Window& other) = delete; + + ~Window(); + + inline GLFWwindow* getHandle() + { + return window_; + } + + private: + + GLFWwindow* window_; + }; + + static inline bool isSingletonInitialized() + { + return singletonInitialized_; + } + + Renderer(); + + Renderer(const Renderer& other) = delete; + Renderer& operator=(const Renderer& other) = delete; + + ~Renderer(); + + inline Window& getWindow() + { + return window_; + } + + void fill( + Texture& tex, + Rectangle loc, + int r, + int g, + int b); + + void blit( + const Texture& src, + Texture& dst, + Rectangle srcrect, + Rectangle dstrect, + double alpha = 1.0); + + void renderScreen(const Texture& tex); + +private: + + friend void setFramebufferSize(GLFWwindow* w, int width, int height); + + void initializeFramebuffers(); + + void bloomPass1( + const GLTexture& src, + GLTexture& dst, + bool horizontal, + glm::vec2 srcRes, + glm::vec2 dstRes); + + static bool singletonInitialized_; + + Window window_; + GLVertexArray vao_; + + GLFramebuffer genericFb_; + GLFramebuffer bloomFb_; + GLRenderbuffer bloomDepth_; + + GLTexture renderPages_[2]; + GLTexture preBloomTex_; + GLTexture bloomPassTex1_; + GLTexture bloomPassTex2_; + + Mesh monitor_; + GLBuffer quadBuffer_; + + GLTexture artifactsTex_; + GLTexture scanlinesTex_; + + Shader ntscShader_; + Shader finalShader_; + Shader blitShader_; + Shader fillShader_; + Shader bloom1Shader_; + Shader bloom2Shader_; + + size_t curBuf_ = 0; + int width_; + int height_; +}; + +#endif diff --git a/src/renderer/shader.cpp b/src/renderer/shader.cpp new file mode 100644 index 0000000..735fc22 --- /dev/null +++ b/src/renderer/shader.cpp @@ -0,0 +1,84 @@ +#include "shader.h" +#include +#include +#include "util.h" + +Shader::Shader(std::string name) +{ + GLShader vertexShader(GL_VERTEX_SHADER); + GLShader fragmentShader(GL_FRAGMENT_SHADER); + + std::ifstream vertexFile("shaders/" + name + ".vertex"); + std::ifstream fragmentFile("shaders/" + name + ".fragment"); + + std::string vertexCode(slurp(vertexFile)); + std::string fragmentCode(slurp(fragmentFile)); + + const char* vertexCodePtr = vertexCode.c_str(); + const char* fragmentCodePtr = fragmentCode.c_str(); + + glShaderSource(vertexShader.getId(), 1, &vertexCodePtr, nullptr); + glShaderSource(fragmentShader.getId(), 1, &fragmentCodePtr, nullptr); + + glCompileShader(vertexShader.getId()); + glCompileShader(fragmentShader.getId()); + +#ifdef DEBUG + GLint result = GL_FALSE; + int infoLogLength; + + glGetShaderiv(vertexShader.getId(), GL_COMPILE_STATUS, &result); + + if (result == GL_FALSE) + { + glGetShaderiv(vertexShader.getId(), GL_INFO_LOG_LENGTH, &infoLogLength); + + std::vector errMsg(infoLogLength); + glGetShaderInfoLog( + vertexShader.getId(), + infoLogLength, + nullptr, + errMsg.data()); + + throw std::gl_error("Could not compile shader", errMsg.data()); + } + + glGetShaderiv(fragmentShader.getId(), GL_COMPILE_STATUS, &result); + + if (result == GL_FALSE) + { + glGetShaderiv(fragmentShader.getId(), GL_INFO_LOG_LENGTH, &infoLogLength); + + std::vector errMsg(infoLogLength); + glGetShaderInfoLog( + fragmentShader.getId(), + infoLogLength, + nullptr, + errMsg.data()); + + throw std::gl_error("Could not compile shader", errMsg.data()); + } +#endif + + glAttachShader(program_.getId(), vertexShader.getId()); + glAttachShader(program_.getId(), fragmentShader.getId()); + glLinkProgram(program_.getId()); + +#ifdef DEBUG + glGetProgramiv(program_.getId(), GL_LINK_STATUS, &result); + + if (result == GL_FALSE) + { + glGetProgramiv(program_.getId(), GL_INFO_LOG_LENGTH, &infoLogLength); + + std::vector errMsg(infoLogLength); + glGetProgramInfoLog( + program_.getId(), + infoLogLength, + nullptr, + errMsg.data()); + + throw std::gl_error("Could not link shader program", errMsg.data()); + } +#endif +} diff --git a/src/renderer/shader.h b/src/renderer/shader.h new file mode 100644 index 0000000..d2c673c --- /dev/null +++ b/src/renderer/shader.h @@ -0,0 +1,58 @@ +#ifndef SHADER_H_25115B63 +#define SHADER_H_25115B63 + +#include +#include +#include "gl.h" +#include "wrappers.h" + +class gl_error : public std::logic_error { +public: + + gl_error( + const char* msg, + std::string info) : + std::logic_error(msg), + info_(std::move(info)) + { + } + + gl_error( + std::string& msg, + std::string info) : + std::logic_error(msg), + info_(std::move(info)) + { + } + + inline const std::string& getInfo() const + { + return info_; + } + +private: + + std::string info_; +}; + +class Shader { +public: + + Shader(std::string name); + + inline void use() + { + glUseProgram(program_.getId()); + } + + inline GLint getUniformLocation(const GLchar* name) + { + return glGetUniformLocation(program_.getId(), name); + } + +private: + + GLProgram program_; +}; + +#endif /* end of include guard: SHADER_H_25115B63 */ diff --git a/src/renderer/texture.cpp b/src/renderer/texture.cpp new file mode 100644 index 0000000..2728665 --- /dev/null +++ b/src/renderer/texture.cpp @@ -0,0 +1,124 @@ +#include "texture.h" +#include +#include "renderer.h" +#include "util.h" + +// include stb_image +#define STBI_ONLY_PNG +#define STBI_ONLY_BMP +#include "stb_image.h" + +Texture::Texture( + int width, + int height) : + width_(width), + height_(height) +{ + if (!Renderer::isSingletonInitialized()) + { + throw std::logic_error("Renderer needs to be initialized"); + } + + glBindTexture(GL_TEXTURE_2D, texture_.getId()); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGBA, + width_, + height_, + 0, + GL_RGBA, + GL_UNSIGNED_BYTE, + 0); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); +} + +Texture::Texture(const char* filename) +{ + if (!Renderer::isSingletonInitialized()) + { + throw std::logic_error("Renderer needs to be initialized"); + } + + glBindTexture(GL_TEXTURE_2D, texture_.getId()); + unsigned char* data = stbi_load(filename, &width_, &height_, 0, 4); + flipImageData(data, width_, height_, 4); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGBA, + width_, + height_, + 0, + GL_RGBA, + GL_UNSIGNED_BYTE, + data); + + stbi_image_free(data); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); +} + +Texture::Texture( + const Texture& tex) : + width_(tex.width_), + height_(tex.height_) +{ + if (!Renderer::isSingletonInitialized()) + { + throw std::logic_error("Renderer needs to be initialized"); + } + + unsigned char* data = new unsigned char[4 * width_ * height_]; + glBindTexture(GL_TEXTURE_2D, tex.getId()); + glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + + glBindTexture(GL_TEXTURE_2D, texture_.getId()); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGBA, + width_, + height_, + 0, + GL_RGBA, + GL_UNSIGNED_BYTE, + data); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + + delete[] data; +} + +Texture::Texture(Texture&& tex) : Texture(0, 0) +{ + swap(*this, tex); +} + +Texture& Texture::operator= (Texture tex) +{ + swap(*this, tex); + + return *this; +} + +void swap(Texture& tex1, Texture& tex2) +{ + std::swap(tex1.width_, tex2.width_); + std::swap(tex1.height_, tex2.height_); + std::swap(tex1.texture_, tex2.texture_); +} + +Rectangle Texture::entirety() const +{ + return {0, 0, width_, height_}; +} diff --git a/src/renderer/texture.h b/src/renderer/texture.h new file mode 100644 index 0000000..3aa8773 --- /dev/null +++ b/src/renderer/texture.h @@ -0,0 +1,52 @@ +#ifndef TEXTURE_H_84EC6DF6 +#define TEXTURE_H_84EC6DF6 + +#include "wrappers.h" + +struct Rectangle { + int x; + int y; + int w; + int h; +}; + +class Texture { +public: + + Texture(int width, int height); + + Texture(const char* file); + + Texture(const Texture& tex); + + Texture(Texture&& tex); + + Texture& operator= (Texture tex); + + friend void swap(Texture& tex1, Texture& tex2); + + Rectangle entirety() const; + + inline GLuint getId() const + { + return texture_.getId(); + } + + inline int getWidth() const + { + return width_; + } + + inline int getHeight() const + { + return height_; + } + +private: + + GLTexture texture_; + int width_; + int height_; +}; + +#endif /* end of include guard: TEXTURE_H_84EC6DF6 */ diff --git a/src/renderer/wrappers.h b/src/renderer/wrappers.h new file mode 100644 index 0000000..c6edc11 --- /dev/null +++ b/src/renderer/wrappers.h @@ -0,0 +1,273 @@ +#ifndef WRAPPERS_H_1EE0965B +#define WRAPPERS_H_1EE0965B + +#include "gl.h" +#include + +class GLVertexArray { +public: + + GLVertexArray() + { + glGenVertexArrays(1, &id_); + } + + GLVertexArray(const GLVertexArray& other) = delete; + GLVertexArray& operator=(const GLVertexArray& other) = delete; + + GLVertexArray(GLVertexArray&& other) : GLVertexArray() + { + std::swap(id_, other.id_); + } + + GLVertexArray& operator=(GLVertexArray&& other) + { + std::swap(id_, other.id_); + + return *this; + } + + ~GLVertexArray() + { + glDeleteVertexArrays(1, &id_); + } + + inline GLuint getId() const + { + return id_; + } + +private: + + GLuint id_; +}; + +class GLFramebuffer { +public: + + GLFramebuffer() + { + glGenFramebuffers(1, &id_); + } + + GLFramebuffer(const GLFramebuffer& other) = delete; + GLFramebuffer& operator=(const GLFramebuffer& other) = delete; + + GLFramebuffer(GLFramebuffer&& other) : GLFramebuffer() + { + std::swap(id_, other.id_); + } + + GLFramebuffer& operator=(GLFramebuffer&& other) + { + std::swap(id_, other.id_); + + return *this; + } + + ~GLFramebuffer() + { + glDeleteFramebuffers(1, &id_); + } + + inline GLuint getId() const + { + return id_; + } + +private: + + GLuint id_; +}; + +class GLRenderbuffer { +public: + + GLRenderbuffer() + { + glGenRenderbuffers(1, &id_); + } + + GLRenderbuffer(const GLRenderbuffer& other) = delete; + GLRenderbuffer& operator=(const GLRenderbuffer& other) = delete; + + GLRenderbuffer(GLRenderbuffer&& other) : GLRenderbuffer() + { + std::swap(id_, other.id_); + } + + GLRenderbuffer& operator=(GLRenderbuffer&& other) + { + std::swap(id_, other.id_); + + return *this; + } + + ~GLRenderbuffer() + { + glDeleteRenderbuffers(1, &id_); + } + + inline GLuint getId() const + { + return id_; + } + +private: + + GLuint id_; +}; + +class GLBuffer { +public: + + GLBuffer() + { + glGenBuffers(1, &id_); + } + + GLBuffer(const GLBuffer& other) = delete; + GLBuffer& operator=(const GLBuffer& other) = delete; + + GLBuffer(GLBuffer&& other) : GLBuffer() + { + std::swap(id_, other.id_); + } + + GLBuffer& operator=(GLBuffer&& other) + { + std::swap(id_, other.id_); + + return *this; + } + + ~GLBuffer() + { + glDeleteBuffers(1, &id_); + } + + inline GLuint getId() const + { + return id_; + } + +private: + + GLuint id_; +}; + +class GLTexture { +public: + + GLTexture() + { + glGenTextures(1, &id_); + } + + GLTexture(const GLTexture& other) = delete; + GLTexture& operator=(const GLTexture& other) = delete; + + GLTexture(GLTexture&& other) : GLTexture() + { + std::swap(id_, other.id_); + } + + GLTexture& operator=(GLTexture&& other) + { + std::swap(id_, other.id_); + + return *this; + } + + ~GLTexture() + { + glDeleteTextures(1, &id_); + } + + inline GLuint getId() const + { + return id_; + } + +private: + + GLuint id_; +}; + +class GLShader { +public: + + GLShader(GLenum type) + { + id_ = glCreateShader(type); + } + + GLShader(const GLShader& other) = delete; + GLShader& operator=(const GLShader& other) = delete; + + GLShader(GLShader&& other) : GLShader(GL_VERTEX_SHADER) + { + std::swap(id_, other.id_); + } + + GLShader& operator=(GLShader&& other) + { + std::swap(id_, other.id_); + + return *this; + } + + ~GLShader() + { + glDeleteShader(id_); + } + + inline GLuint getId() const + { + return id_; + } + +private: + + GLuint id_; +}; + +class GLProgram { +public: + + GLProgram() + { + id_ = glCreateProgram(); + } + + GLProgram(const GLProgram& other) = delete; + GLProgram& operator=(const GLProgram& other) = delete; + + GLProgram(GLProgram&& other) : GLProgram() + { + std::swap(id_, other.id_); + } + + GLProgram& operator=(GLProgram&& other) + { + std::swap(id_, other.id_); + + return *this; + } + + ~GLProgram() + { + glDeleteProgram(id_); + } + + inline GLuint getId() const + { + return id_; + } + +private: + + GLuint id_; +}; + +#endif /* end of include guard: WRAPPERS_H_1EE0965B */ diff --git a/src/systems/animating.cpp b/src/systems/animating.cpp index 91fe925..22224c9 100644 --- a/src/systems/animating.cpp +++ b/src/systems/animating.cpp @@ -51,8 +51,9 @@ void AnimatingSystem::render(Texture& texture) transform.getH()}; const AnimationSet& aset = sprite.getAnimationSet(); - texture.blit( + game_.getRenderer().blit( aset.getTexture(), + texture, aset.getFrameRect(sprite.getFrame()), dstrect); } diff --git a/src/systems/animating.h b/src/systems/animating.h index d6a89a5..548bff1 100644 --- a/src/systems/animating.h +++ b/src/systems/animating.h @@ -3,7 +3,7 @@ #include "system.h" #include -#include "renderer.h" +#include "renderer/texture.h" class AnimatingSystem : public System { public: diff --git a/src/systems/mapping.cpp b/src/systems/mapping.cpp index 5b63ded..120a27a 100644 --- a/src/systems/mapping.cpp +++ b/src/systems/mapping.cpp @@ -48,7 +48,11 @@ void MappingSystem::render(Texture& texture) TILE_WIDTH, TILE_HEIGHT}; - texture.blit(mappable.getTileset(), std::move(src), std::move(dst)); + game_.getRenderer().blit( + mappable.getTileset(), + texture, + std::move(src), + std::move(dst)); } } @@ -67,7 +71,11 @@ void MappingSystem::render(Texture& texture) TILE_WIDTH, TILE_HEIGHT}; - texture.blit(mappable.getFont(), std::move(src), std::move(dst)); + game_.getRenderer().blit( + mappable.getFont(), + texture, + std::move(src), + std::move(dst)); } } } diff --git a/src/util.cpp b/src/util.cpp new file mode 100644 index 0000000..f0c39fd --- /dev/null +++ b/src/util.cpp @@ -0,0 +1,30 @@ +#include "util.h" + +std::string slurp(std::ifstream& in) +{ + std::stringstream sstr; + sstr << in.rdbuf(); + return sstr.str(); +} + +void flipImageData( + unsigned char* data, + int width, + int height, + int comps) +{ + unsigned char* dataCopy = new unsigned char[width * height * comps]; + memcpy(dataCopy, data, width * height * comps); + + int rowSize = width * comps; + + for (int i = 0; i < height; i++) + { + memcpy( + data + (rowSize * i), + dataCopy + (rowSize * (height - i - 1)), + rowSize); + } + + delete[] dataCopy; +} diff --git a/src/util.h b/src/util.h new file mode 100644 index 0000000..72cb0d3 --- /dev/null +++ b/src/util.h @@ -0,0 +1,41 @@ +#ifndef ALGORITHMS_H_1DDC517E +#define ALGORITHMS_H_1DDC517E + +#include +#include +#include + +template< typename ContainerT, typename PredicateT > +void erase_if( ContainerT& items, const PredicateT& predicate ) { + for( auto it = items.begin(); it != items.end(); ) { + if( predicate(*it) ) it = items.erase(it); + else ++it; + } +}; + +struct chlit +{ + chlit(char c) : c_(c) { } + char c_; +}; + +inline std::istream& operator>>(std::istream& is, chlit x) +{ + char c; + if (is >> c && c != x.c_) + { + is.setstate(std::iostream::failbit); + } + + return is; +} + +std::string slurp(std::ifstream& in); + +void flipImageData( + unsigned char* data, + int width, + int height, + int comps); + +#endif /* end of include guard: ALGORITHMS_H_1DDC517E */ -- cgit 1.4.1