Commit 6b373924 authored by Aloshi's avatar Aloshi

Moved Fonts to be Resources.

Moved Renderer::drawText stuff to the Font class.
Fonts are now used as std::shared_ptrs.
parent fe8c5926
......@@ -69,23 +69,25 @@ void Font::initLibrary()
}
}
Font::Font(std::string path, int size)
: fontScale(1.0f)
Font::Font(int size) : fontScale(1.0f), mSize(size)
{
mPath = path;
mSize = size;
LOG(LogInfo) << "CREATING FONT (" << mSize << ")";
}
init();
Font::~Font()
{
LOG(LogInfo) << "~~~DESTROYING FONT (" << mSize << ")";
deinit();
}
void Font::init()
void Font::init(ResourceData data)
{
if(!libraryInitialized)
initLibrary();
mMaxGlyphHeight = 0;
buildAtlas();
buildAtlas(data);
}
void Font::deinit()
......@@ -94,11 +96,11 @@ void Font::deinit()
glDeleteTextures(1, &textureID);
}
void Font::buildAtlas()
void Font::buildAtlas(ResourceData data)
{
if(FT_New_Face(sLibrary, mPath.c_str(), 0, &face))
if(FT_New_Memory_Face(sLibrary, data.ptr, data.length, 0, &face))
{
LOG(LogError) << "Error creating font face! (path: " << mPath.c_str();
LOG(LogError) << "Error creating font face!";
return;
}
......@@ -205,19 +207,13 @@ void Font::buildAtlas()
fontScale *= 1.25f;
mSize = (int)(mSize * (1.0f / fontScale));
deinit();
init();
init(data);
}
else {
LOG(LogInfo) << "Created font with size " << mSize << ".";
//LOG(LogInfo) << "Created font with size " << mSize << ".";
}
}
Font::~Font()
{
if(textureID)
glDeleteTextures(1, &textureID);
}
void Font::drawText(std::string text, int startx, int starty, int color)
{
......@@ -294,6 +290,144 @@ int Font::getHeight()
}
void Font::drawCenteredText(std::string text, int xOffset, int y, unsigned int color)
{
int w, h;
sizeText(text, &w, &h);
int x = Renderer::getScreenWidth() - w;
x = x / 2;
x += xOffset / 2;
drawText(text, x, y, color);
}
//this could probably be optimized
//draws text and ensures it's never longer than xLen
void Font::drawWrappedText(std::string text, int xStart, int yStart, int xLen, unsigned int color)
{
int y = yStart;
std::string line, word, temp;
int w, h;
size_t space, newline;
while(text.length() > 0 || !line.empty()) //while there's text or we still have text to render
{
space = text.find(' ', 0);
if(space == std::string::npos)
space = text.length() - 1;
word = text.substr(0, space + 1);
//check if the next word contains a newline
newline = word.find('\n', 0);
if(newline != std::string::npos)
{
word = word.substr(0, newline);
text.erase(0, newline + 1);
}else{
text.erase(0, space + 1);
}
temp = line + word;
sizeText(temp, &w, &h);
//if we're on the last word and it'll fit on the line, just add it to the line
if((w <= xLen && text.length() == 0) || newline != std::string::npos)
{
line = temp;
word = "";
}
//if the next line will be too long or we're on the last of the text, render it
if(w > xLen || text.length() == 0 || newline != std::string::npos)
{
//render line now
if(w > 0) //make sure it's not blank
drawText(line, xStart, y, color);
//increment y by height and some extra padding for the next line
y += h + 4;
//move the word we skipped to the next line
line = word;
}else{
//there's still space, continue building the line
line = temp;
}
}
}
void Font::sizeWrappedText(std::string text, int xLen, int* xOut, int* yOut)
{
//this is incorrect for text that is so short it doesn't need to wrap
if(xOut != NULL)
*xOut = xLen;
int y = 0;
std::string line, word, temp;
int w, h;
size_t space, newline;
while(text.length() > 0 || !line.empty()) //while there's text or we still have text to render
{
space = text.find(' ', 0);
if(space == std::string::npos)
space = text.length() - 1;
word = text.substr(0, space + 1);
//check if the next word contains a newline
newline = word.find('\n', 0);
if(newline != std::string::npos)
{
word = word.substr(0, newline);
text.erase(0, newline + 1);
}else{
text.erase(0, space + 1);
}
temp = line + word;
sizeText(temp, &w, &h);
//if we're on the last word and it'll fit on the line, just add it to the line
if((w <= xLen && text.length() == 0) || newline != std::string::npos)
{
line = temp;
word = "";
}
//if the next line will be too long or we're on the last of the text, render it
if(w > xLen || text.length() == 0 || newline != std::string::npos)
{
//increment y by height and some extra padding for the next line
y += h + 4;
//move the word we skipped to the next line
line = word;
}else{
//there's still space, continue building the line
line = temp;
}
}
if(yOut != NULL)
*yOut = y;
}
//=============================================================================================================
//TextCache
//=============================================================================================================
......
......@@ -7,17 +7,22 @@
#include <ft2build.h>
#include FT_FREETYPE_H
#include "Vector2.h"
#include "resources/Resource.h"
class TextCache;
#define FONT_SIZE_SMALL ((unsigned int)(0.035f * Renderer::getScreenHeight()))
#define FONT_SIZE_MEDIUM ((unsigned int)(0.045f * Renderer::getScreenHeight()))
#define FONT_SIZE_LARGE ((unsigned int)(0.1f * Renderer::getScreenHeight()))
//A TrueType Font renderer that uses FreeType and OpenGL.
//The library is automatically initialized when it's needed.
class Font
class Font : public Resource
{
public:
static void initLibrary();
Font(std::string path, int size);
Font(int size);
~Font();
FT_Face face;
......@@ -46,10 +51,16 @@ public:
//Create a TextCache, render with it, then delete it. Best used for short text or text that changes frequently.
void drawText(std::string text, int startx, int starty, int color);
void sizeText(std::string text, int* w, int* h); //Sets the width and height of a given string to supplied pointers. A dimension is skipped if its pointer is NULL.
void drawWrappedText(std::string text, int xStart, int yStart, int xLen, unsigned int color);
void sizeWrappedText(std::string text, int xLen, int* xOut, int* yOut);
void drawCenteredText(std::string text, int xOffset, int y, unsigned int color);
int getHeight();
void init();
void deinit();
void init(ResourceData data) override;
void deinit() override;
int getSize();
......@@ -61,14 +72,13 @@ private:
static FT_Library sLibrary;
static bool libraryInitialized;
void buildAtlas(); //Builds a "texture atlas," one big OpenGL texture with glyphs 32 to 128.
void buildAtlas(ResourceData data); //Builds a "texture atlas," one big OpenGL texture with glyphs 32 to 128.
int textureWidth; //OpenGL texture width
int textureHeight; //OpenGL texture height
int mMaxGlyphHeight;
float fontScale; //!<Font scale factor. It is > 1.0 if the font would be to big for the texture
std::string mPath;
int mSize;
};
......
......@@ -25,8 +25,6 @@ namespace Renderer
unsigned int getScreenWidth();
unsigned int getScreenHeight();
enum FontSize { SMALL, MEDIUM, LARGE, FONT_SIZE_COUNT };
Font* getDefaultFont(FontSize size);
void buildGLColorArray(GLubyte* ptr, unsigned int color, unsigned int vertCount);
//graphics commands
......@@ -40,10 +38,6 @@ namespace Renderer
void popClipRect();
void drawRect(int x, int y, int w, int h, unsigned int color);
void drawText(std::string text, int x, int y, unsigned int color, Font* font);
void drawCenteredText(std::string text, int xOffset, int y, unsigned int color, Font* font);
void drawWrappedText(std::string text, int xStart, int yStart, int xLen, unsigned int color, Font* font);
void sizeWrappedText(std::string text, int xLen, Font* font, int* xOut, int* yOut);
}
#endif
......@@ -8,8 +8,6 @@
#include <stack>
namespace Renderer {
bool loadedFonts = false;
std::stack<Rect> clipStack;
void setColor4bArray(GLubyte* array, unsigned int color)
......@@ -120,195 +118,4 @@ namespace Renderer {
glDisableClientState(GL_VERTEX_ARRAY);
glDisable(GL_COLOR_ARRAY);
}
Font* fonts[3] = {NULL, NULL, NULL};
/*void unloadFonts()
{
std::cout << "unloading fonts...";
for(unsigned int i = 0; i < 3; i++)
{
delete fonts[i];
fonts[i] = NULL;
}
loadedFonts = false;
std::cout << "done.\n";
}*/
//creates the default fonts (which shouldn't ever be deleted)
void loadFonts()
{
if(loadedFonts)
return;
std::string fontPath = Font::getDefaultPath();
//make sure our font exists
if(!boost::filesystem::exists(fontPath))
{
LOG(LogError) << "System font wasn't found! Try installing the DejaVu truetype font (pacman -S ttf-dejavu on Arch, sudo apt-get install ttf-dejavu on Debian)";
return;
}
float fontSizes[] = {0.035f, 0.045f, 0.1f};
for(unsigned int i = 0; i < 3; i++)
{
fonts[i] = new Font(fontPath, (unsigned int)(fontSizes[i] * getScreenHeight()));
}
loadedFonts = true;
LOG(LogInfo) << "Loaded fonts successfully.";
}
Font* getDefaultFont(FontSize size)
{
if(!loadedFonts)
loadFonts();
return fonts[size];
}
void drawText(std::string text, int x, int y, unsigned int color, Font* font)
{
font->drawText(text, x, y, color);
}
void drawCenteredText(std::string text, int xOffset, int y, unsigned int color, Font* font)
{
int w, h;
font->sizeText(text, &w, &h);
int x = getScreenWidth() - w;
x = x / 2;
x += xOffset / 2;
drawText(text, x, y, color, font);
}
//this could probably be optimized
//draws text and ensures it's never longer than xLen
void drawWrappedText(std::string text, int xStart, int yStart, int xLen, unsigned int color, Font* font)
{
int y = yStart;
std::string line, word, temp;
int w, h;
size_t space, newline;
while(text.length() > 0 || !line.empty()) //while there's text or we still have text to render
{
space = text.find(' ', 0);
if(space == std::string::npos)
space = text.length() - 1;
word = text.substr(0, space + 1);
//check if the next word contains a newline
newline = word.find('\n', 0);
if(newline != std::string::npos)
{
word = word.substr(0, newline);
text.erase(0, newline + 1);
}else{
text.erase(0, space + 1);
}
temp = line + word;
font->sizeText(temp, &w, &h);
//if we're on the last word and it'll fit on the line, just add it to the line
if((w <= xLen && text.length() == 0) || newline != std::string::npos)
{
line = temp;
word = "";
}
//if the next line will be too long or we're on the last of the text, render it
if(w > xLen || text.length() == 0 || newline != std::string::npos)
{
//render line now
if(w > 0) //make sure it's not blank
drawText(line, xStart, y, color, font);
//increment y by height and some extra padding for the next line
y += h + 4;
//move the word we skipped to the next line
line = word;
}else{
//there's still space, continue building the line
line = temp;
}
}
}
void sizeWrappedText(std::string text, int xLen, Font* font, int* xOut, int* yOut)
{
if(xOut != NULL)
*xOut = xLen;
int y = 0;
std::string line, word, temp;
int w, h;
size_t space, newline;
while(text.length() > 0 || !line.empty()) //while there's text or we still have text to render
{
space = text.find(' ', 0);
if(space == std::string::npos)
space = text.length() - 1;
word = text.substr(0, space + 1);
//check if the next word contains a newline
newline = word.find('\n', 0);
if(newline != std::string::npos)
{
word = word.substr(0, newline);
text.erase(0, newline + 1);
}else{
text.erase(0, space + 1);
}
temp = line + word;
font->sizeText(temp, &w, &h);
//if we're on the last word and it'll fit on the line, just add it to the line
if((w <= xLen && text.length() == 0) || newline != std::string::npos)
{
line = temp;
word = "";
}
//if the next line will be too long or we're on the last of the text, render it
if(w > xLen || text.length() == 0 || newline != std::string::npos)
{
//increment y by height and some extra padding for the next line
y += h + 4;
//move the word we skipped to the next line
line = word;
}else{
//there's still space, continue building the line
line = temp;
}
}
if(yOut != NULL)
*yOut = y;
}
};
......@@ -7,17 +7,9 @@ namespace Renderer
{
void onInit()
{
for(int i = 0; i < (int)FONT_SIZE_COUNT; i++)
{
getDefaultFont((FontSize)i)->init();
}
}
void onDeinit()
{
for(int i = 0; i < (int)FONT_SIZE_COUNT; i++)
{
getDefaultFont((FontSize)i)->deinit();
}
}
};
......@@ -7,6 +7,10 @@
Window::Window()
{
mInputManager = new InputManager(this);
mDefaultFonts.push_back(mResourceManager.getFont(Font::getDefaultPath(), FONT_SIZE_SMALL));
mDefaultFonts.push_back(mResourceManager.getFont(Font::getDefaultPath(), FONT_SIZE_MEDIUM));
mDefaultFonts.push_back(mResourceManager.getFont(Font::getDefaultPath(), FONT_SIZE_LARGE));
}
Window::~Window()
......
......@@ -30,6 +30,8 @@ private:
InputManager* mInputManager;
ResourceManager mResourceManager;
std::vector<GuiComponent*> mGuiStack;
std::vector< std::shared_ptr<Font> > mDefaultFonts;
};
#endif
......@@ -83,25 +83,25 @@ void GuiDetectDevice::update(int deltaTime)
void GuiDetectDevice::render()
{
Font* font = Renderer::getDefaultFont(Renderer::MEDIUM);
std::shared_ptr<Font> font = mWindow->getResourceManager()->getFont(Font::getDefaultPath(), FONT_SIZE_MEDIUM);
std::string playerString;
std::stringstream stream;
stream << (mCurrentPlayer + 1);
stream >> playerString;
Renderer::drawCenteredText("Press a button on the device for", 0, Renderer::getScreenHeight() / 3, 0x000000FF, font);
Renderer::drawCenteredText("PLAYER " + playerString, 0, (int)(Renderer::getScreenHeight()*1.5f) / 3, 0x333333FF, font);
font->drawCenteredText("Press a button on the device for", 0, Renderer::getScreenHeight() / 3, 0x000000FF);
font->drawCenteredText("PLAYER " + playerString, 0, (int)(Renderer::getScreenHeight()*1.5f) / 3, 0x333333FF);
if(mWindow->getInputManager()->getNumPlayers() > 0)
{
Renderer::drawCenteredText("(P1 - hold a button to finish)", 0, (Renderer::getScreenHeight()*2) / 3, (mHoldingFinish ? 0x0000FFFF : 0x000066FF), font);
font->drawCenteredText("(P1 - hold a button to finish)", 0, (Renderer::getScreenHeight()*2) / 3, (mHoldingFinish ? 0x0000FFFF : 0x000066FF));
}
if(mWindow->getInputManager()->getNumJoysticks() == 0)
{
Renderer::drawCenteredText("No joysticks detected!", 0, Renderer::getScreenHeight() - (font->getHeight()*2)-10, 0xFF0000FF, font);
font->drawCenteredText("No joysticks detected!", 0, Renderer::getScreenHeight() - (font->getHeight()*2)-10, 0xFF0000FF);
}
Renderer::drawCenteredText("Press F4 to quit.", 0, Renderer::getScreenHeight() - font->getHeight() - 2 , 0x000000FF, font);
font->drawCenteredText("Press F4 to quit.", 0, Renderer::getScreenHeight() - font->getHeight() - 2 , 0x000000FF);
}
......@@ -41,10 +41,11 @@ void GuiFastSelect::render()
mBox->render();
Renderer::drawCenteredText(LETTERS.substr(mLetterID, 1), 0, (int)(sh * 0.5f - (mTheme->getFastSelectFont()->getHeight() * 0.5f)), mTextColor, mTheme->getFastSelectFont());
Renderer::drawCenteredText("Sort order:", 0, (int)(sh * 0.6f - (mTheme->getDescriptionFont()->getHeight() * 0.5f)), mTextColor, mTheme->getDescriptionFont());
mTheme->getFastSelectFont()->drawCenteredText(LETTERS.substr(mLetterID, 1), 0, (int)(sh * 0.5f - (mTheme->getFastSelectFont()->getHeight() * 0.5f)), mTextColor);
mTheme->getDescriptionFont()->drawCenteredText("Sort order:", 0, (int)(sh * 0.6f - (mTheme->getDescriptionFont()->getHeight() * 0.5f)), mTextColor);
std::string sortString = "<- " + mParent->getSortState().description + " ->";
Renderer::drawCenteredText(sortString, 0, (int)(sh * 0.6f + (mTheme->getDescriptionFont()->getHeight() * 0.5f)), mTextColor, mTheme->getDescriptionFont());
mTheme->getDescriptionFont()->drawCenteredText(sortString, 0, (int)(sh * 0.6f + (mTheme->getDescriptionFont()->getHeight() * 0.5f)), mTextColor);
}
bool GuiFastSelect::input(InputConfig* config, Input input)
......
......@@ -26,7 +26,7 @@ bool GuiGameList::isDetailed() const
GuiGameList::GuiGameList(Window* window) : GuiComponent(window),
mTheme(new ThemeComponent(mWindow)),
mList(window, 0, 0, Renderer::getDefaultFont(Renderer::MEDIUM)),
mList(window, 0, 0, window->getResourceManager()->getFont(Font::getDefaultPath(), FONT_SIZE_MEDIUM)),
mScreenshot(window),
mDescription(window),
mDescContainer(window),
......@@ -114,15 +114,17 @@ void GuiGameList::render()
if(mTheme)
mTheme->render();
std::shared_ptr<Font> headerFont = mWindow->getResourceManager()->getFont(Font::getDefaultPath(), FONT_SIZE_LARGE);
//header
if(!mTheme->getBool("hideHeader"))
Renderer::drawCenteredText(mSystem->getDescName(), 0, 1, 0xFF0000FF, Renderer::getDefaultFont(Renderer::LARGE));
headerFont->drawCenteredText(mSystem->getDescName(), 0, 1, 0xFF0000FF);
if(isDetailed())
{
//divider
if(!mTheme->getBool("hideDividers"))
Renderer::drawRect((int)(Renderer::getScreenWidth() * mTheme->getFloat("listOffsetX")) - 4, Renderer::getDefaultFont(Renderer::LARGE)->getHeight() + 2, 8, Renderer::getScreenHeight(), 0x0000FFFF);
Renderer::drawRect((int)(Renderer::getScreenWidth() * mTheme->getFloat("listOffsetX")) - 4, headerFont->getHeight() + 2, 8, Renderer::getScreenHeight(), 0x0000FFFF);
mScreenshot.render();
mDescContainer.render();
......@@ -324,7 +326,7 @@ void GuiGameList::updateTheme()
mList.setScrollSound(mTheme->getSound("menuScroll"));
mList.setFont(mTheme->getListFont());
mList.setOffset(0, Renderer::getDefaultFont(Renderer::LARGE)->getHeight() + 2);
mList.setOffset(0, FONT_SIZE_LARGE + 2);
if(isDetailed())
{
......
......@@ -77,25 +77,25 @@ bool GuiInputConfig::input(InputConfig* config, Input input)
void GuiInputConfig::render()
{
Font* font = Renderer::getDefaultFont(Renderer::MEDIUM);
std::shared_ptr<Font> font = mWindow->getResourceManager()->getFont(Font::getDefaultPath(), FONT_SIZE_MEDIUM);
std::stringstream stream;
stream << "PLAYER " << mTargetConfig->getPlayerNum() + 1 << ", press...";
Renderer::drawText(stream.str(), 10, 10, 0x000000FF, font);
font->drawText(stream.str(), 10, 10, 0x000000FF);
int y = 14 + font->getHeight();
for(int i = 0; i < mCurInputId; i++)
{
Renderer::drawText(inputDispName[i], 10, y, 0x00CC00FF, font);
font->drawText(inputDispName[i], 10, y, 0x00CC00FF);
y += font->getHeight() + 5;
}
if(mCurInputId >= inputCount)
{
Renderer::drawCenteredText("Basic config done!", 0, (int)(Renderer::getScreenHeight() * 0.4), 0x00CC00FF, font);
Renderer::drawCenteredText("Press any button to continue.", 0, (int)(Renderer::getScreenHeight() * 0.4) + font->getHeight() + 4, 0x000000FF, font);
font->drawCenteredText("Basic config done!", 0, (int)(Renderer::getScreenHeight() * 0.4), 0x00CC00FF);
font->drawCenteredText("Press any button to continue.", 0, (int)(Renderer::getScreenHeight() * 0.4) + font->getHeight() + 4, 0x000000FF);
}else{
Renderer::drawText(inputDispName[mCurInputId], 10, y, 0x000000FF, font);
font->drawText(inputDispName[mCurInputId], 10, y, 0x000000FF);
if(mCanSkip)
{
int textWidth = 0;
......@@ -105,10 +105,10 @@ void GuiInputConfig::render()
if(Renderer::getScreenWidth() / 2.5f > textWidth)
textWidth = (int)(Renderer::getScreenWidth() / 2.5f);
Renderer::drawText("press Accept to skip", textWidth, y, 0x0000AAFF, font);
font->drawText("press Accept to skip", textWidth, y, 0x0000AAFF);
}
}
if(!mErrorMsg.empty())
Renderer::drawCenteredText(mErrorMsg, 0, Renderer::getScreenHeight() - font->getHeight() - 10, 0xFF0000FF, font);
font->drawCenteredText(mErrorMsg, 0, Renderer::getScreenHeight() - font->getHeight() - 10, 0xFF0000FF);
}
......@@ -11,7 +11,8 @@ GuiMenu::GuiMenu(Window* window, GuiGameList* parent) : GuiComponent(window)
{
mParent = parent;
mList = new TextListComponent<std::string>(mWindow, 0, Renderer::getDefaultFont(Renderer::LARGE)->getHeight() + 2, Renderer::getDefaultFont(Renderer::LARGE));
std::shared_ptr<Font> font = mWindow->getResourceManager()->getFont(Font::getDefaultPath(), FONT_SIZE_LARGE);
mList = new TextListComponent<std::string>(mWindow, 0, font->getHeight() + 2, font);
mList->setSelectedTextColor(0x0000FFFF);
populateList();
}
......
#include "SwitchComponent.h"
#include "../Renderer.h"
#include "../Font.h"
#include "../Window.h"
SwitchComponent::SwitchComponent(Window* window, bool state) : GuiComponent(window), mState(state)
{
//mSize = Vector2u((unsigned int)(Renderer::getScreenWidth() * 0.05),
// (unsigned int)(Renderer::getScreenHeight() * 0.05));
Renderer::getDefaultFont(Renderer::MEDIUM)->sizeText("OFF", (int*)&mSize.x, (int*)&mSize.y);
mWindow->getResourceManager()->getFont(Font::getDefaultPath(), FONT_SIZE_MEDIUM)->sizeText("OFF", (int*)&mSize.x, (int*)&mSize.y);
}
bool SwitchComponent::input(InputConfig* config, Input input)
......@@ -25,7 +26,7 @@ void SwitchComponent::onRender()
{