/*
-------------------------------------
代码清单:SpriteBatch.cpp
来自:
http://www.cnblogs.com/kenkao
-------------------------------------
*/
#include
"
StdAfx.h
"
#include
"
SpriteBatch.h
"
//
精灵顶点缓冲结构定义
struct
VertexSprite{
VertexSprite(){}
VertexSprite(
float
x,
float
y,
float
z,
float
nx,
float
ny,
float
nz, D3DCOLOR color,
float
u,
float
v){
_x
=
x; _y
=
y; _z
=
z;
_nx
=
nx; _ny
=
ny; _nz
=
nz;
_color
=
color;
_u
=
u; _v
=
v;
}
float
_x, _y, _z;
float
_nx, _ny, _nz;
D3DCOLOR _color;
float
_u, _v;
static
const
DWORD FVF;
};
const
DWORD VertexSprite::FVF
=
(D3DFVF_XYZ
|
D3DFVF_NORMAL
|
D3DFVF_DIFFUSE
|
D3DFVF_TEX1);
CSpriteBatch::CSpriteBatch(IDirect3DDevice9
*
pDevice) : m_pDevice(NULL),
m_pD3DEffect(NULL),
m_pCurrentTexture(NULL),
m_NumPasses(
0
),
m_OriViewMatrix(D3DXMATRIX_IDENTITY),
m_OriProjMatrix(D3DXMATRIX_IDENTITY),
m_pSpriteNodeList(NULL)
{
//
传入3D设备
this
->
m_pDevice
=
pDevice;
//
获得单位摄影矩阵
m_ViewMatrix
=
D3DXMATRIX_IDENTITY;
//
获得正交投影矩阵
D3DXMatrixOrthoOffCenterLH(
&
m_ProjMatrix,
0.0f
,
640.0f
,
480.0f
,
0.0f
,
0.0f
,
1.0f
);
//
初始化精灵节点列表
m_pSpriteNodeList
=
new
list
<
SpriteNode
>
;
}
CSpriteBatch::
~
CSpriteBatch(
void
)
{
}
void
CSpriteBatch::Begin(CD3DEffect
*
pD3DEffect)
{
//
获得原始状态
m_pDevice
->
GetTransform(D3DTS_VIEW,
&
m_OriViewMatrix);
m_pDevice
->
GetTransform(D3DTS_PROJECTION,
&
m_OriProjMatrix);
//
设置单位摄影矩阵及正交投影矩阵
m_pDevice
->
SetTransform(D3DTS_VIEW,
&
m_ViewMatrix);
m_pDevice
->
SetTransform(D3DTS_PROJECTION,
&
m_ProjMatrix);
//
如果存在特效则应用之
if
(pD3DEffect)
{
this
->
m_pD3DEffect
=
pD3DEffect;
m_pD3DEffect
->
BeginEffect(m_NumPasses);
}
}
void
CSpriteBatch::End()
{
//
结束绘制之前Flush一次全部节点
Flush();
//
如果存在特效则结束之
if
(m_pD3DEffect)
m_pD3DEffect
->
EndEffect();
//
还原原始摄影矩阵及投影矩阵
m_pDevice
->
SetTransform(D3DTS_VIEW,
&
m_OriViewMatrix);
m_pDevice
->
SetTransform(D3DTS_PROJECTION,
&
m_OriProjMatrix);
}
void
CSpriteBatch::PostFrame(RECT DesRect,RECT SurRect,
float
layerDepth,D3DCOLOR Color)
{
//
列表新增一个节点
m_pSpriteNodeList
->
push_back(SpriteNode(DesRect,SurRect,layerDepth,Color));
}
void
CSpriteBatch::Flush()
{
//
错误排查
int
NumNodes
=
m_pSpriteNodeList
->
size();
if
(NumNodes
<=
0
||
!
m_pCurrentTexture)
return
;
//
动态申请顶点缓冲区与索引缓冲区
VertexSprite
*
vb
=
new
VertexSprite[NumNodes
*
4
];
UINT16
*
ib
=
new
UINT16 [NumNodes
*
6
];
memset(vb,
0
,
sizeof
(VertexSprite)
*
NumNodes
*
4
);
memset(ib,
0
,
sizeof
(UINT16)
*
NumNodes
*
6
);
//
遍历全部节点,合并顶点缓冲及索引缓冲
int
i
=
0
;
for
(list
<
SpriteNode
>
::iterator ptr
=
m_pSpriteNodeList
->
begin();ptr
!=
m_pSpriteNodeList
->
end();
++
ptr)
{
//
将纹理区域折合成uv坐标
float
Txcrd_LU_u
=
ptr
->
_SurRect.left
/
m_pCurrentTexture
->
GetWidth();
float
Txcrd_LU_v
=
ptr
->
_SurRect.top
/
m_pCurrentTexture
->
GetHeight();
float
Txcrd_RU_u
=
ptr
->
_SurRect.right
/
m_pCurrentTexture
->
GetWidth();
float
Txcrd_RU_v
=
ptr
->
_SurRect.top
/
m_pCurrentTexture
->
GetHeight();
float
Txcrd_RD_u
=
ptr
->
_SurRect.right
/
m_pCurrentTexture
->
GetWidth();
float
Txcrd_RD_v
=
ptr
->
_SurRect.bottom
/
m_pCurrentTexture
->
GetHeight();
float
Txcrd_LD_u
=
ptr
->
_SurRect.left
/
m_pCurrentTexture
->
GetWidth();
float
Txcrd_LD_v
=
ptr
->
_SurRect.bottom
/
m_pCurrentTexture
->
GetHeight();
//
填充顶点缓冲区数据
vb[i
*
4
]
=
VertexSprite(ptr
->
_DesRect.left, ptr
->
_DesRect.top, ptr
->
_layerDepth,
0.0f
,
0.0f
,
0.0f
, ptr
->
_Color, Txcrd_LU_u, Txcrd_LU_v);
vb[i
*
4
+
1
]
=
VertexSprite(ptr
->
_DesRect.right,ptr
->
_DesRect.top, ptr
->
_layerDepth,
0.0f
,
0.0f
,
0.0f
, ptr
->
_Color, Txcrd_RU_u, Txcrd_RU_v);
vb[i
*
4
+
2
]
=
VertexSprite(ptr
->
_DesRect.right,ptr
->
_DesRect.bottom,ptr
->
_layerDepth,
0.0f
,
0.0f
,
0.0f
, ptr
->
_Color, Txcrd_RD_u, Txcrd_RD_v);
vb[i
*
4
+
3
]
=
VertexSprite(ptr
->
_DesRect.left, ptr
->
_DesRect.bottom,ptr
->
_layerDepth,
0.0f
,
0.0f
,
0.0f
, ptr
->
_Color, Txcrd_LD_u, Txcrd_LD_v);
//
填充索引缓冲区数据
ib[i
*
6
]
=
i
*
4
;
ib[i
*
6
+
1
]
=
i
*
4
+
1
;
ib[i
*
6
+
2
]
=
i
*
4
+
2
;
ib[i
*
6
+
3
]
=
i
*
4
;
ib[i
*
6
+
4
]
=
i
*
4
+
2
;
ib[i
*
6
+
5
]
=
i
*
4
+
3
;
i
++
;
}
//
应用活动纹理
m_pDevice
->
SetTexture(
0
,m_pCurrentTexture
->
GetTexture());
//
如果存在特效则应用全部路径
if
(m_pD3DEffect)
{
for
(UINT i
=
0
;i
<
m_NumPasses;i
++
)
{
//
开启路径
m_pD3DEffect
->
GetEffect()
->
BeginPass(i);
//
一次性绘制全部顶点
m_pDevice
->
SetFVF(VertexSprite::FVF);
m_pDevice
->
DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST,
0
, NumNodes
*
4
, NumNodes
*
2
,
&
ib[
0
],
D3DFMT_INDEX16,
&
vb[
0
],
sizeof
(VertexSprite));
//
路径结束
m_pD3DEffect
->
GetEffect()
->
EndPass();
}
}
//
如果不存在特效则采用普通绘制
else
{
//
一次性绘制全部顶点
m_pDevice
->
SetFVF(VertexSprite::FVF);
m_pDevice
->
DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST,
0
, NumNodes
*
4
, NumNodes
*
2
,
&
ib[
0
],
D3DFMT_INDEX16,
&
vb[
0
],
sizeof
(VertexSprite));
}
//
注销顶点缓冲区与索引缓冲区
delete[] vb;
delete[] ib;
//
清空节点列表数据
m_pSpriteNodeList
->
clear();
}
void
CSpriteBatch::Draw(CTexture2D
*
pTexture,
const
RECT
&
DesRect,
const
RECT
&
SurRect,
const
float
&
layerDepth, D3DCOLOR Color)
{
//
如果当前没有活动纹理则应用之
if
(
!
m_pCurrentTexture)
m_pCurrentTexture
=
pTexture;
//
如果当前纹理状态发生变化,则flush现有全部节点
if
(m_pCurrentTexture
!=
pTexture)
{
Flush();
//
重新应用新的活动纹理
m_pCurrentTexture
=
pTexture;
}
//
投递新节点数据
PostFrame(DesRect,SurRect,layerDepth,Color);
}
//
一系列的重载Draw函数
void
CSpriteBatch::Draw(CTexture2D
*
pTexture,
const
POINT
&
Pos,
const
RECT
&
SurRect,
const
float
&
layerDepth, D3DCOLOR Color)
{
RECT rect;
rect.left
=
Pos.x;
rect.top
=
Pos.y;
rect.right
=
Pos.x
+
pTexture
->
GetWidth();
rect.bottom
=
Pos.y
+
pTexture
->
GetHeight();
Draw(pTexture,rect,SurRect,layerDepth,Color);
}
void
CSpriteBatch::Draw(CTexture2D
*
pTexture,
const
POINT
&
Pos,
const
float
&
layerDepth, D3DCOLOR Color)
{
Draw(pTexture,Pos,pTexture
->
GetRect(),layerDepth,Color);
}
void
CSpriteBatch::Draw(CTexture2D
*
pTexture,
const
RECT
&
DesRect,
const
float
&
layerDepth, D3DCOLOR Color)
{
Draw(pTexture,DesRect,pTexture
->
GetRect(),layerDepth,Color);
}
void
CSpriteBatch::Draw(CTexture2D
*
pTexture,
const
POINT
&
Pos,
const
POINT
&
Size,
const
RECT
&
SurRect,
const
float
&
layerDepth, D3DCOLOR Color)
{
RECT rect;
rect.left
=
Pos.x;
rect.top
=
Pos.y;
rect.right
=
Pos.x
+
Size.x;
rect.bottom
=
Pos.y
+
Size.y;
Draw(pTexture,rect,SurRect,layerDepth,Color);
}
void
CSpriteBatch::Draw(CTexture2D
*
pTexture,
const
POINT
&
Pos,
const
POINT
&
Size,
const
float
&
layerDepth, D3DCOLOR Color)
{
Draw(pTexture,Pos,Size,pTexture
->
GetRect(),layerDepth,Color);
}