summary refs log tree commit diff stats
path: root/src/renderer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/renderer.cpp')
-rw-r--r--src/renderer.cpp861
1 files changed, 0 insertions, 861 deletions
diff --git a/src/renderer.cpp b/src/renderer.cpp deleted file mode 100644 index ffe9d47..0000000 --- a/src/renderer.cpp +++ /dev/null
@@ -1,861 +0,0 @@
1#include "renderer.h"
2#include <string>
3#include <fstream>
4#include <vector>
5#include <cstdio>
6#include <cstring>
7#include <cstdlib>
8#include <glm/glm.hpp>
9#include <glm/gtc/matrix_transform.hpp>
10#include "consts.h"
11
12// include stb_image
13#define STB_IMAGE_IMPLEMENTATION
14#define STBI_ONLY_PNG
15#define STBI_ONLY_BMP
16#include "stb_image.h"
17
18static bool rendererInitialized = false;
19
20static GLFWwindow* window;
21
22static GLuint generic_framebuffer; // The framebuffer
23static GLuint bloom_framebuffer;
24static GLuint bloom_depthbuffer;
25static int buffer_width = 1024;
26static int buffer_height = 768;
27
28static GLuint ntscShader; // The NTSC shader
29static GLuint finalShader; // The passthrough shader
30static GLuint blitShader; // The blitting shader
31static GLuint fillShader; // The fill shader
32static GLuint bloom1Shader;
33static GLuint bloom2Shader;
34
35// The buffers for the NTSC rendering process
36static GLuint renderedTex1;
37static GLuint renderedTex2;
38static GLuint renderedTexBufs[2];
39static int curBuf;
40static GLuint artifactsTex;
41static GLuint scanlinesTex;
42static GLuint preBloomTex;
43static GLuint bloomPassTex1;
44static GLuint bloomPassTex2;
45
46// The VAO
47static GLuint VertexArrayID;
48
49// A plane that fills the renderbuffer
50static GLuint quad_vertexbuffer;
51
52// Buffers for the mesh
53static GLuint mesh_vertexbuffer;
54static GLuint mesh_uvbuffer;
55static GLuint mesh_normalbuffer;
56static int mesh_numvertices;
57
58GLuint LoadShaders(const char* vertex_file_path, const char* fragment_file_path)
59{
60 // Create the shaders
61 GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
62 GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
63
64 // Read the Vertex Shader code from the file
65 std::string VertexShaderCode;
66 std::ifstream VertexShaderStream(vertex_file_path, std::ios::in);
67 if(VertexShaderStream.is_open())
68 {
69 std::string Line = "";
70 while(getline(VertexShaderStream, Line))
71 VertexShaderCode += "\n" + Line;
72 VertexShaderStream.close();
73 }
74
75 // Read the Fragment Shader code from the file
76 std::string FragmentShaderCode;
77 std::ifstream FragmentShaderStream(fragment_file_path, std::ios::in);
78 if(FragmentShaderStream.is_open()){
79 std::string Line = "";
80 while(getline(FragmentShaderStream, Line))
81 FragmentShaderCode += "\n" + Line;
82 FragmentShaderStream.close();
83 }
84
85 GLint Result = GL_FALSE;
86 int InfoLogLength;
87
88 // Compile Vertex Shader
89 printf("Compiling shader : %s\n", vertex_file_path);
90 char const * VertexSourcePointer = VertexShaderCode.c_str();
91 glShaderSource(VertexShaderID, 1, &VertexSourcePointer , nullptr);
92 glCompileShader(VertexShaderID);
93
94 // Check Vertex Shader
95 glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result);
96 glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
97 std::vector<char> VertexShaderErrorMessage(InfoLogLength);
98 glGetShaderInfoLog(VertexShaderID, InfoLogLength, nullptr, &VertexShaderErrorMessage[0]);
99 fprintf(stdout, "%s\n", &VertexShaderErrorMessage[0]);
100
101 // Compile Fragment Shader
102 printf("Compiling shader : %s\n", fragment_file_path);
103 char const * FragmentSourcePointer = FragmentShaderCode.c_str();
104 glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer , nullptr);
105 glCompileShader(FragmentShaderID);
106
107 // Check Fragment Shader
108 glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result);
109 glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
110 std::vector<char> FragmentShaderErrorMessage(InfoLogLength);
111 glGetShaderInfoLog(FragmentShaderID, InfoLogLength, nullptr, &FragmentShaderErrorMessage[0]);
112 fprintf(stdout, "%s\n", &FragmentShaderErrorMessage[0]);
113
114 // Link the program
115 fprintf(stdout, "Linking program\n");
116 GLuint ProgramID = glCreateProgram();
117 glAttachShader(ProgramID, VertexShaderID);
118 glAttachShader(ProgramID, FragmentShaderID);
119 glLinkProgram(ProgramID);
120
121 // Check the program
122 glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
123 glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
124 std::vector<char> ProgramErrorMessage( glm::max(InfoLogLength, int(1)) );
125 glGetProgramInfoLog(ProgramID, InfoLogLength, nullptr, &ProgramErrorMessage[0]);
126 fprintf(stdout, "%s\n", &ProgramErrorMessage[0]);
127
128 glDeleteShader(VertexShaderID);
129 glDeleteShader(FragmentShaderID);
130
131 return ProgramID;
132}
133
134void flipImageData(unsigned char* data, int width, int height, int comps)
135{
136 unsigned char* data_copy = (unsigned char*) malloc(width*height*comps*sizeof(unsigned char));
137 memcpy(data_copy, data, width*height*comps);
138
139 int row_size = width * comps;
140
141 for (int i=0;i<height;i++)
142 {
143 memcpy(data + (row_size*i), data_copy + (row_size*(height-i-1)), row_size);
144 }
145
146 free(data_copy);
147}
148
149void loadMesh(const char* filename, std::vector<glm::vec3>& out_vertices, std::vector<glm::vec2>& out_uvs, std::vector<glm::vec3>& out_normals)
150{
151 FILE* file = fopen(filename, "r");
152 if (file == nullptr)
153 {
154 fprintf(stderr, "Could not open mesh file %s\n", filename);
155 exit(1);
156 }
157
158 std::vector<glm::vec3> temp_vertices;
159 std::vector<glm::vec2> temp_uvs;
160 std::vector<glm::vec3> temp_normals;
161
162 for (;;)
163 {
164 char lineHeader[256];
165 int res = fscanf(file, "%s", lineHeader);
166 if (res == EOF)
167 {
168 break;
169 }
170
171 if (!strncmp(lineHeader, "v", 2))
172 {
173 glm::vec3 vertex;
174 fscanf(file, "%f %f %f\n", &vertex.x,&vertex.y,&vertex.z);
175 temp_vertices.push_back(vertex);
176 } else if (!strncmp(lineHeader, "vt", 3))
177 {
178 glm::vec2 uv;
179 fscanf(file, "%f %f\n", &uv.x, &uv.y);
180 temp_uvs.push_back(uv);
181 } else if (!strncmp(lineHeader, "vn", 3))
182 {
183 glm::vec3 normal;
184 fscanf(file, "%f %f %f\n", &normal.x, &normal.y, &normal.z);
185 temp_normals.push_back(normal);
186 } else if (!strncmp(lineHeader, "f", 2))
187 {
188 int vertexIDs[3], uvIDs[3], normalIDs[3];
189 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]);
190
191 for (int i=0; i<3; i++)
192 {
193 out_vertices.push_back(temp_vertices[vertexIDs[i] - 1]);
194 out_uvs.push_back(temp_uvs[uvIDs[i] - 1]);
195 out_normals.push_back(temp_normals[normalIDs[i] - 1]);
196 }
197 }
198 }
199}
200
201void setFramebufferSize(GLFWwindow* w, int width, int height)
202{
203 buffer_width = width;
204 buffer_height = height;
205
206 glDeleteFramebuffers(1, &bloom_framebuffer);
207 glDeleteRenderbuffers(1, &bloom_depthbuffer);
208
209 glGenFramebuffers(1, &bloom_framebuffer);
210 glBindFramebuffer(GL_FRAMEBUFFER, bloom_framebuffer);
211 GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT1};
212 glDrawBuffers(1, DrawBuffers);
213
214 glGenRenderbuffers(1, &bloom_depthbuffer);
215 glBindRenderbuffer(GL_RENDERBUFFER, bloom_depthbuffer);
216 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
217 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, bloom_depthbuffer);
218
219 glDeleteTextures(1, &preBloomTex);
220 glDeleteTextures(1, &bloomPassTex1);
221 glDeleteTextures(1, &bloomPassTex2);
222
223 glGenTextures(1, &preBloomTex);
224 glBindTexture(GL_TEXTURE_2D, preBloomTex);
225 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
226 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
227 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
228 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
229 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
230
231 glGenTextures(1, &bloomPassTex1);
232 glBindTexture(GL_TEXTURE_2D, bloomPassTex1);
233 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width/4, height/4, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
234 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
235 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
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
239 glGenTextures(1, &bloomPassTex2);
240 glBindTexture(GL_TEXTURE_2D, bloomPassTex2);
241 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width/4, height/4, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
242 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
243 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
244 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
245 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
246}
247
248GLFWwindow* initRenderer()
249{
250 if (rendererInitialized)
251 {
252 fprintf(stderr, "Renderer already initialized\n");
253 exit(-1);
254 }
255
256 // Initialize GLFW
257 if (!glfwInit())
258 {
259 fprintf(stderr, "Failed to initialize GLFW\n");
260 exit(-1);
261 }
262
263 glfwWindowHint(GLFW_SAMPLES, 4); // 4x antialiasing
264 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // We want version 3.3
265 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
266 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Mac requires this
267 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
268
269 // Create a window
270 window = glfwCreateWindow(1024, 768, "Aromatherapy", nullptr, nullptr);
271 if (window == nullptr)
272 {
273 fprintf(stderr, "Failed to open GLFW window\n");
274 glfwTerminate();
275 exit(-1);
276 }
277
278 glfwMakeContextCurrent(window);
279 glewExperimental = true; // Needed in core profile
280 if (glewInit() != GLEW_OK)
281 {
282 fprintf(stderr, "Failed to initialize GLEW\n");
283 exit(-1);
284 }
285
286 glfwSetFramebufferSizeCallback(window, &setFramebufferSize);
287
288 // Set up vertex array object
289 glGenVertexArrays(1, &VertexArrayID);
290 glBindVertexArray(VertexArrayID);
291
292 // Enable depth testing
293 glEnable(GL_DEPTH_TEST);
294 glDepthFunc(GL_LESS);
295
296 // Enable blending
297 glEnable(GL_BLEND);
298 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
299
300 // Set up the framebuffer
301 glGenFramebuffers(1, &generic_framebuffer);
302 glBindFramebuffer(GL_FRAMEBUFFER, generic_framebuffer);
303 GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0};
304 glDrawBuffers(1, DrawBuffers);
305
306 glGenFramebuffers(1, &bloom_framebuffer);
307 glBindFramebuffer(GL_FRAMEBUFFER, bloom_framebuffer);
308 GLenum DrawBuffers2[1] = {GL_COLOR_ATTACHMENT1};
309 glDrawBuffers(1, DrawBuffers2);
310
311 glGenRenderbuffers(1, &bloom_depthbuffer);
312 glBindRenderbuffer(GL_RENDERBUFFER, bloom_depthbuffer);
313 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, 1024, 768);
314 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, bloom_depthbuffer);
315
316 // Set up the NTSC rendering buffers
317 glGenTextures(1, &renderedTex1);
318 glBindTexture(GL_TEXTURE_2D, renderedTex1);
319 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, GAME_WIDTH, GAME_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
320 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
321 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
322 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
323 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
324 renderedTexBufs[0] = renderedTex1;
325
326 glGenTextures(1, &renderedTex2);
327 glBindTexture(GL_TEXTURE_2D, renderedTex2);
328 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, GAME_WIDTH, GAME_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
329 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
330 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
331 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
332 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
333 renderedTexBufs[1] = renderedTex2;
334
335 // Set up bloom rendering buffers
336 glGenTextures(1, &preBloomTex);
337 glBindTexture(GL_TEXTURE_2D, preBloomTex);
338 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1024, 768, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
339 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
340 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
341 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
342 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
343
344 glGenTextures(1, &bloomPassTex1);
345 glBindTexture(GL_TEXTURE_2D, bloomPassTex1);
346 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1024/4, 768/4, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
347 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
348 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
349 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
350 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
351
352 glGenTextures(1, &bloomPassTex2);
353 glBindTexture(GL_TEXTURE_2D, bloomPassTex2);
354 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1024/4, 768/4, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
355 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
356 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
357 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
358 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
359
360 curBuf = 0;
361
362 // Load the mesh!
363 std::vector<glm::vec3> mesh_vertices;
364 std::vector<glm::vec2> mesh_uvs;
365 std::vector<glm::vec3> mesh_normals;
366 loadMesh("res/monitor-old.obj", mesh_vertices, mesh_uvs, mesh_normals);
367
368 mesh_numvertices = mesh_vertices.size();
369
370 glGenBuffers(1, &mesh_vertexbuffer);
371 glBindBuffer(GL_ARRAY_BUFFER, mesh_vertexbuffer);
372 glBufferData(GL_ARRAY_BUFFER, mesh_vertices.size() * sizeof(glm::vec3), &mesh_vertices[0], GL_STATIC_DRAW);
373
374 glGenBuffers(1, &mesh_uvbuffer);
375 glBindBuffer(GL_ARRAY_BUFFER, mesh_uvbuffer);
376 glBufferData(GL_ARRAY_BUFFER, mesh_uvs.size() * sizeof(glm::vec3), &mesh_uvs[0], GL_STATIC_DRAW);
377
378 glGenBuffers(1, &mesh_normalbuffer);
379 glBindBuffer(GL_ARRAY_BUFFER, mesh_normalbuffer);
380 glBufferData(GL_ARRAY_BUFFER, mesh_normals.size() * sizeof(glm::vec3), &mesh_normals[0], GL_STATIC_DRAW);
381
382 // Load the vertices of a flat surface
383 GLfloat g_quad_vertex_buffer_data[] = {
384 -1.0f, -1.0f, 0.0f,
385 1.0f, -1.0f, 0.0f,
386 -1.0f, 1.0f, 0.0f,
387 -1.0f, 1.0f, 0.0f,
388 1.0f, -1.0f, 0.0f,
389 1.0f, 1.0f, 0.0f,
390 };
391
392 glGenBuffers(1, &quad_vertexbuffer);
393 glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer);
394 glBufferData(GL_ARRAY_BUFFER, sizeof(g_quad_vertex_buffer_data), g_quad_vertex_buffer_data, GL_STATIC_DRAW);
395
396 glGenTextures(1, &artifactsTex);
397 glBindTexture(GL_TEXTURE_2D, artifactsTex);
398 int atdw, atdh;
399 unsigned char* artifactsTex_data = stbi_load("res/artifacts.bmp", &atdw, &atdh, 0, 3);
400 flipImageData(artifactsTex_data, atdw, atdh, 3);
401 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, atdw, atdh, 0, GL_RGB, GL_UNSIGNED_BYTE, artifactsTex_data);
402 stbi_image_free(artifactsTex_data);
403 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
404 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
405 glGenerateMipmap(GL_TEXTURE_2D);
406
407 glGenTextures(1, &scanlinesTex);
408 glBindTexture(GL_TEXTURE_2D, scanlinesTex);
409 int stdw, stdh;
410 unsigned char* scanlinesTex_data = stbi_load("res/scanlines_333.bmp", &stdw, &stdh, 0, 3);
411 flipImageData(scanlinesTex_data, stdw, stdh, 3);
412 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, atdw, atdh, 0, GL_RGB, GL_UNSIGNED_BYTE, scanlinesTex_data);
413 stbi_image_free(scanlinesTex_data);
414 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
415 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
416 glGenerateMipmap(GL_TEXTURE_2D);
417
418 // Load the shaders
419 ntscShader = LoadShaders("shaders/ntsc.vertex", "shaders/ntsc.fragment");
420 finalShader = LoadShaders("shaders/final.vertex", "shaders/final.fragment");
421 blitShader = LoadShaders("shaders/blit.vertex", "shaders/blit.fragment");
422 fillShader = LoadShaders("shaders/fill.vertex", "shaders/fill.fragment");
423 bloom1Shader = LoadShaders("shaders/bloom1.vertex", "shaders/bloom1.fragment");
424 bloom2Shader = LoadShaders("shaders/bloom2.vertex", "shaders/bloom2.fragment");
425
426 rendererInitialized = true;
427
428 return window;
429}
430
431void destroyRenderer()
432{
433 if (!rendererInitialized)
434 {
435 fprintf(stderr, "Renderer not initialized\n");
436 exit(-1);
437 }
438
439 // Delete the plane buffer
440 glDeleteBuffers(1, &quad_vertexbuffer);
441 glDeleteBuffers(1, &mesh_vertexbuffer);
442 glDeleteBuffers(1, &mesh_uvbuffer);
443 glDeleteBuffers(1, &mesh_normalbuffer);
444
445 // Delete the shaders
446 glDeleteProgram(ntscShader);
447 glDeleteProgram(finalShader);
448 glDeleteProgram(blitShader);
449 glDeleteProgram(fillShader);
450 glDeleteProgram(bloom1Shader);
451 glDeleteProgram(bloom2Shader);
452
453 // Delete the NTSC rendering buffers
454 glDeleteTextures(1, &renderedTex1);
455 glDeleteTextures(1, &renderedTex2);
456 glDeleteTextures(1, &artifactsTex);
457 glDeleteTextures(1, &scanlinesTex);
458 glDeleteTextures(1, &preBloomTex);
459 glDeleteTextures(1, &bloomPassTex1);
460 glDeleteTextures(1, &bloomPassTex2);
461
462 // Delete the framebuffer
463 glDeleteRenderbuffers(1, &bloom_depthbuffer);
464 glDeleteFramebuffers(1, &bloom_framebuffer);
465 glDeleteFramebuffers(1, &generic_framebuffer);
466
467 // Delete the VAO
468 glDeleteVertexArrays(1, &VertexArrayID);
469
470 // Kill the window
471 glfwTerminate();
472
473 rendererInitialized = false;
474}
475
476Texture::Texture(int width, int height)
477{
478 if (!rendererInitialized)
479 {
480 fprintf(stderr, "Renderer not initialized\n");
481 exit(-1);
482 }
483
484 this->width = width;
485 this->height = height;
486
487 glGenTextures(1, &texID);
488 glBindTexture(GL_TEXTURE_2D, texID);
489 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
490 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
491 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
492 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
493 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
494}
495
496Texture::Texture(const char* filename)
497{
498 if (!rendererInitialized)
499 {
500 fprintf(stderr, "Renderer not initialized\n");
501 exit(-1);
502 }
503
504 glGenTextures(1, &texID);
505 glBindTexture(GL_TEXTURE_2D, texID);
506 unsigned char* data = stbi_load(filename, &width, &height, 0, 4);
507 flipImageData(data, width, height, 4);
508 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
509 stbi_image_free(data);
510 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
511 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
512 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
513 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
514}
515
516Texture::Texture(const Texture& tex)
517{
518 if (!rendererInitialized)
519 {
520 fprintf(stderr, "Renderer not initialized\n");
521 exit(-1);
522 }
523
524 width = tex.width;
525 height = tex.height;
526
527 unsigned char* data = (unsigned char*) malloc(4 * width * height);
528 glBindTexture(GL_TEXTURE_2D, tex.texID);
529 glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
530
531 glGenTextures(1, &texID);
532 glBindTexture(GL_TEXTURE_2D, texID);
533 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
534 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
535 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
536 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
537 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
538
539 free(data);
540}
541
542Texture::Texture(Texture&& tex) : Texture(0, 0)
543{
544 swap(*this, tex);
545}
546
547Texture::~Texture()
548{
549 if (!rendererInitialized)
550 {
551 fprintf(stderr, "Renderer not initialized\n");
552 exit(-1);
553 }
554
555 glDeleteTextures(1, &texID);
556}
557
558Texture& Texture::operator= (Texture tex)
559{
560 swap(*this, tex);
561
562 return *this;
563}
564
565void swap(Texture& tex1, Texture& tex2)
566{
567 std::swap(tex1.width, tex2.width);
568 std::swap(tex1.height, tex2.height);
569 std::swap(tex1.texID, tex2.texID);
570}
571
572void Texture::fill(Rectangle dstrect, int r, int g, int b)
573{
574 if (!rendererInitialized)
575 {
576 fprintf(stderr, "Renderer not initialized\n");
577 exit(-1);
578 }
579
580 // Target the framebuffer
581 glBindFramebuffer(GL_FRAMEBUFFER, generic_framebuffer);
582 glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texID, 0);
583
584 // Set up the vertex attributes
585 GLfloat minx = (GLfloat) dstrect.x / width * 2.0 - 1.0;
586 GLfloat miny = -((GLfloat) dstrect.y / height * 2.0 - 1.0);
587 GLfloat maxx = (GLfloat) (dstrect.x + dstrect.w) / width * 2.0 - 1.0;
588 GLfloat maxy = -((GLfloat) (dstrect.y + dstrect.h) / height * 2.0 - 1.0);
589
590 GLfloat vertexbuffer_data[] = {
591 minx, miny,
592 maxx, miny,
593 maxx, maxy,
594 minx, miny,
595 minx, maxy,
596 maxx, maxy
597 };
598 GLuint vertexbuffer;
599 glGenBuffers(1, &vertexbuffer);
600 glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
601 glBufferData(GL_ARRAY_BUFFER, sizeof(vertexbuffer_data), vertexbuffer_data, GL_STATIC_DRAW);
602 glEnableVertexAttribArray(0);
603 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
604
605 glViewport(0, 0, width, height);
606 glClear(GL_DEPTH_BUFFER_BIT);
607 glUseProgram(fillShader);
608 glUniform3f(glGetUniformLocation(fillShader, "vecColor"), r / 255.0, g / 255.0, b / 255.0);
609
610 glDrawArrays(GL_TRIANGLES, 0, 6);
611
612 glDisableVertexAttribArray(0);
613 glDeleteBuffers(1, &vertexbuffer);
614}
615
616void Texture::blit(const Texture& srctex, Rectangle srcrect, Rectangle dstrect, double alpha)
617{
618 if (!rendererInitialized)
619 {
620 fprintf(stderr, "Renderer not initialized\n");
621 exit(-1);
622 }
623
624 alpha = glm::clamp(alpha, 0.0, 1.0);
625
626 // Target the framebuffer
627 glBindFramebuffer(GL_FRAMEBUFFER, generic_framebuffer);
628 glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texID, 0);
629
630 // Set up the vertex attributes
631 GLfloat minx = (GLfloat) dstrect.x / width * 2.0 - 1.0;
632 GLfloat miny = -((GLfloat) dstrect.y / height * 2.0 - 1.0);
633 GLfloat maxx = (GLfloat) (dstrect.x + dstrect.w) / width * 2.0 - 1.0;
634 GLfloat maxy = -((GLfloat) (dstrect.y + dstrect.h) / height * 2.0 - 1.0);
635
636 GLfloat vertexbuffer_data[] = {
637 minx, miny,
638 maxx, miny,
639 minx, maxy,
640 maxx, maxy
641 };
642 GLuint vertexbuffer;
643 glGenBuffers(1, &vertexbuffer);
644 glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
645 glBufferData(GL_ARRAY_BUFFER, sizeof(vertexbuffer_data), vertexbuffer_data, GL_STATIC_DRAW);
646 glEnableVertexAttribArray(0);
647 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
648
649 GLfloat minu = (GLfloat) srcrect.x / srctex.width;
650 GLfloat minv = 1 - ((GLfloat) srcrect.y / srctex.height);
651 GLfloat maxu = (GLfloat) (srcrect.x + srcrect.w) / srctex.width;
652 GLfloat maxv = 1 - ((GLfloat) (srcrect.y + srcrect.h) / srctex.height);
653
654 GLfloat texcoordbuffer_data[] = {
655 minu, minv,
656 maxu, minv,
657 minu, maxv,
658 maxu, maxv
659 };
660 GLuint texcoordbuffer;
661 glGenBuffers(1, &texcoordbuffer);
662 glBindBuffer(GL_ARRAY_BUFFER, texcoordbuffer);
663 glBufferData(GL_ARRAY_BUFFER, sizeof(texcoordbuffer_data), texcoordbuffer_data, GL_STATIC_DRAW);
664 glEnableVertexAttribArray(1);
665 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
666
667 // Set up the shader
668 glUseProgram(blitShader);
669 glClear(GL_DEPTH_BUFFER_BIT);
670 glViewport(0, 0, width, height);
671
672 glActiveTexture(GL_TEXTURE0);
673 glBindTexture(GL_TEXTURE_2D, srctex.texID);
674 glUniform1i(glGetUniformLocation(blitShader, "srctex"), 0);
675 glUniform1f(glGetUniformLocation(blitShader, "alpha"), alpha);
676
677 // Blit!
678 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
679
680 // Unload everything
681 glDisableVertexAttribArray(1);
682 glDisableVertexAttribArray(0);
683 glDeleteBuffers(1, &texcoordbuffer);
684 glDeleteBuffers(1, &vertexbuffer);
685}
686
687void bloomPass1(GLuint srcTex, GLuint dstTex, bool horizontal, glm::vec2 srcRes, glm::vec2 dstRes)
688{
689 glBindFramebuffer(GL_FRAMEBUFFER, generic_framebuffer);
690 glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, dstTex, 0);
691 glViewport(0,0,dstRes.x,dstRes.y);
692 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
693 glUseProgram(bloom1Shader);
694
695 glActiveTexture(GL_TEXTURE0);
696 glBindTexture(GL_TEXTURE_2D, srcTex);
697 glUniform1i(glGetUniformLocation(bloom1Shader, "inTex"), 0);
698
699 glm::vec2 offset = glm::vec2(0.0);
700 if (horizontal)
701 {
702 offset.x = 1.2/srcRes.x;
703 } else {
704 offset.y = 1.2/srcRes.y;
705 }
706
707 glUniform2f(glGetUniformLocation(bloom1Shader, "offset"), offset.x, offset.y);
708
709 glEnableVertexAttribArray(0);
710 glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer);
711 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
712 glDrawArrays(GL_TRIANGLES, 0, 6);
713 glDisableVertexAttribArray(0);
714}
715
716void Texture::renderScreen() const
717{
718 if (!rendererInitialized)
719 {
720 fprintf(stderr, "Renderer not initialized\n");
721 exit(-1);
722 }
723
724 // First we're going to composite our frame with the previous frame
725 // We start by setting up the framebuffer
726 glBindFramebuffer(GL_FRAMEBUFFER, generic_framebuffer);
727 glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, renderedTexBufs[curBuf], 0);
728
729 // Set up the shader
730 glViewport(0,0,GAME_WIDTH,GAME_HEIGHT);
731 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
732 glUseProgram(ntscShader);
733
734 // Use the current frame texture, nearest neighbor and clamped to edge
735 glActiveTexture(GL_TEXTURE0);
736 glBindTexture(GL_TEXTURE_2D, texID);
737 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
738 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
739 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
740 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
741 glUniform1i(glGetUniformLocation(ntscShader, "curFrameSampler"), 0);
742
743 // Use the previous frame composite texture, nearest neighbor and clamped to edge
744 glActiveTexture(GL_TEXTURE1);
745 glBindTexture(GL_TEXTURE_2D, renderedTexBufs[(curBuf + 1) % 2]);
746 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
747 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
748 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
749 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
750 glUniform1i(glGetUniformLocation(ntscShader, "prevFrameSampler"), 1);
751
752 // Load the NTSC artifact texture
753 glActiveTexture(GL_TEXTURE2);
754 glBindTexture(GL_TEXTURE_2D, artifactsTex);
755 glUniform1i(glGetUniformLocation(ntscShader, "NTSCArtifactSampler"), 2);
756 glUniform1f(glGetUniformLocation(ntscShader, "NTSCLerp"), curBuf * 1.0);
757
758 if ((rand() % 60) == 0)
759 {
760 // Change the 0.0 to a 1.0 or a 10.0 for a glitchy effect!
761 glUniform1f(glGetUniformLocation(ntscShader, "Tuning_NTSC"), 0.0);
762 } else {
763 glUniform1f(glGetUniformLocation(ntscShader, "Tuning_NTSC"), 0.0);
764 }
765
766 // Render our composition
767 glEnableVertexAttribArray(0);
768 glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer);
769 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
770 glDrawArrays(GL_TRIANGLES, 0, 6);
771 glDisableVertexAttribArray(0);
772
773 // We're going to render the screen now
774 glBindFramebuffer(GL_FRAMEBUFFER, bloom_framebuffer);
775 glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, preBloomTex, 0);
776 glViewport(0,0,buffer_width,buffer_height);
777 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
778 glUseProgram(finalShader);
779
780 // Use the composited frame texture, linearly filtered and filling in black for the border
781 glActiveTexture(GL_TEXTURE0);
782 glBindTexture(GL_TEXTURE_2D, renderedTexBufs[curBuf]);
783 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
784 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
785 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
786 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
787 float border_color[] = {0.0f, 0.0f, 0.0f, 1.0f};
788 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color);
789 glGenerateMipmap(GL_TEXTURE_2D);
790 glUniform1i(glGetUniformLocation(finalShader, "rendertex"), 0);
791
792 // Use the scanlines texture
793 glActiveTexture(GL_TEXTURE1);
794 glBindTexture(GL_TEXTURE_2D, scanlinesTex);
795 glUniform1i(glGetUniformLocation(finalShader, "scanlinestex"), 1);
796
797 // Initialize the MVP matrices
798 glm::mat4 p_matrix = glm::perspective(glm::radians(25.0f), (float) buffer_width / (float) buffer_height, 0.1f, 100.0f);
799 glm::mat4 v_matrix = glm::lookAt(glm::vec3(3.75,0,0), glm::vec3(0,0,0), glm::vec3(0,1,0));
800 glm::mat4 m_matrix = glm::mat4(1.0);
801 glm::mat4 mvp_matrix = p_matrix * v_matrix * m_matrix;
802
803 glUniformMatrix4fv(glGetUniformLocation(finalShader, "MVP"), 1, GL_FALSE, &mvp_matrix[0][0]);
804 glUniformMatrix4fv(glGetUniformLocation(finalShader, "worldMat"), 1, GL_FALSE, &m_matrix[0][0]);
805 glUniform2f(glGetUniformLocation(finalShader, "resolution"), buffer_width, buffer_height);
806 glUniform1f(glGetUniformLocation(finalShader, "iGlobalTime"), glfwGetTime());
807 glUniform3f(glGetUniformLocation(finalShader, "frameColor"), 0.76f, 0.78f, 0.81f);
808
809 glEnableVertexAttribArray(0);
810 glBindBuffer(GL_ARRAY_BUFFER, mesh_vertexbuffer);
811 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
812
813 glEnableVertexAttribArray(1);
814 glBindBuffer(GL_ARRAY_BUFFER, mesh_normalbuffer);
815 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
816
817 glEnableVertexAttribArray(2);
818 glBindBuffer(GL_ARRAY_BUFFER, mesh_uvbuffer);
819 glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
820
821 glDrawArrays(GL_TRIANGLES, 0, mesh_numvertices);
822 glDisableVertexAttribArray(2);
823 glDisableVertexAttribArray(1);
824 glDisableVertexAttribArray(0);
825
826 // First pass of bloom!
827 glm::vec2 buffer_size = glm::vec2(buffer_width, buffer_height);
828 bloomPass1(preBloomTex, bloomPassTex1, true, buffer_size, buffer_size / 4.0f);
829 bloomPass1(bloomPassTex1, bloomPassTex2, false, buffer_size / 4.0f, buffer_size / 4.0f);
830
831 // Do the second pass of bloom and render to screen
832 glBindFramebuffer(GL_FRAMEBUFFER, 0);
833 glViewport(0, 0, buffer_width, buffer_height);
834 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
835 glUseProgram(bloom2Shader);
836
837 glActiveTexture(GL_TEXTURE0);
838 glBindTexture(GL_TEXTURE_2D, preBloomTex);
839 glUniform1i(glGetUniformLocation(bloom2Shader, "clearTex"), 0);
840
841 glActiveTexture(GL_TEXTURE1);
842 glBindTexture(GL_TEXTURE_2D, bloomPassTex2);
843 glUniform1i(glGetUniformLocation(bloom2Shader, "blurTex"), 1);
844
845 glUniform1f(glGetUniformLocation(bloom2Shader, "iGlobalTime"), glfwGetTime());
846
847 glEnableVertexAttribArray(0);
848 glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer);
849 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
850 glDrawArrays(GL_TRIANGLES, 0, 6);
851 glDisableVertexAttribArray(0);
852
853 glfwSwapBuffers(window);
854
855 curBuf = (curBuf + 1) % 2;
856}
857
858Rectangle Texture::entirety() const
859{
860 return {0, 0, width, height};
861}