From b9b2c4a962f66e13e41ba457051b7634f86122ed Mon Sep 17 00:00:00 2001 From: vrld Date: Sun, 9 Jan 2011 16:27:19 +0100 Subject: [PATCH] Rewrite Graphics::printf, fixes issue #107 Rewrote the complete logic to not operate on chars, but on lines and tokens. Uses std streams, iterators and algorithms. --- src/modules/graphics/opengl/Graphics.cpp | 141 +++++++++-------------- 1 file changed, 55 insertions(+), 86 deletions(-) diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index 3e1f32ac6..972ca9838 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -23,6 +23,11 @@ #include "Graphics.h" +#include +#include +#include +#include + namespace love { namespace graphics @@ -719,98 +724,62 @@ namespace opengl void Graphics::printf( const char * str, float x, float y, float wrap, AlignMode align) { - if(currentFont != 0) - { - std::string text = ""; - float width = 0; - float lines = 0; + if (currentFont == 0) + return; - for(unsigned int i = 0; i < strlen(str); i++) - { - if(str[i] == '\n') - { - switch(align) - { - case ALIGN_LEFT: - currentFont->print(text, x, y + (lines * currentFont->getHeight() * currentFont->getLineHeight()) ); - break; + using namespace std; + string text(str); + const float width_space = currentFont->getWidth(' '); + vector lines_to_draw; - case ALIGN_RIGHT: - currentFont->print(text, (x + (wrap - currentFont->getWidth(text))), y + (lines * currentFont->getHeight() * currentFont->getLineHeight()) ); - break; + //split text at newlines + istringstream iss( text ); + string line; + while (getline(iss, line, '\n')) { + // split line into words + vector words; + istringstream word_iss(line); + copy(istream_iterator(word_iss), istream_iterator(), + back_inserter< vector >(words)); - case ALIGN_CENTER: - currentFont->print(text, ceil(x + ((wrap - currentFont->getWidth(text)) / 2)), ceil(y + (lines * currentFont->getHeight() * currentFont->getLineHeight())) ); - break; + // put words back together until a wrap occurs + float width = 0.0f; + ostringstream string_builder; + vector::const_iterator word_iter; + for (word_iter = words.begin(); word_iter != words.end(); ++word_iter) { + string word( *word_iter ); + width += currentFont->getWidth( word ); - default: // A copy of the left align code. Kept separate in case an error message is wanted. - currentFont->print(text, x, y + (lines * currentFont->getHeight() * currentFont->getLineHeight()) ); - break; - } - - text = ""; - width = 0; - lines++; - } - else - { - width += currentFont->getWidth(str[i]); - - if(width > wrap && text.find(" ") != std::string::npos) // If there doesn't exist a space, then ignore the wrap limit. - { - // Seek back to the nearest space and print that. - unsigned int space = (unsigned int)text.find_last_of(' '); - std::string temp = text.substr(0, space); - - switch(align) - { - case ALIGN_LEFT: - currentFont->print(temp, x, y + (lines * currentFont->getHeight() * currentFont->getLineHeight()) ); - break; - - case ALIGN_RIGHT: - currentFont->print(temp, (x + (wrap - currentFont->getWidth(temp))), y + (lines * currentFont->getHeight() * currentFont->getLineHeight()) ); - break; - - case ALIGN_CENTER: - currentFont->print(temp, ceil(x + ((wrap - currentFont->getWidth(temp)) / 2)), ceil(y + (lines * currentFont->getHeight() * currentFont->getLineHeight())) ); - break; - - default: // A copy of the left align code. Kept separate in case an error message is wanted. - currentFont->print(temp, x, y + (lines * currentFont->getHeight() * currentFont->getLineHeight()) ); - break; - } - - text = text.substr(space + 1); - width = currentFont->getWidth(text); - lines++; - } - - text += str[i]; - } - } // for - - if(text != "") // Print the last text (if applicable). - { - switch(align) - { - case ALIGN_LEFT: - currentFont->print(text, x, y + (lines * currentFont->getHeight() * currentFont->getLineHeight()) ); - break; - - case ALIGN_RIGHT: - currentFont->print(text, (x + (wrap - currentFont->getWidth(text))), y + (lines * currentFont->getHeight() * currentFont->getLineHeight()) ); - break; - - case ALIGN_CENTER: - currentFont->print(text, ceil(x + ((wrap - currentFont->getWidth(text)) / 2)), ceil(y + (lines * currentFont->getHeight() * currentFont->getLineHeight())) ); - break; - - default: // A copy of the left align code. Kept separate in case an error message is wanted. - currentFont->print(text, x, y + (lines * currentFont->getHeight() * currentFont->getLineHeight())); - break; + // on wordwrap, push line to line buffer and clear string builder + if (width >= wrap) { + lines_to_draw.push_back( string_builder.str() ); + string_builder.str( "" ); + width = currentFont->getWidth( word ); } + string_builder << word << " "; + width += width_space; } + // push last line + lines_to_draw.push_back( string_builder.str() ); + } + + // now for the actual printing + vector::const_iterator line_iter, line_end = lines_to_draw.end(); + for (line_iter = lines_to_draw.begin(); line_iter != line_end; ++line_iter) { + float width = currentFont->getWidth( *line_iter ); + switch (align) { + case ALIGN_RIGHT: + currentFont->print(*line_iter, ceil(x + wrap - width), ceil(y)); + break; + case ALIGN_CENTER: + currentFont->print(*line_iter, ceil(x + (wrap - width) / 2), ceil(y)); + break; + case ALIGN_LEFT: + default: + currentFont->print(*line_iter, ceil(x), ceil(y)); + break; + } + y += currentFont->getHeight() * currentFont->getLineHeight(); } }