Began paving the way for custom font support.

Font sizes might be a little different than they were before - sorry about that!
This commit is contained in:
Aloshi 2012-10-24 10:28:37 -05:00
parent 8b242a0532
commit aa6506aec1
14 changed files with 126 additions and 94 deletions

View file

@ -5,31 +5,57 @@
#include "Renderer.h" #include "Renderer.h"
FT_Library Font::sLibrary; FT_Library Font::sLibrary;
bool Font::libraryInitialized = false;
int Font::getDpiX() { return 300; } int Font::getDpiX() { return 96; }
int Font::getDpiY() { return 300; } int Font::getDpiY() { return 96; }
void Font::initLibrary() void Font::initLibrary()
{ {
if(FT_Init_FreeType(&sLibrary)) if(FT_Init_FreeType(&sLibrary))
{ {
std::cerr << "Error initializing FreeType!\n"; std::cerr << "Error initializing FreeType!\n";
}else{
libraryInitialized = true;
} }
} }
Font::Font(std::string path, int size) Font::Font(std::string path, int size)
{ {
//register to receive init/deinit callbacks
Renderer::registerComponent(this);
mPath = path;
mSize = size;
onInit();
}
void Font::onInit()
{
if(!libraryInitialized)
initLibrary();
mMaxGlyphHeight = 0; mMaxGlyphHeight = 0;
if(FT_New_Face(sLibrary, path.c_str(), 0, &face)) if(FT_New_Face(sLibrary, mPath.c_str(), 0, &face))
{ {
std::cerr << "Error creating font face! (path: " << path.c_str() << "\n"; std::cerr << "Error creating font face! (path: " << mPath.c_str() << "\n";
while(true); return;
} }
FT_Set_Char_Size(face, 0, size * 64, getDpiX(), getDpiY()); //FT_Set_Char_Size(face, 0, size * 64, getDpiX(), getDpiY());
FT_Set_Pixel_Sizes(face, 0, mSize);
buildAtlas(); buildAtlas();
FT_Done_Face(face);
}
void Font::onDeinit()
{
if(textureID)
glDeleteTextures(1, &textureID);
} }
void Font::buildAtlas() void Font::buildAtlas()
@ -130,8 +156,9 @@ void Font::buildAtlas()
Font::~Font() Font::~Font()
{ {
FT_Done_Face(face); Renderer::unregisterComponent(this);
if(textureID)
glDeleteTextures(1, &textureID); glDeleteTextures(1, &textureID);
} }
@ -167,6 +194,13 @@ struct tex {
void Font::drawText(std::string text, int startx, int starty, int color) void Font::drawText(std::string text, int startx, int starty, int color)
{ {
if(!textureID)
{
std::cerr << "Error - tried to draw with Font that has no texture loaded!\n";
return;
}
starty += mMaxGlyphHeight; starty += mMaxGlyphHeight;
//padding (another 0.5% is added to the bottom through the sizeText function) //padding (another 0.5% is added to the bottom through the sizeText function)
@ -255,7 +289,7 @@ void Font::sizeText(std::string text, int* w, int* h)
{ {
unsigned char letter = text[i]; unsigned char letter = text[i];
if(letter < 32 || letter >= 128) if(letter < 32 || letter >= 128)
continue; letter = 127;
cwidth += charData[letter].advX; cwidth += charData[letter].advX;
} }
@ -267,3 +301,8 @@ void Font::sizeText(std::string text, int* w, int* h)
if(h != NULL) if(h != NULL)
*h = mMaxGlyphHeight + mMaxGlyphHeight * 0.5; *h = mMaxGlyphHeight + mMaxGlyphHeight * 0.5;
} }
int Font::getHeight()
{
return mMaxGlyphHeight * 1.5;
}

View file

@ -2,13 +2,14 @@
#define _FONT_H_ #define _FONT_H_
#include <string> #include <string>
#include "GuiComponent.h"
#include "platform.h" #include "platform.h"
#include GLHEADER #include GLHEADER
#include <ft2build.h> #include <ft2build.h>
#include FT_FREETYPE_H #include FT_FREETYPE_H
//A TrueType Font renderer that uses FreeType and OpenGL. initLibrary() MUST be called before using it. //A TrueType Font renderer that uses FreeType and OpenGL. initLibrary() MUST be called before using it.
class Font class Font : GuiComponent
{ {
public: public:
static void initLibrary(); static void initLibrary();
@ -37,17 +38,26 @@ public:
void drawText(std::string text, int startx, int starty, int color); //Render some text using this font. void drawText(std::string text, int startx, int starty, int color); //Render some text using this font.
void sizeText(std::string text, int* w, int* h); //Sets the width and height of a given string to given pointers. Skipped if pointer is NULL. void sizeText(std::string text, int* w, int* h); //Sets the width and height of a given string to given pointers. Skipped if pointer is NULL.
int getHeight();
void onInit();
void onDeinit();
private: private:
static int getDpiX(); static int getDpiX();
static int getDpiY(); static int getDpiY();
static FT_Library sLibrary; static FT_Library sLibrary;
static bool libraryInitialized;
void buildAtlas(); //Builds a "texture atlas," one big OpenGL texture with glyphs 32 to 128. void buildAtlas(); //Builds a "texture atlas," one big OpenGL texture with glyphs 32 to 128.
int textureWidth; //OpenGL texture width int textureWidth; //OpenGL texture width
int textureHeight; //OpenGL texture height int textureHeight; //OpenGL texture height
int mMaxGlyphHeight; int mMaxGlyphHeight;
std::string mPath;
int mSize;
}; };
#endif #endif

View file

@ -3,9 +3,12 @@
#include <vector> #include <vector>
#include <string> #include <string>
#include "Font.h" #include "platform.h"
#include GLHEADER
//#include "Font.h"
class GuiComponent; class GuiComponent;
class Font;
//The Renderer provides several higher-level functions for drawing (rectangles, text, etc.). //The Renderer provides several higher-level functions for drawing (rectangles, text, etc.).
//Defined in multiple files - Renderer.cpp has the GuiComponent stuff, Renderer_draw_* includes renderer-specific drawing implementations, and Renderer_init_* includes renderer-specific init/deinit. //Defined in multiple files - Renderer.cpp has the GuiComponent stuff, Renderer_draw_* includes renderer-specific drawing implementations, and Renderer_init_* includes renderer-specific init/deinit.
@ -26,15 +29,15 @@ namespace Renderer
unsigned int getScreenHeight(); unsigned int getScreenHeight();
enum FontSize { SMALL, MEDIUM, LARGE }; enum FontSize { SMALL, MEDIUM, LARGE };
int getFontHeight(FontSize size); //sometimes font size is needed before fonts have been loaded; this takes care of that Font* getDefaultFont(FontSize size);
void buildGLColorArray(GLubyte* ptr, unsigned int color, unsigned int vertCount); void buildGLColorArray(GLubyte* ptr, unsigned int color, unsigned int vertCount);
//drawing commands //drawing commands
void swapBuffers(); void swapBuffers();
void drawRect(int x, int y, int w, int h, unsigned int color); 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, FontSize fontsize = MEDIUM); 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, FontSize fontsize = MEDIUM); 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, FontSize fontsize = MEDIUM); void drawWrappedText(std::string text, int xStart, int yStart, int xLen, unsigned int color, Font* font);
} }
#endif #endif

View file

@ -57,10 +57,29 @@ namespace Renderer {
Font* fonts[3] = {NULL, NULL, NULL}; Font* fonts[3] = {NULL, NULL, NULL};
//this is never really used, but is here "just in case"
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";
}
void loadFonts() void loadFonts()
{ {
if(loadedFonts)
unloadFonts();
std::cout << "loading fonts..."; std::cout << "loading fonts...";
std::string fontPath = "LinLibertine_R.ttf"; std::string fontPath = "LinLibertine_R.ttf";
@ -77,10 +96,10 @@ namespace Renderer {
} }
} }
float fontSizes[] = {0.004, 0.006, 0.009}; float fontSizes[] = {0.035, 0.05, 0.1};
for(unsigned int i = 0; i < 3; i++) for(unsigned int i = 0; i < 3; i++)
{ {
fonts[i] = new Font(fontPath, (unsigned int)(fontSizes[i] * getScreenWidth())); fonts[i] = new Font(fontPath, (unsigned int)(fontSizes[i] * getScreenHeight()));
} }
loadedFonts = true; loadedFonts = true;
@ -88,22 +107,7 @@ namespace Renderer {
std::cout << "done\n"; std::cout << "done\n";
} }
void unloadFonts() Font* getDefaultFont(FontSize size)
{
std::cout << "unloading fonts...";
for(unsigned int i = 0; i < 3; i++)
{
delete fonts[i];
fonts[i] = NULL;
}
loadedFonts = false;
std::cout << "done.\n";
}
Font* getFont(FontSize size)
{ {
if(!loadedFonts) if(!loadedFonts)
loadFonts(); loadFonts();
@ -111,36 +115,13 @@ namespace Renderer {
return fonts[size]; return fonts[size];
} }
void drawText(std::string text, int x, int y, unsigned int color, Font* font)
int getFontHeight(FontSize size)
{ {
if(!loadedFonts) font->drawText(text, x, y, color);
loadFonts();
int h;
getFont(size)->sizeText("HEIGHT", NULL, &h);
return h;
} }
void drawText(std::string text, int x, int y, unsigned int color, FontSize font) void drawCenteredText(std::string text, int xOffset, int y, unsigned int color, Font* font)
{ {
if(!loadedFonts)
loadFonts();
//if(x < 0)
// std::cout << "drawing at " << x << std::endl;
getFont(font)->drawText(text, x, y, color);
}
void drawCenteredText(std::string text, int xOffset, int y, unsigned int color, FontSize fontsize)
{
if(!loadedFonts)
loadFonts();
Font* font = getFont(fontsize);
int w, h; int w, h;
font->sizeText(text, &w, &h); font->sizeText(text, &w, &h);
@ -149,18 +130,13 @@ namespace Renderer {
x += xOffset * 0.5; x += xOffset * 0.5;
drawText(text, x, y, color, fontsize); drawText(text, x, y, color, font);
} }
//this could probably be optimized //this could probably be optimized
//draws text and ensures it's never longer than xLen //draws text and ensures it's never longer than xLen
void drawWrappedText(std::string text, int xStart, int yStart, int xLen, unsigned int color, FontSize fontsize) void drawWrappedText(std::string text, int xStart, int yStart, int xLen, unsigned int color, Font* font)
{ {
if(!loadedFonts)
loadFonts();
Font* font = getFont(fontsize);
int y = yStart; int y = yStart;
std::string line, word, temp; std::string line, word, temp;
@ -203,7 +179,7 @@ namespace Renderer {
{ {
//render line now //render line now
if(w > 0) //make sure it's not blank if(w > 0) //make sure it's not blank
drawText(line, xStart, y, color, fontsize); drawText(line, xStart, y, color, font);
//increment y by height and some extra padding for the next line //increment y by height and some extra padding for the next line
y += h + 4; y += h + 4;

View file

@ -215,7 +215,7 @@ namespace Renderer
{ {
onDeinit(); onDeinit();
unloadFonts(); //unloadFonts();
destroySurface(); destroySurface();
} }
}; };

View file

@ -79,7 +79,7 @@ namespace Renderer
if(!createdSurface) if(!createdSurface)
return false; return false;
Font::initLibrary(); //Font::initLibrary();
glViewport(0, 0, display_width, display_height); glViewport(0, 0, display_width, display_height);
glOrtho(0, display_width, display_height, 0, -1.0, 1.0); glOrtho(0, display_width, display_height, 0, -1.0, 1.0);
@ -95,7 +95,7 @@ namespace Renderer
{ {
onDeinit(); onDeinit();
unloadFonts(); //unloadFonts();
destroySurface(); destroySurface();
} }
}; };

View file

@ -51,7 +51,7 @@ void GuiFastSelect::onRender()
mBox->render(); mBox->render();
Renderer::drawCenteredText(LETTERS.substr(mLetterID, 1), 0, sh * 0.5 - (Renderer::getFontHeight(Renderer::LARGE) * 0.5), mTextColor, Renderer::LARGE); Renderer::drawCenteredText(LETTERS.substr(mLetterID, 1), 0, sh * 0.5 - (Renderer::getDefaultFont(Renderer::LARGE)->getHeight() * 0.5), mTextColor, Renderer::getDefaultFont(Renderer::LARGE));
} }
void GuiFastSelect::onInput(InputManager::InputButton button, bool keyDown) void GuiFastSelect::onInput(InputManager::InputButton button, bool keyDown)

View file

@ -21,7 +21,7 @@ GuiGameList::GuiGameList(bool useDetail)
//Those with smaller displays may prefer the older view. //Those with smaller displays may prefer the older view.
if(mDetailed) if(mDetailed)
{ {
mList = new GuiList<FileData*>(Renderer::getScreenWidth() * sInfoWidth, Renderer::getFontHeight(Renderer::LARGE) + 2); mList = new GuiList<FileData*>(Renderer::getScreenWidth() * sInfoWidth, Renderer::getDefaultFont(Renderer::LARGE)->getHeight() + 2);
mScreenshot = new GuiImage(Renderer::getScreenWidth() * sInfoWidth * 0.5, Renderer::getScreenHeight() * mTheme->getGameImageOffsetY(), "", Renderer::getScreenWidth() * sInfoWidth * 0.7, 0, false); mScreenshot = new GuiImage(Renderer::getScreenWidth() * sInfoWidth * 0.5, Renderer::getScreenHeight() * mTheme->getGameImageOffsetY(), "", Renderer::getScreenWidth() * sInfoWidth * 0.7, 0, false);
mScreenshot->setOrigin(mTheme->getGameImageOriginX(), mTheme->getGameImageOriginY()); mScreenshot->setOrigin(mTheme->getGameImageOriginX(), mTheme->getGameImageOriginY());
@ -31,7 +31,7 @@ GuiGameList::GuiGameList(bool useDetail)
mImageAnimation->addChild(mScreenshot); mImageAnimation->addChild(mScreenshot);
addChild(mImageAnimation); addChild(mImageAnimation);
}else{ }else{
mList = new GuiList<FileData*>(0, Renderer::getFontHeight(Renderer::LARGE) + 2); mList = new GuiList<FileData*>(0, Renderer::getDefaultFont(Renderer::LARGE)->getHeight() + 2);
mScreenshot = NULL; mScreenshot = NULL;
mImageAnimation = NULL; mImageAnimation = NULL;
} }
@ -93,13 +93,13 @@ void GuiGameList::onRender()
//header //header
if(!mTheme->getHeaderHidden()) if(!mTheme->getHeaderHidden())
Renderer::drawCenteredText(mSystem->getName(), 0, 1, 0xFF0000FF, Renderer::LARGE); Renderer::drawCenteredText(mSystem->getName(), 0, 1, 0xFF0000FF, Renderer::getDefaultFont(Renderer::LARGE));
if(mDetailed) if(mDetailed)
{ {
//divider //divider
if(!mTheme->getDividersHidden()) if(!mTheme->getDividersHidden())
Renderer::drawRect(Renderer::getScreenWidth() * mTheme->getListOffsetX() - 4, Renderer::getFontHeight(Renderer::LARGE) + 2, 8, Renderer::getScreenHeight(), 0x0000FFFF); Renderer::drawRect(Renderer::getScreenWidth() * mTheme->getListOffsetX() - 4, Renderer::getDefaultFont(Renderer::LARGE)->getHeight() + 2, 8, Renderer::getScreenHeight(), 0x0000FFFF);
//if we're not scrolling and we have selected a non-folder //if we're not scrolling and we have selected a non-folder
if(!mList->isScrolling() && mList->getSelectedObject() && !mList->getSelectedObject()->isFolder()) if(!mList->isScrolling() && mList->getSelectedObject() && !mList->getSelectedObject()->isFolder())
@ -108,7 +108,7 @@ void GuiGameList::onRender()
std::string desc = game->getDescription(); std::string desc = game->getDescription();
if(!desc.empty()) if(!desc.empty())
Renderer::drawWrappedText(desc, Renderer::getScreenWidth() * 0.03, mScreenshot->getOffsetY() + mScreenshot->getHeight() + 12, Renderer::getScreenWidth() * (mTheme->getListOffsetX() - 0.03), mTheme->getDescColor(), Renderer::SMALL); Renderer::drawWrappedText(desc, Renderer::getScreenWidth() * 0.03, mScreenshot->getOffsetY() + mScreenshot->getHeight() + 12, Renderer::getScreenWidth() * (mTheme->getListOffsetX() - 0.03), mTheme->getDescColor(), Renderer::getDefaultFont(Renderer::SMALL));
} }
} }
} }

View file

@ -38,19 +38,22 @@ void GuiInputConfig::onRender()
{ {
Renderer::drawRect(0, 0, Renderer::getScreenWidth(), Renderer::getScreenHeight(), 0xFFFFFFFF); Renderer::drawRect(0, 0, Renderer::getScreenWidth(), Renderer::getScreenHeight(), 0xFFFFFFFF);
int height = Renderer::getFontHeight(Renderer::MEDIUM) + 6; Font* font = Renderer::getDefaultFont(Renderer::MEDIUM);
Renderer::drawCenteredText("It looks like you have a joystick plugged in!", 0, 2, 0x000000FF); int height = font->getHeight() + 6;
Renderer::drawCenteredText("POV hats (some D-Pads) are automatically mapped to directions.", 0, height, 0x000000FF);
Renderer::drawCenteredText("You can press a keyboard key to skip any input.", 0, height * 2, 0x000000FF);
Renderer::drawCenteredText("If you want to remap later, just delete ~/.es_input.cfg.", 0, height * 3, 0x000000FF); Renderer::drawCenteredText("It looks like you have a joystick plugged in!", 0, 2, 0x000000FF, font);
Renderer::drawCenteredText("This interface only configures the first joystick plugged in.", 0, height * 4, 0x000000FF); Renderer::drawCenteredText("POV hats (some D-Pads) are automatically mapped to directions.", 0, height, 0x000000FF, font);
Renderer::drawCenteredText("Remember - you'll need to set up your emulator separately!", 0, Renderer::getScreenHeight() - height, 0x000000FF); Renderer::drawCenteredText("You can press a keyboard key to skip any input.", 0, height * 2, 0x000000FF, font);
Renderer::drawCenteredText("If you want to remap later, just delete ~/.es_input.cfg.", 0, height * 3, 0x000000FF, font);
Renderer::drawCenteredText("This interface only configures the first joystick plugged in.", 0, height * 4, 0x000000FF, font);
Renderer::drawCenteredText("Remember - you'll need to set up your emulator separately!", 0, Renderer::getScreenHeight() - height, 0x000000FF, font);
if(mDone) if(mDone)
Renderer::drawCenteredText("All done! Press a keyboard key to save.", 0, height * 5, 0x00BB00FF); Renderer::drawCenteredText("All done! Press a keyboard key to save.", 0, height * 5, 0x00BB00FF, font);
else else
Renderer::drawCenteredText("Please press the axis/button for " + sInputs[mInputNum], 0, height * 5, 0x00C000FF); Renderer::drawCenteredText("Please press the axis/button for " + sInputs[mInputNum], 0, height * 5, 0x00C000FF, font);
} }
void GuiInputConfig::onInput(InputManager::InputButton button, bool keyDown) void GuiInputConfig::onInput(InputManager::InputButton button, bool keyDown)

View file

@ -16,7 +16,7 @@ GuiList<listType>::GuiList(int offsetX, int offsetY, Renderer::FontSize fontsize
mTextOffsetX = 0; mTextOffsetX = 0;
mFont = fontsize; mFont = Renderer::getDefaultFont(fontsize);
mSelectorColor = 0x000000FF; mSelectorColor = 0x000000FF;
mSelectedTextColorOverride = 0x0000FF; mSelectedTextColorOverride = 0x0000FF;
mScrollSound = NULL; mScrollSound = NULL;
@ -35,7 +35,7 @@ template <typename listType>
void GuiList<listType>::onRender() void GuiList<listType>::onRender()
{ {
const int cutoff = getOffsetY(); const int cutoff = getOffsetY();
const int entrySize = Renderer::getFontHeight(mFont) + 5; const int entrySize = mFont->getHeight() + 5;
int startEntry = 0; int startEntry = 0;
@ -69,7 +69,7 @@ void GuiList<listType>::onRender()
//draw selector bar //draw selector bar
if(mSelection == i) if(mSelection == i)
{ {
Renderer::drawRect(getOffsetX(), y, Renderer::getScreenWidth(), Renderer::getFontHeight(mFont), mSelectorColor); Renderer::drawRect(getOffsetX(), y, Renderer::getScreenWidth(), mFont->getHeight(), mSelectorColor);
} }
ListRow row = mRowVector.at((unsigned int)i); ListRow row = mRowVector.at((unsigned int)i);

View file

@ -2,6 +2,7 @@
#define _GUILIST_H_ #define _GUILIST_H_
#include "../Renderer.h" #include "../Renderer.h"
#include "../Font.h"
#include "../GuiComponent.h" #include "../GuiComponent.h"
#include "../InputManager.h" #include "../InputManager.h"
#include <vector> #include <vector>
@ -52,7 +53,7 @@ private:
int mScrollDir, mScrollAccumulator; int mScrollDir, mScrollAccumulator;
bool mScrolling; bool mScrolling;
Renderer::FontSize mFont; Font* mFont;
unsigned int mSelectorColor, mSelectedTextColorOverride; unsigned int mSelectorColor, mSelectedTextColorOverride;
bool mDrawCentered; bool mDrawCentered;

View file

@ -6,7 +6,7 @@ GuiMenu::GuiMenu(GuiComponent* parent)
mParent = parent; mParent = parent;
parent->pause(); parent->pause();
mList = new GuiList<std::string>(0, Renderer::getFontHeight(Renderer::LARGE) + 2, Renderer::LARGE); mList = new GuiList<std::string>(0, Renderer::getDefaultFont(Renderer::LARGE)->getHeight() + 2, Renderer::LARGE);
populateList(); populateList();
addChild(mList); addChild(mList);

View file

@ -65,7 +65,7 @@ void GuiTheme::setDefaults()
mGameImageOriginX = 0.5; mGameImageOriginX = 0.5;
mGameImageOriginY = 0; mGameImageOriginY = 0;
mGameImageOffsetX = mListOffsetX / 2; mGameImageOffsetX = mListOffsetX / 2;
mGameImageOffsetY = (float)Renderer::getFontHeight(Renderer::LARGE) / Renderer::getScreenHeight(); mGameImageOffsetY = (float)Renderer::getDefaultFont(Renderer::LARGE)->getHeight() / Renderer::getScreenHeight();
mGameImageWidth = mListOffsetX; mGameImageWidth = mListOffsetX;
mGameImageHeight = 0; mGameImageHeight = 0;
@ -264,7 +264,7 @@ float GuiTheme::resolveExp(std::string str, float defaultVal)
exp.setExpression(str); exp.setExpression(str);
//set variables //set variables
exp.setVariable("headerHeight", Renderer::getFontHeight(Renderer::LARGE) / Renderer::getScreenHeight()); exp.setVariable("headerHeight", Renderer::getDefaultFont(Renderer::LARGE)->getHeight() / Renderer::getScreenHeight());
exp.setVariable("infoWidth", mListOffsetX); exp.setVariable("infoWidth", mListOffsetX);
return exp.eval(); return exp.eval();

View file

@ -166,7 +166,7 @@ int main(int argc, char* argv[])
ss << framerate; ss << framerate;
std::string fps; std::string fps;
ss >> fps; ss >> fps;
Renderer::drawText(fps, 50, 50, 0x00FF00); Renderer::drawText(fps, 50, 50, 0x00FF00, Renderer::getDefaultFont(Renderer::MEDIUM));
} }