34. GameProject5
为了启动项目,这里将在defines.h文件中为想要在引擎中使用的雾和多采样功能添加几个define语句。对雾而言,将使用想要创建的雾的枚举类型。对多采样而言,将使用可以支持的多采样枚举类型。对该引擎而言,这里将支持非多采样、2倍、4倍、8倍和16倍速率采样等几种采样类型。雾枚举类型的名称是UGP_FOG_TYPE,而多采样枚举类型的名称是UGP_MS_TYPE。更新后的defines.h文件如程序清单6.15所示。注意在defines.h文件末尾处添加枚举类型,由于该文件的其他内容已经介绍过,因此这里没有列出。
程序清单6.15 更新后的defines.h头文件
#ifndef _UGP_DEFINES_H_
#define _UGP_DEFINES_H_
... The beginning of the header file...
// Multi-sampling.
enum UGP_MS_TYPE
{
UGP_MS_NONE,
UGP_MS_SAMPLES_2,
UGP_MS_SAMPLES_4,
UGP_MS_SAMPLES_8,
UGP_MS_SAMPLES_16
};
// Fog.
enum UGP_FOG_TYPE
{
UGP_VERTEX_FOG,
UGP_PIXEL_FOG
};
#endif
下面将在渲染界面类中添加函数原型,以实现细节映射、启用和禁用雾。然后修改初始化函数,而并不对多采样参数做修改。对粒子系统而言,这里将使用已经添加在引擎中的点状sprite。对本章中已经创建的粒子系统而言,可以将创建的那些文件(RainPS.cpp和RainPS.h)放置在引擎文件夹中。在项目窗口中,将把这些文件添加到引擎项目中,这就是对粒子系统所要做的工作。
对雾而言,将使用EnableFog()函数和DisableFog()函数启用和禁用雾。EnableFog()函数的参数包括雾的起点和终点位置、雾的颜色以及一个用于确认是否正在使用基于范围的雾的标识符。DisableFog()函数将调用SetRenderState()函数,并简单地禁用雾。更新后的渲染界面类、D3D渲染类和全部的EnableFog()函数和DisableFog()函数的代码如程序清单6.16所示。
程序清单6.16 RenderInterface.h, D3DRenderer.h更新的内容
virtual void SetTransparency(RenderState state,
TransState src, TransState dst) = 0;
// @start 雾的起始位置
// @end 雾的终点位置
// @type 雾的类型
// @color 雾的颜色
// rangeFog 是否是范围雾
virtual void EnableFog(float start, float end,
UGP_FOG_TYPE type, unsigned long color,
bool rangeFog) = 0;
// 禁止雾
virtual void DisableFog() = 0;
D3DRenderer.cpp中更新的代码:
void CD3DRenderer::EnableFog(float start, float end,
UGP_FOG_TYPE type, unsigned long color, bool rangeFog)
{
if(!m_Device) return;
D3DCAPS9 caps;
m_Device->GetDeviceCaps(&caps);
// Set fog properties.
m_Device->SetRenderState(D3DRS_FOGENABLE, true);
m_Device->SetRenderState(D3DRS_FOGCOLOR, color);
// Start and end dist of fog.
m_Device->SetRenderState(D3DRS_FOGSTART, *(DWORD*)(&start));
m_Device->SetRenderState(D3DRS_FOGEND, *(DWORD*)(&end));
// Set based on type.
if(type == UGP_VERTEX_FOG)
m_Device->SetRenderState(D3DRS_FOGVERTEXMODE, D3DFOG_LINEAR);
else
m_Device->SetRenderState(D3DRS_FOGTABLEMODE, D3DFOG_LINEAR);
// Can only use if hardware supports it.
if(caps.RasterCaps & D3DPRASTERCAPS_FOGRANGE)
{
if(rangeFog)
m_Device->SetRenderState(D3DRS_RANGEFOGENABLE, true);
else
m_Device->SetRenderState(D3DRS_RANGEFOGENABLE, false);
}
}
void CD3DRenderer::DisableFog()
{
if(!m_Device) return;
// Set fog properties.
m_Device->SetRenderState(D3DRS_FOGENABLE, false);
}
对多采样特性而言,这里将为渲染类的Initialize()函数添加一个参数。该参数的类型为要使用的多采样类型。如果不想使用多采样,那么可以给该函数发送UGP_MS_NONE。如果不支持发送给该函数的多采样类型,就会回到默认的无多采样状态。稍后,将添加一个日志系统,可以将不支持的类型写到一个错误日志文件中,而不是强制初始化失败,或强迫初始化的返回默认类型。使用GetD3DMultiSampleType()函数可以检查是否支持所希望的多采样类型。该函数如果成功,将返回Direct3D中UGP_MS_TYPE枚举类型的内容,否则将返回D3DMULTISAMPLE_NONE。GetD3DMultiSampleType()函数和更新后的Initialize()函数如程序清单6.17所示。同在Direct3D类中一样,要确保更新渲染界面中的Initialize()函数原型,要在函数末尾为多采样类型添加一个参数。
程序清单6.17 添加到游戏引擎中的多采样
CRenderInterface.h D3dRenderer.h的Inialize()函数变为:
virtual bool Initialize(int w, int h,
WinHWND mainWin, bool fullScreen, UGP_MS_TYPE ms) = 0;
对应的实现:
bool CD3DRenderer::Initialize(int w, int h, WinHWND mainWin,
bool fullScreen, UGP_MS_TYPE ms)
{
Shutdown();
m_mainHandle = mainWin;
if(!m_mainHandle) return false;
m_fullscreen = fullScreen;
D3DDISPLAYMODE mode;
D3DCAPS9 caps;
D3DPRESENT_PARAMETERS Params;
ZeroMemory(&Params, sizeof(Params));
m_Direct3D = Direct3DCreate9(D3D_SDK_VERSION);
if(!m_Direct3D) return false;
if(FAILED(m_Direct3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,
&mode))) return false;
if(FAILED(m_Direct3D->GetDeviceCaps(D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL, &caps))) return false;
DWORD processing = 0;
if(caps.VertexProcessingCaps != 0)
processing = D3DCREATE_HARDWARE_VERTEXPROCESSING |
D3DCREATE_PUREDEVICE;
else
processing = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
if(m_fullscreen)
{
Params.FullScreen_RefreshRateInHz = mode.RefreshRate;
Params.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
}
else
Params.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
Params.Windowed = !m_fullscreen;
Params.BackBufferWidth = w;
Params.BackBufferHeight = h;
Params.hDeviceWindow = m_mainHandle;
Params.SwapEffect = D3DSWAPEFFECT_DISCARD;
Params.BackBufferFormat = mode.Format;
Params.BackBufferCount = 1;
Params.EnableAutoDepthStencil = TRUE;
Params.AutoDepthStencilFormat = D3DFMT_D16;
// 设置多采样类型
Params.MultiSampleType = GetD3DMultiSampleType(m_Direct3D, ms,
D3DDEVTYPE_HAL, mode.Format, m_fullscreen);
m_screenWidth = w;
m_screenHeight = h;
if(FAILED(m_Direct3D->CreateDevice(D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL, m_mainHandle, processing,
&Params, &m_Device))) return false;
if(m_Device == NULL) return false;
OneTimeInit();
return true;
}
// @d3d D3D
// @ms 想使用的多采样类型
// @type D3D类型
// @format 数据格式
// @fullscreen 是否全屏
// 若不支持想使用的多采样类型则用D3DMULTISAMPLE_NONE
D3DMULTISAMPLE_TYPE GetD3DMultiSampleType(LPDIRECT3D9 d3d, UGP_MS_TYPE ms,
D3DDEVTYPE type, D3DFORMAT format, bool fullscreen)
{
D3DMULTISAMPLE_TYPE t = D3DMULTISAMPLE_NONE;
if(d3d)
{
switch(ms)
{
case UGP_MS_NONE:
t = D3DMULTISAMPLE_NONE;
break;
case UGP_MS_SAMPLES_2:
if(d3d->CheckDeviceMultiSampleType(D3DADAPTER_DEFAULT,
type, format, !fullscreen, D3DMULTISAMPLE_2_SAMPLES,
NULL) == D3D_OK) t = D3DMULTISAMPLE_2_SAMPLES;
break;
case UGP_MS_SAMPLES_4:
if(d3d->CheckDeviceMultiSampleType(D3DADAPTER_DEFAULT,
type, format, !fullscreen, D3DMULTISAMPLE_2_SAMPLES,
NULL) == D3D_OK) t = D3DMULTISAMPLE_4_SAMPLES;
break;
case UGP_MS_SAMPLES_8:
if(d3d->CheckDeviceMultiSampleType(D3DADAPTER_DEFAULT,
type, format, !fullscreen, D3DMULTISAMPLE_8_SAMPLES,
NULL) == D3D_OK) t = D3DMULTISAMPLE_8_SAMPLES;
break;
case UGP_MS_SAMPLES_16:
if(d3d->CheckDeviceMultiSampleType(D3DADAPTER_DEFAULT,
type, format, !fullscreen, D3DMULTISAMPLE_16_SAMPLES,
NULL) == D3D_OK) t = D3DMULTISAMPLE_16_SAMPLES;
break;
default:
break;
}
}
return t;
}
最后要添加的代码是有关细节映射的。它和多纹理贴图很相似。SetDetailMapping()函数将为细节映射设置必要的渲染状态,它没有任何参数,也不返回任何值。由于细节映射是一种与第二个纹理对象稍有不同的状态集合的多纹理贴图技术,这种技术很奏效,也很容易实现。新更新的包含所有创建的原型和SetDetailMapping()函数的渲染界面和Direct3D类如程序清单6.18所示。
RenderInterface.h
virtual void SetDetailMapping() = 0;
D3DRenderer.h
virtual void SetDetailMapping();
D3DRenderer.cpp
void CD3DRenderer::SetDetailMapping()
{
if(!m_Device) return;
m_Device->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0);
m_Device->SetTextureStageState(0, D3DTSS_COLOROP,D3DTOP_SELECTARG1);
m_Device->SetTextureStageState(0, D3DTSS_COLORARG1,D3DTA_TEXTURE);
m_Device->SetTextureStageState(0, D3DTSS_COLORARG2,D3DTA_DIFFUSE);
m_Device->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, 1);
m_Device->SetTextureStageState(1, D3DTSS_COLOROP,D3DTOP_ADDSIGNED);
m_Device->SetTextureStageState(1, D3DTSS_COLORARG1,D3DTA_TEXTURE);
m_Device->SetTextureStageState(1, D3DTSS_COLORARG2,D3DTA_CURRENT);
}
游戏项目中最后一个改动的地方是main源文件。由于已经改动了Direct3D渲染类的Initialize()函数,因此同样必须改动main文件中的InitializeEngine()函数。该函数希望得到游戏中将要使用的多采样类型。如果硬件不支持多采样数目,那么默认情况下不会选择多采样。程序清单6.19给出了游戏main源文件中InitializeEngine()函数的全部代码。
// 创建渲染系统对象,并初始化Direct3D
bool InitializeEngine()
{
// g_Render指向创建的渲染系统抽象基类对象
if (! CreateD3DRenderer(&g_Render) )
{
return false;
}
// 渲染系统初始化Direct3D
if (! g_Render->Initialize(WIN_WIDTH, WIN_HEIGHT, g_hwnd, FULLSCREEN, UGP_MS_SAMPLES_4) )
{
return false;
}
// 设置后台缓存的指定清除色
g_Render->SetClearCol(0, 0, 0);
// 为要显示的文本创建Arial字体
if (! g_Render->CreateText("Arial", 0, true, 18, g_arialID) )
{
return false;
}
return true;
}