summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKelly Rauchenberger <fefferburbia@gmail.com>2018-02-16 16:04:32 -0500
committerKelly Rauchenberger <fefferburbia@gmail.com>2018-02-16 16:04:32 -0500
commited08b673c50b076042d8f0c49501372168142764 (patch)
tree18ecda99942ef11ce4023c3ad4437976f96b75da
parent224645d1071c14b4829dbb3ae35870868fcff85a (diff)
downloadtherapy-ed08b673c50b076042d8f0c49501372168142764.tar.gz
therapy-ed08b673c50b076042d8f0c49501372168142764.tar.bz2
therapy-ed08b673c50b076042d8f0c49501372168142764.zip
Refactored renderer
Renderer is basically now more C++'y, as it makes more use of classes (a lot of GL types have been wrapped), and the renderer itself is now a class. The monitor mesh is also now indexed.

Tweaked the NTSC artifacting after inadvertently fixing a bug with the way the image was loaded.
-rw-r--r--CMakeLists.txt6
-rw-r--r--shaders/final.fragment4
-rw-r--r--src/algorithms.h12
-rw-r--r--src/animation.h2
-rw-r--r--src/components/controllable.h2
-rw-r--r--src/components/mappable.h2
-rw-r--r--src/entity_manager.h2
-rw-r--r--src/game.cpp19
-rw-r--r--src/game.h11
-rw-r--r--src/main.cpp17
-rw-r--r--src/renderer.cpp862
-rw-r--r--src/renderer.h37
-rw-r--r--src/renderer/gl.h7
-rw-r--r--src/renderer/mesh.cpp109
-rw-r--r--src/renderer/mesh.h62
-rw-r--r--src/renderer/renderer.cpp635
-rw-r--r--src/renderer/renderer.h114
-rw-r--r--src/renderer/shader.cpp84
-rw-r--r--src/renderer/shader.h58
-rw-r--r--src/renderer/texture.cpp124
-rw-r--r--src/renderer/texture.h52
-rw-r--r--src/renderer/wrappers.h273
-rw-r--r--src/systems/animating.cpp3
-rw-r--r--src/systems/animating.h2
-rw-r--r--src/systems/mapping.cpp12
-rw-r--r--src/util.cpp30
-rw-r--r--src/util.h41
27 files changed, 1631 insertions, 951 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 22bbc1a..3e7bcb8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt
@@ -49,12 +49,16 @@ link_directories(
49 49
50add_executable(Aromatherapy 50add_executable(Aromatherapy
51 src/main.cpp 51 src/main.cpp
52 src/renderer.cpp
53 src/muxer.cpp 52 src/muxer.cpp
54 src/entity_manager.cpp 53 src/entity_manager.cpp
55 src/game.cpp 54 src/game.cpp
56 src/animation.cpp 55 src/animation.cpp
57 src/world.cpp 56 src/world.cpp
57 src/util.cpp
58 src/renderer/renderer.cpp
59 src/renderer/mesh.cpp
60 src/renderer/shader.cpp
61 src/renderer/texture.cpp
58 src/systems/controlling.cpp 62 src/systems/controlling.cpp
59 src/systems/pondering.cpp 63 src/systems/pondering.cpp
60 src/systems/animating.cpp 64 src/systems/animating.cpp
diff --git a/shaders/final.fragment b/shaders/final.fragment index 9a39597..2e38f38 100644 --- a/shaders/final.fragment +++ b/shaders/final.fragment
@@ -15,8 +15,8 @@ const float Tuning_Dimming = 0.0;
15const float Tuning_Satur = 1.13; 15const float Tuning_Satur = 1.13;
16const float Tuning_ReflScalar = 0.3; 16const float Tuning_ReflScalar = 0.3;
17const float Tuning_Barrel = 0;//0.12; 17const float Tuning_Barrel = 0;//0.12;
18const float Tuning_Scanline_Brightness = 0.5;//0.45; 18const float Tuning_Scanline_Brightness = 0.55;
19const float Tuning_Scanline_Opacity = 0.75;//0.55; 19const float Tuning_Scanline_Opacity = 0.55;
20const float Tuning_Diff_Brightness = 0.75; 20const float Tuning_Diff_Brightness = 0.75;
21const float Tuning_Spec_Brightness = 0.5;//0.35; 21const float Tuning_Spec_Brightness = 0.5;//0.35;
22const float Tuning_Spec_Power = 50.0; 22const float Tuning_Spec_Power = 50.0;
diff --git a/src/algorithms.h b/src/algorithms.h deleted file mode 100644 index 80e3e27..0000000 --- a/src/algorithms.h +++ /dev/null
@@ -1,12 +0,0 @@
1#ifndef ALGORITHMS_H_1DDC517E
2#define ALGORITHMS_H_1DDC517E
3
4template< typename ContainerT, typename PredicateT >
5void erase_if( ContainerT& items, const PredicateT& predicate ) {
6 for( auto it = items.begin(); it != items.end(); ) {
7 if( predicate(*it) ) it = items.erase(it);
8 else ++it;
9 }
10};
11
12#endif /* end of include guard: ALGORITHMS_H_1DDC517E */
diff --git a/src/animation.h b/src/animation.h index 50446d0..58df616 100644 --- a/src/animation.h +++ b/src/animation.h
@@ -1,7 +1,7 @@
1#ifndef ANIMATION_H_74EB0901 1#ifndef ANIMATION_H_74EB0901
2#define ANIMATION_H_74EB0901 2#define ANIMATION_H_74EB0901
3 3
4#include "renderer.h" 4#include "renderer/texture.h"
5#include <string> 5#include <string>
6#include <map> 6#include <map>
7#include <stdexcept> 7#include <stdexcept>
diff --git a/src/components/controllable.h b/src/components/controllable.h index fa78c8b..1b12985 100644 --- a/src/components/controllable.h +++ b/src/components/controllable.h
@@ -2,7 +2,7 @@
2#define CONTROLLABLE_H_4E0B85B4 2#define CONTROLLABLE_H_4E0B85B4
3 3
4#include "component.h" 4#include "component.h"
5#include "renderer.h" 5#include "renderer/gl.h"
6 6
7class ControllableComponent : public Component { 7class ControllableComponent : public Component {
8public: 8public:
diff --git a/src/components/mappable.h b/src/components/mappable.h index 7530919..2dbab77 100644 --- a/src/components/mappable.h +++ b/src/components/mappable.h
@@ -3,7 +3,7 @@
3 3
4#include <map> 4#include <map>
5#include "component.h" 5#include "component.h"
6#include "renderer.h" 6#include "renderer/texture.h"
7#include "map.h" 7#include "map.h"
8 8
9class MappableComponent : public Component { 9class MappableComponent : public Component {
diff --git a/src/entity_manager.h b/src/entity_manager.h index 7fd82fc..65fa6ca 100644 --- a/src/entity_manager.h +++ b/src/entity_manager.h
@@ -7,7 +7,7 @@
7#include <set> 7#include <set>
8#include <stdexcept> 8#include <stdexcept>
9#include "component.h" 9#include "component.h"
10#include "algorithms.h" 10#include "util.h"
11 11
12class EntityManager { 12class EntityManager {
13private: 13private:
diff --git a/src/game.cpp b/src/game.cpp index 1182689..228ff23 100644 --- a/src/game.cpp +++ b/src/game.cpp
@@ -10,12 +10,11 @@
10#include "systems/mapping.h" 10#include "systems/mapping.h"
11#include "systems/orienting.h" 11#include "systems/orienting.h"
12#include "animation.h" 12#include "animation.h"
13#include "renderer.h"
14#include "consts.h" 13#include "consts.h"
15 14
16void key_callback(GLFWwindow* window, int key, int, int action, int) 15void key_callback(GLFWwindow* window, int key, int, int action, int)
17{ 16{
18 Game& game = *((Game*) glfwGetWindowUserPointer(window)); 17 Game& game = *static_cast<Game*>(glfwGetWindowUserPointer(window));
19 18
20 if ((action == GLFW_PRESS) && (key == GLFW_KEY_ESCAPE)) 19 if ((action == GLFW_PRESS) && (key == GLFW_KEY_ESCAPE))
21 { 20 {
@@ -27,10 +26,7 @@ void key_callback(GLFWwindow* window, int key, int, int action, int)
27 game.systemManager_.input(key, action); 26 game.systemManager_.input(key, action);
28} 27}
29 28
30Game::Game( 29Game::Game() : world_("res/maps.xml")
31 GLFWwindow* window) :
32 window_(window),
33 world_("res/maps.xml")
34{ 30{
35 systemManager_.emplaceSystem<ControllingSystem>(*this); 31 systemManager_.emplaceSystem<ControllingSystem>(*this);
36 systemManager_.emplaceSystem<OrientingSystem>(*this); 32 systemManager_.emplaceSystem<OrientingSystem>(*this);
@@ -65,8 +61,8 @@ Game::Game(
65 systemManager_.getSystem<MappingSystem>().loadMap(world_.getStartingMapId()); 61 systemManager_.getSystem<MappingSystem>().loadMap(world_.getStartingMapId());
66 62
67 glfwSwapInterval(1); 63 glfwSwapInterval(1);
68 glfwSetWindowUserPointer(window_, this); 64 glfwSetWindowUserPointer(renderer_.getWindow().getHandle(), this);
69 glfwSetKeyCallback(window_, key_callback); 65 glfwSetKeyCallback(renderer_.getWindow().getHandle(), key_callback);
70} 66}
71 67
72void Game::execute() 68void Game::execute()
@@ -76,7 +72,8 @@ void Game::execute()
76 double accumulator = 0.0; 72 double accumulator = 0.0;
77 Texture texture(GAME_WIDTH, GAME_HEIGHT); 73 Texture texture(GAME_WIDTH, GAME_HEIGHT);
78 74
79 while (!(shouldQuit_ || glfwWindowShouldClose(window_))) 75 while (!(shouldQuit_ ||
76 glfwWindowShouldClose(renderer_.getWindow().getHandle())))
80 { 77 {
81 double currentTime = glfwGetTime(); 78 double currentTime = glfwGetTime();
82 double frameTime = currentTime - lastTime; 79 double frameTime = currentTime - lastTime;
@@ -93,8 +90,8 @@ void Game::execute()
93 } 90 }
94 91
95 // Render 92 // Render
96 texture.fill(texture.entirety(), 0, 0, 0); 93 renderer_.fill(texture, texture.entirety(), 0, 0, 0);
97 systemManager_.render(texture); 94 systemManager_.render(texture);
98 texture.renderScreen(); 95 renderer_.renderScreen(texture);
99 } 96 }
100} 97}
diff --git a/src/game.h b/src/game.h index 346d67e..43e08da 100644 --- a/src/game.h +++ b/src/game.h
@@ -1,18 +1,23 @@
1#ifndef GAME_H_1014DDC9 1#ifndef GAME_H_1014DDC9
2#define GAME_H_1014DDC9 2#define GAME_H_1014DDC9
3 3
4#include "renderer.h"
5#include "entity_manager.h" 4#include "entity_manager.h"
6#include "system_manager.h" 5#include "system_manager.h"
7#include "world.h" 6#include "world.h"
7#include "renderer/renderer.h"
8 8
9class Game { 9class Game {
10public: 10public:
11 11
12 Game(GLFWwindow* window); 12 Game();
13 13
14 void execute(); 14 void execute();
15 15
16 inline Renderer& getRenderer()
17 {
18 return renderer_;
19 }
20
16 inline EntityManager& getEntityManager() 21 inline EntityManager& getEntityManager()
17 { 22 {
18 return entityManager_; 23 return entityManager_;
@@ -37,7 +42,7 @@ public:
37 42
38private: 43private:
39 44
40 GLFWwindow* const window_; 45 Renderer renderer_;
41 EntityManager entityManager_; 46 EntityManager entityManager_;
42 SystemManager systemManager_; 47 SystemManager systemManager_;
43 World world_; 48 World world_;
diff --git a/src/main.cpp b/src/main.cpp index d51da7d..ddbc15f 100644 --- a/src/main.cpp +++ b/src/main.cpp
@@ -1,27 +1,14 @@
1#include <ctime>
2#include <list>
3#include <cstdlib>
4#include "renderer.h"
5#include "muxer.h" 1#include "muxer.h"
6#include "game.h" 2#include "game.h"
7 3
8int main() 4int main()
9{ 5{
10 srand(time(NULL));
11
12 GLFWwindow* window = initRenderer();
13 glfwSwapInterval(1);
14
15 initMuxer(); 6 initMuxer();
16 7
17 // Put this in a block so game goes out of scope before we destroy the renderer 8 Game game;
18 { 9 game.execute();
19 Game game {window};
20 game.execute();
21 }
22 10
23 destroyMuxer(); 11 destroyMuxer();
24 destroyRenderer();
25 12
26 return 0; 13 return 0;
27} 14}
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}
diff --git a/src/renderer.h b/src/renderer.h deleted file mode 100644 index 6dccf7a..0000000 --- a/src/renderer.h +++ /dev/null
@@ -1,37 +0,0 @@
1#include <GL/glew.h>
2#include <GLFW/glfw3.h>
3
4#ifndef RENDERER_H
5#define RENDERER_H
6
7struct Rectangle {
8 int x;
9 int y;
10 int w;
11 int h;
12};
13
14class Texture {
15 public:
16 Texture(int width, int height);
17 Texture(const char* file);
18 Texture(const Texture& tex);
19 Texture(Texture&& tex);
20 ~Texture();
21 Texture& operator= (Texture tex);
22 friend void swap(Texture& tex1, Texture& tex2);
23 void fill(Rectangle loc, int r, int g, int b);
24 void blit(const Texture& src, Rectangle srcrect, Rectangle dstrect, double alpha = 1.0);
25 void renderScreen() const;
26 Rectangle entirety() const;
27
28 private:
29 GLuint texID;
30 int width;
31 int height;
32};
33
34GLFWwindow* initRenderer();
35void destroyRenderer();
36
37#endif
diff --git a/src/renderer/gl.h b/src/renderer/gl.h new file mode 100644 index 0000000..4e98c42 --- /dev/null +++ b/src/renderer/gl.h
@@ -0,0 +1,7 @@
1#ifndef GL_H_3EE4A268
2#define GL_H_3EE4A268
3
4#include <GL/glew.h>
5#include <GLFW/glfw3.h>
6
7#endif /* end of include guard: GL_H_3EE4A268 */
diff --git a/src/renderer/mesh.cpp b/src/renderer/mesh.cpp new file mode 100644 index 0000000..b06b723 --- /dev/null +++ b/src/renderer/mesh.cpp
@@ -0,0 +1,109 @@
1#include "mesh.h"
2#include <fstream>
3#include <vector>
4#include <map>
5#include <glm/glm.hpp>
6#include "util.h"
7
8Mesh::Mesh(std::string filename)
9{
10 std::ifstream meshfile(filename);
11 if (!meshfile.is_open())
12 {
13 throw std::invalid_argument("Could not open mesh file");
14 }
15
16 std::vector<glm::vec3> tempVertices;
17 std::vector<glm::vec2> tempUvs;
18 std::vector<glm::vec3> tempNormals;
19
20 std::vector<glm::vec3> outVertices;
21 std::vector<glm::vec2> outUvs;
22 std::vector<glm::vec3> outNormals;
23 std::map<element, unsigned short> elementIds;
24 std::vector<unsigned short> indices;
25
26 while (meshfile)
27 {
28 std::string linetype;
29 meshfile >> linetype;
30
31 if (linetype == "v")
32 {
33 glm::vec3 vertex;
34 meshfile >> vertex.x >> vertex.y >> vertex.z;
35
36 tempVertices.push_back(std::move(vertex));
37 } else if (linetype == "vt")
38 {
39 glm::vec2 uv;
40 meshfile >> uv.x >> uv.y;
41
42 tempUvs.push_back(std::move(uv));
43 } else if (linetype == "vn")
44 {
45 glm::vec3 normal;
46 meshfile >> normal.x >> normal.y >> normal.z;
47
48 tempNormals.push_back(std::move(normal));
49 } else if (linetype == "f")
50 {
51 element elements[3];
52
53 meshfile
54 >> elements[0].vertexId >> chlit('/')
55 >> elements[0].uvId >> chlit('/')
56 >> elements[0].normalId
57 >> elements[1].vertexId >> chlit('/')
58 >> elements[1].uvId >> chlit('/')
59 >> elements[1].normalId
60 >> elements[2].vertexId >> chlit('/')
61 >> elements[2].uvId >> chlit('/')
62 >> elements[2].normalId;
63
64 for (size_t i = 0; i < 3; i++)
65 {
66 if (!elementIds.count(elements[i]))
67 {
68 elementIds[elements[i]] = outVertices.size();
69
70 outVertices.push_back(tempVertices[elements[i].vertexId - 1]);
71 outUvs.push_back(tempUvs[elements[i].uvId - 1]);
72 outNormals.push_back(tempNormals[elements[i].normalId - 1]);
73 }
74
75 indices.push_back(elementIds[elements[i]]);
76 }
77 }
78 }
79
80 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer_.getId());
81 glBufferData(
82 GL_ARRAY_BUFFER,
83 outVertices.size() * sizeof(glm::vec3),
84 outVertices.data(),
85 GL_STATIC_DRAW);
86
87 glBindBuffer(GL_ARRAY_BUFFER, uvBuffer_.getId());
88 glBufferData(
89 GL_ARRAY_BUFFER,
90 outUvs.size() * sizeof(glm::vec2),
91 outUvs.data(),
92 GL_STATIC_DRAW);
93
94 glBindBuffer(GL_ARRAY_BUFFER, normalBuffer_.getId());
95 glBufferData(
96 GL_ARRAY_BUFFER,
97 outNormals.size() * sizeof(glm::vec3),
98 outNormals.data(),
99 GL_STATIC_DRAW);
100
101 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer_.getId());
102 glBufferData(
103 GL_ELEMENT_ARRAY_BUFFER,
104 indices.size() * sizeof(unsigned short),
105 indices.data(),
106 GL_STATIC_DRAW);
107
108 indexCount_ = indices.size();
109}
diff --git a/src/renderer/mesh.h b/src/renderer/mesh.h new file mode 100644 index 0000000..06bf65d --- /dev/null +++ b/src/renderer/mesh.h
@@ -0,0 +1,62 @@
1#ifndef MESH_H_76B72E12
2#define MESH_H_76B72E12
3
4#include <string>
5#include "gl.h"
6#include "wrappers.h"
7
8class Mesh {
9public:
10
11 Mesh(std::string filename);
12
13 Mesh(const Mesh& other) = delete;
14 Mesh& operator=(const Mesh& other) = delete;
15
16 inline GLuint getVertexBufferId() const
17 {
18 return vertexBuffer_.getId();
19 }
20
21 inline GLuint getUvBufferId() const
22 {
23 return uvBuffer_.getId();
24 }
25
26 inline GLuint getNormalBufferId() const
27 {
28 return normalBuffer_.getId();
29 }
30
31 inline GLuint getIndexBufferId() const
32 {
33 return indexBuffer_.getId();
34 }
35
36 inline size_t getIndexCount() const
37 {
38 return indexCount_;
39 }
40
41private:
42
43 struct element {
44 size_t vertexId;
45 size_t uvId;
46 size_t normalId;
47
48 bool operator<(const element& other) const
49 {
50 return std::tie(vertexId, uvId, normalId) <
51 std::tie(other.vertexId, other.uvId, other.normalId);
52 }
53 };
54
55 GLBuffer vertexBuffer_;
56 GLBuffer uvBuffer_;
57 GLBuffer normalBuffer_;
58 GLBuffer indexBuffer_;
59 size_t indexCount_;
60};
61
62#endif /* end of include guard: MESH_H_76B72E12 */
diff --git a/src/renderer/renderer.cpp b/src/renderer/renderer.cpp new file mode 100644 index 0000000..6eef2f3 --- /dev/null +++ b/src/renderer/renderer.cpp
@@ -0,0 +1,635 @@
1#include "renderer.h"
2#include "consts.h"
3#include "game.h"
4#include <glm/gtc/matrix_transform.hpp>
5#include "texture.h"
6
7// include stb_image
8#define STB_IMAGE_IMPLEMENTATION
9#define STBI_ONLY_PNG
10#define STBI_ONLY_BMP
11#include "stb_image.h"
12
13void setFramebufferSize(GLFWwindow* w, int width, int height)
14{
15 Game& game = *static_cast<Game*>(glfwGetWindowUserPointer(w));
16 Renderer& renderer = game.getRenderer();
17
18 renderer.width_ = width;
19 renderer.height_ = height;
20
21 renderer.bloomFb_ = {};
22 renderer.bloomDepth_ = {};
23 renderer.preBloomTex_ = {};
24 renderer.bloomPassTex1_ = {};
25 renderer.bloomPassTex2_ = {};
26
27 renderer.initializeFramebuffers();
28}
29
30bool Renderer::singletonInitialized_ = false;
31
32Renderer::Window::Window()
33{
34 // Initialize GLFW
35 if (!glfwInit())
36 {
37 throw std::runtime_error("Failed to initialize GLFW");
38 }
39
40 glfwWindowHint(GLFW_SAMPLES, 4); // 4x antialiasing
41 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // We want version 3.3
42 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
43 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Mac requires this
44 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
45
46 // Create a window
47 window_ = glfwCreateWindow(1024, 768, "Aromatherapy", nullptr, nullptr);
48 if (window_ == nullptr)
49 {
50 throw std::runtime_error("Failed to open GLFW window");
51 }
52
53 glfwMakeContextCurrent(window_);
54
55 glewExperimental = true; // Needed in core profile
56 if (glewInit() != GLEW_OK)
57 {
58 throw std::runtime_error("Failed to initialize GLEW");
59 }
60
61 glfwSetFramebufferSizeCallback(window_, &setFramebufferSize);
62}
63
64Renderer::Window::~Window()
65{
66 glfwTerminate();
67}
68
69Renderer::Renderer() :
70 monitor_("res/monitor-old.obj"),
71 ntscShader_("ntsc"),
72 finalShader_("final"),
73 blitShader_("blit"),
74 fillShader_("fill"),
75 bloom1Shader_("bloom1"),
76 bloom2Shader_("bloom2")
77{
78 if (singletonInitialized_)
79 {
80 throw std::logic_error("Singleton renderer already initialized");
81 }
82
83 singletonInitialized_ = true;
84
85 // Set up vertex array object
86 glBindVertexArray(vao_.getId());
87
88 // Enable depth testing
89 glEnable(GL_DEPTH_TEST);
90 glDepthFunc(GL_LESS);
91
92 // Enable blending
93 glEnable(GL_BLEND);
94 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
95
96 // Set up the rendering buffers and textures
97 glfwGetFramebufferSize(window_.getHandle(), &width_, &height_);
98
99 initializeFramebuffers();
100
101 // Load the vertices of a flat surface
102 GLfloat g_quad_vertex_buffer_data[] = {
103 -1.0f, -1.0f, 0.0f,
104 1.0f, -1.0f, 0.0f,
105 -1.0f, 1.0f, 0.0f,
106 -1.0f, 1.0f, 0.0f,
107 1.0f, -1.0f, 0.0f,
108 1.0f, 1.0f, 0.0f,
109 };
110
111 glBindBuffer(GL_ARRAY_BUFFER, quadBuffer_.getId());
112 glBufferData(
113 GL_ARRAY_BUFFER,
114 sizeof(GLfloat) * 18,
115 g_quad_vertex_buffer_data,
116 GL_STATIC_DRAW);
117
118 // Load NTSC artifacts
119 int atdw, atdh;
120 unsigned char* artifactsData =
121 stbi_load("res/artifacts.bmp", &atdw, &atdh, 0, 3);
122
123 flipImageData(artifactsData, atdw, atdh, 3);
124
125 glBindTexture(GL_TEXTURE_2D, artifactsTex_.getId());
126 glTexImage2D(
127 GL_TEXTURE_2D,
128 0,
129 GL_RGB,
130 atdw,
131 atdh,
132 0,
133 GL_RGB,
134 GL_UNSIGNED_BYTE,
135 artifactsData);
136
137 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
138 glTexParameteri(
139 GL_TEXTURE_2D,
140 GL_TEXTURE_MIN_FILTER,
141 GL_NEAREST_MIPMAP_NEAREST);
142
143 glGenerateMipmap(GL_TEXTURE_2D);
144 stbi_image_free(artifactsData);
145
146 // Load NTSC scanlines
147 unsigned char* scanlinesData =
148 stbi_load("res/scanlines_333.bmp", &atdw, &atdh, 0, 3);
149
150 flipImageData(scanlinesData, atdw, atdh, 3);
151
152 glBindTexture(GL_TEXTURE_2D, scanlinesTex_.getId());
153 glTexImage2D(
154 GL_TEXTURE_2D,
155 0,
156 GL_RGB,
157 atdw,
158 atdh,
159 0,
160 GL_RGB,
161 GL_UNSIGNED_BYTE,
162 scanlinesData);
163
164 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
165 glTexParameteri(
166 GL_TEXTURE_2D,
167 GL_TEXTURE_MIN_FILTER,
168 GL_NEAREST_MIPMAP_NEAREST);
169
170 glGenerateMipmap(GL_TEXTURE_2D);
171 stbi_image_free(scanlinesData);
172}
173
174void Renderer::initializeFramebuffers()
175{
176 // Set up the framebuffer
177 glBindFramebuffer(GL_FRAMEBUFFER, genericFb_.getId());
178 GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0};
179 glDrawBuffers(1, DrawBuffers);
180
181 // Set up the bloom framebuffer and depthbuffer
182 glBindFramebuffer(GL_FRAMEBUFFER, bloomFb_.getId());
183 GLenum DrawBuffers2[1] = {GL_COLOR_ATTACHMENT1};
184 glDrawBuffers(1, DrawBuffers2);
185
186 glBindRenderbuffer(GL_RENDERBUFFER, bloomDepth_.getId());
187 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width_, height_);
188 glFramebufferRenderbuffer(
189 GL_FRAMEBUFFER,
190 GL_DEPTH_ATTACHMENT,
191 GL_RENDERBUFFER,
192 bloomDepth_.getId());
193
194 // Set up the NTSC rendering buffers
195 glBindTexture(GL_TEXTURE_2D, renderPages_[0].getId());
196 glTexImage2D(
197 GL_TEXTURE_2D,
198 0,
199 GL_RGB,
200 GAME_WIDTH,
201 GAME_HEIGHT,
202 0,
203 GL_RGB,
204 GL_UNSIGNED_BYTE,
205 0);
206
207 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
208 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
209 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
210 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
211
212 glBindTexture(GL_TEXTURE_2D, renderPages_[1].getId());
213 glTexImage2D(
214 GL_TEXTURE_2D,
215 0,
216 GL_RGB,
217 GAME_WIDTH,
218 GAME_HEIGHT,
219 0,
220 GL_RGB,
221 GL_UNSIGNED_BYTE,
222 0);
223
224 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
225 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
226 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
227 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
228
229 // Set up bloom rendering buffers
230 glBindTexture(GL_TEXTURE_2D, preBloomTex_.getId());
231 glTexImage2D(
232 GL_TEXTURE_2D,
233 0,
234 GL_RGB,
235 width_,
236 height_,
237 0,
238 GL_RGB,
239 GL_UNSIGNED_BYTE,
240 0);
241
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 glBindTexture(GL_TEXTURE_2D, bloomPassTex1_.getId());
248 glTexImage2D(
249 GL_TEXTURE_2D,
250 0,
251 GL_RGB,
252 width_ / 4,
253 height_ / 4,
254 0,
255 GL_RGB,
256 GL_UNSIGNED_BYTE,
257 0);
258
259 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
260 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
261 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
262 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
263
264 glBindTexture(GL_TEXTURE_2D, bloomPassTex2_.getId());
265 glTexImage2D(
266 GL_TEXTURE_2D,
267 0,
268 GL_RGB,
269 width_ / 4,
270 height_ / 4,
271 0,
272 GL_RGB,
273 GL_UNSIGNED_BYTE,
274 0);
275
276 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
277 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
278 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
279 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
280}
281
282Renderer::~Renderer()
283{
284 singletonInitialized_ = false;
285}
286
287void Renderer::fill(Texture& tex, Rectangle dstrect, int r, int g, int b)
288{
289 // Target the framebuffer
290 glBindFramebuffer(GL_FRAMEBUFFER, genericFb_.getId());
291 glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex.getId(), 0);
292
293 // Set up the vertex attributes
294 int width = tex.getWidth();
295 int height = tex.getHeight();
296
297 GLfloat minx = (GLfloat) dstrect.x / width * 2.0 - 1.0;
298 GLfloat miny = -((GLfloat) dstrect.y / height * 2.0 - 1.0);
299 GLfloat maxx = (GLfloat) (dstrect.x + dstrect.w) / width * 2.0 - 1.0;
300 GLfloat maxy = -((GLfloat) (dstrect.y + dstrect.h) / height * 2.0 - 1.0);
301
302 GLfloat vertexData[] = {
303 minx, miny,
304 maxx, miny,
305 maxx, maxy,
306 minx, miny,
307 minx, maxy,
308 maxx, maxy
309 };
310
311 GLBuffer vertexBuffer;
312 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.getId());
313 glBufferData(
314 GL_ARRAY_BUFFER,
315 sizeof(GLfloat) * 12,
316 vertexData, GL_STATIC_DRAW);
317
318 glEnableVertexAttribArray(0);
319 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
320
321 glViewport(0, 0, tex.getWidth(), tex.getHeight());
322 glClear(GL_DEPTH_BUFFER_BIT);
323
324 fillShader_.use();
325 glUniform3f(
326 fillShader_.getUniformLocation("vecColor"),
327 r / 255.0,
328 g / 255.0,
329 b / 255.0);
330
331 glDrawArrays(GL_TRIANGLES, 0, 6);
332
333 glDisableVertexAttribArray(0);
334}
335
336void Renderer::blit(
337 const Texture& src,
338 Texture& dst,
339 Rectangle srcrect,
340 Rectangle dstrect,
341 double alpha)
342{
343 alpha = glm::clamp(alpha, 0.0, 1.0);
344
345 // Target the framebuffer
346 glBindFramebuffer(GL_FRAMEBUFFER, genericFb_.getId());
347 glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, dst.getId(), 0);
348
349 // Set up the vertex attributes
350 int width = dst.getWidth();
351 int height = dst.getHeight();
352
353 GLfloat minx = (GLfloat) dstrect.x / width * 2.0 - 1.0;
354 GLfloat miny = -((GLfloat) dstrect.y / height * 2.0 - 1.0);
355 GLfloat maxx = (GLfloat) (dstrect.x + dstrect.w) / width * 2.0 - 1.0;
356 GLfloat maxy = -((GLfloat) (dstrect.y + dstrect.h) / height * 2.0 - 1.0);
357
358 GLfloat vertexData[] = {
359 minx, miny,
360 maxx, miny,
361 minx, maxy,
362 maxx, maxy
363 };
364
365 GLBuffer vertexBuffer;
366 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.getId());
367 glBufferData(
368 GL_ARRAY_BUFFER,
369 sizeof(GLfloat) * 8,
370 vertexData,
371 GL_STATIC_DRAW);
372
373 glEnableVertexAttribArray(0);
374 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
375
376 GLfloat minu = (GLfloat) srcrect.x / src.getWidth();
377 GLfloat minv = 1 - ((GLfloat) srcrect.y / src.getHeight());
378 GLfloat maxu = (GLfloat) (srcrect.x + srcrect.w) / src.getWidth();
379 GLfloat maxv = 1 - ((GLfloat) (srcrect.y + srcrect.h) / src.getHeight());
380
381 GLfloat uvData[] = {
382 minu, minv,
383 maxu, minv,
384 minu, maxv,
385 maxu, maxv
386 };
387
388 GLBuffer uvBuffer;
389 glBindBuffer(GL_ARRAY_BUFFER, uvBuffer.getId());
390 glBufferData(
391 GL_ARRAY_BUFFER,
392 sizeof(GLfloat) * 8,
393 uvData,
394 GL_STATIC_DRAW);
395
396 glEnableVertexAttribArray(1);
397 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
398
399 // Set up the shader
400 blitShader_.use();
401 glClear(GL_DEPTH_BUFFER_BIT);
402 glViewport(0, 0, dst.getWidth(), dst.getHeight());
403
404 glActiveTexture(GL_TEXTURE0);
405 glBindTexture(GL_TEXTURE_2D, src.getId());
406 glUniform1i(blitShader_.getUniformLocation("srctex"), 0);
407 glUniform1f(blitShader_.getUniformLocation("alpha"), alpha);
408
409 // Blit!
410 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
411
412 // Unload everything
413 glDisableVertexAttribArray(1);
414 glDisableVertexAttribArray(0);
415}
416
417void Renderer::bloomPass1(
418 const GLTexture& src,
419 GLTexture& dst,
420 bool horizontal,
421 glm::vec2 srcRes,
422 glm::vec2 dstRes)
423{
424 glBindFramebuffer(GL_FRAMEBUFFER, genericFb_.getId());
425 glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, dst.getId(), 0);
426 glViewport(0,0,dstRes.x,dstRes.y);
427 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
428 bloom1Shader_.use();
429
430 glActiveTexture(GL_TEXTURE0);
431 glBindTexture(GL_TEXTURE_2D, src.getId());
432 glUniform1i(bloom1Shader_.getUniformLocation("inTex"), 0);
433
434 glm::vec2 offset = glm::vec2(0.0);
435 if (horizontal)
436 {
437 offset.x = 1.2/srcRes.x;
438 } else {
439 offset.y = 1.2/srcRes.y;
440 }
441
442 glUniform2f(bloom1Shader_.getUniformLocation("offset"), offset.x, offset.y);
443
444 glEnableVertexAttribArray(0);
445 glBindBuffer(GL_ARRAY_BUFFER, quadBuffer_.getId());
446 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
447 glDrawArrays(GL_TRIANGLES, 0, 6);
448 glDisableVertexAttribArray(0);
449}
450
451void Renderer::renderScreen(const Texture& tex)
452{
453 // First we're going to composite our frame with the previous frame
454 // We start by setting up the framebuffer
455 glBindFramebuffer(GL_FRAMEBUFFER, genericFb_.getId());
456 glFramebufferTexture(
457 GL_FRAMEBUFFER,
458 GL_COLOR_ATTACHMENT0,
459 renderPages_[curBuf_].getId(),
460 0);
461
462 // Set up the shader
463 glViewport(0,0,GAME_WIDTH,GAME_HEIGHT);
464 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
465 ntscShader_.use();
466
467 // Use the current frame texture, nearest neighbor and clamped to edge
468 glActiveTexture(GL_TEXTURE0);
469 glBindTexture(GL_TEXTURE_2D, tex.getId());
470 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
471 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
472 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
473 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
474 glUniform1i(ntscShader_.getUniformLocation("curFrameSampler"), 0);
475
476 // Use the previous frame composite texture, nearest neighbor and clamped to
477 // edge
478 glActiveTexture(GL_TEXTURE1);
479 glBindTexture(GL_TEXTURE_2D, renderPages_[(curBuf_ + 1) % 2].getId());
480 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
481 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
482 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
483 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
484 glUniform1i(ntscShader_.getUniformLocation("prevFrameSampler"), 1);
485
486 // Load the NTSC artifact texture
487 glActiveTexture(GL_TEXTURE2);
488 glBindTexture(GL_TEXTURE_2D, artifactsTex_.getId());
489 glUniform1i(ntscShader_.getUniformLocation("NTSCArtifactSampler"), 2);
490 glUniform1f(ntscShader_.getUniformLocation("NTSCLerp"), curBuf_ * 1.0);
491
492 // Change the 0.0 to a 1.0 or a 10.0 for a glitchy effect!
493 glUniform1f(ntscShader_.getUniformLocation("Tuning_NTSC"), 0.0);
494
495 // Render our composition
496 glEnableVertexAttribArray(0);
497 glBindBuffer(GL_ARRAY_BUFFER, quadBuffer_.getId());
498 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
499 glDrawArrays(GL_TRIANGLES, 0, 6);
500 glDisableVertexAttribArray(0);
501
502 // We're going to render the screen now
503 glBindFramebuffer(GL_FRAMEBUFFER, bloomFb_.getId());
504 glFramebufferTexture(
505 GL_FRAMEBUFFER,
506 GL_COLOR_ATTACHMENT1,
507 preBloomTex_.getId(),
508 0);
509
510 glViewport(0,0,width_,height_);
511 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
512 finalShader_.use();
513
514 // Use the composited frame texture, linearly filtered and filling in black
515 // for the border
516 glActiveTexture(GL_TEXTURE0);
517 glBindTexture(GL_TEXTURE_2D, renderPages_[curBuf_].getId());
518 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
519 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
520 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
521 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
522
523 float borderColor[] = {0.0f, 0.0f, 0.0f, 1.0f};
524 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
525
526 glGenerateMipmap(GL_TEXTURE_2D);
527 glUniform1i(finalShader_.getUniformLocation("rendertex"), 0);
528
529 // Use the scanlines texture
530 glActiveTexture(GL_TEXTURE1);
531 glBindTexture(GL_TEXTURE_2D, scanlinesTex_.getId());
532 glUniform1i(finalShader_.getUniformLocation("scanlinestex"), 1);
533
534 // Initialize the MVP matrices
535 glm::mat4 p_matrix = glm::perspective(
536 glm::radians(25.0f),
537 static_cast<float>(width_) / static_cast<float>(height_),
538 0.1f,
539 100.0f);
540
541 glm::mat4 v_matrix = glm::lookAt(
542 glm::vec3(3.75,0,0), // Camera
543 glm::vec3(0,0,0), // Center
544 glm::vec3(0,1,0)); // Up
545
546 glm::mat4 m_matrix = glm::mat4(1.0);
547 glm::mat4 mvp_matrix = p_matrix * v_matrix * m_matrix;
548
549 glUniformMatrix4fv(
550 finalShader_.getUniformLocation("MVP"),
551 1,
552 GL_FALSE,
553 &mvp_matrix[0][0]);
554
555 glUniformMatrix4fv(
556 finalShader_.getUniformLocation("worldMat"),
557 1,
558 GL_FALSE,
559 &m_matrix[0][0]);
560
561 glUniform2f(finalShader_.getUniformLocation("resolution"), width_, height_);
562 glUniform1f(finalShader_.getUniformLocation("iGlobalTime"), glfwGetTime());
563
564 glUniform3f(
565 finalShader_.getUniformLocation("frameColor"),
566 0.76f,
567 0.78f,
568 0.81f);
569
570 glEnableVertexAttribArray(0);
571 glBindBuffer(GL_ARRAY_BUFFER, monitor_.getVertexBufferId());
572 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
573
574 glEnableVertexAttribArray(1);
575 glBindBuffer(GL_ARRAY_BUFFER, monitor_.getNormalBufferId());
576 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
577
578 glEnableVertexAttribArray(2);
579 glBindBuffer(GL_ARRAY_BUFFER, monitor_.getUvBufferId());
580 glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
581
582 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, monitor_.getIndexBufferId());
583 glDrawElements(
584 GL_TRIANGLES,
585 monitor_.getIndexCount(),
586 GL_UNSIGNED_SHORT,
587 nullptr);
588
589 glDisableVertexAttribArray(2);
590 glDisableVertexAttribArray(1);
591 glDisableVertexAttribArray(0);
592
593 // First pass of bloom!
594 glm::vec2 bufferSize = glm::vec2(width_, height_);
595
596 bloomPass1(
597 preBloomTex_,
598 bloomPassTex1_,
599 true,
600 bufferSize,
601 bufferSize / 4.0f);
602
603 bloomPass1(
604 bloomPassTex1_,
605 bloomPassTex2_,
606 false,
607 bufferSize / 4.0f,
608 bufferSize / 4.0f);
609
610 // Do the second pass of bloom and render to screen
611 glBindFramebuffer(GL_FRAMEBUFFER, 0);
612 glViewport(0, 0, width_, height_);
613 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
614 bloom2Shader_.use();
615
616 glActiveTexture(GL_TEXTURE0);
617 glBindTexture(GL_TEXTURE_2D, preBloomTex_.getId());
618 glUniform1i(bloom2Shader_.getUniformLocation("clearTex"), 0);
619
620 glActiveTexture(GL_TEXTURE1);
621 glBindTexture(GL_TEXTURE_2D, bloomPassTex2_.getId());
622 glUniform1i(bloom2Shader_.getUniformLocation("blurTex"), 1);
623
624 glUniform1f(bloom2Shader_.getUniformLocation("iGlobalTime"), glfwGetTime());
625
626 glEnableVertexAttribArray(0);
627 glBindBuffer(GL_ARRAY_BUFFER, quadBuffer_.getId());
628 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
629 glDrawArrays(GL_TRIANGLES, 0, 6);
630 glDisableVertexAttribArray(0);
631
632 glfwSwapBuffers(window_.getHandle());
633
634 curBuf_ = (curBuf_ + 1) % 2;
635}
diff --git a/src/renderer/renderer.h b/src/renderer/renderer.h new file mode 100644 index 0000000..0b10af5 --- /dev/null +++ b/src/renderer/renderer.h
@@ -0,0 +1,114 @@
1#ifndef RENDERER_H
2#define RENDERER_H
3
4#include "gl.h"
5#include "wrappers.h"
6#include "mesh.h"
7#include "shader.h"
8#include <glm/glm.hpp>
9
10class Texture;
11struct Rectangle;
12
13class Renderer {
14public:
15
16 class Window {
17 public:
18
19 Window();
20
21 Window(const Window& other) = delete;
22 Window& operator=(const Window& other) = delete;
23
24 ~Window();
25
26 inline GLFWwindow* getHandle()
27 {
28 return window_;
29 }
30
31 private:
32
33 GLFWwindow* window_;
34 };
35
36 static inline bool isSingletonInitialized()
37 {
38 return singletonInitialized_;
39 }
40
41 Renderer();
42
43 Renderer(const Renderer& other) = delete;
44 Renderer& operator=(const Renderer& other) = delete;
45
46 ~Renderer();
47
48 inline Window& getWindow()
49 {
50 return window_;
51 }
52
53 void fill(
54 Texture& tex,
55 Rectangle loc,
56 int r,
57 int g,
58 int b);
59
60 void blit(
61 const Texture& src,
62 Texture& dst,
63 Rectangle srcrect,
64 Rectangle dstrect,
65 double alpha = 1.0);
66
67 void renderScreen(const Texture& tex);
68
69private:
70
71 friend void setFramebufferSize(GLFWwindow* w, int width, int height);
72
73 void initializeFramebuffers();
74
75 void bloomPass1(
76 const GLTexture& src,
77 GLTexture& dst,
78 bool horizontal,
79 glm::vec2 srcRes,
80 glm::vec2 dstRes);
81
82 static bool singletonInitialized_;
83
84 Window window_;
85 GLVertexArray vao_;
86
87 GLFramebuffer genericFb_;
88 GLFramebuffer bloomFb_;
89 GLRenderbuffer bloomDepth_;
90
91 GLTexture renderPages_[2];
92 GLTexture preBloomTex_;
93 GLTexture bloomPassTex1_;
94 GLTexture bloomPassTex2_;
95
96 Mesh monitor_;
97 GLBuffer quadBuffer_;
98
99 GLTexture artifactsTex_;
100 GLTexture scanlinesTex_;
101
102 Shader ntscShader_;
103 Shader finalShader_;
104 Shader blitShader_;
105 Shader fillShader_;
106 Shader bloom1Shader_;
107 Shader bloom2Shader_;
108
109 size_t curBuf_ = 0;
110 int width_;
111 int height_;
112};
113
114#endif
diff --git a/src/renderer/shader.cpp b/src/renderer/shader.cpp new file mode 100644 index 0000000..735fc22 --- /dev/null +++ b/src/renderer/shader.cpp
@@ -0,0 +1,84 @@
1#include "shader.h"
2#include <fstream>
3#include <vector>
4#include "util.h"
5
6Shader::Shader(std::string name)
7{
8 GLShader vertexShader(GL_VERTEX_SHADER);
9 GLShader fragmentShader(GL_FRAGMENT_SHADER);
10
11 std::ifstream vertexFile("shaders/" + name + ".vertex");
12 std::ifstream fragmentFile("shaders/" + name + ".fragment");
13
14 std::string vertexCode(slurp(vertexFile));
15 std::string fragmentCode(slurp(fragmentFile));
16
17 const char* vertexCodePtr = vertexCode.c_str();
18 const char* fragmentCodePtr = fragmentCode.c_str();
19
20 glShaderSource(vertexShader.getId(), 1, &vertexCodePtr, nullptr);
21 glShaderSource(fragmentShader.getId(), 1, &fragmentCodePtr, nullptr);
22
23 glCompileShader(vertexShader.getId());
24 glCompileShader(fragmentShader.getId());
25
26#ifdef DEBUG
27 GLint result = GL_FALSE;
28 int infoLogLength;
29
30 glGetShaderiv(vertexShader.getId(), GL_COMPILE_STATUS, &result);
31
32 if (result == GL_FALSE)
33 {
34 glGetShaderiv(vertexShader.getId(), GL_INFO_LOG_LENGTH, &infoLogLength);
35
36 std::vector<char> errMsg(infoLogLength);
37 glGetShaderInfoLog(
38 vertexShader.getId(),
39 infoLogLength,
40 nullptr,
41 errMsg.data());
42
43 throw std::gl_error("Could not compile shader", errMsg.data());
44 }
45
46 glGetShaderiv(fragmentShader.getId(), GL_COMPILE_STATUS, &result);
47
48 if (result == GL_FALSE)
49 {
50 glGetShaderiv(fragmentShader.getId(), GL_INFO_LOG_LENGTH, &infoLogLength);
51
52 std::vector<char> errMsg(infoLogLength);
53 glGetShaderInfoLog(
54 fragmentShader.getId(),
55 infoLogLength,
56 nullptr,
57 errMsg.data());
58
59 throw std::gl_error("Could not compile shader", errMsg.data());
60 }
61#endif
62
63 glAttachShader(program_.getId(), vertexShader.getId());
64 glAttachShader(program_.getId(), fragmentShader.getId());
65 glLinkProgram(program_.getId());
66
67#ifdef DEBUG
68 glGetProgramiv(program_.getId(), GL_LINK_STATUS, &result);
69
70 if (result == GL_FALSE)
71 {
72 glGetProgramiv(program_.getId(), GL_INFO_LOG_LENGTH, &infoLogLength);
73
74 std::vector<char> errMsg(infoLogLength);
75 glGetProgramInfoLog(
76 program_.getId(),
77 infoLogLength,
78 nullptr,
79 errMsg.data());
80
81 throw std::gl_error("Could not link shader program", errMsg.data());
82 }
83#endif
84}
diff --git a/src/renderer/shader.h b/src/renderer/shader.h new file mode 100644 index 0000000..d2c673c --- /dev/null +++ b/src/renderer/shader.h
@@ -0,0 +1,58 @@
1#ifndef SHADER_H_25115B63
2#define SHADER_H_25115B63
3
4#include <string>
5#include <stdexcept>
6#include "gl.h"
7#include "wrappers.h"
8
9class gl_error : public std::logic_error {
10public:
11
12 gl_error(
13 const char* msg,
14 std::string info) :
15 std::logic_error(msg),
16 info_(std::move(info))
17 {
18 }
19
20 gl_error(
21 std::string& msg,
22 std::string info) :
23 std::logic_error(msg),
24 info_(std::move(info))
25 {
26 }
27
28 inline const std::string& getInfo() const
29 {
30 return info_;
31 }
32
33private:
34
35 std::string info_;
36};
37
38class Shader {
39public:
40
41 Shader(std::string name);
42
43 inline void use()
44 {
45 glUseProgram(program_.getId());
46 }
47
48 inline GLint getUniformLocation(const GLchar* name)
49 {
50 return glGetUniformLocation(program_.getId(), name);
51 }
52
53private:
54
55 GLProgram program_;
56};
57
58#endif /* end of include guard: SHADER_H_25115B63 */
diff --git a/src/renderer/texture.cpp b/src/renderer/texture.cpp new file mode 100644 index 0000000..2728665 --- /dev/null +++ b/src/renderer/texture.cpp
@@ -0,0 +1,124 @@
1#include "texture.h"
2#include <stdexcept>
3#include "renderer.h"
4#include "util.h"
5
6// include stb_image
7#define STBI_ONLY_PNG
8#define STBI_ONLY_BMP
9#include "stb_image.h"
10
11Texture::Texture(
12 int width,
13 int height) :
14 width_(width),
15 height_(height)
16{
17 if (!Renderer::isSingletonInitialized())
18 {
19 throw std::logic_error("Renderer needs to be initialized");
20 }
21
22 glBindTexture(GL_TEXTURE_2D, texture_.getId());
23 glTexImage2D(
24 GL_TEXTURE_2D,
25 0,
26 GL_RGBA,
27 width_,
28 height_,
29 0,
30 GL_RGBA,
31 GL_UNSIGNED_BYTE,
32 0);
33
34 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
35 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
36 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
37 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
38}
39
40Texture::Texture(const char* filename)
41{
42 if (!Renderer::isSingletonInitialized())
43 {
44 throw std::logic_error("Renderer needs to be initialized");
45 }
46
47 glBindTexture(GL_TEXTURE_2D, texture_.getId());
48 unsigned char* data = stbi_load(filename, &width_, &height_, 0, 4);
49 flipImageData(data, width_, height_, 4);
50 glTexImage2D(
51 GL_TEXTURE_2D,
52 0,
53 GL_RGBA,
54 width_,
55 height_,
56 0,
57 GL_RGBA,
58 GL_UNSIGNED_BYTE,
59 data);
60
61 stbi_image_free(data);
62 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
63 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
64 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
65 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
66}
67
68Texture::Texture(
69 const Texture& tex) :
70 width_(tex.width_),
71 height_(tex.height_)
72{
73 if (!Renderer::isSingletonInitialized())
74 {
75 throw std::logic_error("Renderer needs to be initialized");
76 }
77
78 unsigned char* data = new unsigned char[4 * width_ * height_];
79 glBindTexture(GL_TEXTURE_2D, tex.getId());
80 glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
81
82 glBindTexture(GL_TEXTURE_2D, texture_.getId());
83 glTexImage2D(
84 GL_TEXTURE_2D,
85 0,
86 GL_RGBA,
87 width_,
88 height_,
89 0,
90 GL_RGBA,
91 GL_UNSIGNED_BYTE,
92 data);
93
94 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
95 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
96 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
97 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
98
99 delete[] data;
100}
101
102Texture::Texture(Texture&& tex) : Texture(0, 0)
103{
104 swap(*this, tex);
105}
106
107Texture& Texture::operator= (Texture tex)
108{
109 swap(*this, tex);
110
111 return *this;
112}
113
114void swap(Texture& tex1, Texture& tex2)
115{
116 std::swap(tex1.width_, tex2.width_);
117 std::swap(tex1.height_, tex2.height_);
118 std::swap(tex1.texture_, tex2.texture_);
119}
120
121Rectangle Texture::entirety() const
122{
123 return {0, 0, width_, height_};
124}
diff --git a/src/renderer/texture.h b/src/renderer/texture.h new file mode 100644 index 0000000..3aa8773 --- /dev/null +++ b/src/renderer/texture.h
@@ -0,0 +1,52 @@
1#ifndef TEXTURE_H_84EC6DF6
2#define TEXTURE_H_84EC6DF6
3
4#include "wrappers.h"
5
6struct Rectangle {
7 int x;
8 int y;
9 int w;
10 int h;
11};
12
13class Texture {
14public:
15
16 Texture(int width, int height);
17
18 Texture(const char* file);
19
20 Texture(const Texture& tex);
21
22 Texture(Texture&& tex);
23
24 Texture& operator= (Texture tex);
25
26 friend void swap(Texture& tex1, Texture& tex2);
27
28 Rectangle entirety() const;
29
30 inline GLuint getId() const
31 {
32 return texture_.getId();
33 }
34
35 inline int getWidth() const
36 {
37 return width_;
38 }
39
40 inline int getHeight() const
41 {
42 return height_;
43 }
44
45private:
46
47 GLTexture texture_;
48 int width_;
49 int height_;
50};
51
52#endif /* end of include guard: TEXTURE_H_84EC6DF6 */
diff --git a/src/renderer/wrappers.h b/src/renderer/wrappers.h new file mode 100644 index 0000000..c6edc11 --- /dev/null +++ b/src/renderer/wrappers.h
@@ -0,0 +1,273 @@
1#ifndef WRAPPERS_H_1EE0965B
2#define WRAPPERS_H_1EE0965B
3
4#include "gl.h"
5#include <utility>
6
7class GLVertexArray {
8public:
9
10 GLVertexArray()
11 {
12 glGenVertexArrays(1, &id_);
13 }
14
15 GLVertexArray(const GLVertexArray& other) = delete;
16 GLVertexArray& operator=(const GLVertexArray& other) = delete;
17
18 GLVertexArray(GLVertexArray&& other) : GLVertexArray()
19 {
20 std::swap(id_, other.id_);
21 }
22
23 GLVertexArray& operator=(GLVertexArray&& other)
24 {
25 std::swap(id_, other.id_);
26
27 return *this;
28 }
29
30 ~GLVertexArray()
31 {
32 glDeleteVertexArrays(1, &id_);
33 }
34
35 inline GLuint getId() const
36 {
37 return id_;
38 }
39
40private:
41
42 GLuint id_;
43};
44
45class GLFramebuffer {
46public:
47
48 GLFramebuffer()
49 {
50 glGenFramebuffers(1, &id_);
51 }
52
53 GLFramebuffer(const GLFramebuffer& other) = delete;
54 GLFramebuffer& operator=(const GLFramebuffer& other) = delete;
55
56 GLFramebuffer(GLFramebuffer&& other) : GLFramebuffer()
57 {
58 std::swap(id_, other.id_);
59 }
60
61 GLFramebuffer& operator=(GLFramebuffer&& other)
62 {
63 std::swap(id_, other.id_);
64
65 return *this;
66 }
67
68 ~GLFramebuffer()
69 {
70 glDeleteFramebuffers(1, &id_);
71 }
72
73 inline GLuint getId() const
74 {
75 return id_;
76 }
77
78private:
79
80 GLuint id_;
81};
82
83class GLRenderbuffer {
84public:
85
86 GLRenderbuffer()
87 {
88 glGenRenderbuffers(1, &id_);
89 }
90
91 GLRenderbuffer(const GLRenderbuffer& other) = delete;
92 GLRenderbuffer& operator=(const GLRenderbuffer& other) = delete;
93
94 GLRenderbuffer(GLRenderbuffer&& other) : GLRenderbuffer()
95 {
96 std::swap(id_, other.id_);
97 }
98
99 GLRenderbuffer& operator=(GLRenderbuffer&& other)
100 {
101 std::swap(id_, other.id_);
102
103 return *this;
104 }
105
106 ~GLRenderbuffer()
107 {
108 glDeleteRenderbuffers(1, &id_);
109 }
110
111 inline GLuint getId() const
112 {
113 return id_;
114 }
115
116private:
117
118 GLuint id_;
119};
120
121class GLBuffer {
122public:
123
124 GLBuffer()
125 {
126 glGenBuffers(1, &id_);
127 }
128
129 GLBuffer(const GLBuffer& other) = delete;
130 GLBuffer& operator=(const GLBuffer& other) = delete;
131
132 GLBuffer(GLBuffer&& other) : GLBuffer()
133 {
134 std::swap(id_, other.id_);
135 }
136
137 GLBuffer& operator=(GLBuffer&& other)
138 {
139 std::swap(id_, other.id_);
140
141 return *this;
142 }
143
144 ~GLBuffer()
145 {
146 glDeleteBuffers(1, &id_);
147 }
148
149 inline GLuint getId() const
150 {
151 return id_;
152 }
153
154private:
155
156 GLuint id_;
157};
158
159class GLTexture {
160public:
161
162 GLTexture()
163 {
164 glGenTextures(1, &id_);
165 }
166
167 GLTexture(const GLTexture& other) = delete;
168 GLTexture& operator=(const GLTexture& other) = delete;
169
170 GLTexture(GLTexture&& other) : GLTexture()
171 {
172 std::swap(id_, other.id_);
173 }
174
175 GLTexture& operator=(GLTexture&& other)
176 {
177 std::swap(id_, other.id_);
178
179 return *this;
180 }
181
182 ~GLTexture()
183 {
184 glDeleteTextures(1, &id_);
185 }
186
187 inline GLuint getId() const
188 {
189 return id_;
190 }
191
192private:
193
194 GLuint id_;
195};
196
197class GLShader {
198public:
199
200 GLShader(GLenum type)
201 {
202 id_ = glCreateShader(type);
203 }
204
205 GLShader(const GLShader& other) = delete;
206 GLShader& operator=(const GLShader& other) = delete;
207
208 GLShader(GLShader&& other) : GLShader(GL_VERTEX_SHADER)
209 {
210 std::swap(id_, other.id_);
211 }
212
213 GLShader& operator=(GLShader&& other)
214 {
215 std::swap(id_, other.id_);
216
217 return *this;
218 }
219
220 ~GLShader()
221 {
222 glDeleteShader(id_);
223 }
224
225 inline GLuint getId() const
226 {
227 return id_;
228 }
229
230private:
231
232 GLuint id_;
233};
234
235class GLProgram {
236public:
237
238 GLProgram()
239 {
240 id_ = glCreateProgram();
241 }
242
243 GLProgram(const GLProgram& other) = delete;
244 GLProgram& operator=(const GLProgram& other) = delete;
245
246 GLProgram(GLProgram&& other) : GLProgram()
247 {
248 std::swap(id_, other.id_);
249 }
250
251 GLProgram& operator=(GLProgram&& other)
252 {
253 std::swap(id_, other.id_);
254
255 return *this;
256 }
257
258 ~GLProgram()
259 {
260 glDeleteProgram(id_);
261 }
262
263 inline GLuint getId() const
264 {
265 return id_;
266 }
267
268private:
269
270 GLuint id_;
271};
272
273#endif /* end of include guard: WRAPPERS_H_1EE0965B */
diff --git a/src/systems/animating.cpp b/src/systems/animating.cpp index 91fe925..22224c9 100644 --- a/src/systems/animating.cpp +++ b/src/systems/animating.cpp
@@ -51,8 +51,9 @@ void AnimatingSystem::render(Texture& texture)
51 transform.getH()}; 51 transform.getH()};
52 52
53 const AnimationSet& aset = sprite.getAnimationSet(); 53 const AnimationSet& aset = sprite.getAnimationSet();
54 texture.blit( 54 game_.getRenderer().blit(
55 aset.getTexture(), 55 aset.getTexture(),
56 texture,
56 aset.getFrameRect(sprite.getFrame()), 57 aset.getFrameRect(sprite.getFrame()),
57 dstrect); 58 dstrect);
58 } 59 }
diff --git a/src/systems/animating.h b/src/systems/animating.h index d6a89a5..548bff1 100644 --- a/src/systems/animating.h +++ b/src/systems/animating.h
@@ -3,7 +3,7 @@
3 3
4#include "system.h" 4#include "system.h"
5#include <string> 5#include <string>
6#include "renderer.h" 6#include "renderer/texture.h"
7 7
8class AnimatingSystem : public System { 8class AnimatingSystem : public System {
9public: 9public:
diff --git a/src/systems/mapping.cpp b/src/systems/mapping.cpp index 5b63ded..120a27a 100644 --- a/src/systems/mapping.cpp +++ b/src/systems/mapping.cpp
@@ -48,7 +48,11 @@ void MappingSystem::render(Texture& texture)
48 TILE_WIDTH, 48 TILE_WIDTH,
49 TILE_HEIGHT}; 49 TILE_HEIGHT};
50 50
51 texture.blit(mappable.getTileset(), std::move(src), std::move(dst)); 51 game_.getRenderer().blit(
52 mappable.getTileset(),
53 texture,
54 std::move(src),
55 std::move(dst));
52 } 56 }
53 } 57 }
54 58
@@ -67,7 +71,11 @@ void MappingSystem::render(Texture& texture)
67 TILE_WIDTH, 71 TILE_WIDTH,
68 TILE_HEIGHT}; 72 TILE_HEIGHT};
69 73
70 texture.blit(mappable.getFont(), std::move(src), std::move(dst)); 74 game_.getRenderer().blit(
75 mappable.getFont(),
76 texture,
77 std::move(src),
78 std::move(dst));
71 } 79 }
72 } 80 }
73} 81}
diff --git a/src/util.cpp b/src/util.cpp new file mode 100644 index 0000000..f0c39fd --- /dev/null +++ b/src/util.cpp
@@ -0,0 +1,30 @@
1#include "util.h"
2
3std::string slurp(std::ifstream& in)
4{
5 std::stringstream sstr;
6 sstr << in.rdbuf();
7 return sstr.str();
8}
9
10void flipImageData(
11 unsigned char* data,
12 int width,
13 int height,
14 int comps)
15{
16 unsigned char* dataCopy = new unsigned char[width * height * comps];
17 memcpy(dataCopy, data, width * height * comps);
18
19 int rowSize = width * comps;
20
21 for (int i = 0; i < height; i++)
22 {
23 memcpy(
24 data + (rowSize * i),
25 dataCopy + (rowSize * (height - i - 1)),
26 rowSize);
27 }
28
29 delete[] dataCopy;
30}
diff --git a/src/util.h b/src/util.h new file mode 100644 index 0000000..72cb0d3 --- /dev/null +++ b/src/util.h
@@ -0,0 +1,41 @@
1#ifndef ALGORITHMS_H_1DDC517E
2#define ALGORITHMS_H_1DDC517E
3
4#include <fstream>
5#include <sstream>
6#include <cstring>
7
8template< typename ContainerT, typename PredicateT >
9void erase_if( ContainerT& items, const PredicateT& predicate ) {
10 for( auto it = items.begin(); it != items.end(); ) {
11 if( predicate(*it) ) it = items.erase(it);
12 else ++it;
13 }
14};
15
16struct chlit
17{
18 chlit(char c) : c_(c) { }
19 char c_;
20};
21
22inline std::istream& operator>>(std::istream& is, chlit x)
23{
24 char c;
25 if (is >> c && c != x.c_)
26 {
27 is.setstate(std::iostream::failbit);
28 }
29
30 return is;
31}
32
33std::string slurp(std::ifstream& in);
34
35void flipImageData(
36 unsigned char* data,
37 int width,
38 int height,
39 int comps);
40
41#endif /* end of include guard: ALGORITHMS_H_1DDC517E */