# Advanced Text Handling with DirectDraw

This topic is 4880 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

I've seen a lot of tutorials in books and the web regarding text, but unfortunately for me, they all take the lazy way (:P) out and use Direct3D... with it's pretty font engine... grrrr... anyway. I'm making a minor system of my own. One problem with it - it doesn't work. Well, I lie, it works, but it doesn't parse lines correctly. Here's the code:
[source="cpp"]
#include "stdafx.h"
#include "CDialogManager.h"

#include "Log.h"

const unsigned int GKUITEXTSIZE = 3u;

CDialogManager::CDialogManager(void)
{
// Dialog_Handler should only be set active by an actual script call
// for dialog mode.
m_bActive = false;

// Empty out our strings to clear them of crap.
m_szDispDlg = _T("");
m_szRemDlg = _T("");

// Set size of dialog.
m_uiDlgHeight = 200u;					// FIXME: Guesstimate.
m_uiDlgRectHeight = m_uiDlgHeight - 6u; // FIXME: Guesstimate.

// Now set the values of the rects themselves.
Set_DlgRects();

// Set default line parameters.
m_uiDispNumLines = kuiDISPNUMLINES;
m_uiCurLine = 0;
}

CDialogManager::~CDialogManager(void)
{

}

/**********************************************************
Function: void CDialogManager::Set_DlgRects(void)
Description: Sets the position and dimensions of a text rect
in which to place dialog text.
Parameters: None.
Returns: None.
***********************************************************/
void CDialogManager::Set_DlgRects(void)
{
unsigned int uiDlg_top = 0;
unsigned int uiDlg_bottom = 0;
unsigned int uiDlgRect_top = 0;
unsigned int uiDlgRect_bottom = 0;
unsigned int uiDlg_YOffset = 0;		// Determined by pos.

m_uiDlgWidth = (uiDefWidth - 2u);
m_uiDlgRectWidth = (uiDefWidth - 16u);

// Set current pos, used for both rect calculations.
switch(m_ePos)
{
case TOP:
uiDlg_YOffset = 0;
break;
case MIDDLE:
uiDlg_YOffset = uiCurHeight/2;		// FIXME: Can I just bitshift here? Also, need a curheight var.  Stores Current Height of Screen as opposed to DefHeight - default height of screen.
break;
case BOTTOM:
uiDlg_YOffset = (uiCurHeight - m_uiDlgHeight);
break;
};

// Leave a two pixel buffer to prevent crashing(1 pix. on each side).
uiDlg_top = (uiDlg_YOffset + 1u);
uiDlg_bottom = ((uiDlg_top + m_uiDlgHeight) - 1u);

uiDlgRect_top = (uiDlg_YOffset + 6u);
uiDlgRect_bottom = ((uiDlgRect_top + m_uiDlgRectHeight) - 6u);

// Now that the values have been calculated, dump them into the rect.
m_rDlgArea.top = uiDlg_top;
m_rDlgArea.bottom = uiDlg_bottom;

m_rDlgTextArea.top = uiDlgRect_top;
m_rDlgTextArea.bottom = uiDlgRect_bottom;

// Left and right are unaffected by position.
m_rDlgArea.left = 1l;							// 1 pix. border.
m_rDlgArea.right = (m_uiDlgWidth + 1l);			// 1 pix. border.

m_rDlgTextArea.left = 8l;						// 8 pix. border.
m_rDlgTextArea.right = (m_uiDlgRectWidth + 8l);	// 8 pix. border.

return;
}

/**********************************************************
Function: void CDialogManager::ParseDialog(void)
Description: Parses the next group of text appropriately for dialog
format.  Text, once finished, is completely ready for a call to draw
text, string changes and all are contained inside this function.
Parameters: None.
Returns: None.
***********************************************************/
// This function only needs to be in charge of parsing the dialog to be displayed.
// drawing it out character by character can be accomplished in a single loop in the
// drawDlgText function.
void CDialogManager::ParseDialog(void)
{
TCHAR cCur;								// Holds the current character.
std::wstring szDlgLine = _T("");		// Holds the currently formatted line of dialog.
std::wstring szPotentialLine = _T("");	// Holds the current szDlgLine + the next word.  Used as
// a check to see if the word can fit onto the current line.
std::wstring szWord = _T("");			// Holds the currently formatted word.  Important to
// have this variable in order to ensure whole words
// don't break into chunks between lines.
unsigned int uiLine = 0;				// Holds the current line being parsed.

// Seperators
// Seperators are: \n (newline), " ".
//  "." and "  " will be read in automatically as chars.
static const int MAX_SEPS( 2 );
TCHAR cSeps[MAX_SEPS+1] = _T("\n ");

// Display <m_uiDispNumLines> of the remaining dialog (to be displayed...).
// or if there are <m_uiDispNumLines> or less dialog remaining, the length of the message.
for(uiLine = m_uiCurLine; m_szRemDlg.length() && uiLine > (m_uiCurLine+m_uiDispNumLines); )
{
// Remove the first single char from m_szRemDlg.
// this is the next value we'll be adding into the displayable
// text.
cCur = m_szRemDlg[0];
m_szRemDlg = m_szRemDlg.substr(1);

// Append the new character to the word, making sure not
// to append linebreak.
if(cCur != cSeps[0])
szWord += cCur;

// End a word when it is complete.
for(int iIndex = 0; iIndex < MAX_SEPS; iIndex++)
{
// If the character is equal to any of the seperators, then
// the word has been completed.
if(cCur == cSeps[iIndex])
{
// Now, check to see if the completed word can fit into the current line.
szPotentialLine = szDlgLine + szWord;

// If szDlgLine has gotten too wide, end the line
// and start a new one.
if((szPotentialLine.length()*GKUITEXTSIZE) >= m_uiDlgRectWidth)
{
// Trim the line to fit.
szDlgLine = TrimLeft(szPotentialLine);

// Update the displayable dialog to reflect the changes.
m_szDispDlg += szDlgLine;
m_szDispDlg += '\n';
uiLine++;

// Reset the line, and add in the completed word.
szDlgLine = _T("");
szDlgLine += szWord;	// NOTE: I assume here that no word is too big for a line.  FIXME:?
}
// Otherwise, we still have sufficient space on the line.
else
szDlgLine += szWord;

// With the word added into the dialog line appropriately,
// reset it for the next line...
szWord = _T("");

// Make sure the lineBreaks transfer over.
if(cCur == cSeps[0])
{
// Add the current line and lineBreak, reset DlgLine.
m_szDispDlg += szDlgLine;
m_szDispDlg += cSeps[0];
szDlgLine = _T("");
}
break;
}
}
} // End for loop.

// Before we exit, update our m_uiLine variable.  Done here so
// we only call it once, and not 4 times unnecessarily.
// FIXME: Should this be uiLine++?
m_uiCurLine = uiLine;

return;
}

std::wstring CDialogManager::TrimLeft(std::wstring &szPotentialLine)
{
std::wstring szResult = _T("");
std::wstring szLine = _T("");
unsigned int uiDiff = 0;

// Just used to seek really.
for(unsigned int uiPos = 0; uiPos < (szPotentialLine.length()*GKUITEXTSIZE); uiPos+=GKUITEXTSIZE)
{
// Get the total number of chars we can cram in.
if((uiPos + GKUITEXTSIZE) > m_uiDlgRectWidth)
{
// Since we need a substr preformed before we modify potentialline, we need a cloned var.
szLine = szPotentialLine;

// Get the remainder of the string that exceeds the current boundaries.
uiDiff = (szPotentialLine.length()*GKUITEXTSIZE) - uiPos;

// Set a new string to hold all the text we can cram up UNTIL the boundaries.
szResult = szLine.substr(0, uiPos);

// Reformat the remaining line to hold all but the formatted chars held in szResult.
szPotentialLine.substr(uiDiff);
break;
}
}

return szResult;
}

//void CDialogManager::UpdateDialog(void)
//{
//	// Empty out the display dialog - it's time to load in the next set.
//	m_szDispDlg = _T("");
//
//}

// Overload one of two, the first will load from file, this just
// loads a text message to print directly.
{
bool bSuccess = true;

m_szRemDlg = szMessage;
if(m_szRemDlg == _T(""))
bSuccess = false;

// hack.
m_szDispDlg = szMessage;
if(m_szDispDlg == _T(""))
bSuccess = false;

return bSuccess;
}


[source="cpp"]
#ifndef _DOTS_WIN32APP_DIRECTX9C_CDIALOGMANAGER_H
#define _DOTS_WIN32APP_DIRECTX9C_CDIALOGMANAGER_H

enum ePos
{
TOP,
MIDDLE,
BOTTOM
};

// Used for dealing with dialog.
// Prior to this seperate classes were needed for the font
// and font handling, but no more.  Yea~
class CDialogManager
{
public:
CDialogManager(void);
~CDialogManager(void);

std::wstring TrimLeft(std::wstring &szPotentialLine);
void Set_DlgRects(void);
void ParseDialog(void);

bool IsActive(void) { return m_bActive; }
void SetActive(bool bActive) { m_bActive = bActive; return; }

//--Dialog bounds information
CRect m_rDlgArea;				// Stores the Rect representing our dialog area.
CRect m_rDlgTextArea;			// Stores the Rect representing our dialog text area.

//--Dialog contents information
std::wstring m_szRemDlg;		// Holds the remaining dialog(dialog that still needs to be printed out to screen).
std::wstring m_szDispDlg;		// Holds the dialog to display.
unsigned int m_uiCurLine;		// Holds the current line of dialog we are on.
unsigned int m_uiDispNumLines;	// Holds the number of lines to display at once.

//--Dialog sizing information
unsigned int m_uiDlgHeight;		// Holds the size of the full dialog window.
unsigned int m_uiDlgWidth;		// Holds the size of the full dialog window.
unsigned int m_uiDlgRectHeight;	// Holds the size of the full text-fillable rect of the dialog window.
unsigned int m_uiDlgRectWidth;	// Holds the size of the full text-fillable rect of the dialog window.

//--Other vars.
ePos m_ePos;					// Holds the enum value of the position of the dialog box.

private:
bool m_bActive;					// Bool indicating whether to show the dialog box and do
// our dialog related logics.
};

#endif// _DOTS_WIN32APP_DIRECTX9C_CDIALOGMANAGER_H


Can anyone see where my mistake lies? I'm sure it's a simple one... it's all just a matter of finding it, and a second point of view always helps :) (by the way, the actual rendering of said lines is done outside the file using the standard "textout" function):
[source="cpp"]
HRESULT CDirectDraw_Manager::DDraw_Text(LPCWSTR szMessage, COLORREF TextColor, int posx, int posy)
{
HRESULT hr = S_OK;
HDC hdc;

// We have to have a backbuffer to do this.
if(!m_lpDDSBack)
return E_FAIL;

hr = m_lpDDSBack->GetDC(&hdc);
if(SUCCEEDED(hr))
{
SetBkMode(hdc, TRANSPARENT);
SetBkColor(hdc, RGB(0,0,0));
SetTextColor(hdc, TextColor);
TextOut(hdc, posx, posy, szMessage, lstrlen(szMessage));
m_lpDDSBack->ReleaseDC(hdc);
}

// Return result of function.
return hr;
}


Thanks again for your time. :)

##### Share on other sites
What do you mean by "it doesn't parse lines correctly"? Does it crash? Cut them short? Add gibberish?
Any chance of a screenshot of the problem?

Also: // FIXME: Can I just bitshift here?
Yes, you can just shift right by 1 (uiDlg_YOffset = uiCurHeight>>1;), but there's absolutely no point in doing that, because the compiler will optimize it for you, and it just makes your code harder to read. So don't worry about it [smile]

##### Share on other sites
Ah, no, I mean it just prints the line from the desired point straight across and off the screen (amazingly enough, this doesn't crash the program).

ie.
|
|stuffstuffstuffstuffstuffstuffstuffstuffstuffstuffstuffstuffst|
|

What is should do is detect the portion that would be displayed offscreen, and print it out on a new line, so for dialog, you'd get something like this:

ie.
|
|stuffstuffstuffstuffstuffstuffstuffstuffstuffstuffstuffstuff|
|stuffstuffstuffstuffstuffstuffstuffstuffstuffstuffstuffstuff|
|stuffstuffstuffstuffstuffstuffstuffstuffstuffstuffstuffstuff|
|stuffstuffstuffstuffstuffstuff.
|

[Edited by - HeavyBlade on September 14, 2005 11:15:31 AM]

##### Share on other sites
**BUMP**

Sorry for the bump, but does anyone have any ideas as to why this is occuring?
Much thanks.

• ### What is your GameDev Story?

In 2019 we are celebrating 20 years of GameDev.net! Share your GameDev Story with us.

• 11
• 11
• 15
• 11
• 11
• ### Forum Statistics

• Total Topics
634149
• Total Posts
3015833
×