我正在尝试创建位图字体渲染器,但是,我在渲染实际的单个字母位置时遇到问题。
我将通过 GetCharABCWidthsFloat 和 GetTextMetricsW 获取字体字符信息,但是,我不确定如何正确使用 ABC 宽度......或者我是否需要更多信息来执行此操作?
我不想使用 FreeType 或任何其他库来执行此操作,我尝试使用 C++\Windows 提供的标准功能来执行此操作。
如果没有字距调整信息,字母将不会显示正确。例如,看看“Times new roman”,其中“f”和“t”彼此相邻。如果字母间距不正确,它们看起来就会相距太远。
算法示例 ---
float letterBottomLeftX = 0.0f;
float letterHeight = 1.0f;
float letterWidth = 1.0f;
float scale = 1.0f;
for(U32 c = 0; c < numberOfCharacters; ++c)
{
fon->GetCharcterInfo(charValue, charInfo);
//float advancedWith = (charInfo.A * scale) + (charInfo.B * scale) + (charInfo.C * scale);
letterWidth = charInfo.B * scale;
letterHeight = textMetrics.Height * scale;
if(c == 0)
{
letterBottomLeftX = -(charInfo.A * scale);
}
// vertex placement, beginning at letterBottomLeftX
// texture placement
// index placement
letterBottomLeftX += (charInfo.A + charInfo.B + charInfo.C) * scale;
}
这是一个示例,您可以注意到字符之间的间距不好。 (忽略纹理 UV,我将在字母位置正确后修复该问题)。
http://img88.imageshack.us/img88/4015/njpjp2.png
I am attempting to create a bitmap font renderer, however, I am having problems rendering the actual individual letter placements.
I will obtain the font character information via GetCharABCWidthsFloat and GetTextMetricsW, however, I am unsure how to use the ABC width's properly ... or do I need more information to do this?
I do not want to use FreeType or any other libraries's to do this, I am trying to do this with standard functionality available through C++\Windows.
Without the kerning information, the letters will not appear correct. For example, take a look at "Times new roman" when an "f" and a "t" are placed next to each other. Without the correct letter spacing, they will look too far apart.
algorithm example ---
float letterBottomLeftX = 0.0f;
float letterHeight = 1.0f;
float letterWidth = 1.0f;
float scale = 1.0f;
for(U32 c = 0; c < numberOfCharacters; ++c)
{
fon->GetCharcterInfo(charValue, charInfo);
//float advancedWith = (charInfo.A * scale) + (charInfo.B * scale) + (charInfo.C * scale);
letterWidth = charInfo.B * scale;
letterHeight = textMetrics.Height * scale;
if(c == 0)
{
letterBottomLeftX = -(charInfo.A * scale);
}
// vertex placement, beginning at letterBottomLeftX
// texture placement
// index placement
letterBottomLeftX += (charInfo.A + charInfo.B + charInfo.C) * scale;
}
Here is an example of what it looks like, you can notice the bad spacing between characters. (Ignore the texture UV's, I am going to fix that after I get the letter placement correct).
http://img88.imageshack.us/img88/4015/njpjp2.png
发布评论
评论(2)
KERNINGPAIR
的文档看起来非常简单。如果当前字符和后续字符都通过wFirst
和wSecond
成员出现在表中,请将iKernAmount
添加到您要计算的像素数。提前下一个字符。我建议使用
GetKerningPairs
的结果创建一个std::map,int>
以便快速查找。您已经注意到,GetKerningPairs
不会返回每种可能的字符组合的结果。该信息来自字体本身,由字体设计者指示哪些字符对需要调整。这些信息很可能完全丢失,或者丢失对您来说似乎显而易见的字符对。请确保在调用任何这些函数之前执行
SetMapMode(hdc,MM_TEXT)
,因为映射模式会影响结果。The documentation for
KERNINGPAIR
seems pretty straightforward. If both the current character and the following character occur in the table via thewFirst
andwSecond
members, add theiKernAmount
to the number of pixels you advance for the next character.I would suggest creating a
std::map<std::pair<wchar_t,wchar_t>,int>
with the results fromGetKerningPairs
for quick lookup. You have noticed thatGetKerningPairs
does not return a result for every possible combination of characters. This information is coming from the font itself, and it is up to the font designer to indicate which character pairs are in need of adjustment. It is quite possible for this information to be missing entirely, or to be missing character pairs that seem obvious to you.Make sure you do
SetMapMode(hdc,MM_TEXT)
before calling any of these functions, since the mapping mode affects the results.一种常见的解决方案是创建字母对宽度表。因此,字母“Ti”的排列位置会比“MN”靠得更近。这是一张制作速度很快的桌子,并且以成本为代价产生了不错的结果。
One common solution is to create a letter pair width table. So the letters 'Ti' would be placed closer together than say MN. It's a quick table to make and yields decent to excellent results for the cost.