Word Wrapping with SDL_TTF [solved]

Started by
1 comment, last by ender_341 18 years, 1 month ago
Is there a simple way to perform word wrapping with SDL_TTF? The easiest way I see it is to print each character individually with for and insert the line break in there, but this seems like it wouldn't be very efficient. Is this the best method, or are there any tutorials that explain how to do this? I also noticed that the \n does not do a newline, is there a way to do this or do you have to just print the next part under it with another call? [Edited by - ender_341 on March 13, 2006 11:37:36 AM]
-Matt S.
Advertisement
I haven't come across tutorials that explain it. I have done something like this just now, although not with SDL_ttf, it was a lot more tricky than I thought it would be. (I totally underestimated it) This thread is about using SDL_ttf with opengl, but someone made a whole fontmanager complete with caching and multiline rendering (scroll to the middle or so) and posted it there. Maybe you could get some ideas from there.

Some issues to take into consideration:
- If you want word wrapping than you will have to find the space at which you can break the line, not the character.
- SDL_ttf works with proportional fonts just fine, but it can only do kerning when you render a whole string, not char per char.
- When you use monospace fonts the calculations will be easier, you could consider doing that first.
- Some functions in SDL_ttf might be especially useful: something to get glyph metrics (dimensions of a rendered character), a function that only returns the width of the whole string and one that returns whether it is monospace. (i forgot the names, but the documentation is quite good i think).

I wouldn't worry about the efficiency. As long as you do calculations first and render only once it should not be a problem. Rendering the text will probably cost more anyway than some calculations. If you want more efficiency, then you should look into caching (see the thread I linked to).

Hope that helps and good luck.

Thanks, using that link i was able to get a mostly working setup. Now my problem is this. with the code below the window comes up, but it is blank and unresponsive. if i comment out the "if( (n * 16 ) >= text_Width )" in the code it works as expected (creating a newline at every space and displaying in the correct location). Any help would be greatly appreciated.

void TextBox::wrapText( const char *text, Uint16 x, Uint16 y, Uint16 Width ){	// the -40 is for padding in the text box	Uint16 text_Width = Width - 40;		// -- holds the maximum width a line can be (in pixels)	std::vector < std::string > lines;	// -- these are the individual lines of text	std::string temp( text );		// -- holds the current line of text	int n = 0;	int p = 0;	// -- Get until either ' ' or '\0'	while( n != -1 )	{		std::string strSub;		n = p = temp.find( " ", p );		// -- Find the next " "		if( (n * 16 ) >= text_Width )		{			strSub = temp.substr( 0, n);	// -- sets strSub to the of the current line			if( n != -1 )				temp = temp.substr( n+1, std::string::npos );			lines.push_back(strSub);	// -- Puts strSub into the lines vector			p = 0;		}	}	// -- Draws the text for each line of text onto the box	for( Uint8 i = 0; i < lines.size(); i++ )	{		const char *txtPtr = lines.c_str();		m_Graphics->drawText( txtPtr, x + 41, y + line_Skip + ( line_Skip * i ), 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF );	}}


Fixxed Version:
void TextBox::wrapText( const char *text, Uint16 x, Uint16 y, Uint16 Width ){	Uint16 text_Width = Width - 40;		// -- holds the maximum width a line can be (in pixels)	std::vector < std::string > lines;	// -- these are the individual lines of text	std::string temp( text );		// -- holds the current line of text	temp += " ";  // -- Adds a space to the end of the string so that all of the text will always be displayed.	Uint32 n = 0;	// -- Holds the index of the current index to find out if it is past the box	Uint32 p = 0;	// -- Holds the index of the previous space so that the wrod that goes past the end gets wrapped to the next line	// -- Get until either ' ' or '\0'	while( n != -1 )	{		std::string strSub;		n = temp.find( " ", p + 1 );		// -- Find the next " "		if( (n * 16) >= text_Width )		{			strSub = temp.substr( 0, p );	// -- sets strSub to the of the current line			lines.push_back( strSub );	// -- Puts strSub into the lines vector			if( n != -1 ){				temp = temp.substr( p+1, std::string::npos );			}		p = 0;		}		else{			p = n;		}	}	// -- Draws the text for each line of text onto the box	for( Uint8 i = 0; i < lines.size(); i++ )	{		const char *txtPtr = lines.c_str();		m_Graphics->drawText( txtPtr, x + 41, y + line_Skip + ( line_Skip * i ), 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF );	}}


If any of the code needs clarifification please ask.

[edit] OK, i figured out that when it goes into the if statement and it fails and continues with the while loop it just goes into an infinite loop (and creates a 30 MB log file along with it). what i can't figure out is an elagent way out of the loop. Any suggestions? (also edited code to fix one mistake i found)

[edit2] OK, i got it fixxed, this is why i shouldn't be coding at 2 AM.
i added the fixed code above for anyone else that wants a quick example (though you won't be able to just copy and past it, it calls some other class' to draw the text, but it should be simple to modify from here.

[Edited by - ender_341 on March 12, 2006 4:18:21 AM]
-Matt S.

This topic is closed to new replies.

Advertisement