// include the basic windows header file #include #include #include #pragma comment (lib, "d3d11.lib") #include #pragma comment (lib, "d3dcompiler.lib") #include #include namespace dx = DirectX; #include // to usd std::size #include // to use std::sin and std::cos #include "Timer.h" // to use timer Timer timer; // global declarations Microsoft::WRL::ComPtr swapchain; // the pointer to the swap chain interface Microsoft::WRL::ComPtr dev; // the pointer to our Direct3D device interface Microsoft::WRL::ComPtr devcon; // the pointer to our Direct3D device context // 定义Targe View Microsoft::WRL::ComPtr targetView; // Define Shader Microsoft::WRL::ComPtr pPixelShader; Microsoft::WRL::ComPtr pCompiledPixelBlob; Microsoft::WRL::ComPtr pVertexShader; Microsoft::WRL::ComPtr pCompiledVertexBlob; // Define vertex buffer Microsoft::WRL::ComPtr pVertexBuffer; // Create buffer description struct Vertex { float x; float y; float r; float g; float b; }; // create vertex buffer (1 2d triangle at center of screen) const Vertex vertices[] = { // center { 0.0f, 0.5f, 1.0f, 0.0f, 0.0f }, { 0.5f, -0.5f, 0.0f, 1.0f, 0.0f }, { -0.5f, -0.5f, 0.0f, 0.0f, 1.0f }, // left top { 0.0f, 0.5f, 1.0f, 0.0f, 0.0f }, { -0.5f, -0.5f, 0.0f, 0.0f, 1.0f }, { -0.3f, 0.3f, 0.0f, 1.0f, 0.0f }, // right top { 0.5f, -0.5f, 0.0f, 1.0f, 0.0f }, { 0.0f, 0.5f, 1.0f, 0.0f, 0.0f }, { 0.3f, 0.3f, 0.0f, 0.0f, 1.0f }, // center bottom { 0.5f, -0.5f, 0.0f, 1.0f, 0.0f }, { 0.0f, -0.8f, 1.0f, 0.0f, 0.0f }, { -0.5f, -0.5f, 0.0f, 0.0f, 1.0f }, }; // Define constant buffer Microsoft::WRL::ComPtr pConstantBuffer; // Create constant buffer struct struct ConstantBuffer { dx::XMMATRIX transform; }; // create constant buffer const float heightWidthRatio = 0.3f / 0.4f; float angle = 0.0f; ConstantBuffer cb = { // transpose the matrix to change from row_major to column_major dx::XMMatrixTranspose( // rotate Z axis dx::XMMatrixRotationZ(-angle) * dx::XMMatrixScaling(heightWidthRatio, 1.0f, 1.0f) ) }; // Define input layout ID3D11InputLayout* pInputLayout; void DefineShader() { // Load vertex shader file into BLOB, and create COM object of pixel shader D3DReadFileToBlob(L"PixelShader.cso", &pCompiledPixelBlob); dev->CreatePixelShader(pCompiledPixelBlob->GetBufferPointer(), pCompiledPixelBlob->GetBufferSize(), nullptr, &pPixelShader); // Load pixel shader file into BLOB, and create COM object of vertex shader D3DReadFileToBlob(L"VertexShader.cso", &pCompiledVertexBlob); dev->CreateVertexShader(pCompiledVertexBlob->GetBufferPointer(), pCompiledVertexBlob->GetBufferSize(), nullptr, &pVertexShader); // bind pixel shader devcon->PSSetShader(pPixelShader.Get(), nullptr, 0u); // bind vertex shader devcon->VSSetShader(pVertexShader.Get(), nullptr, 0u); } void DefineVertexBuffer() { D3D11_BUFFER_DESC bd = {}; bd.BindFlags = D3D11_BIND_VERTEX_BUFFER; bd.Usage = D3D11_USAGE_DEFAULT; bd.CPUAccessFlags = 0u; bd.MiscFlags = 0u; bd.ByteWidth = sizeof(vertices); bd.StructureByteStride = sizeof(Vertex); D3D11_SUBRESOURCE_DATA sd = {}; sd.pSysMem = vertices; // Create vertex buffer dev->CreateBuffer(&bd, &sd, &pVertexBuffer); } void DefineConstantBuffer(float angle) { cb = { // transpose the matrix to change from row_major to column_major dx::XMMatrixTranspose( // rotate Z axis dx::XMMatrixRotationZ(-angle) * dx::XMMatrixScaling(heightWidthRatio, 1.0f, 1.0f) ) }; D3D11_BUFFER_DESC cbd = {}; cbd.BindFlags = D3D11_BIND_CONSTANT_BUFFER; cbd.Usage = D3D11_USAGE_DYNAMIC; cbd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; cbd.MiscFlags = 0u; cbd.ByteWidth = sizeof(cb); cbd.StructureByteStride = 0u; D3D11_SUBRESOURCE_DATA csd = {}; csd.pSysMem = &cb; // Create constant buffer dev->CreateBuffer(&cbd, &csd, &pConstantBuffer); // Bind constant buffer to vertex buffer devcon->VSSetConstantBuffers(0u, 1u, pConstantBuffer.GetAddressOf()); } void DefineInputLayout() { // Create input elements description, choosing whatever need to send to GPU const D3D11_INPUT_ELEMENT_DESC ied[] = { { "Position",0,DXGI_FORMAT_R32G32_FLOAT,0,0,D3D11_INPUT_PER_VERTEX_DATA,0 }, { "Color",0,DXGI_FORMAT_R32G32B32_FLOAT,0,8,D3D11_INPUT_PER_VERTEX_DATA,0 }, }; // Create input layout, using the description Defined above dev->CreateInputLayout ( ied, (UINT)std::size(ied), pCompiledVertexBlob->GetBufferPointer(), pCompiledVertexBlob->GetBufferSize(), &pInputLayout ); // Bind layout to pipeline // bind vertex layout devcon->IASetInputLayout(pInputLayout); // bind render target devcon->OMSetRenderTargets(1u, targetView.GetAddressOf(), nullptr); } void DrawPrimitive() { // Set the vertex buffer to use. Pick up the vertex buffer created in previous step. // Bind vertex buffer to pipeline const UINT stride = sizeof(Vertex); const UINT offset = 0u; devcon->IASetVertexBuffers(0u, 1u, pVertexBuffer.GetAddressOf(), &stride, &offset); // Set the primitive type to use // Set primitive topology to triangle list (groups of 3 vertices) devcon->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); // Draw the triangle. devcon->Draw((UINT)sizeof(vertices), 0u); } void drawTriangle() { DefineShader(); DefineVertexBuffer(); DefineConstantBuffer(timer.Peek()); DefineInputLayout(); DrawPrimitive(); } // this function initializes and prepares Direct3D for use void InitD3D(HWND hWnd) { // create a struct to hold information about the swap chain DXGI_SWAP_CHAIN_DESC scd; // clear out the struct for use ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC)); // fill the swap chain description struct scd.BufferCount = 1; // one back buffer scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // use 32-bit color scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // how swap chain is to be used scd.OutputWindow = hWnd; // the window to be used scd.SampleDesc.Count = 4; // how many multisamples scd.Windowed = TRUE; // windowed/full-screen mode // create a device, device context and swap chain using the information in the scd struct D3D11CreateDeviceAndSwapChain(NULL, // IDXGIAdapter *pAdapter - Let DXGI take care of what adapter to use (default adapter) D3D_DRIVER_TYPE_HARDWARE, // D3D_DRIVER_TYPE DriverType - hardware or software, or others NULL, // HMODULE Software NULL, // UINT Flags NULL, // D3D_FEATURE_LEVEL *pFeatureLevels NULL, // UINT FeatureLevels D3D11_SDK_VERSION, // UINT SDKVersion &scd, // DXGI_SWAP_CHAIN_DESC *pSwapChainDesc &swapchain, // IDXGISwapChain **ppSwapChain &dev, // ID3D11Device **ppDevice NULL, // D3D_FEATURE_LEVEL *FeatureLevel &devcon); // ID3D11DeviceContext **ppImmediateContext // 从SwapChain中取得back buffer Microsoft::WRL::ComPtr pBackBuffer; swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer); // 根据back buffer,创建新的View Target dev->CreateRenderTargetView(pBackBuffer.Get(), NULL, &targetView); // 将渲染目标设置成我们新创建的View Target devcon->OMSetRenderTargets(1, targetView.GetAddressOf(), NULL); // 指定View Port D3D11_VIEWPORT viewport; ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT)); // 控制View port的位置 viewport.TopLeftX = 0; viewport.TopLeftY = 0; viewport.Width = 800; viewport.Height = 600; devcon->RSSetViewports(1, &viewport); } // this is the function used to render a single frame void RenderFrame(void) { // clear the back buffer to a deep blue const float color[] = { 0.0f, 0.2f, 0.4f, 1.0f }; devcon->ClearRenderTargetView(targetView.Get(), color); // do 3D rendering on the back buffer here drawTriangle(); // switch the back buffer and the front buffer // 切换显示,将back buffer的内容交换到front buffer swapchain->Present(0, 0); } // this is the function that cleans up Direct3D and COM void CleanD3D() { // close and release all existing COM objects // changed to use smart pointer, do NOT need to manually release // pPixelShader->Release(); // pCompiledPixelBlob->Release(); // pVertexShader->Release(); // pCompiledVertexBlob->Release(); // pVertexBuffer->Release(); // pInputLayout->Release(); // swapchain->Release(); // targetView->Release(); // dev->Release(); // devcon->Release(); } // the WindowProc function prototype LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); // the entry point for any Windows program int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { // the handle for the window, filled by a function HWND hWnd; // this struct holds information for the window class WNDCLASSEX wc; // clear out the window class for use ZeroMemory(&wc, sizeof(WNDCLASSEX)); // fill in the struct with the needed information wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WindowProc; wc.hInstance = hInstance; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)COLOR_WINDOW; wc.lpszClassName = "WindowClass"; // register the window class RegisterClassEx(&wc); // create rectangle for client area RECT wr = { 0, 0, 800, 600 }; // set the size only, but not the position AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE); // adjust the size // create the window and use the result as the handle hWnd = CreateWindowEx(NULL, "WindowClass", // name of the window class "Our First Windowed Program", // title of the window WS_OVERLAPPEDWINDOW, // window style 300, // x-position of the window 200, // y-position of the window 800, // width of the window 600, // height of the window NULL, // we have no parent window, NULL NULL, // we aren't using menus, NULL hInstance, // application handle NULL); // used with multiple windows, NULL // display the window on the screen ShowWindow(hWnd, nCmdShow); // set up and initialize Direct3D InitD3D(hWnd); // enter the main loop: // this struct holds Windows event messages MSG msg; // wait for the next message in the queue, store the result in 'msg' while (true) { if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { // translate keystroke messages into the right format TranslateMessage(&msg); // send the message to the WindowProc function DispatchMessage(&msg); // check if message to quit if (msg.message == WM_QUIT) { break; } } else { RenderFrame(); } } // clean up DirectX and COM CleanD3D(); // return this part of the WM_QUIT message to Windows return msg.wParam; } // this is the main message handler for the program LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { // sort through and find what code to run for the message given switch (message) { // this message is read when the window is closed case WM_DESTROY: { // close the application entirely PostQuitMessage(0); return 0; } break; } // Handle any messages the switch statement didn't return DefWindowProc(hWnd, message, wParam, lParam); }