Fixed text rendering bug. Organized UI stuff.

This commit is contained in:
Tiberiu Chibici 2016-11-29 00:20:48 +02:00
parent 70f79935da
commit d2c335bfa5
11 changed files with 99 additions and 46 deletions

View File

@ -61,7 +61,7 @@ void FarmlandsGame::onRender()
{ {
m_gameState.sdlRenderer.renderBegin(); m_gameState.sdlRenderer.renderBegin();
m_gameState.gameRenderer.render(); m_gameState.gameRenderer.render();
m_gameState.guiRenderer.render(); // m_gameState.guiRenderer.render();
m_guiController.render(); m_guiController.render();
m_gameState.sdlRenderer.renderEnd(); m_gameState.sdlRenderer.renderEnd();
} }

View File

@ -7,8 +7,8 @@
#include <GameState.h> #include <GameState.h>
#include <controller/GuiController.h> #include <controller/GuiController.h>
#include <gui/primitives/RenderContext.h> #include <gui/RenderContext.h>
#include <gui/primitives/TextArea.h> #include <gui/widgets/TextArea.h>
#include <cassert> #include <cassert>
@ -37,14 +37,16 @@ void GuiController::initialize(GameState* gameState)
m_canvas.setSize(m_gameState->viewport.width, m_gameState->viewport.height); m_canvas.setSize(m_gameState->viewport.width, m_gameState->viewport.height);
// Add a text element // Add a text element
auto text = new gui::primitives::TextArea(); auto text = new gui::widgets::TextArea();
text->setText("Hello world!\nMy name is Tibi!\nThis is a really really long long long, even the longest ever, line."); text->setText("Hello world!\nMy name is Tibi!\nThis is a really really long long long, even the longest ever, line.\nThis is a very loooooooooooooooooong word.");
text->setSize(200, 100); text->setSize(200, 200);
text->setPosition(100, 10); text->setPosition(100, 10);
text->setColor(0, 1, 0); text->setColor(0, 1, 0);
text->setBackColor(0.5f, 0, 0, 0.5f); text->setBackColor(0.5f, 0, 0, 0.5f);
text->setTextSize(11); text->setTextSize(11);
text->setHorizontalWrap(gui::primitives::TextHorizontalWrapping::Ellipsis); text->setHorizontalWrap(gui::widgets::TextHorizontalWrapping::Wrap);
text->setVerticalWrap(gui::widgets::TextVerticalWrapping::Trim);
text->setAlignment(gui::widgets::TextAlign::BottomRight);
m_canvas.addChild(text); m_canvas.addChild(text);
} }
@ -57,11 +59,11 @@ bool GuiController::processEvent(SDL_Event& event)
if (event.type == SDL_EventType::SDL_KEYDOWN && event.key.keysym.scancode == SDL_SCANCODE_HOME) if (event.type == SDL_EventType::SDL_KEYDOWN && event.key.keysym.scancode == SDL_SCANCODE_HOME)
{ {
m_canvas.child(0)->setSize(currentW + 50, currentH); m_canvas.child(0)->setSize(currentW + 5, currentH);
} }
if (event.type == SDL_EventType::SDL_KEYDOWN && event.key.keysym.scancode == SDL_SCANCODE_END) if (event.type == SDL_EventType::SDL_KEYDOWN && event.key.keysym.scancode == SDL_SCANCODE_END)
{ {
m_canvas.child(0)->setSize(currentW - 50, currentH); m_canvas.child(0)->setSize(currentW - 5, currentH);
} }
return handled; return handled;
@ -70,7 +72,7 @@ bool GuiController::processEvent(SDL_Event& event)
void GuiController::render() void GuiController::render()
{ {
// Compute render context // Compute render context
gui::primitives::RenderContext renderContext = gui::RenderContext renderContext =
{ {
.sdlRenderer = &m_gameState->sdlRenderer, .sdlRenderer = &m_gameState->sdlRenderer,
.resManager = &m_gameState->resManager, .resManager = &m_gameState->resManager,

View File

@ -8,7 +8,7 @@
#ifndef CONTROLLER_GUICONTROLLER_H_ #ifndef CONTROLLER_GUICONTROLLER_H_
#define CONTROLLER_GUICONTROLLER_H_ #define CONTROLLER_GUICONTROLLER_H_
#include <gui/Canvas.h> #include <gui/layout/Canvas.h>
#include <SDL2/SDL.h> #include <SDL2/SDL.h>
@ -42,7 +42,7 @@ namespace controller {
private: private:
GameState* m_gameState; GameState* m_gameState;
gui::Canvas m_canvas; gui::layout::Canvas m_canvas;
}; };
} /* namespace controller */ } /* namespace controller */

View File

@ -13,7 +13,6 @@
namespace farmlands { namespace farmlands {
namespace gui { namespace gui {
namespace primitives {
struct RenderContext struct RenderContext
{ {
@ -24,6 +23,5 @@ namespace primitives {
} }
} }
}
#endif /* GUI_PRIMITIVES_RENDERCONTEXT_H_ */ #endif /* GUI_PRIMITIVES_RENDERCONTEXT_H_ */

View File

@ -5,10 +5,11 @@
* Author: tibi * Author: tibi
*/ */
#include <gui/Canvas.h> #include <gui/layout/Canvas.h>
namespace farmlands { namespace farmlands {
namespace gui { namespace gui {
namespace layout {
Canvas::Canvas() Canvas::Canvas()
{ {
@ -18,11 +19,12 @@ Canvas::~Canvas()
{ {
} }
void Canvas::render(primitives::RenderContext& context) void Canvas::render(RenderContext& context)
{ {
for (auto child : m_children) for (auto child : m_children)
child->render(context); child->render(context);
} }
}
} /* namespace gui */ } /* namespace gui */
} /* namespace farmlands */ } /* namespace farmlands */

View File

@ -9,10 +9,11 @@
#define GUI_PRIMITIVES_CANVAS_H_ #define GUI_PRIMITIVES_CANVAS_H_
#include <gui/primitives/UILayout.h> #include <gui/primitives/UILayout.h>
#include <gui/primitives/RenderContext.h> #include <gui/RenderContext.h>
namespace farmlands { namespace farmlands {
namespace gui { namespace gui {
namespace layout {
class Canvas: public primitives::UILayout class Canvas: public primitives::UILayout
{ {
@ -20,9 +21,10 @@ namespace gui {
Canvas(); Canvas();
virtual ~Canvas(); virtual ~Canvas();
virtual void render(primitives::RenderContext& context) override; virtual void render(RenderContext& context) override;
}; };
}
} /* namespace gui */ } /* namespace gui */
} /* namespace farmlands */ } /* namespace farmlands */

View File

@ -10,7 +10,7 @@
#include <SDL2/SDL.h> #include <SDL2/SDL.h>
#include <gui/primitives/RenderContext.h> #include <gui/RenderContext.h>
namespace farmlands { namespace farmlands {
namespace gui { namespace gui {

View File

@ -5,13 +5,13 @@
* Author: tibi * Author: tibi
*/ */
#include <gui/primitives/Image.h> #include <gui/widgets/Image.h>
namespace farmlands namespace farmlands
{ {
namespace gui namespace gui
{ {
namespace primitives namespace widgets
{ {
Image::Image() Image::Image()

View File

@ -12,9 +12,9 @@
namespace farmlands { namespace farmlands {
namespace gui { namespace gui {
namespace primitives { namespace widgets {
class Image: public UIElement class Image: public primitives::UIElement
{ {
public: public:
Image(); Image();

View File

@ -5,7 +5,7 @@
* Author: tibi * Author: tibi
*/ */
#include <gui/primitives/TextArea.h> #include <gui/widgets/TextArea.h>
#include <resources/Resources.h> #include <resources/Resources.h>
#include <cassert> #include <cassert>
@ -18,7 +18,7 @@ namespace farmlands
{ {
namespace gui namespace gui
{ {
namespace primitives namespace widgets
{ {
TextArea::TextArea() TextArea::TextArea()
@ -30,7 +30,8 @@ TextArea::TextArea()
m_color(), m_color(),
m_align(TextAlign::MiddleCenter), m_align(TextAlign::MiddleCenter),
m_horWrap(TextHorizontalWrapping::Wrap), m_horWrap(TextHorizontalWrapping::Wrap),
m_verWrap(TextVerticalWrapping::Overflow) m_verWrap(TextVerticalWrapping::Overflow),
m_renderedLines()
{ {
} }
@ -49,26 +50,51 @@ void TextArea::render(RenderContext& context)
// Split text in lines // Split text in lines
if (m_textChanged) if (m_textChanged)
{
wrapText(font); wrapText(font);
renderLines(context, font);
}
std::vector<std::string> lines; // Compute y location of first line
boost::split(lines, m_wrappedText, boost::is_any_of("\n"), boost::token_compress_off);
// Render lines
int lineH = TTF_FontLineSkip(font); int lineH = TTF_FontLineSkip(font);
int totalH = 0; int totalH = 0;
for (auto line : lines) if (m_align == TextAlign::MiddleLeft || m_align == TextAlign::MiddleCenter || m_align == TextAlign::MiddleRight)
{ {
SDL_Rect dest = int spaceLeft = height() - lineH * m_renderedLines.size();
totalH = spaceLeft / 2;
}
else if (m_align == TextAlign::BottomLeft || m_align == TextAlign::BottomCenter || m_align == TextAlign::BottomRight)
{ {
(int) x(), (int) (y() + totalH), int spaceLeft = height() - lineH * m_renderedLines.size();
0, 0 totalH = spaceLeft;
}; }
SDL_Texture* tex = context.sdlRenderer->renderText(line.c_str(), font, m_color); // Draw each line
SDL_QueryTexture(tex, NULL, NULL, &dest.w, &dest.h); for (SDL_Texture* lineTexture : m_renderedLines)
SDL_RenderCopy(context.sdlRenderer->internalRenderer(), tex, NULL, &dest); {
SDL_Rect dest;
SDL_QueryTexture(lineTexture, NULL, NULL, &dest.w, &dest.h);
// Compute X position
dest.x = x();
if (m_align == TextAlign::TopCenter || m_align == TextAlign::MiddleCenter || m_align == TextAlign::BottomCenter)
{
int spaceLeft = width() - dest.w;
dest.x += spaceLeft / 2;
}
else if (m_align == TextAlign::TopRight || m_align == TextAlign::MiddleRight || m_align == TextAlign::BottomRight)
{
int spaceLeft = width() - dest.w;
dest.x += spaceLeft;
}
// Compute Y position
dest.y = y() + totalH;
// Draw
SDL_RenderCopy(context.sdlRenderer->internalRenderer(), lineTexture, NULL, &dest);
totalH += lineH; totalH += lineH;
} }
@ -199,17 +225,16 @@ void TextArea::wrapText(TTF_Font* font)
} }
m_wrappedText[wordBegin] = '\n'; m_wrappedText[wordBegin] = '\n';
i = wordBegin;
// Trim line // Trim rest of line
if (m_horWrap == TextHorizontalWrapping::Trim || m_horWrap == TextHorizontalWrapping::Ellipsis) if (m_horWrap == TextHorizontalWrapping::Trim || m_horWrap == TextHorizontalWrapping::Ellipsis)
{ {
i = wordBegin + 1; size_t nextLine = i + 1;
size_t nextLine = i;
while (nextLine < m_wrappedText.size() && m_wrappedText[nextLine] != '\n') while (nextLine < m_wrappedText.size() && m_wrappedText[nextLine] != '\n')
++nextLine; ++nextLine;
m_wrappedText.erase(i, nextLine + 1); m_wrappedText.erase(i, nextLine - i);
} }
} }
} }
@ -227,6 +252,27 @@ void TextArea::wrapText(TTF_Font* font)
totalH += lineHeight; totalH += lineHeight;
} }
} }
m_wrappedText.erase(m_wrappedText.size() - 1);
}
void TextArea::renderLines(RenderContext& context, TTF_Font* font)
{
// Clean up old textures
for (SDL_Texture* tex : m_renderedLines)
SDL_DestroyTexture(tex);
m_renderedLines.clear();
// Break down string into lines
std::vector<std::string> lines;
boost::split(lines, m_wrappedText, boost::is_any_of("\n"), boost::token_compress_off);
for (std::string line : lines)
{
// Render line
SDL_Texture* tex = context.sdlRenderer->renderText(line, font, m_color);
m_renderedLines.push_back(tex);
}
} }
} /* namespace primitives */ } /* namespace primitives */

View File

@ -14,7 +14,7 @@
namespace farmlands { namespace farmlands {
namespace gui { namespace gui {
namespace primitives { namespace widgets {
enum class TextAlign enum class TextAlign
{ {
@ -43,7 +43,7 @@ namespace primitives {
Trim Trim
}; };
class TextArea: public UIElement class TextArea: public primitives::UIElement
{ {
public: public:
TextArea(); TextArea();
@ -71,6 +71,7 @@ namespace primitives {
private: private:
void wrapText(TTF_Font* font); void wrapText(TTF_Font* font);
void renderLines(RenderContext& context, TTF_Font* font);
std::string m_text; std::string m_text;
std::string m_wrappedText; std::string m_wrappedText;
@ -82,6 +83,8 @@ namespace primitives {
TextAlign m_align; TextAlign m_align;
TextHorizontalWrapping m_horWrap; TextHorizontalWrapping m_horWrap;
TextVerticalWrapping m_verWrap; TextVerticalWrapping m_verWrap;
std::vector<SDL_Texture*> m_renderedLines;
}; };
} /* namespace primitives */ } /* namespace primitives */