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.
// Added return.
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;
// Added return.
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 CDialogManager::LoadDialog(std::wstring szMessage)
{
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);
bool LoadDialog(std::wstring szMessage);
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. :)
Join us at: http://www.blade2k.net/piracysucks/to help stop game piracy!