2016-08-22 18:26:36 +00:00
//--------------------------------------------------------------------------------------
// File: DDSView.cpp
//
2022-03-28 00:29:48 +00:00
// DirectX 11 DDS File Viewer sample for DirectXTex
2016-08-22 18:26:36 +00:00
//
2021-02-27 06:59:42 +00:00
// Copyright (c) Microsoft Corporation.
2018-02-24 06:24:46 +00:00
// Licensed under the MIT License.
2016-08-22 18:26:36 +00:00
//--------------------------------------------------------------------------------------
# define WIN32_LEAN_AND_MEAN
# define NOMINMAX
2020-12-30 02:04:51 +00:00
# include <Windows.h>
2016-08-22 18:26:36 +00:00
# include <algorithm>
2020-12-30 02:04:51 +00:00
# include <cassert>
2022-03-28 00:29:48 +00:00
# include <cstddef>
# include <cstdint>
2020-12-30 02:04:51 +00:00
# include <cstdio>
2021-01-07 08:43:18 +00:00
# include <cwchar>
2022-03-28 00:29:48 +00:00
# include <iterator>
# include <tuple>
2020-12-30 02:04:51 +00:00
# include <dxgiformat.h>
# include <d3d11_1.h>
2016-08-22 18:26:36 +00:00
2020-12-30 02:04:51 +00:00
# include <DirectXMath.h>
2016-08-22 18:26:36 +00:00
2024-04-09 14:15:56 +00:00
# ifdef _MSC_VER
2019-10-24 23:55:13 +00:00
# pragma warning(disable : 4619 4616 26812)
2024-04-09 14:15:56 +00:00
# endif
2019-10-24 23:55:13 +00:00
2016-08-22 18:26:36 +00:00
# include "DirectXTex.h"
2023-01-19 19:18:39 +00:00
# include <shellapi.h>
2016-08-22 18:26:36 +00:00
using namespace DirectX ;
//--------------------------------------------------------------------------------------
# define IDI_MAIN_ICON 100
//--------------------------------------------------------------------------------------
# pragma pack(push,1)
struct SimpleVertex
{
XMFLOAT4 Pos ;
XMFLOAT4 Tex ;
} ;
struct CBArrayControl
{
float Index ;
float pad [ 3 ] ;
} ;
# pragma pack(pop)
//--------------------------------------------------------------------------------------
2022-03-28 00:29:48 +00:00
namespace
{
2022-03-28 06:03:24 +00:00
# include "ddsview_vs.inc"
# include "ddsview_ps1D.inc"
# include "ddsview_ps1Darray.inc"
# include "ddsview_ps2D.inc"
# include "ddsview_ps2Darray.inc"
# include "ddsview_ps3D.inc"
# include "ddsview_psCube.inc"
2022-03-28 00:29:48 +00:00
}
2016-08-22 18:26:36 +00:00
//--------------------------------------------------------------------------------------
2022-03-28 00:29:48 +00:00
namespace
{
HINSTANCE g_hInst = nullptr ;
HWND g_hWnd = nullptr ;
D3D_DRIVER_TYPE g_driverType = D3D_DRIVER_TYPE_NULL ;
D3D_FEATURE_LEVEL g_featureLevel = D3D_FEATURE_LEVEL_11_0 ;
2023-01-19 19:18:39 +00:00
ID3D11Device * g_pd3dDevice = nullptr ;
ID3D11DeviceContext * g_pImmediateContext = nullptr ;
IDXGISwapChain * g_pSwapChain = nullptr ;
ID3D11RenderTargetView * g_pRenderTargetView = nullptr ;
ID3D11Texture2D * g_pDepthStencil = nullptr ;
ID3D11DepthStencilView * g_pDepthStencilView = nullptr ;
ID3D11VertexShader * g_pVertexShader = nullptr ;
ID3D11PixelShader * g_pPixelShader = nullptr ;
ID3D11InputLayout * g_pVertexLayout = nullptr ;
ID3D11Buffer * g_pVertexBuffer = nullptr ;
ID3D11Buffer * g_pIndexBuffer = nullptr ;
ID3D11Buffer * g_pCBArrayControl = nullptr ;
ID3D11ShaderResourceView * g_pSRV = nullptr ;
ID3D11BlendState * g_AlphaBlendState = nullptr ;
ID3D11SamplerState * g_pSamplerLinear = nullptr ;
2022-03-28 00:29:48 +00:00
UINT g_iCurrentIndex = 0 ;
UINT g_iMaxIndex = 1 ;
UINT g_iIndices = 0 ;
LPCWSTR g_szAppName = L " DDSView " ;
}
2016-08-22 18:26:36 +00:00
//--------------------------------------------------------------------------------------
2022-03-28 00:29:48 +00:00
HRESULT InitWindow ( HINSTANCE hInstance , int nCmdShow , const TexMetadata & mdata ) ;
HRESULT InitDevice ( const TexMetadata & mdata ) ;
2016-08-22 18:26:36 +00:00
void CleanupDevice ( ) ;
2022-03-28 00:29:48 +00:00
LRESULT CALLBACK WndProc ( HWND , UINT , WPARAM , LPARAM ) ;
2016-08-22 18:26:36 +00:00
void Render ( ) ;
//--------------------------------------------------------------------------------------
2024-04-09 14:15:56 +00:00
# ifdef _MSC_VER
2016-08-22 18:26:36 +00:00
# pragma warning( suppress : 6262 )
2024-04-09 14:15:56 +00:00
# endif
2022-03-28 00:29:48 +00:00
int WINAPI wWinMain (
_In_ HINSTANCE hInstance ,
_In_opt_ HINSTANCE /*hPrevInstance*/ ,
_In_ LPWSTR lpCmdLine ,
_In_ int nCmdShow )
2016-08-22 18:26:36 +00:00
{
2023-01-19 19:18:39 +00:00
static const wchar_t * c_usage = L " Usage: ddsview [-forcesrgb] <filename> " ;
2022-03-28 00:29:48 +00:00
if ( ! * lpCmdLine )
2016-08-22 18:26:36 +00:00
{
2023-01-19 19:18:39 +00:00
MessageBoxW ( nullptr , c_usage , g_szAppName , MB_OK | MB_ICONEXCLAMATION ) ;
2016-08-22 18:26:36 +00:00
return 0 ;
}
2023-01-19 19:18:39 +00:00
int argc = 0 ;
auto argList = CommandLineToArgvW ( lpCmdLine , & argc ) ;
const wchar_t * filename = nullptr ;
bool forceSRGB = false ;
for ( int i = 0 ; i < argc ; + + i )
{
if ( * argList [ i ] = = ' - ' | | * argList [ i ] = = ' / ' )
{
if ( _wcsicmp ( argList [ i ] + 1 , L " forcesrgb " ) = = 0 )
{
forceSRGB = true ;
}
}
else if ( ! filename )
{
filename = argList [ i ] ;
}
}
if ( ! filename )
{
MessageBoxW ( nullptr , c_usage , g_szAppName , MB_OK | MB_ICONEXCLAMATION ) ;
return 1 ;
}
2016-08-22 18:26:36 +00:00
TexMetadata mdata ;
2023-01-19 19:18:39 +00:00
HRESULT hr = GetMetadataFromDDSFile ( filename , DDS_FLAGS_NONE , mdata ) ;
2022-03-28 00:29:48 +00:00
if ( FAILED ( hr ) )
2016-08-22 18:26:36 +00:00
{
2018-01-18 23:02:05 +00:00
wchar_t buff [ 2048 ] = { } ;
2023-01-19 19:18:39 +00:00
swprintf_s ( buff , L " Failed to open texture file \n \n Filename = %ls \n HRESULT %08X " , filename , static_cast < unsigned int > ( hr ) ) ;
2022-03-28 00:29:48 +00:00
MessageBoxW ( nullptr , buff , g_szAppName , MB_OK | MB_ICONEXCLAMATION ) ;
2023-01-19 19:18:39 +00:00
return 1 ;
2016-08-22 18:26:36 +00:00
}
2022-03-28 00:29:48 +00:00
if ( FAILED ( InitWindow ( hInstance , nCmdShow , mdata ) ) )
2023-01-19 19:18:39 +00:00
return 1 ;
2016-08-22 18:26:36 +00:00
2023-01-19 19:18:39 +00:00
SetWindowTextW ( g_hWnd , filename ) ;
2016-08-22 18:26:36 +00:00
2022-03-28 00:29:48 +00:00
if ( FAILED ( InitDevice ( mdata ) ) )
2016-08-22 18:26:36 +00:00
{
CleanupDevice ( ) ;
2023-01-19 19:18:39 +00:00
return 1 ;
2016-08-22 18:26:36 +00:00
}
if ( mdata . dimension = = TEX_DIMENSION_TEXTURE3D )
{
2022-03-28 00:29:48 +00:00
if ( mdata . arraySize > 1 )
2016-08-22 18:26:36 +00:00
{
2018-01-18 23:02:05 +00:00
wchar_t buff [ 2048 ] = { } ;
2023-01-19 19:18:39 +00:00
swprintf_s ( buff , L " Arrays of volume textures are not supported \n \n Filename = %ls \n Array size %zu " , filename , mdata . arraySize ) ;
2022-03-28 00:29:48 +00:00
MessageBoxW ( nullptr , buff , g_szAppName , MB_OK | MB_ICONEXCLAMATION ) ;
2023-01-19 19:18:39 +00:00
return 1 ;
2016-08-22 18:26:36 +00:00
}
2022-03-28 00:29:48 +00:00
g_iMaxIndex = static_cast < UINT > ( mdata . depth ) ;
2016-08-22 18:26:36 +00:00
}
2022-03-28 00:29:48 +00:00
else if ( mdata . arraySize > 1 )
2016-08-22 18:26:36 +00:00
{
2022-03-28 00:29:48 +00:00
if ( g_featureLevel < D3D_FEATURE_LEVEL_10_0 )
{
wchar_t buff [ 2048 ] = { } ;
2023-01-19 19:18:39 +00:00
swprintf_s ( buff , L " Texture arrays require DirectX 10 hardware or later \n \n Filename = %ls \n Array size %zu " , filename , mdata . arraySize ) ;
2022-03-28 00:29:48 +00:00
MessageBoxW ( nullptr , buff , g_szAppName , MB_OK | MB_ICONEXCLAMATION ) ;
2023-01-19 19:18:39 +00:00
return 1 ;
2022-03-28 00:29:48 +00:00
}
g_iMaxIndex = static_cast < UINT > ( mdata . arraySize ) ;
2016-08-22 18:26:36 +00:00
}
2022-03-28 00:29:48 +00:00
switch ( mdata . format )
2016-08-22 18:26:36 +00:00
{
2022-03-28 00:29:48 +00:00
case DXGI_FORMAT_BC4_TYPELESS :
case DXGI_FORMAT_BC4_SNORM :
case DXGI_FORMAT_BC4_UNORM :
case DXGI_FORMAT_BC5_TYPELESS :
case DXGI_FORMAT_BC5_SNORM :
case DXGI_FORMAT_BC5_UNORM :
if ( g_featureLevel < D3D_FEATURE_LEVEL_10_0 )
{
wchar_t buff [ 2048 ] = { } ;
2023-01-19 19:18:39 +00:00
swprintf_s ( buff , L " BC4/BC5 requires DirectX 10 hardware or later \n \n Filename = %ls \n DXGI Format %d \n Feature Level %d " , filename , mdata . format , g_featureLevel ) ;
2022-03-28 00:29:48 +00:00
MessageBoxW ( nullptr , buff , g_szAppName , MB_OK | MB_ICONEXCLAMATION ) ;
2023-01-19 19:18:39 +00:00
return 1 ;
2022-03-28 00:29:48 +00:00
}
break ;
2016-08-22 18:26:36 +00:00
case DXGI_FORMAT_BC6H_TYPELESS :
case DXGI_FORMAT_BC6H_UF16 :
case DXGI_FORMAT_BC6H_SF16 :
case DXGI_FORMAT_BC7_TYPELESS :
case DXGI_FORMAT_BC7_UNORM :
case DXGI_FORMAT_BC7_UNORM_SRGB :
2022-03-28 00:29:48 +00:00
if ( g_featureLevel < D3D_FEATURE_LEVEL_11_0 )
2016-08-22 18:26:36 +00:00
{
2018-01-18 23:02:05 +00:00
wchar_t buff [ 2048 ] = { } ;
2023-01-19 19:18:39 +00:00
swprintf_s ( buff , L " BC6H/BC7 requires DirectX 11 hardware or later \n \n Filename = %ls \n DXGI Format %d \n Feature Level %d " , filename , mdata . format , g_featureLevel ) ;
2022-03-28 00:29:48 +00:00
MessageBoxW ( nullptr , buff , g_szAppName , MB_OK | MB_ICONEXCLAMATION ) ;
2023-01-19 19:18:39 +00:00
return 1 ;
2016-08-22 18:26:36 +00:00
}
break ;
default :
{
UINT flags = 0 ;
2022-03-28 00:29:48 +00:00
hr = g_pd3dDevice - > CheckFormatSupport ( mdata . format , & flags ) ;
constexpr UINT required = D3D11_FORMAT_SUPPORT_TEXTURE1D | D3D11_FORMAT_SUPPORT_TEXTURE2D | D3D11_FORMAT_SUPPORT_TEXTURE3D ;
if ( FAILED ( hr ) | | ! ( flags & required ) )
2016-08-22 18:26:36 +00:00
{
2018-01-18 23:02:05 +00:00
wchar_t buff [ 2048 ] = { } ;
2023-01-19 19:18:39 +00:00
swprintf_s ( buff , L " Format not supported by this DirectX hardware \n \n Filename = %ls \n DXGI Format %d \n Feature Level %d \n HRESULT = %08X " , filename , mdata . format , g_featureLevel , static_cast < unsigned int > ( hr ) ) ;
2022-03-28 00:29:48 +00:00
MessageBoxW ( nullptr , buff , g_szAppName , MB_OK | MB_ICONEXCLAMATION ) ;
2023-01-19 19:18:39 +00:00
return 1 ;
2016-08-22 18:26:36 +00:00
}
}
break ;
}
ScratchImage image ;
2023-01-19 19:18:39 +00:00
hr = LoadFromDDSFile ( filename , DDS_FLAGS_NONE , & mdata , image ) ;
2022-03-28 00:29:48 +00:00
if ( FAILED ( hr ) )
2016-08-22 18:26:36 +00:00
{
2018-01-18 23:02:05 +00:00
wchar_t buff [ 2048 ] = { } ;
2023-01-19 19:18:39 +00:00
swprintf_s ( buff , L " Failed to load texture file \n \n Filename = %ls \n HRESULT %08X " , filename , static_cast < unsigned int > ( hr ) ) ;
2022-03-28 00:29:48 +00:00
MessageBoxW ( nullptr , buff , g_szAppName , MB_OK | MB_ICONEXCLAMATION ) ;
2023-01-19 19:18:39 +00:00
return 1 ;
2016-08-22 18:26:36 +00:00
}
// Special case to make sure Texture cubes remain arrays
mdata . miscFlags & = ~ TEX_MISC_TEXTURECUBE ;
2023-01-19 19:18:39 +00:00
if ( forceSRGB )
{
mdata . format = MakeSRGB ( mdata . format ) ;
image . OverrideFormat ( mdata . format ) ;
}
2022-03-28 00:29:48 +00:00
hr = CreateShaderResourceView ( g_pd3dDevice , image . GetImages ( ) , image . GetImageCount ( ) , mdata , & g_pSRV ) ;
if ( FAILED ( hr ) )
2016-08-22 18:26:36 +00:00
{
2018-01-18 23:02:05 +00:00
wchar_t buff [ 2048 ] = { } ;
2023-01-19 19:18:39 +00:00
swprintf_s ( buff , L " Failed creating texture from file \n \n Filename = %ls \n HRESULT = %08X " , filename , static_cast < unsigned int > ( hr ) ) ;
2022-03-28 00:29:48 +00:00
MessageBoxW ( nullptr , buff , g_szAppName , MB_OK | MB_ICONEXCLAMATION ) ;
2023-01-19 19:18:39 +00:00
return 1 ;
2016-08-22 18:26:36 +00:00
}
// Main message loop
2018-01-18 23:02:05 +00:00
MSG msg = { } ;
2022-03-28 00:29:48 +00:00
while ( WM_QUIT ! = msg . message )
2016-08-22 18:26:36 +00:00
{
2022-03-28 00:29:48 +00:00
if ( PeekMessage ( & msg , nullptr , 0 , 0 , PM_REMOVE ) )
2016-08-22 18:26:36 +00:00
{
2022-03-28 00:29:48 +00:00
TranslateMessage ( & msg ) ;
DispatchMessage ( & msg ) ;
2016-08-22 18:26:36 +00:00
}
else
{
Render ( ) ;
}
}
CleanupDevice ( ) ;
2022-03-28 00:29:48 +00:00
return static_cast < int > ( msg . wParam ) ;
2016-08-22 18:26:36 +00:00
}
//--------------------------------------------------------------------------------------
2022-03-28 00:29:48 +00:00
HRESULT InitWindow (
HINSTANCE hInstance ,
int nCmdShow ,
const TexMetadata & mdata )
2016-08-22 18:26:36 +00:00
{
// Register class
2022-03-28 00:29:48 +00:00
WNDCLASSEXW wcex = { } ;
wcex . cbSize = sizeof ( WNDCLASSEXW ) ;
2016-08-22 18:26:36 +00:00
wcex . style = CS_HREDRAW | CS_VREDRAW ;
wcex . lpfnWndProc = WndProc ;
wcex . hInstance = hInstance ;
2022-03-28 00:29:48 +00:00
wcex . hIcon = LoadIconW ( hInstance , reinterpret_cast < LPCWSTR > ( IDI_MAIN_ICON ) ) ;
wcex . hCursor = LoadCursor ( nullptr , IDC_ARROW ) ;
wcex . hbrBackground = reinterpret_cast < HBRUSH > ( COLOR_WINDOW + 1 ) ;
2016-08-22 18:26:36 +00:00
wcex . lpszClassName = L " DDSViewWindowClass " ;
2022-03-28 00:29:48 +00:00
wcex . hIconSm = LoadIconW ( wcex . hInstance , reinterpret_cast < LPCWSTR > ( IDI_MAIN_ICON ) ) ;
if ( ! RegisterClassExW ( & wcex ) )
2016-08-22 18:26:36 +00:00
return E_FAIL ;
// Create window
g_hInst = hInstance ;
RECT rc = { 0 , 0 , 640 , 480 } ;
2022-03-28 00:29:48 +00:00
int cxborder = GetSystemMetrics ( SM_CXBORDER ) ;
int cxedge = GetSystemMetrics ( SM_CXEDGE ) ;
int screenX = GetSystemMetrics ( SM_CXSCREEN ) - std : : max ( cxborder , cxedge ) ;
if ( rc . right < static_cast < LONG > ( mdata . width ) )
rc . right = static_cast < LONG > ( mdata . width ) ;
if ( rc . right > screenX )
2016-08-22 18:26:36 +00:00
rc . right = screenX ;
2022-03-28 00:29:48 +00:00
int cyborder = GetSystemMetrics ( SM_CYBORDER ) ;
int cyedge = GetSystemMetrics ( SM_CYEDGE ) ;
int screenY = GetSystemMetrics ( SM_CYSCREEN ) - std : : max ( cyborder , cyedge ) ;
if ( rc . bottom < static_cast < LONG > ( mdata . height ) )
rc . bottom = static_cast < LONG > ( mdata . height ) ;
if ( rc . bottom > screenY )
2016-08-22 18:26:36 +00:00
rc . bottom = screenY ;
2022-03-28 00:29:48 +00:00
AdjustWindowRect ( & rc , WS_OVERLAPPEDWINDOW , FALSE ) ;
g_hWnd = CreateWindowW ( L " DDSViewWindowClass " , g_szAppName , WS_OVERLAPPEDWINDOW ,
CW_USEDEFAULT , CW_USEDEFAULT , rc . right - rc . left , rc . bottom - rc . top , nullptr , nullptr , hInstance ,
nullptr ) ;
if ( ! g_hWnd )
2016-08-22 18:26:36 +00:00
return E_FAIL ;
2022-03-28 00:29:48 +00:00
ShowWindow ( g_hWnd , nCmdShow ) ;
2016-08-22 18:26:36 +00:00
return S_OK ;
}
//--------------------------------------------------------------------------------------
2022-03-28 00:29:48 +00:00
LRESULT CALLBACK WndProc ( HWND hWnd , UINT message , WPARAM wParam , LPARAM lParam )
2016-08-22 18:26:36 +00:00
{
2022-03-28 00:29:48 +00:00
switch ( message )
2016-08-22 18:26:36 +00:00
{
2022-03-28 00:29:48 +00:00
case WM_PAINT :
{
PAINTSTRUCT ps ;
std : : ignore = BeginPaint ( hWnd , & ps ) ;
EndPaint ( hWnd , & ps ) ;
}
break ;
2016-08-22 18:26:36 +00:00
2022-03-28 00:29:48 +00:00
case WM_DESTROY :
PostQuitMessage ( 0 ) ;
break ;
2016-08-22 18:26:36 +00:00
2022-03-28 00:29:48 +00:00
case WM_KEYDOWN :
if ( wParam = = VK_RIGHT )
{
if ( g_iCurrentIndex < g_iMaxIndex - 1 )
+ + g_iCurrentIndex ;
}
else if ( wParam = = VK_LEFT )
{
if ( g_iCurrentIndex > 0 )
2016-08-22 18:26:36 +00:00
{
2022-03-28 00:29:48 +00:00
- - g_iCurrentIndex ;
2016-08-22 18:26:36 +00:00
}
2022-03-28 00:29:48 +00:00
}
else if ( wParam > = ' 0 ' & & wParam < = ' 9 ' )
{
UINT index = ( wParam = = ' 0 ' ) ? 10u : static_cast < UINT > ( wParam - ' 1 ' ) ;
if ( index < g_iMaxIndex )
g_iCurrentIndex = index ;
}
InvalidateRect ( hWnd , nullptr , FALSE ) ;
break ;
2016-08-22 18:26:36 +00:00
2022-03-28 00:29:48 +00:00
default :
return DefWindowProc ( hWnd , message , wParam , lParam ) ;
2016-08-22 18:26:36 +00:00
}
return 0 ;
}
//--------------------------------------------------------------------------------------
2022-03-28 00:29:48 +00:00
HRESULT InitDevice ( const TexMetadata & mdata )
2016-08-22 18:26:36 +00:00
{
HRESULT hr = S_OK ;
RECT rc ;
2022-03-28 00:29:48 +00:00
GetClientRect ( g_hWnd , & rc ) ;
auto width = static_cast < UINT > ( rc . right - rc . left ) ;
auto height = static_cast < UINT > ( rc . bottom - rc . top ) ;
2016-08-22 18:26:36 +00:00
UINT createDeviceFlags = 0 ;
# if defined( DEBUG ) || defined( _DEBUG )
createDeviceFlags | = D3D11_CREATE_DEVICE_DEBUG ;
# endif
D3D_DRIVER_TYPE driverTypes [ ] =
{
D3D_DRIVER_TYPE_HARDWARE ,
D3D_DRIVER_TYPE_WARP ,
D3D_DRIVER_TYPE_REFERENCE ,
} ;
2021-01-02 20:44:35 +00:00
constexpr UINT numDriverTypes = static_cast < UINT > ( std : : size ( driverTypes ) ) ;
2016-08-22 18:26:36 +00:00
D3D_FEATURE_LEVEL featureLevels [ ] =
{
D3D_FEATURE_LEVEL_11_0 ,
D3D_FEATURE_LEVEL_10_1 ,
D3D_FEATURE_LEVEL_10_0 ,
} ;
2021-01-02 20:44:35 +00:00
constexpr UINT numFeatureLevels = static_cast < UINT > ( std : : size ( featureLevels ) ) ;
2016-08-22 18:26:36 +00:00
2017-12-18 21:35:07 +00:00
DXGI_SWAP_CHAIN_DESC sd = { } ;
2016-08-22 18:26:36 +00:00
sd . BufferCount = 1 ;
sd . BufferDesc . Width = width ;
sd . BufferDesc . Height = height ;
sd . BufferDesc . Format = DXGI_FORMAT_R8G8B8A8_UNORM ;
sd . BufferDesc . RefreshRate . Numerator = 60 ;
sd . BufferDesc . RefreshRate . Denominator = 1 ;
sd . BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT ;
sd . OutputWindow = g_hWnd ;
sd . SampleDesc . Count = 1 ;
sd . Windowed = TRUE ;
2022-03-28 00:29:48 +00:00
for ( UINT driverTypeIndex = 0 ; driverTypeIndex < numDriverTypes ; driverTypeIndex + + )
2016-08-22 18:26:36 +00:00
{
g_driverType = driverTypes [ driverTypeIndex ] ;
2022-03-28 00:29:48 +00:00
// See https://walbourn.github.io/anatomy-of-direct3d-11-create-device/
hr = D3D11CreateDeviceAndSwapChain ( nullptr , g_driverType , nullptr ,
createDeviceFlags , featureLevels , numFeatureLevels ,
D3D11_SDK_VERSION , & sd ,
& g_pSwapChain , & g_pd3dDevice , & g_featureLevel , & g_pImmediateContext ) ;
if ( SUCCEEDED ( hr ) )
2016-08-22 18:26:36 +00:00
break ;
}
2022-03-28 00:29:48 +00:00
if ( FAILED ( hr ) )
2016-08-22 18:26:36 +00:00
return hr ;
// Create a render target view
ID3D11Texture2D * pBackBuffer = nullptr ;
2022-03-28 00:29:48 +00:00
hr = g_pSwapChain - > GetBuffer ( 0 , IID_PPV_ARGS ( & pBackBuffer ) ) ;
if ( FAILED ( hr ) )
2016-08-22 18:26:36 +00:00
return hr ;
2017-12-18 21:35:07 +00:00
D3D11_RENDER_TARGET_VIEW_DESC vd = { } ;
2017-12-18 21:27:20 +00:00
vd . ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D ;
vd . Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB ;
2022-03-28 00:29:48 +00:00
hr = g_pd3dDevice - > CreateRenderTargetView ( pBackBuffer , & vd , & g_pRenderTargetView ) ;
2016-08-22 18:26:36 +00:00
pBackBuffer - > Release ( ) ;
2022-03-28 00:29:48 +00:00
if ( FAILED ( hr ) )
2016-08-22 18:26:36 +00:00
return hr ;
// Create depth stencil texture
2017-12-18 21:35:07 +00:00
D3D11_TEXTURE2D_DESC descDepth = { } ;
2016-08-22 18:26:36 +00:00
descDepth . Width = width ;
descDepth . Height = height ;
descDepth . MipLevels = 1 ;
descDepth . ArraySize = 1 ;
descDepth . Format = DXGI_FORMAT_D24_UNORM_S8_UINT ;
descDepth . SampleDesc . Count = 1 ;
descDepth . Usage = D3D11_USAGE_DEFAULT ;
descDepth . BindFlags = D3D11_BIND_DEPTH_STENCIL ;
2022-03-28 00:29:48 +00:00
hr = g_pd3dDevice - > CreateTexture2D ( & descDepth , nullptr , & g_pDepthStencil ) ;
if ( FAILED ( hr ) )
2016-08-22 18:26:36 +00:00
return hr ;
// Create the depth stencil view
2017-12-18 21:35:07 +00:00
D3D11_DEPTH_STENCIL_VIEW_DESC descDSV = { } ;
2016-08-22 18:26:36 +00:00
descDSV . Format = descDepth . Format ;
descDSV . ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D ;
descDSV . Texture2D . MipSlice = 0 ;
2022-03-28 00:29:48 +00:00
hr = g_pd3dDevice - > CreateDepthStencilView ( g_pDepthStencil , & descDSV , & g_pDepthStencilView ) ;
if ( FAILED ( hr ) )
2016-08-22 18:26:36 +00:00
return hr ;
2022-03-28 00:29:48 +00:00
g_pImmediateContext - > OMSetRenderTargets ( 1 , & g_pRenderTargetView , g_pDepthStencilView ) ;
2016-08-22 18:26:36 +00:00
// Setup the viewport
2022-05-05 21:50:13 +00:00
const D3D11_VIEWPORT vp = { 0.f , 0.f , static_cast < float > ( width ) , static_cast < float > ( height ) , 0.f , 1.f } ;
2022-03-28 00:29:48 +00:00
g_pImmediateContext - > RSSetViewports ( 1 , & vp ) ;
2016-08-22 18:26:36 +00:00
// Create the vertex shader
2022-03-28 00:29:48 +00:00
hr = g_pd3dDevice - > CreateVertexShader ( g_VS , sizeof ( g_VS ) , nullptr , & g_pVertexShader ) ;
if ( FAILED ( hr ) )
2016-08-22 18:26:36 +00:00
return hr ;
// Define the input layout
D3D11_INPUT_ELEMENT_DESC layout [ ] =
{
{ " POSITION " , 0 , DXGI_FORMAT_R32G32B32A32_FLOAT , 0 , 0 , D3D11_INPUT_PER_VERTEX_DATA , 0 } ,
{ " TEXCOORD " , 0 , DXGI_FORMAT_R32G32B32A32_FLOAT , 0 , sizeof ( XMFLOAT4 ) , D3D11_INPUT_PER_VERTEX_DATA , 0 } ,
} ;
2021-01-02 20:44:35 +00:00
constexpr UINT numElements = static_cast < UINT > ( std : : size ( layout ) ) ;
2016-08-22 18:26:36 +00:00
// Create the input layout
2022-03-28 00:29:48 +00:00
hr = g_pd3dDevice - > CreateInputLayout ( layout , numElements , g_VS , sizeof ( g_VS ) , & g_pVertexLayout ) ;
if ( FAILED ( hr ) )
2016-08-22 18:26:36 +00:00
return hr ;
// Set the input layout
2022-03-28 00:29:48 +00:00
g_pImmediateContext - > IASetInputLayout ( g_pVertexLayout ) ;
2016-08-22 18:26:36 +00:00
// Select the pixel shader
bool isCubeMap = false ;
bool is1D = false ;
const BYTE * pshader = nullptr ;
size_t pshader_size = 0 ;
2022-03-28 00:29:48 +00:00
switch ( mdata . dimension )
2016-08-22 18:26:36 +00:00
{
case TEX_DIMENSION_TEXTURE1D :
2022-03-28 00:29:48 +00:00
if ( mdata . arraySize > 1 )
2016-08-22 18:26:36 +00:00
{
pshader = g_PS_1DArray ;
pshader_size = sizeof ( g_PS_1DArray ) ;
}
else
{
pshader = g_PS_1D ;
pshader_size = sizeof ( g_PS_1D ) ;
}
is1D = true ;
break ;
case TEX_DIMENSION_TEXTURE2D :
2022-03-28 00:29:48 +00:00
if ( mdata . miscFlags & TEX_MISC_TEXTURECUBE )
2016-08-22 18:26:36 +00:00
{
pshader = g_PS_Cube ;
pshader_size = sizeof ( g_PS_Cube ) ;
isCubeMap = true ;
}
2022-03-28 00:29:48 +00:00
else if ( mdata . arraySize > 1 )
2016-08-22 18:26:36 +00:00
{
pshader = g_PS_2DArray ;
pshader_size = sizeof ( g_PS_2DArray ) ;
}
else
{
pshader = g_PS_2D ;
pshader_size = sizeof ( g_PS_2D ) ;
}
break ;
case TEX_DIMENSION_TEXTURE3D :
pshader = g_PS_3D ;
pshader_size = sizeof ( g_PS_3D ) ;
break ;
default :
return E_FAIL ;
}
2022-03-28 00:29:48 +00:00
assert ( pshader & & pshader_size > 0 ) ;
2016-08-22 18:26:36 +00:00
// Create the pixel shader
2022-03-28 00:29:48 +00:00
hr = g_pd3dDevice - > CreatePixelShader ( pshader , pshader_size , nullptr , & g_pPixelShader ) ;
if ( FAILED ( hr ) )
2016-08-22 18:26:36 +00:00
return hr ;
// Create vertex buffer
UINT nverts ;
2017-12-18 21:35:07 +00:00
D3D11_SUBRESOURCE_DATA InitData = { } ;
2016-08-22 18:26:36 +00:00
static const SimpleVertex verticesCube [ ] =
{
// Render cubemaps as horizontal cross
// XPOS
2022-03-28 00:29:48 +00:00
{ XMFLOAT4 ( .5f , .25f , 0.f , 1.f ) , XMFLOAT4 ( 0.f , 0.f , 0.f , 0.f ) } ,
{ XMFLOAT4 ( 1.f , .25f , 0.f , 1.f ) , XMFLOAT4 ( 1.f , 0.f , 0.f , 0.f ) } ,
{ XMFLOAT4 ( .5f , - .25f , 0.f , 1.f ) , XMFLOAT4 ( 0.f , 1.f , 0.f , 0.f ) } ,
{ XMFLOAT4 ( 1.f , - .25f , 0.f , 1.f ) , XMFLOAT4 ( 1.f , 1.f , 0.f , 0.f ) } ,
2016-08-22 18:26:36 +00:00
// XNEG
2022-03-28 00:29:48 +00:00
{ XMFLOAT4 ( - .5f , .25f , 0.f , 1.f ) , XMFLOAT4 ( 0.f , 0.f , 1.f , 0.f ) } ,
{ XMFLOAT4 ( 0.f , .25f , 0.f , 1.f ) , XMFLOAT4 ( 1.f , 0.f , 1.f , 0.f ) } ,
{ XMFLOAT4 ( - .5f , - .25f , 0.f , 1.f ) , XMFLOAT4 ( 0.f , 1.f , 1.f , 0.f ) } ,
{ XMFLOAT4 ( 0.f , - .25f , 0.f , 1.f ) , XMFLOAT4 ( 1.f , 1.f , 1.f , 0.f ) } ,
2016-08-22 18:26:36 +00:00
// YPOS
2022-03-28 00:29:48 +00:00
{ XMFLOAT4 ( - .5f , .75f , 0.f , 1.f ) , XMFLOAT4 ( 0.f , 0.f , 2.f , 0.f ) } ,
{ XMFLOAT4 ( 0.f , .75f , 0.f , 1.f ) , XMFLOAT4 ( 1.f , 0.f , 2.f , 0.f ) } ,
{ XMFLOAT4 ( - .5f , .25f , 0.f , 1.f ) , XMFLOAT4 ( 0.f , 1.f , 2.f , 0.f ) } ,
{ XMFLOAT4 ( 0.f , .25f , 0.f , 1.f ) , XMFLOAT4 ( 1.f , 1.f , 2.f , 0.f ) } ,
2016-08-22 18:26:36 +00:00
// YNEG
2022-03-28 00:29:48 +00:00
{ XMFLOAT4 ( - .5f , - .25f , 0.f , 1.f ) , XMFLOAT4 ( 0.f , 0.f , 3.f , 0.f ) } ,
{ XMFLOAT4 ( 0.f , - .25f , 0.f , 1.f ) , XMFLOAT4 ( 1.f , 0.f , 3.f , 0.f ) } ,
{ XMFLOAT4 ( - .5f , - .75f , 0.f , 1.f ) , XMFLOAT4 ( 0.f , 1.f , 3.f , 0.f ) } ,
{ XMFLOAT4 ( 0.f , - .75f , 0.f , 1.f ) , XMFLOAT4 ( 1.f , 1.f , 3.f , 0.f ) } ,
2016-08-22 18:26:36 +00:00
// ZPOS
2022-03-28 00:29:48 +00:00
{ XMFLOAT4 ( 0.f , .25f , 0.f , 1.f ) , XMFLOAT4 ( 0.f , 0.f , 4.f , 0.f ) } ,
{ XMFLOAT4 ( .5f , .25f , 0.f , 1.f ) , XMFLOAT4 ( 1.f , 0.f , 4.f , 0.f ) } ,
{ XMFLOAT4 ( 0.f , - .25f , 0.f , 1.f ) , XMFLOAT4 ( 0.f , 1.f , 4.f , 0.f ) } ,
{ XMFLOAT4 ( .5f , - .25f , 0.f , 1.f ) , XMFLOAT4 ( 1.f , 1.f , 4.f , 0.f ) } ,
2016-08-22 18:26:36 +00:00
// ZNEG
2022-03-28 00:29:48 +00:00
{ XMFLOAT4 ( - 1.f , .25f , 0.f , 1.f ) , XMFLOAT4 ( 0.f , 0.f , 5.f , 0.f ) } ,
{ XMFLOAT4 ( - .5f , .25f , 0.f , 1.f ) , XMFLOAT4 ( 1.f , 0.f , 5.f , 0.f ) } ,
{ XMFLOAT4 ( - 1.f , - .25f , 0.f , 1.f ) , XMFLOAT4 ( 0.f , 1.f , 5.f , 0.f ) } ,
{ XMFLOAT4 ( - .5f , - .25f , 0.f , 1.f ) , XMFLOAT4 ( 1.f , 1.f , 5.f , 0.f ) } ,
2016-08-22 18:26:36 +00:00
} ;
static const SimpleVertex vertices [ ] =
{
2022-03-28 00:29:48 +00:00
{ XMFLOAT4 ( - 1.f , 1.f , 0.f , 1.f ) , XMFLOAT4 ( 0.f , 0.f , 0.f , 0.f ) } ,
{ XMFLOAT4 ( 1.f , 1.f , 0.f , 1.f ) , XMFLOAT4 ( 1.f , 0.f , 0.f , 0.f ) } ,
{ XMFLOAT4 ( - 1.f , - 1.f , 0.f , 1.f ) , XMFLOAT4 ( 0.f , 1.f , 0.f , 0.f ) } ,
{ XMFLOAT4 ( 1.f , - 1.f , 0.f , 1.f ) , XMFLOAT4 ( 1.f , 1.f , 0.f , 0.f ) } ,
2016-08-22 18:26:36 +00:00
} ;
static const SimpleVertex vertices1D [ ] =
{
2022-03-28 00:29:48 +00:00
{ XMFLOAT4 ( - 1.f , .05f , 0.f , 1.f ) , XMFLOAT4 ( 0.f , 0.f , 0.f , 0.f ) } ,
{ XMFLOAT4 ( 1.f , .05f , 0.f , 1.f ) , XMFLOAT4 ( 1.f , 0.f , 0.f , 0.f ) } ,
{ XMFLOAT4 ( - 1.f , - .05f , 0.f , 1.f ) , XMFLOAT4 ( 0.f , 0.f , 0.f , 0.f ) } ,
{ XMFLOAT4 ( 1.f , - .05f , 0.f , 1.f ) , XMFLOAT4 ( 1.f , 0.f , 0.f , 0.f ) } ,
2016-08-22 18:26:36 +00:00
} ;
2022-03-28 00:29:48 +00:00
if ( isCubeMap )
2016-08-22 18:26:36 +00:00
{
2021-01-02 20:44:35 +00:00
nverts = static_cast < UINT > ( std : : size ( verticesCube ) ) ;
2016-08-22 18:26:36 +00:00
InitData . pSysMem = verticesCube ;
}
2022-03-28 00:29:48 +00:00
else if ( is1D )
2016-08-22 18:26:36 +00:00
{
2021-01-02 20:44:35 +00:00
nverts = static_cast < UINT > ( std : : size ( vertices1D ) ) ;
2016-08-22 18:26:36 +00:00
InitData . pSysMem = vertices1D ;
}
else
{
2021-01-02 20:44:35 +00:00
nverts = static_cast < UINT > ( std : : size ( vertices ) ) ;
2016-08-22 18:26:36 +00:00
InitData . pSysMem = vertices ;
}
2017-12-18 21:35:07 +00:00
D3D11_BUFFER_DESC bd = { } ;
2016-08-22 18:26:36 +00:00
bd . Usage = D3D11_USAGE_DEFAULT ;
2022-03-28 00:29:48 +00:00
bd . ByteWidth = sizeof ( SimpleVertex ) * nverts ;
2016-08-22 18:26:36 +00:00
bd . BindFlags = D3D11_BIND_VERTEX_BUFFER ;
bd . CPUAccessFlags = 0 ;
2022-03-28 00:29:48 +00:00
hr = g_pd3dDevice - > CreateBuffer ( & bd , & InitData , & g_pVertexBuffer ) ;
if ( FAILED ( hr ) )
2016-08-22 18:26:36 +00:00
return hr ;
// Set vertex buffer
2022-03-28 00:29:48 +00:00
UINT stride = sizeof ( SimpleVertex ) ;
2016-08-22 18:26:36 +00:00
UINT offset = 0 ;
2022-03-28 00:29:48 +00:00
g_pImmediateContext - > IASetVertexBuffers ( 0 , 1 , & g_pVertexBuffer , & stride , & offset ) ;
2016-08-22 18:26:36 +00:00
// Create index buffer
static const WORD indicesCube [ ] =
{
0 , 1 , 2 ,
2 , 1 , 3 ,
4 , 5 , 6 ,
6 , 5 , 7 ,
8 , 9 , 10 ,
10 , 9 , 11 ,
12 , 13 , 14 ,
14 , 13 , 15 ,
16 , 17 , 18 ,
18 , 17 , 19 ,
20 , 21 , 22 ,
22 , 21 , 23
} ;
static const WORD indices [ ] =
{
0 , 1 , 2 ,
2 , 1 , 3
} ;
2022-03-28 00:29:48 +00:00
if ( isCubeMap )
2016-08-22 18:26:36 +00:00
{
2021-01-02 20:44:35 +00:00
g_iIndices = static_cast < UINT > ( std : : size ( indicesCube ) ) ;
2016-08-22 18:26:36 +00:00
InitData . pSysMem = indicesCube ;
}
else
{
2021-01-02 20:44:35 +00:00
g_iIndices = static_cast < UINT > ( std : : size ( indices ) ) ;
2016-08-22 18:26:36 +00:00
InitData . pSysMem = indices ;
}
bd . Usage = D3D11_USAGE_DEFAULT ;
bd . ByteWidth = g_iIndices * sizeof ( WORD ) ;
bd . BindFlags = D3D11_BIND_INDEX_BUFFER ;
bd . CPUAccessFlags = 0 ;
2022-03-28 00:29:48 +00:00
hr = g_pd3dDevice - > CreateBuffer ( & bd , & InitData , & g_pIndexBuffer ) ;
if ( FAILED ( hr ) )
2016-08-22 18:26:36 +00:00
return hr ;
// Set index buffer
2022-03-28 00:29:48 +00:00
g_pImmediateContext - > IASetIndexBuffer ( g_pIndexBuffer , DXGI_FORMAT_R16_UINT , 0 ) ;
2016-08-22 18:26:36 +00:00
// Set primitive topology
2022-03-28 00:29:48 +00:00
g_pImmediateContext - > IASetPrimitiveTopology ( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST ) ;
2016-08-22 18:26:36 +00:00
// Create the constant buffers
bd . Usage = D3D11_USAGE_DEFAULT ;
bd . ByteWidth = sizeof ( CBArrayControl ) ;
bd . BindFlags = D3D11_BIND_CONSTANT_BUFFER ;
bd . CPUAccessFlags = 0 ;
2022-03-28 00:29:48 +00:00
hr = g_pd3dDevice - > CreateBuffer ( & bd , nullptr , & g_pCBArrayControl ) ;
if ( FAILED ( hr ) )
2016-08-22 18:26:36 +00:00
return hr ;
// Create the state objects
2017-12-18 21:35:07 +00:00
D3D11_SAMPLER_DESC sampDesc = { } ;
2016-08-22 18:26:36 +00:00
sampDesc . Filter = D3D11_FILTER_MIN_MAG_MIP_POINT ;
sampDesc . AddressU = D3D11_TEXTURE_ADDRESS_WRAP ;
sampDesc . AddressV = D3D11_TEXTURE_ADDRESS_WRAP ;
sampDesc . AddressW = D3D11_TEXTURE_ADDRESS_WRAP ;
sampDesc . ComparisonFunc = D3D11_COMPARISON_NEVER ;
sampDesc . MinLOD = 0 ;
sampDesc . MaxLOD = D3D11_FLOAT32_MAX ;
2022-03-28 00:29:48 +00:00
hr = g_pd3dDevice - > CreateSamplerState ( & sampDesc , & g_pSamplerLinear ) ;
if ( FAILED ( hr ) )
2016-08-22 18:26:36 +00:00
return hr ;
2022-03-28 00:29:48 +00:00
D3D11_BLEND_DESC dsc =
2016-08-22 18:26:36 +00:00
{
false ,
false ,
{
2019-04-17 00:38:37 +00:00
{
true ,
D3D11_BLEND_SRC_ALPHA ,
D3D11_BLEND_INV_SRC_ALPHA ,
D3D11_BLEND_OP_ADD ,
D3D11_BLEND_ZERO ,
D3D11_BLEND_ZERO ,
D3D11_BLEND_OP_ADD ,
D3D11_COLOR_WRITE_ENABLE_ALL
} ,
2022-03-28 00:29:48 +00:00
// ...
}
2016-08-22 18:26:36 +00:00
} ;
2022-03-28 00:29:48 +00:00
hr = g_pd3dDevice - > CreateBlendState ( & dsc , & g_AlphaBlendState ) ;
if ( FAILED ( hr ) )
2016-08-22 18:26:36 +00:00
return hr ;
return S_OK ;
}
//--------------------------------------------------------------------------------------
void Render ( )
{
float ClearColor [ 4 ] = { 0.f , 1.f , 1.f , 1.0f } ; //red,green,blue,alpha
2022-03-28 00:29:48 +00:00
g_pImmediateContext - > ClearRenderTargetView ( g_pRenderTargetView , ClearColor ) ;
g_pImmediateContext - > ClearDepthStencilView ( g_pDepthStencilView , D3D11_CLEAR_DEPTH , 1.0f , 0 ) ;
2016-08-22 18:26:36 +00:00
2022-03-28 00:29:48 +00:00
float bf [ 4 ] = { 1.0f , 1.0f , 1.0f , 1.0f } ;
g_pImmediateContext - > OMSetBlendState ( g_AlphaBlendState , bf , 0xffffffff ) ;
2016-08-22 18:26:36 +00:00
2022-03-28 00:29:48 +00:00
CBArrayControl cb = { } ;
cb . Index = static_cast < float > ( g_iCurrentIndex ) ;
g_pImmediateContext - > UpdateSubresource ( g_pCBArrayControl , 0 , nullptr , & cb , 0 , 0 ) ;
2016-08-22 18:26:36 +00:00
2022-03-28 00:29:48 +00:00
g_pImmediateContext - > VSSetShader ( g_pVertexShader , nullptr , 0 ) ;
g_pImmediateContext - > PSSetShader ( g_pPixelShader , nullptr , 0 ) ;
g_pImmediateContext - > PSSetConstantBuffers ( 0 , 1 , & g_pCBArrayControl ) ;
g_pImmediateContext - > PSSetShaderResources ( 0 , 1 , & g_pSRV ) ;
g_pImmediateContext - > PSSetSamplers ( 0 , 1 , & g_pSamplerLinear ) ;
g_pImmediateContext - > DrawIndexed ( g_iIndices , 0 , 0 ) ;
2016-08-22 18:26:36 +00:00
2022-03-28 00:29:48 +00:00
g_pSwapChain - > Present ( 0 , 0 ) ;
2016-08-22 18:26:36 +00:00
}
//--------------------------------------------------------------------------------------
void CleanupDevice ( )
{
2022-03-28 00:29:48 +00:00
if ( g_pImmediateContext ) g_pImmediateContext - > ClearState ( ) ;
if ( g_pSamplerLinear ) g_pSamplerLinear - > Release ( ) ;
if ( g_AlphaBlendState ) g_AlphaBlendState - > Release ( ) ;
if ( g_pSRV ) g_pSRV - > Release ( ) ;
if ( g_pVertexBuffer ) g_pVertexBuffer - > Release ( ) ;
if ( g_pIndexBuffer ) g_pIndexBuffer - > Release ( ) ;
if ( g_pCBArrayControl ) g_pCBArrayControl - > Release ( ) ;
if ( g_pVertexLayout ) g_pVertexLayout - > Release ( ) ;
if ( g_pVertexShader ) g_pVertexShader - > Release ( ) ;
if ( g_pPixelShader ) g_pPixelShader - > Release ( ) ;
if ( g_pDepthStencil ) g_pDepthStencil - > Release ( ) ;
if ( g_pDepthStencilView ) g_pDepthStencilView - > Release ( ) ;
if ( g_pRenderTargetView ) g_pRenderTargetView - > Release ( ) ;
if ( g_pSwapChain ) g_pSwapChain - > Release ( ) ;
if ( g_pImmediateContext ) g_pImmediateContext - > Release ( ) ;
if ( g_pd3dDevice ) g_pd3dDevice - > Release ( ) ;
2016-08-22 18:26:36 +00:00
}