text align rendering

This commit is contained in:
Eduardo Bart 2011-04-07 17:36:40 -03:00
parent 7739c7bb29
commit 8a33e0cf19
5 changed files with 136 additions and 68 deletions

View File

@ -102,12 +102,11 @@ void Engine::run()
// render fps // render fps
if(m_calculateFps) { if(m_calculateFps) {
g_defaultFont->renderText(fpsPos, format("FPS: %d", fps)); g_defaultFont->renderText(format("FPS: %d", fps), fpsPos);
} }
// swap buffers // swap buffers
Platform::swapBuffers(); Platform::swapBuffers();
//}
} }
} }

View File

@ -101,15 +101,24 @@ bool Font::load(const std::string& file)
return true; return true;
} }
void Font::renderText(const Point& pos, const std::string& text) void Font::renderText(const std::string& text,
const Point& startPos)
{ {
Size boxSize = g_graphics.getScreenSize() - pos.toSize(); Size boxSize = g_graphics.getScreenSize() - startPos.toSize();
Rect screenCoords(pos, boxSize); Rect screenCoords(startPos, boxSize);
Font::renderText(screenCoords, text); Font::renderText(text, screenCoords);
} }
void Font::renderText(const Rect& screenCoords, const std::string& text, const Point& startRenderPosition, bool debug) void Font::renderText(const std::string& text,
const Rect& screenCoords,
int align,
const Point& startInternalPos,
bool debug)
{ {
// prevent glitches from invalid rects
if(!screenCoords.isValid())
return;
// begin texture rendering // begin texture rendering
g_graphics.setColor(m_color); g_graphics.setColor(m_color);
g_graphics._beginTextureRender(m_texture.get()); g_graphics._beginTextureRender(m_texture.get());
@ -118,7 +127,8 @@ void Font::renderText(const Rect& screenCoords, const std::string& text, const P
int textLenght = text.length(); int textLenght = text.length();
// map glyphs positions // map glyphs positions
Point *glyphsPositions = mapGlyphsPositions(text); Size textBoxSize;
Point *glyphsPositions = calculateGlyphsPositions(text, align, &textBoxSize);
for(int i = 0; i < textLenght; ++i) { for(int i = 0; i < textLenght; ++i) {
int glyph = (int)text[i]; int glyph = (int)text[i];
@ -127,26 +137,45 @@ void Font::renderText(const Rect& screenCoords, const std::string& text, const P
if(glyph < 32) if(glyph < 32)
continue; continue;
// calculate virtual glyph rect // calculate initial glyph rect and texture coords
Rect glyphScreenCoords(glyphsPositions[i], m_glyphsSize[glyph]); Rect glyphScreenCoords(glyphsPositions[i], m_glyphsSize[glyph]);
Rect glyphTextureCoords = m_glyphsTextureCoords[glyph]; Rect glyphTextureCoords = m_glyphsTextureCoords[glyph];
// only render glyphs that is visible after startRenderPosition // first translate to align position
if(glyphScreenCoords.bottom() < startRenderPosition.y || glyphScreenCoords.right() < startRenderPosition.x) if(align & ALIGN_BOTTOM) {
glyphScreenCoords.translate(0, screenCoords.height() - textBoxSize.height());
} else if(align & ALIGN_VERTICAL_CENTER) {
glyphScreenCoords.translate(0, (screenCoords.height() - textBoxSize.height()) / 2);
} else { // ALIGN_TOP
// nothing to do
}
if(align & ALIGN_RIGHT) {
glyphScreenCoords.translate(screenCoords.width() - textBoxSize.width(), 0);
} else if(align & ALIGN_HORIZONTAL_CENTER) {
glyphScreenCoords.translate((screenCoords.width() - textBoxSize.width()) / 2, 0);
} else { // ALIGN_TOP
// nothing to do
}
// only render glyphs that are after startRenderPosition
if(glyphScreenCoords.bottom() < startInternalPos.y || glyphScreenCoords.right() < startInternalPos.x)
continue; continue;
// bound glyph topLeft to startRenderPosition // bound glyph topLeft to startRenderPosition
if(glyphScreenCoords.top() < startRenderPosition.y) { if(glyphScreenCoords.top() < startInternalPos.y) {
glyphTextureCoords.setTop(glyphTextureCoords.top() + (startRenderPosition.y - glyphScreenCoords.top())); glyphTextureCoords.setTop(glyphTextureCoords.top() + (startInternalPos.y - glyphScreenCoords.top()));
glyphScreenCoords.setTop(startRenderPosition.y); glyphScreenCoords.setTop(startInternalPos.y);
} }
if(glyphScreenCoords.left() < startRenderPosition.x) { if(glyphScreenCoords.left() < startInternalPos.x) {
glyphTextureCoords.setLeft(glyphTextureCoords.left() + (startRenderPosition.x - glyphScreenCoords.left())); glyphTextureCoords.setLeft(glyphTextureCoords.left() + (startInternalPos.x - glyphScreenCoords.left()));
glyphScreenCoords.setLeft(startRenderPosition.x); glyphScreenCoords.setLeft(startInternalPos.x);
} }
// translate glyph // subtract startInternalPos
glyphScreenCoords.translate(-startRenderPosition); glyphScreenCoords.translate(-startInternalPos);
// translate rect to screen coords
glyphScreenCoords.translate(screenCoords.topLeft()); glyphScreenCoords.translate(screenCoords.topLeft());
// only render if glyph rect is visible on screenCoords // only render if glyph rect is visible on screenCoords
@ -175,46 +204,78 @@ void Font::renderText(const Rect& screenCoords, const std::string& text, const P
g_graphics.drawBoundingRect(screenCoords.expanded(1), Color(0xFF00FF00), 1); g_graphics.drawBoundingRect(screenCoords.expanded(1), Color(0xFF00FF00), 1);
} }
Size Font::calculateTextSize(const std::string& text, Point *glyphsPositions) Point* Font::calculateGlyphsPositions(const std::string& text, int align, Size *textBoxSize)
{
if(!glyphsPositions) {
glyphsPositions = mapGlyphsPositions(text);
}
Size size;
int numGlyphs = text.length();
for(int i = 0; i < numGlyphs; ++i) {
Point bottomLeft = glyphsPositions[i] + m_glyphsSize[(int)text[i]].toPoint();
size = size.expandedTo(bottomLeft.toSize());
}
return size;
}
Point* Font::mapGlyphsPositions(const std::string& text)
{ {
static Point glyphsPositions[8192]; static Point glyphsPositions[8192];
int numGlyphs = text.length(); static int lineWidths[512];
Point virtualPos; int maxLineWidth = 0;
int lines = 0;
int glyph;
int i;
// protect buffer overflow on glyphsPostions
int numGlyphs = text.length();
if(numGlyphs > 8192) if(numGlyphs > 8192)
logFatal("A text was too long to render!"); logFatal("A text was too long to render!");
for(int i = 0; i < numGlyphs; ++i) { // calculate lines width
int glyph = (int)text[i]; if((align & ALIGN_RIGHT || align & ALIGN_HORIZONTAL_CENTER) || textBoxSize) {
lineWidths[0] = 0;
for(i = 0; i< numGlyphs; ++i) {
glyph = (int)text[i];
if(glyph == (uchar)'\n') {
lineWidths[++lines] = 0;
} else if(glyph >= 32) {
lineWidths[lines] += m_glyphsSize[glyph].width();
maxLineWidth = std::max(maxLineWidth, lineWidths[lines]);
}
}
}
Point virtualPos;
lines = 0;
for(i = 0; i < numGlyphs; ++i) {
glyph = (int)text[i];
// store current glyph topLeft // store current glyph topLeft
glyphsPositions[i] = virtualPos; glyphsPositions[i] = virtualPos;
// new line // new line or first glyph
if(glyph == (uchar)'\n' || i == 0) {
if(glyph == (uchar)'\n') { if(glyph == (uchar)'\n') {
virtualPos.y += m_lineHeight; virtualPos.y += m_lineHeight;
lines++;
}
// calculate start x pos
if(align & ALIGN_RIGHT) {
virtualPos.x = (maxLineWidth - lineWidths[lines]);
} else if(align & ALIGN_HORIZONTAL_CENTER) {
virtualPos.x = (maxLineWidth - lineWidths[lines]) / 2;
} else { // ALIGN_LEFT
virtualPos.x = 0; virtualPos.x = 0;
} }
}
// render only if the glyph is valid // render only if the glyph is valid
else if(glyph >= 32) { if(glyph >= 32 && glyph != (uchar)'\n') {
virtualPos.x += m_glyphsSize[glyph].width(); virtualPos.x += m_glyphsSize[glyph].width();
} }
} }
if(textBoxSize) {
textBoxSize->setWidth(maxLineWidth);
textBoxSize->setHeight(virtualPos.y + m_lineHeight);
}
return (Point *)glyphsPositions; return (Point *)glyphsPositions;
} }
Size Font::calculateTextBoxSize(const std::string& text)
{
Size size;
calculateGlyphsPositions(text, ALIGN_TOP_LEFT, &size);
return size;
}

View File

@ -30,29 +30,6 @@
#include "texture.h" #include "texture.h"
#include "rect.h" #include "rect.h"
class Font
{
public:
Font();
virtual ~Font() { }
/// Load font from file
bool load(const std::string &file);
/// Simple text render starting at pos
void renderText(const Point& pos, const std::string& text);
/** Advanced text render
* screenCoords is the rect that will be filled on the screen
* startRenderPosition is the postion to start rendering relative to the text rect
*/
void renderText(const Rect& screenCoords, const std::string& text, const Point& startRenderPosition = Point(), bool debug = false);
/// Simulate render and calculate text size
Size calculateTextSize(const std::string& text, Point *glyphsPositions = NULL);
Point *mapGlyphsPositions(const std::string& text);
/*
enum EAlign { enum EAlign {
ALIGN_TOP = 1 << 0, ALIGN_TOP = 1 << 0,
ALIGN_BOTTOM = 1 << 1, ALIGN_BOTTOM = 1 << 1,
@ -66,6 +43,37 @@ public:
ALIGN_BOTTOM_RIGHT = ALIGN_BOTTOM | ALIGN_RIGHT, ALIGN_BOTTOM_RIGHT = ALIGN_BOTTOM | ALIGN_RIGHT,
ALIGN_BOTTOM_LEFT = ALIGN_BOTTOM | ALIGN_LEFT ALIGN_BOTTOM_LEFT = ALIGN_BOTTOM | ALIGN_LEFT
}; };
class Font
{
public:
Font();
virtual ~Font() { }
/// Load font from file
bool load(const std::string &file);
/// Simple text render starting at pos
void renderText(const std::string& text,
const Point& startPos);
/** Advanced text render
* screenCoords is the rect that will be filled on the screen
* startRenderPosition is the postion to start rendering relative to the text rect
*/
void renderText(const std::string& text,
const Rect& screenCoords,
int align = ALIGN_TOP_LEFT,
const Point& startInternalPos = Point(),
bool debug = false);
/// Calculate glyphs positions to use on render, also calculates textBoxSize if wanted
Point *calculateGlyphsPositions(const std::string& text, int align = ALIGN_TOP_LEFT, Size *textBoxSize = NULL);
/// Simulate render and calculate text size
Size calculateTextBoxSize(const std::string& text);
/*
/// Render a text inside a rect /// Render a text inside a rect
void renderText(const Rect& screenCoords, EAlign align, const std::string& text); void renderText(const Rect& screenCoords, EAlign align, const std::string& text);
*/ */

View File

@ -101,7 +101,7 @@ int main(int argc, const char *argv[])
640, 480, 640, 480,
g_configs.getBoolean("window maximized")); g_configs.getBoolean("window maximized"));
Platform::setWindowTitle("OTClient"); Platform::setWindowTitle("OTClient");
Platform::setVsync(); //Platform::setVsync();
// init engine // init engine
g_engine.init(); g_engine.init();

View File

@ -94,9 +94,9 @@ void MenuState::render()
"Praesent at enim sapien, at vestibulum ligula.\n" "Praesent at enim sapien, at vestibulum ligula.\n"
"Aliquam eleifend ante eu sapien vehicula consectetur.\n" "Aliquam eleifend ante eu sapien vehicula consectetur.\n"
"Nunc id ligula ligula, eget vestibulum magna.\n" "Nunc id ligula ligula, eget vestibulum magna.\n"
"In mattis nisi non nisl semper ultricies.\n"; "In mattis nisi non nisl semper ultricies.";
Size textSize = g_defaultFont->calculateTextSize(text); Size textSize = g_defaultFont->calculateTextBoxSize(text);
g_defaultFont->renderText(Rect(100, 100, textSize.width() - 120, textSize.height() - 15), text, Point(x,y), true); g_defaultFont->renderText(text, Rect(100, 100, textSize.width()-30, textSize.height()-30), ALIGN_CENTER, Point(x,y), true);
} }
void MenuState::update(int ticks, int elapsedTicks) void MenuState::update(int ticks, int elapsedTicks)