diff --git a/Makefile b/Makefile index 6aa8420..13989d5 100644 --- a/Makefile +++ b/Makefile @@ -1,15 +1,16 @@ CC := g++ CFLAGS := -std=c++17 -O3 LDFLAGS := -ldl -lglfw +INCLUDES := -I/usr/include/freetype2/ -I/usr/include/libpng16 -ghostland: glad.o ghostland.o stb_image.o collisions.o player.o shader.o ghost.o - $(CC) -o ghostland glad.o ghostland.o stb_image.o collisions.o player.o shader.o ghost.o $(LDFLAGS) $(CFLAGS) +ghostland: glad.o ghostland.o stb_image.o collisions.o player.o shader.o ghost.o text.o + $(CC) -o ghostland glad.o ghostland.o stb_image.o collisions.o player.o shader.o ghost.o text.o /usr/lib/x86_64-linux-gnu/libfreetype.so $(LDFLAGS) $(CFLAGS) glad.o: glad.c $(CC) -c -o glad.o glad.c $(CFLAGS) ghostland.o: ghostland.cpp - $(CC) -c -o ghostland.o ghostland.cpp $(CFLAGS) + $(CC) -c -o ghostland.o ghostland.cpp $(CFLAGS) $(INCLUDES) stb_image.o: stb_image.c $(CC) -c -o stb_image.o stb_image.c $(CFLAGS) @@ -26,5 +27,8 @@ shader.o: shader.cpp shader.h ghost.o: ghost.cpp ghost.h $(CC) -c -o ghost.o ghost.cpp $(CFLAGS) +text.o: text.cpp text.h + $(CC) -c -o text.o text.cpp $(CFLAGS) $(INCLUDES) + clean: rm -f *.o ghostland diff --git a/ghostland.cpp b/ghostland.cpp index 62f31f1..76044d5 100644 --- a/ghostland.cpp +++ b/ghostland.cpp @@ -2,6 +2,7 @@ #include #include #include + #include #include @@ -17,6 +18,7 @@ #include "player.h" #include "shader.h" #include "ghost.h" +#include "text.h" void framebuffer_size_callback(GLFWwindow* window, int width, int height); void mouse_callback(GLFWwindow* window, double xpos, double ypos); @@ -172,7 +174,7 @@ int main(int argc, char *argv[]) } glEnable(GL_DEPTH_TEST); - + //glEnable(GL_CULL_FACE); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); @@ -314,6 +316,14 @@ int main(int argc, char *argv[]) glGenerateMipmap(GL_TEXTURE_2D); stbi_image_free(ghost_data); + // do stuff for text + int text_program; + if (init_text(&text_program) < 0) { + printf("Failed to load text module!\n"); + glfwTerminate(); + return -1; + } + // TODO move these into config file?? int time_secI = 0, num_frames = 1; float time_sec; @@ -333,13 +343,16 @@ int main(int argc, char *argv[]) ghosts.push_back(new Ghost(xmin_wall, xmax_wall, zmin_wall, zmax_wall)); } - player->mouse_callback(window, WINDOWWIDTH/2, WINDOWHEIGHT/2); + player->mouse_callback(window, WINDOWWIDTH, WINDOWHEIGHT); + + int FPS = -1; while (!glfwWindowShouldClose(window)) { float current_frame = static_cast(glfwGetTime()); int current_frameI = (int)current_frame; - if (current_frameI != time_secI) { + if (current_frameI != time_secI) { // show stats every second + FPS = num_frames; glm::vec3 player_pos = player->get_position(); float yaw, pitch; yaw = player->get_yaw(); @@ -358,7 +371,7 @@ int main(int argc, char *argv[]) if (trail_sz < trailmax) { trail_sz++; } - } else { + } else { // otherwise increase number of frames num_frames++; } timed = current_frame - last_frame; @@ -463,6 +476,15 @@ int main(int argc, char *argv[]) glDrawArrays(GL_TRIANGLES, 0, (3 + 3 + 2) * 6); } + if (FPS != -1) { + glUseProgram(text_program); + projection = glm::ortho(0.0f, static_cast(WINDOWWIDTH), 0.0f, static_cast(WINDOWHEIGHT)); + set_uniform(text_program, projectionC, projection); + char fps_buff[256]; + sprintf(fps_buff, "FPS: %d", FPS); + render_text(text_program, std::string(fps_buff), 25.0F, WINDOWHEIGHT - 35.0f, 0.5f, glm::vec3(1.0f, 0.0f, 0.0f)); + } + player->apply_movement(timed); glfwSwapBuffers(window); diff --git a/maze.txt b/maze.txt index efb67c2..c6dc10b 100644 --- a/maze.txt +++ b/maze.txt @@ -1,4 +1,4 @@ -845.0 2.5 -5.0 270.0 +845.0 2.5 -5.0 0.0 6498 -0.5 0.0 0.5 0.0 0.0 1.0 959.5 0.0 0.5 0.0 0.0 1.0 diff --git a/text.cpp b/text.cpp new file mode 100644 index 0000000..a472179 --- /dev/null +++ b/text.cpp @@ -0,0 +1,141 @@ +#include +#include +#include + +#include "text.h" +#include "shader.h" + +FT_Library ft; +FT_Face face; + +const char *textcolorC = "textColor"; + +unsigned int textVAO, textVBO; + +struct character_t { + unsigned int texture_id; + glm::ivec2 size; + glm::ivec2 bearing; + unsigned int advance; +}; + +std::map glyph_to_character; + +int init_text(int *shader) { + + if (FT_Init_FreeType(&ft)) { + printf("Could not init freetype library.\n"); + return -1; + } + + if (FT_New_Face(ft, "fonts/LiberationSerif-Regular.ttf", 0, &face)) { + printf("Could not font face.\n"); + return -1; + } + + FT_Set_Pixel_Sizes(face, 0, 48); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + for (unsigned char c = 0; c < 128; c++) { + + if (FT_Load_Char(face, c, FT_LOAD_RENDER)) { + printf("Failed to load glyph: %c\n", c); + return -1; + } + + unsigned int texture; + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RED, + face->glyph->bitmap.width, + face->glyph->bitmap.rows, + 0, + GL_RED, + GL_UNSIGNED_BYTE, + face->glyph->bitmap.buffer + ); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + character_t character = { + texture, + glm::ivec2(face->glyph->bitmap.width, face->glyph->bitmap.rows), + glm::ivec2(face->glyph->bitmap_left, face->glyph->bitmap_top), + static_cast(face->glyph->advance.x), + }; + + glyph_to_character.insert(std::pair(c, character)); + + } + + glBindTexture(GL_TEXTURE_2D, 0); + + FT_Done_Face(face); + FT_Done_FreeType(ft); + + // configure textVAO/textVBO for texture quads + // ----------------------------------- + glGenVertexArrays(1, &textVAO); + glGenBuffers(1, &textVBO); + glBindVertexArray(textVAO); + glBindBuffer(GL_ARRAY_BUFFER, textVBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 4, NULL, GL_DYNAMIC_DRAW); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(0); + + *shader = create_shader_program("textshader.glsl", "textfragshader.glsl"); + if (*shader < 0) { + printf("Got error compiling text shader!\n"); + return -1; + } + + return 0; + +} + +void render_text(int shader, std::string text, float x, float y, float scale, glm::vec3 color) { + + set_uniform(shader, textcolorC, color); + glActiveTexture(GL_TEXTURE0); + glBindVertexArray(textVAO); + + std::string::const_iterator c; + for (c = text.begin(); c != text.end(); c++) { + character_t ch = glyph_to_character[*c]; + + float xpos = x + ch.bearing.x * scale; + float ypos = y - (ch.size.y - ch.bearing.y) * scale; + + float w = ch.size.x * scale; + float h = ch.size.y * scale; + + float vertices[24] = { + xpos, ypos + h, 0.0f, 0.0f, + xpos, ypos, 0.0f, 1.0f, + xpos + w, ypos, 1.0f, 1.0f, + xpos, ypos + h, 0.0f, 0.0f, + xpos + w, ypos, 1.0f, 1.0f, + xpos + w, ypos + h, 1.0f, 0.0f, + }; + glBindTexture(GL_TEXTURE_2D, ch.texture_id); + glBindBuffer(GL_ARRAY_BUFFER, textVBO); + glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float) * (2 + 2) * 6, vertices); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glDrawArrays(GL_TRIANGLES, 0, (2 + 2) * 6); + + x += (ch.advance >> 6) * scale; + + } + + glBindVertexArray(0); + glBindTexture(GL_TEXTURE_2D, 0); + +} diff --git a/text.h b/text.h new file mode 100644 index 0000000..365cea5 --- /dev/null +++ b/text.h @@ -0,0 +1,13 @@ +#ifndef TEXT_H +#define TEXT_H + +#include +#include + +#include +#include FT_FREETYPE_H + +int init_text(int *shader); +void render_text(int shader, std::string text, float x, float y, float scale, glm::vec3 color); + +#endif diff --git a/textfragshader.glsl b/textfragshader.glsl new file mode 100644 index 0000000..b11904a --- /dev/null +++ b/textfragshader.glsl @@ -0,0 +1,12 @@ +#version 460 core +in vec2 TexCoords; +out vec4 color; + +uniform sampler2D text; +uniform vec3 textColor; + +void main() +{ + vec4 sampled = vec4(1.0, 1.0, 1.0, texture(text, TexCoords).r); + color = vec4(textColor, 1.0) * sampled; +} diff --git a/textshader.glsl b/textshader.glsl new file mode 100644 index 0000000..177eef4 --- /dev/null +++ b/textshader.glsl @@ -0,0 +1,11 @@ +#version 460 core +layout (location = 0) in vec4 vertex; // +out vec2 TexCoords; + +uniform mat4 projection; + +void main() +{ + gl_Position = projection * vec4(vertex.xy, 0.0f, 1.0); + TexCoords = vertex.zw; +}