Build: Rename duckstation to duckstation-sdl

This commit is contained in:
Connor McLaughlin
2020-02-03 14:16:59 +10:00
parent 6c8eaa5204
commit ec55ab7f5e
23 changed files with 24 additions and 24 deletions

View File

@ -0,0 +1,27 @@
add_executable(duckstation-sdl
icon.cpp
icon.h
imgui_impl_sdl.cpp
imgui_impl_sdl.h
imgui_styles.cpp
imgui_styles.h
main.cpp
opengl_host_display.cpp
opengl_host_display.h
sdl_audio_stream.cpp
sdl_audio_stream.h
sdl_host_interface.cpp
sdl_host_interface.h
sdl_settings_interface.cpp
sdl_settings_interface.h
)
if(WIN32)
target_sources(duckstation-sdl PRIVATE
d3d11_host_display.cpp
d3d11_host_display.h
)
target_link_libraries(duckstation-sdl PRIVATE d3d11.lib dxgi.lib winmm.lib)
endif()
target_link_libraries(duckstation-sdl PRIVATE core common imgui nativefiledialog glad simpleini SDL2::Main)

View File

@ -0,0 +1,429 @@
#include "d3d11_host_display.h"
#include "common/assert.h"
#include "common/d3d11/shader_compiler.h"
#include "common/log.h"
#include <SDL_syswm.h>
#include <array>
#include <dxgi1_5.h>
#include <imgui.h>
#include <imgui_impl_dx11.h>
#include "imgui_impl_sdl.h"
Log_SetChannel(D3D11HostDisplay);
class D3D11HostDisplayTexture : public HostDisplayTexture
{
public:
template<typename T>
using ComPtr = Microsoft::WRL::ComPtr<T>;
D3D11HostDisplayTexture(ComPtr<ID3D11Texture2D> texture, ComPtr<ID3D11ShaderResourceView> srv, u32 width, u32 height,
bool dynamic)
: m_texture(std::move(texture)), m_srv(std::move(srv)), m_width(width), m_height(height), m_dynamic(dynamic)
{
}
~D3D11HostDisplayTexture() override = default;
void* GetHandle() const override { return m_srv.Get(); }
u32 GetWidth() const override { return m_width; }
u32 GetHeight() const override { return m_height; }
ID3D11Texture2D* GetD3DTexture() const { return m_texture.Get(); }
ID3D11ShaderResourceView* GetD3DSRV() const { return m_srv.Get(); }
bool IsDynamic() const { return m_dynamic; }
static std::unique_ptr<D3D11HostDisplayTexture> Create(ID3D11Device* device, u32 width, u32 height, const void* data,
u32 data_stride, bool dynamic)
{
const CD3D11_TEXTURE2D_DESC desc(DXGI_FORMAT_R8G8B8A8_UNORM, width, height, 1, 1, D3D11_BIND_SHADER_RESOURCE,
dynamic ? D3D11_USAGE_DYNAMIC : D3D11_USAGE_DEFAULT,
dynamic ? D3D11_CPU_ACCESS_WRITE : 0, 1, 0, 0);
const D3D11_SUBRESOURCE_DATA srd{data, data_stride, data_stride * height};
ComPtr<ID3D11Texture2D> texture;
HRESULT hr = device->CreateTexture2D(&desc, data ? &srd : nullptr, texture.GetAddressOf());
if (FAILED(hr))
return {};
const CD3D11_SHADER_RESOURCE_VIEW_DESC srv_desc(D3D11_SRV_DIMENSION_TEXTURE2D, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 1, 0,
1);
ComPtr<ID3D11ShaderResourceView> srv;
hr = device->CreateShaderResourceView(texture.Get(), &srv_desc, srv.GetAddressOf());
if (FAILED(hr))
return {};
return std::make_unique<D3D11HostDisplayTexture>(std::move(texture), std::move(srv), width, height, dynamic);
}
private:
ComPtr<ID3D11Texture2D> m_texture;
ComPtr<ID3D11ShaderResourceView> m_srv;
u32 m_width;
u32 m_height;
bool m_dynamic;
};
D3D11HostDisplay::D3D11HostDisplay(SDL_Window* window) : m_window(window)
{
SDL_GetWindowSize(window, &m_window_width, &m_window_height);
}
D3D11HostDisplay::~D3D11HostDisplay()
{
ImGui_ImplDX11_Shutdown();
ImGui_ImplSDL2_Shutdown();
if (m_window)
SDL_DestroyWindow(m_window);
}
HostDisplay::RenderAPI D3D11HostDisplay::GetRenderAPI() const
{
return HostDisplay::RenderAPI::D3D11;
}
void* D3D11HostDisplay::GetRenderDevice() const
{
return m_device.Get();
}
void* D3D11HostDisplay::GetRenderContext() const
{
return m_context.Get();
}
void* D3D11HostDisplay::GetRenderWindow() const
{
return m_window;
}
void D3D11HostDisplay::ChangeRenderWindow(void* new_window)
{
Panic("Not supported");
}
std::unique_ptr<HostDisplayTexture> D3D11HostDisplay::CreateTexture(u32 width, u32 height, const void* data,
u32 data_stride, bool dynamic)
{
return D3D11HostDisplayTexture::Create(m_device.Get(), width, height, data, data_stride, dynamic);
}
void D3D11HostDisplay::UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* data,
u32 data_stride)
{
D3D11HostDisplayTexture* d3d11_texture = static_cast<D3D11HostDisplayTexture*>(texture);
if (!d3d11_texture->IsDynamic())
{
const CD3D11_BOX dst_box(x, y, 0, x + width, y + height, 1);
m_context->UpdateSubresource(d3d11_texture->GetD3DTexture(), 0, &dst_box, data, data_stride, data_stride * height);
}
else
{
D3D11_MAPPED_SUBRESOURCE sr;
HRESULT hr = m_context->Map(d3d11_texture->GetD3DTexture(), 0, D3D11_MAP_WRITE_DISCARD, 0, &sr);
if (FAILED(hr))
Panic("Failed to map dynamic host display texture");
char* dst_ptr = static_cast<char*>(sr.pData) + (y * sr.RowPitch) + (x * sizeof(u32));
const char* src_ptr = static_cast<const char*>(data);
if (sr.RowPitch == data_stride)
{
std::memcpy(dst_ptr, src_ptr, data_stride * height);
}
else
{
for (u32 row = 0; row < height; row++)
{
std::memcpy(dst_ptr, src_ptr, width * sizeof(u32));
src_ptr += data_stride;
dst_ptr += sr.RowPitch;
}
}
m_context->Unmap(d3d11_texture->GetD3DTexture(), 0);
}
}
void D3D11HostDisplay::SetVSync(bool enabled)
{
m_vsync = enabled;
}
std::tuple<u32, u32> D3D11HostDisplay::GetWindowSize() const
{
return std::make_tuple(static_cast<u32>(m_window_width), static_cast<u32>(m_window_height));
}
void D3D11HostDisplay::WindowResized()
{
SDL_GetWindowSize(m_window, &m_window_width, &m_window_height);
m_swap_chain_rtv.Reset();
HRESULT hr = m_swap_chain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN,
m_allow_tearing_supported ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0);
if (FAILED(hr))
Log_ErrorPrintf("ResizeBuffers() failed: 0x%08X", hr);
if (!CreateSwapChainRTV())
Panic("Failed to recreate swap chain RTV after resize");
}
bool D3D11HostDisplay::CreateD3DDevice(bool debug_device)
{
SDL_SysWMinfo syswm = {};
if (!SDL_GetWindowWMInfo(m_window, &syswm))
{
Log_ErrorPrintf("SDL_GetWindowWMInfo failed");
return false;
}
ComPtr<IDXGIFactory> dxgi_factory;
HRESULT hr = CreateDXGIFactory(IID_PPV_ARGS(dxgi_factory.GetAddressOf()));
if (FAILED(hr))
{
Log_ErrorPrintf("Failed to create DXGI factory: 0x%08X", hr);
return false;
}
m_allow_tearing_supported = false;
ComPtr<IDXGIFactory5> dxgi_factory5;
hr = dxgi_factory.As(&dxgi_factory5);
if (SUCCEEDED(hr))
{
BOOL allow_tearing_supported = false;
hr = dxgi_factory5->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allow_tearing_supported,
sizeof(allow_tearing_supported));
if (SUCCEEDED(hr))
m_allow_tearing_supported = (allow_tearing_supported == TRUE);
}
UINT create_flags = 0;
if (debug_device)
create_flags |= D3D11_CREATE_DEVICE_DEBUG;
hr = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, create_flags, nullptr, 0, D3D11_SDK_VERSION,
m_device.GetAddressOf(), nullptr, m_context.GetAddressOf());
if (FAILED(hr))
{
Log_ErrorPrintf("Failed to create D3D device: 0x%08X", hr);
return false;
}
DXGI_SWAP_CHAIN_DESC swap_chain_desc = {};
swap_chain_desc.BufferDesc.Width = m_window_width;
swap_chain_desc.BufferDesc.Height = m_window_height;
swap_chain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swap_chain_desc.SampleDesc.Count = 1;
swap_chain_desc.BufferCount = 3;
swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swap_chain_desc.OutputWindow = syswm.info.win.window;
swap_chain_desc.Windowed = TRUE;
swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
if (m_allow_tearing_supported)
swap_chain_desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
hr = dxgi_factory->CreateSwapChain(m_device.Get(), &swap_chain_desc, m_swap_chain.GetAddressOf());
if (FAILED(hr))
{
Log_WarningPrintf("Failed to create a flip-discard swap chain, trying discard.");
swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
swap_chain_desc.Flags = 0;
m_allow_tearing_supported = false;
hr = dxgi_factory->CreateSwapChain(m_device.Get(), &swap_chain_desc, m_swap_chain.GetAddressOf());
if (FAILED(hr))
{
Log_ErrorPrintf("CreateSwapChain failed: 0x%08X", hr);
return false;
}
}
if (debug_device)
{
ComPtr<ID3D11InfoQueue> info;
hr = m_device.As(&info);
if (SUCCEEDED(hr))
{
info->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, TRUE);
info->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_WARNING, TRUE);
}
}
return true;
}
bool D3D11HostDisplay::CreateSwapChainRTV()
{
ComPtr<ID3D11Texture2D> backbuffer;
HRESULT hr = m_swap_chain->GetBuffer(0, IID_PPV_ARGS(backbuffer.GetAddressOf()));
if (FAILED(hr))
{
Log_ErrorPrintf("GetBuffer for RTV failed: 0x%08X", hr);
return false;
}
D3D11_TEXTURE2D_DESC backbuffer_desc;
backbuffer->GetDesc(&backbuffer_desc);
CD3D11_RENDER_TARGET_VIEW_DESC rtv_desc(D3D11_RTV_DIMENSION_TEXTURE2D, backbuffer_desc.Format, 0, 0,
backbuffer_desc.ArraySize);
hr = m_device->CreateRenderTargetView(backbuffer.Get(), &rtv_desc, m_swap_chain_rtv.GetAddressOf());
if (FAILED(hr))
{
Log_ErrorPrintf("CreateRenderTargetView for swap chain failed: 0x%08X", hr);
return false;
}
return true;
}
bool D3D11HostDisplay::CreateD3DResources()
{
static constexpr char fullscreen_quad_vertex_shader[] = R"(
cbuffer UBOBlock : register(b0)
{
float4 u_src_rect;
};
void main(in uint vertex_id : SV_VertexID,
out float2 v_tex0 : TEXCOORD0,
out float4 o_pos : SV_Position)
{
float2 pos = float2(float((vertex_id << 1) & 2u), float(vertex_id & 2u));
v_tex0 = u_src_rect.xy + pos * u_src_rect.zw;
o_pos = float4(pos * float2(2.0f, -2.0f) + float2(-1.0f, 1.0f), 0.0f, 1.0f);
}
)";
static constexpr char display_pixel_shader[] = R"(
Texture2D samp0 : register(t0);
SamplerState samp0_ss : register(s0);
void main(in float2 v_tex0 : TEXCOORD0,
out float4 o_col0 : SV_Target)
{
o_col0 = samp0.Sample(samp0_ss, v_tex0);
}
)";
HRESULT hr;
m_display_vertex_shader =
D3D11::ShaderCompiler::CompileAndCreateVertexShader(m_device.Get(), fullscreen_quad_vertex_shader, false);
m_display_pixel_shader =
D3D11::ShaderCompiler::CompileAndCreatePixelShader(m_device.Get(), display_pixel_shader, false);
if (!m_display_vertex_shader || !m_display_pixel_shader)
return false;
if (!m_display_uniform_buffer.Create(m_device.Get(), D3D11_BIND_CONSTANT_BUFFER, DISPLAY_UNIFORM_BUFFER_SIZE))
return false;
CD3D11_RASTERIZER_DESC rasterizer_desc = CD3D11_RASTERIZER_DESC(CD3D11_DEFAULT());
rasterizer_desc.CullMode = D3D11_CULL_NONE;
hr = m_device->CreateRasterizerState(&rasterizer_desc, m_display_rasterizer_state.GetAddressOf());
if (FAILED(hr))
return false;
CD3D11_DEPTH_STENCIL_DESC depth_stencil_desc = CD3D11_DEPTH_STENCIL_DESC(CD3D11_DEFAULT());
depth_stencil_desc.DepthEnable = FALSE;
depth_stencil_desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
hr = m_device->CreateDepthStencilState(&depth_stencil_desc, m_display_depth_stencil_state.GetAddressOf());
if (FAILED(hr))
return false;
CD3D11_BLEND_DESC blend_desc = CD3D11_BLEND_DESC(CD3D11_DEFAULT());
hr = m_device->CreateBlendState(&blend_desc, m_display_blend_state.GetAddressOf());
if (FAILED(hr))
return false;
CD3D11_SAMPLER_DESC sampler_desc = CD3D11_SAMPLER_DESC(CD3D11_DEFAULT());
sampler_desc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
hr = m_device->CreateSamplerState(&sampler_desc, m_point_sampler.GetAddressOf());
if (FAILED(hr))
return false;
sampler_desc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;
hr = m_device->CreateSamplerState(&sampler_desc, m_linear_sampler.GetAddressOf());
if (FAILED(hr))
return false;
return true;
}
bool D3D11HostDisplay::CreateImGuiContext()
{
if (!ImGui_ImplSDL2_InitForD3D(m_window) || !ImGui_ImplDX11_Init(m_device.Get(), m_context.Get()))
return false;
ImGui_ImplDX11_NewFrame();
ImGui_ImplSDL2_NewFrame(m_window);
return true;
}
std::unique_ptr<HostDisplay> D3D11HostDisplay::Create(SDL_Window* window, bool debug_device)
{
std::unique_ptr<D3D11HostDisplay> display = std::make_unique<D3D11HostDisplay>(window);
if (!display->CreateD3DDevice(debug_device) || !display->CreateSwapChainRTV() || !display->CreateD3DResources() ||
!display->CreateImGuiContext())
{
return nullptr;
}
return display;
}
void D3D11HostDisplay::Render()
{
static constexpr std::array<float, 4> clear_color = {};
m_context->ClearRenderTargetView(m_swap_chain_rtv.Get(), clear_color.data());
m_context->OMSetRenderTargets(1, m_swap_chain_rtv.GetAddressOf(), nullptr);
RenderDisplay();
ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
if (!m_vsync && m_allow_tearing_supported)
m_swap_chain->Present(0, DXGI_PRESENT_ALLOW_TEARING);
else
m_swap_chain->Present(BoolToUInt32(m_vsync), 0);
ImGui_ImplSDL2_NewFrame(m_window);
ImGui_ImplDX11_NewFrame();
}
void D3D11HostDisplay::RenderDisplay()
{
if (!m_display_texture_handle)
return;
// - 20 for main menu padding
auto [vp_left, vp_top, vp_width, vp_height] =
CalculateDrawRect(m_window_width, std::max(m_window_height - m_display_top_margin, 1), m_display_aspect_ratio);
vp_top += m_display_top_margin;
m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
m_context->VSSetShader(m_display_vertex_shader.Get(), nullptr, 0);
m_context->PSSetShader(m_display_pixel_shader.Get(), nullptr, 0);
m_context->PSSetShaderResources(0, 1, reinterpret_cast<ID3D11ShaderResourceView**>(&m_display_texture_handle));
m_context->PSSetSamplers(
0, 1, m_display_linear_filtering ? m_linear_sampler.GetAddressOf() : m_point_sampler.GetAddressOf());
const float uniforms[4] = {static_cast<float>(m_display_offset_x) / static_cast<float>(m_display_texture_width),
static_cast<float>(m_display_offset_y) / static_cast<float>(m_display_texture_height),
static_cast<float>(m_display_width) / static_cast<float>(m_display_texture_width),
static_cast<float>(m_display_height) / static_cast<float>(m_display_texture_height)};
const auto map = m_display_uniform_buffer.Map(m_context.Get(), sizeof(uniforms), sizeof(uniforms));
std::memcpy(map.pointer, uniforms, sizeof(uniforms));
m_display_uniform_buffer.Unmap(m_context.Get(), sizeof(uniforms));
m_context->VSSetConstantBuffers(0, 1, m_display_uniform_buffer.GetD3DBufferArray());
const CD3D11_VIEWPORT vp(static_cast<float>(vp_left), static_cast<float>(vp_top), static_cast<float>(vp_width),
static_cast<float>(vp_height));
m_context->RSSetViewports(1, &vp);
m_context->RSSetState(m_display_rasterizer_state.Get());
m_context->OMSetDepthStencilState(m_display_depth_stencil_state.Get(), 0);
m_context->OMSetBlendState(m_display_blend_state.Get(), nullptr, 0xFFFFFFFFu);
m_context->Draw(3, 0);
}

View File

@ -0,0 +1,73 @@
#pragma once
#include "common/d3d11/stream_buffer.h"
#include "common/d3d11/texture.h"
#include "common/windows_headers.h"
#include "core/host_display.h"
#include <SDL.h>
#include <d3d11.h>
#include <memory>
#include <wrl/client.h>
class D3D11HostDisplay final : public HostDisplay
{
public:
template<typename T>
using ComPtr = Microsoft::WRL::ComPtr<T>;
D3D11HostDisplay(SDL_Window* window);
~D3D11HostDisplay();
static std::unique_ptr<HostDisplay> Create(SDL_Window* window, bool debug_device);
RenderAPI GetRenderAPI() const override;
void* GetRenderDevice() const override;
void* GetRenderContext() const override;
void* GetRenderWindow() const override;
void ChangeRenderWindow(void* new_window) override;
std::unique_ptr<HostDisplayTexture> CreateTexture(u32 width, u32 height, const void* data, u32 data_stride,
bool dynamic) override;
void UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* data,
u32 data_stride) override;
void SetVSync(bool enabled) override;
std::tuple<u32, u32> GetWindowSize() const override;
void WindowResized() override;
private:
static constexpr u32 DISPLAY_UNIFORM_BUFFER_SIZE = 16;
bool CreateD3DDevice(bool debug_device);
bool CreateD3DResources();
bool CreateSwapChainRTV();
bool CreateImGuiContext();
void Render();
void RenderDisplay();
SDL_Window* m_window = nullptr;
SDL_GLContext m_gl_context = nullptr;
int m_window_width = 0;
int m_window_height = 0;
ComPtr<ID3D11Device> m_device;
ComPtr<ID3D11DeviceContext> m_context;
ComPtr<IDXGISwapChain> m_swap_chain;
ComPtr<ID3D11RenderTargetView> m_swap_chain_rtv;
ComPtr<ID3D11RasterizerState> m_display_rasterizer_state;
ComPtr<ID3D11DepthStencilState> m_display_depth_stencil_state;
ComPtr<ID3D11BlendState> m_display_blend_state;
ComPtr<ID3D11VertexShader> m_display_vertex_shader;
ComPtr<ID3D11PixelShader> m_display_pixel_shader;
ComPtr<ID3D11SamplerState> m_point_sampler;
ComPtr<ID3D11SamplerState> m_linear_sampler;
D3D11::Texture m_display_pixels_texture;
D3D11::StreamBuffer m_display_uniform_buffer;
bool m_allow_tearing_supported = false;
bool m_vsync = false;
};

View File

@ -0,0 +1,395 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="DebugFast|Win32">
<Configuration>DebugFast</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="DebugFast|x64">
<Configuration>DebugFast</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="ReleaseLTCG|Win32">
<Configuration>ReleaseLTCG</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="ReleaseLTCG|x64">
<Configuration>ReleaseLTCG</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\dep\imgui\imgui.vcxproj">
<Project>{bb08260f-6fbc-46af-8924-090ee71360c6}</Project>
</ProjectReference>
<ProjectReference Include="..\..\dep\nativefiledialog\nativefiledialog.vcxproj">
<Project>{ace32f47-2960-4fb3-9f77-2c375625bf61}</Project>
</ProjectReference>
<ProjectReference Include="..\common\common.vcxproj">
<Project>{ee054e08-3799-4a59-a422-18259c105ffd}</Project>
</ProjectReference>
<ProjectReference Include="..\core\core.vcxproj">
<Project>{868b98c8-65a1-494b-8346-250a73a48c0a}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ClCompile Include="d3d11_host_display.cpp" />
<ClCompile Include="imgui_impl_sdl.cpp" />
<ClCompile Include="imgui_styles.cpp" />
<ClCompile Include="opengl_host_display.cpp" />
<ClCompile Include="icon.cpp" />
<ClCompile Include="sdl_audio_stream.cpp" />
<ClCompile Include="sdl_host_interface.cpp" />
<ClCompile Include="main.cpp" />
<ClCompile Include="sdl_settings_interface.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="d3d11_host_display.h" />
<ClInclude Include="imgui_impl_sdl.h" />
<ClInclude Include="imgui_styles.h" />
<ClInclude Include="opengl_host_display.h" />
<ClInclude Include="icon.h" />
<ClInclude Include="sdl_audio_stream.h" />
<ClInclude Include="sdl_host_interface.h" />
<ClInclude Include="sdl_settings_interface.h" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>duckstation-sdl</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<ImportGroup Label="ExtensionSettings">
<Import Project="..\..\dep\msvc\vsprops\SDL2Compile.props" />
</ImportGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)bin\$(Platform)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</IntDir>
<TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<IntDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</IntDir>
<TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)bin\$(Platform)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)bin\$(Platform)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</IntDir>
<TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'">
<IntDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</IntDir>
<TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)bin\$(Platform)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>$(SolutionDir)bin\$(Platform)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</IntDir>
<TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)bin\$(Platform)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</IntDir>
<TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<IntDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</IntDir>
<TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>
<OutDir>$(SolutionDir)bin\$(Platform)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|x64'">
<IntDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</IntDir>
<TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)bin\$(Platform)\</OutDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include;$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\nativefiledialog\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<MinimalRebuild>false</MinimalRebuild>
<LanguageStandard>stdcpp17</LanguageStandard>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>d3d11.lib;dxgi.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include;$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\nativefiledialog\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<MinimalRebuild>false</MinimalRebuild>
<LanguageStandard>stdcpp17</LanguageStandard>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>d3d11.lib;dxgi.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_ITERATOR_DEBUG_LEVEL=1;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUGFAST;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include;$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\nativefiledialog\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<MinimalRebuild>false</MinimalRebuild>
<LanguageStandard>stdcpp17</LanguageStandard>
<SupportJustMyCode>false</SupportJustMyCode>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>d3d11.lib;dxgi.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_ITERATOR_DEBUG_LEVEL=1;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUGFAST;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include;$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\nativefiledialog\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<MinimalRebuild>false</MinimalRebuild>
<LanguageStandard>stdcpp17</LanguageStandard>
<SupportJustMyCode>false</SupportJustMyCode>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>d3d11.lib;dxgi.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include;$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\nativefiledialog\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<WholeProgramOptimization>false</WholeProgramOptimization>
<LanguageStandard>stdcpp17</LanguageStandard>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>d3d11.lib;dxgi.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
<LinkTimeCodeGeneration>Default</LinkTimeCodeGeneration>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|Win32'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include;$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\nativefiledialog\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<WholeProgramOptimization>true</WholeProgramOptimization>
<LanguageStandard>stdcpp17</LanguageStandard>
<OmitFramePointers>true</OmitFramePointers>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>d3d11.lib;dxgi.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include;$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\nativefiledialog\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<WholeProgramOptimization>false</WholeProgramOptimization>
<LanguageStandard>stdcpp17</LanguageStandard>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>d3d11.lib;dxgi.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
<LinkTimeCodeGeneration>Default</LinkTimeCodeGeneration>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|x64'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include;$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\nativefiledialog\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<WholeProgramOptimization>true</WholeProgramOptimization>
<LanguageStandard>stdcpp17</LanguageStandard>
<OmitFramePointers>true</OmitFramePointers>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>d3d11.lib;dxgi.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="main.cpp" />
<ClCompile Include="sdl_audio_stream.cpp" />
<ClCompile Include="icon.cpp" />
<ClCompile Include="opengl_host_display.cpp" />
<ClCompile Include="sdl_host_interface.cpp" />
<ClCompile Include="d3d11_host_display.cpp" />
<ClCompile Include="imgui_styles.cpp" />
<ClCompile Include="sdl_settings_interface.cpp" />
<ClCompile Include="imgui_impl_sdl.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="icon.h" />
<ClInclude Include="sdl_audio_stream.h" />
<ClInclude Include="opengl_host_display.h" />
<ClInclude Include="sdl_host_interface.h" />
<ClInclude Include="d3d11_host_display.h" />
<ClInclude Include="imgui_styles.h" />
<ClInclude Include="sdl_settings_interface.h" />
<ClInclude Include="imgui_impl_sdl.h" />
</ItemGroup>
</Project>

File diff suppressed because it is too large Load Diff

7975
src/duckstation-sdl/icon.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,9 @@
#pragma once
constexpr int WINDOW_ICON_WIDTH = 64;
constexpr int WINDOW_ICON_HEIGHT = 64;
extern unsigned int WINDOW_ICON_DATA[WINDOW_ICON_WIDTH * WINDOW_ICON_HEIGHT];
constexpr int APP_ICON_WIDTH = 260;
constexpr int APP_ICON_HEIGHT = 260;
extern unsigned int APP_ICON_DATA[APP_ICON_WIDTH * APP_ICON_HEIGHT];

View File

@ -0,0 +1,680 @@
// dear imgui: Platform Binding for SDL2
// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
// (Info: SDL2 is a cross-platform general purpose library for handling windows, inputs, graphics context creation, etc.)
// (Requires: SDL 2.0. Prefer SDL 2.0.4+ for full feature support.)
// Implemented features:
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
// [X] Platform: Clipboard support.
// [X] Platform: Keyboard arrays indexed using SDL_SCANCODE_* codes, e.g. ImGui::IsKeyPressed(SDL_SCANCODE_SPACE).
// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
// [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
// Missing features:
// [ ] Platform: SDL2 handling of IME under Windows appears to be broken and it explicitly disable the regular Windows IME. You can restore Windows IME by compiling SDL with SDL_DISABLE_WINDOWS_IME.
// [ ] Platform: Multi-viewport + Minimized windows seems to break mouse wheel events (at least under Windows).
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
// https://github.com/ocornut/imgui
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2019-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
// 2019-07-21: Inputs: Added mapping for ImGuiKey_KeyPadEnter.
// 2019-04-23: Inputs: Added support for SDL_GameController (if ImGuiConfigFlags_NavEnableGamepad is set by user application).
// 2019-03-12: Misc: Preserve DisplayFramebufferScale when main window is minimized.
// 2018-12-21: Inputs: Workaround for Android/iOS which don't seem to handle focus related calls.
// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
// 2018-11-14: Changed the signature of ImGui_ImplSDL2_ProcessEvent() to take a 'const SDL_Event*'.
// 2018-08-01: Inputs: Workaround for Emscripten which doesn't seem to handle focus related calls.
// 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor.
// 2018-06-08: Misc: Extracted imgui_impl_sdl.cpp/.h away from the old combined SDL2+OpenGL/Vulkan examples.
// 2018-06-08: Misc: ImGui_ImplSDL2_InitForOpenGL() now takes a SDL_GLContext parameter.
// 2018-05-09: Misc: Fixed clipboard paste memory leak (we didn't call SDL_FreeMemory on the data returned by SDL_GetClipboardText).
// 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors flag + honor ImGuiConfigFlags_NoMouseCursorChange flag.
// 2018-02-16: Inputs: Added support for mouse cursors, honoring ImGui::GetMouseCursor() value.
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
// 2018-02-06: Inputs: Added mapping for ImGuiKey_Space.
// 2018-02-05: Misc: Using SDL_GetPerformanceCounter() instead of SDL_GetTicks() to be able to handle very high framerate (1000+ FPS).
// 2018-02-05: Inputs: Keyboard mapping is using scancodes everywhere instead of a confusing mixture of keycodes and scancodes.
// 2018-01-20: Inputs: Added Horizontal Mouse Wheel support.
// 2018-01-19: Inputs: When available (SDL 2.0.4+) using SDL_CaptureMouse() to retrieve coordinates outside of client area when dragging. Otherwise (SDL 2.0.3 and before) testing for SDL_WINDOW_INPUT_FOCUS instead of SDL_WINDOW_MOUSE_FOCUS.
// 2018-01-18: Inputs: Added mapping for ImGuiKey_Insert.
// 2017-08-25: Inputs: MousePos set to -FLT_MAX,-FLT_MAX when mouse is unavailable/missing (instead of -1,-1).
// 2016-10-15: Misc: Added a void* user_data parameter to Clipboard function handlers.
#include "imgui.h"
#include "imgui_impl_sdl.h"
// SDL
// (the multi-viewports feature requires SDL features supported from SDL 2.0.4+. SDL 2.0.5+ is highly recommended)
#include <SDL.h>
#include <SDL_syswm.h>
#if defined(__APPLE__)
#include "TargetConditionals.h"
#endif
#define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE SDL_VERSION_ATLEAST(2,0,4)
#define SDL_HAS_WINDOW_ALPHA SDL_VERSION_ATLEAST(2,0,5)
#define SDL_HAS_ALWAYS_ON_TOP SDL_VERSION_ATLEAST(2,0,5)
#define SDL_HAS_USABLE_DISPLAY_BOUNDS SDL_VERSION_ATLEAST(2,0,5)
#define SDL_HAS_PER_MONITOR_DPI SDL_VERSION_ATLEAST(2,0,4)
#define SDL_HAS_VULKAN SDL_VERSION_ATLEAST(2,0,6)
#define SDL_HAS_MOUSE_FOCUS_CLICKTHROUGH SDL_VERSION_ATLEAST(2,0,5)
#if !SDL_HAS_VULKAN
static const Uint32 SDL_WINDOW_VULKAN = 0x10000000;
#endif
// Data
static SDL_Window* g_Window = NULL;
static Uint64 g_Time = 0;
static bool g_MousePressed[3] = { false, false, false };
static SDL_Cursor* g_MouseCursors[ImGuiMouseCursor_COUNT] = {};
static char* g_ClipboardTextData = NULL;
// Forward Declarations
static void ImGui_ImplSDL2_InitPlatformInterface(SDL_Window* window, void* sdl_gl_context);
static void ImGui_ImplSDL2_ShutdownPlatformInterface();
static const char* ImGui_ImplSDL2_GetClipboardText(void*)
{
if (g_ClipboardTextData)
SDL_free(g_ClipboardTextData);
g_ClipboardTextData = SDL_GetClipboardText();
return g_ClipboardTextData;
}
static void ImGui_ImplSDL2_SetClipboardText(void*, const char* text)
{
SDL_SetClipboardText(text);
}
// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application.
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application.
// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
// If you have multiple SDL events and some of them are not meant to be used by dear imgui, you may need to filter events based on their windowID field.
bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event)
{
ImGuiIO& io = ImGui::GetIO();
switch (event->type)
{
case SDL_MOUSEWHEEL:
{
if (event->wheel.x > 0) io.MouseWheelH += 1;
if (event->wheel.x < 0) io.MouseWheelH -= 1;
if (event->wheel.y > 0) io.MouseWheel += 1;
if (event->wheel.y < 0) io.MouseWheel -= 1;
return true;
}
case SDL_MOUSEBUTTONDOWN:
{
if (event->button.button == SDL_BUTTON_LEFT) g_MousePressed[0] = true;
if (event->button.button == SDL_BUTTON_RIGHT) g_MousePressed[1] = true;
if (event->button.button == SDL_BUTTON_MIDDLE) g_MousePressed[2] = true;
return true;
}
case SDL_TEXTINPUT:
{
io.AddInputCharactersUTF8(event->text.text);
return true;
}
case SDL_KEYDOWN:
case SDL_KEYUP:
{
int key = event->key.keysym.scancode;
IM_ASSERT(key >= 0 && key < IM_ARRAYSIZE(io.KeysDown));
io.KeysDown[key] = (event->type == SDL_KEYDOWN);
io.KeyShift = ((SDL_GetModState() & KMOD_SHIFT) != 0);
io.KeyCtrl = ((SDL_GetModState() & KMOD_CTRL) != 0);
io.KeyAlt = ((SDL_GetModState() & KMOD_ALT) != 0);
io.KeySuper = ((SDL_GetModState() & KMOD_GUI) != 0);
return true;
}
// Multi-viewport support
case SDL_WINDOWEVENT:
Uint8 window_event = event->window.event;
if (window_event == SDL_WINDOWEVENT_CLOSE || window_event == SDL_WINDOWEVENT_MOVED || window_event == SDL_WINDOWEVENT_RESIZED)
if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle((void*)SDL_GetWindowFromID(event->window.windowID)))
{
if (window_event == SDL_WINDOWEVENT_CLOSE)
viewport->PlatformRequestClose = true;
if (window_event == SDL_WINDOWEVENT_MOVED)
viewport->PlatformRequestMove = true;
if (window_event == SDL_WINDOWEVENT_RESIZED)
viewport->PlatformRequestResize = true;
return true;
}
break;
}
return false;
}
static bool ImGui_ImplSDL2_Init(SDL_Window* window, void* sdl_gl_context)
{
g_Window = window;
// Setup back-end capabilities flags
ImGuiIO& io = ImGui::GetIO();
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE
io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports; // We can create multi-viewports on the Platform side (optional)
#endif
io.BackendPlatformName = "imgui_impl_sdl";
// Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array.
io.KeyMap[ImGuiKey_Tab] = SDL_SCANCODE_TAB;
io.KeyMap[ImGuiKey_LeftArrow] = SDL_SCANCODE_LEFT;
io.KeyMap[ImGuiKey_RightArrow] = SDL_SCANCODE_RIGHT;
io.KeyMap[ImGuiKey_UpArrow] = SDL_SCANCODE_UP;
io.KeyMap[ImGuiKey_DownArrow] = SDL_SCANCODE_DOWN;
io.KeyMap[ImGuiKey_PageUp] = SDL_SCANCODE_PAGEUP;
io.KeyMap[ImGuiKey_PageDown] = SDL_SCANCODE_PAGEDOWN;
io.KeyMap[ImGuiKey_Home] = SDL_SCANCODE_HOME;
io.KeyMap[ImGuiKey_End] = SDL_SCANCODE_END;
io.KeyMap[ImGuiKey_Insert] = SDL_SCANCODE_INSERT;
io.KeyMap[ImGuiKey_Delete] = SDL_SCANCODE_DELETE;
io.KeyMap[ImGuiKey_Backspace] = SDL_SCANCODE_BACKSPACE;
io.KeyMap[ImGuiKey_Space] = SDL_SCANCODE_SPACE;
io.KeyMap[ImGuiKey_Enter] = SDL_SCANCODE_RETURN;
io.KeyMap[ImGuiKey_Escape] = SDL_SCANCODE_ESCAPE;
io.KeyMap[ImGuiKey_KeyPadEnter] = SDL_SCANCODE_RETURN2;
io.KeyMap[ImGuiKey_A] = SDL_SCANCODE_A;
io.KeyMap[ImGuiKey_C] = SDL_SCANCODE_C;
io.KeyMap[ImGuiKey_V] = SDL_SCANCODE_V;
io.KeyMap[ImGuiKey_X] = SDL_SCANCODE_X;
io.KeyMap[ImGuiKey_Y] = SDL_SCANCODE_Y;
io.KeyMap[ImGuiKey_Z] = SDL_SCANCODE_Z;
io.SetClipboardTextFn = ImGui_ImplSDL2_SetClipboardText;
io.GetClipboardTextFn = ImGui_ImplSDL2_GetClipboardText;
io.ClipboardUserData = NULL;
g_MouseCursors[ImGuiMouseCursor_Arrow] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW);
g_MouseCursors[ImGuiMouseCursor_TextInput] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM);
g_MouseCursors[ImGuiMouseCursor_ResizeAll] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEALL);
g_MouseCursors[ImGuiMouseCursor_ResizeNS] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENS);
g_MouseCursors[ImGuiMouseCursor_ResizeEW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEWE);
g_MouseCursors[ImGuiMouseCursor_ResizeNESW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENESW);
g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENWSE);
g_MouseCursors[ImGuiMouseCursor_Hand] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND);
// Our mouse update function expect PlatformHandle to be filled for the main viewport
ImGuiViewport* main_viewport = ImGui::GetMainViewport();
main_viewport->PlatformHandle = (void*)window;
#if defined(_WIN32)
SDL_SysWMinfo info;
SDL_VERSION(&info.version);
if (SDL_GetWindowWMInfo(window, &info))
main_viewport->PlatformHandleRaw = info.info.win.window;
#endif
// We need SDL_CaptureMouse(), SDL_GetGlobalMouseState() from SDL 2.0.4+ to support multiple viewports.
// We left the call to ImGui_ImplSDL2_InitPlatformInterface() outside of #ifdef to avoid unused-function warnings.
if ((io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) && (io.BackendFlags & ImGuiBackendFlags_PlatformHasViewports))
ImGui_ImplSDL2_InitPlatformInterface(window, sdl_gl_context);
return true;
}
bool ImGui_ImplSDL2_InitForOpenGL(SDL_Window* window, void* sdl_gl_context)
{
(void)sdl_gl_context; // Viewport branch will need this.
return ImGui_ImplSDL2_Init(window, sdl_gl_context);
}
bool ImGui_ImplSDL2_InitForVulkan(SDL_Window* window)
{
#if !SDL_HAS_VULKAN
IM_ASSERT(0 && "Unsupported");
#endif
return ImGui_ImplSDL2_Init(window, NULL);
}
bool ImGui_ImplSDL2_InitForD3D(SDL_Window* window)
{
#if !defined(_WIN32)
IM_ASSERT(0 && "Unsupported");
#endif
return ImGui_ImplSDL2_Init(window, NULL);
}
void ImGui_ImplSDL2_Shutdown()
{
ImGui_ImplSDL2_ShutdownPlatformInterface();
g_Window = NULL;
// Destroy last known clipboard data
if (g_ClipboardTextData)
SDL_free(g_ClipboardTextData);
g_ClipboardTextData = NULL;
// Destroy SDL mouse cursors
for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++)
SDL_FreeCursor(g_MouseCursors[cursor_n]);
memset(g_MouseCursors, 0, sizeof(g_MouseCursors));
}
// This code is incredibly messy because some of the functions we need for full viewport support are not available in SDL < 2.0.4.
static void ImGui_ImplSDL2_UpdateMousePosAndButtons()
{
ImGuiIO& io = ImGui::GetIO();
io.MouseHoveredViewport = 0;
// [1]
// Only when requested by io.WantSetMousePos: set OS mouse pos from Dear ImGui mouse pos.
// (rarely used, mostly when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
if (io.WantSetMousePos)
{
#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
SDL_WarpMouseGlobal((int)io.MousePos.x, (int)io.MousePos.y);
else
#endif
SDL_WarpMouseInWindow(g_Window, (int)io.MousePos.x, (int)io.MousePos.y);
}
else
{
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
}
// [2]
// Set Dear ImGui mouse pos from OS mouse pos + get buttons. (this is the common behavior)
int mouse_x_local, mouse_y_local;
Uint32 mouse_buttons = SDL_GetMouseState(&mouse_x_local, &mouse_y_local);
io.MouseDown[0] = g_MousePressed[0] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_LEFT)) != 0; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
io.MouseDown[1] = g_MousePressed[1] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_RIGHT)) != 0;
io.MouseDown[2] = g_MousePressed[2] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_MIDDLE)) != 0;
g_MousePressed[0] = g_MousePressed[1] = g_MousePressed[2] = false;
#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE && !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) && !(defined(__APPLE__) && TARGET_OS_IOS)
// SDL 2.0.4 and later has SDL_GetGlobalMouseState() and SDL_CaptureMouse()
int mouse_x_global, mouse_y_global;
SDL_GetGlobalMouseState(&mouse_x_global, &mouse_y_global);
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
// Multi-viewport mode: mouse position in OS absolute coordinates (io.MousePos is (0,0) when the mouse is on the upper-left of the primary monitor)
if (SDL_Window* focused_window = SDL_GetKeyboardFocus())
if (ImGui::FindViewportByPlatformHandle((void*)focused_window) != NULL)
io.MousePos = ImVec2((float)mouse_x_global, (float)mouse_y_global);
}
else
{
// Single-viewport mode: mouse position in client window coordinatesio.MousePos is (0,0) when the mouse is on the upper-left corner of the app window)
if (SDL_GetWindowFlags(g_Window) & SDL_WINDOW_INPUT_FOCUS)
{
int window_x, window_y;
SDL_GetWindowPosition(g_Window, &window_x, &window_y);
io.MousePos = ImVec2((float)(mouse_x_global - window_x), (float)(mouse_y_global - window_y));
}
}
// SDL_CaptureMouse() let the OS know e.g. that our imgui drag outside the SDL window boundaries shouldn't e.g. trigger the OS window resize cursor.
// The function is only supported from SDL 2.0.4 (released Jan 2016)
bool any_mouse_button_down = ImGui::IsAnyMouseDown();
SDL_CaptureMouse(any_mouse_button_down ? SDL_TRUE : SDL_FALSE);
#else
// SDL 2.0.3 and before: single-viewport only
if (SDL_GetWindowFlags(g_Window) & SDL_WINDOW_INPUT_FOCUS)
io.MousePos = ImVec2((float)mouse_x_local, (float)mouse_y_local);
#endif
}
static void ImGui_ImplSDL2_UpdateMouseCursor()
{
ImGuiIO& io = ImGui::GetIO();
if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange)
return;
ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
if (io.MouseDrawCursor || imgui_cursor == ImGuiMouseCursor_None)
{
// Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
SDL_ShowCursor(SDL_FALSE);
}
else
{
// Show OS mouse cursor
SDL_SetCursor(g_MouseCursors[imgui_cursor] ? g_MouseCursors[imgui_cursor] : g_MouseCursors[ImGuiMouseCursor_Arrow]);
SDL_ShowCursor(SDL_TRUE);
}
}
static void ImGui_ImplSDL2_UpdateGamepads()
{
ImGuiIO& io = ImGui::GetIO();
memset(io.NavInputs, 0, sizeof(io.NavInputs));
if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0)
return;
// Get gamepad
SDL_GameController* game_controller = SDL_GameControllerOpen(0);
if (!game_controller)
{
io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
return;
}
// Update gamepad inputs
#define MAP_BUTTON(NAV_NO, BUTTON_NO) { io.NavInputs[NAV_NO] = (SDL_GameControllerGetButton(game_controller, BUTTON_NO) != 0) ? 1.0f : 0.0f; }
#define MAP_ANALOG(NAV_NO, AXIS_NO, V0, V1) { float vn = (float)(SDL_GameControllerGetAxis(game_controller, AXIS_NO) - V0) / (float)(V1 - V0); if (vn > 1.0f) vn = 1.0f; if (vn > 0.0f && io.NavInputs[NAV_NO] < vn) io.NavInputs[NAV_NO] = vn; }
const int thumb_dead_zone = 8000; // SDL_gamecontroller.h suggests using this value.
MAP_BUTTON(ImGuiNavInput_Activate, SDL_CONTROLLER_BUTTON_A); // Cross / A
MAP_BUTTON(ImGuiNavInput_Cancel, SDL_CONTROLLER_BUTTON_B); // Circle / B
MAP_BUTTON(ImGuiNavInput_Menu, SDL_CONTROLLER_BUTTON_X); // Square / X
MAP_BUTTON(ImGuiNavInput_Input, SDL_CONTROLLER_BUTTON_Y); // Triangle / Y
MAP_BUTTON(ImGuiNavInput_DpadLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT); // D-Pad Left
MAP_BUTTON(ImGuiNavInput_DpadRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT); // D-Pad Right
MAP_BUTTON(ImGuiNavInput_DpadUp, SDL_CONTROLLER_BUTTON_DPAD_UP); // D-Pad Up
MAP_BUTTON(ImGuiNavInput_DpadDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN); // D-Pad Down
MAP_BUTTON(ImGuiNavInput_FocusPrev, SDL_CONTROLLER_BUTTON_LEFTSHOULDER); // L1 / LB
MAP_BUTTON(ImGuiNavInput_FocusNext, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER); // R1 / RB
MAP_BUTTON(ImGuiNavInput_TweakSlow, SDL_CONTROLLER_BUTTON_LEFTSHOULDER); // L1 / LB
MAP_BUTTON(ImGuiNavInput_TweakFast, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER); // R1 / RB
MAP_ANALOG(ImGuiNavInput_LStickLeft, SDL_CONTROLLER_AXIS_LEFTX, -thumb_dead_zone, -32768);
MAP_ANALOG(ImGuiNavInput_LStickRight, SDL_CONTROLLER_AXIS_LEFTX, +thumb_dead_zone, +32767);
MAP_ANALOG(ImGuiNavInput_LStickUp, SDL_CONTROLLER_AXIS_LEFTY, -thumb_dead_zone, -32767);
MAP_ANALOG(ImGuiNavInput_LStickDown, SDL_CONTROLLER_AXIS_LEFTY, +thumb_dead_zone, +32767);
io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
#undef MAP_BUTTON
#undef MAP_ANALOG
}
void ImGui_ImplSDL2_NewFrame(SDL_Window* window)
{
ImGuiIO& io = ImGui::GetIO();
IM_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built! It is generally built by the renderer back-end. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame().");
// Setup display size (every frame to accommodate for window resizing)
int w, h;
int display_w, display_h;
SDL_GetWindowSize(window, &w, &h);
SDL_GL_GetDrawableSize(window, &display_w, &display_h);
io.DisplaySize = ImVec2((float)w, (float)h);
if (w > 0 && h > 0)
io.DisplayFramebufferScale = ImVec2((float)display_w / w, (float)display_h / h);
// Setup time step (we don't use SDL_GetTicks() because it is using millisecond resolution)
static Uint64 frequency = SDL_GetPerformanceFrequency();
Uint64 current_time = SDL_GetPerformanceCounter();
io.DeltaTime = g_Time > 0 ? (float)((double)(current_time - g_Time) / frequency) : (float)(1.0f / 60.0f);
g_Time = current_time;
ImGui_ImplSDL2_UpdateMousePosAndButtons();
ImGui_ImplSDL2_UpdateMouseCursor();
// Update game controllers (if enabled and available)
ImGui_ImplSDL2_UpdateGamepads();
}
//--------------------------------------------------------------------------------------------------------
// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
// This is an _advanced_ and _optional_ feature, allowing the back-end to create and handle multiple viewports simultaneously.
// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
//--------------------------------------------------------------------------------------------------------
struct ImGuiViewportDataSDL2
{
SDL_Window* Window;
Uint32 WindowID;
bool WindowOwned;
SDL_GLContext GLContext;
ImGuiViewportDataSDL2() { Window = NULL; WindowID = 0; WindowOwned = false; GLContext = NULL; }
~ImGuiViewportDataSDL2() { IM_ASSERT(Window == NULL && GLContext == NULL); }
};
static void ImGui_ImplSDL2_CreateWindow(ImGuiViewport* viewport)
{
ImGuiViewportDataSDL2* data = IM_NEW(ImGuiViewportDataSDL2)();
viewport->PlatformUserData = data;
ImGuiViewport* main_viewport = ImGui::GetMainViewport();
ImGuiViewportDataSDL2* main_viewport_data = (ImGuiViewportDataSDL2*)main_viewport->PlatformUserData;
// Share GL resources with main context
bool use_opengl = (main_viewport_data->GLContext != NULL);
SDL_GLContext backup_context = NULL;
if (use_opengl)
{
backup_context = SDL_GL_GetCurrentContext();
SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1);
SDL_GL_MakeCurrent(main_viewport_data->Window, main_viewport_data->GLContext);
}
Uint32 sdl_flags = 0;
sdl_flags |= use_opengl ? SDL_WINDOW_OPENGL : SDL_WINDOW_VULKAN;
sdl_flags |= SDL_GetWindowFlags(g_Window) & SDL_WINDOW_ALLOW_HIGHDPI;
sdl_flags |= SDL_WINDOW_HIDDEN;
sdl_flags |= (viewport->Flags & ImGuiViewportFlags_NoDecoration) ? SDL_WINDOW_BORDERLESS : 0;
sdl_flags |= (viewport->Flags & ImGuiViewportFlags_NoDecoration) ? 0 : SDL_WINDOW_RESIZABLE;
#if SDL_HAS_ALWAYS_ON_TOP
sdl_flags |= (viewport->Flags & ImGuiViewportFlags_TopMost) ? SDL_WINDOW_ALWAYS_ON_TOP : 0;
#endif
data->Window = SDL_CreateWindow("No Title Yet", (int)viewport->Pos.x, (int)viewport->Pos.y, (int)viewport->Size.x, (int)viewport->Size.y, sdl_flags);
data->WindowOwned = true;
if (use_opengl)
{
data->GLContext = SDL_GL_CreateContext(data->Window);
SDL_GL_SetSwapInterval(0);
}
if (use_opengl && backup_context)
SDL_GL_MakeCurrent(data->Window, backup_context);
viewport->PlatformHandle = (void*)data->Window;
#if defined(_WIN32)
SDL_SysWMinfo info;
SDL_VERSION(&info.version);
if (SDL_GetWindowWMInfo(data->Window, &info))
viewport->PlatformHandleRaw = info.info.win.window;
#endif
}
static void ImGui_ImplSDL2_DestroyWindow(ImGuiViewport* viewport)
{
if (ImGuiViewportDataSDL2* data = (ImGuiViewportDataSDL2*)viewport->PlatformUserData)
{
if (data->GLContext && data->WindowOwned)
SDL_GL_DeleteContext(data->GLContext);
if (data->Window && data->WindowOwned)
SDL_DestroyWindow(data->Window);
data->GLContext = NULL;
data->Window = NULL;
IM_DELETE(data);
}
viewport->PlatformUserData = viewport->PlatformHandle = NULL;
}
static void ImGui_ImplSDL2_ShowWindow(ImGuiViewport* viewport)
{
ImGuiViewportDataSDL2* data = (ImGuiViewportDataSDL2*)viewport->PlatformUserData;
#if defined(_WIN32)
HWND hwnd = (HWND)viewport->PlatformHandleRaw;
// SDL hack: Hide icon from task bar
// Note: SDL 2.0.6+ has a SDL_WINDOW_SKIP_TASKBAR flag which is supported under Windows but the way it create the window breaks our seamless transition.
if (viewport->Flags & ImGuiViewportFlags_NoTaskBarIcon)
{
LONG ex_style = ::GetWindowLong(hwnd, GWL_EXSTYLE);
ex_style &= ~WS_EX_APPWINDOW;
ex_style |= WS_EX_TOOLWINDOW;
::SetWindowLong(hwnd, GWL_EXSTYLE, ex_style);
}
// SDL hack: SDL always activate/focus windows :/
if (viewport->Flags & ImGuiViewportFlags_NoFocusOnAppearing)
{
::ShowWindow(hwnd, SW_SHOWNA);
return;
}
#endif
SDL_ShowWindow(data->Window);
}
static ImVec2 ImGui_ImplSDL2_GetWindowPos(ImGuiViewport* viewport)
{
ImGuiViewportDataSDL2* data = (ImGuiViewportDataSDL2*)viewport->PlatformUserData;
int x = 0, y = 0;
SDL_GetWindowPosition(data->Window, &x, &y);
return ImVec2((float)x, (float)y);
}
static void ImGui_ImplSDL2_SetWindowPos(ImGuiViewport* viewport, ImVec2 pos)
{
ImGuiViewportDataSDL2* data = (ImGuiViewportDataSDL2*)viewport->PlatformUserData;
SDL_SetWindowPosition(data->Window, (int)pos.x, (int)pos.y);
}
static ImVec2 ImGui_ImplSDL2_GetWindowSize(ImGuiViewport* viewport)
{
ImGuiViewportDataSDL2* data = (ImGuiViewportDataSDL2*)viewport->PlatformUserData;
int w = 0, h = 0;
SDL_GetWindowSize(data->Window, &w, &h);
return ImVec2((float)w, (float)h);
}
static void ImGui_ImplSDL2_SetWindowSize(ImGuiViewport* viewport, ImVec2 size)
{
ImGuiViewportDataSDL2* data = (ImGuiViewportDataSDL2*)viewport->PlatformUserData;
SDL_SetWindowSize(data->Window, (int)size.x, (int)size.y);
}
static void ImGui_ImplSDL2_SetWindowTitle(ImGuiViewport* viewport, const char* title)
{
ImGuiViewportDataSDL2* data = (ImGuiViewportDataSDL2*)viewport->PlatformUserData;
SDL_SetWindowTitle(data->Window, title);
}
#if SDL_HAS_WINDOW_ALPHA
static void ImGui_ImplSDL2_SetWindowAlpha(ImGuiViewport* viewport, float alpha)
{
ImGuiViewportDataSDL2* data = (ImGuiViewportDataSDL2*)viewport->PlatformUserData;
SDL_SetWindowOpacity(data->Window, alpha);
}
#endif
static void ImGui_ImplSDL2_SetWindowFocus(ImGuiViewport* viewport)
{
ImGuiViewportDataSDL2* data = (ImGuiViewportDataSDL2*)viewport->PlatformUserData;
SDL_RaiseWindow(data->Window);
}
static bool ImGui_ImplSDL2_GetWindowFocus(ImGuiViewport* viewport)
{
ImGuiViewportDataSDL2* data = (ImGuiViewportDataSDL2*)viewport->PlatformUserData;
return (SDL_GetWindowFlags(data->Window) & SDL_WINDOW_INPUT_FOCUS) != 0;
}
static bool ImGui_ImplSDL2_GetWindowMinimized(ImGuiViewport* viewport)
{
ImGuiViewportDataSDL2* data = (ImGuiViewportDataSDL2*)viewport->PlatformUserData;
return (SDL_GetWindowFlags(data->Window) & SDL_WINDOW_MINIMIZED) != 0;
}
static void ImGui_ImplSDL2_RenderWindow(ImGuiViewport* viewport, void*)
{
ImGuiViewportDataSDL2* data = (ImGuiViewportDataSDL2*)viewport->PlatformUserData;
if (data->GLContext)
SDL_GL_MakeCurrent(data->Window, data->GLContext);
}
static void ImGui_ImplSDL2_SwapBuffers(ImGuiViewport* viewport, void*)
{
ImGuiViewportDataSDL2* data = (ImGuiViewportDataSDL2*)viewport->PlatformUserData;
if (data->GLContext)
{
SDL_GL_MakeCurrent(data->Window, data->GLContext);
SDL_GL_SwapWindow(data->Window);
}
}
// Vulkan support (the Vulkan renderer needs to call a platform-side support function to create the surface)
// SDL is graceful enough to _not_ need <vulkan/vulkan.h> so we can safely include this.
#if SDL_HAS_VULKAN
#include <SDL_vulkan.h>
static int ImGui_ImplSDL2_CreateVkSurface(ImGuiViewport* viewport, ImU64 vk_instance, const void* vk_allocator, ImU64* out_vk_surface)
{
ImGuiViewportDataSDL2* data = (ImGuiViewportDataSDL2*)viewport->PlatformUserData;
(void)vk_allocator;
SDL_bool ret = SDL_Vulkan_CreateSurface(data->Window, (VkInstance)vk_instance, (VkSurfaceKHR*)out_vk_surface);
return ret ? 0 : 1; // ret ? VK_SUCCESS : VK_NOT_READY
}
#endif // SDL_HAS_VULKAN
// FIXME-PLATFORM: SDL doesn't have an event to notify the application of display/monitor changes
static void ImGui_ImplSDL2_UpdateMonitors()
{
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
platform_io.Monitors.resize(0);
int display_count = SDL_GetNumVideoDisplays();
for (int n = 0; n < display_count; n++)
{
// Warning: the validity of monitor DPI information on Windows depends on the application DPI awareness settings, which generally needs to be set in the manifest or at runtime.
ImGuiPlatformMonitor monitor;
SDL_Rect r;
SDL_GetDisplayBounds(n, &r);
monitor.MainPos = monitor.WorkPos = ImVec2((float)r.x, (float)r.y);
monitor.MainSize = monitor.WorkSize = ImVec2((float)r.w, (float)r.h);
#if SDL_HAS_USABLE_DISPLAY_BOUNDS
SDL_GetDisplayUsableBounds(n, &r);
monitor.WorkPos = ImVec2((float)r.x, (float)r.y);
monitor.WorkSize = ImVec2((float)r.w, (float)r.h);
#endif
#if SDL_HAS_PER_MONITOR_DPI
float dpi = 0.0f;
if (!SDL_GetDisplayDPI(n, &dpi, NULL, NULL))
monitor.DpiScale = dpi / 96.0f;
#endif
platform_io.Monitors.push_back(monitor);
}
}
static void ImGui_ImplSDL2_InitPlatformInterface(SDL_Window* window, void* sdl_gl_context)
{
// Register platform interface (will be coupled with a renderer interface)
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
platform_io.Platform_CreateWindow = ImGui_ImplSDL2_CreateWindow;
platform_io.Platform_DestroyWindow = ImGui_ImplSDL2_DestroyWindow;
platform_io.Platform_ShowWindow = ImGui_ImplSDL2_ShowWindow;
platform_io.Platform_SetWindowPos = ImGui_ImplSDL2_SetWindowPos;
platform_io.Platform_GetWindowPos = ImGui_ImplSDL2_GetWindowPos;
platform_io.Platform_SetWindowSize = ImGui_ImplSDL2_SetWindowSize;
platform_io.Platform_GetWindowSize = ImGui_ImplSDL2_GetWindowSize;
platform_io.Platform_SetWindowFocus = ImGui_ImplSDL2_SetWindowFocus;
platform_io.Platform_GetWindowFocus = ImGui_ImplSDL2_GetWindowFocus;
platform_io.Platform_GetWindowMinimized = ImGui_ImplSDL2_GetWindowMinimized;
platform_io.Platform_SetWindowTitle = ImGui_ImplSDL2_SetWindowTitle;
platform_io.Platform_RenderWindow = ImGui_ImplSDL2_RenderWindow;
platform_io.Platform_SwapBuffers = ImGui_ImplSDL2_SwapBuffers;
#if SDL_HAS_WINDOW_ALPHA
platform_io.Platform_SetWindowAlpha = ImGui_ImplSDL2_SetWindowAlpha;
#endif
#if SDL_HAS_VULKAN
platform_io.Platform_CreateVkSurface = ImGui_ImplSDL2_CreateVkSurface;
#endif
// SDL2 by default doesn't pass mouse clicks to the application when the click focused a window. This is getting in the way of our interactions and we disable that behavior.
#if SDL_HAS_MOUSE_FOCUS_CLICKTHROUGH
SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1");
#endif
ImGui_ImplSDL2_UpdateMonitors();
// Register main window handle (which is owned by the main application, not by us)
ImGuiViewport* main_viewport = ImGui::GetMainViewport();
ImGuiViewportDataSDL2* data = IM_NEW(ImGuiViewportDataSDL2)();
data->Window = window;
data->WindowID = SDL_GetWindowID(window);
data->WindowOwned = false;
data->GLContext = sdl_gl_context;
main_viewport->PlatformUserData = data;
main_viewport->PlatformHandle = data->Window;
}
static void ImGui_ImplSDL2_ShutdownPlatformInterface()
{
}

View File

@ -0,0 +1,30 @@
// dear imgui: Platform Binding for SDL2
// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
// (Info: SDL2 is a cross-platform general purpose library for handling windows, inputs, graphics context creation, etc.)
// Implemented features:
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
// [X] Platform: Clipboard support.
// [X] Platform: Keyboard arrays indexed using SDL_SCANCODE_* codes, e.g. ImGui::IsKeyPressed(SDL_SCANCODE_SPACE).
// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
// [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
// Missing features:
// [ ] Platform: SDL2 handling of IME under Windows appears to be broken and it explicitly disable the regular Windows IME. You can restore Windows IME by compiling SDL with SDL_DISABLE_WINDOWS_IME.
// [ ] Platform: Multi-viewport + Minimized windows seems to break mouse wheel events (at least under Windows).
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
// https://github.com/ocornut/imgui
#pragma once
#include "imgui.h"
struct SDL_Window;
typedef union SDL_Event SDL_Event;
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForOpenGL(SDL_Window* window, void* sdl_gl_context);
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForVulkan(SDL_Window* window);
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForD3D(SDL_Window* window);
IMGUI_IMPL_API void ImGui_ImplSDL2_Shutdown();
IMGUI_IMPL_API void ImGui_ImplSDL2_NewFrame(SDL_Window* window);
IMGUI_IMPL_API bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event);

View File

@ -0,0 +1,66 @@
#include "imgui_styles.h"
void ImGui::StyleColorsDarker(ImGuiStyle* dst)
{
ImGuiStyle* style = dst ? dst : &ImGui::GetStyle();
ImVec4* colors = style->Colors;
colors[ImGuiCol_Text] = ImVec4(0.95f, 0.96f, 0.98f, 1.00f);
colors[ImGuiCol_TextDisabled] = ImVec4(0.36f, 0.42f, 0.47f, 1.00f);
colors[ImGuiCol_WindowBg] = ImVec4(0.11f, 0.15f, 0.17f, 1.00f);
colors[ImGuiCol_ChildBg] = ImVec4(0.15f, 0.18f, 0.22f, 1.00f);
colors[ImGuiCol_PopupBg] = ImVec4(0.08f, 0.08f, 0.08f, 0.94f);
colors[ImGuiCol_Border] = ImVec4(0.08f, 0.10f, 0.12f, 1.00f);
colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
colors[ImGuiCol_FrameBg] = ImVec4(0.20f, 0.25f, 0.29f, 1.00f);
colors[ImGuiCol_FrameBgHovered] = ImVec4(0.12f, 0.20f, 0.28f, 1.00f);
colors[ImGuiCol_FrameBgActive] = ImVec4(0.09f, 0.12f, 0.14f, 1.00f);
colors[ImGuiCol_TitleBg] = ImVec4(0.09f, 0.12f, 0.14f, 0.65f);
colors[ImGuiCol_TitleBgActive] = ImVec4(0.08f, 0.10f, 0.12f, 1.00f);
colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.00f, 0.00f, 0.00f, 0.51f);
colors[ImGuiCol_MenuBarBg] = ImVec4(0.15f, 0.18f, 0.22f, 1.00f);
colors[ImGuiCol_ScrollbarBg] = ImVec4(0.02f, 0.02f, 0.02f, 0.39f);
colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.20f, 0.25f, 0.29f, 1.00f);
colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.18f, 0.22f, 0.25f, 1.00f);
colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.09f, 0.21f, 0.31f, 1.00f);
colors[ImGuiCol_CheckMark] = ImVec4(0.28f, 0.56f, 1.00f, 1.00f);
colors[ImGuiCol_SliderGrab] = ImVec4(0.28f, 0.56f, 1.00f, 1.00f);
colors[ImGuiCol_SliderGrabActive] = ImVec4(0.37f, 0.61f, 1.00f, 1.00f);
colors[ImGuiCol_Button] = ImVec4(0.20f, 0.25f, 0.29f, 1.00f);
colors[ImGuiCol_ButtonHovered] = ImVec4(0.33f, 0.38f, 0.46f, 1.00f);
colors[ImGuiCol_ButtonActive] = ImVec4(0.27f, 0.32f, 0.38f, 1.00f);
colors[ImGuiCol_Header] = ImVec4(0.20f, 0.25f, 0.29f, 0.55f);
colors[ImGuiCol_HeaderHovered] = ImVec4(0.33f, 0.38f, 0.46f, 1.00f);
colors[ImGuiCol_HeaderActive] = ImVec4(0.27f, 0.32f, 0.38f, 1.00f);
colors[ImGuiCol_Separator] = ImVec4(0.20f, 0.25f, 0.29f, 1.00f);
colors[ImGuiCol_SeparatorHovered] = ImVec4(0.33f, 0.38f, 0.46f, 1.00f);
colors[ImGuiCol_SeparatorActive] = ImVec4(0.27f, 0.32f, 0.38f, 1.00f);
colors[ImGuiCol_ResizeGrip] = ImVec4(0.26f, 0.59f, 0.98f, 0.25f);
colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.33f, 0.38f, 0.46f, 1.00f);
colors[ImGuiCol_ResizeGripActive] = ImVec4(0.27f, 0.32f, 0.38f, 1.00f);
colors[ImGuiCol_Tab] = ImVec4(0.11f, 0.15f, 0.17f, 1.00f);
colors[ImGuiCol_TabHovered] = ImVec4(0.33f, 0.38f, 0.46f, 1.00f);
colors[ImGuiCol_TabActive] = ImVec4(0.27f, 0.32f, 0.38f, 1.00f);
colors[ImGuiCol_TabUnfocused] = ImVec4(0.11f, 0.15f, 0.17f, 1.00f);
colors[ImGuiCol_TabUnfocusedActive] = ImVec4(0.11f, 0.15f, 0.17f, 1.00f);
colors[ImGuiCol_DockingPreview] = ImVec4(0.26f, 0.59f, 0.98f, 0.70f);
colors[ImGuiCol_DockingEmptyBg] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f);
colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f);
colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);
colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f);
colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f);
colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f);
colors[ImGuiCol_NavHighlight] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f);
colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f);
colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f);
}
#include "font_roboto_regular.inl"
void ImGui::AddRobotoRegularFont(float size /*= 15.0f*/)
{
ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(s_font_roboto_regular_compressed_data,
s_font_roboto_regular_compressed_size, size);
}

View File

@ -0,0 +1,7 @@
#pragma once
#include <imgui.h>
namespace ImGui {
void StyleColorsDarker(ImGuiStyle* dst = nullptr);
void AddRobotoRegularFont(float size = 15.0f);
}

View File

@ -0,0 +1,78 @@
#include "common/assert.h"
#include "common/log.h"
#include "core/system.h"
#include "sdl_host_interface.h"
#include <SDL.h>
#include <cstdio>
static int Run(int argc, char* argv[])
{
// init sdl
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_GAMECONTROLLER | SDL_INIT_HAPTIC) < 0)
{
Panic("SDL initialization failed");
return -1;
}
// parameters
const char* filename = nullptr;
const char* exp1_filename = nullptr;
std::string state_filename;
for (int i = 1; i < argc; i++)
{
#define CHECK_ARG(str) !std::strcmp(argv[i], str)
#define CHECK_ARG_PARAM(str) (!std::strcmp(argv[i], str) && ((i + 1) < argc))
if (CHECK_ARG_PARAM("-state"))
state_filename = SDLHostInterface::GetSaveStateFilename(std::strtoul(argv[++i], nullptr, 10));
else if (CHECK_ARG_PARAM("-exp1"))
exp1_filename = argv[++i];
else
filename = argv[i];
#undef CHECK_ARG
#undef CHECK_ARG_PARAM
}
// create display and host interface
std::unique_ptr<SDLHostInterface> host_interface =
SDLHostInterface::Create(filename, exp1_filename, state_filename.empty() ? nullptr : state_filename.c_str());
if (!host_interface)
{
Panic("Failed to create host interface");
SDL_Quit();
return -1;
}
// run
host_interface->Run();
// done
host_interface.reset();
SDL_Quit();
return 0;
}
// SDL requires the entry point declared without c++ decoration
#undef main
int main(int argc, char* argv[])
{
// set log flags
#ifndef _DEBUG
const LOGLEVEL level = LOGLEVEL_INFO;
// const LOGLEVEL level = LOGLEVEL_DEV;
// const LOGLEVEL level = LOGLEVEL_PROFILE;
Log::SetConsoleOutputParams(true, nullptr, level);
Log::SetFilterLevel(level);
#else
Log::SetConsoleOutputParams(true, nullptr, LOGLEVEL_DEBUG);
// Log::SetConsoleOutputParams(true, "GPU GPU_HW_OpenGL SPU Pad DigitalController", LOGLEVEL_DEBUG);
// Log::SetConsoleOutputParams(true, "GPU GPU_HW_OpenGL Pad DigitalController MemoryCard InterruptController SPU
// MDEC", LOGLEVEL_DEBUG); g_pLog->SetFilterLevel(LOGLEVEL_TRACE);
Log::SetFilterLevel(LOGLEVEL_DEBUG);
// Log::SetFilterLevel(LOGLEVEL_DEV);
#endif
// return NoGUITest();
return Run(argc, argv);
}

View File

@ -0,0 +1,378 @@
#include "opengl_host_display.h"
#include "common/assert.h"
#include "common/log.h"
#include <array>
#include <imgui.h>
#include <imgui_impl_opengl3.h>
#include "imgui_impl_sdl.h"
#include <tuple>
Log_SetChannel(OpenGLHostDisplay);
class OpenGLHostDisplayTexture : public HostDisplayTexture
{
public:
OpenGLHostDisplayTexture(GLuint id, u32 width, u32 height) : m_id(id), m_width(width), m_height(height) {}
~OpenGLHostDisplayTexture() override { glDeleteTextures(1, &m_id); }
void* GetHandle() const override { return reinterpret_cast<void*>(static_cast<uintptr_t>(m_id)); }
u32 GetWidth() const override { return m_width; }
u32 GetHeight() const override { return m_height; }
GLuint GetGLID() const { return m_id; }
static std::unique_ptr<OpenGLHostDisplayTexture> Create(u32 width, u32 height, const void* initial_data,
u32 initial_data_stride)
{
GLuint id;
glGenTextures(1, &id);
GLint old_texture_binding = 0;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_texture_binding);
// TODO: Set pack width
Assert(!initial_data || initial_data_stride == (width * sizeof(u32)));
glBindTexture(GL_TEXTURE_2D, id);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, initial_data);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, id);
return std::make_unique<OpenGLHostDisplayTexture>(id, width, height);
}
private:
GLuint m_id;
u32 m_width;
u32 m_height;
};
OpenGLHostDisplay::OpenGLHostDisplay(SDL_Window* window) : m_window(window)
{
SDL_GetWindowSize(window, &m_window_width, &m_window_height);
}
OpenGLHostDisplay::~OpenGLHostDisplay()
{
if (m_gl_context)
{
if (m_display_vao != 0)
glDeleteVertexArrays(1, &m_display_vao);
if (m_display_linear_sampler != 0)
glDeleteSamplers(1, &m_display_linear_sampler);
if (m_display_nearest_sampler != 0)
glDeleteSamplers(1, &m_display_nearest_sampler);
m_display_program.Destroy();
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplSDL2_Shutdown();
SDL_GL_MakeCurrent(nullptr, nullptr);
SDL_GL_DeleteContext(m_gl_context);
}
if (m_window)
SDL_DestroyWindow(m_window);
}
HostDisplay::RenderAPI OpenGLHostDisplay::GetRenderAPI() const
{
return m_is_gles ? HostDisplay::RenderAPI::OpenGLES : HostDisplay::RenderAPI::OpenGL;
}
void* OpenGLHostDisplay::GetRenderDevice() const
{
return nullptr;
}
void* OpenGLHostDisplay::GetRenderContext() const
{
return m_gl_context;
}
void* OpenGLHostDisplay::GetRenderWindow() const
{
return m_window;
}
void OpenGLHostDisplay::ChangeRenderWindow(void* new_window)
{
Panic("Not implemented");
}
std::unique_ptr<HostDisplayTexture> OpenGLHostDisplay::CreateTexture(u32 width, u32 height, const void* data,
u32 data_stride, bool dynamic)
{
return OpenGLHostDisplayTexture::Create(width, height, data, data_stride);
}
void OpenGLHostDisplay::UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height,
const void* data, u32 data_stride)
{
OpenGLHostDisplayTexture* tex = static_cast<OpenGLHostDisplayTexture*>(texture);
Assert(data_stride == (width * sizeof(u32)));
GLint old_texture_binding = 0;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_texture_binding);
glBindTexture(GL_TEXTURE_2D, tex->GetGLID());
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data);
glBindTexture(GL_TEXTURE_2D, old_texture_binding);
}
void OpenGLHostDisplay::SetVSync(bool enabled)
{
// Window framebuffer has to be bound to call SetSwapInterval.
GLint current_fbo = 0;
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &current_fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
SDL_GL_SetSwapInterval(enabled ? 1 : 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, current_fbo);
}
std::tuple<u32, u32> OpenGLHostDisplay::GetWindowSize() const
{
return std::make_tuple(static_cast<u32>(m_window_width), static_cast<u32>(m_window_height));
}
void OpenGLHostDisplay::WindowResized()
{
SDL_GetWindowSize(m_window, &m_window_width, &m_window_height);
}
const char* OpenGLHostDisplay::GetGLSLVersionString() const
{
return m_is_gles ? "#version 300 es" : "#version 130\n";
}
std::string OpenGLHostDisplay::GetGLSLVersionHeader() const
{
std::string header = GetGLSLVersionString();
header += "\n\n";
if (m_is_gles)
{
header += "precision highp float;\n";
header += "precision highp int;\n\n";
}
return header;
}
static void APIENTRY GLDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length,
const GLchar* message, const void* userParam)
{
switch (severity)
{
case GL_DEBUG_SEVERITY_HIGH_KHR:
Log_ErrorPrintf(message);
break;
case GL_DEBUG_SEVERITY_MEDIUM_KHR:
Log_WarningPrint(message);
break;
case GL_DEBUG_SEVERITY_LOW_KHR:
Log_InfoPrintf(message);
break;
case GL_DEBUG_SEVERITY_NOTIFICATION:
// Log_DebugPrint(message);
break;
}
}
bool OpenGLHostDisplay::CreateGLContext(bool debug_device)
{
// Prefer a desktop OpenGL context where possible. If we can't get this, try OpenGL ES.
static constexpr std::array<std::tuple<int, int>, 11> desktop_versions_to_try = {
{{4, 6}, {4, 5}, {4, 4}, {4, 3}, {4, 2}, {4, 1}, {4, 0}, {3, 3}, {3, 2}, {3, 1}, {3, 0}}};
static constexpr std::array<std::tuple<int, int>, 4> es_versions_to_try = {{{3, 2}, {3, 1}, {3, 0}}};
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
if (debug_device)
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);
for (const auto [major, minor] : desktop_versions_to_try)
{
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, major);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, minor);
Log_InfoPrintf("Trying a Desktop OpenGL %d.%d context", major, minor);
m_gl_context = SDL_GL_CreateContext(m_window);
if (m_gl_context)
{
Log_InfoPrintf("Got a desktop OpenGL %d.%d context", major, minor);
break;
}
}
if (!m_gl_context)
{
// try es
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0);
for (const auto [major, minor] : es_versions_to_try)
{
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, major);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, minor);
Log_InfoPrintf("Trying a OpenGL ES %d.%d context", major, minor);
m_gl_context = SDL_GL_CreateContext(m_window);
if (m_gl_context)
{
Log_InfoPrintf("Got a OpenGL ES %d.%d context", major, minor);
m_is_gles = true;
break;
}
}
}
if (!m_gl_context || SDL_GL_MakeCurrent(m_window, m_gl_context) != 0)
{
Log_ErrorPrintf("Failed to create any GL context");
return false;
}
// Load GLAD.
const auto load_result =
m_is_gles ? gladLoadGLES2Loader(SDL_GL_GetProcAddress) : gladLoadGLLoader(SDL_GL_GetProcAddress);
if (!load_result)
{
Log_ErrorPrintf("Failed to load GL functions");
return false;
}
if (debug_device && GLAD_GL_KHR_debug)
{
glad_glDebugMessageCallbackKHR(GLDebugCallback, nullptr);
glEnable(GL_DEBUG_OUTPUT);
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
}
return true;
}
bool OpenGLHostDisplay::CreateImGuiContext()
{
if (!ImGui_ImplSDL2_InitForOpenGL(m_window, m_gl_context) || !ImGui_ImplOpenGL3_Init(GetGLSLVersionString()))
return false;
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplSDL2_NewFrame(m_window);
return true;
}
bool OpenGLHostDisplay::CreateGLResources()
{
static constexpr char fullscreen_quad_vertex_shader[] = R"(
uniform vec4 u_src_rect;
out vec2 v_tex0;
void main()
{
vec2 pos = vec2(float((gl_VertexID << 1) & 2), float(gl_VertexID & 2));
v_tex0 = u_src_rect.xy + pos * u_src_rect.zw;
gl_Position = vec4(pos * vec2(2.0f, -2.0f) + vec2(-1.0f, 1.0f), 0.0f, 1.0f);
}
)";
static constexpr char display_fragment_shader[] = R"(
uniform sampler2D samp0;
in vec2 v_tex0;
out vec4 o_col0;
void main()
{
o_col0 = texture(samp0, v_tex0);
}
)";
if (!m_display_program.Compile(GetGLSLVersionHeader() + fullscreen_quad_vertex_shader,
GetGLSLVersionHeader() + display_fragment_shader))
{
Log_ErrorPrintf("Failed to compile display shaders");
return false;
}
if (!m_is_gles)
m_display_program.BindFragData(0, "o_col0");
if (!m_display_program.Link())
{
Log_ErrorPrintf("Failed to link display program");
return false;
}
m_display_program.Bind();
m_display_program.RegisterUniform("u_src_rect");
m_display_program.RegisterUniform("samp0");
m_display_program.Uniform1i(1, 0);
glGenVertexArrays(1, &m_display_vao);
// samplers
glGenSamplers(1, &m_display_nearest_sampler);
glSamplerParameteri(m_display_nearest_sampler, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glSamplerParameteri(m_display_nearest_sampler, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glGenSamplers(1, &m_display_linear_sampler);
glSamplerParameteri(m_display_linear_sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glSamplerParameteri(m_display_linear_sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
return true;
}
std::unique_ptr<HostDisplay> OpenGLHostDisplay::Create(SDL_Window* window, bool debug_device)
{
std::unique_ptr<OpenGLHostDisplay> display = std::make_unique<OpenGLHostDisplay>(window);
if (!display->CreateGLContext(debug_device) || !display->CreateImGuiContext() || !display->CreateGLResources())
return nullptr;
return display;
}
void OpenGLHostDisplay::Render()
{
glDisable(GL_SCISSOR_TEST);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
RenderDisplay();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
SDL_GL_SwapWindow(m_window);
ImGui_ImplSDL2_NewFrame(m_window);
ImGui_ImplOpenGL3_NewFrame();
GL::Program::ResetLastProgram();
}
void OpenGLHostDisplay::RenderDisplay()
{
if (!m_display_texture_handle)
return;
// - 20 for main menu padding
const auto [vp_left, vp_top, vp_width, vp_height] =
CalculateDrawRect(m_window_width, std::max(m_window_height - m_display_top_margin, 1), m_display_aspect_ratio);
glViewport(vp_left, m_window_height - (m_display_top_margin + vp_top) - vp_height, vp_width, vp_height);
glDisable(GL_BLEND);
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glDisable(GL_SCISSOR_TEST);
glDepthMask(GL_FALSE);
m_display_program.Bind();
m_display_program.Uniform4f(0, static_cast<float>(m_display_offset_x) / static_cast<float>(m_display_texture_width),
static_cast<float>(m_display_offset_y) / static_cast<float>(m_display_texture_height),
static_cast<float>(m_display_width) / static_cast<float>(m_display_texture_width),
static_cast<float>(m_display_height) / static_cast<float>(m_display_texture_height));
glBindTexture(GL_TEXTURE_2D, static_cast<GLuint>(reinterpret_cast<uintptr_t>(m_display_texture_handle)));
glBindSampler(0, m_display_linear_filtering ? m_display_linear_sampler : m_display_nearest_sampler);
glBindVertexArray(m_display_vao);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindSampler(0, 0);
}

View File

@ -0,0 +1,56 @@
#pragma once
#include "common/gl/program.h"
#include "common/gl/texture.h"
#include "core/host_display.h"
#include <SDL.h>
#include <string>
#include <memory>
class OpenGLHostDisplay final : public HostDisplay
{
public:
OpenGLHostDisplay(SDL_Window* window);
~OpenGLHostDisplay();
static std::unique_ptr<HostDisplay> Create(SDL_Window* window, bool debug_device);
RenderAPI GetRenderAPI() const override;
void* GetRenderDevice() const override;
void* GetRenderContext() const override;
void* GetRenderWindow() const override;
void ChangeRenderWindow(void* new_window) override;
std::unique_ptr<HostDisplayTexture> CreateTexture(u32 width, u32 height, const void* data, u32 data_stride,
bool dynamic) override;
void UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* data,
u32 data_stride) override;
void SetVSync(bool enabled) override;
std::tuple<u32, u32> GetWindowSize() const override;
void WindowResized() override;
private:
const char* GetGLSLVersionString() const;
std::string GetGLSLVersionHeader() const;
bool CreateGLContext(bool debug_device);
bool CreateImGuiContext();
bool CreateGLResources();
void Render();
void RenderDisplay();
SDL_Window* m_window = nullptr;
SDL_GLContext m_gl_context = nullptr;
int m_window_width = 0;
int m_window_height = 0;
GL::Program m_display_program;
GLuint m_display_vao = 0;
GLuint m_display_nearest_sampler = 0;
GLuint m_display_linear_sampler = 0;
bool m_is_gles = false;
};

View File

@ -0,0 +1,63 @@
#include "sdl_audio_stream.h"
#include "common/assert.h"
#include "common/log.h"
#include <SDL.h>
Log_SetChannel(SDLAudioStream);
SDLAudioStream::SDLAudioStream() = default;
SDLAudioStream::~SDLAudioStream()
{
if (m_is_open)
SDLAudioStream::CloseDevice();
}
bool SDLAudioStream::OpenDevice()
{
DebugAssert(!m_is_open);
SDL_AudioSpec spec = {};
spec.freq = m_output_sample_rate;
spec.channels = static_cast<Uint8>(m_channels);
spec.format = AUDIO_S16;
spec.samples = static_cast<Uint16>(m_buffer_size);
spec.callback = AudioCallback;
spec.userdata = static_cast<void*>(this);
SDL_AudioSpec obtained = {};
if (SDL_OpenAudio(&spec, &obtained) < 0)
{
Log_ErrorPrintf("SDL_OpenAudio failed");
return false;
}
m_is_open = true;
return true;
}
void SDLAudioStream::PauseDevice(bool paused)
{
SDL_PauseAudio(paused ? 1 : 0);
}
void SDLAudioStream::CloseDevice()
{
DebugAssert(m_is_open);
SDL_CloseAudio();
m_is_open = false;
}
void SDLAudioStream::AudioCallback(void* userdata, uint8_t* stream, int len)
{
SDLAudioStream* const this_ptr = static_cast<SDLAudioStream*>(userdata);
const u32 num_samples = len / sizeof(SampleType) / this_ptr->m_channels;
const u32 read_samples = this_ptr->ReadSamples(reinterpret_cast<SampleType*>(stream), num_samples);
const u32 silence_samples = num_samples - read_samples;
if (silence_samples > 0)
{
std::memset(reinterpret_cast<SampleType*>(stream) + (read_samples * this_ptr->m_channels), 0,
silence_samples * this_ptr->m_channels * sizeof(SampleType));
}
}
void SDLAudioStream::BufferAvailable() {}

View File

@ -0,0 +1,20 @@
#pragma once
#include "common/audio_stream.h"
#include <cstdint>
class SDLAudioStream final : public AudioStream
{
public:
SDLAudioStream();
~SDLAudioStream();
protected:
bool OpenDevice() override;
void PauseDevice(bool paused) override;
void CloseDevice() override;
void BufferAvailable() override;
static void AudioCallback(void* userdata, uint8_t* stream, int len);
bool m_is_open = false;
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,142 @@
#pragma once
#include "common/gl/program.h"
#include "common/gl/texture.h"
#include "core/host_display.h"
#include "core/host_interface.h"
#include <SDL.h>
#include <array>
#include <deque>
#include <map>
#include <memory>
#include <mutex>
#include <string>
class System;
class AudioStream;
class Controller;
class SDLHostInterface final : public HostInterface
{
public:
SDLHostInterface();
~SDLHostInterface();
static std::unique_ptr<SDLHostInterface> Create(const char* filename = nullptr, const char* exp1_filename = nullptr,
const char* save_state_filename = nullptr);
static std::string GetSaveStateFilename(u32 index);
void ReportError(const char* message) override;
void ReportMessage(const char* message) override;
void Run();
private:
enum class KeyboardControllerAction
{
Up,
Down,
Left,
Right,
Triangle,
Cross,
Square,
Circle,
L1,
R1,
L2,
R2,
Start,
Select,
Count
};
using KeyboardControllerActionMap = std::array<s32, static_cast<int>(KeyboardControllerAction::Count)>;
struct ControllerData
{
SDL_GameController* controller;
SDL_Haptic* haptic;
u32 controller_index;
float last_rumble_strength;
};
static constexpr u32 NUM_QUICK_SAVE_STATES = 10;
static constexpr char RESUME_SAVESTATE_FILENAME[] = "savestate_resume.bin";
bool HasSystem() const { return static_cast<bool>(m_system); }
#ifdef WIN32
bool UseOpenGLRenderer() const { return m_settings.gpu_renderer == GPURenderer::HardwareOpenGL; }
#else
bool UseOpenGLRenderer() const { return true; }
#endif
bool CreateSDLWindow();
void DestroySDLWindow();
bool CreateDisplay();
void DestroyDisplay();
void CreateImGuiContext();
void CreateAudioStream();
void SaveSettings();
void QueueSwitchGPURenderer();
void SwitchGPURenderer();
void SwitchAudioBackend();
void UpdateFullscreen();
void UpdateControllerMapping();
// We only pass mouse input through if it's grabbed
void DrawImGui();
void DoPowerOff();
void DoResume();
void DoStartDisc();
void DoStartBIOS();
void DoChangeDisc();
void DoLoadState(u32 index);
void DoSaveState(u32 index);
void DoTogglePause();
void DoFrameStep();
void DoToggleFullscreen();
void HandleSDLEvent(const SDL_Event* event);
void HandleSDLKeyEvent(const SDL_Event* event);
void UpdateKeyboardControllerMapping();
bool HandleSDLKeyEventForController(const SDL_Event* event);
bool OpenGameController(int index);
bool CloseGameController(int index);
void CloseGameControllers();
void UpdateControllerControllerMapping();
void HandleSDLControllerAxisEventForController(const SDL_Event* event);
void HandleSDLControllerButtonEventForController(const SDL_Event* event);
void UpdateControllerRumble();
void DrawMainMenuBar();
void DrawQuickSettingsMenu();
void DrawDebugMenu();
void DrawPoweredOffWindow();
void DrawSettingsWindow();
void DrawAboutWindow();
bool DrawFileChooser(const char* label, std::string* path, const char* filter = nullptr);
SDL_Window* m_window = nullptr;
std::unique_ptr<HostDisplayTexture> m_app_icon_texture;
KeyboardControllerActionMap m_keyboard_button_mapping;
std::map<int, ControllerData> m_sdl_controllers;
std::array<s32, SDL_CONTROLLER_AXIS_MAX> m_controller_axis_mapping;
std::array<s32, SDL_CONTROLLER_BUTTON_MAX> m_controller_button_mapping;
u32 m_switch_gpu_renderer_event_id = 0;
bool m_quit_request = false;
bool m_frame_step_request = false;
bool m_focus_main_menu_bar = false;
bool m_settings_window_open = false;
bool m_about_window_open = false;
};

View File

@ -0,0 +1,105 @@
#include "sdl_settings_interface.h"
#include "common/log.h"
#include <algorithm>
Log_SetChannel(SDLSettingsInterface);
SDLSettingsInterface::SDLSettingsInterface(const char* filename) : m_filename(filename), m_ini(true, true)
{
SI_Error err = m_ini.LoadFile(filename);
if (err != SI_OK)
Log_WarningPrintf("Settings could not be loaded from '%s', defaults will be used.", filename);
}
SDLSettingsInterface::~SDLSettingsInterface()
{
SI_Error err = m_ini.SaveFile(m_filename.c_str(), false);
if (err != SI_OK)
Log_WarningPrintf("Failed to save settings to '%s'.", m_filename.c_str());
}
int SDLSettingsInterface::GetIntValue(const char* section, const char* key, int default_value /*= 0*/)
{
return static_cast<int>(m_ini.GetLongValue(section, key, default_value));
}
float SDLSettingsInterface::GetFloatValue(const char* section, const char* key, float default_value /*= 0.0f*/)
{
return static_cast<float>(m_ini.GetDoubleValue(section, key, default_value));
}
bool SDLSettingsInterface::GetBoolValue(const char* section, const char* key, bool default_value /*= false*/)
{
return m_ini.GetBoolValue(section, key, default_value);
}
std::string SDLSettingsInterface::GetStringValue(const char* section, const char* key,
const char* default_value /*= ""*/)
{
return m_ini.GetValue(section, key, default_value);
}
void SDLSettingsInterface::SetIntValue(const char* section, const char* key, int value)
{
m_ini.SetLongValue(section, key, static_cast<long>(value), nullptr, false, true);
}
void SDLSettingsInterface::SetFloatValue(const char* section, const char* key, float value)
{
m_ini.SetDoubleValue(section, key, static_cast<double>(value), nullptr, true);
}
void SDLSettingsInterface::SetBoolValue(const char* section, const char* key, bool value)
{
m_ini.SetBoolValue(section, key, value, nullptr, true);
}
void SDLSettingsInterface::SetStringValue(const char* section, const char* key, const char* value)
{
m_ini.SetValue(section, key, value, nullptr, true);
}
void SDLSettingsInterface::DeleteValue(const char* section, const char* key)
{
m_ini.Delete(section, key);
}
std::vector<std::string> SDLSettingsInterface::GetStringList(const char* section, const char* key)
{
std::list<CSimpleIniA::Entry> entries;
if (!m_ini.GetAllValues(section, key, entries))
return {};
std::vector<std::string> ret;
ret.reserve(entries.size());
std::transform(entries.begin(), entries.end(), std::back_inserter(ret),
[](const CSimpleIniA::Entry& it) { return std::string(it.pItem); });
return ret;
}
void SDLSettingsInterface::SetStringList(const char* section, const char* key,
const std::vector<std::string_view>& items)
{
m_ini.Delete(section, key);
for (const std::string_view& sv : items)
m_ini.SetValue(section, key, std::string(sv).c_str(), nullptr, false);
}
bool SDLSettingsInterface::RemoveFromStringList(const char* section, const char* key, const char* item)
{
return m_ini.DeleteValue(section, key, item, true);
}
bool SDLSettingsInterface::AddToStringList(const char* section, const char* key, const char* item)
{
std::list<CSimpleIniA::Entry> entries;
if (m_ini.GetAllValues(section, key, entries) &&
std::find_if(entries.begin(), entries.end(),
[item](const CSimpleIniA::Entry& e) { return (std::strcmp(e.pItem, item) == 0); }) != entries.end())
{
return false;
}
m_ini.SetValue(section, key, item, nullptr, false);
return true;
}

View File

@ -0,0 +1,31 @@
#pragma once
#include "core/settings.h"
#include "SimpleIni.h"
class SDLSettingsInterface : public SettingsInterface
{
public:
SDLSettingsInterface(const char* filename);
~SDLSettingsInterface();
int GetIntValue(const char* section, const char* key, int default_value = 0) override;
float GetFloatValue(const char* section, const char* key, float default_value = 0.0f) override;
bool GetBoolValue(const char* section, const char* key, bool default_value = false) override;
std::string GetStringValue(const char* section, const char* key, const char* default_value = "") override;
void SetIntValue(const char* section, const char* key, int value) override;
void SetFloatValue(const char* section, const char* key, float value) override;
void SetBoolValue(const char* section, const char* key, bool value) override;
void SetStringValue(const char* section, const char* key, const char* value) override;
void DeleteValue(const char* section, const char* key) override;
std::vector<std::string> GetStringList(const char* section, const char* key) override;
void SetStringList(const char* section, const char* key, const std::vector<std::string_view>& items) override;
bool RemoveFromStringList(const char* section, const char* key, const char* item) override;
bool AddToStringList(const char* section, const char* key, const char* item) override;
private:
std::string m_filename;
CSimpleIniA m_ini;
};