Addsd the text renderer and internal font (Open-Sans.ttf)
Some graphics testing code added to the core game loopGui_Panel_Refactor
parent
6afa6d8505
commit
7919f34d01
@ -0,0 +1,36 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* File - InternalFont.h
|
||||||
|
* Author - Joey Pollack
|
||||||
|
* Date - 2020/01/08 (y/m/d)
|
||||||
|
* Mod Date - 2021/09/07 (y/m/d)
|
||||||
|
* Description - Generates a font file (from OpenSans-Regular.ttf)
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#include "InternalFont.h"
|
||||||
|
#include "InternalFontData.h"
|
||||||
|
#include <utils/logger.h>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
namespace lunarium
|
||||||
|
{
|
||||||
|
bool GenerateFontFileAt(const char * filename)
|
||||||
|
{
|
||||||
|
std::ofstream ofs(filename, std::ios_base::binary);
|
||||||
|
|
||||||
|
if (!ofs.is_open())
|
||||||
|
{
|
||||||
|
Logger::Log(LogCategory::GRAPHICS, LogLevel::WARNING, "Could not generate the default font file at: %s", filename);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ofs.write((const char*)FontData, DataSize);
|
||||||
|
|
||||||
|
ofs.close();
|
||||||
|
ofs.clear();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* File - InternalFont.h
|
||||||
|
* Author - Joey Pollack
|
||||||
|
* Date - 2020/01/08 (y/m/d)
|
||||||
|
* Mod Date - 2020/01/08 (y/m/d)
|
||||||
|
* Description - Generates a font file (from OpenSans-Regular.ttf)
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef INTERNAL_FONT_H_
|
||||||
|
#define INTERNAL_FONT_H_
|
||||||
|
|
||||||
|
namespace lunarium
|
||||||
|
{
|
||||||
|
bool GenerateFontFileAt(const char* filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // INTERNAL_FONT_H_
|
||||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,227 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* File - glText.cpp
|
||||||
|
* Author - Joey Pollack
|
||||||
|
* Date - 2021/09/07 (y/m/d)
|
||||||
|
* Mod Date - 2021/09/07 (y/m/d)
|
||||||
|
* Description - Used to load and manage fonts. Renders text using freetype
|
||||||
|
* and openGL.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#include "glText.h"
|
||||||
|
#include <utils/logger.h>
|
||||||
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
|
#include <glm/gtc/type_ptr.hpp>
|
||||||
|
|
||||||
|
#include <ft2build.h>
|
||||||
|
#include FT_FREETYPE_H
|
||||||
|
|
||||||
|
namespace lunarium
|
||||||
|
{
|
||||||
|
int glText::LoadFont(const char* fontFile, float size, int weight)
|
||||||
|
{
|
||||||
|
if (!mTextShader.IsBuilt())
|
||||||
|
{
|
||||||
|
Logger::Log(LogCategory::GRAPHICS, LogLevel::ERROR, "Unable to load font because no text rendering shaders are loaded");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
FT_Library ft;
|
||||||
|
if (FT_Init_FreeType(&ft))
|
||||||
|
{
|
||||||
|
Logger::Log(LogCategory::GRAPHICS, LogLevel::ERROR, "FREETYPE: Could not init FreeType Library");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
FT_Face face;
|
||||||
|
if (FT_New_Face(ft, fontFile, 0, &face))
|
||||||
|
{
|
||||||
|
Logger::Log(LogCategory::GRAPHICS, LogLevel::ERROR, "FREETYPE: Failed to load font from file: %s", fontFile);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
FT_Set_Pixel_Sizes(face, 0, 48);
|
||||||
|
|
||||||
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // Disable byte-alignment restriction
|
||||||
|
|
||||||
|
// NOTE: Testing code
|
||||||
|
float sizes[128] = { 0.0f };
|
||||||
|
|
||||||
|
mFonts.push_back(Font());
|
||||||
|
int fontIdx = (int)(mFonts.size() - 1);
|
||||||
|
for (GLubyte c = 0; c < 128; c++)
|
||||||
|
{
|
||||||
|
// Load character glyph
|
||||||
|
if (FT_Load_Char(face, c, FT_LOAD_RENDER))
|
||||||
|
{
|
||||||
|
Logger::Log(LogCategory::GRAPHICS, LogLevel::ERROR, "FREETYTPE: Failed to load Glyph %c from font file %s", c, fontFile);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Generate texture
|
||||||
|
GLuint 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,
|
||||||
|
{ (float)face->glyph->bitmap.width, (float)face->glyph->bitmap.rows },
|
||||||
|
glm::vec2((float)face->glyph->bitmap_left, (float)face->glyph->bitmap_top),
|
||||||
|
(int)face->glyph->bitmap.rows - face->glyph->bitmap_top,
|
||||||
|
(unsigned int)face->glyph->advance.x
|
||||||
|
};
|
||||||
|
mFonts.back().CharSet.insert(std::pair<GLchar, Character>(c, character));
|
||||||
|
|
||||||
|
// Find Max (positive) Down Shift
|
||||||
|
if (character.DownShift > 0 && ((int)mFonts.back().MaxDownShift) < character.DownShift)
|
||||||
|
{
|
||||||
|
mFonts.back().MaxDownShift = character.DownShift;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determines the distance from the top down to the baseline
|
||||||
|
if (character.Size.Height == character.Bearing.y && mFonts.back().MaxHeight < character.Size.Height)
|
||||||
|
{
|
||||||
|
mFonts.back().MaxHeight = (unsigned int)character.Size.Height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FT_Done_Face(face);
|
||||||
|
FT_Done_FreeType(ft);
|
||||||
|
|
||||||
|
return fontIdx;
|
||||||
|
}
|
||||||
|
|
||||||
|
OpRes glText::Initialize()
|
||||||
|
{
|
||||||
|
glGenVertexArrays(1, &mTextVAO);
|
||||||
|
glGenBuffers(1, &mTextVBO);
|
||||||
|
glBindVertexArray(mTextVAO);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, mTextVBO);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 6 * 4, NULL, GL_DYNAMIC_DRAW);
|
||||||
|
glEnableVertexAttribArray(0);
|
||||||
|
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), 0);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
glBindVertexArray(0);
|
||||||
|
|
||||||
|
|
||||||
|
// Load text shaders
|
||||||
|
mTextShader.SetSource(glShader::TYPE_VERTEX, VertShader, false);
|
||||||
|
mTextShader.SetSource(glShader::TYPE_FRAGMENT, FragShader, false);
|
||||||
|
if (!mTextShader.BuildProgram())
|
||||||
|
{
|
||||||
|
return OpRes::Fail("Unable to build text shader program. Fonts will not load and text will not render.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return OpRes::OK();
|
||||||
|
}
|
||||||
|
|
||||||
|
void glText::DrawString(int fontID, const char* text, glm::vec2 position, Color color, float scale, glm::mat4 projection)
|
||||||
|
{
|
||||||
|
// HACK: There might be a better way to specify no limit to the bottom right
|
||||||
|
DrawString(fontID, text, position, glm::vec2(9000000.0f, 9000000.0f), color, scale, projection);
|
||||||
|
}
|
||||||
|
|
||||||
|
void glText::DrawString(int fontID, const char* text, glm::vec2 topLeft, glm::vec2 botRight, Color color, float scale, glm::mat4 projection)
|
||||||
|
{
|
||||||
|
if (!mTextShader.IsBuilt())
|
||||||
|
{
|
||||||
|
Logger::Log(LogCategory::GRAPHICS, LogLevel::ERROR, "Unable to draw string because no text rendering shaders are loaded");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fontID < 0 || fontID >= mFonts.size())
|
||||||
|
{
|
||||||
|
Logger::Log(LogCategory::GRAPHICS, LogLevel::ERROR, "Invalid font ID specified for DrawString: %d", fontID);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//glEnable(GL_BLEND);
|
||||||
|
//glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
|
// NOTE: String drawing code based on code from: https://learnopengl.com/In-Practice/Text-Rendering
|
||||||
|
mTextShader.MakeActive();
|
||||||
|
mTextShader.SetUniformMatrix("projection", 1, glm::value_ptr(projection));
|
||||||
|
mTextShader.SetUniformf("textColor", { color.Red, color.Green, color.Blue, color.Alpha });
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
glBindVertexArray(mTextVAO);
|
||||||
|
|
||||||
|
float lineSize = (mFonts[fontID].MaxHeight + mFonts[fontID].MaxDownShift) * scale;
|
||||||
|
|
||||||
|
float curX = topLeft.x;
|
||||||
|
float curY = topLeft.y;
|
||||||
|
|
||||||
|
// Iterate through all characters
|
||||||
|
int len = (int)strlen(text);
|
||||||
|
for (int c = 0; c < len; c++)
|
||||||
|
{
|
||||||
|
Character ch = mFonts[fontID].CharSet[text[c]];
|
||||||
|
|
||||||
|
GLfloat advance = (ch.Advance >> 6) * scale;
|
||||||
|
if (curX + advance > botRight.x)
|
||||||
|
{
|
||||||
|
curX = topLeft.x;
|
||||||
|
curY += lineSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (curY + lineSize > botRight.y)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
GLfloat xpos = curX + ch.Bearing.x * scale;
|
||||||
|
GLfloat ypos = curY + (mFonts[fontID].MaxHeight - ch.Size.Height) * scale;
|
||||||
|
|
||||||
|
// Apply a down offset if the char should go below the baseline
|
||||||
|
ypos += (ch.DownShift * scale);
|
||||||
|
|
||||||
|
// NOTE: The following code does not work because it assumes that positive y is the upward direction
|
||||||
|
//
|
||||||
|
//GLfloat test_ypos = curY + (ch.Size.Height - ch.Bearing.Y) * scale;
|
||||||
|
//
|
||||||
|
|
||||||
|
GLfloat w = ch.Size.Width * scale;
|
||||||
|
GLfloat h = ch.Size.Height * scale;
|
||||||
|
// Update VBO for each character
|
||||||
|
GLfloat vertices[6][4] = {
|
||||||
|
{ xpos, ypos + h, 0.0, 1.0 },
|
||||||
|
{ xpos + w, ypos, 1.0, 0.0 },
|
||||||
|
{ xpos, ypos, 0.0, 0.0 },
|
||||||
|
|
||||||
|
{ xpos, ypos + h, 0.0, 1.0 },
|
||||||
|
{ xpos + w, ypos + h, 1.0, 1.0 },
|
||||||
|
{ xpos + w, ypos, 1.0, 0.0 }
|
||||||
|
};
|
||||||
|
// Render glyph texture over quad
|
||||||
|
glBindTexture(GL_TEXTURE_2D, ch.TextureID);
|
||||||
|
// Update content of VBO memory
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, mTextVBO);
|
||||||
|
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
|
||||||
|
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)
|
||||||
|
curX += (ch.Advance >> 6) * scale; // Bitshift by 6 to get value in pixels (2^6 = 64)
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
glBindVertexArray(0);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,90 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* File - glText.h
|
||||||
|
* Author - Joey Pollack
|
||||||
|
* Date - 2021/09/07 (y/m/d)
|
||||||
|
* Mod Date - 2021/09/07 (y/m/d)
|
||||||
|
* Description - Used to load and manage fonts. Renders text using freetype
|
||||||
|
* and openGL.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef GL_TEXT_H_
|
||||||
|
#define GL_TEXT_H_
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
#include <glad/gl.h>
|
||||||
|
#include "glShader.h"
|
||||||
|
#include <utils/opRes.h>
|
||||||
|
#include <utils/types.h>
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
namespace lunarium
|
||||||
|
{
|
||||||
|
class glText
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
OpRes Initialize();
|
||||||
|
int LoadFont(const char* fontFile, float size = 12.0f, int weight = 400);
|
||||||
|
void DrawString(int fontID, const char* text, glm::vec2 position, Color color, float scale, glm::mat4 projection);
|
||||||
|
void DrawString(int fontID, const char* text, glm::vec2 topLeft, glm::vec2 botRight, Color color, float scale, glm::mat4 projection);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
struct Character
|
||||||
|
{
|
||||||
|
unsigned int TextureID; // ID handle of the glyph texture
|
||||||
|
Sizef Size; // Size of glyph
|
||||||
|
glm::vec2 Bearing; // Offset from baseline to left/top of glyph
|
||||||
|
int DownShift; // Size/Amount of glyph below the baseline
|
||||||
|
unsigned int Advance; // Offset to advance to next glyph
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Font
|
||||||
|
{
|
||||||
|
// The tallest character that does not go below the base line
|
||||||
|
// This is also the distance from the string Y position to the baseline
|
||||||
|
unsigned int MaxHeight;
|
||||||
|
|
||||||
|
// This is the max distance a char will go below the baseline
|
||||||
|
unsigned int MaxDownShift;
|
||||||
|
std::map<char, Character> CharSet;
|
||||||
|
Font() : MaxHeight(0), MaxDownShift(0)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<Font> mFonts;
|
||||||
|
|
||||||
|
GLuint mTextVAO;
|
||||||
|
GLuint mTextVBO;
|
||||||
|
glShader mTextShader;
|
||||||
|
|
||||||
|
private: // SHADER CODE
|
||||||
|
const char* VertShader = "#version 450 core\n\
|
||||||
|
layout(location = 0) in vec4 vertex; \
|
||||||
|
out vec2 TexCoords;\
|
||||||
|
\
|
||||||
|
uniform mat4 projection;\
|
||||||
|
\
|
||||||
|
void main()\
|
||||||
|
{\
|
||||||
|
gl_Position = projection * vec4(vertex.xy, 0.0, 1.0);\
|
||||||
|
TexCoords = vertex.zw;\
|
||||||
|
} ";
|
||||||
|
|
||||||
|
const char* FragShader = "#version 450 core\n\
|
||||||
|
in vec2 TexCoords;\
|
||||||
|
out vec4 color;\
|
||||||
|
\
|
||||||
|
uniform sampler2D text;\
|
||||||
|
uniform vec4 textColor;\
|
||||||
|
\
|
||||||
|
void main()\
|
||||||
|
{\
|
||||||
|
vec4 sampled = vec4(1.0, 1.0, 1.0, texture(text, TexCoords).r);\
|
||||||
|
color = vec4(textColor) * sampled;\
|
||||||
|
}";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // GL_TEXT_H_
|
||||||
Loading…
Reference in New Issue