Skip to content

Instantly share code, notes, and snippets.

@tylerreisinger
Created April 6, 2018 20:57
Show Gist options
  • Save tylerreisinger/3f9748e88b882330a335952be31c7cc0 to your computer and use it in GitHub Desktop.
Save tylerreisinger/3f9748e88b882330a335952be31c7cc0 to your computer and use it in GitHub Desktop.
SpriteFont class cpp
/*
* SpriteFont.cpp
*
* Created on: Dec 1, 2012
* Author: tyler
*/
#include "SpriteFont.h"
#include "FontFace.h"
#include "Rectangle.h"
SpriteFont::SpriteFont(FontFace* face)
{
int characterWidth = face->MaxAdvanceWidth();
int characterHeight = face->Height();
int charCount = 127 - 32;
int textureWidth = 512;
int charactersPerLine = textureWidth / characterWidth;
int lines = std::ceil(static_cast<float>(charCount) / charactersPerLine + 1);
int textureHeight = std::pow(2, std::ceil(std::log2(lines * characterWidth)));
unsigned char characters[charCount + 1];
for(int ch = 33; ch < 128; ++ch)
{
characters[ch - 33] = ch;
}
m_charPositions.reserve(charCount);
unsigned int* bitmap = new unsigned int[textureWidth * textureHeight];
FT_Face faceObj = face->GetFreeTypeFaceObject();
int xCursor = 0;
int yCursor = 0;
for(int i = 0; i < charCount; ++i)
{
FT_Load_Char(faceObj, characters[i], FT_LOAD_RENDER);
int belowBaseline = faceObj->glyph->bitmap_top - faceObj->glyph->bitmap.rows;
if(belowBaseline > 0)
{
belowBaseline = 0;
}
for(int y = 0; y < faceObj->glyph->bitmap.rows; ++y)
{
for(int x = 0; x < faceObj->glyph->bitmap.width; ++x)
{
int position = textureWidth * ((yCursor + characterHeight - faceObj->glyph->bitmap_top + belowBaseline) + y) + (xCursor + x + faceObj->glyph->bitmap_left);
unsigned char color = faceObj->glyph->bitmap.buffer[faceObj->glyph->bitmap.pitch * y + x];
if(color == 0)
{
bitmap[position] = 0;
}
else
{
bitmap[position] = 0x00FFFFFF | (color << 24);
}
}
}
m_charPositions[characters[i]] = std::make_tuple(xCursor / static_cast<double>(textureWidth), yCursor / static_cast<double>(textureHeight),
(xCursor + (faceObj->glyph->advance.x >> 6)) / static_cast<double>(textureWidth), (yCursor + characterHeight) / static_cast<double>(textureHeight),
belowBaseline);
if(xCursor < (charactersPerLine - 1) * characterWidth)
{
xCursor += faceObj->glyph->advance.x >> 6;
}
else
{
xCursor = 0;
yCursor += characterHeight;
}
}
m_firstCharacter = 33;
m_characterMaxWidth = characterWidth;
m_characterHeight = characterHeight;
m_characterCount = charCount;
m_glyphTexture = Texture(textureWidth, textureHeight, bitmap);
delete [] bitmap;
}
SpriteFont::~SpriteFont()
{
}
Rectangle SpriteFont::MeasureString(const char* string, unsigned int maxWidth, unsigned int maxHeight)
{
unsigned int* characters = new unsigned int[std::strlen(string)];
for(unsigned int i = 0; i < std::strlen(string); i++)
{
characters[i] = string[i];
}
Rectangle rect = MeasureString(characters, std::strlen(string), maxWidth, maxHeight);
delete [] characters;
return rect;
}
void SpriteFont::RenderString(const char* string, int x, int y, Color color, unsigned int maxWidth, unsigned int maxHeight)
{
unsigned int* characters = new unsigned int[std::strlen(string)];
for(unsigned int i = 0; i < std::strlen(string); i++)
{
characters[i] = string[i];
}
RenderString(characters, std::strlen(string), x, y, color, maxWidth, maxHeight);
delete [] characters;
}
Rectangle SpriteFont::MeasureString(const wchar_t* string, unsigned int maxWidth, unsigned int maxHeight)
{
unsigned int* characters = new unsigned int[std::wcslen(string)];
for(unsigned int i = 0; i < std::wcslen(string); i++)
{
characters[i] = string[i];
}
Rectangle rect = MeasureString(characters, std::wcslen(string), maxWidth, maxHeight);
delete [] characters;
return rect;
}
void SpriteFont::RenderString(const wchar_t* string, int x, int y, Color color, unsigned int maxWidth, unsigned int maxHeight)
{
unsigned int* characters = new unsigned int[std::wcslen(string)];
for(unsigned int i = 0; i < std::wcslen(string); i++)
{
characters[i] = string[i];
}
RenderString(characters, std::wcslen(string), x, y, color, maxWidth, maxHeight);
delete [] characters;
}
Rectangle SpriteFont::MeasureString(const std::string& string, unsigned int maxWidth, unsigned int maxHeight)
{
unsigned int* characters = new unsigned int[string.size()];
for(unsigned int i = 0; i < string.size(); i++)
{
characters[i] = string[i];
}
Rectangle rect = MeasureString(characters, string.size(), maxWidth, maxHeight);
delete [] characters;
return rect;
}
void SpriteFont::RenderString(const std::string& string, int x, int y, Color color, unsigned int maxWidth, unsigned int maxHeight)
{
unsigned int* characters = new unsigned int[string.size()];
for(unsigned int i = 0; i < string.size(); i++)
{
characters[i] = string[i];
}
RenderString(characters, string.size(), x, y, color, maxWidth, maxHeight);
delete [] characters;
}
Rectangle SpriteFont::MeasureString(const std::wstring& string, unsigned int maxWidth, unsigned int maxHeight)
{
unsigned int* characters = new unsigned int[string.size()];
for(unsigned int i = 0; i < string.size(); i++)
{
characters[i] = string[i];
}
Rectangle rect = MeasureString(characters, string.size(), maxWidth, maxHeight);
delete [] characters;
return rect;
}
void SpriteFont::RenderString(const std::wstring& string, int x, int y, Color color, unsigned int maxWidth, unsigned int maxHeight)
{
unsigned int* characters = new unsigned int[string.size()];
for(unsigned int i = 0; i < string.size(); i++)
{
characters[i] = string[i];
}
RenderString(characters, string.size(), x, y, color, maxWidth, maxHeight);
delete [] characters;
}
Rectangle SpriteFont::MeasureString(unsigned int* characters, int characterCount, unsigned int maxWidth, unsigned int maxHeight)
{
int charactersPerLine = (maxWidth / m_characterMaxWidth);
int width = charactersPerLine * m_characterMaxWidth;
int height = (characterCount / charactersPerLine) * m_characterHeight + m_characterHeight;
if(characterCount < charactersPerLine)
{
width = characterCount * m_characterMaxWidth;
}
int maxLines = maxHeight / m_characterHeight;
if(height > maxLines * static_cast<int>(m_characterHeight))
{
height = maxLines * m_characterHeight;
}
return Rectangle(0, 0, width, height);
}
void SpriteFont::RenderString(unsigned int* characters, int characterCount, int x, int y, Color color, unsigned int maxWidth, unsigned int maxHeight)
{
int xCursor = 0;
int yCursor = 0;
int splitIndex = 0;
int quadCount = 0;
GLfloat* texCoordArray = new GLfloat[characterCount * 8];
GLfloat* vertexArray = new GLfloat[characterCount * 8];
for(int i = 0; i < characterCount; ++i)
{
if(characters[i] == '\n')
{
if(yCursor + m_characterHeight > maxHeight)
{
break;
}
yCursor += m_characterHeight;
xCursor = 0.;
continue;
}
if(i != 0 && (characters[i - 1] == ' ' || characters[i - 1] == '-'))
{
int advance = ShouldWrap(characters, characterCount, i, xCursor, maxWidth);
if(advance != -1)
{
if(yCursor + m_characterHeight > maxHeight)
{
break;
}
yCursor += m_characterHeight;
xCursor = 0.;
}
}
if(xCursor == 0.)
{
int advance = ShouldWrap(characters, characterCount, i, xCursor, maxWidth);
if(advance != -1)
{
splitIndex = advance + i;
}
}
if(i != 0 && splitIndex == static_cast<int>(i))
{
if(yCursor + m_characterHeight > maxHeight)
{
break;
}
yCursor += m_characterHeight;
xCursor = 0.;
}
if(characters[i] == ' ')
{
}
else if(m_charPositions.find(characters[i]) == m_charPositions.end())
{
const auto& m_charData = m_charPositions['?'];
texCoordArray[quadCount * 8] = std::get<0>(m_charData);
texCoordArray[quadCount * 8 + 1] = std::get<1>(m_charData);
texCoordArray[quadCount * 8 + 2] = std::get<2>(m_charData);
texCoordArray[quadCount * 8 + 3] = std::get<1>(m_charData);
texCoordArray[quadCount * 8 + 4] = std::get<2>(m_charData);
texCoordArray[quadCount * 8 + 5] = std::get<3>(m_charData);
texCoordArray[quadCount * 8 + 6] = std::get<0>(m_charData);
texCoordArray[quadCount * 8 + 7] = std::get<3>(m_charData);
vertexArray[quadCount * 8] = xCursor;
vertexArray[quadCount * 8 + 1] = yCursor;
vertexArray[quadCount * 8 + 2] = xCursor + m_characterMaxWidth;
vertexArray[quadCount * 8 + 3] = yCursor;
vertexArray[quadCount * 8 + 4] = xCursor + m_characterMaxWidth;
vertexArray[quadCount * 8 + 5] = yCursor + m_characterHeight;
vertexArray[quadCount * 8 + 6] = xCursor;
vertexArray[quadCount * 8 + 7] = yCursor + m_characterHeight;
quadCount++;
}
else
{
const auto& m_charData = m_charPositions[characters[i]];
texCoordArray[quadCount * 8] = std::get<0>(m_charData);
texCoordArray[quadCount * 8 + 1] = std::get<1>(m_charData);
texCoordArray[quadCount * 8 + 2] = std::get<2>(m_charData);
texCoordArray[quadCount * 8 + 3] = std::get<1>(m_charData);
texCoordArray[quadCount * 8 + 4] = std::get<2>(m_charData);
texCoordArray[quadCount * 8 + 5] = std::get<3>(m_charData);
texCoordArray[quadCount * 8 + 6] = std::get<0>(m_charData);
texCoordArray[quadCount * 8 + 7] = std::get<3>(m_charData);
vertexArray[quadCount * 8] = xCursor;
vertexArray[quadCount * 8 + 1] = yCursor - std::get<4>(m_charData);
vertexArray[quadCount * 8 + 2] = xCursor + m_characterMaxWidth;
vertexArray[quadCount * 8 + 3] = yCursor - std::get<4>(m_charData);
vertexArray[quadCount * 8 + 4] = xCursor + m_characterMaxWidth;
vertexArray[quadCount * 8 + 5] = yCursor + m_characterHeight - std::get<4>(m_charData);
vertexArray[quadCount * 8 + 6] = xCursor;
vertexArray[quadCount * 8 + 7] = yCursor + m_characterHeight - std::get<4>(m_charData);
quadCount++;
}
xCursor += m_characterMaxWidth;
}
glLoadIdentity();
m_glyphTexture.Bind();
glColor4f(color.red, color.green, color.blue, color.alpha);
glTranslatef(x, y, 0);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, vertexArray);
glTexCoordPointer(2, GL_FLOAT, 0, texCoordArray);
glDrawArrays(GL_QUADS, 0, quadCount * 4);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
delete [] vertexArray;
delete [] texCoordArray;
}
int SpriteFont::ShouldWrap(unsigned int* characters, int characterCount, unsigned int index, unsigned int startWidth, unsigned int maxWidth)
{
unsigned int width = startWidth;
for(int i = index; i < characterCount; ++i)
{
if(i != static_cast<int>(index) && (characters[i - 1] == L' ' || characters[i - 1] == L'-'))
{
return -1;
}
else
{
width += m_characterMaxWidth;
if(width > maxWidth)
{
if(characters[i] == ' ')
{
return -1;
}
return i - index;
}
}
}
return -1;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment