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