原文链接:
MFC D3D Application: Direct3D Tutorial Part I
作者这个 MFC 程序中第一个有趣的地方是让用于 Direct3D 绘制的窗口类从 CWnd 类和 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;
}
Enumeration
|
+
--AdapterInfos[
0
]
||
|
+
--DisplayModes[
0
]
|
+
--DisplayModes[
1
]
|
||
|
+
--DeviceInfos[
0
]
|||
||
+
--DeviceCombos[
0
]
||||
|||
+
--VPTypes
|||
+
--DSFormats
|||
+
--MSTypes
|||
+
--MSQualityLevels
|||
+
--DSMSConflicts
|||
+
--PresentIntervals
||
+
--DeviceCombos[
1
]
||
|
+
--DeviceInfos[
1
]
|
+
--AdapterInfos[
1
]
作者这个 MFC 程序中第一个有趣的地方是让用于 Direct3D 绘制的窗口类从 CWnd 类和 CXD3D 类继承下来:
class CD3DWnd : public CXD3D, public CWnd
CD3DWnd类是用于窗口中控件(比如一个PictureBox)的基类,这个控件将提供普通Cwnd类的功能,但同时也拥有CXD3D的3D绘制的能力。
先来看CXD3D类:











































































































<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->


























































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































在CXD3D::CreateD3D函数中,首先初始化了一个D3D对象,然后构建了一个列表,这个列表包含了机器上的所有显卡,显卡模式和设备。我们需要知道机器上有多少显卡(一般只有一个),而且每个显卡也可以支持多个设备。对于每个设备会有一种支持的格式,设置和能力,这对于应用程序来说不一定是合适的,因此我们需要一个列表来跟踪这些信息,以便挑选出合适的。
再来看枚举类CXD3DEnum,它用来为应用程序中使用的分辨率,颜色,A通道,显示格式,后备缓冲格式,深度/模板缓冲格式,多重采样类型,提交显示时间间隔等参数建立约束。
文中枚举类的代码很多,但我们只需要记住一点就可以了,要使Direct3D建立起来,我们首先得不断地枚举,枚举,再枚举,不断检查它的各种属性,各种能力是否满足,基本上检查的顺序可以用下图来表示:


























