DirectX教程(8):全屏显示

  使游戏全屏显示很容易,但是需要更改程序的一些细节,并添加几行代码。在本节中,我们将介绍两件事:首先,我们将介绍如何全球化你的屏幕分辨率以及为什么要这样做;其次,我们将介绍如何使窗口进行全屏模式并再次返回的机制。

设置屏幕尺寸

  在你的DirectX游戏编程中,你会遇到许多需要了解屏幕尺寸的函数和结构体。当你决定更改分辨率,尤其是当你决定在运行时更改分辨率时,这可能会很麻烦。现在,我们将介绍一种简单的方法来标准化程序中的屏幕大小。
  首先,我们必须早程序顶部添加两个指令,它们代表屏幕的宽度和高度。

// 定义屏幕分辨率
#define SCREEN_WIDTH  800
#define SCREEN_HEIGHT 600

  下一步是遍历程序,指示窗口的宽度和高度。到本教程目前为止,你只有两个地方需要修改。对代码执行如下操作:

hWnd = CreateWindowEx(NULL,
                      L"WindowClass",
                      L"Our Direct3D Program",
                      WS_OVERLAPPEDWINDOW,
                      300, 300,
                      SCREEN_WIDTH, SCREEN_HEIGHT,    // 将窗口设置为新的分辨率
                      NULL,
                      NULL,
                      hInstance,
                      NULL);
viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
viewport.Width = SCREEN_WIDTH; // 设置新的宽度
viewport.Height = SCREEN_HEIGHT; //设置新的高度

  在下一节中,我们将介绍在运行时更改屏幕后如何在整个游戏中保持屏幕尺寸。大多数PC都有特定的分辨率,下表中可以找到最常见的分辨率。
常见PC的分辨率

更改为全屏模式

  尽管几乎所有主要的游戏都以全屏模式播放,但许多游戏都具有在全屏和窗口模式之间切换的功能。虽然我们默认情况下希望全屏显示,但我们也希望用户能够在全屏和窗口之间轻松切换(通常使用Alt+Enter键完成)。当切换到全屏模式时,我们需要做以下几件事:1、修改窗口使其没有背景;2、将后台缓冲区设置为特定大小;3、将DirectX设置为在使用Alt-Enter时自动切换;4、修改CleanD3D()函数,使其在关闭时进行全屏关闭。

1、修改窗口使其没有背景

  要删除窗口的背景,我们需要注释掉WINDOWCLASSEX结构的hbrBackground成员,该成员用于设置背景wc.hbrBackground = (HBRUSH)COLOR_WINDOW;。这样做会使背景保持不变,这意味着在游戏开始前一两秒钟只显示背景而不会显示为窗口(这使得游戏看起来很专业)

2、将后台缓冲区设置为特定大小

  接下来,我们必须告诉DirectX我们新的屏幕分辨率。为此,我们对上一节中构建的scd结构进行一些更改:

void initD3D(HWND hWnd)
{
    DXGI_SWAP_CHAIN_DESC scd;    // create a struct to hold various swap chain information

    ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC));    // clear out the struct for use

    scd.BufferCount = 1;                                    // one back buffer
    scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;     // use 32-bit color
    scd.BufferDesc.Width = SCREEN_WIDTH;                    // 设置后缓冲区宽度
    scd.BufferDesc.Height = SCREEN_HEIGHT;                  // 设置后缓冲区高度
    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 = 1;                               // how many multisamples
    scd.SampleDesc.Quality = 0;                             // multisample quality level
    scd.Windowed = TRUE;                                    // windowed/full-screen mode

    // ...

3、将DirectX设置为在使用Alt-Enter时自动切换

  这一步很简单,我们需要做的就是在scd结构中添加一个标志,并将该标志放入DXGI_SWAP_CHAIN_DESC结构体的Flags成员中。

void initD3D(HWND hWnd)
{
    DXGI_SWAP_CHAIN_DESC scd;    // create a struct to hold various swap chain information

    ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC));    // clear out the struct for use

    scd.BufferCount = 1;                                    // one back buffer
    scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;     // use 32-bit color
    scd.BufferDesc.Width = SCREEN_WIDTH;                    // set the back buffer width
    scd.BufferDesc.Height = SCREEN_HEIGHT;                  // set the back buffer height
    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 = 1;                               // how many multisamples
    scd.SampleDesc.Quality = 0;                             // multisample quality level
    scd.Windowed = TRUE;                                    // windowed/full-screen mode
    scd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;     // 允许全屏切换
    // ...

4、修改CleanD3D()函数,使其在关闭时进行全屏关闭

  在全屏模式下,Direct3D实际上无法关闭,这是由于在后台发生的某些线程问题,要正确关闭,我们必须确保我们处于窗口模式。我们可以使用SetFullscreenState()函数来做到这一点。

// this is the function that cleans up Direct3D and COM
void CleanD3D(void)
{
    swapchain->SetFullscreenState(FALSE, NULL);    // 切换到窗口模式

    // close and release all existing COM objects
    swapchain->Release();
    backbuffer->Release();
    dev->Release();
    devcon->Release();
}

  SetFullscreenState()函数的第一个参数是你希望切换到的转态,FALSE表示窗口模式,而TRUE表示全屏模式。第二个参数是一项功能,可以让你选择要使用的视频适配器,对于使用多个显示器的特殊场景,这将很有用。但是,对于几乎所有游戏,你都可以设置为NULL,它将自动选择正确的适配器。

最终程序

// include the basic windows header files and the Direct3D header files
#include <windows.h>
#include <windowsx.h>
#include <d3d11.h>
#include <d3dx11.h>
#include <d3dx10.h>

// include the Direct3D Library file
#pragma comment (lib, "d3d11.lib")
#pragma comment (lib, "d3dx11.lib")
#pragma comment (lib, "d3dx10.lib")

// define the screen resolution
#define SCREEN_WIDTH  800
#define SCREEN_HEIGHT 600

// global declarations
IDXGISwapChain *swapchain;             // the pointer to the swap chain interface
ID3D11Device *dev;                     // the pointer to our Direct3D device interface
ID3D11DeviceContext *devcon;           // the pointer to our Direct3D device context
ID3D11RenderTargetView *backbuffer;    // the pointer to our back buffer

// function prototypes
void InitD3D(HWND hWnd);    // sets up and initializes Direct3D
void RenderFrame(void);     // renders a single frame
void CleanD3D(void);        // closes Direct3D and releases memory

// 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)
{
    HWND hWnd;
    WNDCLASSEX wc;

    ZeroMemory(&wc, sizeof(WNDCLASSEX));

    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 = L"WindowClass";

    RegisterClassEx(&wc);

    RECT wr = {0, 0, SCREEN_WIDTH, SCREEN_HEIGHT};
    AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE);

    hWnd = CreateWindowEx(NULL,
                          L"WindowClass",
                          L"Our First Direct3D Program",
                          WS_OVERLAPPEDWINDOW,
                          300,
                          300,
                          wr.right - wr.left,
                          wr.bottom - wr.top,
                          NULL,
                          NULL,
                          hInstance,
                          NULL);

    ShowWindow(hWnd, nCmdShow);

    // set up and initialize Direct3D
    InitD3D(hWnd);

    // enter the main loop:

    MSG msg;

    while(TRUE)
    {
        if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);

            if(msg.message == WM_QUIT)
                break;
        }

        RenderFrame();
    }

    // clean up DirectX and COM
    CleanD3D();

    return msg.wParam;
}


// this is the main message handler for the program
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch(message)
    {
        case WM_DESTROY:
            {
                PostQuitMessage(0);
                return 0;
            } break;
    }

    return DefWindowProc (hWnd, message, wParam, lParam);
}


// 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.BufferDesc.Width = SCREEN_WIDTH;                    // set the back buffer width
    scd.BufferDesc.Height = SCREEN_HEIGHT;                  // set the back buffer height
    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
    scd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;     // allow full-screen switching

    // create a device, device context and swap chain using the information in the scd struct
    D3D11CreateDeviceAndSwapChain(NULL,
                                  D3D_DRIVER_TYPE_HARDWARE,
                                  NULL,
                                  NULL,
                                  NULL,
                                  NULL,
                                  D3D11_SDK_VERSION,
                                  &scd,
                                  &swapchain,
                                  &dev,
                                  NULL,
                                  &devcon);


    // get the address of the back buffer
    ID3D11Texture2D *pBackBuffer;
    swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);

    // use the back buffer address to create the render target
    dev->CreateRenderTargetView(pBackBuffer, NULL, &backbuffer);
    pBackBuffer->Release();

    // set the render target as the back buffer
    devcon->OMSetRenderTargets(1, &backbuffer, NULL);


    // Set the viewport
    D3D11_VIEWPORT viewport;
    ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT));

    viewport.TopLeftX = 0;
    viewport.TopLeftY = 0;
    viewport.Width = SCREEN_WIDTH;
    viewport.Height = SCREEN_HEIGHT;

    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
    devcon->ClearRenderTargetView(backbuffer, D3DXCOLOR(0.0f, 0.2f, 0.4f, 1.0f));

    // do 3D rendering on the back buffer here

    // switch the back buffer and the front buffer
    swapchain->Present(0, 0);
}


// this is the function that cleans up Direct3D and COM
void CleanD3D(void)
{
    swapchain->SetFullscreenState(FALSE, NULL);    // switch to windowed mode

    // close and release all existing COM objects
    swapchain->Release();
    backbuffer->Release();
    dev->Release();
    devcon->Release();
}

  程序运行的结果就是一个带鼠标指针的蓝色矩形。

发布了19 篇原创文章 · 获赞 6 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/hjc132/article/details/104984574