Skip to content

Commit 7a18e0d

Browse files
committed
InputCommon: add support for overlaying host textures onto the final texture instead of overwriting
1 parent 8502649 commit 7a18e0d

7 files changed

Lines changed: 99 additions & 11 deletions

File tree

Source/Core/InputCommon/DynamicInputTextures/DITConfiguration.cpp

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,8 @@ bool Configuration::ApplyEmulatedEntry(const Configuration::HostEntries& host_en
205205
section->Get(entry.m_key, &host_key);
206206
return ApplyEmulatedSingleEntry(
207207
host_entries, std::vector<std::string>{host_key}, entry.m_tag,
208-
entry.m_region, image_to_write, preserve_aspect_ratio);
208+
entry.m_region, entry.m_copy_type, image_to_write,
209+
preserve_aspect_ratio);
209210
},
210211
[&, this](const Data::EmulatedMultiEntry& entry) {
211212
return ApplyEmulatedMultiEntry(host_entries, entry, section,
@@ -218,7 +219,8 @@ bool Configuration::ApplyEmulatedEntry(const Configuration::HostEntries& host_en
218219
bool Configuration::ApplyEmulatedSingleEntry(const Configuration::HostEntries& host_entries,
219220
const std::vector<std::string> keys,
220221
const std::optional<std::string> tag,
221-
const Rect& region, ImagePixelData& image_to_write,
222+
const Rect& region, Data::CopyType copy_type,
223+
ImagePixelData& image_to_write,
222224
bool preserve_aspect_ratio) const
223225
{
224226
for (auto& host_entry : host_entries)
@@ -243,8 +245,16 @@ bool Configuration::ApplyEmulatedSingleEntry(const Configuration::HostEntries& h
243245
Resize(ResizeMode::Nearest, *host_key_image, region.GetWidth(), region.GetHeight());
244246
}
245247

246-
CopyImageRegion(pixel_data, image_to_write, Rect{0, 0, region.GetWidth(), region.GetHeight()},
247-
region);
248+
if (copy_type == DynamicInputTextures::Data::CopyType::Overwrite)
249+
{
250+
CopyImageRegion(pixel_data, image_to_write,
251+
Rect{0, 0, region.GetWidth(), region.GetHeight()}, region);
252+
}
253+
else
254+
{
255+
OverlayImageRegion(pixel_data, image_to_write,
256+
Rect{0, 0, region.GetWidth(), region.GetHeight()}, region);
257+
}
248258

249259
return true;
250260
}
@@ -270,8 +280,8 @@ bool Configuration::ApplyEmulatedMultiEntry(const Configuration::HostEntries& ho
270280
host_keys.push_back(host_key);
271281
}
272282
if (ApplyEmulatedSingleEntry(host_entries, host_keys, emulated_entry.m_combined_tag,
273-
emulated_entry.m_combined_region, image_to_write,
274-
preserve_aspect_ratio))
283+
emulated_entry.m_combined_region, emulated_entry.m_copy_type,
284+
image_to_write, preserve_aspect_ratio))
275285
{
276286
return true;
277287
}
@@ -287,10 +297,20 @@ bool Configuration::ApplyEmulatedMultiEntry(const Configuration::HostEntries& ho
287297

288298
if (apply)
289299
{
290-
CopyImageRegion(temporary_pixel_data, image_to_write,
291-
Rect{0, 0, emulated_entry.m_combined_region.GetWidth(),
292-
emulated_entry.m_combined_region.GetHeight()},
293-
emulated_entry.m_combined_region);
300+
if (emulated_entry.m_copy_type == DynamicInputTextures::Data::CopyType::Overwrite)
301+
{
302+
CopyImageRegion(temporary_pixel_data, image_to_write,
303+
Rect{0, 0, emulated_entry.m_combined_region.GetWidth(),
304+
emulated_entry.m_combined_region.GetHeight()},
305+
emulated_entry.m_combined_region);
306+
}
307+
else
308+
{
309+
OverlayImageRegion(temporary_pixel_data, image_to_write,
310+
Rect{0, 0, emulated_entry.m_combined_region.GetWidth(),
311+
emulated_entry.m_combined_region.GetHeight()},
312+
emulated_entry.m_combined_region);
313+
}
294314
}
295315

296316
return apply;

Source/Core/InputCommon/DynamicInputTextures/DITConfiguration.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ class Configuration
3535
bool ApplyEmulatedSingleEntry(const HostEntries& host_entries,
3636
const std::vector<std::string> keys,
3737
const std::optional<std::string> tag, const Rect& region,
38-
ImagePixelData& image_to_write, bool preserve_aspect_ratio) const;
38+
Data::CopyType copy_type, ImagePixelData& image_to_write,
39+
bool preserve_aspect_ratio) const;
3940
bool ApplyEmulatedMultiEntry(const HostEntries& host_entries,
4041
const Data::EmulatedMultiEntry& emulated_entry,
4142
const IniFile::Section* section, ImagePixelData& image_to_write,

Source/Core/InputCommon/DynamicInputTextures/DITData.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,25 @@ struct Data
2323
struct EmulatedMultiEntry;
2424
using EmulatedEntry = std::variant<EmulatedSingleEntry, EmulatedMultiEntry>;
2525

26+
enum class CopyType
27+
{
28+
Overwrite,
29+
Overlay
30+
};
31+
2632
struct EmulatedSingleEntry
2733
{
2834
std::string m_key;
2935
std::optional<std::string> m_tag;
3036
Rect m_region;
37+
CopyType m_copy_type = CopyType::Overwrite;
3138
};
3239

3340
struct EmulatedMultiEntry
3441
{
3542
std::string m_combined_tag;
3643
Rect m_combined_region;
44+
CopyType m_copy_type = CopyType::Overwrite;
3745

3846
std::vector<EmulatedEntry> m_sub_entries;
3947
};

Source/Core/InputCommon/DynamicInputTextures/DITSpecification.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,29 @@ std::optional<Data::EmulatedEntry> GetEmulatedEntry(const picojson::object& entr
9898
entry.m_key = *entry_key;
9999
entry.m_tag = GetJsonValueFromMap<std::string>(entry_obj, "tag", json_file, false);
100100

101+
const auto copy_type =
102+
GetJsonValueFromMap<std::string>(entry_obj, "copy_type", json_file, false);
103+
if (copy_type)
104+
{
105+
const auto& copy_type_str = *copy_type;
106+
if (copy_type_str == "overwrite")
107+
{
108+
entry.m_copy_type = DynamicInputTextures::Data::CopyType::Overwrite;
109+
}
110+
else if (copy_type_str == "overlay")
111+
{
112+
entry.m_copy_type = DynamicInputTextures::Data::CopyType::Overlay;
113+
}
114+
else
115+
{
116+
ERROR_LOG_FMT(VIDEO,
117+
"Failed to load dynamic input json file '{}' because field "
118+
"'copy_type' had invalid value '{}'",
119+
json_file, copy_type_str);
120+
return std::nullopt;
121+
}
122+
}
123+
101124
const auto entry_region = GetRect(entry_obj, "region", json_file);
102125
if (!entry_region)
103126
return std::nullopt;

Source/Core/InputCommon/ImageOperations.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,28 @@ void CopyImageRegion(const ImagePixelData& src, ImagePixelData& dst, const Rect&
4545
}
4646
}
4747

48+
void OverlayImageRegion(const ImagePixelData& src, ImagePixelData& dst, const Rect& src_region,
49+
const Rect& dst_region, const Pixel& pixel_skip_color)
50+
{
51+
if (src_region.GetWidth() != dst_region.GetWidth() ||
52+
src_region.GetHeight() != dst_region.GetHeight())
53+
{
54+
return;
55+
}
56+
57+
for (u32 x = 0; x < dst_region.GetWidth(); x++)
58+
{
59+
for (u32 y = 0; y < dst_region.GetHeight(); y++)
60+
{
61+
const auto& src_pixel = src.pixels[(y + src_region.top) * src.width + x + src_region.left];
62+
if (src_pixel == pixel_skip_color)
63+
continue;
64+
65+
dst.pixels[(y + dst_region.top) * dst.width + x + dst_region.left] = src_pixel;
66+
}
67+
}
68+
}
69+
4870
std::optional<ImagePixelData> LoadImage(const std::string& path)
4971
{
5072
File::IOFile file;

Source/Core/InputCommon/ImageOperations.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ struct ImagePixelData
4747

4848
void CopyImageRegion(const ImagePixelData& src, ImagePixelData& dst, const Rect& src_region,
4949
const Rect& dst_region);
50+
void OverlayImageRegion(const ImagePixelData& src, ImagePixelData& dst, const Rect& src_region,
51+
const Rect& dst_region, const Pixel& pixel_skip_color = Pixel{});
5052

5153
std::optional<ImagePixelData> LoadImage(const std::string& path);
5254

docs/DynamicInputTextures/DynamicInputTexturesV2.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,17 @@ Here is an example of a single key with a tag:
8484
}
8585
```
8686

87+
By default the region expressed by the key will be overwritten by the host image. For many games though, there are colors or details that we do not want to completely remove and therefore want to overlay the host image on top of the underlying game texture. To do this you can use "copy_type". By default "copy_type" defaults to 'overwrite' but you may also set it to 'overlay'. Here is an example of a key with the 'overlay' copy_type:
88+
89+
```js
90+
{
91+
"bind_type": "single",
92+
"key": "Buttons/A",
93+
"copy_type": "overlay",
94+
"region": [0, 0, 30, 30]
95+
}
96+
```
97+
8798
##### Multi Key
8899

89100
The single key case works well when an image maps directly to Dolphin's emulated controller bindings. However, what about the case where there is a dpad icon? Dolphin has four mappings for that. This is where a "bind_type" of ``multi`` is helpful.
@@ -96,6 +107,7 @@ Here's an example of that:
96107
{
97108
"bind_type": "multi",
98109
"tag": "dpad",
110+
"copy_type": "overlay",
99111
"region": [0, 0, 45, 45],
100112
"sub_entries": [
101113
{

0 commit comments

Comments
 (0)