summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main.cpp149
-rw-r--r--src/map.cpp241
-rw-r--r--src/map.h42
-rw-r--r--src/mob.h10
-rw-r--r--src/renderer.cpp582
-rw-r--r--src/renderer.h42
6 files changed, 1066 insertions, 0 deletions
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 @@
1#include <ctime>
2#include <list>
3#include "map.h"
4#include "renderer.h"
5
6using namespace::std;
7
8#if defined(__WIN32__) || defined(_WIN32) || defined(WIN32) || defined(__WINDOWS__) || defined(__TOS_WIN__)
9
10 #include <windows.h>
11
12 inline void delay( unsigned long ms )
13 {
14 Sleep( ms );
15 }
16
17#else /* presume POSIX */
18
19 #include <unistd.h>
20
21 inline void delay( unsigned long ms )
22 {
23 usleep( ms * 1000 );
24 }
25
26#endif
27
28const int FRAMES_PER_SECOND = 60;
29bool holding_left = false;
30bool holding_right = false;
31bool quit = false;
32mob_t* player;
33
34// Initialize jump physics
35double jump_height = TILE_HEIGHT*3;
36double jump_length = 0.25 * FRAMES_PER_SECOND;
37double jump_velocity = -2 * jump_height / jump_length;
38double jump_gravity = -1 * jump_velocity / jump_length;
39
40void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
41{
42 if (action == GLFW_PRESS)
43 {
44 switch (key)
45 {
46 case GLFW_KEY_LEFT: holding_left = true; break;
47 case GLFW_KEY_RIGHT: holding_right = true; break;
48 case GLFW_KEY_UP: player->y_vel = jump_velocity; break;
49 case GLFW_KEY_ESCAPE: quit = true; break;
50 }
51 } else if (action == GLFW_RELEASE)
52 {
53 switch (key)
54 {
55 case GLFW_KEY_LEFT: holding_left = false; break;
56 case GLFW_KEY_RIGHT: holding_right = false; break;
57 }
58 }
59}
60
61int main()
62{
63 GLFWwindow* window = initRenderer();
64 glfwSwapInterval(1);
65 glfwSetKeyCallback(window, key_callback);
66
67 Texture* buffer = createTexture(GAME_WIDTH, GAME_HEIGHT);
68
69 // Initialize player data
70 player = new mob_t();
71 player->x = 100;
72 player->y = 100;
73 player->x_vel = 0;
74 player->y_vel = 0;
75 player->x_accel = 0;
76 player->y_accel = jump_gravity;
77 player->w = 10;
78 player->h = 14;
79
80 Map* map = new Map();
81
82 Texture* tiles = loadTextureFromBMP("../res/tiles.bmp");
83
84 double lastTime = glfwGetTime();
85 int nbFrames = 0;
86
87 while (!quit)
88 {
89 double currentTime = glfwGetTime();
90 nbFrames++;
91 if ( currentTime - lastTime >= 1.0 ){ // If last prinf() was more than 1 sec ago
92 // printf and reset timer
93 printf("%f ms/frame\n", 1000.0/double(nbFrames));
94 nbFrames = 0;
95 lastTime += 1.0;
96 }
97
98 if (holding_left && player->x_vel >= 0)
99 {
100 player->x_vel = -2;
101 } else if (holding_right && player->x_vel <= 0)
102 {
103 player->x_vel = 2;
104 } else if (!holding_left && !holding_right) {
105 player->x_vel = 0;
106 }
107
108 player->x_vel += player->x_accel;
109 if (player->x_vel < -16) player->x_vel = -16;
110 if (player->x_vel > 16) player->x_vel = 16;
111 int playerx_next = player->x + player->x_vel;
112
113 player->y_vel += player->y_accel;
114 if (player->y_vel > 16) player->y_vel = 16; // Terminal velocity
115 if (player->y_vel < -16) player->y_vel = -16;
116 int playery_next = player->y + player->y_vel;
117
118 map->check_collisions(player, playerx_next, playery_next);
119
120 // Do rendering
121 map->render(buffer);
122
123 //Rectangle src_rect(96, 0, 8, 8);
124 Rectangle dst_rect(player->x, player->y, player->w, player->h);
125
126 //blitTexture(tiles, buffer, &src_rect, &dst_rect);
127 fillTexture(buffer, &dst_rect, 85, 85, 255);
128 //fillTexture(buffer, NULL, 85, 85, 0);
129
130 renderScreen(buffer);
131
132 //fuckThePolice(buffer);
133
134 glfwPollEvents();
135
136 // Regulate frame rate
137 /*if ((clock() - frame_start) < CLOCKS_PER_SEC / FRAMES_PER_SECOND)
138 {
139 //delay(((CLOCKS_PER_SEC / FRAMES_PER_SECOND) - clock() + frame_start) * CLOCKS_PER_SEC / 1000);
140 }*/
141 }
142
143 delete map;
144 delete player;
145
146 destroyRenderer();
147
148 return 0;
149}
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 @@
1#include "map.h"
2
3struct platform_t {
4 int x;
5 int y;
6 int w;
7 int h;
8 bool enter_from_left;
9 bool enter_from_right;
10 bool enter_from_top;
11 bool enter_from_bottom;
12 int r;
13 int g;
14 int b;
15 int a;
16};
17
18Map::Map()
19{
20 add_collision(-6, 0, GAME_WIDTH, left, 1);
21 add_collision(GAME_WIDTH+6, 0, GAME_WIDTH, right, 1);
22
23 FILE* f = fopen("../maps/bigmap.txt", "r");
24 char* mapbuf = (char*) malloc(MAP_WIDTH*MAP_HEIGHT*sizeof(char));
25
26 for (int i=0; i<MAP_HEIGHT; i++)
27 {
28 fread(mapbuf + i*MAP_WIDTH, sizeof(char), MAP_WIDTH, f);
29 fgetc(f);
30 }
31
32 fclose(f);
33
34 //Texture* tiles = loadTextureFromBMP("../res/tiles.bmp");
35 bg = createTexture(GAME_WIDTH, GAME_HEIGHT);
36 fillTexture(bg, NULL, 0, 0, 0);
37
38 for (int i=0; i<MAP_WIDTH*MAP_HEIGHT; i++)
39 {
40 int x = i % MAP_WIDTH;
41 int y = i / MAP_WIDTH;
42 Rectangle dst(x*TILE_WIDTH, y*TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT);
43 //Rectangle src;
44
45 switch (mapbuf[i])
46 {
47 case ' ': break;
48 case 'X': fillTexture(bg, &dst, 255, 85, 85); break;
49 case 'P': fillTexture(bg, &dst, 85, 255, 255); break;
50 }
51
52 //blitTexture(tiles, bg, &src, &dst);
53
54 if (mapbuf[i] == 'X')
55 {
56 if ((x != 0) && (mapbuf[i-1] != 'X'))
57 {
58 add_collision(x*TILE_WIDTH, y*TILE_HEIGHT, (y+1)*TILE_HEIGHT, right, 0);
59 }
60
61 if ((x != 15) && (mapbuf[i+1] != 'X'))
62 {
63 add_collision((x+1)*TILE_WIDTH, y*TILE_HEIGHT, (y+1)*TILE_HEIGHT, left, 0);
64 }
65
66 if ((y != 0) && (mapbuf[i-MAP_WIDTH] != 'X'))
67 {
68 add_collision(y*TILE_HEIGHT, x*TILE_WIDTH, (x+1)*TILE_WIDTH, down, 0);
69 }
70
71 if ((y != 15) && (mapbuf[i+MAP_WIDTH] != 'X'))
72 {
73 add_collision((y+1)*TILE_HEIGHT, x*TILE_WIDTH, (x+1)*TILE_WIDTH, up, 0);
74 }
75 } else if (mapbuf[i] == 'P')
76 {
77 add_collision(y*TILE_HEIGHT, x*TILE_WIDTH, (x+1)*TILE_WIDTH, down, 0);
78 }
79 }
80
81 //destroyTexture(tiles);
82}
83
84Map::~Map()
85{
86 destroyTexture(bg);
87}
88
89void Map::add_collision(int axis, int lower, int upper, direction_t dir, int type)
90{
91 //printf("added collision\n");
92 list<collision_t>::iterator it;
93
94 switch (dir)
95 {
96 case up:
97 it = up_collisions.begin();
98 for (; it!=up_collisions.end(); it++)
99 {
100 if (it->axis < axis) break;
101 }
102
103 up_collisions.insert(it, {axis, lower, upper, type});
104
105 break;
106 case down:
107 it = down_collisions.begin();
108 for (; it!=down_collisions.end(); it++)
109 {
110 if (it->axis > axis) break;
111 }
112
113 down_collisions.insert(it, {axis, lower, upper, type});
114
115 break;
116 case left:
117 it = left_collisions.begin();
118 for (; it!=left_collisions.end(); it++)
119 {
120 if (it->axis < axis) break;
121 }
122
123 left_collisions.insert(it, {axis, lower, upper, type});
124
125 break;
126 case right:
127 it = right_collisions.begin();
128 for (; it!=right_collisions.end(); it++)
129 {
130 if (it->axis > axis) break;
131 }
132
133 right_collisions.insert(it, {axis, lower, upper, type});
134
135 break;
136 }
137}
138
139void Map::check_collisions(mob_t* mob, int x_next, int y_next)
140{
141 if (x_next < mob->x)
142 {
143 for (list<collision_t>::iterator it=left_collisions.begin(); it!=left_collisions.end(); it++)
144 {
145 if (it->axis > mob->x) continue;
146 if (it->axis < x_next) break;
147
148 if ((mob->y+mob->h > it->lower) && (mob->y < it->upper))
149 {
150 // We have a collision!
151 if (it->type == 0)
152 {
153 x_next = it->axis;
154 mob->x_vel = 0;
155 } else if (it->type == 1)
156 {
157 x_next = GAME_WIDTH-mob->w/2;
158 }
159
160 break;
161 }
162 }
163 } else if (x_next > mob->x)
164 {
165 for (list<collision_t>::iterator it=right_collisions.begin(); it!=right_collisions.end(); it++)
166 {
167 if (it->axis < mob->x+mob->w) continue;
168 if (it->axis > x_next+mob->w) break;
169
170 if ((mob->y+mob->h > it->lower) && (mob->y < it->upper))
171 {
172 // We have a collision!
173 if (it->type == 0)
174 {
175 x_next = it->axis - mob->w;
176 mob->x_vel = 0;
177 } else if (it->type == 1)
178 {
179 x_next = -mob->w/2;
180 }
181
182 break;
183 }
184 }
185 }
186
187 mob->x = x_next;
188
189 if (y_next < mob->y)
190 {
191 for (list<collision_t>::iterator it=up_collisions.begin(); it!=up_collisions.end(); it++)
192 {
193 if (it->axis > mob->y) continue;
194 if (it->axis < y_next) break;
195
196 if ((mob->x+mob->w > it->lower) && (mob->x < it->upper))
197 {
198 // We have a collision!
199 if (it->type == 0)
200 {
201 y_next = it->axis;
202 mob->y_vel = 0;
203 } else if (it->type == 1)
204 {
205 y_next = GAME_HEIGHT-mob->h/2-1;
206 }
207
208 break;
209 }
210 }
211 } else if (y_next > mob->y)
212 {
213 for (list<collision_t>::iterator it=down_collisions.begin(); it!=down_collisions.end(); it++)
214 {
215 if (it->axis < mob->y+mob->h) continue;
216 if (it->axis > y_next+mob->h) break;
217
218 if ((mob->x+mob->w > it->lower) && (mob->x < it->upper))
219 {
220 // We have a collision!
221 if (it->type == 0)
222 {
223 y_next = it->axis - mob->h;
224 mob->y_vel = 0;
225 } else if (it->type == 1)
226 {
227 y_next = 1 - mob->h/2;
228 }
229
230 break;
231 }
232 }
233 }
234
235 mob->y = y_next;
236}
237
238void Map::render(Texture* buffer)
239{
240 blitTexture(bg, buffer, NULL, NULL);
241}
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 @@
1#include <list>
2#include <vector>
3#include "mob.h"
4#include "renderer.h"
5
6using namespace::std;
7
8const int TILE_WIDTH = 8;
9const int TILE_HEIGHT = 8;
10const int GAME_WIDTH = 320;
11const int GAME_HEIGHT = 200;
12const int MAP_WIDTH = GAME_WIDTH/TILE_WIDTH;
13const int MAP_HEIGHT = GAME_HEIGHT/TILE_HEIGHT;
14
15enum direction_t {
16 up, left, down, right
17};
18
19typedef struct {
20 int axis;
21 int lower;
22 int upper;
23 int type;
24} collision_t;
25
26class Map {
27public:
28 Map();
29 ~Map();
30 void render(Texture* buffer);
31 void check_collisions(mob_t* mob, int x_next, int y_next);
32
33private:
34 void add_collision(int axis, int lower, int upper, direction_t dir, int type);
35
36 list<collision_t> left_collisions;
37 list<collision_t> right_collisions;
38 list<collision_t> up_collisions;
39 list<collision_t> down_collisions;
40
41 Texture* bg;
42}; \ 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 @@
1typedef struct {
2 int x;
3 int y;
4 double x_vel;
5 double y_vel;
6 double x_accel;
7 double y_accel;
8 int w;
9 int h;
10} 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 @@
1#include "renderer.h"
2#include <string>
3#include <fstream>
4#include <vector>
5#include <cstdio>
6#include "map.h"
7
8static bool rendererInitialized = false;
9
10static GLFWwindow* window;
11
12static GLuint FramebufferName; // The framebuffer
13static GLuint ntscShader; // The NTSC shader
14static GLuint finalShader; // The passthrough shader
15static GLuint blitShader; // The blitting shader
16static GLuint fillShader; // The fill shader
17
18// The buffers for the NTSC rendering process
19static GLuint renderedTex1;
20static GLuint renderedTex2;
21static GLuint renderedTexBufs[2];
22static int curBuf;
23static GLuint artifactsTex;
24static GLuint scanlinesTex;
25
26GLuint LoadShaders(const char* vertex_file_path, const char* fragment_file_path)
27{
28 // Create the shaders
29 GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
30 GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
31
32 // Read the Vertex Shader code from the file
33 std::string VertexShaderCode;
34 std::ifstream VertexShaderStream(vertex_file_path, std::ios::in);
35 if(VertexShaderStream.is_open())
36 {
37 std::string Line = "";
38 while(getline(VertexShaderStream, Line))
39 VertexShaderCode += "\n" + Line;
40 VertexShaderStream.close();
41 }
42
43 // Read the Fragment Shader code from the file
44 std::string FragmentShaderCode;
45 std::ifstream FragmentShaderStream(fragment_file_path, std::ios::in);
46 if(FragmentShaderStream.is_open()){
47 std::string Line = "";
48 while(getline(FragmentShaderStream, Line))
49 FragmentShaderCode += "\n" + Line;
50 FragmentShaderStream.close();
51 }
52
53 GLint Result = GL_FALSE;
54 int InfoLogLength;
55
56 // Compile Vertex Shader
57 printf("Compiling shader : %s\n", vertex_file_path);
58 char const * VertexSourcePointer = VertexShaderCode.c_str();
59 glShaderSource(VertexShaderID, 1, &VertexSourcePointer , NULL);
60 glCompileShader(VertexShaderID);
61
62 // Check Vertex Shader
63 glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result);
64 glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
65 std::vector<char> VertexShaderErrorMessage(InfoLogLength);
66 glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]);
67 fprintf(stdout, "%s\n", &VertexShaderErrorMessage[0]);
68
69 // Compile Fragment Shader
70 printf("Compiling shader : %s\n", fragment_file_path);
71 char const * FragmentSourcePointer = FragmentShaderCode.c_str();
72 glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer , NULL);
73 glCompileShader(FragmentShaderID);
74
75 // Check Fragment Shader
76 glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result);
77 glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
78 std::vector<char> FragmentShaderErrorMessage(InfoLogLength);
79 glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]);
80 fprintf(stdout, "%s\n", &FragmentShaderErrorMessage[0]);
81
82 // Link the program
83 fprintf(stdout, "Linking program\n");
84 GLuint ProgramID = glCreateProgram();
85 glAttachShader(ProgramID, VertexShaderID);
86 glAttachShader(ProgramID, FragmentShaderID);
87 glLinkProgram(ProgramID);
88
89 // Check the program
90 glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
91 glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
92 std::vector<char> ProgramErrorMessage( glm::max(InfoLogLength, int(1)) );
93 glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]);
94 fprintf(stdout, "%s\n", &ProgramErrorMessage[0]);
95
96 glDeleteShader(VertexShaderID);
97 glDeleteShader(FragmentShaderID);
98
99 return ProgramID;
100}
101
102GLuint loadBMP_custom(const char * imagepath){
103
104 printf("Reading image %s\n", imagepath);
105
106 // Data read from the header of the BMP file
107 unsigned char header[54];
108 unsigned int dataPos;
109 unsigned int imageSize;
110 unsigned int width, height;
111 // Actual RGB data
112 unsigned char * data;
113
114 // Open the file
115 FILE * file = fopen(imagepath,"rb");
116 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;}
117
118 // Read the header, i.e. the 54 first bytes
119
120 // If less than 54 bytes are read, problem
121 if ( fread(header, 1, 54, file)!=54 ){
122 printf("Not a correct BMP file\n");
123 return 0;
124 }
125 // A BMP files always begins with "BM"
126 if ( header[0]!='B' || header[1]!='M' ){
127 printf("Not a correct BMP file\n");
128 return 0;
129 }
130 // Make sure this is a 24bpp file
131 if ( *(int*)&(header[0x1E])!=0 ) {printf("Not a correct BMP file\n"); return 0;}
132 if ( *(int*)&(header[0x1C])!=24 ) {printf("Not a correct BMP file\n"); return 0;}
133
134 // Read the information about the image
135 dataPos = *(int*)&(header[0x0A]);
136 imageSize = *(int*)&(header[0x22]);
137 width = *(int*)&(header[0x12]);
138 height = *(int*)&(header[0x16]);
139
140 // Some BMP files are misformatted, guess missing information
141 if (imageSize==0) imageSize=width*height*3; // 3 : one byte for each Red, Green and Blue component
142 if (dataPos==0) dataPos=54; // The BMP header is done that way
143
144 // Create a buffer
145 data = new unsigned char [imageSize];
146
147 // Read the actual data from the file into the buffer
148 fread(data,1,imageSize,file);
149
150 // Everything is in memory now, the file wan be closed
151 fclose (file);
152
153 // Create one OpenGL texture
154 GLuint textureID;
155 glGenTextures(1, &textureID);
156
157 // "Bind" the newly created texture : all future texture functions will modify this texture
158 glBindTexture(GL_TEXTURE_2D, textureID);
159
160 // Give the image to OpenGL
161 glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, width, height, 0, GL_BGR, GL_UNSIGNED_BYTE, data);
162
163 // OpenGL has now copied the data. Free our own version
164 delete [] data;
165
166 // Poor filtering, or ...
167 //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
168 //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
169
170 // ... nice trilinear filtering.
171 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
172 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
173 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
174 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
175 glGenerateMipmap(GL_TEXTURE_2D);
176
177 // Return the ID of the texture we just created
178 return textureID;
179}
180
181GLFWwindow* initRenderer()
182{
183 if (rendererInitialized)
184 {
185 fprintf(stderr, "Renderer already initialized\n");
186 exit(-1);
187 }
188
189 // Initialize GLFW
190 if (!glfwInit())
191 {
192 fprintf(stderr, "Failed to initialize GLFW\n");
193 exit(-1);
194 }
195
196 glfwWindowHint(GLFW_SAMPLES, 4); // 4x antialiasing
197 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // We want version 3.3
198 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
199 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Mac requires this
200 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
201
202 // Create a window
203 window = glfwCreateWindow(1024, 768, "Aromatherapy", NULL, NULL);
204 if (window == NULL)
205 {
206 fprintf(stderr, "Failed to open GLFW window\n");
207 glfwTerminate();
208 exit(-1);
209 }
210
211 glfwMakeContextCurrent(window);
212 glewExperimental = true; // Needed in core profile
213 if (glewInit() != GLEW_OK)
214 {
215 fprintf(stderr, "Failed to initialize GLEW\n");
216 exit(-1);
217 }
218
219 // Set up vertex array object
220 GLuint VertexArrayID;
221 glGenVertexArrays(1, &VertexArrayID);
222 glBindVertexArray(VertexArrayID);
223
224 // Set up the framebuffer
225 glGenFramebuffers(1, &FramebufferName);
226 glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName);
227 GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0};
228 glDrawBuffers(1, DrawBuffers);
229
230 // Set up the NTSC rendering buffers
231 glGenTextures(1, &renderedTex1);
232 glBindTexture(GL_TEXTURE_2D, renderedTex1);
233 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, GAME_WIDTH, GAME_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
234 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
235 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
236 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
237 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
238 renderedTexBufs[0] = renderedTex1;
239
240 glGenTextures(1, &renderedTex2);
241 glBindTexture(GL_TEXTURE_2D, renderedTex2);
242 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, GAME_WIDTH, GAME_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
243 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
244 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
245 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
246 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
247 renderedTexBufs[1] = renderedTex2;
248
249 curBuf = 0;
250
251 artifactsTex = loadBMP_custom("../res/artifacts.bmp");
252 scanlinesTex = loadBMP_custom("../res/scanlines.bmp");
253
254 // Load the shaders
255 ntscShader = LoadShaders("../shaders/ntsc.vertex", "../shaders/ntsc.fragment");
256 finalShader = LoadShaders("../shaders/final.vertex", "../shaders/final.fragment");
257 blitShader = LoadShaders("../shaders/blit.vertex", "../shaders/blit.fragment");
258 fillShader = LoadShaders("../shaders/fill.vertex", "../shaders/fill.fragment");
259
260 rendererInitialized = true;
261
262 return window;
263}
264
265void destroyRenderer()
266{
267 if (!rendererInitialized)
268 {
269 fprintf(stderr, "Renderer not initialized\n");
270 exit(-1);
271 }
272
273 // Delete the shaders
274 glDeleteProgram(ntscShader);
275 glDeleteProgram(finalShader);
276 glDeleteProgram(blitShader);
277 glDeleteProgram(fillShader);
278
279 // Delete the NTSC rendering buffers
280 glDeleteTextures(1, &renderedTex1);
281 glDeleteTextures(1, &renderedTex2);
282 glDeleteTextures(1, &artifactsTex);
283 glDeleteTextures(1, &scanlinesTex);
284
285 // Delete the framebuffer
286 glDeleteFramebuffers(1, &FramebufferName);
287
288 // Kill the window
289 glfwTerminate();
290
291 rendererInitialized = false;
292}
293
294Texture* createTexture(int width, int height)
295{
296 if (!rendererInitialized)
297 {
298 fprintf(stderr, "Renderer not initialized\n");
299 exit(-1);
300 }
301
302 Texture* tex = new Texture();
303 tex->width = width;
304 tex->height = height;
305
306 glGenTextures(1, &(tex->texID));
307 glBindTexture(GL_TEXTURE_2D, tex->texID);
308 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
309 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
310 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
311 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
312 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
313
314 return tex;
315}
316
317void destroyTexture(Texture* tex)
318{
319 if (!rendererInitialized)
320 {
321 fprintf(stderr, "Renderer not initialized\n");
322 exit(-1);
323 }
324
325 glDeleteTextures(1, &(tex->texID));
326
327 delete tex;
328}
329
330Texture* loadTextureFromBMP(char* filename)
331{
332 if (!rendererInitialized)
333 {
334 fprintf(stderr, "Renderer not initialized\n");
335 exit(-1);
336 }
337
338 Texture* tex = new Texture();
339 tex->texID = loadBMP_custom(filename);
340
341 glBindTexture(GL_TEXTURE_2D, tex->texID);
342 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &(tex->width));
343 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &(tex->height));
344
345 return tex;
346}
347
348void fillTexture(Texture* tex, Rectangle* dstrect, int r, int g, int b)
349{
350 if (!rendererInitialized)
351 {
352 fprintf(stderr, "Renderer not initialized\n");
353 exit(-1);
354 }
355
356 // Target the framebuffer
357 glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName);
358 glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex->texID, 0);
359
360 // Set up the vertex attributes
361 GLfloat minx = (dstrect == NULL) ? 0.0f : dstrect->x;
362 GLfloat miny = (dstrect == NULL) ? 0.0f : dstrect->y;
363 GLfloat maxx = (dstrect == NULL) ? tex->width : dstrect->x + dstrect->w;
364 GLfloat maxy = (dstrect == NULL) ? tex->height : dstrect->y + dstrect->h;
365
366 minx = minx / tex->width * 2.0 - 1.0;
367 miny = -(miny / tex->height * 2.0 - 1.0);
368 maxx = maxx / tex->width * 2.0 - 1.0;
369 maxy = -(maxy / tex->height * 2.0 - 1.0);
370
371 GLfloat vertexbuffer_data[] = {
372 minx, miny,
373 maxx, miny,
374 maxx, maxy,
375 minx, miny,
376 minx, maxy,
377 maxx, maxy
378 };
379 GLuint vertexbuffer;
380 glGenBuffers(1, &vertexbuffer);
381 glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
382 glBufferData(GL_ARRAY_BUFFER, sizeof(vertexbuffer_data), vertexbuffer_data, GL_STATIC_DRAW);
383 glEnableVertexAttribArray(0);
384 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
385
386 glViewport(0, 0, tex->width, tex->height);
387 glUseProgram(fillShader);
388 glUniform3f(glGetUniformLocation(fillShader, "vecColor"), r / 255.0, g / 255.0, b / 255.0);
389
390 glDrawArrays(GL_TRIANGLES, 0, 6);
391
392 glDisableVertexAttribArray(0);
393 glDeleteBuffers(1, &vertexbuffer);
394}
395
396void blitTexture(Texture* srctex, Texture* dsttex, Rectangle* srcrect, Rectangle* dstrect)
397{
398 if (!rendererInitialized)
399 {
400 fprintf(stderr, "Renderer not initialized\n");
401 exit(-1);
402 }
403
404 // Target the framebuffer
405 glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName);
406 glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, dsttex->texID, 0);
407
408 // Set up the vertex attributes
409 GLfloat minx = (dstrect == NULL) ? 0.0f : dstrect->x;
410 GLfloat miny = (dstrect == NULL) ? 0.0f : dstrect->y;
411 GLfloat maxx = (dstrect == NULL) ? dsttex->width : dstrect->x + dstrect->w;
412 GLfloat maxy = (dstrect == NULL) ? dsttex->height : dstrect->y + dstrect->h;
413
414 minx = minx / dsttex->width * 2.0 - 1.0;
415 miny = -(miny / dsttex->height * 2.0 - 1.0);
416 maxx = maxx / dsttex->width * 2.0 - 1.0;
417 maxy = -(maxy / dsttex->height * 2.0 - 1.0);
418
419 GLfloat vertexbuffer_data[] = {
420 minx, miny,
421 maxx, miny,
422 minx, maxy,
423 maxx, maxy
424 };
425 GLuint vertexbuffer;
426 glGenBuffers(1, &vertexbuffer);
427 glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
428 glBufferData(GL_ARRAY_BUFFER, sizeof(vertexbuffer_data), vertexbuffer_data, GL_STATIC_DRAW);
429 glEnableVertexAttribArray(0);
430 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
431
432 GLfloat minu = (srcrect == NULL) ? 0.0f : srcrect->x;
433 GLfloat minv = (srcrect == NULL) ? 0.0f : srcrect->y;
434 GLfloat maxu = (srcrect == NULL) ? srctex->width : srcrect->x + srcrect->w;
435 GLfloat maxv = (srcrect == NULL) ? srctex->height : srcrect->y + srcrect->h;
436
437 minu = minu / srctex->width;
438 minv = 1 - (minv / srctex->height);
439 maxu = maxu / srctex->width;
440 maxv = 1 - (maxv / srctex->height);
441
442 GLfloat texcoordbuffer_data[] = {
443 minu, minv,
444 maxu, minv,
445 minu, maxv,
446 maxu, maxv
447 };
448 GLuint texcoordbuffer;
449 glGenBuffers(1, &texcoordbuffer);
450 glBindBuffer(GL_ARRAY_BUFFER, texcoordbuffer);
451 glBufferData(GL_ARRAY_BUFFER, sizeof(texcoordbuffer_data), texcoordbuffer_data, GL_STATIC_DRAW);
452 glEnableVertexAttribArray(1);
453 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
454
455 // Set up the shader
456 glUseProgram(blitShader);
457 glViewport(0, 0, dsttex->width, dsttex->height);
458
459 glActiveTexture(GL_TEXTURE0);
460 glBindTexture(GL_TEXTURE_2D, srctex->texID);
461 glUniform1i(glGetUniformLocation(blitShader, "srctex"), 0);
462
463 // Blit!
464 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
465
466 // Unload everything
467 glDisableVertexAttribArray(1);
468 glDisableVertexAttribArray(0);
469 glDeleteBuffers(1, &texcoordbuffer);
470 glDeleteBuffers(1, &vertexbuffer);
471}
472
473void renderScreen(Texture* tex)
474{
475 if (!rendererInitialized)
476 {
477 fprintf(stderr, "Renderer not initialized\n");
478 exit(-1);
479 }
480
481 // Set up framebuffer
482 glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName);
483 glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, renderedTexBufs[curBuf], 0);
484
485 // Set up renderer
486 glViewport(0,0,GAME_WIDTH,GAME_HEIGHT);
487 glClear(GL_COLOR_BUFFER_BIT);
488 glUseProgram(ntscShader);
489
490 glActiveTexture(GL_TEXTURE0);
491 glBindTexture(GL_TEXTURE_2D, tex->texID);
492 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
493 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
494 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
495 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
496 glUniform1i(glGetUniformLocation(ntscShader, "curFrameSampler"), 0);
497
498 glActiveTexture(GL_TEXTURE1);
499 glBindTexture(GL_TEXTURE_2D, renderedTexBufs[(curBuf + 1) % 2]);
500 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
501 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
502 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
503 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
504 glUniform1i(glGetUniformLocation(ntscShader, "prevFrameSampler"), 1);
505
506 glActiveTexture(GL_TEXTURE2);
507 glBindTexture(GL_TEXTURE_2D, artifactsTex);
508 glUniform1i(glGetUniformLocation(ntscShader, "NTSCArtifactSampler"), 2);
509
510 glUniform1f(glGetUniformLocation(ntscShader, "NTSCLerp"), curBuf * 1.0);
511
512 GLfloat g_quad_vertex_buffer_data[] = {
513 -1.0f, -1.0f, 0.0f,
514 1.0f, -1.0f, 0.0f,
515 -1.0f, 1.0f, 0.0f,
516 -1.0f, 1.0f, 0.0f,
517 1.0f, -1.0f, 0.0f,
518 1.0f, 1.0f, 0.0f,
519 };
520
521 GLuint quad_vertexbuffer;
522 glGenBuffers(1, &quad_vertexbuffer);
523 glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer);
524 glBufferData(GL_ARRAY_BUFFER, sizeof(g_quad_vertex_buffer_data), g_quad_vertex_buffer_data, GL_STATIC_DRAW);
525
526 glEnableVertexAttribArray(0);
527 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
528 glDrawArrays(GL_TRIANGLES, 0, 6);
529 glDisableVertexAttribArray(0);
530
531 GLfloat g_norms_data[] = {
532 0.0f, 0.0f, 1.0f,
533 0.0f, 0.0f, 1.0f,
534 0.0f, 0.0f, 1.0f,
535 0.0f, 0.0f, 1.0f,
536 0.0f, 0.0f, 1.0f,
537 0.0f, 0.0f, 1.0f
538 };
539
540 GLuint g_norms;
541 glGenBuffers(1, &g_norms);
542 glBindBuffer(GL_ARRAY_BUFFER, g_norms);
543 glBufferData(GL_ARRAY_BUFFER, sizeof(g_norms_data), g_norms_data, GL_STATIC_DRAW);
544
545 glBindFramebuffer(GL_FRAMEBUFFER, 0);
546 glViewport(0,0,1024,768);
547 glClear(GL_COLOR_BUFFER_BIT);
548 glUseProgram(finalShader);
549 glActiveTexture(GL_TEXTURE0);
550 glBindTexture(GL_TEXTURE_2D, renderedTexBufs[curBuf]);
551 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
552 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
553 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
554 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
555 float border_color[] = {0.0f, 0.0f, 0.0f, 1.0f};
556 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color);
557 glGenerateMipmap(GL_TEXTURE_2D);
558 glUniform1i(glGetUniformLocation(finalShader, "rendertex"), 0);
559
560 glActiveTexture(GL_TEXTURE1);
561 glBindTexture(GL_TEXTURE_2D, scanlinesTex);
562 glUniform1i(glGetUniformLocation(finalShader, "scanlinestex"), 1);
563
564 glEnableVertexAttribArray(0);
565 glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer);
566 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
567
568 glEnableVertexAttribArray(1);
569 glBindBuffer(GL_ARRAY_BUFFER, g_norms);
570 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
571
572 glDrawArrays(GL_TRIANGLES, 0, 6);
573 glDisableVertexAttribArray(1);
574 glDisableVertexAttribArray(0);
575
576 glfwSwapBuffers(window);
577
578 glDeleteBuffers(1, &g_norms);
579 glDeleteBuffers(1, &quad_vertexbuffer);
580
581 curBuf = (curBuf + 1) % 2;
582}
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 @@
1#include <GL/glew.h>
2#include <GLFW/glfw3.h>
3#include <glm/glm.hpp>
4
5using namespace glm;
6
7#ifndef RENDERER_H
8#define RENDERER_H
9
10struct Rectangle {
11 int x;
12 int y;
13 int w;
14 int h;
15
16 Rectangle() {};
17
18 Rectangle(int m_x, int m_y, int m_w, int m_h)
19 {
20 x = m_x;
21 y = m_y;
22 w = m_w;
23 h = m_h;
24 }
25};
26
27struct Texture {
28 GLuint texID;
29 int width;
30 int height;
31};
32
33GLFWwindow* initRenderer();
34void destroyRenderer();
35Texture* createTexture(int width, int height);
36void destroyTexture(Texture* tex);
37Texture* loadTextureFromBMP(char* filename);
38void fillTexture(Texture* tex, Rectangle* loc, int r, int g, int b);
39void blitTexture(Texture* srctex, Texture* dsttex, Rectangle* srcrect, Rectangle* dstrect);
40void renderScreen(Texture* tex);
41
42#endif