-
Notifications
You must be signed in to change notification settings - Fork 511
Implementation
For Visual C++, the projects make use of the default C++11/C++14 mode rather than /std:c++17
mode, although occasionally run a validation pass to confirm it's fully compatible with C++17 (i.e. avoid all use of auto_ptr
, random_shuffle
, and other deprecated features). The library does not make use of newer C++17 language & library features such as string_view
, static_assert
without a message, etc. although that may change in the future. The projects make use of /Wall
, /permissive-
, /Zc:__cplusplus
, and /analyze
to ensure a high-level of C++ conformance.
For clang/LLVM for Windows, there is a CMakeList.txt
provided to validate the code and ensure a high-level of conformance. This primarily means addressing warnings generated using /Wall -Wpedantic -Wextra
.
While the DirectX Tool Kit design is heavily influenced by the XNA Game Studio framework C# object design, it uses C++ conventions consistent with modern Win32 APIs rather than the strict .NET use of PascalCase as enforced by FXCop.
- PascalCase for class names, methods, functions, and enums.
- camelCase for class member variables, struct members
- UPPERCASE for preprocessor defines (and nameless enums)
The library does not generally make use of Hungarian notation which as been deprecated for Win32 C++ APIs for many years, with the exception of a few uses of p
for pointers and sz
for strings.
The use of Standard C++ types is preferred including the fundamental types supplied by the language (i.e. int
, unsigned int
, size_t
, ptrdiff_t
, bool
, true
/false
, char
, wchar_t
) with the addition of the C99 fixed width types (i.e. uint32_t
, uint64_t
, intptr_t
, uintptr_t
, etc.)
Avoid using Windows "portability" types except when dealing directly with Win32 APIs: VOID
, UINT
, INT
, DWORD
, FLOAT
, BOOL
, TRUE
/FALSE
, WCHAR
, CONST
, etc.
To provide type-safe bitmask flags, we make use of the DEFINE_ENUM_FLAG_OPERATORS
macro (in winnt.h) to make an enum work as you'd expect for bitmask flags based on recommendations in the C+ standard under 17.5.2.1.3 Bitmask types.
The impact to client code is minimal, but mostly means you can't pass a 0
literal and must use the defined default value like WIC_LOADER_DEFAULT
.
We generally use enum
rather than class enum
because it simplifies testing the bitflags. For example, this converts a standard enum
to a bool based on a bit-test:
... = (myFlags & MYFLAGS_BIT2) != 0;
To do the same thing with a class enum
requires:
... = (myFlags & MYFLAGS_BIT2) == MYFLAGS_BIT2;
Direct3D 11 does not make use of the strongly-type enum bitmask flags, but Direct3D 12 does.
The Modern C++ recommendation is to use UTF-8 Everywhere except where specifically interacting with Win32 or Windows Runtime APIs which require converting to wchar_t
(UTF-16LE).
- Always explicitly call the "W" or "A" versions of Win32 APIs. Prefer to convert from UTF-8 at the point of call.
- Do not rely on the macros to select "W" vs. "A", but always build with
UNICODE
and_UNICODE
defined for safety.
Most functions in DirectX Tool Kit take wchar_t*
since they are passed directly along to Win32 types. SpriteFont provides both UTF-8 char*
and UTF-16LE wchar_t*
methods.
The DirectX Toolkit library makes extensive use of SAL2 annotations (_In_
, _Outptr_opt_
, etc.) which greatly improves the accuracy of the Visual C++ static code analysis (also known as PREFAST). The standard Windows headers #define
them all to empty strings if not building with /analyze
, so they have no effect on code-generation.
DirectXTK's implementation makes extensive use of the pImpl idiom. This keeps the public headers slim and minimizes inter-module dependencies.
// SpriteBatch.h public header
class SpriteBatch
{
public:
SpriteBatch(...) noexcept(false);
SpriteBatch(SpriteBatch&& moveFrom) noexcept;
SpriteBatch& operator= (SpriteBatch&& moveFrom) noexcept;
SpriteBatch(SpriteBatch const&) = delete;
SpriteBatch& operator=(SpriteBatch const&) = delete;
virtual ~SpriteBatch();
...
private:
// Private implementation.
class Impl;
std::unique_ptr<Impl> pImpl;
};
This also allows the implementation to allocate the pImpl class internally using _aligned_malloc(x,16);
so that we can use the DirectXMath aligned XMVECTOR
and XMMATRIX
types directly in the implementation across all architectures.
-
The class default constructor can throw an exception since it creates a Impl instance, hence the
noexcept(false)
. -
The class destructor can't be inline and must be implemented in the
.cpp
file sinceunique_ptr
needs the realImpl
type size.
Public methods in the library are explicitly marked __cdecl
to ensure consistent behavior no matter what the client code is using. Internally it is not specified as it's assumed from the default setting except where XM_VECTORCALL
is utilized (see the DirectXMath section below)
The std::function
is used for callbacks as a general pattern so that client code can provide function pointers, lambdas, functors, etc. To support building with a mix of calling conventions, we need to annotate the std::function
correctly.
HRESULT __cdecl SaveWICTextureToFile( /*...*/,
std::function<void __cdecl(IPropertyBag2*)> setCustomProps
= nullptr );
The C++11 standard includes a more efficient = default
and = delete
construct for dealing with special constructors and operators.
To declare a standard copy constructor and copy assignment operators, we use:
Rectangle(const Rectangle&) = default;
Rectangle& operator= (const Rectangle&) = default;
To prevent copying we use:
// Prevent copying.
SpriteBatch(SpriteBatch const&) = delete;
SpriteBatch& operator= (SpriteBatch const&) = delete;
Per C++ Core Guidelines recommendations, if you declare a copy constructor/assignment operator, you should also defined the move equivalents:
Rectangle(Rectangle&&) = default;
Rectangle& operator= (Rectangle&&) = default;
Note that use of
= default
can improve codegen for derived types as well.
The library uses the DirectXMath calling convention types to improve parameter passing of XMVECTOR
and XMMATRIX
types.
All content and source code for this package are subject to the terms of the MIT License.
This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact [email protected] with any additional questions or comments.
- Universal Windows Platform apps
- Windows desktop apps
- Windows 11
- Windows 10
- Windows 8.1
- Windows 7 Service Pack 1
- Xbox One
- x86
- x64
- ARM64
- Visual Studio 2022
- Visual Studio 2019 (16.11)
- clang/LLVM v12 - v18
- MinGW 12.2, 13.2
- CMake 3.20