Phinecos(洞庭散人)
光荣在于平淡,艰巨因为漫长
多层纹理混合
//
=============================================================================
//
Desc: 主程序源文件
//
=============================================================================
#include
"
dxstdafx.h
"
#include
"
resource.h
"
//
-----------------------------------------------------------------------------
//
全局变量
//
-----------------------------------------------------------------------------
ID3DXFont
*
g_pFont
=
NULL;
//
ID3DXFont字体对象
ID3DXSprite
*
g_pTextSprite
=
NULL;
//
ID3DXSprite文本精灵对象
bool
g_bShowHelp
=
true
;
//
标识是否显示简单说明文本
CDXUTDialogResourceManager g_DialogResourceManager;
//
对话框资源管理器
CD3DSettingsDlg g_SettingsDlg;
//
Direct3D设备设置对话框
CDXUTDialog g_HUD;
//
CDXUTDialog g_SampleUI;
//
LPDIRECT3DVERTEXBUFFER9 g_pVB
=
NULL;
//
顶点缓冲区
LPDIRECT3DTEXTURE9 g_pTexture1
=
NULL;
//
第一层纹理
LPDIRECT3DTEXTURE9 g_pTexture2
=
NULL;
//
第二层纹理
//
定义顶点结构和灵活顶点格式
struct
CUSTOMVERTEX
{
FLOAT x, y, z;
//
未经过坐标转换的顶点坐标
DWORD color;
//
顶点漫反射颜色值
FLOAT u,v ;
//
顶点纹理坐标
FLOAT u1,v1 ;
//
顶点纹理坐标
}
;
#define
D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ| D3DFVF_DIFFUSE| D3DFVF_TEX2)
//
-----------------------------------------------------------------------------
//
控件ID
//
-----------------------------------------------------------------------------
#define
IDC_TOGGLEFULLSCREEN 1
#define
IDC_TOGGLEREF 2
#define
IDC_CHANGEDEVICE 3
//
-----------------------------------------------------------------------------
//
Desc: 函数声明
//
------------------------------------------------------------------------------
bool
CALLBACK IsDeviceAcceptable( D3DCAPS9
*
pCaps, D3DFORMAT AdapterFormat, D3DFORMAT BackBufferFormat,
bool
bWindowed,
void
*
pUserContext );
bool
CALLBACK ModifyDeviceSettings( DXUTDeviceSettings
*
pDeviceSettings,
const
D3DCAPS9
*
pCaps,
void
*
pUserContext );
HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9
*
pd3dDevice,
const
D3DSURFACE_DESC
*
pBackBufferSurfaceDesc,
void
*
pUserContext );
HRESULT CALLBACK OnResetDevice( IDirect3DDevice9
*
pd3dDevice,
const
D3DSURFACE_DESC
*
pBackBufferSurfaceDesc,
void
*
pUserContext );
void
CALLBACK OnFrameMove( IDirect3DDevice9
*
pd3dDevice,
double
fTime,
float
fElapsedTime,
void
*
pUserContext );
void
CALLBACK OnFrameRender( IDirect3DDevice9
*
pd3dDevice,
double
fTime,
float
fElapsedTime,
void
*
pUserContext );
LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
bool
*
pbNoFurtherProcessing,
void
*
pUserContext );
void
CALLBACK KeyboardProc( UINT nChar,
bool
bKeyDown,
bool
bAltDown,
void
*
pUserContext );
void
CALLBACK OnGUIEvent( UINT nEvent,
int
nControlID, CDXUTControl
*
pControl,
void
*
pUserContext );
void
CALLBACK OnLostDevice(
void
*
pUserContext );
void
CALLBACK OnDestroyDevice(
void
*
pUserContext );
void
InitApp();
void
RenderText();
//
-----------------------------------------------------------------------------
//
Desc: 入口函数
//
-----------------------------------------------------------------------------
INT WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR,
int
)
{
//
为Debug配置启用运行时内存检查功能
#if
defined(DEBUG) | defined(_DEBUG)
_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF
|
_CRTDBG_LEAK_CHECK_DF );
#endif
//
设置回调函数
DXUTSetCallbackDeviceCreated( OnCreateDevice );
DXUTSetCallbackDeviceReset( OnResetDevice );
DXUTSetCallbackDeviceLost( OnLostDevice );
DXUTSetCallbackDeviceDestroyed( OnDestroyDevice );
DXUTSetCallbackMsgProc( MsgProc );
DXUTSetCallbackKeyboard( KeyboardProc );
DXUTSetCallbackFrameRender( OnFrameRender );
DXUTSetCallbackFrameMove( OnFrameMove );
//
应用程序相关的初始化
InitApp();
//
初始化DXUT, 创建窗口, 创建Direct3D设备对象
DXUTInit(
true
,
true
,
true
);
DXUTSetCursorSettings(
true
,
true
);
DXUTCreateWindow( L
"
MultiTexture
"
);
DXUTCreateDevice( D3DADAPTER_DEFAULT,
true
,
640
,
480
,
IsDeviceAcceptable, ModifyDeviceSettings );
//
进入消息循环和场景渲染
DXUTMainLoop();
//
在此进行应用程序相关的清除工作
return
DXUTGetExitCode();
}
//
-----------------------------------------------------------------------------
//
Desc: 应用程序相关初始化
//
-----------------------------------------------------------------------------
void
InitApp()
{
//
初始化对话框
g_SettingsDlg.Init(
&
g_DialogResourceManager );
g_HUD.Init(
&
g_DialogResourceManager );
g_SampleUI.Init(
&
g_DialogResourceManager );
//
为g_HUD对话框设置消息处理函数,添加控件
g_HUD.SetCallback( OnGUIEvent );
int
iY
=
10
;
g_HUD.AddButton( IDC_TOGGLEFULLSCREEN, L
"
Toggle full screen
"
,
35
, iY,
125
,
22
);
g_HUD.AddButton( IDC_TOGGLEREF, L
"
Toggle REF (F3)
"
,
35
, iY
+=
24
,
125
,
22
);
g_HUD.AddButton( IDC_CHANGEDEVICE, L
"
Change device (F2)
"
,
35
, iY
+=
24
,
125
,
22
, VK_F2 );
}
//
-----------------------------------------------------------------------------
//
Desc: 设备能力检查
//
-----------------------------------------------------------------------------
bool
CALLBACK IsDeviceAcceptable( D3DCAPS9
*
pCaps, D3DFORMAT AdapterFormat,
D3DFORMAT BackBufferFormat,
bool
bWindowed,
void
*
pUserContext )
{
//
检查后台缓冲区格式是否支持Alpha混合等操作(post pixel blending operations)
IDirect3D9
*
pD3D
=
DXUTGetD3DObject();
if
( FAILED( pD3D
->
CheckDeviceFormat( pCaps
->
AdapterOrdinal, pCaps
->
DeviceType,
AdapterFormat, D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING,
D3DRTYPE_TEXTURE, BackBufferFormat ) ) )
return
false
;
//
检查当前渲染设备是否支持多层纹理混合
if
( pCaps
->
MaxTextureBlendStages
<=
1
)
return
false
;
return
true
;
}
//
-----------------------------------------------------------------------------
//
Desc: 修改Direct3D渲染设备设置
//
-----------------------------------------------------------------------------
bool
CALLBACK ModifyDeviceSettings( DXUTDeviceSettings
*
pDeviceSettings,
const
D3DCAPS9
*
pCaps,
void
*
pUserContext )
{
//
如果不支持硬件顶点处理则使用软件顶点处理
if
( (pCaps
->
DevCaps
&
D3DDEVCAPS_HWTRANSFORMANDLIGHT)
==
0
)
{
pDeviceSettings
->
BehaviorFlags
=
D3DCREATE_SOFTWARE_VERTEXPROCESSING;
}
//
如果使用参考设备,则弹出警告对话框
static
bool
s_bFirstTime
=
true
;
if
( s_bFirstTime )
{
s_bFirstTime
=
false
;
if
( pDeviceSettings
->
DeviceType
==
D3DDEVTYPE_REF )
DXUTDisplaySwitchingToREFWarning();
}
return
true
;
}
//
-----------------------------------------------------------------------------
//
Desc: 在此创建管理内存资源对象
//
-----------------------------------------------------------------------------
HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9
*
pd3dDevice,
const
D3DSURFACE_DESC
*
pBackBufferSurfaceDesc,
void
*
pUserContext )
{
HRESULT hr;
V_RETURN( g_DialogResourceManager.OnCreateDevice( pd3dDevice ) );
V_RETURN( g_SettingsDlg.OnCreateDevice( pd3dDevice ) );
//
创建字体
V_RETURN( D3DXCreateFont( pd3dDevice,
15
,
0
, FW_BOLD,
1
, FALSE, DEFAULT_CHARSET,
OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH
|
FF_DONTCARE,
L
"
Arial
"
,
&
g_pFont ) );
//
创建第一层纹理对象
V_RETURN( D3DXCreateTextureFromFile( pd3dDevice, L
"
Wall.bmp
"
,
&
g_pTexture1 ) );
//
创建第二层纹理对象
V_RETURN( D3DXCreateTextureFromFile( pd3dDevice, L
"
light.jpg
"
,
&
g_pTexture2 ) );
//
设置顶点数据
CUSTOMVERTEX g_Vertices[]
=
{
{
-
3.0f
,
-
3.0f
,
0.0f
,
0xffffffff
,
0.0f
,
1.0f
,
0.0f
,
1.0f
}
,
{
-
3.0f
,
3.0f
,
0.0f
,
0xffffffff
,
0.0f
,
0.0f
,
0.0f
,
0.0f
}
,
{
3.0f
,
-
3.0f
,
0.0f
,
0xffffffff
,
1.0f
,
1.0f
,
1.0f
,
1.0f
}
,
{
3.0f
,
3.0f
,
0.0f
,
0xffffffff
,
1.0f
,
0.0f
,
1.0f
,
0.0f
}
}
;
//
创建顶点缓冲区
V_RETURN( pd3dDevice
->
CreateVertexBuffer(
4
*
sizeof
(CUSTOMVERTEX),
0
, D3DFVF_CUSTOMVERTEX,
D3DPOOL_MANAGED,
&
g_pVB,NULL ) );
//
填充顶点数据
VOID
*
pVertices;
V_RETURN( g_pVB
->
Lock(
0
,
sizeof
(g_Vertices), (
void
**
)
&
pVertices,
0
) );
memcpy( pVertices, g_Vertices,
sizeof
(g_Vertices) );
g_pVB
->
Unlock();
return
S_OK;
}
//
-----------------------------------------------------------------------------
//
Desc: 在此创建默认内存类型资源对象
//
-----------------------------------------------------------------------------
HRESULT CALLBACK OnResetDevice( IDirect3DDevice9
*
pd3dDevice,
const
D3DSURFACE_DESC
*
pBackBufferSurfaceDesc,
void
*
pUserContext )
{
HRESULT hr;
V_RETURN( g_DialogResourceManager.OnResetDevice() );
V_RETURN( g_SettingsDlg.OnResetDevice() );
//
设置对话框位置和尺寸
g_HUD.SetLocation( pBackBufferSurfaceDesc
->
Width
-
170
,
0
);
g_HUD.SetSize(
170
,
170
);
g_SampleUI.SetLocation( pBackBufferSurfaceDesc
->
Width
-
170
,
pBackBufferSurfaceDesc
->
Height
-
350
);
g_SampleUI.SetSize(
170
,
300
);
//
恢复字体
if
( g_pFont )
V_RETURN( g_pFont
->
OnResetDevice() );
//
创建ID3DXSprite接口对象
V_RETURN( D3DXCreateSprite( pd3dDevice,
&
g_pTextSprite ) );
//
设置观察矩阵
D3DXMATRIXA16 matView;
D3DXVECTOR3 vEyePt(
0.0f
,
0.0f
,
-
8
);
D3DXVECTOR3 vLookatPt(
0.0f
,
0.0f
,
0.0f
);
D3DXVECTOR3 vUpVec(
0.0f
,
1.0f
,
0.0f
);
D3DXMatrixLookAtLH(
&
matView,
&
vEyePt,
&
vLookatPt,
&
vUpVec );
pd3dDevice
->
SetTransform( D3DTS_VIEW,
&
matView );
//
设置投影矩阵
D3DXMATRIXA16 matProj;
float
fAspectRatio
=
(
float
)pBackBufferSurfaceDesc
->
Width
/
pBackBufferSurfaceDesc
->
Height;
D3DXMatrixPerspectiveFovLH(
&
matProj, D3DX_PI
/
4
, fAspectRatio,
1.0f
,
100.0f
);
pd3dDevice
->
SetTransform( D3DTS_PROJECTION,
&
matProj );
//
设置第层纹理、纹理阶段状态和纹理坐标索引
pd3dDevice
->
SetTexture(
0
, g_pTexture1 );
pd3dDevice
->
SetTextureStageState(
0
, D3DTSS_COLOROP, D3DTOP_MODULATE );
pd3dDevice
->
SetTextureStageState(
0
, D3DTSS_COLORARG1, D3DTA_TEXTURE );
pd3dDevice
->
SetTextureStageState(
0
, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
pd3dDevice
->
SetTextureStageState(
0
, D3DTSS_ALPHAOP, D3DTOP_DISABLE );
pd3dDevice
->
SetTextureStageState(
0
, D3DTSS_TEXCOORDINDEX,
0
);
pd3dDevice
->
SetSamplerState(
0
, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
pd3dDevice
->
SetSamplerState(
0
, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
//
设置第层纹理、纹理阶段状态和纹理坐标索引
pd3dDevice
->
SetTexture(
1
, g_pTexture2 );
pd3dDevice
->
SetTextureStageState(
1
, D3DTSS_COLOROP, D3DTOP_ADD);
pd3dDevice
->
SetTextureStageState(
1
, D3DTSS_COLORARG1, D3DTA_TEXTURE );
pd3dDevice
->
SetTextureStageState(
1
, D3DTSS_COLORARG2, D3DTA_CURRENT);
pd3dDevice
->
SetTextureStageState(
1
, D3DTSS_ALPHAOP, D3DTOP_DISABLE );
pd3dDevice
->
SetTextureStageState(
1
, D3DTSS_TEXCOORDINDEX,
1
);
pd3dDevice
->
SetSamplerState(
1
, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
pd3dDevice
->
SetSamplerState(
1
, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
//
关闭光照计算
pd3dDevice
->
SetRenderState( D3DRS_LIGHTING,
false
);
return
S_OK;
}
//
-----------------------------------------------------------------------------
//
Desc: 更新场景
//
-----------------------------------------------------------------------------
void
CALLBACK OnFrameMove( IDirect3DDevice9
*
pd3dDevice,
double
fTime,
float
fElapsedTime,
void
*
pUserContext )
{
}
//
-----------------------------------------------------------------------------
//
Desc: 渲染场景
//
-----------------------------------------------------------------------------
void
CALLBACK OnFrameRender( IDirect3DDevice9
*
pd3dDevice,
double
fTime,
float
fElapsedTime,
void
*
pUserContext )
{
HRESULT hr;
//
如果正在利用Direct3D设备设置对话框进行设置, 则不渲染场景
if
( g_SettingsDlg.IsActive() )
{
g_SettingsDlg.OnRender( fElapsedTime );
return
;
}
//
清除后台颜色缓冲区和深度缓冲区
V( pd3dDevice
->
Clear(
0
, NULL, D3DCLEAR_TARGET
|
D3DCLEAR_ZBUFFER,
D3DCOLOR_ARGB(
0
,
45
,
50
,
170
),
1.0f
,
0
) );
//
渲染场景
if
( SUCCEEDED( pd3dDevice
->
BeginScene() ) )
{
pd3dDevice
->
SetStreamSource(
0
, g_pVB,
0
,
sizeof
(CUSTOMVERTEX) );
pd3dDevice
->
SetFVF( D3DFVF_CUSTOMVERTEX );
pd3dDevice
->
DrawPrimitive( D3DPT_TRIANGLESTRIP,
0
,
2
);
//
渲染文本和控件
DXUT_BeginPerfEvent( DXUT_PERFEVENTCOLOR, L
"
HUD / Stats
"
);
RenderText();
V( g_HUD.OnRender( fElapsedTime ) );
V( g_SampleUI.OnRender( fElapsedTime ) );
DXUT_EndPerfEvent();
V( pd3dDevice
->
EndScene() );
}
}
//
-----------------------------------------------------------------------------
//
Desc: 渲染文本
//
-----------------------------------------------------------------------------
void
RenderText()
{
CDXUTTextHelper txtHelper( g_pFont, g_pTextSprite,
15
);
//
显示当前Direct3D设备状态和渲染帧速率
txtHelper.Begin();
txtHelper.SetInsertionPos(
5
,
5
);
txtHelper.SetForegroundColor( D3DXCOLOR(
1.0f
,
1.0f
,
0.0f
,
1.0f
) );
txtHelper.DrawTextLine( DXUTGetFrameStats(
true
) );
txtHelper.DrawTextLine( DXUTGetDeviceStats() );
//
显示其他简要信息
txtHelper.SetForegroundColor( D3DXCOLOR(
1.0f
,
1.0f
,
1.0f
,
1.0f
) );
txtHelper.DrawTextLine( L
"
多层纹理混合
"
);
//
显示简单帮助文本
const
D3DSURFACE_DESC
*
pd3dsdBackBuffer
=
DXUTGetBackBufferSurfaceDesc();
if
( g_bShowHelp )
{
txtHelper.SetInsertionPos(
10
, pd3dsdBackBuffer
->
Height
-
15
*
6
);
txtHelper.SetForegroundColor( D3DXCOLOR(
1.0f
,
0.75f
,
0.0f
,
1.0f
) );
txtHelper.DrawTextLine( L
"
Controls (F1 to hide):
"
);
txtHelper.SetInsertionPos(
40
, pd3dsdBackBuffer
->
Height
-
15
*
5
);
txtHelper.DrawTextLine( L
"
Quit: ESC
"
);
}
else
{
txtHelper.SetInsertionPos(
10
, pd3dsdBackBuffer
->
Height
-
15
*
2
);
txtHelper.SetForegroundColor( D3DXCOLOR(
1.0f
,
1.0f
,
1.0f
,
1.0f
) );
txtHelper.DrawTextLine( L
"
Press F1 for help
"
);
}
txtHelper.End();
}
//
-----------------------------------------------------------------------------
//
Desc: 消息处理
//
-----------------------------------------------------------------------------
LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
bool
*
pbNoFurtherProcessing,
void
*
pUserContext )
{
*
pbNoFurtherProcessing
=
g_DialogResourceManager.MsgProc( hWnd, uMsg, wParam, lParam );
if
(
*
pbNoFurtherProcessing )
return
0
;
if
( g_SettingsDlg.IsActive() )
{
g_SettingsDlg.MsgProc( hWnd, uMsg, wParam, lParam );
return
0
;
}
*
pbNoFurtherProcessing
=
g_HUD.MsgProc( hWnd, uMsg, wParam, lParam );
if
(
*
pbNoFurtherProcessing )
return
0
;
*
pbNoFurtherProcessing
=
g_SampleUI.MsgProc( hWnd, uMsg, wParam, lParam );
if
(
*
pbNoFurtherProcessing )
return
0
;
return
0
;
}
//
-----------------------------------------------------------------------------
//
Desc: 键盘消息处理
//
-----------------------------------------------------------------------------
void
CALLBACK KeyboardProc( UINT nChar,
bool
bKeyDown,
bool
bAltDown,
void
*
pUserContext )
{
if
( bKeyDown )
{
switch
( nChar )
{
case
VK_F1: g_bShowHelp
=
!
g_bShowHelp;
break
;
}
}
}