Browse Source

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.
vrld 14 years ago
parent
commit
b9b2c4a962
1 changed files with 57 additions and 88 deletions
  1. 57 88
      src/modules/graphics/opengl/Graphics.cpp

+ 57 - 88
src/modules/graphics/opengl/Graphics.cpp

@@ -23,6 +23,11 @@
 
 #include "Graphics.h"
 
+#include <vector>
+#include <sstream>
+#include <algorithm>
+#include <iterator>
+
 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;
-
-						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;
-					}
-
-					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];
+		using namespace std;
+		string text(str);
+		const float width_space = currentFont->getWidth(' ');
+		vector<string> lines_to_draw;
+
+		//split text at newlines
+		istringstream iss( text );
+		string line;
+		while (getline(iss, line, '\n')) {
+			// split line into words
+			vector<string> words;
+			istringstream word_iss(line);
+			copy(istream_iterator<string>(word_iss), istream_iterator<string>(),
+					back_inserter< vector<string> >(words));
+
+			// put words back together until a wrap occurs
+			float width = 0.0f;
+			ostringstream string_builder;
+			vector<string>::const_iterator word_iter;
+			for (word_iter = words.begin(); word_iter != words.end(); ++word_iter) {
+				string word( *word_iter );
+				width += currentFont->getWidth( word );
+
+				// 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 );
 				}
-			} // 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;
+				string_builder << word << " ";
+				width += width_space;
+			}
+			// push last line
+			lines_to_draw.push_back( string_builder.str() );
+		}
 
-					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;
-				}
+		// now for the actual printing
+		vector<string>::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();
 		}
 	}