Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
0076827
Common: Add variant util helper to simplify writing variant lambda ov…
iwubcode Feb 22, 2021
af39181
InputCommon: Update dynamic input textures data with v2 specification…
iwubcode Feb 22, 2021
f1b9848
InputCommon: update dynamic input textures configuration with support…
iwubcode Feb 22, 2021
62e3749
InputCommon: update v1 specification to use new data structure
iwubcode Feb 22, 2021
8ff225b
InputCommon: Add v2 specification...details later
iwubcode Feb 24, 2021
cdf6485
docs: Move dynamic input texture documentation to a V1 specification
iwubcode Feb 27, 2021
13b116d
docs: add dynamic input texture V2 specification
iwubcode Feb 27, 2021
e1d6127
InputCommon: Update dynamic input textures data with v2 specification…
iwubcode Aug 13, 2021
c2d1aa1
InputCommon: update dynamic input textures configuration with support…
iwubcode Aug 13, 2021
99d00fa
InputCommon: update v1 specification to use new data structure
iwubcode Aug 13, 2021
71aa013
InputCommon: Add v2 specification...details later
iwubcode Aug 13, 2021
9f85e1e
docs: Move dynamic input texture documentation to a V1 specification
iwubcode Aug 13, 2021
8b597a7
docs: add dynamic input texture V2 specification
iwubcode Aug 13, 2021
9239c00
Correct json in documentation
tauqua Aug 14, 2021
9ae714e
Merge branch 'dynamic_input_textures_v2' of https://github.com/tauqua…
tauqua Aug 14, 2021
dd0d80a
Update examples to use v2
tauqua Aug 15, 2021
b0c4ef7
Add example of multi-binding host controls
tauqua Aug 15, 2021
1df8d7c
InputCommon: Update dynamic input textures data with v2 specification…
iwubcode Feb 22, 2021
be14f17
InputCommon: update dynamic input textures configuration with support…
iwubcode Feb 22, 2021
69cfe99
InputCommon: update v1 specification to use new data structure
iwubcode Feb 22, 2021
ffd616b
InputCommon: Add v2 specification...details later
iwubcode Feb 24, 2021
77ec4f1
docs: Move dynamic input texture documentation to a V1 specification
iwubcode Feb 27, 2021
5181341
docs: add dynamic input texture V2 specification
iwubcode Feb 27, 2021
2f45867
Add proof-of-concept relative paths
tauqua Oct 5, 2021
d400ded
Implement proper relative path support
tauqua Oct 8, 2021
b35fcdd
Merge branch 'dynamic_input_textures_v2' of https://github.com/iwubco…
tauqua Oct 8, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
180 changes: 141 additions & 39 deletions Source/Core/InputCommon/DynamicInputTextures/DITConfiguration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "Common/FileUtil.h"
#include "Common/Logging/Log.h"
#include "Common/StringUtil.h"
#include "Common/VariantUtil.h"
#include "Core/ConfigManager.h"
#include "InputCommon/ControllerEmu/ControllerEmu.h"
#include "InputCommon/DynamicInputTextures/DITSpecification.h"
Expand Down Expand Up @@ -72,16 +73,22 @@ Configuration::Configuration(const std::string& json_file)
specification = static_cast<u8>(spec_from_json);
}

if (specification != 1)
if (specification == 1)
{
m_valid = ProcessSpecificationV1(root, m_dynamic_input_textures, m_base_path, json_file);
}
else if (specification == 2)
{
m_valid = ProcessSpecificationV2(root, m_dynamic_input_textures, m_base_path, json_file);
}
else
{
ERROR_LOG_FMT(VIDEO,
"Failed to load dynamic input json file '{}', specification '{}' is invalid",
json_file, specification);
m_valid = false;
return;
}

m_valid = ProcessSpecificationV1(root, m_dynamic_input_textures, m_base_path, json_file);
}

Configuration::~Configuration() = default;
Expand Down Expand Up @@ -109,7 +116,6 @@ bool Configuration::GenerateTexture(const IniFile& file,
auto image_to_write = original_image;

bool dirty = false;

for (const auto& controller_name : controller_names)
{
auto* sec = file.GetSection(controller_name);
Expand Down Expand Up @@ -145,7 +151,7 @@ bool Configuration::GenerateTexture(const IniFile& file,
}
}

for (auto& [emulated_key, rects] : emulated_controls_iter->second)
for (auto& emulated_entry : emulated_controls_iter->second)
{
if (!device_found)
{
Expand All @@ -155,43 +161,11 @@ bool Configuration::GenerateTexture(const IniFile& file,
continue;
}

std::string host_key;
sec->Get(emulated_key, &host_key);

const auto input_image_iter = host_devices_iter->second.find(host_key);
if (input_image_iter == host_devices_iter->second.end())
if (ApplyEmulatedEntry(host_devices_iter->second, emulated_entry, sec, *image_to_write,
texture_data.m_preserve_aspect_ratio))
{
dirty = true;
}
else
{
const auto host_key_image = LoadImage(m_base_path + input_image_iter->second);

for (const auto& rect : rects)
{
InputCommon::ImagePixelData pixel_data;
if (host_key_image->width == rect.GetWidth() &&
host_key_image->height == rect.GetHeight())
{
pixel_data = *host_key_image;
}
else if (texture_data.m_preserve_aspect_ratio)
{
pixel_data =
ResizeKeepAspectRatio(ResizeMode::Nearest, *host_key_image, rect.GetWidth(),
rect.GetHeight(), Pixel{0, 0, 0, 0});
}
else
{
pixel_data =
Resize(ResizeMode::Nearest, *host_key_image, rect.GetWidth(), rect.GetHeight());
}

CopyImageRegion(pixel_data, *image_to_write,
Rect{0, 0, rect.GetWidth(), rect.GetHeight()}, rect);
dirty = true;
}
}
}
}

Expand All @@ -218,4 +192,132 @@ bool Configuration::GenerateTexture(const IniFile& file,

return false;
}

bool Configuration::ApplyEmulatedEntry(const Configuration::HostEntries& host_entries,
const Data::EmulatedEntry& emulated_entry,
const IniFile::Section* section,
ImagePixelData& image_to_write,
bool preserve_aspect_ratio) const
{
return std::visit(overloaded{
[&, this](const Data::EmulatedSingleEntry& entry) {
std::string host_key;
section->Get(entry.m_key, &host_key);
return ApplyEmulatedSingleEntry(
host_entries, std::vector<std::string>{host_key}, entry.m_tag,
entry.m_region, image_to_write, preserve_aspect_ratio);
},
[&, this](const Data::EmulatedMultiEntry& entry) {
return ApplyEmulatedMultiEntry(host_entries, entry, section,
image_to_write, preserve_aspect_ratio);
},
},
emulated_entry);
}

bool Configuration::ApplyEmulatedSingleEntry(const Configuration::HostEntries& host_entries,
const std::vector<std::string> keys,
const std::optional<std::string> tag,
const Rect& region, ImagePixelData& image_to_write,
bool preserve_aspect_ratio) const
{
for (auto& host_entry : host_entries)
{
if (keys == host_entry.m_keys && tag == host_entry.m_tag)
{
const auto host_key_image = LoadImage(m_base_path + host_entry.m_path);
ImagePixelData pixel_data;
if (host_key_image->width == region.GetWidth() &&
host_key_image->height == region.GetHeight())
{
pixel_data = *host_key_image;
}
else if (preserve_aspect_ratio)
{
pixel_data = ResizeKeepAspectRatio(ResizeMode::Nearest, *host_key_image, region.GetWidth(),
region.GetHeight(), Pixel{0, 0, 0, 0});
}
else
{
pixel_data =
Resize(ResizeMode::Nearest, *host_key_image, region.GetWidth(), region.GetHeight());
}

CopyImageRegion(pixel_data, image_to_write, Rect{0, 0, region.GetWidth(), region.GetHeight()},
region);

return true;
}
}

return false;
}

bool Configuration::ApplyEmulatedMultiEntry(const Configuration::HostEntries& host_entries,
const Data::EmulatedMultiEntry& emulated_entry,
const IniFile::Section* section,
InputCommon::ImagePixelData& image_to_write,
bool preserve_aspect_ratio) const
{
// Try to apply our group'd region first
const auto emulated_keys = GetKeysFrom(emulated_entry);
std::vector<std::string> host_keys;
host_keys.reserve(emulated_keys.size());
for (const auto& emulated_key : emulated_keys)
{
std::string host_key;
section->Get(emulated_key, &host_key);
host_keys.push_back(host_key);
}
if (ApplyEmulatedSingleEntry(host_entries, host_keys, emulated_entry.m_combined_tag,
emulated_entry.m_combined_region, image_to_write,
preserve_aspect_ratio))
{
return true;
}

ImagePixelData temporary_pixel_data(emulated_entry.m_combined_region.GetWidth(),
emulated_entry.m_combined_region.GetHeight());
bool apply = false;
for (const auto& sub_entry : emulated_entry.m_sub_entries)
{
apply |= ApplyEmulatedEntry(host_entries, sub_entry, section, temporary_pixel_data,
preserve_aspect_ratio);
}

if (apply)
{
CopyImageRegion(temporary_pixel_data, image_to_write,
Rect{0, 0, emulated_entry.m_combined_region.GetWidth(),
emulated_entry.m_combined_region.GetHeight()},
emulated_entry.m_combined_region);
}

return apply;
}

std::vector<std::string> Configuration::GetKeysFrom(const Data::EmulatedEntry& emulated_entry) const
{
return std::visit(
overloaded{
[&, this](const Data::EmulatedSingleEntry& entry) {
return std::vector<std::string>{entry.m_key};
},
[&, this](const Data::EmulatedMultiEntry& entry) { return GetKeysFrom(entry); },
},
emulated_entry);
}

std::vector<std::string>
Configuration::GetKeysFrom(const Data::EmulatedMultiEntry& emulated_entry) const
{
std::vector<std::string> result;
for (const auto& sub_entry : emulated_entry.m_sub_entries)
{
const auto sub_entry_keys = GetKeysFrom(sub_entry);
result.reserve(result.size() + sub_entry_keys.size());
result.insert(result.end(), sub_entry_keys.begin(), sub_entry_keys.end());
}
return result;
}
} // namespace InputCommon::DynamicInputTextures
20 changes: 20 additions & 0 deletions Source/Core/InputCommon/DynamicInputTextures/DITConfiguration.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@

#include <string>
#include <unordered_map>
#include <variant>
#include <vector>

#include "Common/CommonTypes.h"
#include "Common/IniFile.h"
#include "InputCommon/DynamicInputTextures/DITData.h"
#include "InputCommon/ImageOperations.h"

namespace InputCommon::DynamicInputTextures
{
Expand All @@ -25,6 +27,24 @@ class Configuration
bool GenerateTexture(const IniFile& file, const std::vector<std::string>& controller_names,
const Data& texture_data) const;

using HostEntries = std::vector<Data::HostEntry>;
bool ApplyEmulatedEntry(const HostEntries& host_entries,
const Data::EmulatedEntry& emulated_entry,
const IniFile::Section* section, ImagePixelData& image_to_write,
bool preserve_aspect_ratio) const;
bool ApplyEmulatedSingleEntry(const HostEntries& host_entries,
const std::vector<std::string> keys,
const std::optional<std::string> tag, const Rect& region,
ImagePixelData& image_to_write, bool preserve_aspect_ratio) const;
bool ApplyEmulatedMultiEntry(const HostEntries& host_entries,
const Data::EmulatedMultiEntry& emulated_entry,
const IniFile::Section* section, ImagePixelData& image_to_write,
bool preserve_aspect_ratio) const;

std::vector<std::string> GetKeysFrom(const Data::EmulatedEntry& emulated_entry) const;

std::vector<std::string> GetKeysFrom(const Data::EmulatedMultiEntry& emulated_entry) const;

std::vector<Data> m_dynamic_input_textures;
std::string m_base_path;
bool m_valid = true;
Expand Down
37 changes: 30 additions & 7 deletions Source/Core/InputCommon/DynamicInputTextures/DITData.h
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
// Copyright 2021 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <optional>
#include <string>
#include <unordered_map>
#include <variant>
#include <vector>

#include "InputCommon/ImageOperations.h"
Expand All @@ -17,11 +16,35 @@ struct Data
std::string m_hires_texture_name;
std::string m_generated_folder_name;

using EmulatedKeyToRegionsMap = std::unordered_map<std::string, std::vector<Rect>>;
std::unordered_map<std::string, EmulatedKeyToRegionsMap> m_emulated_controllers;
struct EmulatedSingleEntry;
struct EmulatedMultiEntry;
using EmulatedEntry = std::variant<EmulatedSingleEntry, EmulatedMultiEntry>;

struct EmulatedSingleEntry
{
std::string m_key;
std::optional<std::string> m_tag;
Rect m_region;
};

struct EmulatedMultiEntry
{
std::string m_combined_tag;
Rect m_combined_region;

std::vector<EmulatedEntry> m_sub_entries;
};

std::unordered_map<std::string, std::vector<EmulatedEntry>> m_emulated_controllers;

struct HostEntry
{
std::vector<std::string> m_keys;
std::optional<std::string> m_tag;
std::string m_path;
};

using HostKeyToImagePath = std::unordered_map<std::string, std::string>;
std::unordered_map<std::string, HostKeyToImagePath> m_host_devices;
std::unordered_map<std::string, std::vector<HostEntry>> m_host_devices;
bool m_preserve_aspect_ratio = true;
};
} // namespace InputCommon::DynamicInputTextures
Loading