diff --git a/src/framework/font.cpp b/src/framework/font.cpp index 0118e40d..f73733b7 100644 --- a/src/framework/font.cpp +++ b/src/framework/font.cpp @@ -102,62 +102,119 @@ bool Font::load(const std::string& file) } 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 g_graphics.setColor(m_color); g_graphics._beginTextureRender(m_texture.get()); - Point currentPos = pos; - const Size& screenSize = g_graphics.getScreenSize(); const Size& textureSize = m_texture->getSize(); int textLenght = text.length(); + // map glyphs positions + Point *glyphsPositions = mapGlyphsPositions(text); + for(int i = 0; i < textLenght; ++i) { int glyph = (int)text[i]; - // break rendering if the Y pos is below the screen - if(currentPos.y >= screenSize.height()) - break; + // skip invalid glyphs + if(glyph < 32) + continue; - // new line - if(glyph == (uchar)'\n') { - currentPos.y += m_lineHeight; - currentPos.x = pos.x; + // calculate virtual glyph rect + Rect glyphScreenCoords(glyphsPositions[i], m_glyphsSize[glyph]); + Rect glyphTextureCoords = m_glyphsTextureCoords[glyph]; + + // 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 - else if(glyph >= 32 && currentPos.x < screenSize.width()) { - g_graphics._drawTexturedRect(Rect(currentPos, m_glyphsSize[glyph]), - m_glyphsTextureCoords[glyph], - textureSize); - currentPos.x += m_glyphsSize[glyph].width(); + if(glyphScreenCoords.left() < startRenderPosition.x) { + glyphTextureCoords.setLeft(glyphTextureCoords.left() + (startRenderPosition.x - glyphScreenCoords.left())); + glyphScreenCoords.setLeft(startRenderPosition.x); } + + // 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 g_graphics._endTextureRender(); g_graphics.resetColor(); - // debug box - //g_graphics.drawBoundingRect(Rect(pos, calculateTextSize(text)).expanded(1), Color(0xFF00FF00), 1); + if(debug) + 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; - Point currentPos(0,m_lineHeight); + 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; +} - for(int i = 0; i < textLenght; ++i) { +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') { - currentPos.y += m_lineHeight; - currentPos.x = 0; + virtualPos.y += m_lineHeight; + virtualPos.x = 0; } + // render only if the glyph is valid else if(glyph >= 32) { - currentPos.x += m_glyphsSize[glyph].width(); + virtualPos.x += m_glyphsSize[glyph].width(); } - size = size.expandedTo(currentPos.toSize()); } - return size; + + return (Point *)glyphsPositions; } diff --git a/src/framework/font.h b/src/framework/font.h index dc50d42c..a0981d14 100644 --- a/src/framework/font.h +++ b/src/framework/font.h @@ -42,18 +42,16 @@ public: /// Simple text render starting at pos 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 * 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 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 - Size calculateTextSize(const std::string& text); + Size calculateTextSize(const std::string& text, Point *glyphsPositions = NULL); + Point *mapGlyphsPositions(const std::string& text); /* enum EAlign { ALIGN_TOP = 1 << 0, diff --git a/src/framework/rect.h b/src/framework/rect.h index c4a58be5..90857df0 100644 --- a/src/framework/rect.h +++ b/src/framework/rect.h @@ -96,15 +96,15 @@ public: inline void moveBottomLeft(const TPoint &p) { moveLeft(p.x); moveBottom(p.y); } inline TRect translated(int x, int y) const { return TRect(TPoint(x1 + x, y1 + y), TPoint(x2 + x, y2 + y)); } - inline TRect translated(const TPoint &p) const { return TRect(TPoint(x1 + p.x(), y1 + p.y()), TPoint(x2 + p.x(), y2 + p.y())); } + inline TRect translated(const TPoint &p) const { return TRect(TPoint(x1 + p.x, y1 + p.y), TPoint(x2 + p.x, y2 + p.y)); } - inline TRect expanded(T pixels) { return TRect(TPoint(x1 - pixels, y1 - pixels), TPoint(x2 + pixels, y2 + pixels)); } + inline TRect expanded(T pixels) const { return TRect(TPoint(x1 - pixels, y1 - pixels), TPoint(x2 + pixels, y2 + pixels)); } inline void moveCenter(const TPoint &p) { T w = x2 - x1; T h = y2 - y1; - x1 = p.x() - w/2; - y1 = p.y() - h/2; + x1 = p.x - w/2; + y1 = p.y - h/2; x2 = x1 + w; y2 = y1 + h; } @@ -119,10 +119,10 @@ public: r = x2; } if(insideOnly) { - if(p.x() <= l || p.x() >= r) + if(p.x <= l || p.x >= r) return false; } else { - if(p.x() < l || p.x() > r) + if(p.x < l || p.x > r) return false; } int t, b; @@ -134,10 +134,10 @@ public: b = y2; } if(insideOnly) { - if(p.y() <= t || p.y() >= b) + if(p.y <= t || p.y >= b) return false; } else { - if(p.y() < t || p.y() > b) + if(p.y < t || p.y > b) return false; } return true; diff --git a/src/main.cpp b/src/main.cpp index a16149bd..90577feb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -101,7 +101,7 @@ int main(int argc, const char *argv[]) 640, 480, g_configs.getBoolean("window maximized")); Platform::setWindowTitle("OTClient"); - //Platform::setVsync(); + Platform::setVsync(); // init engine g_engine.init(); diff --git a/src/menustate.cpp b/src/menustate.cpp index 96393132..1362074a 100644 --- a/src/menustate.cpp +++ b/src/menustate.cpp @@ -30,6 +30,7 @@ #include "framework/engine.h" #include "framework/rect.h" #include "framework/fonts.h" +#include "framework/input.h" TexturePtr background; @@ -49,8 +50,24 @@ void MenuState::onClose() g_engine.stop(); } +int x, y; 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() @@ -67,9 +84,15 @@ void MenuState::render() Rect texCoords(0, 0, texCoordsSize); texCoords.moveBottomRight(texSize.toPoint()); 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" - "Integer faucibus magna quis metus fermentum suscipit."); + + static const char *text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n" + "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)