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图像相关的立体效果控件~~