Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // shader.h
- #ifndef SHADER_H
- #define SHADER_H
- #include <glad/glad.h>
- #include <glm/glm.hpp>
- #include <string>
- #include <fstream>
- #include <sstream>
- #include <iostream>
- class Shader
- {
- public:
- unsigned int ID;
- // constructor generates the shader on the fly
- // ------------------------------------------------------------------------
- Shader(const char* vertexPath, const char* fragmentPath, const char* geometryPath = nullptr)
- {
- // 1. retrieve the vertex/fragment source code from filePath
- std::string vertexCode;
- std::string fragmentCode;
- std::string geometryCode;
- std::ifstream vShaderFile;
- std::ifstream fShaderFile;
- std::ifstream gShaderFile;
- // ensure ifstream objects can throw exceptions:
- vShaderFile.exceptions (std::ifstream::failbit | std::ifstream::badbit);
- fShaderFile.exceptions (std::ifstream::failbit | std::ifstream::badbit);
- gShaderFile.exceptions (std::ifstream::failbit | std::ifstream::badbit);
- try
- {
- // open files
- vShaderFile.open(vertexPath);
- fShaderFile.open(fragmentPath);
- std::stringstream vShaderStream, fShaderStream;
- // read file's buffer contents into streams
- vShaderStream << vShaderFile.rdbuf();
- fShaderStream << fShaderFile.rdbuf();
- // close file handlers
- vShaderFile.close();
- fShaderFile.close();
- // convert stream into string
- vertexCode = vShaderStream.str();
- fragmentCode = fShaderStream.str();
- // if geometry shader path is present, also load a geometry shader
- if(geometryPath != nullptr)
- {
- gShaderFile.open(geometryPath);
- std::stringstream gShaderStream;
- gShaderStream << gShaderFile.rdbuf();
- gShaderFile.close();
- geometryCode = gShaderStream.str();
- }
- }
- catch (std::ifstream::failure& e)
- {
- std::cout << "ERROR::SHADER::FILE_NOT_SUCCESSFULLY_READ: " << e.what() << std::endl;
- }
- const char* vShaderCode = vertexCode.c_str();
- const char * fShaderCode = fragmentCode.c_str();
- // 2. compile shaders
- unsigned int vertex, fragment;
- // vertex shader
- vertex = glCreateShader(GL_VERTEX_SHADER);
- glShaderSource(vertex, 1, &vShaderCode, NULL);
- glCompileShader(vertex);
- checkCompileErrors(vertex, "VERTEX");
- // fragment Shader
- fragment = glCreateShader(GL_FRAGMENT_SHADER);
- glShaderSource(fragment, 1, &fShaderCode, NULL);
- glCompileShader(fragment);
- checkCompileErrors(fragment, "FRAGMENT");
- // if geometry shader is given, compile geometry shader
- unsigned int geometry;
- if(geometryPath != nullptr)
- {
- const char * gShaderCode = geometryCode.c_str();
- geometry = glCreateShader(GL_GEOMETRY_SHADER);
- glShaderSource(geometry, 1, &gShaderCode, NULL);
- glCompileShader(geometry);
- checkCompileErrors(geometry, "GEOMETRY");
- }
- // shader Program
- ID = glCreateProgram();
- glAttachShader(ID, vertex);
- glAttachShader(ID, fragment);
- if(geometryPath != nullptr)
- glAttachShader(ID, geometry);
- glLinkProgram(ID);
- checkCompileErrors(ID, "PROGRAM");
- // delete the shaders as they're linked into our program now and no longer necessary
- glDeleteShader(vertex);
- glDeleteShader(fragment);
- if(geometryPath != nullptr)
- glDeleteShader(geometry);
- }
- // activate the shader
- // ------------------------------------------------------------------------
- void use()
- {
- glUseProgram(ID);
- }
- // utility uniform functions
- // ------------------------------------------------------------------------
- void setBool(const std::string &name, bool value) const
- {
- glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value);
- }
- // ------------------------------------------------------------------------
- void setInt(const std::string &name, int value) const
- {
- glUniform1i(glGetUniformLocation(ID, name.c_str()), value);
- }
- // ------------------------------------------------------------------------
- void setFloat(const std::string &name, float value) const
- {
- glUniform1f(glGetUniformLocation(ID, name.c_str()), value);
- }
- // ------------------------------------------------------------------------
- void setVec2(const std::string &name, const glm::vec2 &value) const
- {
- glUniform2fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
- }
- void setVec2(const std::string &name, float x, float y) const
- {
- glUniform2f(glGetUniformLocation(ID, name.c_str()), x, y);
- }
- // ------------------------------------------------------------------------
- void setVec3(const std::string &name, const glm::vec3 &value) const
- {
- glUniform3fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
- }
- void setVec3(const std::string &name, float x, float y, float z) const
- {
- glUniform3f(glGetUniformLocation(ID, name.c_str()), x, y, z);
- }
- // ------------------------------------------------------------------------
- void setVec4(const std::string &name, const glm::vec4 &value) const
- {
- glUniform4fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
- }
- void setVec4(const std::string &name, float x, float y, float z, float w)
- {
- glUniform4f(glGetUniformLocation(ID, name.c_str()), x, y, z, w);
- }
- // ------------------------------------------------------------------------
- void setMat2(const std::string &name, const glm::mat2 &mat) const
- {
- glUniformMatrix2fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]);
- }
- // ------------------------------------------------------------------------
- void setMat3(const std::string &name, const glm::mat3 &mat) const
- {
- glUniformMatrix3fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]);
- }
- // ------------------------------------------------------------------------
- void setMat4(const std::string &name, const glm::mat4 &mat) const
- {
- glUniformMatrix4fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]);
- }
- private:
- // utility function for checking shader compilation/linking errors.
- // ------------------------------------------------------------------------
- void checkCompileErrors(GLuint shader, std::string type)
- {
- GLint success;
- GLchar infoLog[1024];
- if(type != "PROGRAM")
- {
- glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
- if(!success)
- {
- glGetShaderInfoLog(shader, 1024, NULL, infoLog);
- std::cout << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;
- }
- }
- else
- {
- glGetProgramiv(shader, GL_LINK_STATUS, &success);
- if(!success)
- {
- glGetProgramInfoLog(shader, 1024, NULL, infoLog);
- std::cout << "ERROR::PROGRAM_LINKING_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;
- }
- }
- }
- };
- #endif
- // text_rendering.cpp
- #include <iostream>
- #include <map>
- #include <string>
- #include <glad/glad.h>
- #include <GLFW/glfw3.h>
- #include <glm/glm.hpp>
- #include <glm/gtc/matrix_transform.hpp>
- #include <glm/gtc/type_ptr.hpp>
- #include <ft2build.h>
- #include FT_FREETYPE_H
- #include <learnopengl/shader.h>
- void framebuffer_size_callback(GLFWwindow* window, int width, int height);
- void processInput(GLFWwindow *window);
- void RenderText(Shader &shader, std::string text, float x, float y, float scale, glm::vec3 color);
- // settings
- const unsigned int SCR_WIDTH = 800;
- const unsigned int SCR_HEIGHT = 600;
- /// Holds all state information relevant to a character as loaded using FreeType
- struct Character {
- unsigned int TextureID; // ID handle of the glyph texture
- glm::ivec2 Size; // Size of glyph
- glm::ivec2 Bearing; // Offset from baseline to left/top of glyph
- unsigned int Advance; // Horizontal offset to advance to next glyph
- };
- std::map<GLchar, Character> Characters;
- unsigned int VAO, VBO;
- int main()
- {
- // glfw: initialize and configure
- // ------------------------------
- glfwInit();
- glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
- glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
- glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
- #ifdef __APPLE__
- glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
- #endif
- // glfw window creation
- // --------------------
- GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
- if (window == NULL)
- {
- std::cout << "Failed to create GLFW window" << std::endl;
- glfwTerminate();
- return -1;
- }
- glfwMakeContextCurrent(window);
- glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
- // glad: load all OpenGL function pointers
- // ---------------------------------------
- if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
- {
- std::cout << "Failed to initialize GLAD" << std::endl;
- return -1;
- }
- // OpenGL state
- // ------------
- glEnable(GL_CULL_FACE);
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- // compile and setup the shader
- // ----------------------------
- Shader shader("text.vs", "text.fs");
- glm::mat4 projection = glm::ortho(0.0f, static_cast<float>(SCR_WIDTH), 0.0f, static_cast<float>(SCR_HEIGHT));
- shader.use();
- glUniformMatrix4fv(glGetUniformLocation(shader.ID, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
- // FreeType
- // --------
- FT_Library ft;
- // All functions return a value different than 0 whenever an error occurred
- if (FT_Init_FreeType(&ft))
- {
- std::cout << "ERROR::FREETYPE: Could not init FreeType Library" << std::endl;
- return -1;
- }
- // find path to font
- std::string font_name = FileSystem::getPath("resources/fonts/Antonio-Bold.ttf");
- if (font_name.empty())
- {
- std::cout << "ERROR::FREETYPE: Failed to load font_name" << std::endl;
- return -1;
- }
- // load font as face
- FT_Face face;
- if (FT_New_Face(ft, font_name.c_str(), 0, &face)) {
- std::cout << "ERROR::FREETYPE: Failed to load font" << std::endl;
- return -1;
- }
- else {
- // set size to load glyphs as
- FT_Set_Pixel_Sizes(face, 0, 48);
- // disable byte-alignment restriction
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
- // load first 128 characters of ASCII set
- for (unsigned char c = 0; c < 128; c++)
- {
- // Load character glyph
- if (FT_Load_Char(face, c, FT_LOAD_RENDER))
- {
- std::cout << "ERROR::FREETYTPE: Failed to load Glyph" << std::endl;
- continue;
- }
- // generate texture
- 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
- );
- // set texture options
- 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);
- // now store character for later use
- Character character = {
- texture,
- glm::ivec2(face->glyph->bitmap.width, face->glyph->bitmap.rows),
- glm::ivec2(face->glyph->bitmap_left, face->glyph->bitmap_top),
- static_cast<unsigned int>(face->glyph->advance.x)
- };
- Characters.insert(std::pair<char, Character>(c, character));
- }
- glBindTexture(GL_TEXTURE_2D, 0);
- }
- // destroy FreeType once we're finished
- FT_Done_Face(face);
- FT_Done_FreeType(ft);
- // configure VAO/VBO for texture quads
- // -----------------------------------
- glGenVertexArrays(1, &VAO);
- glGenBuffers(1, &VBO);
- glBindVertexArray(VAO);
- glBindBuffer(GL_ARRAY_BUFFER, VBO);
- 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);
- // render loop
- // -----------
- while (!glfwWindowShouldClose(window))
- {
- // input
- // -----
- processInput(window);
- // render
- // ------
- glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
- glClear(GL_COLOR_BUFFER_BIT);
- RenderText(shader, "Hello World!", 25.0f, 25.0f, 1.0f, glm::vec3(0.5, 0.8f, 0.2f));
- // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
- // -------------------------------------------------------------------------------
- glfwSwapBuffers(window);
- glfwPollEvents();
- }
- glfwTerminate();
- return 0;
- }
- // process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
- // ---------------------------------------------------------------------------------------------------------
- void processInput(GLFWwindow *window)
- {
- if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
- glfwSetWindowShouldClose(window, true);
- }
- // glfw: whenever the window size changed (by OS or user resize) this callback function executes
- // ---------------------------------------------------------------------------------------------
- void framebuffer_size_callback(GLFWwindow* window, int width, int height)
- {
- // make sure the viewport matches the new window dimensions; note that width and
- // height will be significantly larger than specified on retina displays.
- glViewport(0, 0, width, height);
- }
- // render line of text
- // -------------------
- void RenderText(Shader &shader, std::string text, float x, float y, float scale, glm::vec3 color)
- {
- // activate corresponding render state
- shader.use();
- glUniform3f(glGetUniformLocation(shader.ID, "textColor"), color.x, color.y, color.z);
- glActiveTexture(GL_TEXTURE0);
- glBindVertexArray(VAO);
- // iterate through all characters
- std::string::const_iterator c;
- for (c = text.begin(); c != text.end(); c++)
- {
- Character ch = Characters[*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;
- // update VBO for each character
- float vertices[6][4] = {
- { 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 }
- };
- // render glyph texture over quad
- glBindTexture(GL_TEXTURE_2D, ch.TextureID);
- // update content of VBO memory
- glBindBuffer(GL_ARRAY_BUFFER, VBO);
- glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices); // be sure to use glBufferSubData and not glBufferData
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- // render quad
- glDrawArrays(GL_TRIANGLES, 0, 6);
- // now advance cursors for next glyph (note that advance is number of 1/64 pixels)
- x += (ch.Advance >> 6) * scale; // bitshift by 6 to get value in pixels (2^6 = 64 (divide amount of 1/64th pixels by 64 to get amount of pixels))
- }
- glBindVertexArray(0);
- glBindTexture(GL_TEXTURE_2D, 0);
- }
- // Credit: https://learnopengl.com/In-Practice/Text-Rendering
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement