ID3DXFont rect calculation issue

Started by
4 comments, last by Crazyfool 15 years, 1 month ago
I made a method to calculate the size of the rect used to render some text, however for some reason the size it returns is diffrent from the size used when rendering the text for real :( Looking at the actaul size of the area the text is rendered to and the size returned it appears my calc rect method is adding an extra line break after the first word...

//the draw method
void Font::DrawWidth(Point2<float> pos, unsigned width, const std::wstring &text, Align align, unsigned col)
{
	RECT rect;
	rect.top = (long)pos.y;
	unsigned flags = DT_NOCLIP | DT_WORDBREAK;
	switch(align)
	{
	case IFont::CENTRE:
		rect.left  = (int)pos.x-width/2;
		rect.right = (int)pos.x+width/2;
		flags |= DT_CENTER;
		break;
	case IFont::RIGHT:
		rect.right = (int)pos.x;
		rect.left = (int)pos.x-width;
		flags |= DT_RIGHT;
		break;
	case IFont::LEFT:
	default:
		rect.left  = (int)pos.x;
		rect.right = (int)pos.x+width;
		flags |= DT_LEFT;
		break;
	}
	if(FAILED(font->DrawTextW(
		0, text.c_str(),
		text.length(), &rect, flags, col)))
		throw exception::Error(L"Failed to draw text");
}
//the calcu size method
Size2<> Font::CalcSizeWidth(unsigned width, const std::wstring &text, Align align)
{
	RECT rect = {0,0,width,0};
	unsigned flags = DT_NOCLIP | DT_CALCRECT | DT_WORDBREAK;
	switch(align)
	{
	case IFont::CENTRE:
		flags |= DT_CENTER;
		break;
	case IFont::RIGHT:
		flags |= DT_RIGHT;
		break;
	case IFont::LEFT:
	default:
		flags |= DT_LEFT;
		break;
	}
	if(FAILED(font->DrawTextW(
		0, text.c_str(),
		text.length(), &rect, flags, 0)))
		throw exception::Error(L"Failed to calc text size");
	return Size2<>((float)rect.right-rect.left, (float)rect.bottom-rect.top);
}

When testing with the string "Multiple lines of text." and a width of 150 the actual text is less lines and wider than the calcuated size. -actaul text layout

Multiple lines of
text.
-how the calc method appears to be laying it out

Multiple
lines of
text.
Advertisement
Still havnt solved this...I cant see anything wrong with my code, is it an issue with CALCRECT or something? If so is there some work around as I really need to reliabley determin the size of the area the text will be rendered too...
If I remember correctly when I was using DX's font helpers it uses the corner of the RECT as a starting position. It doesn't force the text to remain within the RECT. I could be wrong, but, if my memory serves me correctly...
Are you certain that it should fit within 150 pixels exactly how you imagine it? If you input a width of say, 500, does it fit all in one line?

I'm not sure on your methodology and why you're attempting it render text the way you are. Are you trying to make something that will automatically adjust for everything? I can't think of a time that you wouldn't want to specify the width of a text you're rendering (assuming its multiple lines).
Quote:
Are you certain that it should fit within 150 pixels exactly how you imagine it? If you input a width of say, 500, does it fit all in one line?

I didnt imagen anything. The size returned by the calc method is simply diffrent from the size of the area the text is actaully rendered too with DrawWidth

Quote:
I'm not sure on your methodology and why you're attempting it render text the way you are. Are you trying to make something that will automatically adjust for everything? I can't think of a time that you wouldn't want to specify the width of a text you're rendering (assuming its multiple lines).

I'm simply trying to determin how much space the rendered text will take which has many applications.

For example ensureing that the dialogs in my game are large enough for the text to fit on them (the dialogs have a fixed width of 80% the window width, hence using the CalcWidth version which accepts a fixed width as its argument, so the text will expand vertically onto however many lines it needs.)


Ive added a sample of the problem below
	//calc the area the text is rendered too	Size2<> size = fontB->CalcWidth(150, L"Multiple lines of text.");	//draw the area as the background	primitive::DrawRect(primVb.ptr(), Point2<>(50,100), size, 0xFFFF8000);	//mark where 150 pixels is past 50 (ie 200)	primitive::DrawLine(primVb.ptr(), Point2<>(200,100), Point2<>(200,150), 0xFFFF0000);	//render the actaul text	fontC->DrawWidth(Point2<>(50,100), 150, L"Multiple lines of text.");

Ah, well you can use a different function for that GetTextExtentPoint32.

I make use of this for position messages like Author: text messages which use different colors. However, I do not use this for rendering text within a menu. I am confused because I cant imagine when you'd want to do this (aside from the height, maybe, but there are better solutions to that even) with menus.

A menu should have a position (x,y) and a width/height to them. So when you want to check for the width of your rect to draw, it should be 80% of your menu width, and likewise any rules you have for heights. You do not need to compute all this extra stuff. Simply but the bottom of the rect at the desired level and it will not render text beyond that point (not sure if you need to remove the NOCLIP flag).

For example:
int x = menu.x + menu.width * 0.1f;int y = menu.y + 15; //for the title, whatever size you needdrawText(x, y, menu.width * 0.8f, "hey this is a string!");

This topic is closed to new replies.

Advertisement