游戏框架其八:2D图像 { Sprite | Font }

2D图像包括Sprite和Font两种,他们都是基于Windows底层进行封装的UI控件,如下:

1. Font的实现

#pragma once
//========================================================================
// Font.h : Useful classes for drawing and formatting text strings
//========================================================================
class Sprite;

// 字体的样式
enum FontEnum
{
	FONT_DEFAULT,
	FONT_SYSTEM = FONT_DEFAULT,		//0
	FONT_ARIAL_BOLD_8,				//1
	FONT_ARIAL_BOLD_14,				//2
	FONT_ARIAL_BLACK_12,			//3          
	FONT_ARIAL_BLACK_24,			//4
	FONT_WINGDING_10,				//5
	FONT_COURIERNEW_18,				//6
	FONT_PALATINO_SMALL,			//7
	FONT_PALATINO_MEDIUM,			//8
	FONT_PALATINO_LARGE,			//9
	FONT_LARGE_LED_DISPLAY,			//10
	FONT_TREBUCHET_10,				//11
	FONT_TREBUCHET_MED,				//12
	FONT_TAHOMA_MED,				//13
	FONT_TAHOMA_LARGE,				//14

	// Define more font enumerations here....and add definitions into 
	// FontHandler::m_FontRecords in Font.cpp

	MAX_FONTS						//15
};

struct CPoint {
    CPoint(){ _x = _y = 0; }
    CPoint(float x, float y):_x(x),_y(y){}
    float _x;
    float _y;
};

struct CSize {
    float height;
    float width;
    CSize(float h, float w):height(h),width(w){}
    CSize(){ height=width=0; }
};

typedef D3DXCOLOR Color;

struct TextShadow
{
	Color m_color;
	CPoint m_offset;
    // 文字的阴影
	TextShadow(Color const &color, CPoint const &offset=CPoint(1,1))
		: m_color(color), m_offset(offset) { }
};

// 文本风格
struct TextStyle
{
	FontEnum m_font;
	Color m_foreground;
	Color m_background;
	int m_format;
	optional<TextShadow> m_shadow;

	TextStyle(
		FontEnum font, 
		Color foreground, 
		Color background=g_Transparent,  // 默认背景颜色为透明的
		int format = DT_TOP | DT_LEFT,
		optional<TextShadow> shadow=optional_empty() // 阴影效果可选
	);

	TextStyle & operator = (const TextStyle &sp);
};
	

//
// Class Font
//

class Font
{
	friend class FontHandler;
public:
	Font(ID3DXFont *font) { m_d3dFont = font;  }
	virtual ~Font() { SAFE_RELEASE(m_d3dFont); }

private:
	ID3DXFont *m_d3dFont;
};


class FontHandler
{
protected:
	static D3DXFONT_DESC m_FontRecords[];
	Font *m_pFonts[MAX_FONTS];

	CSize GetStringSize(std::wstring const &s, Font *font, int format) const;

public:

	FontHandler();
	virtual ~FontHandler();

	CSize const GetStringSize(std::wstring const &s, TextStyle const style) const;
	int	GetHeight(TextStyle const style) const;
	int	GetStringWidth(std::wstring const &s, TextStyle style) const;
	std::wstring const ParseMessage(std::wstring const &s, TextStyle style, const CSize & size ) const;

	HRESULT FontHandler::DrawText(
		Sprite *pSprite,
		const std::wstring strText,
		const TextStyle style,
		const CPoint & origin
		) const;
};
//========================================================================
// Font.cpp : Useful classes for drawing and formatting text strings
//========================================================================

//========================================================================
//
//  TextStyle - a class to encapsulate font creation parameters. Using text
//              styles in your game is similar to using CSS on a web site - it
//              becomes very easy to change the entire look of the game.
//
//  FontHandler - a useful class that preloads font definitions. The wise
//                programmer would make this class read from a data file...
//                It is also responsible for drawing fonts onto surfaces.
// 
//========================================================================


#include "GameCodeStd.h"
#include "GameCode.h"
#include <iostream>
#include "optional"
#include "Font.h"
#include "Sprite.h"
#include "String.h"
using namespace std::optional;

TextStyle::TextStyle(
	FontEnum font, 
	Color foreground, 
	Color background, 
	int format,
                     std::optional<TextShadow> shadow )
{
	m_font = font;
	m_foreground = foreground;
	m_background = background; 
	m_format = format;
	m_shadow = shadow;
}

TextStyle & TextStyle::operator = (const TextStyle &other) 
{
	m_shadow.clear();
	m_font = other.m_font;
	m_foreground = other.m_foreground;
	m_background = other.m_background; 
	m_format = other.m_format;
	if (other.m_shadow.valid())
		m_shadow = TextShadow((*(other.m_shadow)).m_color, (*(other.m_shadow)).m_offset) ;
	
	return *this;
}


// 
// FontHandler::m_FontRecords -
//
typedef std::string _T;
typedef int  INT;
typedef unsigned int  UINT;
typedef bool BOOL;
typedef char BYTE;
#ifdef   UNICODE
typedef wchar_t       TCHAR;
#else
typedef unsigned char TCHAR;
#endif
typedef struct D3DXFONT_DESC {
    INT   Height;
    UINT  Width;
    UINT  Weight;
    UINT  MipLevels;
    BOOL  Italic;
    BYTE  CharSet;
    BYTE  OutputPrecision;
    BYTE  Quality;
    BYTE  PitchAndFamily;
    TCHAR FaceName;
} D3DXFONT_DESC, *LPD3DXFONT_DESC;

// 定义了一些基于windows的字体
D3DXFONT_DESC FontHandler::m_FontRecords[] = 
{
	//  h   w  weight      mip,itl   char. set       outPrecisions     quality                 pitch/family                    typeface
	{ -14,	0,	FW_NORMAL,	1,	0,	ANSI_CHARSET,	OUT_STROKE_PRECIS, ANTIALIASED_QUALITY,	FF_SWISS | VARIABLE_PITCH,		_T("(Arial)") },
	{ -11,	0,	FW_BOLD,	1,	0,	ANSI_CHARSET,	OUT_STROKE_PRECIS, ANTIALIASED_QUALITY,	FF_SWISS | VARIABLE_PITCH,		_T("(Arial)") },	
	{ -19,	0,	FW_BOLD,	1,	0,	ANSI_CHARSET,	OUT_STROKE_PRECIS, ANTIALIASED_QUALITY,	FF_SWISS | VARIABLE_PITCH,		_T("(Arial)") },		
	{ -16,	0,	FW_BOLD,	1,	0,	ANSI_CHARSET,	OUT_STROKE_PRECIS, ANTIALIASED_QUALITY,	FF_SWISS | VARIABLE_PITCH,		_T("(Arial)") },		
	{ -37,	0,	FW_NORMAL,	1,	0,	ANSI_CHARSET,	OUT_STROKE_PRECIS, ANTIALIASED_QUALITY,	FF_SWISS | VARIABLE_PITCH,		_T("(Impact)") },			
	{ -17,	0,	FW_NORMAL,	1,	0,	SYMBOL_CHARSET,	OUT_STROKE_PRECIS, ANTIALIASED_QUALITY,	FF_DONTCARE | VARIABLE_PITCH,	_T("(Wingdings)") },			
	{ -21,	0,	FW_NORMAL,	1,	0,	ANSI_CHARSET,	OUT_STROKE_PRECIS, ANTIALIASED_QUALITY,	FF_SCRIPT | VARIABLE_PITCH,		_T("(Forte)") },
	{ -11,	0,	FW_BOLD,	1,	0,	ANSI_CHARSET,	OUT_STROKE_PRECIS, ANTIALIASED_QUALITY,	FF_ROMAN | VARIABLE_PITCH,		_T("(Palatino Linotype)") },
	{ -13,	0,	FW_BOLD,	1,	0,	ANSI_CHARSET,	OUT_STROKE_PRECIS, ANTIALIASED_QUALITY,	FF_ROMAN  | VARIABLE_PITCH,		_T("(Palatino Linotype)") },
	{ -16,	0,	FW_BOLD,	1,	0,	ANSI_CHARSET,	OUT_STROKE_PRECIS, ANTIALIASED_QUALITY,	FF_ROMAN | VARIABLE_PITCH,		_T("(Palatino Linotype)") },
	{ -35,	0,	FW_NORMAL,	1,	0,	ANSI_CHARSET,	OUT_STROKE_PRECIS, ANTIALIASED_QUALITY,	FF_DECORATIVE | FIXED_PITCH,	_T("(Quartz)") },
	{ -13,	0,	FW_BOLD,	1,	0,	ANSI_CHARSET,	OUT_STROKE_PRECIS, ANTIALIASED_QUALITY,	FF_SWISS | VARIABLE_PITCH,		_T("(Trebuchet MS)") },
	{ -16,	0,	FW_BOLD,	1,	0,	ANSI_CHARSET,	OUT_STROKE_PRECIS, ANTIALIASED_QUALITY,	FF_SWISS | VARIABLE_PITCH,		_T("(Trebuchet MS)") },
	{ -16,	0,	FW_BOLD,	1,	0,	ANSI_CHARSET,	OUT_STROKE_PRECIS, ANTIALIASED_QUALITY,	FF_SWISS | VARIABLE_PITCH,		_T("(Tahoma)") },
	{ -21,	0,	FW_BOLD,	1,	0,	ANSI_CHARSET,	OUT_STROKE_PRECIS, ANTIALIASED_QUALITY,	FF_SWISS | VARIABLE_PITCH,		_T("(Tahoma)") }
};



// 
// FontHandler::FontHandler
//
FontHandler::FontHandler()
{
	for (int i=0; i<MAX_FONTS; ++i)
	{
		HRESULT hr;
		ID3DXFont *pFont = NULL;
		hr = D3DXCreateFontIndirect(DXUTGetD3D9Device(),&m_FontRecords[i], &pFont);
		if (hr==S_OK && pFont) 
		{
			m_pFonts[i] = GCC_NEW Font(pFont);
		}
		else
		{
			TCHAR msg[256];
			_tcssprintf(msg, _T("Font error: Couldn't initialize %s"), m_FontRecords[i].FaceName);
			MessageBox(g_pApp->GetHwnd(), msg, _T("Error"), MB_OK);
			GCC_ASSERT(0 && msg);
			m_pFonts[i] = NULL;
		}
	}
}


// 
// FontHandler::~FontHandler
//
FontHandler::~FontHandler()
{
	for (int i=0; i<MAX_FONTS; ++i)
	{
		SAFE_DELETE(m_pFonts[i]);
	}
}

// 
// FontHandler::GetStringSize 获取字符串的尺寸框大小
//
CSize FontHandler::GetStringSize(std::wstring const &s, Font *font, int format) const
{
	CRect rect(0,0,0,0);
	if (font->m_d3dFont->DrawText(NULL, s.c_str(), -1, &rect, DT_CALCRECT | format, 0)==0)
	{
		return CSize(0,0);
	}

	return rect.BottomRight();
}

// 
// FontHandler::GetStringSize 获取字符串的尺寸框大小
//
CSize const FontHandler::GetStringSize(std::wstring const &text, TextStyle const style) const 
{
	GCC_ASSERT(text.length() && "Empty text sprites are not allowed!");

	CSize sizeText( 0, 0 );

	sizeText = GetStringSize(text, m_pFonts[style.m_font], style.m_format);

	if (style.m_shadow.valid())
	{
		CPoint offset = (*(style.m_shadow)).m_offset;
		sizeText.cx += abs( offset.x );
		sizeText.cy += abs( offset.y );
	}

	return sizeText;
}


// 
// FontHandler::GetHeight
//
int	FontHandler::GetHeight( const TextStyle style) const
{
	std::wstring space = _T(" ");
	CSize size = GetStringSize(space, style);
	return size.cy;
}

// 
// FontHandler::GetStringWidth
//
int	FontHandler::GetStringWidth(std::wstring const &s,  const TextStyle style) const
{
	return GetStringSize(s, style).cx;
}

// 
// FontHandler::ParseMessage 
//
std::wstring const FontHandler::ParseMessage( std::wstring const & nmessage, const TextStyle style, const CSize & size ) const
{
	//Initialize
	std::wstring line;
	std::wstring word;
	std::wstring multilineMessage;
	std::wstring message = nmessage;

	std::wstring potentialLine;

	TCHAR ch;

	// seperators
	static const int MAX_SEPS( 5 );
	TCHAR seps[MAX_SEPS+1] = _T("\n\t,- ");

	while (message.length())
	{
		//Remove the first single character from 'message'
		ch = message[ 0 ];
		message = message.substr(1);

		//Append that character to the word, making sure not to append lineBreak
		if(ch!=seps[0])
		{
			word += ch;
		}

		potentialLine = line + word;

		//If the potentialLine is too wide, then end this line
		if(GetStringWidth(potentialLine,style)>size.cx)
		{
			TrimLeft(line);
			multilineMessage += line;
			multilineMessage += '\n';
			line = _T("");
		}

		//End a word when it is complete
		for ( int i = 0; i < MAX_SEPS; i++ )
		{
			if ( ch == seps[ i ] )
			{
				line += word;
				word = _T("");

				//Make sure the lineBreaks transfer over
				if(ch==seps[0])
				{
					multilineMessage += line;
					multilineMessage += seps[0];
					line = _T("");
				}
				break;
			}
		}
	}//end while loop

	//Append what is left of the remaining line and word
	line += word;
	TrimLeft(line);
	multilineMessage += line;

	return multilineMessage;
}//end ParseMessage




// 
// FontHandler::DrawText
//
HRESULT FontHandler::DrawText(
	Sprite *sprite,
	const std::wstring strText,
	const TextStyle style,
	const CPoint & origin
	) const
{
	Font *pFont = m_pFonts[style.m_font];
	ID3DXSprite *xSprite = (ID3DXSprite *)sprite->GetSurface();
	CRect rect(0,0,0,0);
	pFont->m_d3dFont->DrawText(xSprite, strText.c_str(), -1, &rect, DT_CALCRECT | style.m_format, style.m_foreground);

	if(style.m_shadow.valid())//Draw the shadow if you must
	{
		TextShadow shadow = *(style.m_shadow);
		//The shadow text gets drawn first, with the background color intact

		CRect shadowRect = rect;
		shadowRect.MoveToXY(rect.left + shadow.m_offset.x, rect.top + shadow.m_offset.y);
		pFont->m_d3dFont->DrawText(xSprite, strText.c_str(), -1, &shadowRect, style.m_format, shadow.m_color);
	}

	pFont->m_d3dFont->DrawText(xSprite, strText.c_str(), -1, &rect, style.m_format, style.m_foreground);

    return S_OK;
}
2. Sprite的实现:

#pragma once
//========================================================================
// Sprite.h : Defines sprites
//========================================================================

#include "ResCache.h"				// needed for ResourceSprite
#include "Font.h"

//
// class IScreenElement
//

enum HRESULT {
    E_INVALIDARG,
    E_FAIL,
    S_OK,
};

class IScreenElement
{
public:
    virtual HRESULT VOnRestore() = 0;
    virtual HRESULT VOnLostDevice() = 0;
    virtual HRESULT VOnRender(double fTime, float fElapsedTime) = 0;
    virtual void VOnUpdate(int deltaMilliseconds) = 0;
    
    virtual int VGetZOrder() const = 0;
    virtual void VSetZOrder(int const zOrder) = 0;
    virtual bool VIsVisible() const = 0;
    virtual void VSetVisible(bool visible) = 0;
    
    virtual LRESULT CALLBACK VOnMsgProc( AppMsg msg )=0;
    
    virtual ~IScreenElement() { };
    virtual bool const operator <(IScreenElement const &other) { return VGetZOrder() < other.VGetZOrder(); }
};

class Sprite : public IScreenElement
{
protected:
	// Position and Pixel data
	// -----------------------------
	ID3DXSprite *m_d3dSprite;			// D3D X Sprite
	IDirect3DTexture9 *m_pTexture;		// Texture to draw on the Sprite

	CPoint m_Position, m_Hotspot;		// subtract HS from pos to get origin
	int m_ZOrder;						// the sort order of the sprite
	int m_Width, m_Height;				// dimensions of one frame
	int m_TextureWidth, m_TextureHeight;// dimensions of the entire texture
	int m_CurrentFrame, m_NumFrames;	// current frame and total frames
	bool m_HasColorKey;				// set to true if the sprite has a color key
	bool m_IsVisible;				// set to true if you want the sprite to draw

	// Members that control animation
	// ------------------------------
	bool m_IsPaused;			// set to true if the animation has been paused
	bool m_LoopingAnim;			// set to true if the animation loops
	int m_ElapsedTime;			// the measure of total elapsed time in ms
	int m_MSPerFrame;			// ms per frame (1000 / desired frames per second)

public:
	Sprite();
	virtual ~Sprite() { SAFE_RELEASE(m_d3dSprite); SAFE_RELEASE(m_pTexture); }

	virtual CPoint const VGetPos() const { return m_Position; } 
	virtual void VSetPos(const CPoint &loc) { m_Position = loc; }
	virtual void VSetHotspot(const CPoint &loc) { m_Hotspot = loc; }
	virtual void VSetSize(const CPoint &size) { m_Width=size.x; m_Height=size.y; }
	virtual CRect const VGetRect() const { return CRect(0,0,m_Width-1,m_Height-1); }
	virtual int const VGetWidth() const { return m_Width; }
	virtual int const VGetHeight() const { return m_Height; }

	// Implementation of the IScreenElement interface
	virtual void VOnUpdate(int deltaMS);
	virtual HRESULT VOnRender(double fTime, float fElapsedTime);
	virtual int VGetZOrder() const { return m_ZOrder; }
	virtual void VSetZOrder(int const zOrder) { m_ZOrder = zOrder; }
	virtual bool VIsVisible() const { return m_IsVisible; }
	virtual void VSetVisible(bool visible) { m_IsVisible = visible; }
	virtual LRESULT CALLBACK VOnMsgProc( AppMsg msg ) { return 0; }
	virtual HRESULT VOnRestore();

	void *GetSurface() { return m_d3dSprite; }

	// the method that sets the current frame
	void SetFrame(const int desiredFrame) { m_CurrentFrame = desiredFrame % m_NumFrames; }

	// the method that retrieves the current frame
	int GetFrame() const { return m_CurrentFrame; }

	// the method that returns the number of frames in this animation
	int GetFrameCount() const 	{ return m_NumFrames; }

	void SetAnim(bool isPaused=false, bool looping=true, int msPerFrame=67)
		{ m_IsPaused=isPaused; m_LoopingAnim=looping; m_MSPerFrame=msPerFrame; }
};


// Members added post-press
// --------------------------

class BitmapSprite : public Sprite
{
protected:
	std::string m_fileName;
	bool m_bInCache;

public:
	BitmapSprite(const std::string fileName, bool inCache, const int frames);

	// Implementation of the IScreenElement interface
	virtual HRESULT VOnRestore();
};


class TextSprite : public Sprite
{
protected:
	std::wstring m_text;				// the text to draw
	TextStyle m_style;					// the style of the text
	bool m_isCentered;					// justification
	optional<CPoint> m_size;			// a static surface size, or size to fit if size is invalid

public:
	TextSprite (
		std::wstring text,					// the text to draw
		TextStyle style, 					// the style of the text
		bool isCentered,					// justification
		const CPoint &position,				// position of this sprite on the parent surface
		optional<CPoint> size				// a static surface size, or size to fit if size is invalid
	);

	// Implementation of the IScreenElement interface
	virtual HRESULT VOnRestore();
	HRESULT VOnRender(double fTime, float fElapsedTime);

	void SetText(const std::wstring text);			// changes the text string
};


//========================================================================
// Sprite.cpp : Defines sprites
//========================================================================

#include "GameCodeStd.h"
#include "GameCode.h"
#include "String.h"
#include "Sprite.h"
#include "Font.h"


// 
// Sprite::Sprite
//
Sprite::Sprite()
{
	m_d3dSprite = NULL;
	m_Position = m_Hotspot = CPoint(0,0);
	m_Width = m_Height = 0;
	m_TextureWidth = m_TextureHeight = 0;
	m_CurrentFrame = m_NumFrames = 0;
	m_HasColorKey = true;

	m_IsPaused = true;
	m_LoopingAnim = false;;
	m_ElapsedTime = 0;
    m_MSPerFrame = 1000 / 15;
	m_IsVisible = true;
	m_pTexture = NULL;
	m_ZOrder = ZORDER_LAYER2;
};

// 
// Sprite::VOnRestore
//
HRESULT Sprite::VOnRestore()
{
	SAFE_RELEASE(m_d3dSprite);
	return (D3DXCreateSprite(DXUTGetD3D9Device(), &m_d3dSprite)==S_OK);
}

// 
// Sprite::VOnRestore 
//
HRESULT Sprite::VOnRender(double fTime, float fElapsedTime)
{
	CPoint actualPos( m_Position - m_Hotspot );
	CRect sourceRect( CPoint(0,0), CPoint(m_Width-1, m_Height-1 ) );

	// Adjust for the frame
	sourceRect.top += ( m_CurrentFrame * m_TextureHeight );
	sourceRect.bottom += ( m_CurrentFrame * m_TextureHeight );

	Vec3 center(1.0f, 1.0f, 0.0f);
	Vec3 translation((const float)actualPos.x, (const float)actualPos.y, 0.0f);

	if (m_d3dSprite && m_pTexture)
	{
		m_d3dSprite->Begin(D3DXSPRITE_ALPHABLEND);
		m_d3dSprite->Draw(m_pTexture, &sourceRect, ¢er, &translation, g_White);
		m_d3dSprite->End();
	}

	return S_OK;
}

// 
// Sprite::VOnRestore 
//
void Sprite::VOnUpdate(int deltaMS)
{
	if (m_IsPaused)
	{
		return;	
	}

	m_ElapsedTime += deltaMS;

	// Only call SetFrame() if we have to.
	// We're guaranteed to have to advance at least one frame...

	if (m_ElapsedTime >= m_MSPerFrame)
	{
		DWORD const numFramesToAdvance = (m_ElapsedTime / m_MSPerFrame);

		m_ElapsedTime -= (numFramesToAdvance * m_MSPerFrame);

		int desiredFrame = GetFrame() + numFramesToAdvance;

		//Check if we're looping...
		if ((false==m_LoopingAnim) && (desiredFrame >= GetFrameCount()))
		{
			desiredFrame = GetFrameCount() - 1;	//Stay on last frame...
		}
		
		//Now advance our frame properly...
		SetFrame(desiredFrame);		
	}
}



// 
// BitmapSprite::BitmapSprite
//
BitmapSprite::BitmapSprite(const std::string fileName, bool inCache, const int frames)
{
	m_fileName = fileName;
	m_NumFrames = frames;
	m_bInCache = inCache;
}

// 
// BitmapSprite::VOnRestore
//
HRESULT BitmapSprite::VOnRestore()
{
	if (FAILED (Sprite::VOnRestore() ) )
	{
		return E_FAIL;
	}

	SAFE_RELEASE(m_pTexture);

    D3DXIMAGE_INFO imageInfo;
	ZeroMemory(&imageInfo, sizeof(D3DXIMAGE_INFO));

	if (m_bInCache)
	{
		Resource resource(m_fileName.c_str());
		shared_ptr<ResHandle> texture = g_pApp->m_ResCache->GetHandle(&resource);
		if ( FAILED ( D3DXCreateTextureFromFileInMemoryEx( 
			DXUTGetD3D9Device(), // device
			texture->Buffer(),		// source data
			texture->Size(),	// source data size
			D3DX_DEFAULT,		// width - get it from the file
			D3DX_DEFAULT,		// height - get it from the file
			D3DX_DEFAULT,		// miplevels - get it from the file
			0,					// useage - default (not a render target or dynamic)
			D3DFMT_UNKNOWN,		// format - get it from the file
			D3DPOOL_DEFAULT,	// pool - use default
			D3DX_FILTER_NONE,	// filter - don't use any filter
			D3DX_DEFAULT,		// mip filter - use default
			g_Transparent,		// color key - use our transparent color
			&imageInfo,			// grab the source info
			NULL,				// palleteindex - we don't need it
			&m_pTexture ) ) )	// the texture pointer
			return E_FAIL;
	}
	else
	{
		if ( FAILED ( D3DXCreateTextureFromFileExA ( 
			DXUTGetD3D9Device(), 
			m_fileName.c_str(),	// source file name
			D3DX_DEFAULT,		// width - get it from the file
			D3DX_DEFAULT,		// height - get it from the file
			D3DX_DEFAULT,		// miplevels - get it from the file
			0,					// useage - default (not a render target or dynamic)
			D3DFMT_UNKNOWN,		// format - get it from the file
			D3DPOOL_DEFAULT,	// pool - use default
			D3DX_FILTER_NONE,	// filter - don't use any filter
			D3DX_DEFAULT,		// mip filter - use default
			g_Transparent,		// color key - use our transparent color
			&imageInfo,			// grab the source info
			NULL,				// palleteindex - we don't need it
			&m_pTexture ) ) )	// the texture pointer
			return E_FAIL;
	}

	m_TextureWidth = m_Width = imageInfo.Width;
	m_TextureHeight = m_Height = imageInfo.Height / m_NumFrames;
	GCC_ASSERT(m_Height * m_NumFrames == imageInfo.Height && _T("Sprite height error"));

	return S_OK;
}




TextSprite::TextSprite(
	std::wstring text,			// the text to draw
	TextStyle style, 			// the style of the text
	const bool isCentered,		// justification
	const CPoint &position,		// position of this sprite on the parent surface
	optional<CPoint> size		// a static surface size, or size to fit if size is invalid
) : m_style(style)
{
	m_text = text;
	m_isCentered = isCentered;

	m_size.clear();
	m_size = size;

	m_Position = position;
	m_NumFrames = 1;
};



HRESULT TextSprite::VOnRestore()
{
	// Two situations:
	// 1) String should be broken into a multiline entity to fit into a specific area
	// 2) String sent it need should take up as much space H&V that it needs

	// Set the width and height
	CSize sizeText;
	CSize sizeTotal;

	std::wstring multiline;

	if ( m_size.valid() )
	{
		// This is the total to fit into	
		sizeTotal = *m_size;

		// Fit the original text inside the bounds
		multiline = g_pApp->GetFontHandler()->ParseMessage( m_text, m_style, sizeTotal);
		sizeText = g_pApp->GetFontHandler()->GetStringSize(multiline, m_style);
	}
	else
	{
		// Set the width and height
		sizeText = g_pApp->GetFontHandler()->GetStringSize(m_text, m_style);
        sizeTotal = sizeText;

		multiline = m_text;
	}

	int numLines = CountLines(multiline);

	GCC_ASSERT(sizeTotal.cx > 0 && sizeTotal.cy > 0 && "About to create sprite with no width or height, is this what you want?");

	m_TextureWidth = m_Width = sizeTotal.cx;
	m_TextureHeight = m_Height = sizeTotal.cy;
	
	UINT texW = static_cast<UINT>(m_TextureWidth);
	UINT texH = static_cast<UINT>(m_TextureHeight);
	UINT numMipLevels = D3DX_DEFAULT;
	D3DFORMAT format = D3DFMT_UNKNOWN;
	
	// This call will reset width, height, and miplevels to the 
	// correct values.
	if (FAILED (D3DXCheckTextureRequirements(
		DXUTGetD3D9Device(), 
		&texW,
		&texH,
		&numMipLevels,
		0,
		&format,
		D3DPOOL_DEFAULT	) ) )
	{
		return false;
	}

	// Create the texture
	SAFE_RELEASE(m_pTexture);
	if ( FAILED ( DXUTGetD3D9Device()->CreateTexture(
		texW,		// width 
		texH,	// height 
		numMipLevels,		// miplevels - use default
		0,					// useage - default (not a render target or dynamic)
		format,				// format - unknown format
		D3DPOOL_DEFAULT,	// pool - use default
		&m_pTexture,		// the texture pointer
		NULL ) ) )
	{
		return false;
	}

	m_TextureWidth = texW;
	m_TextureHeight = texH;

	// Reinitialize the utility string to count the line breaks
	std::wstring utilString = multiline;

	// Size of border
	CSize sizeBorder( sizeTotal - sizeText );

	int initialX = sizeBorder.cx / 2;
	int initialY = sizeBorder.cy / 2;
	int deltaY = sizeText.cy / numLines;
	
	if (m_isCentered)
	{	
		// Determine how the lines will be spaced vertically
		std::wstring firstLine;
		RemoveFirstLine(utilString, firstLine);
		CSize const firstLineSize = g_pApp->GetFontHandler()->GetStringSize( firstLine, m_style );
		CSize printArea = sizeTotal - sizeBorder;
		bool const fitsVertically = printArea.cy >= firstLineSize.cy * numLines;

		if (fitsVertically)
		{	// Enough room, place lines in the center of the print area
			initialY += (printArea.cy - firstLineSize.cy * numLines) / 2;
			deltaY = firstLineSize.cy;
		}
		else
		{	// Not enough room, squeeze lines on top of each other
			deltaY = printArea.cy / numLines;
			initialY += (deltaY - firstLineSize.cy) / 2;
		}
	}
	else
	{
		deltaY = g_pApp->GetFontHandler()->GetHeight( m_style );
	}

	//Draw each line one at a time
	for(int i=0; i<numLines; ++i)
	{
		std::wstring line;
		RemoveFirstLine(multiline, line);
		
		int x = initialX;
		int y = initialY + i * deltaY;

		if (line.length())
		{
			if ( m_isCentered )
			{
				CSize sizeText = g_pApp->GetFontHandler()->GetStringSize( line, m_style );
				x = x + ( sizeTotal.cx - sizeBorder.cx - sizeText.cx ) / 2;
			}

			if(FAILED(g_pApp->GetFontHandler()->DrawText( this, line, m_style, CPoint( x, y ) ) ) )
				return false;
		}
	}

    return true;
}


HRESULT TextSprite::VOnRender(double fTime, float fElapsedTime)
{
	CPoint actualPos( m_Position - m_Hotspot );
	CRect sourceRect( CPoint(0,0), CPoint(m_Width-1, m_Height-1 ) );

	// Adjust for the frame
	sourceRect.top += ( m_CurrentFrame * m_TextureHeight );
	sourceRect.bottom += ( m_CurrentFrame * m_TextureHeight );

	Vec3 center(1.0f, 1.0f, 0.0f);
	Vec3 translation((const float)actualPos.x, (const float)actualPos.y, 0.0f);

	if (m_d3dSprite && m_pTexture)
	{
		m_d3dSprite->Begin(D3DXSPRITE_ALPHABLEND);
		VOnRestore();
		m_d3dSprite->End();
	}

	return S_OK;
}

void TextSprite::SetText(const std::wstring text)
{
	if (text != m_text)
	{
		m_text = text;
		VOnRestore();
	}
}


上面是2D图像的所有UI空间,下篇将是3D图像相关的立体效果控件~~




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值