advanced text render

This commit is contained in:
Eduardo Bart 2011-04-07 15:49:35 -03:00
parent 8d1281b316
commit f3df212793
5 changed files with 127 additions and 49 deletions

View File

@ -102,62 +102,119 @@ bool Font::load(const std::string& file)
} }
void Font::renderText(const Point& pos, const std::string& text) void Font::renderText(const Point& pos, const std::string& text)
{
Size boxSize = g_graphics.getScreenSize() - pos.toSize();
Rect screenCoords(pos, boxSize);
Font::renderText(screenCoords, text);
}
void Font::renderText(const Rect& screenCoords, const std::string& text, const Point& startRenderPosition, bool debug)
{ {
// 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());
Point currentPos = pos;
const Size& screenSize = g_graphics.getScreenSize();
const Size& textureSize = m_texture->getSize(); const Size& textureSize = m_texture->getSize();
int textLenght = text.length(); int textLenght = text.length();
// map glyphs positions
Point *glyphsPositions = mapGlyphsPositions(text);
for(int i = 0; i < textLenght; ++i) { for(int i = 0; i < textLenght; ++i) {
int glyph = (int)text[i]; int glyph = (int)text[i];
// break rendering if the Y pos is below the screen // skip invalid glyphs
if(currentPos.y >= screenSize.height()) if(glyph < 32)
break; continue;
// new line // calculate virtual glyph rect
if(glyph == (uchar)'\n') { Rect glyphScreenCoords(glyphsPositions[i], m_glyphsSize[glyph]);
currentPos.y += m_lineHeight; Rect glyphTextureCoords = m_glyphsTextureCoords[glyph];
currentPos.x = pos.x;
// only render glyphs that is visible after startRenderPosition
if(glyphScreenCoords.bottom() < startRenderPosition.y || glyphScreenCoords.right() < startRenderPosition.x)
continue;
// bound glyph topLeft to startRenderPosition
if(glyphScreenCoords.top() < startRenderPosition.y) {
glyphTextureCoords.setTop(glyphTextureCoords.top() + (startRenderPosition.y - glyphScreenCoords.top()));
glyphScreenCoords.setTop(startRenderPosition.y);
} }
// render only if the glyph is valid and visible if(glyphScreenCoords.left() < startRenderPosition.x) {
else if(glyph >= 32 && currentPos.x < screenSize.width()) { glyphTextureCoords.setLeft(glyphTextureCoords.left() + (startRenderPosition.x - glyphScreenCoords.left()));
g_graphics._drawTexturedRect(Rect(currentPos, m_glyphsSize[glyph]), glyphScreenCoords.setLeft(startRenderPosition.x);
m_glyphsTextureCoords[glyph],
textureSize);
currentPos.x += m_glyphsSize[glyph].width();
} }
// translate glyph
glyphScreenCoords.translate(-startRenderPosition);
glyphScreenCoords.translate(screenCoords.topLeft());
// only render if glyph rect is visible on screenCoords
if(!screenCoords.intersects(glyphScreenCoords))
continue;
// bound glyph bottomRight to screenCoords bottomRight
if(glyphScreenCoords.bottom() > screenCoords.bottom()) {
glyphTextureCoords.setBottom(glyphTextureCoords.bottom() + (screenCoords.bottom() - glyphScreenCoords.bottom()));
glyphScreenCoords.setBottom(screenCoords.bottom());
}
if(glyphScreenCoords.right() > screenCoords.right()) {
glyphTextureCoords.setRight(glyphTextureCoords.right() + (screenCoords.right() - glyphScreenCoords.right()));
glyphScreenCoords.setRight(screenCoords.right());
}
// render glyph
g_graphics._drawTexturedRect(glyphScreenCoords, glyphTextureCoords, textureSize);
} }
// end texture redering // end texture redering
g_graphics._endTextureRender(); g_graphics._endTextureRender();
g_graphics.resetColor(); g_graphics.resetColor();
// debug box if(debug)
//g_graphics.drawBoundingRect(Rect(pos, calculateTextSize(text)).expanded(1), Color(0xFF00FF00), 1); g_graphics.drawBoundingRect(screenCoords.expanded(1), Color(0xFF00FF00), 1);
} }
Size Font::calculateTextSize(const std::string& text) Size Font::calculateTextSize(const std::string& text, Point *glyphsPositions)
{ {
int textLenght = text.length(); if(!glyphsPositions) {
glyphsPositions = mapGlyphsPositions(text);
}
Size size; Size size;
Point currentPos(0,m_lineHeight); int numGlyphs = text.length();
for(int i = 0; i < numGlyphs; ++i) {
for(int i = 0; i < textLenght; ++i) { Point bottomLeft = glyphsPositions[i] + m_glyphsSize[(int)text[i]].toPoint();
int glyph = (int)text[i]; size = size.expandedTo(bottomLeft.toSize());
if(glyph == (uchar)'\n') {
currentPos.y += m_lineHeight;
currentPos.x = 0;
}
else if(glyph >= 32) {
currentPos.x += m_glyphsSize[glyph].width();
}
size = size.expandedTo(currentPos.toSize());
} }
return size; return size;
} }
Point* Font::mapGlyphsPositions(const std::string& text)
{
static Point glyphsPositions[8192];
int numGlyphs = text.length();
Point virtualPos;
if(numGlyphs > 8192)
logFatal("A text was too long to render!");
for(int i = 0; i < numGlyphs; ++i) {
int glyph = (int)text[i];
// store current glyph topLeft
glyphsPositions[i] = virtualPos;
// new line
if(glyph == (uchar)'\n') {
virtualPos.y += m_lineHeight;
virtualPos.x = 0;
}
// render only if the glyph is valid
else if(glyph >= 32) {
virtualPos.x += m_glyphsSize[glyph].width();
}
}
return (Point *)glyphsPositions;
}

View File

@ -42,18 +42,16 @@ public:
/// Simple text render starting at pos /// Simple text render starting at pos
void renderText(const Point& pos, const std::string& text); void renderText(const Point& pos, const std::string& text);
/// Render text delimited by screenCoords rect
void renderText(const Rect& screenCoords, const std::string& text);
/** Advanced text render /** Advanced text render
* screenCoords is the rect that will be filled on the screen * screenCoords is the rect that will be filled on the screen
* startRenderPosition is the postion to start rendering relative to the text rect * startRenderPosition is the postion to start rendering relative to the text rect
*/ */
void renderText(const Rect& screenCoords, const Point& startRenderPosition, const std::string& text); void renderText(const Rect& screenCoords, const std::string& text, const Point& startRenderPosition = Point(), bool debug = false);
/// Simulate render and calculate text size /// Simulate render and calculate text size
Size calculateTextSize(const std::string& text); 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,

View File

@ -96,15 +96,15 @@ public:
inline void moveBottomLeft(const TPoint<T> &p) { moveLeft(p.x); moveBottom(p.y); } inline void moveBottomLeft(const TPoint<T> &p) { moveLeft(p.x); moveBottom(p.y); }
inline TRect<T> translated(int x, int y) const { return TRect<T>(TPoint<T>(x1 + x, y1 + y), TPoint<T>(x2 + x, y2 + y)); } inline TRect<T> translated(int x, int y) const { return TRect<T>(TPoint<T>(x1 + x, y1 + y), TPoint<T>(x2 + x, y2 + y)); }
inline TRect<T> translated(const TPoint<T> &p) const { return TRect<T>(TPoint<T>(x1 + p.x(), y1 + p.y()), TPoint<T>(x2 + p.x(), y2 + p.y())); } inline TRect<T> translated(const TPoint<T> &p) const { return TRect<T>(TPoint<T>(x1 + p.x, y1 + p.y), TPoint<T>(x2 + p.x, y2 + p.y)); }
inline TRect<T> expanded(T pixels) { return TRect<T>(TPoint<T>(x1 - pixels, y1 - pixels), TPoint<T>(x2 + pixels, y2 + pixels)); } inline TRect<T> expanded(T pixels) const { return TRect<T>(TPoint<T>(x1 - pixels, y1 - pixels), TPoint<T>(x2 + pixels, y2 + pixels)); }
inline void moveCenter(const TPoint<T> &p) { inline void moveCenter(const TPoint<T> &p) {
T w = x2 - x1; T w = x2 - x1;
T h = y2 - y1; T h = y2 - y1;
x1 = p.x() - w/2; x1 = p.x - w/2;
y1 = p.y() - h/2; y1 = p.y - h/2;
x2 = x1 + w; x2 = x1 + w;
y2 = y1 + h; y2 = y1 + h;
} }
@ -119,10 +119,10 @@ public:
r = x2; r = x2;
} }
if(insideOnly) { if(insideOnly) {
if(p.x() <= l || p.x() >= r) if(p.x <= l || p.x >= r)
return false; return false;
} else { } else {
if(p.x() < l || p.x() > r) if(p.x < l || p.x > r)
return false; return false;
} }
int t, b; int t, b;
@ -134,10 +134,10 @@ public:
b = y2; b = y2;
} }
if(insideOnly) { if(insideOnly) {
if(p.y() <= t || p.y() >= b) if(p.y <= t || p.y >= b)
return false; return false;
} else { } else {
if(p.y() < t || p.y() > b) if(p.y < t || p.y > b)
return false; return false;
} }
return true; return true;

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

@ -30,6 +30,7 @@
#include "framework/engine.h" #include "framework/engine.h"
#include "framework/rect.h" #include "framework/rect.h"
#include "framework/fonts.h" #include "framework/fonts.h"
#include "framework/input.h"
TexturePtr background; TexturePtr background;
@ -49,8 +50,24 @@ void MenuState::onClose()
g_engine.stop(); g_engine.stop();
} }
int x, y;
void MenuState::onInputEvent(InputEvent* event) void MenuState::onInputEvent(InputEvent* event)
{ {
static bool moving = false;
static int lastX;
static int lastY;
if(event->type == EV_MOUSE_LDOWN) {
moving = true;
lastX = event->mouse.x;
lastY = event->mouse.y;
} else if(event->type == EV_MOUSE_LUP) {
moving = false;
} else if(event->type == EV_MOUSE_MOVE) {
if(moving) {
x = lastX - event->mouse.x;
y = lastY - event->mouse.y;
}
}
} }
void MenuState::render() void MenuState::render()
@ -67,9 +84,15 @@ void MenuState::render()
Rect texCoords(0, 0, texCoordsSize); Rect texCoords(0, 0, texCoordsSize);
texCoords.moveBottomRight(texSize.toPoint()); texCoords.moveBottomRight(texSize.toPoint());
g_graphics.drawTexturedRect(Rect(0, 0, screenSize), m_background.get(), texCoords); g_graphics.drawTexturedRect(Rect(0, 0, screenSize), m_background.get(), texCoords);
g_defaultFont->renderText(Point(10,screenSize.height() - 50), "Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n"
"Sed blandit justo in lectus ornare ultricies.\n" static const char *text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n"
"Integer faucibus magna quis metus fermentum suscipit."); "Nulla pulvinar odio ac arcu tempor consequat.\n"
"Praesent at enim sapien, at vestibulum ligula.\n"
"Aliquam eleifend ante eu sapien vehicula consectetur.\n"
"Nunc id ligula ligula, eget vestibulum magna.\n"
"In mattis nisi non nisl semper ultricies.\n";
Size textSize = g_defaultFont->calculateTextSize(text);
g_defaultFont->renderText(Rect(100, 100, textSize.width() - 120, textSize.height() - 15), text, Point(x,y), true);
} }
void MenuState::update(int ticks, int elapsedTicks) void MenuState::update(int ticks, int elapsedTicks)