Seems like I need to post the full function, again.
Code:
void DrawBMPFont(char Text[1024], short StartX, short StartY, short width, int XBorder, int YBorder)
{
/* This function draws bitmap font text to the screen.
Rules:
* The last character's numerical value must be zero. If it's not zero, it should be set prior to processing to prevent infinite loops.
* Wordwrap occurs only when the space character is encountered.
* Wordwrap should never occur when a "\n" is encountered. Instead, the row should advance and the x position reset.
* Strings are processed until a space is encountered. When encountered, wordwrap is checked.
* If there's enough space, the word is placed on the next line. If not, text wraps to the next line below.
* The X and Y parameters set the position of the upper left corner where text is to be drawn to.
* The width parameter specifies how wide of an area to cover before wordwrap is used.
* The border parameters are used to set padding for easier use and reading
* Processing should continue until the null character is found, from which it stops.
*/
short PosX = 0; // initialize start positions
short PosY = 0;
short VSpacing = (short)FontInfo.biHeight; // the vertical spacing
unsigned short ArrayIndex = 0; // text array position
unsigned short StartArrayIndex; // first character of the current word
unsigned short EndArrayIndex; // first character of the next word
int DrawXPosition = 0;
int DrawYPosition = 0;
int SourceXWidth = 2;
int DrawXWidth = 2;
int SourceXPosition = 0;
int LoopCount[3] = {0, 0, 0}; // debugging only
width = width + 2 - XBorder*2; // gives the actual width. +2 for the spacing between characters XBorder*2 because there are two sides
SelectObject(HDCBitmap, FontBMPHandle);
/*
if (Text[1023] != 0) // if last possible character is not null
{
Text[1023] = 0; // the null character must be enforced. // Unhandled exception - Huh!?
}
*/
while (Text[ArrayIndex] != 0) // loop until the null character is reached
{
StartArrayIndex = ArrayIndex; // copy the starting point in the string
while ((Text[ArrayIndex] != TextSpace) || (Text[ArrayIndex] != 0x0A) || (Text[ArrayIndex] != 0)) // loop until a space, line feed, or the null character is encountered // an infinite loop, but how?
{
PosX += Font.CharWidth[Text[ArrayIndex]]; // add the character's width
ArrayIndex++;
LoopCount[0]++; // debugging only
if (LoopCount[0] >= 10000000) // ten million loops is way too many
{
sprintf(DebugDetails, "Warning: an infinite loop in the first loop is present!"); // for debugging
MessageBox(hwnd, DebugDetails, "Debug Results", MB_OK);
break; // terminate the function regardless of the function's success // doesn't seem to execute
}
}
if (LoopCount[0] >= 10000000) // to break the main loop
{
break; // break the main loop // doesn't execute either
}
EndArrayIndex = ArrayIndex; // copies the current array position to mark the end of a word
if (PosX > width) // if too long to display in the given width
{
PosY += VSpacing; // go down a row
PosX = 0; // and return to the leftmost position
}
else // if space remains
{
if (Text[ArrayIndex] != 0x0A) // if a linefeed is not used
{
PosX += Font.CharWidth[Text[ArrayIndex]]; // include the space character
}
}
if (Text[ArrayIndex] == 0x0A) // the linefeed
{
PosY += VSpacing; // go down a row
PosX = 0; // and return to the leftmost position
}
ArrayIndex = StartArrayIndex; // reset the array index to where the word started at, now for drawing
DrawYPosition = (int)StartY+(int)PosY+YBorder; // the Y position to draw to doesn't change
while (ArrayIndex < EndArrayIndex) // repeat until the end of the word is reached
{
DrawXPosition = (int)StartX+(int)PosX+XBorder; // this one is dynamic and sets the X position to draw to
DrawXWidth = (int)Font.CharEndPos[Text[ArrayIndex]]-(int)Font.CharEndPos[Text[ArrayIndex-1]]; // set the width of the area to draw to
SourceXPosition = (int)Font.CharEndPos[Text[ArrayIndex-1]]; // the start drawing point is the ending point of previous character
AlphaBlend(HDCBack, DrawXPosition, DrawYPosition, DrawXWidth, FontInfo.biHeight, HDCBitmap, SourceXPosition, 0, DrawXWidth, FontInfo.biHeight, AlphaUsage); // draw the anti-aliased character
PosX += Font.CharWidth[Text[ArrayIndex]]; // add the character's width
ArrayIndex++;
LoopCount[1]++;
if (LoopCount[1] >= 10000000) // ten million loops is way too many
{
sprintf(DebugDetails, "Warning: an infinite loop in the second loop is present!"); // for debugging
MessageBox(hwnd, DebugDetails, "Debug Results", MB_OK);
break; // terminate the function regardless of the function's success
}
}
if (LoopCount[1] >= 10000000)
{
break; // break the main loop
}
if (Text[ArrayIndex] == 0) // the null character is encountered
{
break; // terminate the loop
}
LoopCount[2]++;
if (LoopCount[2] >= 10000000) // ten million loops is way too many
{
sprintf(DebugDetails, "Warning: an infinite loop in the main loop is present!"); // for debugging
MessageBox(hwnd, DebugDetails, "Debug Results", MB_OK);
break; // terminate the function regardless of the function's success
}
}
}
// this function is used in this function:
void DrawScenery()
{
... // the rest of the scenery
DrawBMPFont("SampleString", 640, 0, 160, 1, 1); // string to display, x and y positions to draw to, the width for wordwrap, and x and y borders for "padding"
... // swapping the front and back buffers
}
The font is a TGA file with alpha channel (for anti-aliasing). The character widths vary. The font is set up like this (as it seems I need it):
Code:
struct FontBase
{
short CharWidth[128];
short CharEndPos[128];
short CharHeight;
};
unsigned char FontData[70400]; // The mountains background
LPVOID FontDataPointer;
BITMAPINFO FontMainInfo;
BITMAPINFOHEADER FontInfo;
LPBITMAPINFOHEADER FontInfoPointer;
HBITMAP FontBMPHandle;
struct FontBase Font;
void FillFontStructure(unsigned short Character, unsigned short width, unsigned short ArrayIndex)
{
Font.CharWidth[Character] = width;
Font.CharEndPos[ArrayIndex] = Font.CharEndPos[Character-1] + width;
}
void SetUpFont()
{
unsigned short ArrayIndex = 0;
Font.CharHeight = FontInfo.biHeight;
Font.CharEndPos[0x1F] = 0; // initialize end position of a character before the space, for usage in the text drawing function
FillFontStructure(TextSpace, 4, ArrayIndex);
FillFontStructure(TextExclamation, 4, ArrayIndex);
FillFontStructure(TextQuote, 8, ArrayIndex);
FillFontStructure(TextNumber, 12, ArrayIndex);
FillFontStructure(TextDollarSign, 10, ArrayIndex);
FillFontStructure(TextPercent, 12, ArrayIndex);
FillFontStructure(TextAmpersand, 11, ArrayIndex);
FillFontStructure(TextApostrophe, 4, ArrayIndex);
FillFontStructure(TextLeftParenthesis, 6, ArrayIndex);
FillFontStructure(TextRightParenthesis, 6, ArrayIndex);
... // and so on, for each of the ASCII characters
}