基于MFC的Direct3D程序设计

原文链接: MFC D3D Application: Direct3D Tutorial Part I
作者这个 MFC 程序中第一个有趣的地方是让用于 Direct3D 绘制的窗口类从 CWnd 类和 CXD3D 类继承下来:

class CD3DWnd : public CXD3D, public CWnd

CD3DWnd类是用于窗口中控件(比如一个PictureBox)的基类,这个控件将提供普通Cwnd类的功能,但同时也拥有CXD3D3D绘制的能力。

先来看CXD3D类:

// -----------------------------------------------------------------------------
// CXD3Dclass:theclassaviewclasswillderivefromtoprovideawindow
// handletorenderinto,andthatwilloverridethe3Dscenerendering.
// -----------------------------------------------------------------------------
class CXD3D
{
protected:
//internalstatevariables
boolm_bActive;//toggledonPause,canbequeriedupon
//initializingtoissueaCreate[false]
boolm_bStartFullscreen;//queriedonChooseInitialSettings[false]
boolm_bShowCursor;//infullscreenmode[true]
boolm_bClipCursor;//infullscreenmode[true]
boolm_bWindowed;//queriedonBuildPresentParamsFromSettings
//[true]
boolm_bIgnoreSizeChange;//queriedonHandlePossibleSizeChange[false]
boolm_bDeviceLost;//truewhenthedevice'sPresentfails
boolm_bDeviceObjectsInited;//trueifInitDeviceObjectssucceeds
boolm_bDeviceObjectsRestored;//trueifRestoreDeviceObjectssucceeds
//internaltimingvariables
FLOATm_fTime;//absolutetimehandledbyDXUtil_Timer
FLOATm_fElapsedTime;//elapsedtimehandledbyDXUtil_Timer
FLOATm_fFPS;//theframerate,orframespersecond
//statistics
TCHARm_strDeviceStats[256];//devicedescription
TCHARm_strFrameStats[16];//framestatistics
//mainobjectsusedforcreatingandrenderingthe3Dscene
HWNDm_hWndRender;//devicewindow
HWNDm_hWndFocus;//focuswindow
LPDIRECT3D9m_pd3d;//mainD3Dobject
LPDIRECT3DDEVICE9m_pd3dDevice;//D3Drenderingdevice
D3DPRESENT_PARAMETERSm_d3dpp;//presentationparameters
DWORDm_dwCreateFlags;//sw/hwVP+puredevice
DWORDm_dwWindowStyle;//savedformodeswitches
RECTm_rcWindow;//windowandclientrects,
RECTm_rcClient;//savedformodeswitches
//setupobjects
CXD3DEnumEnumeration;//hierarchyofadapters,modes,devices,etc.
CXD3DSettingsSettings;//currentdisplaysettings
protected:
//internalerrorhandlingfunction
HRESULTDisplayErrorMsg(HRESULThr,DWORDdwType);
//internalmanagementfunctions
voidBuildPresentParamsFromSettings();
boolFindBestWindowedMode(boolbHAL,boolbREF);
boolFindBestFullscreenMode(boolbHAL,boolbREF);
HRESULTChooseInitialSettings();
HRESULTInitializeEnvironment();
HRESULTResetEnvironment();
voidCleanupEnvironment();
public:
HRESULTRenderEnvironment();
HRESULTHandlePossibleSizeChange();
protected:
voidUpdateStats();
//Overridablefunctionsforthe3Dscenecreatedbytheapp
virtualHRESULTOneTimeSceneInit(){returnS_OK;}
virtualHRESULTInitDeviceObjects(){returnS_OK;}
virtualHRESULTRestoreDeviceObjects(){returnS_OK;}
virtualHRESULTFrameMove(){returnS_OK;}

virtualHRESULTInvalidateDeviceObjects(){returnS_OK;}
virtualHRESULTDeleteDeviceObjects(){returnS_OK;}
virtualHRESULTFinalCleanup(){returnS_OK;}

public:
virtualHRESULTRender(){returnS_OK;}
//construct/destruct,createandpause/play
CXD3D();
virtual~CXD3D(){}
virtualHRESULTCreateD3D();
virtualvoidPause(boolbPause);
//activestatewrapper
boolIsActive(){returnm_bActive;};
//deviceandframestatisticswrappers
LPCTSTRGetDeviceStats(){returnm_strDeviceStats;}
LPCTSTRGetFrameStats()
{returnm_strFrameStats;}
}
;

CXD3D实现文件
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->
//-----------------------------------------------------------------------------
//XD3D.cpp:customDirect3D(CXD3D)Implementationfile
//-----------------------------------------------------------------------------

#include
"stdafx.h"
#include
"XD3D.h"

//-----------------------------------------------------------------------------
//CXD3DConstructor
//-----------------------------------------------------------------------------
CXD3D::CXD3D()
{
m_bActive
=false;

m_bStartFullscreen
=false;

m_bShowCursor
=true;
m_bClipCursor
=true;

m_bWindowed
=true;
m_bIgnoreSizeChange
=false;

m_bDeviceLost
=false;
m_bDeviceObjectsInited
=false;
m_bDeviceObjectsRestored
=false;

m_fTime
=0.0f;
m_fElapsedTime
=0.0f;
m_fFPS
=0.0f;

m_strDeviceStats[
0]=_T('/0');
m_strFrameStats[
0]=_T('/0');

m_hWndRender
=NULL;
m_hWndFocus
=NULL;

m_pd3d
=NULL;
m_pd3dDevice
=NULL;

m_dwCreateFlags
=0L;

Pause(
true);//untilwe'rereadytorender
}


//-----------------------------------------------------------------------------
//CreateD3D():providedm_hWndhasbeeninitialised,itinstantiatesthed3d
//object,choosesinitiald3dsettingsandinitializesthed3dstuff.
//-----------------------------------------------------------------------------
HRESULTCXD3D::CreateD3D()
{
HRESULThr;

//checkforawindowtorenderto
if(m_hWndRender==NULL)//待绘制的窗口为空
returnDisplayErrorMsg(D3DAPPERR_NOWINDOW,MSGERR_CANNOTCONTINUE);

//instantiateaD3DObject
if((m_pd3d=Direct3DCreate9(D3D_SDK_VERSION))==NULL)
returnDisplayErrorMsg(D3DAPPERR_NODIRECT3D,MSGERR_CANNOTCONTINUE);

//buildalistofD3Dadapters,modesanddevices
if(FAILED(hr=Enumeration.Enumerate(m_pd3d)))
{
SAFE_RELEASE(m_pd3d);

returnDisplayErrorMsg(hr,MSGERR_CANNOTCONTINUE);
}


//usethedevicewindowasthefocuswindow,unlessotherwisespecified
if(m_hWndFocus==NULL)m_hWndFocus=m_hWndRender;

//savesomewindowpropertiesintoclassmembers
m_dwWindowStyle=GetWindowLong(m_hWndRender,GWL_STYLE);

GetWindowRect(m_hWndRender,
&m_rcWindow);
GetClientRect(m_hWndRender,
&m_rcClient);

//choosethebestsettingstorender
if(FAILED(hr=ChooseInitialSettings()))
{
SAFE_RELEASE(m_pd3d);

returnDisplayErrorMsg(hr,MSGERR_CANNOTCONTINUE);
}


//initializethetimer
DXUtil_Timer(TIMER_START);

//initializetheapp'scustom(pre-devicecreation)stuff
if(FAILED(hr=OneTimeSceneInit()))
{
SAFE_RELEASE(m_pd3d);

returnDisplayErrorMsg(hr,MSGERR_CANNOTCONTINUE);
}


//initializethe3Denvironment,creatingthedevice
if(FAILED(hr=InitializeEnvironment()))
{
SAFE_RELEASE(m_pd3d);

returnDisplayErrorMsg(hr,MSGERR_CANNOTCONTINUE);
}


//D3Disreadytogosounpauseit
Pause(false);

returnS_OK;
}


//-----------------------------------------------------------------------------
//FindBestFullscreenMode():Adjustsettingswiththebestavailablefullscreen
//mode,subjecttotheHALandREFconstraints;returnsfalseifnosuchmode
//canbefound.
//-----------------------------------------------------------------------------
boolCXD3D::FindBestFullscreenMode(boolbHAL,boolbREF)
{
//forfullscreen,defaulttothefirstHALdevicecombothatsupportsthe
//currentdesktopdisplaymode,toanydisplaymodeifHALisincompatible
//withthedesktopmode,ortoanon-HALifnoHALisavailable
D3DDISPLAYMODEdmDesktop;
D3DDISPLAYMODEdmDesktopBest;
D3DDISPLAYMODEdmBest;

//fortunatelyforus,D3DFMT_UNKNOWN==0
ZeroMemory(&dmDesktopBest,sizeof(D3DDISPLAYMODE));
ZeroMemory(
&dmBest,sizeof(D3DDISPLAYMODE));

//'best'storage
AdapterInfo*paiBest=NULL;
DeviceInfo
*pdiBest=NULL;
DeviceCombo
*pdcBest=NULL;

//iterators
AdapterInfo*pai;
DeviceInfo
*pdi;
DeviceCombo
*pdc;

//successflags
boolbBetter,bBest;

UINTi,j,k;

//traversetheadpaterinfos
for(i=0;i<Enumeration.AdapterInfos.Length();i++)
{
pai
=&Enumeration.AdapterInfos[i];

//getthecurrentdisplaymodeofeachadapter
m_pd3d->GetAdapterDisplayMode(pai->AdapterOrdinal,&dmDesktop);

//traversedeviceinfosoneachadapterinfo
for(j=0;j<pai->DeviceInfos.Length();j++)
{
pdi
=&pai->DeviceInfos[j];

//skipdeviceswithotherthantherequestedtype
if(bHAL&&pdi->DevType!=D3DDEVTYPE_HAL)
continue;

if(bREF&&pdi->DevType!=D3DDEVTYPE_REF)
continue;

//traversedevicecombosforeachdeviceinfo
for(k=0;k<pdi->DeviceCombos.Length();k++)
{
pdc
=&pdi->DeviceCombos[k];

//skipthewindowedcombos
if(pdc->Windowed)
continue;

//thisdevicecombois'better'thanthecurrentbestif:
//(a)there'snobestyet;
//(b)it'saHALandthecurrentbestisnot;
//(c)it'saHALmatchingthedesktop'sformat,whilethe
//currentbestdoesnot;
//(d)it'saHALandboththedisplayandbackbufferformats
//matchthedesktop's,inwhichcaseitisalsothebest

bBetter
=pdcBest==NULL||

pdc
->DevType==D3DDEVTYPE_HAL&&
pdcBest
->DevType!=D3DDEVTYPE_HAL||

pdc
->DevType==D3DDEVTYPE_HAL&&
pdc
->DisplayFormat==dmDesktop.Format&&
pdcBest
->DisplayFormat!=dmDesktop.Format;

bBest
=pdc->DevType==D3DDEVTYPE_HAL&&
pdc
->DisplayFormat==dmDesktop.Format&&
pdc
->BackBufferFormat==dmDesktop.Format;

bBetter
|=bBest;

if(bBetter)
{
//makeitthebestsofar
dmDesktopBest=dmDesktop;
paiBest
=pai;
pdiBest
=pdi;
pdcBest
=pdc;

//thisonelooksgreat--takeit
if(bBest)
gotoDoneSearchingFDC;
}

}

}

}


DoneSearchingFDC:

//nosuitabledcfound!
if(pdcBest==NULL)
returnfalse;

//nowweneedtofindadisplaymodeonthebestaithatusesthebest
//dc'sdisplayformatandisasclosetothebestdesktopdisplaymode
//aspossible
D3DDISPLAYMODEdm;

for(i=0;i<paiBest->DisplayModes.Length();i++)
{
dm
=paiBest->DisplayModes[i];

//formatsmustmatch
if(dm.Format!=dmDesktopBest.Format)
continue;

//compareotherproperties
if(dm.Width==dmDesktopBest.Width&&
dm.Height
==dmDesktopBest.Height&&
dm.RefreshRate
==dmDesktopBest.RefreshRate)
{
//perfectmatch,breakout
dmBest=dm;
break;
}

elseif(dm.Width==dmDesktopBest.Width&&
dm.Height
==dmDesktopBest.Height&&
dm.RefreshRate
>dmBest.RefreshRate)
{
//faster
dmBest=dm;
}

elseif(dm.Width==dmDesktopBest.Width)
{
//samewidth
dmBest=dm;
}

elseif(dmBest.Width==0)
{
//wedon'thaveanythingbetteryet
dmBest=dm;
}

}


//savethesesettings
Settings.Windowed=0;
Settings.AdapterInfos[
0]=paiBest;

//indextothebestdmwithintheai
Settings.ndm[0]=paiBest->DisplayModes.Find(dm);

//indicestothebestdianddc
if(bBest)
{
Settings.ndi[
0]=j;
Settings.ndc[
0]=k;
}

else
{
//retracttothe'better'dianddc
Settings.ndi[0]=(UINT)paiBest->DeviceInfos.Find(*pdiBest);
Settings.ndc[
0]=(UINT)pdiBest->DeviceCombos.Find(*pdcBest);
}


returntrue;
}


//-----------------------------------------------------------------------------
//FindBestWindowedMode():adjustssettingswithbestavailablewindowedmode,
//subjecttotheHALandREFconstraints;returnsfalseifnosuchmodecanbe
//found.
//-----------------------------------------------------------------------------
boolCXD3D::FindBestWindowedMode(boolbHAL,boolbREF)
{
//getthedisplaymodeoftheprimaryadapter,whichisassumedtobe
//wherethewindowwillappear
D3DDISPLAYMODEdm;

m_pd3d
->GetAdapterDisplayMode(0,&dm);

//'best'storage
AdapterInfo*paiBest=NULL;
DeviceInfo
*pdiBest=NULL;
DeviceCombo
*pdcBest=NULL;

//iterators
AdapterInfo*pai;
DeviceInfo
*pdi;
DeviceCombo
*pdc;

//successflags
boolbBetter,bBest;

UINTi,j,k;

//traversetheenumeratedadaptersinformation
for(i=0;i<Enumeration.AdapterInfos.Length();i++)
{
pai
=&Enumeration.AdapterInfos[i];

//foreachadapter,traversethedeviceinfos
for(j=0;j<pai->DeviceInfos.Length();j++)
{
pdi
=&pai->DeviceInfos[j];

//skipaccordingtotherequirements
if(bHAL&&pdi->DevType!=D3DDEVTYPE_HAL)
continue;

if(bREF&&pdi->DevType!=D3DDEVTYPE_REF)
continue;

//traversedevicecombosforthisdevice
for(k=0;k<pdi->DeviceCombos.Length();k++)
{
pdc
=&pdi->DeviceCombos[k];

//skipthenon-windowedordistinctformatcombos
if(!pdc->Windowed)
continue;

if(pdc->DisplayFormat!=dm.Format)
continue;

//thisdevicecomboisbetterthanthecurrentbestif:
//(a)there'snobestyet;
//(b)it'saHALandthecurrentbestisnot;
//(c)it'saHALwithmatchingbackbufferanddisplay
//formats,inwhichcaseisalsothebest
bBetter=pdcBest==NULL||

pdc
->DevType==D3DDEVTYPE_HAL&&
pdcBest
->DevType!=D3DDEVTYPE_HAL;

bBest
=pdc->DevType==D3DDEVTYPE_HAL&&
pdc
->BackBufferFormat==pdc->DisplayFormat;

bBetter
|=bBest;

if(bBetter)
{
//saveitasthecurrentbest
paiBest=pai;
pdiBest
=pdi;
pdcBest
=pdc;

//thisdclooksgreat--takeit
if(bBest)
gotoDoneSearchingWDC;
}

}

}

}


DoneSearchingWDC:

//nonefound!!
if(pdcBest==NULL)
returnfalse;

Settings.Windowed
=1;
Settings.AdapterInfos[
1]=paiBest;

intl=paiBest->DisplayModes.Find(dm);

//forsomebizarremulti-monitorsetupsinwhichtheprimaryadapter's
//currentdmisnotavailableinasecondaryone,there'snothingelse
//wecando
if(i>0&&l==-1)
returnfalse;

//indextothebestdmwithintheai
Settings.ndm[1]=l;

//indicestothebestdianddc
if(bBest)
{
Settings.ndi[
1]=j;
Settings.ndc[
1]=k;
}

else
{
//retracttothe'better'dianddc
Settings.ndi[1]=(UINT)paiBest->DeviceInfos.Find(*pdiBest);
Settings.ndc[
1]=(UINT)pdiBest->DeviceCombos.Find(*pdcBest);
}


returntrue;
}


//-----------------------------------------------------------------------------
//ChooseInitialSettings():accordingtothebestmodefoundsandappsettings
//-----------------------------------------------------------------------------
HRESULTCXD3D::ChooseInitialSettings()
{
boolbFoundFullscreen=FindBestFullscreenMode(false,false);
boolbFoundWindowed=FindBestWindowedMode(false,false);

if(m_bStartFullscreen&&bFoundFullscreen)
Settings.Windowed
=0;

if(!bFoundWindowed&&bFoundFullscreen)
Settings.Windowed
=0;

if(!bFoundFullscreen&&!bFoundWindowed)
returnD3DAPPERR_NOCOMPATIBLEDEVICES;

if(!m_bStartFullscreen&&!bFoundWindowed)
returnD3DAPPERR_NOCOMPATIBLEDEVICES;

returnS_OK;
}


//-----------------------------------------------------------------------------
//HandlePossibleSizeChange():resetthedeviceiftheclientareasizehas
//changed;itwillupdatethewindowproperties,butitwillnotissueareset
//unlessoldandnewdimensionsdiffer;anewwindowsizewillrequireanew
//backbuffersize,sothe3Denvironmentmustchangeaccordingly.
//-----------------------------------------------------------------------------
HRESULTCXD3D::HandlePossibleSizeChange()
{
if(m_bIgnoreSizeChange)
returnS_OK;

HRESULThr
=S_OK;

RECTrcOld
=m_rcClient;

GetClientRect(m_hWndRender,
&m_rcClient);

//checkforclientrectchanges
if(rcOld.right-rcOld.left!=m_rcClient.right-m_rcClient.left||
rcOld.bottom
-rcOld.top!=m_rcClient.bottom-m_rcClient.top)
{
Pause(
true);

//storethenewdims
m_d3dpp.BackBufferWidth=m_rcClient.right-m_rcClient.left;
m_d3dpp.BackBufferHeight
=m_rcClient.bottom-m_rcClient.top;

//reset
if(m_pd3dDevice!=NULL)
{
if(FAILED(hr=ResetEnvironment()))
{
if(hr!=D3DERR_OUTOFVIDEOMEMORY)
hr
=D3DAPPERR_RESETFAILED;

DisplayErrorMsg(hr,MSGERR_CANNOTCONTINUE);
}

}


Pause(
false);
}


returnhr;
}


//-----------------------------------------------------------------------------
//BuildPresentParamsFromSettings():'builds'presentationparametersfrom
//thecurrentsettings
//-----------------------------------------------------------------------------
voidCXD3D::BuildPresentParamsFromSettings()
{
m_d3dpp.Windowed
=Settings.Windowed;
m_d3dpp.hDeviceWindow
=m_hWndRender;
m_d3dpp.BackBufferCount
=1;
m_d3dpp.EnableAutoDepthStencil
=Enumeration.AppUsesDepthBuffer;
m_d3dpp.MultiSampleType
=Settings.GetMSType();
m_d3dpp.MultiSampleQuality
=Settings.GetMSQuality();
m_d3dpp.SwapEffect
=D3DSWAPEFFECT_DISCARD;
m_d3dpp.Flags
=0;

if(Enumeration.AppUsesDepthBuffer)
{
m_d3dpp.Flags
=D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL;
m_d3dpp.AutoDepthStencilFormat
=Settings.GetDSFormat();
}


if(m_bWindowed)
{
m_d3dpp.BackBufferWidth
=m_rcClient.right-m_rcClient.left;
m_d3dpp.BackBufferHeight
=m_rcClient.bottom-m_rcClient.top;
m_d3dpp.FullScreen_RefreshRateInHz
=0;
}

else
{
m_d3dpp.BackBufferWidth
=Settings.GetDisplayMode().Width;
m_d3dpp.BackBufferHeight
=Settings.GetDisplayMode().Height;
m_d3dpp.FullScreen_RefreshRateInHz
=Settings.GetDisplayMode().RefreshRate;
}


m_d3dpp.BackBufferFormat
=Settings.GetBackBufferFormat();
m_d3dpp.PresentationInterval
=Settings.GetPresentInterval();
}


//-----------------------------------------------------------------------------
//InitializeEnvironment():checksforanullREFdevice,buildspresentation
//parametersfromsettings,instancesthed3ddevice,setsupdevicestats,
//savesthebackbufferdescription,setsupthefullscreencursorandfinally
//initsandrestoresdeviceobjects.Ifthelaststepfails,itretries,but
//inwindowedmode(todisplayawarning)andthereferencerasterizer.
//-----------------------------------------------------------------------------
HRESULTCXD3D::InitializeEnvironment()
{
HRESULThr;

AdapterInfo
*pai=Settings.GetAdapterInfo();
DeviceInfo
*pdi=Settings.GetDeviceInfo();

//WarnuseraboutanullREFdevicethatcannotrenderanything
if(pdi->Caps.PrimitiveMiscCaps&D3DPMISCCAPS_NULLREFERENCE)
DisplayErrorMsg(D3DAPPERR_NULLREFDEVICE,
0);

//translatetheVPtypetoadevicecreationbehavior
switch(Settings.GetVPType())
{
casePURE_VP:m_dwCreateFlags=D3DCREATE_PUREDEVICE;
caseHARD_VP:m_dwCreateFlags|=D3DCREATE_HARDWARE_VERTEXPROCESSING;break;
caseMIXD_VP:m_dwCreateFlags=D3DCREATE_MIXED_VERTEXPROCESSING;break;
caseSOFT_VP:m_dwCreateFlags=D3DCREATE_SOFTWARE_VERTEXPROCESSING;break;
default:returnE_FAIL;
}


//setupthecreationpresentationparameters
BuildPresentParamsFromSettings();

//createthedevice
hr=m_pd3d->CreateDevice(pdi->AdapterOrdinal,
pdi
->DevType,
m_hWndRender,
m_dwCreateFlags,
&m_d3dpp,
&m_pd3dDevice);

if(SUCCEEDED(hr))
{
//storethedevice'sdescription,beginningwithtype;
lstrcpy(m_strDeviceStats,DEVICETYPESTRING(pdi->DevType,false));

//thenVPtype,includingnon-HALdevicessimulatinghardwareVPand
//thepurehardwareVPvariant
if((m_dwCreateFlags&D3DCREATE_SOFTWARE_VERTEXPROCESSING)==0&&
pdi
->DevType!=D3DDEVTYPE_HAL)
lstrcat(m_strDeviceStats,TEXT(
"simulated"));

if(m_dwCreateFlags&D3DCREATE_HARDWARE_VERTEXPROCESSING)
{
if(m_dwCreateFlags&D3DCREATE_PUREDEVICE)
lstrcat(m_strDeviceStats,TEXT(
"pure"));

lstrcat(m_strDeviceStats,TEXT(
"hardware"));
}

elseif(m_dwCreateFlags&D3DCREATE_MIXED_VERTEXPROCESSING)
lstrcat(m_strDeviceStats,TEXT(
"mixed"));
else
lstrcat(m_strDeviceStats,TEXT(
"software"));

lstrcat(m_strDeviceStats,TEXT(
"VP"));

//andtheadapter'sdescriptionforHALdevices
if(pdi->DevType==D3DDEVTYPE_HAL)
{
lstrcat(m_strDeviceStats,TEXT(
"on"));

//besurenottooverflowm_strDeviceStatswhenappending
constintnDescription=sizeof(pai->AdapterIdentifier.Description);

TCHARszDescription[nDescription];

//DXUtilshandleunicodesomewhatgracefully
DXUtil_ConvertAnsiStringToGenericCch(szDescription,
pai
->AdapterIdentifier.Description,
nDescription);

lstrcat(szDescription,TEXT(
"@"));

//appendasmanycharactersasspaceisleftonthestats
_tcsncat(m_strDeviceStats,
szDescription,
UBOUND(m_strDeviceStats)
-lstrlen(m_strDeviceStats)-1);

TCHARszDims[
100];
TCHARszFmt[
100];
TCHARszDepthFmt[
100];
TCHAR
*szMS;

_sntprintf(szDims,
100,TEXT("%dx%d,"),
m_d3dpp.BackBufferWidth,
m_d3dpp.BackBufferHeight);

szDims[
99]=TEXT('/0');

//appendasmanycharactersasspaceisleftonthestats
_tcsncat(m_strDeviceStats,szDims,
UBOUND(m_strDeviceStats)
-lstrlen(m_strDeviceStats)-1);

D3DFORMATfmt
=Settings.GetDisplayMode().Format;

//displayformat(includingthebackbufferformatiftheydonotmatch)
if(fmt==m_d3dpp.BackBufferFormat)
lstrcpyn(szFmt,D3DUtil_D3DFormatToString(fmt,
false),100);
else
_sntprintf(szFmt,
100,TEXT("%sback,%sfront"),
D3DUtil_D3DFormatToString(m_d3dpp.BackBufferFormat,
false),
D3DUtil_D3DFormatToString(fmt,
false));

szFmt[
99]=TEXT('/0');

//appendasmanycharactersasspaceisleftonthestats
_tcsncat(m_strDeviceStats,
szFmt,
UBOUND(m_strDeviceStats)
-lstrlen(m_strDeviceStats)-1);

//depth/stencilbufferformat
if(Enumeration.AppUsesDepthBuffer)
{
_sntprintf(szDepthFmt,
100,TEXT("(%s)"),
D3DUtil_D3DFormatToString(Settings.GetDSFormat(),
false));

szDepthFmt[
99]=TEXT('/0');

//appendasmanycharactersasspaceisleftonthestats
_tcsncat(m_strDeviceStats,
szDepthFmt,
UBOUND(m_strDeviceStats)
-lstrlen(m_strDeviceStats)-1);
}


//multisamplingtype(no.ofsamplesornonmaskable)
szMS=MULTISAMPLESTRING(Settings.GetMSType(),false);

//appendasmanycharactersasspaceisleftonthestats
_tcsncat(m_strDeviceStats,
szMS,
UBOUND(m_strDeviceStats)
-lstrlen(m_strDeviceStats)-1);
}


//setupthefullscreencursor
if(m_bShowCursor&&!m_bWindowed)
{
HCURSORhCursor
=(HCURSOR)GetClassLong(m_hWndRender,GCL_HCURSOR);

D3DUtil_SetDeviceCursor(m_pd3dDevice,hCursor,
true);
m_pd3dDevice
->ShowCursor(true);
}


//confinethecursortothefullscreenwindow
if(m_bClipCursor)
ClipCursor(m_bWindowed
?NULL:&m_rcWindow);

//initializetheapp'sdevice-dependantobjects
if(FAILED(hr=InitDeviceObjects()))
DeleteDeviceObjects();
else
{
m_bDeviceObjectsInited
=true;

//restoretheapp'sdevice-dependantobjects
if(FAILED(hr=RestoreDeviceObjects()))
InvalidateDeviceObjects();
else
{
m_bDeviceObjectsRestored
=true;
returnS_OK;
}

}


//ifanyofthatfailed,cleanupbeforewetryagain
CleanupEnvironment();
}


//iffailurecomesstrictlyfromIDirect3D9we'lltryfallingbackto
//thereferencerasterizer;inotherwords,we'llignoretheerrorif
//itisa'filenotfound'error,becauseitisnotDirect3D'sfault,
//it'stheprogrammer's(oruser's)fault!
if(hr!=D3DAPPERR_MEDIANOTFOUND&&
hr
!=HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)&&
pdi
->DevType==D3DDEVTYPE_HAL)
{
//requestareferencedevice
if(FindBestWindowedMode(false,true))
{
//mainwindowmustnotbetopmosttoshowanerrormessage
SetWindowPos(m_hWndRender,
HWND_NOTOPMOST,
m_rcWindow.left,
m_rcWindow.top,
(m_rcWindow.right
-m_rcWindow.left),
(m_rcWindow.bottom
-m_rcWindow.top),
SWP_SHOWWINDOW);

//inwhichwelettheuserknowweareswitching
DisplayErrorMsg(hr,MSGWARN_SWITCHEDTOREF);

//tryagain
hr=InitializeEnvironment();
}

}


returnhr;
}


//-----------------------------------------------------------------------------
//ResetEnvironment():signalstheappitmustinvalidateallvideomemory
//objectsandrenderthecurrentframeifpaused,thenresetsthedevice.The
//backbufferdescriptionissaved.
//-----------------------------------------------------------------------------
HRESULTCXD3D::ResetEnvironment()
{
HRESULThr;

//invalidateanyresourcesthattcannotsurvivethereset
if(m_bDeviceObjectsRestored)
{
m_bDeviceObjectsRestored
=false;
InvalidateDeviceObjects();
}


if(FAILED(hr=m_pd3dDevice->Reset(&m_d3dpp)))
returnhr;

//restore(re-create)resources
if(FAILED(hr=RestoreDeviceObjects()))
{
InvalidateDeviceObjects();
returnhr;
}

m_bDeviceObjectsRestored
=true;
returnS_OK;
}


//-----------------------------------------------------------------------------
//RenderEnvironment():testsforcooplevel,possiblyresetstheenvironment
//andissuestheappdefinedFrameMoveandRenderthatwillactuallydrawthe
//scene.
//-----------------------------------------------------------------------------
HRESULTCXD3D::RenderEnvironment()
{
HRESULThr;
if(m_bDeviceLost)
{
//testthecooperativeleveltoseeifit'sokaytorender
if(FAILED(hr=m_pd3dDevice->TestCooperativeLevel()))
{
//ifthedevicewastrulylost,(i.e.,afullscreendevicejust
//lostfocus),waituntilwegetitback
if(hr==D3DERR_DEVICELOST)
returnS_OK;
//eventually,wewillgetthisreturnvalue,indicating
//thatwecanresetthedevice
if(hr==D3DERR_DEVICENOTRESET)
{
//ifwearewindowed,readthedesktopmodeandusethesame
//formatforthebackbufferUNTESTEDWITHTHENEWSETTINGSCLASS!!!
if(m_bWindowed)
{
m_pd3d
->GetAdapterDisplayMode(Settings.GetAdapterInfo()->AdapterOrdinal,
&Settings.GetDisplayMode());

m_d3dpp.BackBufferFormat
=Settings.GetDisplayMode().Format;
}

//beforeresettingthedevice
if(FAILED(hr=ResetEnvironment()))
returnhr;
}

returnhr;
}

//wehaveadevice
m_bDeviceLost=false;
}

//setuptheapp'stimers
FLOATfTime=DXUtil_Timer(TIMER_GETAPPTIME);
FLOATfElapsedTime
=DXUtil_Timer(TIMER_GETELAPSEDTIME);
//skiprenderingifnotimeelapsed(theapplicationispaused)
if(fElapsedTime==0.0f)
returnS_OK;
//storethetime
m_fTime=fTime;
m_fElapsedTime
=fElapsedTime;
//movethescene
if(FAILED(hr=FrameMove()))
returnhr;
//renderthesceneasnormal
if(FAILED(hr=Render()))
returnhr;
//updatetheFPS
UpdateStats();
//presentthenextbufferintheswapchain
if(m_pd3dDevice->Present(NULL,NULL,NULL,NULL)==D3DERR_DEVICELOST)
m_bDeviceLost
=true;
returnS_OK;
}


//-----------------------------------------------------------------------------
//CleanupEnvironment():cleanupdeviceobjects
//-----------------------------------------------------------------------------
voidCXD3D::CleanupEnvironment()
{
if(m_pd3dDevice!=NULL)
{
if(m_bDeviceObjectsRestored)
{
m_bDeviceObjectsRestored
=false;
InvalidateDeviceObjects();
}

if(m_bDeviceObjectsInited)
{
m_bDeviceObjectsInited
=false;
DeleteDeviceObjects();
}

if(m_pd3dDevice->Release()>0)
DisplayErrorMsg(D3DAPPERR_NONZEROREFCOUNT,MSGERR_CANNOTCONTINUE);
m_pd3dDevice
=NULL;
}

}


//-----------------------------------------------------------------------------
//UpdateStats()
//-----------------------------------------------------------------------------
voidCXD3D::UpdateStats()
{
//keeptrackoftheframecount
staticfloatfLastTime=0.0f;
staticDWORDdwFrames=0;
floatfTime=DXUtil_Timer(TIMER_GETABSOLUTETIME);
++dwFrames;
//letafullsecondelapsebeforeupdatingthescenestats
if(fTime-fLastTime<=1.0f)
return;
m_fFPS
=dwFrames/(fTime-fLastTime);
fLastTime
=fTime;
dwFrames
=0;
constintnMax=UBOUND(m_strFrameStats);
_sntprintf(m_strFrameStats,nMax,_T(
"%.02ffps"),m_fFPS);
m_strFrameStats[nMax
-1]=TEXT('/0');
}


//-----------------------------------------------------------------------------
//Pause():togglestheactivestateoftheappandresetsthetimer
//-----------------------------------------------------------------------------
voidCXD3D::Pause(boolbPause)
{
staticDWORDdwAppPausedCount=0;
dwAppPausedCount
+=BSCALE(bPause);
m_bActive
=dwAppPausedCount==0;

//handlethefirstpauserequest(ofmany,nestablepauserequests)and
//stopthescenefromanimating
if(bPause&&dwAppPausedCount==1)
DXUtil_Timer(TIMER_STOP);
//restartthetimer
if(dwAppPausedCount==0)
DXUtil_Timer(TIMER_START);
}


//-----------------------------------------------------------------------------
//Name:DisplayErrorMsg()
//-----------------------------------------------------------------------------
HRESULTCXD3D::DisplayErrorMsg(HRESULThr,DWORDdwType)
{
staticbools_bFatalErrorReported=false;
TCHARstrMsg[
512];
//Ifafatalerrormessagehasalreadybeenreported,theapp
//isalreadyshuttingdown,sodon'tshowmoreerrormessages.
if(s_bFatalErrorReported)
returnhr;
switch(hr)
{
caseD3DAPPERR_NODIRECT3D:
_tcscpy(strMsg,
_T(
"CouldnotinitializeDirect3D;checkthatthe/n")
_T(
"latestversionofDirectXiscorrectlyinstalled/n")
_T(
"onyoursystem."));
break;
caseD3DAPPERR_NOCOMPATIBLEDEVICES:
_tcscpy(strMsg,
_T(
"CouldnotfindanycompatibleDirect3Ddevices."));
break;
caseD3DAPPERR_NOWINDOWABLEDEVICES:
_tcscpy(strMsg,
_T(
"Cannotruninadesktopwindowwiththecurrent/n")
_T(
"displaysettings;changeyourdesktopsettings/n")
_T(
"toa16-or32-bitdisplaymodeandretry."));
break;
caseD3DAPPERR_NOHARDWAREDEVICE:
_tcscpy(strMsg,
_T(
"Nohardware-acceleratedDirect3Ddevicesfound."));
break;
caseD3DAPPERR_HALNOTCOMPATIBLE:
_tcscpy(strMsg,
_T(
"Thisapplicationrequiresfunctionalitynot/n")
_T(
"availableonyourDirect3Dhardwareaccelerator."));
break;
caseD3DAPPERR_NOWINDOW:
_tcscpy(strMsg,
_T(
"Nowindowtorendertowassupplied./n"));
break;
caseD3DAPPERR_NOWINDOWEDHAL:
_tcscpy(strMsg,
_T(
"YourDirect3Dhardwareacceleratorcannotrender/n")
_T(
"intoawindow./n"));
break;
caseD3DAPPERR_NODESKTOPHAL:
_tcscpy(strMsg,
_T(
"YourDirect3Dhardwareacceleratorcannotrender/n")
_T(
"intoawindowwiththecurrentdesktopdisplay/n")
_T(
"settings."));
break;
caseD3DAPPERR_NOHALTHISMODE:
_tcscpy(strMsg,
_T(
"Thisapplicationrequiresfunctionalitythatis/n")
_T(
"notavailableonyourDirect3Dhardwareaccelerator/n")
_T(
"withthecurrentdesktopdisplaysettings./n"));
break;
caseD3DAPPERR_MEDIANOTFOUND:
caseHRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND):
_tcscpy(strMsg,_T(
"Couldnotloadrequiredmedia."));
break;
caseD3DAPPERR_RESETFAILED:
_tcscpy(strMsg,_T(
"CouldnotresettheDirect3Ddevice."));
break;
caseD3DAPPERR_INITFAILED:
_tcscpy(strMsg,_T(
"CouldnotinitializetheDirect3Ddevice."));
break;
caseD3DAPPERR_NONZEROREFCOUNT:
_tcscpy(strMsg,
_T(
"AD3Dobjecthasanon-zeroreferencecount/n")
_T(
"(meaningthingswerenotproperlycleanedup)."));
break;
caseD3DAPPERR_NULLREFDEVICE:
_tcscpy(strMsg,
_T(
"Warning:Nothingwillberendered./n")
_T(
"Thereferencerenderingdevicewasselected,but/n")
_T(
"yourcomputeronlyhasareduced-functionality/n")
_T(
"referencedeviceinstalled.InstalltheDirectX/n")
_T(
"SDKtogetthefullreferencedevice./n"));
break;
caseE_OUTOFMEMORY:
_tcscpy(strMsg,_T(
"Notenoughmemory."));
break;
caseD3DERR_OUTOFVIDEOMEMORY:
_tcscpy(strMsg,_T(
"Notenoughvideomemory."));
break;
default:
_tcscpy(strMsg,_T(
"UnknownDirect3Derror."));
}

if(dwType==MSGWARN_SWITCHEDTOREF)
{
_tcscat(strMsg,
_T(
"/n/nSwitchingtothereferencerasterizer,a/n")
_T(
"softwaredevicethatimplementstheentire/n")
_T(
"Direct3Dfeatureset,butrunsveryslowly."));
}

if(dwType==MSGERR_CANNOTCONTINUE)
{
s_bFatalErrorReported
=true;

_tcscat(strMsg,_T(
"/n/nDirect3Dcannotcontinue."));

}

MessageBox(NULL,strMsg,
"Direct3D",MB_ICONWARNING|MB_OK);
//closethewindow
if(s_bFatalErrorReported&&m_hWndRender)SendMessage(m_hWndRender,WM_CLOSE,0,0);
returnhr;
}

CXD3D::CreateD3D函数中,首先初始化了一个D3D对象,然后构建了一个列表,这个列表包含了机器上的所有显卡,显卡模式和设备。我们需要知道机器上有多少显卡(一般只有一个),而且每个显卡也可以支持多个设备。对于每个设备会有一种支持的格式,设置和能力,这对于应用程序来说不一定是合适的,因此我们需要一个列表来跟踪这些信息,以便挑选出合适的。

再来看枚举类CXD3DEnum,它用来为应用程序中使用的分辨率,颜色,A通道,显示格式,后备缓冲格式,深度/模板缓冲格式,多重采样类型,提交显示时间间隔等参数建立约束。

文中枚举类的代码很多,但我们只需要记住一点就可以了,要使Direct3D建立起来,我们首先得不断地枚举,枚举,再枚举,不断检查它的各种属性,各种能力是否满足,基本上检查的顺序可以用下图来表示:

Enumeration
|
+ --AdapterInfos[ 0 ]
||
|
+ --DisplayModes[ 0 ]
|
+ --DisplayModes[ 1 ]
|

||
|
+ --DeviceInfos[ 0 ]
|||
||
+ --DeviceCombos[ 0 ]
||||
|||
+ --VPTypes
|||
+ --DSFormats
|||
+ --MSTypes
|||
+ --MSQualityLevels
|||
+ --DSMSConflicts
|||
+ --PresentIntervals
||
+ --DeviceCombos[ 1 ]
||

|
+ --DeviceInfos[ 1 ]
|

+ --AdapterInfos[ 1 ]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值