DirectX Box
通过该Demo,可以清楚了解DirectX流程。将完整程序贴出,自己加以注释,方面查看理解。
1 /* 2 2015.4 3 d3dUtil.h 4 5 d3d 常用工具代码 6 */ 7 8 #ifndef D3DUTIL_H 9 #define D3DUTIL_H 10 11 // Let VC++ know we are compiling for WinXP and up. This let's us use 12 // API functions specific to WinXP (e.g., WM_INPUT API). 13 #ifndef _WIN32_WINNT 14 #define _WIN32_WINNT 0x0600 // Vista 15 #endif 16 17 // Enable extra D3D debugging in debug builds if using the debug DirectX runtime. 18 // This makes D3D objects work well in the debugger watch window, but slows down 19 // performance slightly. 20 #if defined(DEBUG) || defined(_DEBUG) 21 #ifndef D3D_DEBUG_INFO 22 #define D3D_DEBUG_INFO 23 #endif 24 #endif 25 26 #if defined(DEBUG) || defined(_DEBUG) 27 #define _CRTDBG_MAP_ALLOC 28 #include <crtdbg.h> 29 #endif 30 31 32 #include <d3dx10.h> 33 #include <dxerr.h> 34 #include <cassert> 35 36 // Simple d3d error checker. 37 #if defined(DEBUG) | defined(_DEBUG) 38 #ifndef HR 39 #define HR(x) \ 40 { \ 41 HRESULT hr = (x); \ 42 if (FAILED(hr)) \ 43 { \ 44 DXTrace(__FILE__, (DWORD)__LINE__, hr, L#x, true); \ 45 } \ 46 } \ 47 /*当DXTrace函数的最后一个参数设为false时,该函数不会显示消息框, 48 而是把调试信息输出到Visual C++的输出窗口*/ 49 #endif 50 51 #else 52 #ifndef HR 53 #define HR(x) (x) 54 #endif 55 #endif 56 57 // releasing COM objects 58 #define ReleaseCOM(x) { if(x){ x->Release();x = 0; } } 59 60 // 内联函数 61 // Converts ARGB 32-bit color format to ABGR 32-bit color format. 62 D3DX10INLINE UINT ARGB2ABGR(UINT argb) 63 { 64 BYTE A = (argb >> 24) & 0xff; 65 BYTE R = (argb >> 16) & 0xff; 66 BYTE G = (argb >> 8) & 0xff; 67 BYTE B = (argb >> 0) & 0xff; 68 69 return (A << 24) | (B << 16) | (G << 8) | (R << 0); 70 } 71 72 // Returns random float in [0, 1). 73 D3DX10INLINE float RandF() 74 { 75 return (float)(rand()) / (float)RAND_MAX; 76 } 77 // Returns random float in [a, b). 78 D3DX10INLINE float RandF(float a, float b) 79 { 80 return a + RandF()*(b - a); 81 } 82 83 // 获得单位球体向量 84 D3DX10INLINE D3DXVECTOR3 RandUnitVec3() 85 { 86 D3DXVECTOR3 v(RandF(), RandF(), RandF()); 87 D3DXVec3Normalize(&v, &v); 88 return v; 89 } 90 91 template<typename T> 92 D3DX10INLINE T Min(const T& a, const T& b) 93 { 94 return a < b ? a : b; 95 } 96 97 template<typename T> 98 D3DX10INLINE T Max(const T& a, const T& b) 99 { 100 return a > b ? a : b; 101 } 102 103 //线性插值,在不生成像素的情况下增加图像像素大小的一种方法 104 template<typename T> 105 D3DX10INLINE T Lerp(const T& a, const T& b, float t) 106 { 107 return a + (b - a)*t; 108 } 109 110 template<typename T> 111 D3DX10INLINE T Clamp(const T& x, const T& low, const T& high) 112 { 113 return x < low ? low : (x > high ? high : x); 114 } 115 116 const float PI = 3.14159265358979323f; 117 const float MATH_EPS = 0.0001f; 118 119 const D3DXCOLOR WHITE(1.0f, 1.0f, 1.0f, 1.0f); 120 const D3DXCOLOR BLACK(0.0f, 0.0f, 0.0f, 1.0f); 121 const D3DXCOLOR RED(1.0f, 0.0f, 0.0f, 1.0f); 122 const D3DXCOLOR GREEN(0.0f, 1.0f, 0.0f, 1.0f); 123 const D3DXCOLOR BLUE(0.0f, 0.0f, 1.0f, 1.0f); 124 const D3DXCOLOR YELLOW(1.0f, 1.0f, 0.0f, 1.0f); 125 const D3DXCOLOR CYAN(0.0f, 1.0f, 1.0f, 1.0f); 126 const D3DXCOLOR MAGENTA(1.0f, 0.0f, 1.0f, 1.0f); 127 128 const D3DXCOLOR BEACH_SAND(1.0f, 0.96f, 0.62f, 1.0f); 129 const D3DXCOLOR LIGHT_YELLOW_GREEN(0.48f, 0.77f, 0.46f, 1.0f); 130 const D3DXCOLOR DARK_YELLOW_GREEN(0.1f, 0.48f, 0.19f, 1.0f); 131 const D3DXCOLOR DARKBROWN(0.45f, 0.39f, 0.34f, 1.0f); 132 133 #endif
1 /* 2 2015.4 3 GameTimer.h 4 5 */ 6 7 #ifndef GAMETIMER_H 8 #define GAMETIMER_H 9 10 class GameTimer 11 { 12 public: 13 GameTimer(); 14 15 float getGameTime()const; // in seconds 16 17 // 获得增量 18 float getDeltaTime()const; // in seconds 19 20 void reset(); // Call before message loop. 21 void start(); // Call when unpaused. 22 void stop(); // Call when paused. 23 void tick(); // Call every frame. 24 25 private: 26 double mSecondsPerCount; 27 double mDeltaTime; 28 29 __int64 mBaseTime; 30 __int64 mPausedTime; 31 __int64 mStopTime; 32 __int64 mPrevTime; 33 __int64 mCurrTime; 34 35 bool mStopped; 36 }; 37 38 #endif
1 /* 2 2015.4 3 GameTimer.cpp 4 5 */ 6 #include "GameTimer.h" 7 #include <windows.h> 8 9 GameTimer::GameTimer() 10 : mSecondsPerCount(0.0), mDeltaTime(-1.0), mBaseTime(0), 11 mPausedTime(0), mPrevTime(0), mCurrTime(0), mStopped(false) 12 { 13 __int64 countsPerSec; 14 15 // 获取性能计时器的频率(每秒的计数次数) 16 QueryPerformanceFrequency((LARGE_INTEGER*)&countsPerSec); 17 mSecondsPerCount = 1.0 / (double)countsPerSec; 18 } 19 20 // Returns the total time elapsed since reset() was called, NOT counting any 21 // time when the clock is stopped. 22 float GameTimer::getGameTime()const 23 { 24 // If we are stopped, do not count the time that has passed since we stopped. 25 // 26 // ----*---------------*------------------------------*------> time 27 // mBaseTime mStopTime mCurrTime 28 29 if (mStopped) 30 { 31 return (float)((mStopTime - mBaseTime)*mSecondsPerCount); 32 } 33 34 // The distance mCurrTime - mBaseTime includes paused time, 35 // which we do not want to count. To correct this, we can subtract 36 // the paused time from mCurrTime: 37 // 38 // (mCurrTime - mPausedTime) - mBaseTime 39 // 40 // |<-------d------->| 41 // ----*---------------*-----------------*------------*------> time 42 // mBaseTime mStopTime startTime mCurrTime 43 44 else 45 { 46 return (float)(((mCurrTime - mPausedTime) - mBaseTime)*mSecondsPerCount); 47 } 48 } 49 50 float GameTimer::getDeltaTime()const 51 { 52 return (float)mDeltaTime; 53 } 54 55 void GameTimer::reset() 56 { 57 __int64 currTime; 58 QueryPerformanceCounter((LARGE_INTEGER*)&currTime); 59 60 mBaseTime = currTime; 61 mPrevTime = currTime; 62 mStopTime = 0; 63 mStopped = false; 64 } 65 66 void GameTimer::start() 67 { 68 __int64 startTime; 69 QueryPerformanceCounter((LARGE_INTEGER*)&startTime); 70 71 72 // Accumulate the time elapsed between stop and start pairs. 73 // 74 // |<-------d------->| 75 // ----*---------------*-----------------*------------> time 76 // mBaseTime mStopTime startTime 77 78 if (mStopped) 79 { 80 mPausedTime += (startTime - mStopTime); 81 82 mPrevTime = startTime; 83 mStopTime = 0; 84 mStopped = false; 85 } 86 } 87 88 void GameTimer::stop() 89 { 90 if (!mStopped) 91 { 92 __int64 currTime; 93 QueryPerformanceCounter((LARGE_INTEGER*)&currTime); 94 95 mStopTime = currTime; 96 mStopped = true; 97 } 98 } 99 100 void GameTimer::tick() 101 { 102 if (mStopped) 103 { 104 mDeltaTime = 0.0; 105 return; 106 } 107 108 __int64 currTime; 109 QueryPerformanceCounter((LARGE_INTEGER*)&currTime); 110 mCurrTime = currTime; 111 112 // Time difference between this frame and the previous. 113 mDeltaTime = (mCurrTime - mPrevTime)*mSecondsPerCount; 114 115 // Prepare for next frame. 116 mPrevTime = mCurrTime; 117 118 // Force nonnegative. The DXSDK's CDXUTTimer mentions that if the 119 // processor goes into a power save mode or we get shuffled to another 120 // processor, then mDeltaTime can be negative. 121 if (mDeltaTime < 0.0) 122 { 123 mDeltaTime = 0.0; 124 } 125 }
1 /* 2 2015.4 3 d3dApp.h 4 5 Simple Direct3D demo application class. 6 7 Make sure you link: d3d10.lib d3dx10d.lib dxerr.lib dxguid.lib. 8 Link d3dx10.lib for release mode builds instead of d3dx10d.lib. 9 */ 10 11 #ifndef D3DAPP_H 12 #define D3DAPP_H 13 14 15 #include "d3dUtil.h" 16 #include "GameTimer.h" 17 #include <string> 18 19 #pragma comment(lib, "d3d10.lib") 20 #pragma comment(lib, "d3dx10d.lib") 21 #pragma comment(lib, "dxguid.lib") 22 #pragma comment(lib, "dxerr.lib") 23 24 class D3DApp 25 { 26 public: 27 D3DApp(HINSTANCE hInstance); 28 virtual ~D3DApp(); 29 30 HINSTANCE getAppInst(); 31 HWND getMainWnd(); 32 33 int run(); 34 35 // Framework methods. Derived client class overrides these methods to 36 // implement specific application requirements. 37 38 virtual void initApp(); 39 virtual void onResize();// reset projection/etc 40 virtual void updateScene(float dt); 41 virtual void drawScene(); 42 virtual LRESULT msgProc(UINT msg, WPARAM wParam, LPARAM lParam); 43 44 protected: 45 void initMainWindow(); 46 void initDirect3D(); 47 48 protected: 49 50 HINSTANCE mhAppInst; 51 HWND mhMainWnd; 52 bool mAppPaused; 53 bool mMinimized; 54 bool mMaximized; 55 bool mResizing; 56 57 GameTimer mTimer; 58 59 std::wstring mFrameStats; 60 61 ID3D10Device* md3dDevice; 62 IDXGISwapChain* mSwapChain; 63 ID3D10Texture2D* mDepthStencilBuffer; 64 ID3D10RenderTargetView* mRenderTargetView; 65 ID3D10DepthStencilView* mDepthStencilView; 66 ID3DX10Font* mFont; 67 68 // Derived class should set these in derived constructor to customize starting values. 69 std::wstring mMainWndCaption; 70 D3D10_DRIVER_TYPE md3dDriverType; 71 D3DXCOLOR mClearColor; 72 int mClientWidth; 73 int mClientHeight; 74 }; 75 76 #endif // D3DAPP_H
1 /* 2 2015.4 3 d3dApp.cpp 4 5 */ 6 #include "d3dApp.h" 7 #include <sstream> 8 9 LRESULT CALLBACK MainWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 10 { 11 static D3DApp* app = 0; 12 13 switch (msg) 14 { 15 case WM_CREATE: 16 { 17 // Get the 'this' pointer we passed to CreateWindow via the lpParam parameter. 18 // CREATESTRUCT结构定义了应用程序中窗口过程的初始化参数 19 CREATESTRUCT* cs = (CREATESTRUCT*)lParam; 20 app = (D3DApp*)cs->lpCreateParams; 21 return 0; 22 } 23 } 24 25 // Don't start processing messages until after WM_CREATE. 26 if (app) 27 return app->msgProc(msg, wParam, lParam); 28 else 29 return DefWindowProc(hwnd, msg, wParam, lParam); 30 } 31 32 D3DApp::D3DApp(HINSTANCE hInstance) 33 { 34 mhAppInst = hInstance; 35 mhMainWnd = 0; 36 mAppPaused = false; 37 mMinimized = false; 38 mMaximized = false; 39 mResizing = false; 40 41 mFrameStats = L""; 42 43 md3dDevice = 0; 44 mSwapChain = 0; 45 mDepthStencilBuffer = 0; 46 mRenderTargetView = 0; 47 mDepthStencilView = 0; 48 mFont = 0; 49 50 mMainWndCaption = L"D3D10 Application"; 51 md3dDriverType = D3D10_DRIVER_TYPE_HARDWARE; 52 mClearColor = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f); // Set background color 53 mClientWidth = 800; 54 mClientHeight = 600; 55 } 56 57 D3DApp::~D3DApp() 58 { 59 ReleaseCOM(mRenderTargetView); 60 ReleaseCOM(mDepthStencilView); 61 ReleaseCOM(mSwapChain); 62 ReleaseCOM(mDepthStencilBuffer); 63 ReleaseCOM(md3dDevice); 64 ReleaseCOM(mFont); 65 } 66 67 HINSTANCE D3DApp::getAppInst() 68 { 69 return mhAppInst; 70 } 71 72 HWND D3DApp::getMainWnd() 73 { 74 return mhMainWnd; 75 } 76 77 int D3DApp::run() 78 { 79 MSG msg = { 0 }; 80 81 mTimer.reset(); 82 83 while (msg.message != WM_QUIT) 84 { 85 // If there are Window messages then process them. 86 if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) 87 { 88 TranslateMessage(&msg); 89 DispatchMessage(&msg); 90 } 91 // Otherwise, do animation/game. 92 else 93 { 94 mTimer.tick(); 95 96 if (!mAppPaused) 97 updateScene(mTimer.getDeltaTime()); 98 else 99 Sleep(50); 100 101 drawScene(); 102 } 103 } 104 return (int)msg.wParam; 105 } 106 107 void D3DApp::initApp() 108 { 109 initMainWindow(); 110 initDirect3D(); 111 112 D3DX10_FONT_DESC fontDesc; 113 fontDesc.Height = 20; 114 fontDesc.Width = 0; 115 fontDesc.Weight = 500; // 字体的粗细0~1000 116 fontDesc.MipLevels = 1; 117 fontDesc.Italic = false;//非斜体 118 fontDesc.CharSet = DEFAULT_CHARSET; 119 fontDesc.OutputPrecision = OUT_DEFAULT_PRECIS; 120 fontDesc.Quality = DEFAULT_QUALITY; 121 fontDesc.PitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; 122 wcscpy_s(fontDesc.FaceName, L"Arial");// font style 123 124 D3DX10CreateFontIndirect(md3dDevice, &fontDesc, &mFont); 125 ////文本输出示例: 126 //// We specify DT_NOCLIP, so we do not care about width/height of the rect. 127 //const D3DXCOLOR BLACK(0.0f, 0.0f, 0.0f, 1.0f); 128 //RECT R = { 5, 5, 0, 0 }; 129 //mFont->DrawText(0, L"Hello, Direct3D!", -1, &R, DT_NOCLIP, BLACK); 130 } 131 132 void D3DApp::onResize() 133 { 134 // Release the old views, as they hold references to the buffers we 135 // will be destroying. Also release the old depth/stencil buffer. 136 137 ReleaseCOM(mRenderTargetView); 138 ReleaseCOM(mDepthStencilView); 139 ReleaseCOM(mDepthStencilBuffer); 140 141 142 // Resize the swap chain and recreate the render target view. 143 144 HR(mSwapChain->ResizeBuffers(1, mClientWidth, mClientHeight, DXGI_FORMAT_R8G8B8A8_UNORM, 0)); 145 ID3D10Texture2D* backBuffer; 146 HR(mSwapChain->GetBuffer(0, __uuidof(ID3D10Texture2D), reinterpret_cast<void**>(&backBuffer))); 147 HR(md3dDevice->CreateRenderTargetView(backBuffer, 0, &mRenderTargetView)); 148 ReleaseCOM(backBuffer); 149 150 151 // Create the depth/stencil buffer and view. 152 153 D3D10_TEXTURE2D_DESC depthStencilDesc; 154 155 depthStencilDesc.Width = mClientWidth; 156 depthStencilDesc.Height = mClientHeight; 157 depthStencilDesc.MipLevels = 1; 158 depthStencilDesc.ArraySize = 1; 159 depthStencilDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; 160 depthStencilDesc.SampleDesc.Count = 1; // multisampling must match 161 depthStencilDesc.SampleDesc.Quality = 0; // swap chain values. 162 depthStencilDesc.Usage = D3D10_USAGE_DEFAULT; 163 depthStencilDesc.BindFlags = D3D10_BIND_DEPTH_STENCIL; 164 depthStencilDesc.CPUAccessFlags = 0; 165 depthStencilDesc.MiscFlags = 0; 166 167 HR(md3dDevice->CreateTexture2D(&depthStencilDesc, 0, &mDepthStencilBuffer)); 168 HR(md3dDevice->CreateDepthStencilView(mDepthStencilBuffer, 0, &mDepthStencilView)); 169 170 171 // Bind the render target view and depth/stencil view to the pipeline. 172 173 md3dDevice->OMSetRenderTargets(1, &mRenderTargetView, mDepthStencilView); 174 175 176 // Set the viewport transform. 177 178 D3D10_VIEWPORT vp; 179 vp.TopLeftX = 0; 180 vp.TopLeftY = 0; 181 vp.Width = mClientWidth; 182 vp.Height = mClientHeight; 183 vp.MinDepth = 0.0f; 184 vp.MaxDepth = 1.0f; 185 186 md3dDevice->RSSetViewports(1, &vp); 187 } 188 189 void D3DApp::updateScene(float dt) 190 { 191 // Code computes the average frames per second, and also the 192 // average time it takes to render one frame. 193 194 static int frameCnt = 0; 195 static float t_base = 0.0f; 196 197 frameCnt++; 198 199 // Compute averages over one second period. 200 if ((mTimer.getGameTime() - t_base) >= 1.0f) 201 { 202 float fps = (float)frameCnt; // fps = frameCnt / 1 203 float mspf = 1000.0f / fps; 204 205 std::wostringstream outs; 206 outs.precision(6); 207 outs << L"FPS: " << fps << L"\n" 208 << "Milliseconds(Per Frame): " << mspf; 209 mFrameStats = outs.str(); 210 211 // Reset for next average. 212 frameCnt = 0; 213 t_base += 1.0f; 214 } 215 } 216 217 void D3DApp::drawScene() 218 { 219 // Set all the elements in a render target to one value 220 md3dDevice->ClearRenderTargetView(mRenderTargetView, mClearColor); 221 222 // Clears the depth-stencil resource 223 md3dDevice->ClearDepthStencilView(mDepthStencilView, D3D10_CLEAR_DEPTH | D3D10_CLEAR_STENCIL, 1.0f, 0); 224 } 225 226 LRESULT D3DApp::msgProc(UINT msg, WPARAM wParam, LPARAM lParam) 227 { 228 switch (msg) 229 { 230 // WM_ACTIVATE is sent when the window is activated or deactivated. 231 // We pause the game when the window is deactivated and unpause it 232 // when it becomes active. 233 case WM_ACTIVATE: 234 if (LOWORD(wParam) == WA_INACTIVE) 235 { 236 mAppPaused = true; 237 mTimer.stop(); 238 } 239 else 240 { 241 mAppPaused = false; 242 mTimer.start(); 243 } 244 return 0; 245 246 // WM_SIZE is sent when the user resizes the window. 247 case WM_SIZE: 248 // Save the new client area dimensions. 249 mClientWidth = LOWORD(lParam); 250 mClientHeight = HIWORD(lParam); 251 if (md3dDevice) 252 { 253 if (wParam == SIZE_MINIMIZED) 254 { 255 mAppPaused = true; 256 mMinimized = true; 257 mMaximized = false; 258 } 259 else if (wParam == SIZE_MAXIMIZED) 260 { 261 mAppPaused = false; 262 mMinimized = false; 263 mMaximized = true; 264 onResize(); 265 } 266 else if (wParam == SIZE_RESTORED) 267 { 268 269 // Restoring from minimized state? 270 if (mMinimized) 271 { 272 mAppPaused = false; 273 mMinimized = false; 274 onResize(); 275 } 276 277 // Restoring from maximized state? 278 else if (mMaximized) 279 { 280 mAppPaused = false; 281 mMaximized = false; 282 onResize(); 283 } 284 else if (mResizing) 285 { 286 // If user is dragging the resize bars, we do not resize 287 // the buffers here because as the user continuously 288 // drags the resize bars, a stream of WM_SIZE messages are 289 // sent to the window, and it would be pointless (and slow) 290 // to resize for each WM_SIZE message received from dragging 291 // the resize bars. So instead, we reset after the user is 292 // done resizing the window and releases the resize bars, which 293 // sends a WM_EXITSIZEMOVE message. 294 } 295 else // API call such as SetWindowPos or mSwapChain->SetFullscreenState. 296 { 297 onResize(); 298 } 299 } 300 } 301 return 0; 302 303 // WM_EXITSIZEMOVE is sent when the user grabs the resize bars. 304 case WM_ENTERSIZEMOVE: 305 mAppPaused = true; 306 mResizing = true; 307 mTimer.stop(); 308 return 0; 309 310 // WM_EXITSIZEMOVE is sent when the user releases the resize bars. 311 // Here we reset everything based on the new window dimensions. 312 case WM_EXITSIZEMOVE: 313 mAppPaused = false; 314 mResizing = false; 315 mTimer.start(); 316 onResize(); 317 return 0; 318 319 // WM_DESTROY is sent when the window is being destroyed. 320 case WM_DESTROY: 321 PostQuitMessage(0); 322 return 0; 323 324 // The WM_MENUCHAR message is sent when a menu is active and the user presses 325 // a key that does not correspond to any mnemonic or accelerator key. 326 case WM_MENUCHAR: 327 // Don't beep when we alt-enter. 328 return MAKELRESULT(0, MNC_CLOSE); 329 330 // Catch this message so to prevent the window from becoming too small. 331 case WM_GETMINMAXINFO: 332 ((MINMAXINFO*)lParam)->ptMinTrackSize.x = 200; 333 ((MINMAXINFO*)lParam)->ptMinTrackSize.y = 200; 334 return 0; 335 } 336 337 return DefWindowProc(mhMainWnd, msg, wParam, lParam); 338 } 339 340 void D3DApp::initMainWindow() 341 { 342 WNDCLASS wc; 343 wc.style = CS_HREDRAW | CS_VREDRAW; 344 wc.lpfnWndProc = MainWndProc; 345 wc.cbClsExtra = 0; 346 wc.cbWndExtra = 0; 347 wc.hInstance = mhAppInst; 348 wc.hIcon = LoadIcon(0, IDI_APPLICATION); 349 wc.hCursor = LoadCursor(0, IDC_ARROW); 350 wc.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH); 351 wc.lpszMenuName = 0; 352 wc.lpszClassName = L"D3DWndClassName"; 353 354 if (!RegisterClass(&wc)) 355 { 356 MessageBox(0, L"RegisterClass FAILED", 0, 0); 357 PostQuitMessage(0); 358 } 359 360 // Compute window rectangle dimensions based on requested client area dimensions. 361 RECT R = { 0, 0, mClientWidth, mClientHeight }; 362 AdjustWindowRect(&R, WS_OVERLAPPEDWINDOW, false); 363 int width = R.right - R.left; 364 int height = R.bottom - R.top; 365 366 mhMainWnd = CreateWindow(L"D3DWndClassName", mMainWndCaption.c_str(), 367 WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, width, height, 0, 0, mhAppInst, this); 368 if (!mhMainWnd) 369 { 370 MessageBox(0, L"CreateWindow FAILED", 0, 0); 371 PostQuitMessage(0); 372 } 373 374 ShowWindow(mhMainWnd, SW_SHOW); 375 UpdateWindow(mhMainWnd); 376 } 377 378 void D3DApp::initDirect3D() 379 { 380 // Fill out a DXGI_SWAP_CHAIN_DESC to describe our swap chain. 381 DXGI_SWAP_CHAIN_DESC sd; 382 383 // describes the backbuffer display mode 384 sd.BufferDesc.Width = mClientWidth; 385 sd.BufferDesc.Height = mClientHeight; 386 sd.BufferDesc.RefreshRate.Numerator = 60; 387 sd.BufferDesc.RefreshRate.Denominator = 1; 388 sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; 389 sd.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; 390 sd.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; 391 392 // describes multi-sampling parameters 393 // No multisampling. 394 sd.SampleDesc.Count = 1; 395 sd.SampleDesc.Quality = 0; 396 397 // The back buffer can be used for shader input or render-target output 398 sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; 399 400 sd.BufferCount = 1; 401 402 sd.OutputWindow = mhMainWnd; 403 404 sd.Windowed = true; 405 406 sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; 407 408 sd.Flags = 0; 409 410 411 // Create the device. 412 UINT createDeviceFlags = 0; 413 #if defined(DEBUG) || defined(_DEBUG) 414 createDeviceFlags |= D3D10_CREATE_DEVICE_DEBUG; 415 #endif 416 417 HR(D3D10CreateDeviceAndSwapChain( 418 0, //default adapter 419 md3dDriverType, 420 0, // no software device 421 createDeviceFlags, 422 D3D10_SDK_VERSION, 423 &sd, 424 &mSwapChain, 425 &md3dDevice)); 426 427 onResize(); 428 }
1 /* 2 2015.4 3 Box.h 4 5 */ 6 #ifndef BOX_H 7 #define BOX_H 8 9 #include "d3dUtil.h" 10 11 struct Vertex 12 { 13 D3DXVECTOR3 pos; 14 D3DXCOLOR color; 15 }; 16 17 class Box 18 { 19 public: 20 Box(); 21 ~Box(); 22 23 void init(ID3D10Device* device, float scale); 24 void draw(); 25 26 private: 27 DWORD mNumVertices; 28 DWORD mNumFaces; 29 30 ID3D10Device* md3dDevice; 31 ID3D10Buffer* mVB; 32 ID3D10Buffer* mIB; 33 }; 34 35 #endif // BOX_H
1 /* 2 2015.4 3 Box.cpp 4 5 */ 6 7 #include "Box.h" 8 9 Box::Box() 10 : mNumVertices(0), mNumFaces(0), md3dDevice(0), mVB(0), mIB(0) 11 { 12 } 13 14 Box::~Box() 15 { 16 ReleaseCOM(mVB); 17 ReleaseCOM(mIB); 18 } 19 20 void Box::init(ID3D10Device* device, float scale) 21 { 22 md3dDevice = device; 23 24 mNumVertices = 8; 25 mNumFaces = 12; 26 27 // Create vertex buffer 28 Vertex vertices[] = 29 { 30 { D3DXVECTOR3(-1.0f, -1.0f, -1.0f), WHITE}, 31 { D3DXVECTOR3(-1.0f, +1.0f, -1.0f), BLACK}, 32 { D3DXVECTOR3(+1.0f, +1.0f, -1.0f), RED}, 33 { D3DXVECTOR3(+1.0f, -1.0f, -1.0f), GREEN}, 34 { D3DXVECTOR3(-1.0f, -1.0f, +1.0f), BLUE}, 35 { D3DXVECTOR3(-1.0f, +1.0f, +1.0f), YELLOW}, 36 { D3DXVECTOR3(+1.0f, +1.0f, +1.0f), CYAN}, 37 { D3DXVECTOR3(+1.0f, -1.0f, +1.0f), MAGENTA}, 38 }; 39 40 // Scale the box. 41 // 乘上比例 42 for(DWORD i = 0; i < mNumVertices; ++i) 43 vertices[i].pos *= scale; 44 45 // Describes a buffer resource 46 /* 47 typedef enum D3D10_USAGE { 48 D3D10_USAGE_DEFAULT = 0, 49 D3D10_USAGE_IMMUTABLE = 1, // only be read by the GPU. 50 D3D10_USAGE_DYNAMIC = 2, // is accessible by both the GPU and the CPU (write only). 51 D3D10_USAGE_STAGING = 3 52 } D3D10_USAGE; 53 54 */ 55 D3D10_BUFFER_DESC vbd; 56 vbd.Usage = D3D10_USAGE_IMMUTABLE; 57 vbd.ByteWidth = sizeof(Vertex) * mNumVertices; 58 vbd.BindFlags = D3D10_BIND_VERTEX_BUFFER; 59 vbd.CPUAccessFlags = 0; 60 vbd.MiscFlags = 0; 61 62 // Specifies data for initializing a subresource 63 D3D10_SUBRESOURCE_DATA vinitData; 64 vinitData.pSysMem = vertices; 65 66 // Create a buffer (vertex buffer, index buffer, or shader-constant buffer) 67 /* 68 HRESULT CreateBuffer( 69 [in] const D3D10_BUFFER_DESC *pDesc, 70 [in] const D3D10_SUBRESOURCE_DATA *pInitialData, 71 [out] ID3D10Buffer **ppBuffer ); 72 */ 73 HR(md3dDevice->CreateBuffer(&vbd, &vinitData, &mVB)); 74 75 // Create the index buffer 76 // Box 六面 77 DWORD indices[] = { 78 // front face 79 0, 1, 2, 80 0, 2, 3, 81 82 // back face 83 4, 6, 5, 84 4, 7, 6, 85 86 // left face 87 4, 5, 1, 88 4, 1, 0, 89 90 // right face 91 3, 2, 6, 92 3, 6, 7, 93 94 // top face 95 1, 5, 6, 96 1, 6, 2, 97 98 // bottom face 99 4, 0, 3, 100 4, 3, 7 101 }; 102 103 D3D10_BUFFER_DESC ibd; 104 ibd.Usage = D3D10_USAGE_IMMUTABLE; 105 ibd.ByteWidth = sizeof(DWORD) * mNumFaces*3; 106 ibd.BindFlags = D3D10_BIND_INDEX_BUFFER; 107 ibd.CPUAccessFlags = 0; 108 ibd.MiscFlags = 0; 109 110 D3D10_SUBRESOURCE_DATA iinitData; 111 iinitData.pSysMem = indices; 112 HR(md3dDevice->CreateBuffer(&ibd, &iinitData, &mIB)); 113 } 114 115 void Box::draw() 116 { 117 UINT stride = sizeof(Vertex); 118 UINT offset = 0; 119 /* 120 Bind an array of vertex buffers to the input-assembler stage 121 122 void IASetVertexBuffers( 123 [in] UINT StartSlot, 124 [in] UINT NumBuffers, 125 [in] ID3D10Buffer *const *ppVertexBuffers, 126 [in] const UINT *pStrides, 127 [in] const UINT *pOffsets ); //Pointer to an array of offset values; 128 */ 129 md3dDevice->IASetVertexBuffers(0, 1, &mVB, &stride, &offset); 130 131 /* 132 Bind an index buffer to the input-assembler stage. 133 将一个索引缓冲区绑定到输入汇编器阶段 134 void IASetIndexBuffer( 135 [in] ID3D10Buffer *pIndexBuffer, 136 [in] DXGI_FORMAT Format, 137 [in] UINT Offset ); 138 */ 139 md3dDevice->IASetIndexBuffer(mIB, DXGI_FORMAT_R32_UINT, 0); 140 141 /* 142 void DrawIndexed( 143 [in] UINT IndexCount, 144 [in] UINT StartIndexLocation, 145 [in] INT BaseVertexLocation ); //Offset from the start of the vertex buffer to the first vertex 146 */ 147 md3dDevice->DrawIndexed(mNumFaces*3, 0, 0); 148 149 150 /* 151 完成图元汇编后,顶点将被送往顶点着色器(vertex shader)阶段。顶点着色器可以被看成是一个以顶点作为输入输出数据的函数, 152 每个将要绘制的顶点都会通过顶点着色器推送至硬件. 153 */ 154 }
1 /* 2 2015.4 3 color.fx 4 5 Transforms and colors geometry. 6 使用下面的后缀来表示空间:L(局部空间)、W(世界空间)、V(观察空间)、H(齐次裁剪空间) 7 */ 8 9 10 cbuffer cbPerObject 11 { 12 // 常量缓冲区,由着色器来访问 13 float4x4 gWVP; 14 }; 15 16 void VS(float3 iPosL : POSITION, 17 float4 iColor : COLOR, 18 out float4 oPosH : SV_POSITION, 19 out float4 oColor : COLOR) 20 { 21 // Transform to homogeneous clip space. 22 // 将顶点位置从局部空间变换到齐次裁剪空间,矩阵gWVP是世界矩阵、观察矩阵和投影矩阵的组合矩阵 23 // float4(iPosL, 1.0f)相当于“float4(iPosL.x,iPosL.y, iPosL.z, 1.0f) 24 oPosH = mul(float4(iPosL, 1.0f), gWVP); 25 26 oColor = iColor; 27 } 28 29 float4 PS(float4 posH : SV_POSITION, 30 float4 color : COLOR) : SV_Target 31 { 32 // 这里像素着色器只是简单地返回插值颜色 33 return color; 34 } 35 36 // 一个technique 由一个或多个pass 组成,每个pass实现一种不同的几何体渲染方式 37 technique10 ColorTech 38 { 39 // 一个pass 由一个顶点着色器、一个可选的几何着色器、一个像素着色器和一些渲染状态组成 40 pass P0 41 { 42 // 顶点着色器设置为版本4.0, 4.0不再使用常量寄存器,而是使用常量缓存Constant Buffer 43 SetVertexShader( CompileShader( vs_4_0, VS() ) ); 44 SetGeometryShader( NULL ); 45 SetPixelShader( CompileShader( ps_4_0, PS() ) ); 46 } 47 }
1 /* 2 2015.4 3 main_Box.cpp 4 5 Color Cube 6 Controls: 7 'A'/'D'/'W'/'S' - Rotate 8 */ 9 10 #include "d3dApp.h" 11 #include "Box.h" 12 13 class ColoredCubeApp : public D3DApp 14 { 15 public: 16 ColoredCubeApp(HINSTANCE hInstance); 17 ~ColoredCubeApp(); 18 19 void initApp(); 20 void onResize(); 21 void updateScene(float dt); 22 void drawScene(); 23 24 private: 25 void buildFX(); 26 void buildVertexLayouts(); 27 28 private: 29 Box mBox; 30 31 ID3D10Effect* mFX; 32 ID3D10EffectTechnique* mTech; 33 ID3D10InputLayout* mVertexLayout; 34 ID3D10EffectMatrixVariable* mfxWVPVar; 35 36 D3DXMATRIX mView; 37 D3DXMATRIX mProj; 38 D3DXMATRIX mWVP; 39 40 float mTheta; 41 float mPhi; 42 }; 43 44 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance,PSTR cmdLine, int showCmd) 45 { 46 // Enable run-time memory check for debug builds. 47 #if defined(DEBUG) | defined(_DEBUG) 48 _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); 49 #endif 50 51 ColoredCubeApp theApp(hInstance); 52 theApp.initApp(); 53 54 return theApp.run(); 55 } 56 57 ColoredCubeApp::ColoredCubeApp(HINSTANCE hInstance) 58 : D3DApp(hInstance), mFX(0), mTech(0), mVertexLayout(0), 59 mfxWVPVar(0), mTheta(0.0f), mPhi(PI*0.25f) 60 { 61 // 设为单位矩阵 62 D3DXMatrixIdentity(&mView); 63 D3DXMatrixIdentity(&mProj); 64 D3DXMatrixIdentity(&mWVP); 65 } 66 67 ColoredCubeApp::~ColoredCubeApp() 68 { 69 if (md3dDevice) 70 md3dDevice->ClearState(); 71 72 ReleaseCOM(mFX); 73 ReleaseCOM(mVertexLayout); 74 } 75 76 void ColoredCubeApp::initApp() 77 { 78 D3DApp::initApp(); 79 80 // Box 绑定到该 md3dDevice 81 mBox.init(md3dDevice, 1.0f); 82 83 buildFX(); 84 buildVertexLayouts(); 85 } 86 87 void ColoredCubeApp::onResize() 88 { 89 D3DApp::onResize(); 90 91 float aspect = (float)mClientWidth / mClientHeight; 92 D3DXMatrixPerspectiveFovLH(&mProj, 0.25f*PI, aspect, 1.0f, 1000.0f); 93 } 94 95 void ColoredCubeApp::updateScene(float dt) 96 { 97 D3DApp::updateScene(dt); 98 99 // Update angles based on input to orbit camera around box. 100 //改变夹角 101 if (GetAsyncKeyState('A') & 0x8000) mTheta -= 5.0f*dt; 102 if (GetAsyncKeyState('D') & 0x8000) mTheta += 5.0f*dt; 103 if (GetAsyncKeyState('W') & 0x8000) mPhi -= 5.0f*dt; 104 if (GetAsyncKeyState('S') & 0x8000) mPhi += 5.0f*dt; 105 106 // Restrict the angle mPhi. 107 if (mPhi < 0.1f) mPhi = 0.1f; 108 if (mPhi > PI - 0.1f) mPhi = PI - 0.1f; 109 110 // Convert Spherical to Cartesian coordinates: mPhi measured from +y 111 // and mTheta measured counterclockwise from -z. 112 float x = 5.0f*sinf(mPhi)*sinf(mTheta); 113 float z = -5.0f*sinf(mPhi)*cosf(mTheta); 114 float y = 5.0f*cosf(mPhi); 115 116 // Build the view matrix. 117 D3DXVECTOR3 pos(x, y, z); 118 D3DXVECTOR3 target(0.0f, 0.0f, 0.0f); 119 D3DXVECTOR3 up(0.0f, 1.0f, 0.0f); 120 121 D3DXMatrixLookAtLH(&mView, &pos, &target, &up); 122 } 123 124 void ColoredCubeApp::drawScene() 125 { 126 D3DApp::drawScene(); 127 128 // Restore default states, input layout and primitive topology 129 // because mFont->DrawText changes them. Note that we can 130 // restore the default states by passing null. 131 md3dDevice->OMSetDepthStencilState(0, 0); 132 float blendFactors[] = { 0.0f, 0.0f, 0.0f, 0.0f }; 133 md3dDevice->OMSetBlendState(0, blendFactors, 0xffffffff); 134 135 // 当一个input layout被创建以后, 调用IASetInputLayout函数可以把它绑定一个divece中 136 md3dDevice->IASetInputLayout(mVertexLayout); 137 138 // vertex buffer只是在内存中存储了一系列内存点,用Primitive Topology告诉Direct3D用点形成几何图形的方式 139 md3dDevice->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST); 140 141 // set constants 142 mWVP = mView*mProj; 143 mfxWVPVar->SetMatrix((float*)&mWVP); 144 145 D3D10_TECHNIQUE_DESC techDesc; 146 mTech->GetDesc(&techDesc); 147 for (UINT p = 0; p < techDesc.Passes; ++p) 148 { 149 /*Apply方法的作用: 150 更新存储在GPU 内存中的常量缓冲区、将着色器程序绑定到管线、并启用在pass中指定的各种渲染状态。 151 */ 152 mTech->GetPassByIndex(p)->Apply(0); 153 154 mBox.draw(); 155 } 156 157 // We specify DT_NOCLIP, so we do not care about width/height of the rect. 158 RECT R = { 5, 5, 0, 0 }; 159 mFont->DrawText(0, mFrameStats.c_str(), -1, &R, DT_NOCLIP, BLACK); 160 161 mSwapChain->Present(0, 0); 162 } 163 164 // 着色器 165 void ColoredCubeApp::buildFX() 166 { 167 DWORD shaderFlags = D3D10_SHADER_ENABLE_STRICTNESS; 168 #if defined( DEBUG ) || defined( _DEBUG ) 169 shaderFlags |= D3D10_SHADER_DEBUG; 170 shaderFlags |= D3D10_SHADER_SKIP_OPTIMIZATION; 171 #endif 172 173 // 通用内存块,使用时应该对它执行相应的类型转换 174 // used to return object code and error messages in APIs that compile vertex, geometry and pixel shaders. 175 ID3D10Blob* compilationErrors = 0; 176 177 HRESULT hr = 0; 178 // 编译着色器 179 hr = D3DX10CreateEffectFromFile(L"color.fx", 0, 0, 180 "fx_4_0", shaderFlags, 0, md3dDevice, 0, 0, &mFX, &compilationErrors, 0); 181 if (FAILED(hr)) 182 { 183 if (compilationErrors) 184 { 185 MessageBoxA(0, (char*)compilationErrors->GetBufferPointer(), 0, 0); 186 ReleaseCOM(compilationErrors); 187 } 188 // Outputs a formatted error message to the debug stream 189 DXTrace(__FILE__, (DWORD)__LINE__, hr, L"D3DX10CreateEffectFromFile", true); 190 } 191 192 // 获得指向technique对象的指针 193 mTech = mFX->GetTechniqueByName("ColorTech"); 194 195 /* 196 ID3D10Effect::GetVariableByName方法返回一个ID3D10EffectVariable指针。 197 它是一种通用效果变量类型;要获得指向特定类型变量的指针(例如,矩阵、向量、标量), 198 你必须使用相应的As*****方法(例如,AsMatrix、AsVector、AsScalar)。 199 然后可以通过C++接口来更新它们 200 */ 201 mfxWVPVar = mFX->GetVariableByName("gWVP")->AsMatrix(); 202 } 203 204 // 构建图元 205 void ColoredCubeApp::buildVertexLayouts() 206 { 207 /* 208 typedef struct D3D10_INPUT_ELEMENT_DESC { 209 LPCSTR SemanticName; 210 UINT SemanticIndex; 211 DXGI_FORMAT Format; 212 UINT InputSlot; // between 0 and 15 213 UINT AlignedByteOffset; 214 D3D10_INPUT_CLASSIFICATION InputSlotClass; 215 UINT InstanceDataStepRate; 216 } D3D10_INPUT_ELEMENT_DESC; 217 */ 218 D3D10_INPUT_ELEMENT_DESC vertexDesc[] = 219 { 220 { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 }, 221 { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0 } 222 }; 223 224 D3D10_PASS_DESC PassDesc; 225 // Get a pass description by calling ID3D10EffectPass::GetDesc 226 mTech->GetPassByIndex(0)->GetDesc(&PassDesc); 227 228 /* 229 Create an input-layout object to describe the input-buffer data for the input-assembler stage. 230 231 HRESULT CreateInputLayout( 232 [in] const D3D10_INPUT_ELEMENT_DESC *pInputElementDescs, 233 [in] UINT NumElements, 234 [in] const void *pShaderBytecodeWithInputSignature, 235 [in] SIZE_T BytecodeLength, 236 [out] ID3D10InputLayout **ppInputLayout ); 237 238 After creating an input layout object, it must be bound to the input-assembler stage 239 before calling a draw API. 240 */ 241 HR(md3dDevice->CreateInputLayout(vertexDesc, 2, PassDesc.pIAInputSignature, 242 PassDesc.IAInputSignatureSize, &mVertexLayout)); 243 }