From de5a458cb037bb8e1e80c849c5e6525f9413b43a Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Sat, 14 Feb 2015 12:09:41 -0500 Subject: Monitor stuff is looking pretty cool! --- src/main.cpp | 149 ++++++++++++++ src/map.cpp | 241 +++++++++++++++++++++++ src/map.h | 42 ++++ src/mob.h | 10 + src/renderer.cpp | 582 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/renderer.h | 42 ++++ 6 files changed, 1066 insertions(+) create mode 100644 src/main.cpp create mode 100644 src/map.cpp create mode 100644 src/map.h create mode 100644 src/mob.h create mode 100644 src/renderer.cpp create mode 100644 src/renderer.h (limited to 'src') diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..a2743d1 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,149 @@ +#include +#include +#include "map.h" +#include "renderer.h" + +using namespace::std; + +#if defined(__WIN32__) || defined(_WIN32) || defined(WIN32) || defined(__WINDOWS__) || defined(__TOS_WIN__) + + #include + + inline void delay( unsigned long ms ) + { + Sleep( ms ); + } + +#else /* presume POSIX */ + + #include + + inline void delay( unsigned long ms ) + { + usleep( ms * 1000 ); + } + +#endif + +const int FRAMES_PER_SECOND = 60; +bool holding_left = false; +bool holding_right = false; +bool quit = false; +mob_t* player; + +// Initialize jump physics +double jump_height = TILE_HEIGHT*3; +double jump_length = 0.25 * FRAMES_PER_SECOND; +double jump_velocity = -2 * jump_height / jump_length; +double jump_gravity = -1 * jump_velocity / jump_length; + +void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) +{ + if (action == GLFW_PRESS) + { + switch (key) + { + case GLFW_KEY_LEFT: holding_left = true; break; + case GLFW_KEY_RIGHT: holding_right = true; break; + case GLFW_KEY_UP: player->y_vel = jump_velocity; break; + case GLFW_KEY_ESCAPE: quit = true; break; + } + } else if (action == GLFW_RELEASE) + { + switch (key) + { + case GLFW_KEY_LEFT: holding_left = false; break; + case GLFW_KEY_RIGHT: holding_right = false; break; + } + } +} + +int main() +{ + GLFWwindow* window = initRenderer(); + glfwSwapInterval(1); + glfwSetKeyCallback(window, key_callback); + + Texture* buffer = createTexture(GAME_WIDTH, GAME_HEIGHT); + + // Initialize player data + player = new mob_t(); + player->x = 100; + player->y = 100; + player->x_vel = 0; + player->y_vel = 0; + player->x_accel = 0; + player->y_accel = jump_gravity; + player->w = 10; + player->h = 14; + + Map* map = new Map(); + + Texture* tiles = loadTextureFromBMP("../res/tiles.bmp"); + + double lastTime = glfwGetTime(); + int nbFrames = 0; + + while (!quit) + { + double currentTime = glfwGetTime(); + nbFrames++; + if ( currentTime - lastTime >= 1.0 ){ // If last prinf() was more than 1 sec ago + // printf and reset timer + printf("%f ms/frame\n", 1000.0/double(nbFrames)); + nbFrames = 0; + lastTime += 1.0; + } + + if (holding_left && player->x_vel >= 0) + { + player->x_vel = -2; + } else if (holding_right && player->x_vel <= 0) + { + player->x_vel = 2; + } else if (!holding_left && !holding_right) { + player->x_vel = 0; + } + + player->x_vel += player->x_accel; + if (player->x_vel < -16) player->x_vel = -16; + if (player->x_vel > 16) player->x_vel = 16; + int playerx_next = player->x + player->x_vel; + + player->y_vel += player->y_accel; + if (player->y_vel > 16) player->y_vel = 16; // Terminal velocity + if (player->y_vel < -16) player->y_vel = -16; + int playery_next = player->y + player->y_vel; + + map->check_collisions(player, playerx_next, playery_next); + + // Do rendering + map->render(buffer); + + //Rectangle src_rect(96, 0, 8, 8); + Rectangle dst_rect(player->x, player->y, player->w, player->h); + + //blitTexture(tiles, buffer, &src_rect, &dst_rect); + fillTexture(buffer, &dst_rect, 85, 85, 255); + //fillTexture(buffer, NULL, 85, 85, 0); + + renderScreen(buffer); + + //fuckThePolice(buffer); + + glfwPollEvents(); + + // Regulate frame rate + /*if ((clock() - frame_start) < CLOCKS_PER_SEC / FRAMES_PER_SECOND) + { + //delay(((CLOCKS_PER_SEC / FRAMES_PER_SECOND) - clock() + frame_start) * CLOCKS_PER_SEC / 1000); + }*/ + } + + delete map; + delete player; + + destroyRenderer(); + + return 0; +} diff --git a/src/map.cpp b/src/map.cpp new file mode 100644 index 0000000..10cd313 --- /dev/null +++ b/src/map.cpp @@ -0,0 +1,241 @@ +#include "map.h" + +struct platform_t { + int x; + int y; + int w; + int h; + bool enter_from_left; + bool enter_from_right; + bool enter_from_top; + bool enter_from_bottom; + int r; + int g; + int b; + int a; +}; + +Map::Map() +{ + add_collision(-6, 0, GAME_WIDTH, left, 1); + add_collision(GAME_WIDTH+6, 0, GAME_WIDTH, right, 1); + + FILE* f = fopen("../maps/bigmap.txt", "r"); + char* mapbuf = (char*) malloc(MAP_WIDTH*MAP_HEIGHT*sizeof(char)); + + for (int i=0; i::iterator it; + + switch (dir) + { + case up: + it = up_collisions.begin(); + for (; it!=up_collisions.end(); it++) + { + if (it->axis < axis) break; + } + + up_collisions.insert(it, {axis, lower, upper, type}); + + break; + case down: + it = down_collisions.begin(); + for (; it!=down_collisions.end(); it++) + { + if (it->axis > axis) break; + } + + down_collisions.insert(it, {axis, lower, upper, type}); + + break; + case left: + it = left_collisions.begin(); + for (; it!=left_collisions.end(); it++) + { + if (it->axis < axis) break; + } + + left_collisions.insert(it, {axis, lower, upper, type}); + + break; + case right: + it = right_collisions.begin(); + for (; it!=right_collisions.end(); it++) + { + if (it->axis > axis) break; + } + + right_collisions.insert(it, {axis, lower, upper, type}); + + break; + } +} + +void Map::check_collisions(mob_t* mob, int x_next, int y_next) +{ + if (x_next < mob->x) + { + for (list::iterator it=left_collisions.begin(); it!=left_collisions.end(); it++) + { + if (it->axis > mob->x) continue; + if (it->axis < x_next) break; + + if ((mob->y+mob->h > it->lower) && (mob->y < it->upper)) + { + // We have a collision! + if (it->type == 0) + { + x_next = it->axis; + mob->x_vel = 0; + } else if (it->type == 1) + { + x_next = GAME_WIDTH-mob->w/2; + } + + break; + } + } + } else if (x_next > mob->x) + { + for (list::iterator it=right_collisions.begin(); it!=right_collisions.end(); it++) + { + if (it->axis < mob->x+mob->w) continue; + if (it->axis > x_next+mob->w) break; + + if ((mob->y+mob->h > it->lower) && (mob->y < it->upper)) + { + // We have a collision! + if (it->type == 0) + { + x_next = it->axis - mob->w; + mob->x_vel = 0; + } else if (it->type == 1) + { + x_next = -mob->w/2; + } + + break; + } + } + } + + mob->x = x_next; + + if (y_next < mob->y) + { + for (list::iterator it=up_collisions.begin(); it!=up_collisions.end(); it++) + { + if (it->axis > mob->y) continue; + if (it->axis < y_next) break; + + if ((mob->x+mob->w > it->lower) && (mob->x < it->upper)) + { + // We have a collision! + if (it->type == 0) + { + y_next = it->axis; + mob->y_vel = 0; + } else if (it->type == 1) + { + y_next = GAME_HEIGHT-mob->h/2-1; + } + + break; + } + } + } else if (y_next > mob->y) + { + for (list::iterator it=down_collisions.begin(); it!=down_collisions.end(); it++) + { + if (it->axis < mob->y+mob->h) continue; + if (it->axis > y_next+mob->h) break; + + if ((mob->x+mob->w > it->lower) && (mob->x < it->upper)) + { + // We have a collision! + if (it->type == 0) + { + y_next = it->axis - mob->h; + mob->y_vel = 0; + } else if (it->type == 1) + { + y_next = 1 - mob->h/2; + } + + break; + } + } + } + + mob->y = y_next; +} + +void Map::render(Texture* buffer) +{ + blitTexture(bg, buffer, NULL, NULL); +} diff --git a/src/map.h b/src/map.h new file mode 100644 index 0000000..7986e0d --- /dev/null +++ b/src/map.h @@ -0,0 +1,42 @@ +#include +#include +#include "mob.h" +#include "renderer.h" + +using namespace::std; + +const int TILE_WIDTH = 8; +const int TILE_HEIGHT = 8; +const int GAME_WIDTH = 320; +const int GAME_HEIGHT = 200; +const int MAP_WIDTH = GAME_WIDTH/TILE_WIDTH; +const int MAP_HEIGHT = GAME_HEIGHT/TILE_HEIGHT; + +enum direction_t { + up, left, down, right +}; + +typedef struct { + int axis; + int lower; + int upper; + int type; +} collision_t; + +class Map { +public: + Map(); + ~Map(); + void render(Texture* buffer); + void check_collisions(mob_t* mob, int x_next, int y_next); + +private: + void add_collision(int axis, int lower, int upper, direction_t dir, int type); + + list left_collisions; + list right_collisions; + list up_collisions; + list down_collisions; + + Texture* bg; +}; \ No newline at end of file diff --git a/src/mob.h b/src/mob.h new file mode 100644 index 0000000..7a4b707 --- /dev/null +++ b/src/mob.h @@ -0,0 +1,10 @@ +typedef struct { + int x; + int y; + double x_vel; + double y_vel; + double x_accel; + double y_accel; + int w; + int h; +} mob_t; diff --git a/src/renderer.cpp b/src/renderer.cpp new file mode 100644 index 0000000..e74c6a4 --- /dev/null +++ b/src/renderer.cpp @@ -0,0 +1,582 @@ +#include "renderer.h" +#include +#include +#include +#include +#include "map.h" + +static bool rendererInitialized = false; + +static GLFWwindow* window; + +static GLuint FramebufferName; // The framebuffer +static GLuint ntscShader; // The NTSC shader +static GLuint finalShader; // The passthrough shader +static GLuint blitShader; // The blitting shader +static GLuint fillShader; // The fill shader + +// 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; + +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; +} + +GLuint loadBMP_custom(const char * imagepath){ + + printf("Reading image %s\n", imagepath); + + // Data read from the header of the BMP file + unsigned char header[54]; + unsigned int dataPos; + unsigned int imageSize; + unsigned int width, height; + // Actual RGB data + unsigned char * data; + + // Open the file + FILE * file = fopen(imagepath,"rb"); + if (!file) {printf("%s could not be opened. Are you in the right directory ? Don't forget to read the FAQ !\n", imagepath); getchar(); return 0;} + + // Read the header, i.e. the 54 first bytes + + // If less than 54 bytes are read, problem + if ( fread(header, 1, 54, file)!=54 ){ + printf("Not a correct BMP file\n"); + return 0; + } + // A BMP files always begins with "BM" + if ( header[0]!='B' || header[1]!='M' ){ + printf("Not a correct BMP file\n"); + return 0; + } + // Make sure this is a 24bpp file + if ( *(int*)&(header[0x1E])!=0 ) {printf("Not a correct BMP file\n"); return 0;} + if ( *(int*)&(header[0x1C])!=24 ) {printf("Not a correct BMP file\n"); return 0;} + + // Read the information about the image + dataPos = *(int*)&(header[0x0A]); + imageSize = *(int*)&(header[0x22]); + width = *(int*)&(header[0x12]); + height = *(int*)&(header[0x16]); + + // Some BMP files are misformatted, guess missing information + if (imageSize==0) imageSize=width*height*3; // 3 : one byte for each Red, Green and Blue component + if (dataPos==0) dataPos=54; // The BMP header is done that way + + // Create a buffer + data = new unsigned char [imageSize]; + + // Read the actual data from the file into the buffer + fread(data,1,imageSize,file); + + // Everything is in memory now, the file wan be closed + fclose (file); + + // Create one OpenGL texture + GLuint textureID; + glGenTextures(1, &textureID); + + // "Bind" the newly created texture : all future texture functions will modify this texture + glBindTexture(GL_TEXTURE_2D, textureID); + + // Give the image to OpenGL + glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, width, height, 0, GL_BGR, GL_UNSIGNED_BYTE, data); + + // OpenGL has now copied the data. Free our own version + delete [] data; + + // Poor filtering, or ... + //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + + // ... nice trilinear filtering. + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glGenerateMipmap(GL_TEXTURE_2D); + + // Return the ID of the texture we just created + return textureID; +} + +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); + } + + // Set up vertex array object + GLuint VertexArrayID; + glGenVertexArrays(1, &VertexArrayID); + glBindVertexArray(VertexArrayID); + + // Set up the framebuffer + glGenFramebuffers(1, &FramebufferName); + glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName); + GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0}; + glDrawBuffers(1, DrawBuffers); + + // 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; + + curBuf = 0; + + artifactsTex = loadBMP_custom("../res/artifacts.bmp"); + scanlinesTex = loadBMP_custom("../res/scanlines.bmp"); + + // 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"); + + rendererInitialized = true; + + return window; +} + +void destroyRenderer() +{ + if (!rendererInitialized) + { + fprintf(stderr, "Renderer not initialized\n"); + exit(-1); + } + + // Delete the shaders + glDeleteProgram(ntscShader); + glDeleteProgram(finalShader); + glDeleteProgram(blitShader); + glDeleteProgram(fillShader); + + // Delete the NTSC rendering buffers + glDeleteTextures(1, &renderedTex1); + glDeleteTextures(1, &renderedTex2); + glDeleteTextures(1, &artifactsTex); + glDeleteTextures(1, &scanlinesTex); + + // Delete the framebuffer + glDeleteFramebuffers(1, &FramebufferName); + + // 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_RGB, width, 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_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(); + tex->texID = loadBMP_custom(filename); + + glBindTexture(GL_TEXTURE_2D, tex->texID); + glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &(tex->width)); + glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &(tex->height)); + + return tex; +} + +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); + 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); + 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 renderScreen(Texture* tex) +{ + if (!rendererInitialized) + { + fprintf(stderr, "Renderer not initialized\n"); + exit(-1); + } + + // Set up framebuffer + glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName); + glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, renderedTexBufs[curBuf], 0); + + // Set up renderer + glViewport(0,0,GAME_WIDTH,GAME_HEIGHT); + glClear(GL_COLOR_BUFFER_BIT); + glUseProgram(ntscShader); + + 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); + + 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); + + glActiveTexture(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_2D, artifactsTex); + glUniform1i(glGetUniformLocation(ntscShader, "NTSCArtifactSampler"), 2); + + glUniform1f(glGetUniformLocation(ntscShader, "NTSCLerp"), curBuf * 1.0); + + 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, + }; + + GLuint quad_vertexbuffer; + 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); + + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); + glDrawArrays(GL_TRIANGLES, 0, 6); + glDisableVertexAttribArray(0); + + GLfloat g_norms_data[] = { + 0.0f, 0.0f, 1.0f, + 0.0f, 0.0f, 1.0f, + 0.0f, 0.0f, 1.0f, + 0.0f, 0.0f, 1.0f, + 0.0f, 0.0f, 1.0f, + 0.0f, 0.0f, 1.0f + }; + + GLuint g_norms; + glGenBuffers(1, &g_norms); + glBindBuffer(GL_ARRAY_BUFFER, g_norms); + glBufferData(GL_ARRAY_BUFFER, sizeof(g_norms_data), g_norms_data, GL_STATIC_DRAW); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glViewport(0,0,1024,768); + glClear(GL_COLOR_BUFFER_BIT); + glUseProgram(finalShader); + 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); + + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, scanlinesTex); + glUniform1i(glGetUniformLocation(finalShader, "scanlinestex"), 1); + + glEnableVertexAttribArray(0); + glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); + + glEnableVertexAttribArray(1); + glBindBuffer(GL_ARRAY_BUFFER, g_norms); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); + + glDrawArrays(GL_TRIANGLES, 0, 6); + glDisableVertexAttribArray(1); + glDisableVertexAttribArray(0); + + glfwSwapBuffers(window); + + glDeleteBuffers(1, &g_norms); + glDeleteBuffers(1, &quad_vertexbuffer); + + curBuf = (curBuf + 1) % 2; +} diff --git a/src/renderer.h b/src/renderer.h new file mode 100644 index 0000000..de5fc31 --- /dev/null +++ b/src/renderer.h @@ -0,0 +1,42 @@ +#include +#include +#include + +using namespace glm; + +#ifndef RENDERER_H +#define RENDERER_H + +struct Rectangle { + int x; + int y; + int w; + int h; + + Rectangle() {}; + + Rectangle(int m_x, int m_y, int m_w, int m_h) + { + x = m_x; + y = m_y; + w = m_w; + h = m_h; + } +}; + +struct Texture { + GLuint texID; + int width; + int height; +}; + +GLFWwindow* initRenderer(); +void destroyRenderer(); +Texture* createTexture(int width, int height); +void destroyTexture(Texture* tex); +Texture* loadTextureFromBMP(char* filename); +void fillTexture(Texture* tex, Rectangle* loc, int r, int g, int b); +void blitTexture(Texture* srctex, Texture* dsttex, Rectangle* srcrect, Rectangle* dstrect); +void renderScreen(Texture* tex); + +#endif -- cgit 1.4.1