Tag Archives: DIRECT3D

Create a D3D11 application process

Declaration meaning:
1. SwapChain is a COM interface object that is buffered before and after switching (double buffering). The scene is rendered first to buffered after rendering, so when rendered to the display, it will be fully drawn. If you don’t use this method, you’ll see a scan line, which is what happens when the program draws the scene from top to bottom.
ID3D11Device (a new DirectX11 interface) is an interface for representing hardware devices (Gpus). It is in two parts to support the new multithreading capabilities. Here, the ID3D11DeivceContext interface object will be used to call all the render methods, and the ID3D11Device interface will be used to call the remaining methods that need not be used for rendering.
The reason ID3D11Device is divided into two parts is because DirectX 11 has added new multithreading functions, which can improve the speed of the application. The ID3D11Device object is called to create or load a model or object into memory. When an object or model is loaded or created, the ID3D11DeviceContext interface object can be called to continue rendering the scene.
4. Another interface is the render target view. It is usually written to the render target view first, which is a 2D texture (i.e., post-buffered), rather than written directly to the screen. The texture is sent to the output blending phase of the pipeline before it is rendered to the screen.
This is followed by changing the color of the background.

IDXGISwapChain* SwapChain;
ID3D11Device* d3d11Device;
ID3D11DeviceContext* d3d11DevCon;
ID3D11RenderTargetView* renderTargetView;

float red = 0.0f;
float green = 0.0f;
float blue = 0.0f;
int colormodr = 1;
int colormodg = 1;
int colormodb = 1;

Function prototype: The first function is used to initialize Direct3D. The second is to release unwanted objects to avoid memory leaks. The third InitScene is used to initialize the scene. UpdateScene updates the scene for each frame, and the subsequent DrawScene is used to draw each frame scene to the screen, which is also updated for each frame.

bool InitializeDirect3d11App(HINSTANCE hInstance);
void ReleaseObjects();
bool InitScene();
void UpdateScene();
void DrawScene();

In the winMain function, call InitializeDirect3d11App, then InitScene. Call Messageloop again, and after the Message loop completes, release the object and end the program.

if(!InitializeDirect3d11App(hInstance))    //Initialize Direct3D
{
    MessageBox(0, L"Direct3D Initialization - Failed",
        L"Error", MB_OK);
    return 0;
}

if(!InitScene())    //Initialize our scene
{
    MessageBox(0, L"Scene Initialization - Failed",
        L"Error", MB_OK);
    return 0;
}

messageloop();

ReleaseObjects();    

Initialize D3D 11

The following is the function definition that initializes D3D, which has only one handle argument to the application.

bool InitializeDirect3dApp(HINSTANCE hInstance)
{
HRESULT hr;

//Describe our Buffer
DXGI_MODE_DESC bufferDesc;

ZeroMemory(&bufferDesc, sizeof(DXGI_MODE_DESC));

bufferDesc.Width = Width;
bufferDesc.Height = Height;
bufferDesc.RefreshRate.Numerator = 60;
bufferDesc.RefreshRate.Denominator = 1;
bufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
bufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
bufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;

//Describe our SwapChain
DXGI_SWAP_CHAIN_DESC swapChainDesc; 
    
ZeroMemory(&swapChainDesc, sizeof(DXGI_SWAP_CHAIN_DESC));

swapChainDesc.BufferDesc = bufferDesc;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.BufferCount = 1;
swapChainDesc.OutputWindow = hwnd; 
swapChainDesc.Windowed = TRUE; 
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;


//Create our SwapChain
hr = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, NULL, NULL, NULL,
    D3D11_SDK_VERSION, &swapChainDesc, &SwapChain, &d3d11Device, NULL, &d3d11DevCon);

//Create our BackBuffer
ID3D11Texture2D* BackBuffer;
hr = SwapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), (void**)&BackBuffer );

//Create our Render Target
hr = d3d11Device->CreateRenderTargetView( BackBuffer, NULL, &renderTargetView );
BackBuffer->Release();

//Set our Render Target
d3d11DevCon->OMSetRenderTargets( 1, &renderTargetView, NULL );

return true;
}

Create an HRESULT object HR for error detection:
HRESULT hr;
Post-declaration buffering: ====. 20171220 correction
DXGI_MODE_DESC
The first thing to do in this function is to describe the post-buffer. Creates a DXGI_MODE_DESC object called bufferDesc. ZeroMemory clears the space (empties the dirty value) and fills in the post-buffer descriptor. The structure of DXGI_MODE_DESC is as follows:

typedef struct DXGI_MODE_DESC {
  UINT                     Width;
  UINT                     Height;
  DXGI_RATIONAL            RefreshRate;
  DXGI_FORMAT              Format;
  DXGI_MODE_SCANLINE_ORDER ScanlineOrdering;
  DXGI_MODE_SCALING        Scaling;
} DXGI_MODE_DESC, *LPDXGI_MODE_DESC;

The members are described as follows:
Width
Denotes resolution width
Height
Denotes resolution height
RefreshRate
Represents the DXGI_RATIONAL type, in Hertz, set to 60/1 or 60Hz.
Format
Represents a display format, which is the type of a DXGI_FORMAT enumeration. Is a 32-bit unsigned integer that can be used in the DXGI_FORMAT_R8G8B8A8_UNORM format, 8 bit for RGBA.
ScanlineOrdering
Indicates how rasterization is rendered to a window, of the DXGI_MODE_SCANLINE_ORDER enumeration type. It can be set to DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED, indicating that it is independent of the order of rendering on the window.
Scaling
Represents how the image is stretched to meet the resolution of the display. An enumeration type of DXGI_MODE_SCALING. Use one of the following:
DXGI_MODE_SCALING_UNSPECIFIED means that no scaling or stretching is specified
DXGI_MODE_SCALING_CENTERED is the idea that the image is centered in the center of the screen and that it’s not scaled or stretched at all
Dxgi_mode_scaling_chord represents stretching the image to the display resolution

DXGI_MODE_DESC bufferDesc;

ZeroMemory(&bufferDesc, sizeof(DXGI_MODE_DESC));

bufferDesc.Width = Width;
bufferDesc.Height = Height;
bufferDesc.RefreshRate.Numerator = 60;
bufferDesc.RefreshRate.Denominator = 1;
bufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
bufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
bufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;

Declaration exchange chain

(DXGI_SWAP_CHAIN_DESC)
Create a DXGI_CHAIN_DESC named swapChainDesc and call the ZeroMemory function to clear.

typedef struct DXGI_SWAP_CHAIN_DESC {
  DXGI_MODE_DESC   BufferDesc;
  DXGI_SAMPLE_DESC SampleDesc;
  DXGI_USAGE       BufferUsage;
  UINT             BufferCount;
  HWND             OutputWindow;
  BOOL             Windowed;
  DXGI_SWAP_EFFECT SwapEffect;
  UINT             Flags;
} DXGI_SWAP_CHAIN_DESC;

BufferDesc
Represents the post-buffered display mode, DXGI_MODE_DESC structure.
SampleDesc
Represents a multiple sampling parameter, the DXGI_SAMPLE_DESC structure. Multiple sampling is used to eliminate jagged lines and edges because the pixels on the display are not infinitely small.
BufferUsage
Represents the purpose of the window after the buffer and how the CPU is accessed. Is the enumerated type of DXGI_USAGE. The post-buffer can be used for the input to the shader or the output of the render target. When caching is to be rendered as the target output, set to DXGI_USAGE_RENDER_TARGET_OUTPUT.
BufferCount
Represents the number of buffers in the swap chain. “1” means double buffering, “2” means three buffering, and you can set more buffering.
OutputWindow
Window handle, HWND
Windowed
Use to specify whether a window is windowed or full-screen, and set it to true for windowing or false for windowing. Proposal to create a window of exchange of chain, and then let the user through IDXGISwapChain: : SetFullscreenState method to switch to full screen will exchange chain; In other words, do not force the switch chain to be full screen by setting this value to false. However, if you are creating a swap chain in full screen, the BufferDesc member also provides the user with a list of supported display modes. This is because if the exchange chain is created in an unsupported display mode, the display will go black.
SwapEffect
Represents the processing of the render buffer content after rendering a window, which is an enumeration type of DXGI_SWAP_EFFECT. Set to DXGI_SWAP_EFFECT_DISCARD to specify the bit block transfer model and to have DXGI discard the contents of the post-buffer. Although the application value reads and writes to buffer 0, this flag bit is useful for exchanges with more than one post-buffer. This flag enables the display driver to select the most efficient rendering technique for the exchange chain.
Flags
DXGI_SWAP_CHAIN_FLAG enumeration type. Used to describe the behavior of exchange chains. The only thing that might work now is DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH, which changes the display resolution when switching between windowing and full-screen.

DXGI_SWAP_CHAIN_DESC swapChainDesc; 
    
ZeroMemory(&swapChainDesc, sizeof(DXGI_SWAP_CHAIN_DESC));

swapChainDesc.BufferDesc = bufferDesc;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.BufferCount = 1;
swapChainDesc.OutputWindow = hwnd; 
swapChainDesc.Windowed = TRUE; 
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;

Create device and exchange chains
(D3D11CreateDeviceAndSwapChain)
D3d core function called D3D11CreateDeviceAndSwapChain () function to create d3d device, the device context, as well as the exchange of chain. The function parameters are similar to the following:

HRESULT D3D11CreateDeviceAndSwapChain(
  __in   IDXGIAdapter *pAdapter,
  __in   D3D_DRIVER_TYPE DriverType,
  __in   HMODULE Software,
  __in   UINT Flags,
  __in   const D3D_FEATURE_LEVEL *pFeatureLevels,
  __in   UINT FeatureLevels,
  __in   UINT SDKVersion,
  __in   const DXGI_SWAP_CHAIN_DESC *pSwapChainDesc,
  __out  IDXGISwapChain **ppSwapChain,
  __out  ID3D11Device **ppDevice,
  __out  D3D_FEATURE_LEVEL *pFeatureLevel,
  __out  ID3D11DeviceContext **ppImmediateContext
);

pAdapter
Represents the video card to be used when creating the device, or NULL if the default video card is used. By enumeration method of graphics IDXGIFactory1: namely: EnumAdapters enumeration to the first video card.
DriverType
Represents the type of driver to create, the D3D_DRIVER_TYPE enumeration type. Use D3D_DRIVER_TYPE_HARDWARE to indicate that D3D functions will be implemented using hardware, which is the primary way for D3D applications, since it performs best.
Software
This is a handle to a DLL for rasterizing software. If DriverType is set to D3D_DRIVER_TYPE_SOFTWARE, this value cannot be set to NULL; Otherwise, it can be NULL. The handle can be obtained by the functions LoadLibrary, LoadLibraryEx, or GetModuleHandle.
Flags
Represents the result of one or more operations of type D3D11_CREATE_DEVICE_FLAG. It represents the runtime layer to enable.
pFeatureLevels
Represents a pointer to the D3D_FEATURE_LEVEL enumeration array, which determines which feature level is used to create the device. Setting NULL means the highest level of functionality is used.
FeatureLevels
Number of elements in the pFeatureLevels array. Set to NULL
SDKVersion
Version number of DirectX SDK, set to D3D11_SDK_VERSION
pSwapChainDesc
A pointer to the exchange chain (DXGI_SWAP_CHAIN_DESC), created earlier, which contains the initialization parameters for the exchange chain.
ppSwapChain[out]
Returns the address of a pointer to the IDXGISwapChain object, representing the swap chain to render.
ppDevice[out]
Returns the address of an ID3D11Device object pointer, representing the device that has been created. If this parameter is set to NULL, then no ID3D11Device device is returned.
pFeatureLevel[out]
Returns a pointer to D3D_FEATURE_LEVLE, which represents the first element in the feature-level array supported by the device. (Function levels are used for backward compatibility)
ppImmediateContext[out]
Returns the address of an ID3D11DeviceContext (device context) pointer. The device context will be used in the device’s rendering method to support multithreading to improve performance.

hr = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, NULL, NULL, NULL,
    D3D11_SDK_VERSION, &swapChainDesc, &SwapChain, &d3d11Device, NULL, &d3d11DevCon);

Create post-buffer:
(GetBuffer())
Create a buffer before creating the render target view. Call the GetBuffer method of the SwapChain interface.

HRESULT GetBuffer(
  [in]       UINT Buffer,
  [in]       REFIID riid,
  [in, out]  void **ppSurface
);

Buffer
Is a buffered index number starting at 0.
Because I’ve already set swapchaindesc. SwapEffect to dxGI_swap_effect_effect, I can only access the first buffer, so the index is set to 0.
If swapchaindesc. SwapEffect is set to DXGI_SWAP_EFFECT_SEQUENTIAL or DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, only the 0 buffer of the swap chain can be read and written, and only buffers larger than 0 can be read. So if you call the IDXGIResource::GetUsage method on this buffer, you must set the flag DXGI_USAGE_READ_ONLY.
riid
The interface type used to manipulate the buffer is 2d texture (ID3D11Texture2D).
ppSurface
This is a pointer to the post-buffered interface and is the window to be rendered.

ID3D11Texture2D* BackBuffer;
hr = SwapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), (void**)&BackBuffer );

Create render target view:

(ID3D11Device::CreateRenderTargetView())
Create the render target view, which will be sent to the output merge phase of the pipeline. The render target view is created by calling the CreateRenderTargetView method of the device interface

HRESULT CreateRenderTargetView(
  [in]   ID3D11Resource *pResource,
  [in]   const D3D11_RENDER_TARGET_VIEW_DESC *pDesc,
  [out]  ID3D11RenderTargetView **ppRTView
);

pResource [in]
Represents the render target, which points to an ID3D11Resource. The resource must have been created using the flag D3D11_BIND_RENDER_TARGET.
pDesc [in]
Represents the render target view descriptor. A pointer to the D3D11_RENDER_TARGET_VIEW_DESC structure. The view created when set to NULL will access all subresources with bitmap mapping level 0.
ppRTView[out,optional]
Pointing to the address of the pointer to the interface ID3D11RenderTargetView structure, setting this parameter to NULL will validate the other output parameters (this method will return S_FALSE if the other input parameters pass validation)
Post-release buffering

hr = d3d11Device->CreateRenderTargetView( BackBuffer, NULL, &renderTargetView );
BackBuffer->Release();

Set the render target
(ID3D11DeviceContext: : OMSetRenderTargets ())
The last thing to do in initialization is to bind the render target view and the depth template buffer to the pipeline’s output blending phase. But since the depth template buffer has not been created yet, set this parameter to NULL.

void OMSetRenderTargets(
  [in]  UINT NumViews,
  [in]  ID3D11RenderTargetView *const **ppRenderTargetViews,
  [in]  ID3D11DepthStencilView *pDepthStencilView
);

NumViews[in]

There is only one render target to bind to. Its range is 0~D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT. If this parameter is non-zero, the number of entries in the array specified by ppRenderTargetViews must be equal to this parameter.
ppRenderTargetViews[in]
Points to the array of render target View ID3D11RenderTargetView to bind to the device. If this parameter is set to NULL and NumViews is 0, no render target is bound.
pDepthStencilView[in]
The depth template buffer pointer to bind to the device, which is not yet available, is set to NULL.
The maximum number of render targets that a device has activated is specified by a macro D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT in the header file D3D11.h.

At this point, all the basic Direct3D 11 initialization has been completed.

d3d11DevCon->OMSetRenderTargets( 1, &renderTargetView, NULL );

Clean up recovered resources
ReleaseObjects() releases the COM object created, which will leak memory if forgotten.

void ReleaseObjects()
{
    //Release the COM Objects we created
    SwapChain->Release();
    d3d11Device->Release();
    d3dDevCon->Release();
}

Initialization scenario
InitScene() is used to initialize the scene. Within a video game, there are many different scenarios that can be renamed using the function InitScene. You can do the necessary things in the scene, such as placing objects, loading models, textures, sounds, etc.

bool InitScene()
{

    return true;
}

Update scenarios

Use the UpdateScene function to update the scene, such as changing object position, changing color values, etc. Anything that needs to be changed in the scene can be done here. In this case, you just change the background color of the scene.

void UpdateScene()
{
    //Update the colors of our scene
    red += colormodr * 0.00005f;
    green += colormodg * 0.00002f;
    blue += colormodb * 0.00001f;

    if(red >= 1.0f || red <= 0.0f)
        colormodr *= -1;
    if(green >= 1.0f || green <= 0.0f)
        colormodg *= -1;
    if(blue >= 1.0f || blue <= 0.0f)
        colormodb *= -1;
}

Render the scene

Render the scene using the DrawScene function, in which you do nothing to update the scene, make sure that the function only draws the scene. With earlier DirectX versions, such as Direct 10, all the rendering-related methods have been moved to the device context interface, so you should call the d3dDeviceContext object to get the ClearRenderTargetView method, rather than a d3dDevice object like the one used in Direct 10 to get it. But you can also use the d3dDevice object to call methods that are not related to rendering to do GPus related things. Finally, the Present method of the exchange link port is called to render the scenario. So here’s the buffer before and after swap, and in the drawScene method, it’s rendered to the buffer after, which then calls the Present method to render the content.

void DrawScene()
{
    //Clear our backbuffer to the updated color
    D3DXCOLOR bgColor( red, green, blue, 1.0f );

    d3d11DevCon->ClearRenderTargetView(renderTargetView, bgColor);

    //Present the backbuffer to the screen
    SwapChain->Present(0, 0);
}

in the messageloop function calls the UpdateScene() function to update the scene data, and then calls the DrawScene() function to draw the buffer to be rendered to the screen

int messageloop(){
MSG msg;
ZeroMemory(&msg, sizeof(MSG));
while(true)
{
    BOOL PeekMessageL( 
        LPMSG lpMsg,
        HWND hWnd,
        UINT wMsgFilterMin,
        UINT wMsgFilterMax,
        UINT wRemoveMsg
        );

    if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
    {
        if (msg.message == WM_QUIT)
            break;
        TranslateMessage(&msg);    
        DispatchMessage(&msg);
    }
    else{
///**************new**************
        // run game code
        
        UpdateScene();
        DrawScene();
        
///**************new**************
    }
}
return msg.wParam;
}

Error detection:
The application may continue to run even if the function fails, in which case using error detection in the code saves debugging time. When the function returns, the value of the HRESULT can be detected to determine how the code is running.
S_OK
Function returns success
E_NOTIMPL
The function is not implemented
E_NOINTERFACE
Interface not supported
E_ABORT
Abnormal function
E_FAIL
Function failure
E_INVALIDARG
More than one parameter is invalid
You can display the value of the error code by calling the function DXGetErrorDescription(HRESULT HRESULT). To use this function, you need the link library “DXErr. Lib “and the header file “DXErr. H”.
Here is the function InitializeDirect3d11App() with error detection :(when the error box pops up, you can set it to window mode before displaying the message if you want to leave it in full screen.)

#pragma comment (lib, "DXErr.lib")
#include <DXErr.h>

...

bool InitializeDirect3d11App(HINSTANCE hInstance)
{
    HRESULT hr;

    //Describe our Buffer
    DXGI_MODE_DESC bufferDesc;

    ZeroMemory(&bufferDesc, sizeof(DXGI_MODE_DESC));

    bufferDesc.Width = Width;
    bufferDesc.Height = Height;
    bufferDesc.RefreshRate.Numerator = 60;
    bufferDesc.RefreshRate.Denominator = 1;
    bufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    bufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
    bufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
    
    //Describe our SwapChain
    DXGI_SWAP_CHAIN_DESC swapChainDesc; 
        
    ZeroMemory(&swapChainDesc, sizeof(DXGI_SWAP_CHAIN_DESC));

    swapChainDesc.BufferDesc = bufferDesc;
    swapChainDesc.SampleDesc.Count = 1;
    swapChainDesc.SampleDesc.Quality = 0;
    swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    swapChainDesc.BufferCount = 1;
    swapChainDesc.OutputWindow = hwnd; 
    swapChainDesc.Windowed = TRUE; 
    swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;


    //Create our SwapChain
    hr = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, NULL, NULL, NULL,
        D3D11_SDK_VERSION, &swapChainDesc, &SwapChain, &d3d11Device, NULL, &d3d11DevCon);
    if(FAILED(hr))
    {    
        MessageBox(NULL, DXGetErrorDescription(hr),
            TEXT(" D3D11CreateDeviceAndSwapChain"), MB_OK);    
        return 0;    
    }    

    //Create our BackBuffer
    ID3D11Texture2D* BackBuffer;
    hr = SwapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), (void**)&BackBuffer );
    if(FAILED(hr))
    {    
        MessageBox(NULL, DXGetErrorDescription(hr),
            TEXT("SwapChain->GetBuffer"), MB_OK);    
        return 0;    
    }    

    //Create our Render Target
    hr = d3d11Device->CreateRenderTargetView( BackBuffer, NULL, &renderTargetView );
    BackBuffer->Release();
    if(FAILED(hr))
    {    
        MessageBox(NULL, DXGetErrorDescription(hr),
            TEXT("d3d11Device->CreateRenderTargetView"), MB_OK);    
        return 0;    
    }    

    //Set our Render Target
    d3d11DevCon->OMSetRenderTargets( 1, &renderTargetView, NULL );

    return true;
}

An instance of creating double buffering is as follows:

#include "stdafx.h"
#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "d3dx11.lib")
#pragma comment(lib, "d3dx10.lib")

#include <windows.h>
#include "Resource.h"
#include <d3d11.h>
#include <d3dx11.h>
#include <d3dx10.h>
#include <xnamath.h>

//全局描述符
IDXGISwapChain* SwapChain;
ID3D11Device* d3d11Device;
ID3D11DeviceContext* d3d11DevCon;
ID3D11RenderTargetView* renderTargetView;

float red = 0.0f;
float green = 0.0f;
float blue = 0.0f;
int colormodr = 1;
int colormodg = 1;
int colormodb = 1;

/
LPCTSTR WndClassName = "firstwindow";
HWND hwnd = NULL;

const int Width = 800; //设置宽
const int Height = 800; // 设置高
//函数声明
bool InitializeDirect3d11App(HINSTANCE hInstance);
void ReleaseObjects();
bool InitScene();
void UpdateScene();
void DrawScene();

// 初始化窗口
bool InitializeWindow(HINSTANCE hInstance,
	int ShowWnd,
	int width, int height,
	bool windowed);

//初始化消息循环函数
int messageloop();
//初始化窗口回调过程。Windows API是事件驱动型的编程模型。在该函数中捕获Windows消息,比如一个按键按下(也叫事件)以及程序操作流程。

LRESULT CALLBACK WndProc(HWND hWnd,
	UINT msg,
	WPARAM wParam,
	LPARAM lParam);

//主函数,传入应用程序句柄hInstance,前一个应用程序句柄hPrevInstance,传给函数处理的命令行lpCmdLine以及窗口显示方式的nShowCmd
int WINAPI WinMain(HINSTANCE hInstance,
	HINSTANCE hPrevInstance,
	LPSTR lpCmdLine,
	int nShowCmd)
{
	//创建并注册窗口
	if (!InitializeWindow(hInstance, nShowCmd, Width, Height, true))
	{
		MessageBox(0, "Window Initilization - Failed", "Error", MB_OK);
		return 0;
	}

	/new
	if (!InitializeDirect3d11App(hInstance)) // 初始化D3D
	{
		MessageBox(0, "Direct3D Initialization - Failed", "Error", MB_OK);
		return 0;
	}

	if (!InitScene)
	{
		MessageBox(0, "Scene Initialization - Failed", "Error", MB_OK);
		return 0;
	}
	
	messageloop();

	ReleaseObjects();

	return 0;
}
// windowed 若为true则为窗口模式显示,若为false则为全屏模式显示
bool InitializeWindow(HINSTANCE hInstance,
	int ShowWnd,
	int width, int height,
	bool windowed)
{
	/*typedef struct _WNDCLASS{
		UINT cbSize;
		UINT style;
		WNDPROC lpfnWndProc;
		int cbClsExtra;
		int cbWndExtra;
		HANDLE hInstance;
		HICON hIcon;
		HCURSOR hCursor;
		HBRUSH hbrBackground;
		LPCTSTR lpszMenuName;
		LPCTSTR lpszClassName;
	}WNDCLASS;
	*/
	WNDCLASSEX wc;
	wc.cbSize = sizeof(WNDCLASSEX); //window类的大小
	/********windows类风格
	*CS_CLASSDC 一个使用该类创建的在所有窗口间共享的设备上下文
	*CS_DBLCLKS 在窗口上使能双击功能
	*CS_HREDRAW 若窗口的宽度有改变或者窗口水平地移动,窗口将会刷新
	*CS_NOCLOSE 窗口菜单上禁止关闭选项
	*CS_OWNDC   为每个窗口创建自己的设备上下文。正好与CS_CLASSDC相反
	*CS_PARENTDC 这会设置创建的子窗口的剪裁四边形到父窗口,这允许子窗口能够在父窗口上绘画
	*CS_VERDRAW 若在窗口的高度或窗口在垂直方向有移动窗口会重绘
	**/
	wc.style = CS_HREDRAW | CS_VREDRAW;
	//lpfnWndProc是一个指向处理窗口消息函数的指针,设置窗口处理函数的函数名WndProc
	wc.lpfnWndProc = WndProc;
	//cbClsExtra是WNDCLASSEX之后额外申请的字节数
	wc.cbClsExtra = NULL;
	//cbWndExtra指定窗口实例之后所申请的字节数
	wc.cbWndExtra = NULL;
	//当前窗口应用程序的句柄,通过给函数GetModuleHandle()函数第一个参数传入NULL可获取当前窗口应用程序。
	wc.hInstance = hInstance;

	//hIcon用来指定窗口标题栏左上角的图标。以下是一些标准图标:
	/*
	*IDI_APPLICATION 默认应用程序图标
	*IDI_HAND 手形状的图标
	*IDI_EXCLAMATION 感叹号图标
	*IDI_INFORMATION 星号图标
	*IDI_QUESTION 问号图标
	*IDI_WINLOGO 若使用的是XP则是默认应用程序图标,否则是窗口logo
	*/
	wc.hIcon = LoadIcon(NULL, (LPCTSTR)IDI_SMALL);

	/*定义光标图标
	*IDC_APPSTARTING 标准箭头以及小型沙漏光标
	*IDC_ARROW 标准箭头光标
	*IDC_CROSS 十字线光标
	*IDC_HAND 手型光标
	*IDC_NO 斜线圈光标
	*IDC_WAIT 沙漏光标
	*/
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	//hbrBackground是一个刷子的句柄,可使得背景黑色。
	wc.hbrBackground = (HBRUSH)(COLOR_BTNSHADOW + 2);
	//附加到窗口的菜单名字,不需要的话设置为NULL
	wc.lpszMenuName = NULL;
	//对类进行命名
	wc.lpszClassName = WndClassName;
	//指定任务栏的图标,使用上面的IDI_图标
	wc.hIconSm = LoadIcon(NULL, (LPCTSTR)IDI_MYICON);
	//注册类。若失败则会获得一个错误,若成功,则继续创建窗口
	if (!RegisterClassEx(&wc))
	{
		MessageBox(NULL, "Error registering class", "Error", MB_OK | MB_ICONERROR);
		return 1;
	}

	//创建窗口
	hwnd = CreateWindowEx(NULL, WndClassName, "Window Title", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, width,
		height, NULL, NULL, hInstance, NULL);

	if (!hwnd)
	{
		MessageBox(NULL, "Error registering class", "Error", MB_OK | MB_ICONERROR);
		return 1;
	}

	//BOOL ShowWindow(HWND hWnd, int nCmdShow);
	//BOOL UpdateWindow(HWND hWnd);

	ShowWindow(hwnd, ShowWnd);
	UpdateWindow(hwnd);// 发送WM_PAINT消息到窗口过程,若窗口客户区没有任何东西要显示,则不发送消息。返回true,继续运行到mainloop中去。

	return true;
}

bool InitializeDirect3d11App(HINSTANCE hInstance)
{
	//声明缓冲
	DXGI_MODE_DESC bufferDesc;

	ZeroMemory(&bufferDesc, sizeof(DXGI_MODE_DESC));

	bufferDesc.Width = Width;
	bufferDesc.Height = Height;
	bufferDesc.RefreshRate.Numerator = 60;
	bufferDesc.RefreshRate.Denominator = 1;
	bufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
	bufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
	bufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;

	//声明交换链
	DXGI_SWAP_CHAIN_DESC swapChainDesc;

	ZeroMemory(&swapChainDesc, sizeof(DXGI_SWAP_CHAIN_DESC));

	swapChainDesc.BufferDesc = bufferDesc;
	swapChainDesc.SampleDesc.Count = 1;
	swapChainDesc.SampleDesc.Quality = 0;
	swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
	swapChainDesc.BufferCount = 1;
	swapChainDesc.OutputWindow = hwnd;
	swapChainDesc.Windowed = TRUE;
	swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;


	//创建交换链
	D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, NULL, NULL, NULL,
		D3D11_SDK_VERSION, &swapChainDesc, &SwapChain, &d3d11Device, NULL, &d3d11DevCon);

	//创建后缓冲
	ID3D11Texture2D* BackBuffer;
	SwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&BackBuffer);

	//创建渲染目标
	d3d11Device->CreateRenderTargetView(BackBuffer, NULL, &renderTargetView);
	BackBuffer->Release();

	//设置渲染目标
	d3d11DevCon->OMSetRenderTargets(1, &renderTargetView, NULL);

	return true;
}

void ReleaseObjects()
{
//释放创建的COM对象
	SwapChain->Release();
	d3d11Device->Release();
	d3d11DevCon->Release();
}

bool InitScene()
{
	return true;
}

void UpdateScene()
{
	// 更新场景颜色
	red += colormodr * 0.00005f;
	green += colormodg * 0.00002f;
	blue += colormodb * 0.00001f;

	if (red >= 1.0f || red <= 0.0f)
		colormodr *= -1;
	if (green >= 1.0f || green <= 0.0f)
		colormodg *= -1;
	if (blue >= 1.0f || blue <= 0.0f)
		colormodb *= -1;
}

void DrawScene()
{
	//将更新的颜色填充后缓冲
	D3DXCOLOR bgColor(red, green, blue, 1.0f);
	d3d11DevCon->ClearRenderTargetView(renderTargetView, bgColor);

	//将后缓冲呈现到屏幕
	SwapChain->Present(0, 0);
}

int messageloop(){
	MSG msg;
	ZeroMemory(&msg, sizeof(MSG));//清除结构体被设为NULL。

	while (true){
		//使用PeekMessage()检查是否有消息传进来
		/*LPMSG lpMsg 消息结构体的指针
		*HWND hWnd 发送消息的窗口句柄。若设为NULL,那么它会从当前程序中接收来自任何一个窗口的消息
		*UINT wMsgFilterMin 指定消息范围内第一个要检查的消息的值。若wMsgFilterMin和wMsgFilterMax都设为0,那么PeekMessage将会检查素有的消息
		*UINT wMsgFilterMax 指定消息范围内最后一个要检测的消息的值
		*UINT wRemoveMsg 指定消息的处理方式。若设置为PM_REMOVE,则在读取之后会被删除
		*/
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			if (msg.message == WM_QUIT)
			{
				break;
			}
			//若消息为窗口消息,则解析并分发它。TranslateMessage()将会让窗口做一些解析,类似键盘的虚拟键值转换到字符形式。
			//而DispatchMessage()则发送消息到窗口过程WndProc。
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		else //若没有窗口消息,则运行游戏
		{
			 // run game code
			UpdateScene();
			DrawScene();
		}
	}
	return msg.wParam;
}

//窗口消息处理函数
//HWND hwnd 获取消息的窗口句柄
//UINT msg 消息的内容
/*
*WM_ACTIVE 当窗口激活时发送的消息
*WM_CLOSE 当窗口关闭时发送的消息
*WM_CREATE 当窗口创建时发送的消息
*WM_DESTROY 当窗口销毁时发送的消息
*/
//wParam和lParam时消息的额外信息。使用wParam来检测键盘输入消息
LRESULT CALLBACK WndProc(HWND hwnd,
	UINT msg,
	WPARAM wParam,
	LPARAM lParam
	)
{
	// 这是事件检测消息的地方,若escape键被按下,会显示一个消息框,询问是否真的退出。若点击yes,则程序关闭。若不点击,则消息框关闭。若消息包含WM_DESTROY
	// 则意味着窗口正在被销毁,返回0并且程序关闭
	switch (msg)
	{
	case WM_KEYDOWN:
		if (wParam == VK_ESCAPE)
		{
			if (MessageBox(0, "Are you sure you want to exit?",
				"Really?", MB_YESNO | MB_ICONASTERISK) == IDYES)
			{
				DestroyWindow(hwnd);
			}
			return 0;

		}
		break;

	case WM_DESTROY:
		PostQuitMessage(0);
		break;

	default:
		break;
	}

	//调用默认窗口过程函数
	return DefWindowProc(hwnd,
		msg,
		wParam,
		lParam);
}

DirectX SDK development kit can be downloaded from the official website
Refer to the website
The effects are as follows:

Introduction to flow chart: