diff --git a/framework/platform-dx/adapter.cpp b/framework/platform-dx/adapter.cpp index 964bf66..a522ea7 100644 --- a/framework/platform-dx/adapter.cpp +++ b/framework/platform-dx/adapter.cpp @@ -1,9 +1,7 @@ #include "xna/graphics/adapter.hpp" #include "xna/graphics/displaymode.hpp" -#include "xna/platform-dx/headers.hpp" -#include "xna/platform-dx/helpers.hpp" -#include "xna/platform-dx/implementations.hpp" #include "xna/game/gdevicemanager.hpp" +#include "xna/platform-dx/dx.hpp" namespace xna { static size_t getDisplayModesCount(IDXGIAdapter* adapter); diff --git a/framework/platform-dx/audioengine.cpp b/framework/platform-dx/audioengine.cpp index 4e5cbce..fe6b877 100644 --- a/framework/platform-dx/audioengine.cpp +++ b/framework/platform-dx/audioengine.cpp @@ -1,4 +1,4 @@ -#include "xna/platform-dx/implementations.hpp" +#include "xna/platform-dx/dx.hpp" namespace xna { void AudioEngine::Initialize() { diff --git a/framework/platform-dx/blendstate.cpp b/framework/platform-dx/blendstate.cpp index d4ce0a3..0a680dc 100644 --- a/framework/platform-dx/blendstate.cpp +++ b/framework/platform-dx/blendstate.cpp @@ -1,9 +1,6 @@ #include "xna/graphics/blendstate.hpp" #include "xna/graphics/gresource.hpp" -#include "xna/platform-dx/headers.hpp" -#include "xna/platform-dx/helpers.hpp" -#include "xna/graphics/blendstate.hpp" -#include "xna/platform-dx/implementations.hpp" +#include "xna/platform-dx/dx.hpp" namespace xna { BlendState::BlendState() : GraphicsResource(nullptr) { diff --git a/framework/platform-dx/buffer.cpp b/framework/platform-dx/buffer.cpp index c3e5c5a..61cf105 100644 --- a/framework/platform-dx/buffer.cpp +++ b/framework/platform-dx/buffer.cpp @@ -1,7 +1,6 @@ #include "xna/graphics/buffer.hpp" #include "xna/common/numerics.hpp" -#include "xna/platform-dx/headers.hpp" -#include "xna/platform-dx/implementations.hpp" +#include "xna/platform-dx/dx.hpp" namespace xna { ConstantBuffer::ConstantBuffer() : GraphicsResource(nullptr){ diff --git a/framework/platform-dx/depthstencilstate.cpp b/framework/platform-dx/depthstencilstate.cpp index 9d8f573..d5b680f 100644 --- a/framework/platform-dx/depthstencilstate.cpp +++ b/framework/platform-dx/depthstencilstate.cpp @@ -1,6 +1,5 @@ #include "xna/graphics/depthstencilstate.hpp" -#include "xna/platform-dx/headers.hpp" -#include "xna/platform-dx/implementations.hpp" +#include "xna/platform-dx/dx.hpp" namespace xna { static D3D11_DEPTH_STENCIL_DESC defaultDesc() { diff --git a/framework/platform-dx/device.cpp b/framework/platform-dx/device.cpp index 59fd5be..2ebcb01 100644 --- a/framework/platform-dx/device.cpp +++ b/framework/platform-dx/device.cpp @@ -1,4 +1,4 @@ -#include "xna/platform-dx/implementations.hpp" +#include "xna/platform-dx/dx.hpp" #include "xna/game/gdevicemanager.hpp" namespace xna { diff --git a/framework/platform-dx/displaymode.cpp b/framework/platform-dx/displaymode.cpp index a80659f..3ae4ace 100644 --- a/framework/platform-dx/displaymode.cpp +++ b/framework/platform-dx/displaymode.cpp @@ -1,4 +1,4 @@ -#include "xna/platform-dx/implementations.hpp" +#include "xna/platform-dx/dx.hpp" #include "xna/graphics/displaymode.hpp" namespace xna { diff --git a/framework/platform-dx/game.cpp b/framework/platform-dx/game.cpp index 7c74c26..5a00943 100644 --- a/framework/platform-dx/game.cpp +++ b/framework/platform-dx/game.cpp @@ -1,10 +1,10 @@ -#include "xna/csharp/type.hpp" -#include "xna/game/time.hpp" -#include "xna/game/component.hpp" -#include "xna/game/servicecontainer.hpp" -#include "xna/platform-dx/implementations.hpp" -#include "xna/game/gdevicemanager.hpp" #include "xna/content/manager.hpp" +#include "xna/csharp/type.hpp" +#include "xna/game/component.hpp" +#include "xna/game/gdevicemanager.hpp" +#include "xna/game/servicecontainer.hpp" +#include "xna/game/time.hpp" +#include "xna/platform-dx/dx.hpp" namespace xna { Game::Game() { diff --git a/framework/platform-dx/gamepad.cpp b/framework/platform-dx/gamepad.cpp index de6655f..037df03 100644 --- a/framework/platform-dx/gamepad.cpp +++ b/framework/platform-dx/gamepad.cpp @@ -1,4 +1,4 @@ -#include "xna/platform-dx/implementations.hpp" +#include "xna/platform-dx/dx.hpp" #include "xna/input/gamepad.hpp" namespace xna { diff --git a/framework/platform-dx/gdevicemanager.cpp b/framework/platform-dx/gdevicemanager.cpp index 4b89639..28e2837 100644 --- a/framework/platform-dx/gdevicemanager.cpp +++ b/framework/platform-dx/gdevicemanager.cpp @@ -1,7 +1,7 @@ #include "xna/game/gdevicemanager.hpp" #include "xna/graphics/presentparams.hpp" #include "xna/graphics/swapchain.hpp" -#include "xna/platform-dx/implementations.hpp" +#include "xna/platform-dx/dx.hpp" namespace xna { GraphicsDeviceManager::GraphicsDeviceManager(sptr const& game) : _game(game) diff --git a/framework/platform-dx/init.cpp b/framework/platform-dx/init.cpp index a7b9c35..0351eba 100644 --- a/framework/platform-dx/init.cpp +++ b/framework/platform-dx/init.cpp @@ -4,7 +4,7 @@ #include "xna/content/readers/audio.hpp" #include "xna/content/typereadermanager.hpp" #include "xna/content/readers/default.hpp" -#include "xna/platform-dx/implementations.hpp" +#include "xna/platform-dx/dx.hpp" namespace xna { void Platform::Init() { diff --git a/framework/platform-dx/keyboard.cpp b/framework/platform-dx/keyboard.cpp index c11a070..ec0da4e 100644 --- a/framework/platform-dx/keyboard.cpp +++ b/framework/platform-dx/keyboard.cpp @@ -1,5 +1,5 @@ #include "xna/input/keyboard.hpp" -#include "xna/platform-dx/implementations.hpp" +#include "xna/platform-dx/dx.hpp" namespace xna { KeyboardState Keyboard::GetState() { diff --git a/framework/platform-dx/mouse.cpp b/framework/platform-dx/mouse.cpp index 310f30e..577edef 100644 --- a/framework/platform-dx/mouse.cpp +++ b/framework/platform-dx/mouse.cpp @@ -1,5 +1,5 @@ #include "xna/input/mouse.hpp" -#include "xna/platform-dx/implementations.hpp" +#include "xna/platform-dx/dx.hpp" namespace xna { MouseState Mouse::GetState() { diff --git a/framework/platform-dx/rasterizerstate.cpp b/framework/platform-dx/rasterizerstate.cpp index aec633c..311865c 100644 --- a/framework/platform-dx/rasterizerstate.cpp +++ b/framework/platform-dx/rasterizerstate.cpp @@ -1,5 +1,5 @@ #include "xna/graphics/rasterizerstate.hpp" -#include "xna/platform-dx/implementations.hpp" +#include "xna/platform-dx/dx.hpp" namespace xna { diff --git a/framework/platform-dx/rendertarget.cpp b/framework/platform-dx/rendertarget.cpp index 12fe883..d266c0d 100644 --- a/framework/platform-dx/rendertarget.cpp +++ b/framework/platform-dx/rendertarget.cpp @@ -1,4 +1,4 @@ -#include "xna/platform-dx/implementations.hpp" +#include "xna/platform-dx/dx.hpp" namespace xna { RenderTarget2D::RenderTarget2D() : Texture2D() { diff --git a/framework/platform-dx/samplerstate.cpp b/framework/platform-dx/samplerstate.cpp index 6d61ddc..597c5cb 100644 --- a/framework/platform-dx/samplerstate.cpp +++ b/framework/platform-dx/samplerstate.cpp @@ -1,7 +1,6 @@ #include "xna/graphics/samplerstate.hpp" #include "xna/graphics/samplerstate.hpp" -#include "xna/platform-dx/implementations.hpp" -#include "xna/platform-dx/helpers.hpp" +#include "xna/platform-dx/dx.hpp" namespace xna { SamplerState::SamplerState() : GraphicsResource(nullptr) { diff --git a/framework/platform-dx/shader.cpp b/framework/platform-dx/shader.cpp index b243fe8..9ed7453 100644 --- a/framework/platform-dx/shader.cpp +++ b/framework/platform-dx/shader.cpp @@ -1,5 +1,5 @@ #include "xna/graphics/buffer.hpp" -#include "xna/platform-dx/implementations.hpp" +#include "xna/platform-dx/dx.hpp" #include "xna/graphics/shader.hpp" namespace xna { diff --git a/framework/platform-dx/soundeffect.cpp b/framework/platform-dx/soundeffect.cpp index 2c83731..da984aa 100644 --- a/framework/platform-dx/soundeffect.cpp +++ b/framework/platform-dx/soundeffect.cpp @@ -1,4 +1,4 @@ -#include "xna/platform-dx/implementations.hpp" +#include "xna/platform-dx/dx.hpp" #include "xna/csharp/stream.hpp" using DxSoundEffect = DirectX::SoundEffect; diff --git a/framework/platform-dx/sprite.cpp b/framework/platform-dx/sprite.cpp index c6657a0..c05768a 100644 --- a/framework/platform-dx/sprite.cpp +++ b/framework/platform-dx/sprite.cpp @@ -6,8 +6,7 @@ #include "xna/graphics/viewport.hpp" #include "xna/graphics/blendstate.hpp" #include "xna/graphics/depthstencilstate.hpp" -#include "xna/platform-dx/implementations.hpp" -#include +#include "xna/platform-dx/dx.hpp" using DxSpriteBatch = DirectX::SpriteBatch; using DxSpriteSortMode = DirectX::SpriteSortMode; diff --git a/framework/platform-dx/swapchain.cpp b/framework/platform-dx/swapchain.cpp index 73586c5..f47fa39 100644 --- a/framework/platform-dx/swapchain.cpp +++ b/framework/platform-dx/swapchain.cpp @@ -1,7 +1,6 @@ -#include "xna/platform-dx/helpers.hpp" #include "xna/graphics/adapter.hpp" #include "xna/graphics/swapchain.hpp" -#include "xna/platform-dx/implementations.hpp" +#include "xna/platform-dx/dx.hpp" #include "xna/graphics/device.hpp" namespace xna { diff --git a/framework/platform-dx/texture.cpp b/framework/platform-dx/texture.cpp index f2960fd..0a95a67 100644 --- a/framework/platform-dx/texture.cpp +++ b/framework/platform-dx/texture.cpp @@ -1,5 +1,4 @@ -#include "xna/platform-dx/implementations.hpp" -#include "xna/platform-dx/helpers.hpp" +#include "xna/platform-dx/dx.hpp" namespace xna { Texture2D::~Texture2D() { diff --git a/framework/platform-dx/window.cpp b/framework/platform-dx/window.cpp index 66cdc97..3e734f6 100644 --- a/framework/platform-dx/window.cpp +++ b/framework/platform-dx/window.cpp @@ -1,4 +1,4 @@ -#include "xna/platform-dx/implementations.hpp" +#include "xna/platform-dx/dx.hpp" namespace xna { GameWindow::GameWindow() { diff --git a/inc/xna/platform-dx/dx.hpp b/inc/xna/platform-dx/dx.hpp new file mode 100644 index 0000000..2555106 --- /dev/null +++ b/inc/xna/platform-dx/dx.hpp @@ -0,0 +1,963 @@ +#ifndef XNA_PLATFORMDX_DX_HPP +#define XNA_PLATFORMDX_DX_HPP + +//--------------------------------// +// DX INCLUDES +//--------------------------------// + +//DirectX +#include "dxgi.h" +#include "d3d11.h" +#include +#include +//HSLS +#include +//DirectXTK +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//Windows +#define NOMINMAX +#include +#include +#include +#include +#include + +//--------------------------------// +// USINGS +//--------------------------------// + +template +using comptr = Microsoft::WRL::ComPtr; + +//--------------------------------// +// OTHERS INCLUDES +//--------------------------------// + +#include "../graphics/blendstate.hpp" +#include "../graphics/adapter.hpp" +#include "../graphics/device.hpp" +#include "../graphics/adapter.hpp" +#include "../graphics/blendstate.hpp" +#include "../graphics/buffer.hpp" +#include "../graphics/depthstencilstate.hpp" +#include "../graphics/displaymode.hpp" +#include "../graphics/sprite.hpp" +#include "../graphics/samplerstate.hpp" +#include "../input/gamepad.hpp" +#include "../input/keyboard.hpp" +#include "../input/mouse.hpp" +#include "../graphics/rasterizerstate.hpp" +#include "../graphics/presentparams.hpp" +#include "../graphics/shader.hpp" +#include "../graphics/swapchain.hpp" +#include "../graphics/texture.hpp" +#include "../graphics/rendertarget.hpp" +#include "../game/window.hpp" +#include "../audio/audioengine.hpp" +#include "../audio/soundeffect.hpp" +#include "../graphics/viewport.hpp" +#include "../common/color.hpp" +#include "../game/game.hpp" +#include +#include +#include + +//--------------------------------// +// CLASSES +//--------------------------------// + +namespace xna { + //==============================================// + //================ DXHELPERS ================// + //==============================================// + + struct DxHelpers { + static constexpr DXGI_FORMAT ConvertSurfaceToDXGIFORMAT(SurfaceFormat format) + { + switch (format) + { + case SurfaceFormat::Color://21 + return DXGI_FORMAT_R8G8B8A8_UNORM; + case SurfaceFormat::Bgr565: //23 + return DXGI_FORMAT_B5G6R5_UNORM; + case SurfaceFormat::Bgra5551://25 + return DXGI_FORMAT_B5G5R5A1_UNORM; + case SurfaceFormat::Bgra4444://26 + return DXGI_FORMAT_B4G4R4A4_UNORM; + case SurfaceFormat::Dxt1://827611204 + return DXGI_FORMAT_BC1_UNORM; + case SurfaceFormat::Dxt3://861165636 + return DXGI_FORMAT_BC2_UNORM; + case SurfaceFormat::Dxt5://894720068 + return DXGI_FORMAT_BC3_UNORM; + case SurfaceFormat::NormalizedByte2://60 + return DXGI_FORMAT_R8G8_SNORM; + case SurfaceFormat::NormalizedByte4://63 + return DXGI_FORMAT_R8G8B8A8_SNORM; + case SurfaceFormat::Rgba1010102://31 + return DXGI_FORMAT_R10G10B10A2_UNORM; + case SurfaceFormat::Rg32://34 + return DXGI_FORMAT_R16G16_UNORM; + case SurfaceFormat::Rgba64://36 + return DXGI_FORMAT_R16G16B16A16_UNORM; + case SurfaceFormat::Alpha8://28 + return DXGI_FORMAT_A8_UNORM; + case SurfaceFormat::Single://114 + return DXGI_FORMAT_R32_FLOAT; + case SurfaceFormat::Vector2://115 + return DXGI_FORMAT_R32G32_FLOAT; + case SurfaceFormat::Vector4://116 + return DXGI_FORMAT_R32G32B32A32_FLOAT; + case SurfaceFormat::HalfSingle://111 + return DXGI_FORMAT_R16_FLOAT; + case SurfaceFormat::HalfVector2://112 + return DXGI_FORMAT_R16G16_FLOAT; + case SurfaceFormat::HalfVector4://113 + return DXGI_FORMAT_R16G16B16A16_FLOAT; + case SurfaceFormat::HdrBlendable://113 + return DXGI_FORMAT_R16G16B16A16_FLOAT; + default://0 + return DXGI_FORMAT_UNKNOWN; + } + } + + static constexpr SurfaceFormat ConvertDXGIFORMATToSurface(DXGI_FORMAT format) { + switch (format) + { + case DXGI_FORMAT_R8G8B8A8_UNORM: + case DXGI_FORMAT_B8G8R8A8_UNORM: + return SurfaceFormat::Color; + case DXGI_FORMAT_B5G6R5_UNORM: + return SurfaceFormat::Bgr565; + case DXGI_FORMAT_B5G5R5A1_UNORM: + return SurfaceFormat::Bgra5551; + case DXGI_FORMAT_B4G4R4A4_UNORM: + return SurfaceFormat::Bgra4444; + case DXGI_FORMAT_BC2_UNORM: + return SurfaceFormat::Dxt3; + case DXGI_FORMAT_BC3_UNORM: + return SurfaceFormat::Dxt5; + case DXGI_FORMAT_R8G8_SNORM: + return SurfaceFormat::NormalizedByte2; + case DXGI_FORMAT_R8G8B8A8_SNORM: + return SurfaceFormat::NormalizedByte4; + case DXGI_FORMAT_R10G10B10A2_UNORM: + return SurfaceFormat::Rgba1010102; + case DXGI_FORMAT_R16G16_UNORM: + return SurfaceFormat::Rg32; + case DXGI_FORMAT_R16G16B16A16_UNORM: + return SurfaceFormat::Rgba64; + case DXGI_FORMAT_A8_UNORM: + return SurfaceFormat::Alpha8; + case DXGI_FORMAT_R32_FLOAT: + return SurfaceFormat::Single; + case DXGI_FORMAT_R32G32_FLOAT: + return SurfaceFormat::Vector2; + case DXGI_FORMAT_R32G32B32A32_FLOAT: + return SurfaceFormat::Vector4; + case DXGI_FORMAT_R16_FLOAT: + return SurfaceFormat::HalfSingle; + case DXGI_FORMAT_R16G16_FLOAT: + return SurfaceFormat::HalfVector2; + case DXGI_FORMAT_R16G16B16A16_FLOAT: + return SurfaceFormat::HalfVector4; + default: + return SurfaceFormat::Unknown; + } + } + + static constexpr D3D11_BLEND ConvertBlend(Blend blend) { + switch (blend) + { + case xna::Blend::Zero: + return D3D11_BLEND_ZERO; + case xna::Blend::One: + return D3D11_BLEND_ONE; + case xna::Blend::SourceColor: + return D3D11_BLEND_SRC_COLOR; + case xna::Blend::InverseSourceColor: + return D3D11_BLEND_INV_SRC_COLOR; + case xna::Blend::SourceAlpha: + return D3D11_BLEND_SRC_ALPHA; + case xna::Blend::InverseSourceAlpha: + return D3D11_BLEND_INV_SRC_ALPHA; + case xna::Blend::DestinationAlpha: + return D3D11_BLEND_DEST_ALPHA; + case xna::Blend::InverseDestinationAlpha: + return D3D11_BLEND_INV_DEST_ALPHA; + case xna::Blend::DestinationColor: + return D3D11_BLEND_DEST_COLOR; + case xna::Blend::InverseDestinationColor: + return D3D11_BLEND_INV_DEST_COLOR; + case xna::Blend::SourceAlphaSaturation: + return D3D11_BLEND_SRC_ALPHA_SAT; + case xna::Blend::BlendFactor: + return D3D11_BLEND_BLEND_FACTOR; + case xna::Blend::InverseBlendFactor: + return D3D11_BLEND_INV_BLEND_FACTOR; + case xna::Blend::Source1Color: + return D3D11_BLEND_SRC1_COLOR; + case xna::Blend::InverseSource1Color: + return D3D11_BLEND_INV_SRC1_COLOR; + case xna::Blend::Source1Alpha: + return D3D11_BLEND_SRC1_ALPHA; + case xna::Blend::InverseSource1Alpha: + return D3D11_BLEND_INV_SRC1_ALPHA; + default: + return D3D11_BLEND_ZERO; + } + } + + static constexpr D3D11_BLEND_OP ConvertOperation(BlendOperation op) { + return static_cast(static_cast(op) + 1); + } + + static constexpr D3D11_COLOR_WRITE_ENABLE ConvertColorWrite(ColorWriteChannels colorWrite) { + switch (colorWrite) + { + case xna::ColorWriteChannels::Red: + return D3D11_COLOR_WRITE_ENABLE_RED; + case xna::ColorWriteChannels::Green: + return D3D11_COLOR_WRITE_ENABLE_GREEN; + case xna::ColorWriteChannels::Blue: + return D3D11_COLOR_WRITE_ENABLE_BLUE; + case xna::ColorWriteChannels::Alpha: + return D3D11_COLOR_WRITE_ENABLE_ALPHA; + case xna::ColorWriteChannels::All: + return D3D11_COLOR_WRITE_ENABLE_ALL; + default: + return D3D11_COLOR_WRITE_ENABLE_ALL; + } + } + + static constexpr void ConvertAddressMode(TextureAddressMode value, D3D11_TEXTURE_ADDRESS_MODE& target) { + target = static_cast(static_cast(value) + 1); + } + + static constexpr void ConvertAddressMode(D3D11_TEXTURE_ADDRESS_MODE value, TextureAddressMode& target) { + target = static_cast(value - 1); + } + }; + + //==============================================// + //================ STEPTIMER ================// + //==============================================// + + // Helper class for animation and simulation timing. + class StepTimer + { + public: + StepTimer() noexcept(false) : + m_elapsedTicks(0), + m_totalTicks(0), + m_leftOverTicks(0), + m_frameCount(0), + m_framesPerSecond(0), + m_framesThisSecond(0), + m_qpcSecondCounter(0), + m_isFixedTimeStep(false), + m_targetElapsedTicks(TicksPerSecond / 60) + { + if (!QueryPerformanceFrequency(&m_qpcFrequency)) + { + throw std::exception(); + } + + if (!QueryPerformanceCounter(&m_qpcLastTime)) + { + throw std::exception(); + } + + // Initialize max delta to 1/10 of a second. + m_qpcMaxDelta = static_cast(m_qpcFrequency.QuadPart / 10); + } + + // Get elapsed time since the previous Update call. + uint64_t GetElapsedTicks() const noexcept { return m_elapsedTicks; } + double GetElapsedSeconds() const noexcept { return TicksToSeconds(m_elapsedTicks); } + + // Get total time since the start of the program. + uint64_t GetTotalTicks() const noexcept { return m_totalTicks; } + double GetTotalSeconds() const noexcept { return TicksToSeconds(m_totalTicks); } + + // Get total number of updates since start of the program. + uint32_t GetFrameCount() const noexcept { return m_frameCount; } + + // Get the current framerate. + uint32_t GetFramesPerSecond() const noexcept { return m_framesPerSecond; } + + // Set whether to use fixed or variable timestep mode. + void SetFixedTimeStep(bool isFixedTimestep) noexcept { m_isFixedTimeStep = isFixedTimestep; } + + // Set how often to call Update when in fixed timestep mode. + void SetTargetElapsedTicks(uint64_t targetElapsed) noexcept { m_targetElapsedTicks = targetElapsed; } + void SetTargetElapsedSeconds(double targetElapsed) noexcept { m_targetElapsedTicks = SecondsToTicks(targetElapsed); } + + // Integer format represents time using 10,000,000 ticks per second. + static constexpr uint64_t TicksPerSecond = 10000000; + + static constexpr double TicksToSeconds(uint64_t ticks) noexcept { return static_cast(ticks) / TicksPerSecond; } + static constexpr uint64_t SecondsToTicks(double seconds) noexcept { return static_cast(seconds * TicksPerSecond); } + + // After an intentional timing discontinuity (for instance a blocking IO operation) + // call this to avoid having the fixed timestep logic attempt a set of catch-up + // Update calls. + + void ResetElapsedTime() + { + if (!QueryPerformanceCounter(&m_qpcLastTime)) + { + throw std::exception(); + } + + m_leftOverTicks = 0; + m_framesPerSecond = 0; + m_framesThisSecond = 0; + m_qpcSecondCounter = 0; + } + + // Update timer state, calling the specified Update function the appropriate number of times. + template + void Tick(const TUpdate& update) + { + // Query the current time. + LARGE_INTEGER currentTime; + + if (!QueryPerformanceCounter(¤tTime)) + { + throw std::exception(); + } + + uint64_t timeDelta = static_cast(currentTime.QuadPart - m_qpcLastTime.QuadPart); + + m_qpcLastTime = currentTime; + m_qpcSecondCounter += timeDelta; + + // Clamp excessively large time deltas (e.g. after paused in the debugger). + if (timeDelta > m_qpcMaxDelta) + { + timeDelta = m_qpcMaxDelta; + } + + // Convert QPC units into a canonical tick format. This cannot overflow due to the previous clamp. + timeDelta *= TicksPerSecond; + timeDelta /= static_cast(m_qpcFrequency.QuadPart); + + const uint32_t lastFrameCount = m_frameCount; + + if (m_isFixedTimeStep) + { + // Fixed timestep update logic + + // If the app is running very close to the target elapsed time (within 1/4 of a millisecond) just clamp + // the clock to exactly match the target value. This prevents tiny and irrelevant errors + // from accumulating over time. Without this clamping, a game that requested a 60 fps + // fixed update, running with vsync enabled on a 59.94 NTSC display, would eventually + // accumulate enough tiny errors that it would drop a frame. It is better to just round + // small deviations down to zero to leave things running smoothly. + + if (static_cast(std::abs(static_cast(timeDelta - m_targetElapsedTicks))) < TicksPerSecond / 4000) + { + timeDelta = m_targetElapsedTicks; + } + + m_leftOverTicks += timeDelta; + + while (m_leftOverTicks >= m_targetElapsedTicks) + { + m_elapsedTicks = m_targetElapsedTicks; + m_totalTicks += m_targetElapsedTicks; + m_leftOverTicks -= m_targetElapsedTicks; + m_frameCount++; + + update(); + } + } + else + { + // Variable timestep update logic. + m_elapsedTicks = timeDelta; + m_totalTicks += timeDelta; + m_leftOverTicks = 0; + m_frameCount++; + + update(); + } + + // Track the current framerate. + if (m_frameCount != lastFrameCount) + { + m_framesThisSecond++; + } + + if (m_qpcSecondCounter >= static_cast(m_qpcFrequency.QuadPart)) + { + m_framesPerSecond = m_framesThisSecond; + m_framesThisSecond = 0; + m_qpcSecondCounter %= static_cast(m_qpcFrequency.QuadPart); + } + } + + private: + // Source timing data uses QPC units. + LARGE_INTEGER m_qpcFrequency; + LARGE_INTEGER m_qpcLastTime; + uint64_t m_qpcMaxDelta; + + // Derived timing data uses a canonical tick format. + uint64_t m_elapsedTicks; + uint64_t m_totalTicks; + uint64_t m_leftOverTicks; + + // Members for tracking the framerate. + uint32_t m_frameCount; + uint32_t m_framesPerSecond; + uint32_t m_framesThisSecond; + uint64_t m_qpcSecondCounter; + + // Members for configuring fixed timestep mode. + bool m_isFixedTimeStep; + uint64_t m_targetElapsedTicks; + }; + + + //==============================================// + //================ IMPL ================// + //==============================================// + + struct SpriteFont::PlatformImplementation { + sptr _dxSpriteFont = nullptr; + }; + + struct SpriteBatch::PlatformImplementation { + sptr _dxspriteBatch = nullptr; + }; + + struct GraphicsAdapter::PlatformImplementation { + ~PlatformImplementation() { + if (dxadapter) { + dxadapter->Release(); + dxadapter = nullptr; + } + } + + IDXGIAdapter1* dxadapter = nullptr; + private: + friend class GraphicsAdapter; + Uint _index{ 0 }; + sptr _currentDisplayMode = nullptr; + + public: + bool GetOutput(UINT slot, IDXGIOutput*& output); + }; + + struct BlendRenderTarget { + bool Enabled{ true }; + Blend Source{ Blend::SourceAlpha }; + Blend Destination{ Blend::InverseSourceAlpha }; + BlendOperation Operation{ BlendOperation::Add }; + Blend SourceAlpha{ Blend::One }; + Blend DestinationAlpha{ Blend::Zero }; + BlendOperation OperationAlpha{ BlendOperation::Add }; + ColorWriteChannels WriteMask{ ColorWriteChannels::All }; + + constexpr BlendRenderTarget() = default; + }; + + struct BlendState::PlatformImplementation { + ~PlatformImplementation() { + if (dxBlendState) { + dxBlendState->Release(); + dxBlendState = nullptr; + } + } + + ID3D11BlendState* dxBlendState = nullptr; + D3D11_BLEND_DESC dxDescription{}; + float blendFactor[4]{ 1.0F, 1.0F, 1.0F, 1.0F }; + UINT sampleMask{ 0xffffffff }; + }; + + struct ConstantBuffer::PlatformImplementation { + ~PlatformImplementation() { + if (_buffer) { + _buffer->Release(); + _buffer = nullptr; + } + } + + D3D11_BUFFER_DESC _description{}; + D3D11_SUBRESOURCE_DATA _subResource{}; + ID3D11Buffer* _buffer = nullptr; + DirectX::XMMATRIX _worldViewProjection{}; + }; + + struct DataBuffer::PlatformImplementation { + ~PlatformImplementation() { + if (_blob) { + _blob->Release(); + _blob = nullptr; + } + } + + ID3DBlob* _blob = nullptr; + + void Set(ID3DBlob*& blob) { + _blob = blob; + } + }; + + struct DepthStencilState::PlatformImplementation { + ~PlatformImplementation() { + if (dxDepthStencil) { + dxDepthStencil->Release(); + dxDepthStencil = nullptr; + } + } + + ID3D11DepthStencilState* dxDepthStencil = nullptr; + D3D11_DEPTH_STENCIL_DESC dxDescription{}; + }; + + struct DisplayModeRefreshRate { + constexpr DisplayModeRefreshRate() = default; + + constexpr DisplayModeRefreshRate(DXGI_RATIONAL const& dxrational) { + Numerator = dxrational.Numerator; + Denominator = dxrational.Denominator; + } + constexpr DisplayModeRefreshRate(Uint numerator, Uint denominator) + : Numerator(numerator), Denominator(denominator) {} + + Uint Numerator{ 0 }; + Uint Denominator{ 0 }; + + constexpr bool operator==(const DisplayModeRefreshRate& other) const + { + return Numerator == other.Numerator && Denominator == other.Denominator; + } + }; + + struct DisplayModeDescription { + DisplayModeScanlineOrder _scanlineOrdering{ DisplayModeScanlineOrder::Unspecified }; + DisplayModeScaling _scaling{ DisplayModeScaling::Unspecified }; + DisplayModeRefreshRate _refreshRate{}; + + constexpr bool operator==(const DisplayModeDescription& other) const + { + return _scanlineOrdering == other._scanlineOrdering && _scaling == other._scaling && _refreshRate == other._refreshRate; + } + }; + + struct DisplayMode::PlatformImplementation { + std::vector Descriptions; + }; + + struct GamePad::PlatformImplementation { + inline static uptr _dxGamePad = nullptr; + + void Suspend() { + if (_dxGamePad) + _dxGamePad->Suspend(); + } + + void Resume() { + if (_dxGamePad) + _dxGamePad->Resume(); + } + }; + + struct IndexBuffer::PlatformImplementation { + ~PlatformImplementation() { + if (dxBuffer) { + dxBuffer->Release(); + dxBuffer = nullptr; + } + } + + ID3D11Buffer* dxBuffer = nullptr; + }; + + struct Keyboard::PlatformImplementation { + inline static uptr _dxKeyboard = nullptr; + + void ProcessMessage(UINT message, WPARAM wParam, LPARAM lParam) { + if (_dxKeyboard) + _dxKeyboard->ProcessMessage(message, wParam, lParam); + } + }; + + struct Mouse::PlatformImplementation { + inline static uptr _dxMouse = nullptr; + + void ProcessMessage(UINT message, WPARAM wParam, LPARAM lParam) { + if (_dxMouse) + _dxMouse->ProcessMessage(message, wParam, lParam); + } + }; + + struct RasterizerState::PlatformImplementation { + ~PlatformImplementation() { + if (dxRasterizerState) { + dxRasterizerState->Release(); + dxRasterizerState = nullptr; + } + } + + ID3D11RasterizerState* dxRasterizerState = nullptr; + D3D11_RASTERIZER_DESC dxDescription{}; + }; + + struct SamplerState::PlatformImplementation { + ~PlatformImplementation() { + if (_samplerState) { + _samplerState->Release(); + _samplerState = nullptr; + } + } + + ID3D11SamplerState* _samplerState = nullptr; + D3D11_SAMPLER_DESC _description{}; + }; + + struct VertexShader::PlatformImplementation { + ~PlatformImplementation() { + if (_vertexShader) { + _vertexShader->Release(); + _vertexShader = nullptr; + } + } + + ID3D11VertexShader* _vertexShader = nullptr; + }; + + struct PixelShader::PlatformImplementation { + ~PlatformImplementation() { + if (_pixelShader) { + _pixelShader->Release(); + _pixelShader = nullptr; + } + } + + ID3D11PixelShader* _pixelShader = nullptr; + }; + + struct SwapChain::PlatformImplementation { + ~PlatformImplementation() { + if (dxSwapChain) { + dxSwapChain->Release(); + dxSwapChain = nullptr; + } + } + + IDXGISwapChain1* dxSwapChain{ nullptr }; + DXGI_SWAP_CHAIN_DESC1 dxDescription{}; + DXGI_SWAP_CHAIN_FULLSCREEN_DESC dxFullScreenDescription{}; + + bool GetBackBuffer(ID3D11Texture2D*& texture2D) { + if (!dxSwapChain) + return false; + + const auto hr = dxSwapChain->GetBuffer(0, __uuidof(texture2D), (void**)(&texture2D)); + + return !FAILED(hr); + } + }; + + struct Texture2D::PlatformImplementation { + ~PlatformImplementation() { + if (dxTexture2D) { + dxTexture2D->Release(); + dxTexture2D = nullptr; + } + + if (dxShaderResource) { + dxShaderResource->Release(); + dxShaderResource = nullptr; + } + } + + ID3D11Texture2D* dxTexture2D{ nullptr }; + ID3D11ShaderResourceView* dxShaderResource{ nullptr }; + D3D11_SUBRESOURCE_DATA dxSubResource{}; + D3D11_TEXTURE2D_DESC dxDescription{}; + D3D11_SHADER_RESOURCE_VIEW_DESC dxShaderDescription{}; + }; + + struct RenderTarget2D::PlatformImplementation { + ~PlatformImplementation() { + if (_renderTargetView) { + _renderTargetView->Release(); + _renderTargetView = nullptr; + } + } + + ID3D11RenderTargetView* _renderTargetView = nullptr; + D3D11_RENDER_TARGET_VIEW_DESC _renderTargetDesc{}; + }; + + struct VertexBuffer::PlatformImplementation { + ~PlatformImplementation() { + if (dxBuffer) { + dxBuffer->Release(); + dxBuffer = nullptr; + } + } + + ID3D11Buffer* dxBuffer = nullptr; + UINT size{ 0 }; + }; + + struct VertexInputLayout::PlatformImplementation { + ~PlatformImplementation() { + if (_inputLayout) { + _inputLayout->Release(); + _inputLayout = nullptr; + } + } + + ID3D11InputLayout* _inputLayout{ nullptr }; + std::vector _description{}; + }; + + enum class GameWindowMode : UINT { + Fullscreen = WS_POPUP | WS_VISIBLE, + Windowed = WS_OVERLAPPED | WS_SYSMENU | WS_VISIBLE, + Borderless = WS_EX_TOPMOST | WS_POPUP | WS_VISIBLE, + }; + + struct GameWindow::PlatformImplementation { + public: + constexpr void Mode(GameWindowMode mode) { + _windowStyle = static_cast(mode); + } + + constexpr GameWindowMode Mode() const { + return static_cast(_windowStyle); + } + + void Position(int width, int height, bool update = true); + void Size(int width, int height, bool update = true); + + inline HINSTANCE HInstance() const { + return _hInstance; + } + + inline HWND WindowHandle() const { + return _windowHandle; + } + + constexpr int Width() const { + return _windowWidth; + } + + constexpr int Height() const { + return _windowHeight; + } + + inline void Icon(unsigned int icon) { + _windowIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(icon)); + } + + inline void Icon(HICON icon) { + _windowIcon = icon; + } + + inline void Cursor(unsigned int cursor) { + _windowCursor = LoadCursor(GetModuleHandle(NULL), MAKEINTRESOURCE(cursor)); + } + + inline void Cursor(HCURSOR cursor) { + _windowCursor = cursor; + } + + constexpr float CenterX() const { + return _windowCenterX; + } + + constexpr float CenterY() const { + return _windowCenterY; + } + + inline void CursorVisibility(bool visible) const { + ShowCursor(visible); + } + + inline void Close() { + PostMessage(_windowHandle, WM_DESTROY, 0, 0); + } + + constexpr COLORREF Color() const { + return _windowColor; + } + + constexpr void Color(COLORREF color) { + _windowColor = color; + } + + constexpr void Color(BYTE r, BYTE g, BYTE b) { + _windowColor = RGB(r, g, b); + } + + bool Create(); + bool Update(); + + static LRESULT CALLBACK WinProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); + + private: + friend class GameWindow; + + HINSTANCE _hInstance{ nullptr }; + HWND _windowHandle{ nullptr }; + int _windowWidth{ 800 }; + int _windowHeight{ 480 }; + HICON _windowIcon{ nullptr }; + HCURSOR _windowCursor{ nullptr }; + COLORREF _windowColor{ RGB(0,0,0) }; + String _windowTitle{ "Xna++ Game Development" }; + DWORD _windowStyle{ 0 }; + int _windowPosX{ 0 }; + int _windowPosY{ 0 }; + float _windowCenterX{ 0 }; + float _windowCenterY{ 0 }; + + inline void setPosition() { + _windowPosX = GetSystemMetrics(SM_CXSCREEN) / 2 - _windowWidth / 2; + _windowPosY = GetSystemMetrics(SM_CYSCREEN) / 2 - _windowHeight / 2; + } + + inline void setCenter() { + _windowCenterX = _windowWidth / 2.0f; + _windowCenterY = _windowHeight / 2.0f; + } + }; + + struct AudioEngine::PlatformImplementation { + PlatformImplementation() { + _dxAudioEngine = unew( +#ifdef _DEBUG + DirectX::AudioEngine_Debug +#endif + ); + } + + ~PlatformImplementation() { + if (_dxAudioEngine) { + _dxAudioEngine->Suspend(); + } + } + + uptr _dxAudioEngine = nullptr; + }; + + struct GraphicsDevice::PlatformImplementation { + ~PlatformImplementation() { + if (_device) { + _device->Release(); + _device = nullptr; + } + + if (_context) { + _context->Release(); + _device = nullptr; + } + + if (_factory) { + _factory->Release(); + _factory = nullptr; + } + } + + ID3D11Device* _device{ nullptr }; + ID3D11DeviceContext* _context{ nullptr }; + IDXGIFactory1* _factory = nullptr; + sptr _swapChain{ nullptr }; + sptr _adapter{ nullptr }; + sptr _renderTarget2D{ nullptr }; + sptr _blendState{ nullptr }; + sptr _gameWindow = nullptr; + xna::Viewport _viewport{}; + sptr _presentationParameters; + D3D_FEATURE_LEVEL _featureLevel{ D3D_FEATURE_LEVEL::D3D_FEATURE_LEVEL_11_0 }; + + private: + friend class GraphicsDevice; + float _backgroundColor[4] = { 0, 0, 0, 0 }; + bool _usevsync{ true }; + }; + + struct Game::PlatformImplementation { + private: + friend class Game; + + xna::StepTimer _stepTimer{}; + }; + + struct SoundEffectInstance::PlatformImplementation { + uptr _dxInstance = nullptr; + }; + + struct SoundEffect::PlatformImplementation { + ~PlatformImplementation() { + } + + uptr _dxSoundEffect = nullptr; + }; + + template + inline bool IndexBuffer::Initialize(std::vector const& data, xna_error_ptr_arg) { + if (!impl || !m_device || !m_device->impl->_device || data.empty()) { + xna_error_apply(err, XnaErrorCode::INVALID_OPERATION); + return false; + } + + const auto hr = DirectX::CreateStaticBuffer(m_device->impl->_device, data.data(), data.size(), sizeof(T), D3D11_BIND_INDEX_BUFFER, &impl->dxBuffer); + + if (FAILED(hr)) { + xna_error_apply(err, XnaErrorCode::FAILED_OPERATION); + return false; + } + + return true; + } + + template + inline bool VertexBuffer::Initialize(std::vector const& data, xna_error_ptr_arg) { + if (!impl || !m_device || !m_device->impl->_device || data.empty()) { + xna_error_apply(err, XnaErrorCode::INVALID_OPERATION); + return false; + } + + const auto hr = DirectX::CreateStaticBuffer(m_device->impl->_device, data.data(), data.size(), sizeof(T), D3D11_BIND_VERTEX_BUFFER, &impl->dxBuffer); + + if (FAILED(hr)) { + xna_error_apply(err, XnaErrorCode::FAILED_OPERATION); + return false; + } + + impl->size = sizeof(T); + + return true; + } +} +#endif \ No newline at end of file diff --git a/inc/xna/platform-dx/headers.hpp b/inc/xna/platform-dx/headers.hpp deleted file mode 100644 index 6009b28..0000000 --- a/inc/xna/platform-dx/headers.hpp +++ /dev/null @@ -1,36 +0,0 @@ -//DirectX -#include "dxgi.h" -#include "d3d11.h" -#include -#include -//HSLS -#include -//DirectXTK -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -//Windows -#define NOMINMAX -#include -#include -#include -#include -#include \ No newline at end of file diff --git a/inc/xna/platform-dx/helpers.hpp b/inc/xna/platform-dx/helpers.hpp deleted file mode 100644 index 9d564c0..0000000 --- a/inc/xna/platform-dx/helpers.hpp +++ /dev/null @@ -1,173 +0,0 @@ -#include "headers.hpp" -#include "../graphics/blendstate.hpp" -#include "../graphics/adapter.hpp" - -namespace xna { - struct DxHelpers { - static constexpr DXGI_FORMAT ConvertSurfaceToDXGIFORMAT(SurfaceFormat format) - { - switch (format) - { - case SurfaceFormat::Color://21 - return DXGI_FORMAT_R8G8B8A8_UNORM; - case SurfaceFormat::Bgr565: //23 - return DXGI_FORMAT_B5G6R5_UNORM; - case SurfaceFormat::Bgra5551://25 - return DXGI_FORMAT_B5G5R5A1_UNORM; - case SurfaceFormat::Bgra4444://26 - return DXGI_FORMAT_B4G4R4A4_UNORM; - case SurfaceFormat::Dxt1://827611204 - return DXGI_FORMAT_BC1_UNORM; - case SurfaceFormat::Dxt3://861165636 - return DXGI_FORMAT_BC2_UNORM; - case SurfaceFormat::Dxt5://894720068 - return DXGI_FORMAT_BC3_UNORM; - case SurfaceFormat::NormalizedByte2://60 - return DXGI_FORMAT_R8G8_SNORM; - case SurfaceFormat::NormalizedByte4://63 - return DXGI_FORMAT_R8G8B8A8_SNORM; - case SurfaceFormat::Rgba1010102://31 - return DXGI_FORMAT_R10G10B10A2_UNORM; - case SurfaceFormat::Rg32://34 - return DXGI_FORMAT_R16G16_UNORM; - case SurfaceFormat::Rgba64://36 - return DXGI_FORMAT_R16G16B16A16_UNORM; - case SurfaceFormat::Alpha8://28 - return DXGI_FORMAT_A8_UNORM; - case SurfaceFormat::Single://114 - return DXGI_FORMAT_R32_FLOAT; - case SurfaceFormat::Vector2://115 - return DXGI_FORMAT_R32G32_FLOAT; - case SurfaceFormat::Vector4://116 - return DXGI_FORMAT_R32G32B32A32_FLOAT; - case SurfaceFormat::HalfSingle://111 - return DXGI_FORMAT_R16_FLOAT; - case SurfaceFormat::HalfVector2://112 - return DXGI_FORMAT_R16G16_FLOAT; - case SurfaceFormat::HalfVector4://113 - return DXGI_FORMAT_R16G16B16A16_FLOAT; - case SurfaceFormat::HdrBlendable://113 - return DXGI_FORMAT_R16G16B16A16_FLOAT; - default://0 - return DXGI_FORMAT_UNKNOWN; - } - } - - static constexpr SurfaceFormat ConvertDXGIFORMATToSurface(DXGI_FORMAT format) { - switch (format) - { - case DXGI_FORMAT_R8G8B8A8_UNORM: - case DXGI_FORMAT_B8G8R8A8_UNORM: - return SurfaceFormat::Color; - case DXGI_FORMAT_B5G6R5_UNORM: - return SurfaceFormat::Bgr565; - case DXGI_FORMAT_B5G5R5A1_UNORM: - return SurfaceFormat::Bgra5551; - case DXGI_FORMAT_B4G4R4A4_UNORM: - return SurfaceFormat::Bgra4444; - case DXGI_FORMAT_BC2_UNORM: - return SurfaceFormat::Dxt3; - case DXGI_FORMAT_BC3_UNORM: - return SurfaceFormat::Dxt5; - case DXGI_FORMAT_R8G8_SNORM: - return SurfaceFormat::NormalizedByte2; - case DXGI_FORMAT_R8G8B8A8_SNORM: - return SurfaceFormat::NormalizedByte4; - case DXGI_FORMAT_R10G10B10A2_UNORM: - return SurfaceFormat::Rgba1010102; - case DXGI_FORMAT_R16G16_UNORM: - return SurfaceFormat::Rg32; - case DXGI_FORMAT_R16G16B16A16_UNORM: - return SurfaceFormat::Rgba64; - case DXGI_FORMAT_A8_UNORM: - return SurfaceFormat::Alpha8; - case DXGI_FORMAT_R32_FLOAT: - return SurfaceFormat::Single; - case DXGI_FORMAT_R32G32_FLOAT: - return SurfaceFormat::Vector2; - case DXGI_FORMAT_R32G32B32A32_FLOAT: - return SurfaceFormat::Vector4; - case DXGI_FORMAT_R16_FLOAT: - return SurfaceFormat::HalfSingle; - case DXGI_FORMAT_R16G16_FLOAT: - return SurfaceFormat::HalfVector2; - case DXGI_FORMAT_R16G16B16A16_FLOAT: - return SurfaceFormat::HalfVector4; - default: - return SurfaceFormat::Unknown; - } - } - - static constexpr D3D11_BLEND ConvertBlend(Blend blend) { - switch (blend) - { - case xna::Blend::Zero: - return D3D11_BLEND_ZERO; - case xna::Blend::One: - return D3D11_BLEND_ONE; - case xna::Blend::SourceColor: - return D3D11_BLEND_SRC_COLOR; - case xna::Blend::InverseSourceColor: - return D3D11_BLEND_INV_SRC_COLOR; - case xna::Blend::SourceAlpha: - return D3D11_BLEND_SRC_ALPHA; - case xna::Blend::InverseSourceAlpha: - return D3D11_BLEND_INV_SRC_ALPHA; - case xna::Blend::DestinationAlpha: - return D3D11_BLEND_DEST_ALPHA; - case xna::Blend::InverseDestinationAlpha: - return D3D11_BLEND_INV_DEST_ALPHA; - case xna::Blend::DestinationColor: - return D3D11_BLEND_DEST_COLOR; - case xna::Blend::InverseDestinationColor: - return D3D11_BLEND_INV_DEST_COLOR; - case xna::Blend::SourceAlphaSaturation: - return D3D11_BLEND_SRC_ALPHA_SAT; - case xna::Blend::BlendFactor: - return D3D11_BLEND_BLEND_FACTOR; - case xna::Blend::InverseBlendFactor: - return D3D11_BLEND_INV_BLEND_FACTOR; - case xna::Blend::Source1Color: - return D3D11_BLEND_SRC1_COLOR; - case xna::Blend::InverseSource1Color: - return D3D11_BLEND_INV_SRC1_COLOR; - case xna::Blend::Source1Alpha: - return D3D11_BLEND_SRC1_ALPHA; - case xna::Blend::InverseSource1Alpha: - return D3D11_BLEND_INV_SRC1_ALPHA; - default: - return D3D11_BLEND_ZERO; - } - } - - static constexpr D3D11_BLEND_OP ConvertOperation(BlendOperation op) { - return static_cast(static_cast(op) + 1); - } - - static constexpr D3D11_COLOR_WRITE_ENABLE ConvertColorWrite(ColorWriteChannels colorWrite) { - switch (colorWrite) - { - case xna::ColorWriteChannels::Red: - return D3D11_COLOR_WRITE_ENABLE_RED; - case xna::ColorWriteChannels::Green: - return D3D11_COLOR_WRITE_ENABLE_GREEN; - case xna::ColorWriteChannels::Blue: - return D3D11_COLOR_WRITE_ENABLE_BLUE; - case xna::ColorWriteChannels::Alpha: - return D3D11_COLOR_WRITE_ENABLE_ALPHA; - case xna::ColorWriteChannels::All: - return D3D11_COLOR_WRITE_ENABLE_ALL; - default: - return D3D11_COLOR_WRITE_ENABLE_ALL; - } - } - - static constexpr void ConvertAddressMode(TextureAddressMode value, D3D11_TEXTURE_ADDRESS_MODE& target) { - target = static_cast(static_cast(value) + 1); - } - - static constexpr void ConvertAddressMode(D3D11_TEXTURE_ADDRESS_MODE value, TextureAddressMode& target) { - target = static_cast(value - 1); - } - }; -} \ No newline at end of file diff --git a/inc/xna/platform-dx/implementations.hpp b/inc/xna/platform-dx/implementations.hpp deleted file mode 100644 index 12a5bde..0000000 --- a/inc/xna/platform-dx/implementations.hpp +++ /dev/null @@ -1,547 +0,0 @@ -#ifndef XNA_PLATFORM_DX_IMPLEMENTATIONS_HPP -#define XNA_PLATFORM_DX_IMPLEMENTATIONS_HPP - -#include "headers.hpp" -#include "stepTimer.hpp" -#include "../graphics/device.hpp" -#include "../graphics/adapter.hpp" -#include "../graphics/blendstate.hpp" -#include "../graphics/buffer.hpp" -#include "../graphics/depthstencilstate.hpp" -#include "../graphics/displaymode.hpp" -#include "../graphics/sprite.hpp" -#include "../graphics/samplerstate.hpp" -#include "../input/gamepad.hpp" -#include "../input/keyboard.hpp" -#include "../input/mouse.hpp" -#include "../graphics/rasterizerstate.hpp" -#include "../graphics/presentparams.hpp" -#include "../graphics/shader.hpp" -#include "../graphics/swapchain.hpp" -#include "../graphics/texture.hpp" -#include "../graphics/rendertarget.hpp" -#include "../game/window.hpp" -#include "../audio/audioengine.hpp" -#include "../audio/soundeffect.hpp" -#include "../graphics/viewport.hpp" -#include "../common/color.hpp" -#include "../game/game.hpp" - -namespace xna { - struct SpriteFont::PlatformImplementation { - sptr _dxSpriteFont = nullptr; - }; - - struct SpriteBatch::PlatformImplementation { - sptr _dxspriteBatch = nullptr; - }; - - struct GraphicsAdapter::PlatformImplementation { - ~PlatformImplementation() { - if (dxadapter) { - dxadapter->Release(); - dxadapter = nullptr; - } - } - - IDXGIAdapter1* dxadapter = nullptr; - private: - friend class GraphicsAdapter; - Uint _index{ 0 }; - sptr _currentDisplayMode = nullptr; - - public: - bool GetOutput(UINT slot, IDXGIOutput*& output); - }; - - struct BlendRenderTarget { - bool Enabled{ true }; - Blend Source{ Blend::SourceAlpha }; - Blend Destination{ Blend::InverseSourceAlpha }; - BlendOperation Operation{ BlendOperation::Add }; - Blend SourceAlpha{ Blend::One }; - Blend DestinationAlpha{ Blend::Zero }; - BlendOperation OperationAlpha{ BlendOperation::Add }; - ColorWriteChannels WriteMask{ ColorWriteChannels::All }; - - constexpr BlendRenderTarget() = default; - }; - - struct BlendState::PlatformImplementation { - ~PlatformImplementation() { - if (dxBlendState) { - dxBlendState->Release(); - dxBlendState = nullptr; - } - } - - ID3D11BlendState* dxBlendState = nullptr; - D3D11_BLEND_DESC dxDescription{}; - float blendFactor[4]{ 1.0F, 1.0F, 1.0F, 1.0F }; - UINT sampleMask{ 0xffffffff }; - }; - - struct ConstantBuffer::PlatformImplementation { - ~PlatformImplementation() { - if (_buffer) { - _buffer->Release(); - _buffer = nullptr; - } - } - - D3D11_BUFFER_DESC _description{}; - D3D11_SUBRESOURCE_DATA _subResource{}; - ID3D11Buffer* _buffer = nullptr; - DirectX::XMMATRIX _worldViewProjection{}; - }; - - struct DataBuffer::PlatformImplementation { - ~PlatformImplementation() { - if (_blob) { - _blob->Release(); - _blob = nullptr; - } - } - - ID3DBlob* _blob = nullptr; - - void Set(ID3DBlob*& blob) { - _blob = blob; - } - }; - - struct DepthStencilState::PlatformImplementation { - ~PlatformImplementation() { - if (dxDepthStencil) { - dxDepthStencil->Release(); - dxDepthStencil = nullptr; - } - } - - ID3D11DepthStencilState* dxDepthStencil = nullptr; - D3D11_DEPTH_STENCIL_DESC dxDescription{}; - }; - - struct DisplayModeRefreshRate { - constexpr DisplayModeRefreshRate() = default; - - constexpr DisplayModeRefreshRate(DXGI_RATIONAL const& dxrational) { - Numerator = dxrational.Numerator; - Denominator = dxrational.Denominator; - } - constexpr DisplayModeRefreshRate(Uint numerator, Uint denominator) - : Numerator(numerator), Denominator(denominator) {} - - Uint Numerator{ 0 }; - Uint Denominator{ 0 }; - - constexpr bool operator==(const DisplayModeRefreshRate& other) const - { - return Numerator == other.Numerator && Denominator == other.Denominator; - } - }; - - struct DisplayModeDescription { - DisplayModeScanlineOrder _scanlineOrdering{ DisplayModeScanlineOrder::Unspecified }; - DisplayModeScaling _scaling{ DisplayModeScaling::Unspecified }; - DisplayModeRefreshRate _refreshRate{}; - - constexpr bool operator==(const DisplayModeDescription& other) const - { - return _scanlineOrdering == other._scanlineOrdering && _scaling == other._scaling && _refreshRate == other._refreshRate; - } - }; - - struct DisplayMode::PlatformImplementation { - std::vector Descriptions; - }; - - struct GamePad::PlatformImplementation { - inline static uptr _dxGamePad = nullptr; - - void Suspend() { - if (_dxGamePad) - _dxGamePad->Suspend(); - } - - void Resume() { - if (_dxGamePad) - _dxGamePad->Resume(); - } - }; - - struct IndexBuffer::PlatformImplementation { - ~PlatformImplementation() { - if (dxBuffer) { - dxBuffer->Release(); - dxBuffer = nullptr; - } - } - - ID3D11Buffer* dxBuffer = nullptr; - }; - - struct Keyboard::PlatformImplementation { - inline static uptr _dxKeyboard = nullptr; - - void ProcessMessage(UINT message, WPARAM wParam, LPARAM lParam) { - if (_dxKeyboard) - _dxKeyboard->ProcessMessage(message, wParam, lParam); - } - }; - - struct Mouse::PlatformImplementation { - inline static uptr _dxMouse = nullptr; - - void ProcessMessage(UINT message, WPARAM wParam, LPARAM lParam) { - if (_dxMouse) - _dxMouse->ProcessMessage(message, wParam, lParam); - } - }; - - struct RasterizerState::PlatformImplementation { - ~PlatformImplementation() { - if (dxRasterizerState) { - dxRasterizerState->Release(); - dxRasterizerState = nullptr; - } - } - - ID3D11RasterizerState* dxRasterizerState = nullptr; - D3D11_RASTERIZER_DESC dxDescription{}; - }; - - struct SamplerState::PlatformImplementation { - ~PlatformImplementation() { - if (_samplerState) { - _samplerState->Release(); - _samplerState = nullptr; - } - } - - ID3D11SamplerState* _samplerState = nullptr; - D3D11_SAMPLER_DESC _description{}; - }; - - struct VertexShader::PlatformImplementation { - ~PlatformImplementation() { - if (_vertexShader) { - _vertexShader->Release(); - _vertexShader = nullptr; - } - } - - ID3D11VertexShader* _vertexShader = nullptr; - }; - - struct PixelShader::PlatformImplementation { - ~PlatformImplementation() { - if (_pixelShader) { - _pixelShader->Release(); - _pixelShader = nullptr; - } - } - - ID3D11PixelShader* _pixelShader = nullptr; - }; - - struct SwapChain::PlatformImplementation { - ~PlatformImplementation() { - if (dxSwapChain) { - dxSwapChain->Release(); - dxSwapChain = nullptr; - } - } - - IDXGISwapChain1* dxSwapChain{ nullptr }; - DXGI_SWAP_CHAIN_DESC1 dxDescription{}; - DXGI_SWAP_CHAIN_FULLSCREEN_DESC dxFullScreenDescription{}; - - bool GetBackBuffer(ID3D11Texture2D*& texture2D) { - if (!dxSwapChain) - return false; - - const auto hr = dxSwapChain->GetBuffer(0, __uuidof(texture2D), (void**)(&texture2D)); - - return !FAILED(hr); - } - }; - - struct Texture2D::PlatformImplementation { - ~PlatformImplementation() { - if (dxTexture2D) { - dxTexture2D->Release(); - dxTexture2D = nullptr; - } - - if (dxShaderResource) { - dxShaderResource->Release(); - dxShaderResource = nullptr; - } - } - - ID3D11Texture2D* dxTexture2D{ nullptr }; - ID3D11ShaderResourceView* dxShaderResource{ nullptr }; - D3D11_SUBRESOURCE_DATA dxSubResource{}; - D3D11_TEXTURE2D_DESC dxDescription{}; - D3D11_SHADER_RESOURCE_VIEW_DESC dxShaderDescription{}; - }; - - struct RenderTarget2D::PlatformImplementation { - ~PlatformImplementation() { - if (_renderTargetView) { - _renderTargetView->Release(); - _renderTargetView = nullptr; - } - } - - ID3D11RenderTargetView* _renderTargetView = nullptr; - D3D11_RENDER_TARGET_VIEW_DESC _renderTargetDesc{}; - }; - - struct VertexBuffer::PlatformImplementation { - ~PlatformImplementation() { - if (dxBuffer) { - dxBuffer->Release(); - dxBuffer = nullptr; - } - } - - ID3D11Buffer* dxBuffer = nullptr; - UINT size{ 0 }; - }; - - struct VertexInputLayout::PlatformImplementation { - ~PlatformImplementation() { - if (_inputLayout) { - _inputLayout->Release(); - _inputLayout = nullptr; - } - } - - ID3D11InputLayout* _inputLayout{ nullptr }; - std::vector _description{}; - }; - - enum class GameWindowMode : UINT { - Fullscreen = WS_POPUP | WS_VISIBLE, - Windowed = WS_OVERLAPPED | WS_SYSMENU | WS_VISIBLE, - Borderless = WS_EX_TOPMOST | WS_POPUP | WS_VISIBLE, - }; - - struct GameWindow::PlatformImplementation { - public: - constexpr void Mode(GameWindowMode mode) { - _windowStyle = static_cast(mode); - } - - constexpr GameWindowMode Mode() const { - return static_cast(_windowStyle); - } - - void Position(int width, int height, bool update = true); - void Size(int width, int height, bool update = true); - - inline HINSTANCE HInstance() const { - return _hInstance; - } - - inline HWND WindowHandle() const { - return _windowHandle; - } - - constexpr int Width() const { - return _windowWidth; - } - - constexpr int Height() const { - return _windowHeight; - } - - inline void Icon(unsigned int icon) { - _windowIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(icon)); - } - - inline void Icon(HICON icon) { - _windowIcon = icon; - } - - inline void Cursor(unsigned int cursor) { - _windowCursor = LoadCursor(GetModuleHandle(NULL), MAKEINTRESOURCE(cursor)); - } - - inline void Cursor(HCURSOR cursor) { - _windowCursor = cursor; - } - - constexpr float CenterX() const { - return _windowCenterX; - } - - constexpr float CenterY() const { - return _windowCenterY; - } - - inline void CursorVisibility(bool visible) const { - ShowCursor(visible); - } - - inline void Close() { - PostMessage(_windowHandle, WM_DESTROY, 0, 0); - } - - constexpr COLORREF Color() const { - return _windowColor; - } - - constexpr void Color(COLORREF color) { - _windowColor = color; - } - - constexpr void Color(BYTE r, BYTE g, BYTE b) { - _windowColor = RGB(r, g, b); - } - - bool Create(); - bool Update(); - - static LRESULT CALLBACK WinProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); - - private: - friend class GameWindow; - - HINSTANCE _hInstance{ nullptr }; - HWND _windowHandle{ nullptr }; - int _windowWidth{ 800 }; - int _windowHeight{ 480 }; - HICON _windowIcon{ nullptr }; - HCURSOR _windowCursor{ nullptr }; - COLORREF _windowColor{ RGB(0,0,0) }; - String _windowTitle{ "Xna++ Game Development" }; - DWORD _windowStyle{ 0 }; - int _windowPosX{ 0 }; - int _windowPosY{ 0 }; - float _windowCenterX{ 0 }; - float _windowCenterY{ 0 }; - - inline void setPosition() { - _windowPosX = GetSystemMetrics(SM_CXSCREEN) / 2 - _windowWidth / 2; - _windowPosY = GetSystemMetrics(SM_CYSCREEN) / 2 - _windowHeight / 2; - } - - inline void setCenter() { - _windowCenterX = _windowWidth / 2.0f; - _windowCenterY = _windowHeight / 2.0f; - } - }; - - struct AudioEngine::PlatformImplementation { - PlatformImplementation() { - _dxAudioEngine = unew( -#ifdef _DEBUG - DirectX::AudioEngine_Debug -#endif - ); - } - - ~PlatformImplementation() { - if (_dxAudioEngine) { - _dxAudioEngine->Suspend(); - } - } - - uptr _dxAudioEngine = nullptr; - }; - - struct GraphicsDevice::PlatformImplementation { - ~PlatformImplementation() { - if (_device) { - _device->Release(); - _device = nullptr; - } - - if (_context) { - _context->Release(); - _device = nullptr; - } - - if (_factory) { - _factory->Release(); - _factory = nullptr; - } - } - - ID3D11Device* _device{ nullptr }; - ID3D11DeviceContext* _context{ nullptr }; - IDXGIFactory1* _factory = nullptr; - sptr _swapChain{ nullptr }; - sptr _adapter{ nullptr }; - sptr _renderTarget2D{ nullptr }; - sptr _blendState{ nullptr }; - sptr _gameWindow = nullptr; - xna::Viewport _viewport{}; - sptr _presentationParameters; - D3D_FEATURE_LEVEL _featureLevel{ D3D_FEATURE_LEVEL::D3D_FEATURE_LEVEL_11_0 }; - - private: - friend class GraphicsDevice; - float _backgroundColor[4] = { 0, 0, 0, 0 }; - bool _usevsync{ true }; - }; - - struct Game::PlatformImplementation { - private: - friend class Game; - - xna::StepTimer _stepTimer{}; - }; - - struct SoundEffectInstance::PlatformImplementation { - uptr _dxInstance = nullptr; - }; - - struct SoundEffect::PlatformImplementation { - ~PlatformImplementation() { - } - - uptr _dxSoundEffect = nullptr; - }; - - template - inline bool IndexBuffer::Initialize(std::vector const& data, xna_error_ptr_arg) { - if (!impl || !m_device || !m_device->impl->_device || data.empty()) { - xna_error_apply(err, XnaErrorCode::INVALID_OPERATION); - return false; - } - - const auto hr = DirectX::CreateStaticBuffer(m_device->impl->_device, data.data(), data.size(), sizeof(T), D3D11_BIND_INDEX_BUFFER, &impl->dxBuffer); - - if (FAILED(hr)) { - xna_error_apply(err, XnaErrorCode::FAILED_OPERATION); - return false; - } - - return true; - } - - template - inline bool VertexBuffer::Initialize(std::vector const& data, xna_error_ptr_arg) { - if (!impl || !m_device || !m_device->impl->_device || data.empty()) { - xna_error_apply(err, XnaErrorCode::INVALID_OPERATION); - return false; - } - - const auto hr = DirectX::CreateStaticBuffer(m_device->impl->_device, data.data(), data.size(), sizeof(T), D3D11_BIND_VERTEX_BUFFER, &impl->dxBuffer); - - if (FAILED(hr)) { - xna_error_apply(err, XnaErrorCode::FAILED_OPERATION); - return false; - } - - impl->size = sizeof(T); - - return true; - } -} - -#endif \ No newline at end of file diff --git a/inc/xna/platform-dx/steptimer.hpp b/inc/xna/platform-dx/steptimer.hpp deleted file mode 100644 index cf9bdfd..0000000 --- a/inc/xna/platform-dx/steptimer.hpp +++ /dev/null @@ -1,195 +0,0 @@ -#ifndef XNA_PLATFORM_DX_STEPTIMER_HPP -#define XNA_PLATFORM_DX_STEPTIMER_HPP -// -// StepTimer.h - A simple timer that provides elapsed time information -// -// https://github.com/microsoft/DirectXTK/wiki/StepTimer - -#pragma once - -#include -#include -#include -#include "headers.hpp" - -namespace xna -{ - // Helper class for animation and simulation timing. - class StepTimer - { - public: - StepTimer() noexcept(false) : - m_elapsedTicks(0), - m_totalTicks(0), - m_leftOverTicks(0), - m_frameCount(0), - m_framesPerSecond(0), - m_framesThisSecond(0), - m_qpcSecondCounter(0), - m_isFixedTimeStep(false), - m_targetElapsedTicks(TicksPerSecond / 60) - { - if (!QueryPerformanceFrequency(&m_qpcFrequency)) - { - throw std::exception(); - } - - if (!QueryPerformanceCounter(&m_qpcLastTime)) - { - throw std::exception(); - } - - // Initialize max delta to 1/10 of a second. - m_qpcMaxDelta = static_cast(m_qpcFrequency.QuadPart / 10); - } - - // Get elapsed time since the previous Update call. - uint64_t GetElapsedTicks() const noexcept { return m_elapsedTicks; } - double GetElapsedSeconds() const noexcept { return TicksToSeconds(m_elapsedTicks); } - - // Get total time since the start of the program. - uint64_t GetTotalTicks() const noexcept { return m_totalTicks; } - double GetTotalSeconds() const noexcept { return TicksToSeconds(m_totalTicks); } - - // Get total number of updates since start of the program. - uint32_t GetFrameCount() const noexcept { return m_frameCount; } - - // Get the current framerate. - uint32_t GetFramesPerSecond() const noexcept { return m_framesPerSecond; } - - // Set whether to use fixed or variable timestep mode. - void SetFixedTimeStep(bool isFixedTimestep) noexcept { m_isFixedTimeStep = isFixedTimestep; } - - // Set how often to call Update when in fixed timestep mode. - void SetTargetElapsedTicks(uint64_t targetElapsed) noexcept { m_targetElapsedTicks = targetElapsed; } - void SetTargetElapsedSeconds(double targetElapsed) noexcept { m_targetElapsedTicks = SecondsToTicks(targetElapsed); } - - // Integer format represents time using 10,000,000 ticks per second. - static constexpr uint64_t TicksPerSecond = 10000000; - - static constexpr double TicksToSeconds(uint64_t ticks) noexcept { return static_cast(ticks) / TicksPerSecond; } - static constexpr uint64_t SecondsToTicks(double seconds) noexcept { return static_cast(seconds * TicksPerSecond); } - - // After an intentional timing discontinuity (for instance a blocking IO operation) - // call this to avoid having the fixed timestep logic attempt a set of catch-up - // Update calls. - - void ResetElapsedTime() - { - if (!QueryPerformanceCounter(&m_qpcLastTime)) - { - throw std::exception(); - } - - m_leftOverTicks = 0; - m_framesPerSecond = 0; - m_framesThisSecond = 0; - m_qpcSecondCounter = 0; - } - - // Update timer state, calling the specified Update function the appropriate number of times. - template - void Tick(const TUpdate& update) - { - // Query the current time. - LARGE_INTEGER currentTime; - - if (!QueryPerformanceCounter(¤tTime)) - { - throw std::exception(); - } - - uint64_t timeDelta = static_cast(currentTime.QuadPart - m_qpcLastTime.QuadPart); - - m_qpcLastTime = currentTime; - m_qpcSecondCounter += timeDelta; - - // Clamp excessively large time deltas (e.g. after paused in the debugger). - if (timeDelta > m_qpcMaxDelta) - { - timeDelta = m_qpcMaxDelta; - } - - // Convert QPC units into a canonical tick format. This cannot overflow due to the previous clamp. - timeDelta *= TicksPerSecond; - timeDelta /= static_cast(m_qpcFrequency.QuadPart); - - const uint32_t lastFrameCount = m_frameCount; - - if (m_isFixedTimeStep) - { - // Fixed timestep update logic - - // If the app is running very close to the target elapsed time (within 1/4 of a millisecond) just clamp - // the clock to exactly match the target value. This prevents tiny and irrelevant errors - // from accumulating over time. Without this clamping, a game that requested a 60 fps - // fixed update, running with vsync enabled on a 59.94 NTSC display, would eventually - // accumulate enough tiny errors that it would drop a frame. It is better to just round - // small deviations down to zero to leave things running smoothly. - - if (static_cast(std::abs(static_cast(timeDelta - m_targetElapsedTicks))) < TicksPerSecond / 4000) - { - timeDelta = m_targetElapsedTicks; - } - - m_leftOverTicks += timeDelta; - - while (m_leftOverTicks >= m_targetElapsedTicks) - { - m_elapsedTicks = m_targetElapsedTicks; - m_totalTicks += m_targetElapsedTicks; - m_leftOverTicks -= m_targetElapsedTicks; - m_frameCount++; - - update(); - } - } - else - { - // Variable timestep update logic. - m_elapsedTicks = timeDelta; - m_totalTicks += timeDelta; - m_leftOverTicks = 0; - m_frameCount++; - - update(); - } - - // Track the current framerate. - if (m_frameCount != lastFrameCount) - { - m_framesThisSecond++; - } - - if (m_qpcSecondCounter >= static_cast(m_qpcFrequency.QuadPart)) - { - m_framesPerSecond = m_framesThisSecond; - m_framesThisSecond = 0; - m_qpcSecondCounter %= static_cast(m_qpcFrequency.QuadPart); - } - } - - private: - // Source timing data uses QPC units. - LARGE_INTEGER m_qpcFrequency; - LARGE_INTEGER m_qpcLastTime; - uint64_t m_qpcMaxDelta; - - // Derived timing data uses a canonical tick format. - uint64_t m_elapsedTicks; - uint64_t m_totalTicks; - uint64_t m_leftOverTicks; - - // Members for tracking the framerate. - uint32_t m_frameCount; - uint32_t m_framesPerSecond; - uint32_t m_framesThisSecond; - uint64_t m_qpcSecondCounter; - - // Members for configuring fixed timestep mode. - bool m_isFixedTimeStep; - uint64_t m_targetElapsedTicks; - }; -} - -#endif diff --git a/inc/xna/platform-dx/xna-dx.hpp b/inc/xna/platform-dx/xna-dx.hpp deleted file mode 100644 index 7bf56eb..0000000 --- a/inc/xna/platform-dx/xna-dx.hpp +++ /dev/null @@ -1,4 +0,0 @@ -#include "headers.hpp" -#include "implementations.hpp" -#include "init.hpp" -#include "steptimer.hpp" \ No newline at end of file diff --git a/inc/xna/xna.hpp b/inc/xna/xna.hpp index 09c8323..e2d56e8 100644 --- a/inc/xna/xna.hpp +++ b/inc/xna/xna.hpp @@ -53,4 +53,4 @@ #include "input/keyboard.hpp" #include "input/mouse.hpp" #include "platforminit.hpp" -#include "platform-dx/xna-dx.hpp" \ No newline at end of file +#include "xna/platform-dx/dx.hpp" \ No newline at end of file