#include "renderer.h" #include #include #include #include #include #include "mapview.h" #include // 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 FramebufferName; // The framebuffer static GLuint depthrenderbuffer; 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 renderedTex1; static GLuint renderedTex2; static GLuint renderedTexBufs[2]; static int curBuf; static GLuint artifactsTex; static GLuint scanlinesTex; static GLuint preBloomTex; static GLuint bloomPassTex; // 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 , NULL); 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, NULL, &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 , NULL); 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, NULL, &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, NULL, &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) { FILE* file = fopen(filename, "r"); if (file == NULL) { 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)) { 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)) { vec2 uv; fscanf(file, "%f %f\n", &uv.x, &uv.y); temp_uvs.push_back(uv); } else if (!strncmp(lineHeader, "vn", 3)) { 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, &FramebufferName); glDeleteRenderbuffers(1, &depthrenderbuffer); glGenFramebuffers(1, &FramebufferName); glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName); GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0}; glDrawBuffers(1, DrawBuffers); glGenRenderbuffers(1, &depthrenderbuffer); glBindRenderbuffer(GL_RENDERBUFFER, depthrenderbuffer); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthrenderbuffer); glDeleteTextures(1, &preBloomTex); glDeleteTextures(1, &bloomPassTex); 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, &bloomPassTex); glBindTexture(GL_TEXTURE_2D, bloomPassTex); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width/16, height/16, 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", NULL, NULL); if (window == NULL) { 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, &FramebufferName); glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName); GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0}; glDrawBuffers(1, DrawBuffers); glGenRenderbuffers(1, &depthrenderbuffer); glBindRenderbuffer(GL_RENDERBUFFER, depthrenderbuffer); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, 1024, 768); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthrenderbuffer); // Set up the NTSC rendering buffers glGenTextures(1, &renderedTex1); glBindTexture(GL_TEXTURE_2D, renderedTex1); 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); renderedTexBufs[0] = renderedTex1; glGenTextures(1, &renderedTex2); glBindTexture(GL_TEXTURE_2D, renderedTex2); 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); renderedTexBufs[1] = renderedTex2; // Set up bloom rendering buffers glGenTextures(1, &preBloomTex); glBindTexture(GL_TEXTURE_2D, preBloomTex); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1024, 768, 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, &bloomPassTex); glBindTexture(GL_TEXTURE_2D, bloomPassTex); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 64, 48, 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-fef.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(vec3), &mesh_vertices[0], GL_STATIC_DRAW); glGenBuffers(1, &mesh_uvbuffer); glBindBuffer(GL_ARRAY_BUFFER, mesh_uvbuffer); glBufferData(GL_ARRAY_BUFFER, mesh_uvs.size() * sizeof(vec3), &mesh_uvs[0], GL_STATIC_DRAW); glGenBuffers(1, &mesh_normalbuffer); glBindBuffer(GL_ARRAY_BUFFER, mesh_normalbuffer); glBufferData(GL_ARRAY_BUFFER, mesh_normals.size() * sizeof(vec3), &mesh_normals[0], 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.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(1, &renderedTex1); glDeleteTextures(1, &renderedTex2); glDeleteTextures(1, &artifactsTex); glDeleteTextures(1, &scanlinesTex); glDeleteTextures(1, &preBloomTex); glDeleteTextures(1, &bloomPassTex); // Delete the framebuffer glDeleteRenderbuffers(1, &depthrenderbuffer); glDeleteFramebuffers(1, &FramebufferName); // Delete the VAO glDeleteVertexArrays(1, &VertexArrayID); // Kill the window glfwTerminate(); rendererInitialized = false; } Texture* createTexture(int width, int height) { if (!rendererInitialized) { fprintf(stderr, "Renderer not initialized\n"); exit(-1); } Texture* tex = new Texture(); tex->width = width; tex->height = height; glGenTextures(1, &(tex->texID)); glBindTexture(GL_TEXTURE_2D, tex->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); return tex; } void destroyTexture(Texture* tex) { if (!rendererInitialized) { fprintf(stderr, "Renderer not initialized\n"); exit(-1); } glDeleteTextures(1, &(tex->texID)); delete tex; } Texture* loadTextureFromBMP(char* filename) { if (!rendererInitialized) { fprintf(stderr, "Renderer not initialized\n"); exit(-1); } Texture* tex = new Texture(); glGenTextures(1, &(tex->texID)); glBindTexture(GL_TEXTURE_2D, tex->texID); unsigned char* data = stbi_load(filename, &(tex->width), &(tex->height), 0, 4); flipImageData(data, tex->width, tex->height, 4); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex->width, tex->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); return tex; } void saveTextureToBMP(Texture* tex, char* filename) { if (!rendererInitialized) { fprintf(stderr, "Renderer not initialized\n"); exit(-1); } int size = 54 + 3*tex->width*tex->height; char* buf = (char*) calloc(size, sizeof(char)); buf[0x00] = 'B'; buf[0x01] = 'M'; *(int*)&(buf[0x0A]) = 54; *(int*)&(buf[0x12]) = tex->width; *(int*)&(buf[0x16]) = tex->height; *(int*)&(buf[0x1C]) = 24; *(int*)&(buf[0x1E]) = 0; *(int*)&(buf[0x22]) = size; glBindTexture(GL_TEXTURE_2D, tex->texID); glGetTexImage(GL_TEXTURE_2D, 0, GL_BGR, GL_UNSIGNED_BYTE, buf + 54); FILE* f = fopen(filename, "wb"); fwrite(buf, sizeof(char), size, f); fclose(f); free(buf); } void fillTexture(Texture* tex, Rectangle* dstrect, int r, int g, int b) { if (!rendererInitialized) { fprintf(stderr, "Renderer not initialized\n"); exit(-1); } // Target the framebuffer glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName); glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex->texID, 0); // Set up the vertex attributes GLfloat minx = (dstrect == NULL) ? 0.0f : dstrect->x; GLfloat miny = (dstrect == NULL) ? 0.0f : dstrect->y; GLfloat maxx = (dstrect == NULL) ? tex->width : dstrect->x + dstrect->w; GLfloat maxy = (dstrect == NULL) ? tex->height : dstrect->y + dstrect->h; minx = minx / tex->width * 2.0 - 1.0; miny = -(miny / tex->height * 2.0 - 1.0); maxx = maxx / tex->width * 2.0 - 1.0; maxy = -(maxy / tex->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, tex->width, tex->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 blitTexture(Texture* srctex, Texture* dsttex, Rectangle* srcrect, Rectangle* dstrect) { if (!rendererInitialized) { fprintf(stderr, "Renderer not initialized\n"); exit(-1); } // Target the framebuffer glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName); glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, dsttex->texID, 0); // Set up the vertex attributes GLfloat minx = (dstrect == NULL) ? 0.0f : dstrect->x; GLfloat miny = (dstrect == NULL) ? 0.0f : dstrect->y; GLfloat maxx = (dstrect == NULL) ? dsttex->width : dstrect->x + dstrect->w; GLfloat maxy = (dstrect == NULL) ? dsttex->height : dstrect->y + dstrect->h; minx = minx / dsttex->width * 2.0 - 1.0; miny = -(miny / dsttex->height * 2.0 - 1.0); maxx = maxx / dsttex->width * 2.0 - 1.0; maxy = -(maxy / dsttex->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 = (srcrect == NULL) ? 0.0f : srcrect->x; GLfloat minv = (srcrect == NULL) ? 0.0f : srcrect->y; GLfloat maxu = (srcrect == NULL) ? srctex->width : srcrect->x + srcrect->w; GLfloat maxv = (srcrect == NULL) ? srctex->height : srcrect->y + srcrect->h; minu = minu / srctex->width; minv = 1 - (minv / srctex->height); maxu = maxu / srctex->width; maxv = 1 - (maxv / 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, dsttex->width, dsttex->height); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, srctex->texID); glUniform1i(glGetUniformLocation(blitShader, "srctex"), 0); // Blit! glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); // Unload everything glDisableVertexAttribArray(1); glDisableVertexAttribArray(0); glDeleteBuffers(1, &texcoordbuffer); glDeleteBuffers(1, &vertexbuffer); } void renderWithoutEffects(Texture* tex) { if (!rendererInitialized) { fprintf(stderr, "Renderer not initialized\n"); exit(-1); } glBindFramebuffer(GL_FRAMEBUFFER, 0); glViewport(0, 0, buffer_width, buffer_height); glClear(GL_COLOR_BUFFER_BIT); glUseProgram(blitShader); const GLfloat fullBlitVertices_data[] = { -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0 }; GLuint fullBlitVertices; glGenBuffers(1, &fullBlitVertices); glBindBuffer(GL_ARRAY_BUFFER, fullBlitVertices); glBufferData(GL_ARRAY_BUFFER, sizeof(fullBlitVertices_data), fullBlitVertices_data, GL_STATIC_DRAW); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)0); const GLfloat fullBlitTex_data[] = { 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0 }; GLuint fullBlitTex; glGenBuffers(1, &fullBlitTex); glBindBuffer(GL_ARRAY_BUFFER, fullBlitTex); glBufferData(GL_ARRAY_BUFFER, sizeof(fullBlitTex_data), fullBlitTex_data, GL_STATIC_DRAW); glEnableVertexAttribArray(1); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void*)0); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, tex->texID); glUniform1i(glGetUniformLocation(blitShader, "srctex"), 0); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glDisableVertexAttribArray(1); glDisableVertexAttribArray(0); glDeleteBuffers(1, &fullBlitTex); glDeleteBuffers(1, &fullBlitVertices); glfwSwapBuffers(window); } void renderScreen(Texture* tex) { 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, FramebufferName); 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, tex->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 glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, preBloomTex, 0); //glBindFramebuffer(GL_FRAMEBUFFER, 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 mat4 p_matrix = perspective(45.0f, (float) buffer_width / (float) buffer_height, 0.1f, 100.0f); mat4 v_matrix = lookAt(vec3(2,0,0), vec3(0,0,0), vec3(0,1,0)); mat4 m_matrix = mat4(1.0); mat4 mvp_matrix = p_matrix * v_matrix * m_matrix; //mat4 mv_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); 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); // Do the first pass of bloom (downsampling and tapping) glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, bloomPassTex, 0); glViewport(0, 0, buffer_width/16, buffer_height/16); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glUseProgram(bloom1Shader); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, preBloomTex); glUniform1i(glGetUniformLocation(bloom1Shader, "screenTex"), 0); glUniform1f(glGetUniformLocation(bloom1Shader, "iGlobalTime"), glfwGetTime()); glUniform2f(glGetUniformLocation(bloom1Shader, "resolution"), buffer_width, buffer_height); 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); // 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, "screenTex"), 0); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, bloomPassTex); glUniform1i(glGetUniformLocation(bloom2Shader, "downsampledTex"), 1); glUniform1f(glGetUniformLocation(bloom2Shader, "iGlobalTime"), glfwGetTime()); glUniform2f(glGetUniformLocation(bloom2Shader, "resolution"), buffer_width, buffer_height); 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; }