summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt6
-rw-r--r--CMakeModules/CopyYuzuQt5Deps.cmake7
-rw-r--r--src/yuzu/CMakeLists.txt5
-rw-r--r--src/yuzu/bootmanager.cpp71
-rw-r--r--src/yuzu/bootmanager.h12
-rw-r--r--src/yuzu/configuration/config.cpp12
-rw-r--r--src/yuzu/configuration/config.h2
-rw-r--r--src/yuzu/configuration/configure_camera.cpp126
-rw-r--r--src/yuzu/configuration/configure_camera.h52
-rw-r--r--src/yuzu/configuration/configure_camera.ui170
-rw-r--r--src/yuzu/configuration/configure_input.cpp5
-rw-r--r--src/yuzu/configuration/configure_input_advanced.cpp3
-rw-r--r--src/yuzu/configuration/configure_input_advanced.h1
-rw-r--r--src/yuzu/configuration/configure_input_advanced.ui14
-rw-r--r--src/yuzu/main.cpp9
15 files changed, 491 insertions, 4 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3f7dcc924..40ca8b149 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -196,7 +196,7 @@ if(ENABLE_QT)
196 # Check for system Qt on Linux, fallback to bundled Qt 196 # Check for system Qt on Linux, fallback to bundled Qt
197 if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux") 197 if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
198 if (NOT YUZU_USE_BUNDLED_QT) 198 if (NOT YUZU_USE_BUNDLED_QT)
199 find_package(Qt5 ${QT_VERSION} COMPONENTS Widgets DBus) 199 find_package(Qt5 ${QT_VERSION} COMPONENTS Widgets DBus Multimedia)
200 endif() 200 endif()
201 if (NOT Qt5_FOUND OR YUZU_USE_BUNDLED_QT) 201 if (NOT Qt5_FOUND OR YUZU_USE_BUNDLED_QT)
202 # Check for dependencies, then enable bundled Qt download 202 # Check for dependencies, then enable bundled Qt download
@@ -300,9 +300,9 @@ if(ENABLE_QT)
300 set(YUZU_QT_NO_CMAKE_SYSTEM_PATH "NO_CMAKE_SYSTEM_PATH") 300 set(YUZU_QT_NO_CMAKE_SYSTEM_PATH "NO_CMAKE_SYSTEM_PATH")
301 endif() 301 endif()
302 if ((${CMAKE_SYSTEM_NAME} STREQUAL "Linux") AND YUZU_USE_BUNDLED_QT) 302 if ((${CMAKE_SYSTEM_NAME} STREQUAL "Linux") AND YUZU_USE_BUNDLED_QT)
303 find_package(Qt5 ${QT_VERSION} REQUIRED COMPONENTS Widgets Concurrent DBus ${QT_PREFIX_HINT} ${YUZU_QT_NO_CMAKE_SYSTEM_PATH}) 303 find_package(Qt5 ${QT_VERSION} REQUIRED COMPONENTS Widgets Concurrent Multimedia DBus ${QT_PREFIX_HINT} ${YUZU_QT_NO_CMAKE_SYSTEM_PATH})
304 else() 304 else()
305 find_package(Qt5 ${QT_VERSION} REQUIRED COMPONENTS Widgets Concurrent ${QT_PREFIX_HINT} ${YUZU_QT_NO_CMAKE_SYSTEM_PATH}) 305 find_package(Qt5 ${QT_VERSION} REQUIRED COMPONENTS Widgets Concurrent Multimedia ${QT_PREFIX_HINT} ${YUZU_QT_NO_CMAKE_SYSTEM_PATH})
306 endif() 306 endif()
307 if (YUZU_USE_QT_WEB_ENGINE) 307 if (YUZU_USE_QT_WEB_ENGINE)
308 find_package(Qt5 REQUIRED COMPONENTS WebEngineCore WebEngineWidgets) 308 find_package(Qt5 REQUIRED COMPONENTS WebEngineCore WebEngineWidgets)
diff --git a/CMakeModules/CopyYuzuQt5Deps.cmake b/CMakeModules/CopyYuzuQt5Deps.cmake
index 0c27d51a6..4702a504c 100644
--- a/CMakeModules/CopyYuzuQt5Deps.cmake
+++ b/CMakeModules/CopyYuzuQt5Deps.cmake
@@ -10,11 +10,13 @@ function(copy_yuzu_Qt5_deps target_dir)
10 set(Qt5_PLATFORMS_DIR "${Qt5_DIR}/../../../plugins/platforms/") 10 set(Qt5_PLATFORMS_DIR "${Qt5_DIR}/../../../plugins/platforms/")
11 set(Qt5_PLATFORMTHEMES_DIR "${Qt5_DIR}/../../../plugins/platformthemes/") 11 set(Qt5_PLATFORMTHEMES_DIR "${Qt5_DIR}/../../../plugins/platformthemes/")
12 set(Qt5_PLATFORMINPUTCONTEXTS_DIR "${Qt5_DIR}/../../../plugins/platforminputcontexts/") 12 set(Qt5_PLATFORMINPUTCONTEXTS_DIR "${Qt5_DIR}/../../../plugins/platforminputcontexts/")
13 set(Qt5_MEDIASERVICE_DIR "${Qt5_DIR}/../../../plugins/mediaservice/")
13 set(Qt5_XCBGLINTEGRATIONS_DIR "${Qt5_DIR}/../../../plugins/xcbglintegrations/") 14 set(Qt5_XCBGLINTEGRATIONS_DIR "${Qt5_DIR}/../../../plugins/xcbglintegrations/")
14 set(Qt5_STYLES_DIR "${Qt5_DIR}/../../../plugins/styles/") 15 set(Qt5_STYLES_DIR "${Qt5_DIR}/../../../plugins/styles/")
15 set(Qt5_IMAGEFORMATS_DIR "${Qt5_DIR}/../../../plugins/imageformats/") 16 set(Qt5_IMAGEFORMATS_DIR "${Qt5_DIR}/../../../plugins/imageformats/")
16 set(Qt5_RESOURCES_DIR "${Qt5_DIR}/../../../resources/") 17 set(Qt5_RESOURCES_DIR "${Qt5_DIR}/../../../resources/")
17 set(PLATFORMS ${DLL_DEST}plugins/platforms/) 18 set(PLATFORMS ${DLL_DEST}plugins/platforms/)
19 set(MEDIASERVICE ${DLL_DEST}mediaservice/)
18 set(STYLES ${DLL_DEST}plugins/styles/) 20 set(STYLES ${DLL_DEST}plugins/styles/)
19 set(IMAGEFORMATS ${DLL_DEST}plugins/imageformats/) 21 set(IMAGEFORMATS ${DLL_DEST}plugins/imageformats/)
20 if (MSVC) 22 if (MSVC)
@@ -22,6 +24,7 @@ function(copy_yuzu_Qt5_deps target_dir)
22 Qt5Core$<$<CONFIG:Debug>:d>.* 24 Qt5Core$<$<CONFIG:Debug>:d>.*
23 Qt5Gui$<$<CONFIG:Debug>:d>.* 25 Qt5Gui$<$<CONFIG:Debug>:d>.*
24 Qt5Widgets$<$<CONFIG:Debug>:d>.* 26 Qt5Widgets$<$<CONFIG:Debug>:d>.*
27 Qt5Multimedia$<$<CONFIG:Debug>:d>.*
25 ) 28 )
26 29
27 if (YUZU_USE_QT_WEB_ENGINE) 30 if (YUZU_USE_QT_WEB_ENGINE)
@@ -53,6 +56,10 @@ function(copy_yuzu_Qt5_deps target_dir)
53 qjpeg$<$<CONFIG:Debug>:d>.* 56 qjpeg$<$<CONFIG:Debug>:d>.*
54 qgif$<$<CONFIG:Debug>:d>.* 57 qgif$<$<CONFIG:Debug>:d>.*
55 ) 58 )
59 windows_copy_files(yuzu ${Qt5_MEDIASERVICE_DIR} ${MEDIASERVICE}
60 dsengine$<$<CONFIG:Debug>:d>.*
61 wmfengine$<$<CONFIG:Debug>:d>.*
62 )
56 else() 63 else()
57 set(Qt5_DLLS 64 set(Qt5_DLLS
58 "${Qt5_DLL_DIR}libQt5Core.so.5" 65 "${Qt5_DLL_DIR}libQt5Core.so.5"
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index 242867a4f..a11a3b908 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -43,6 +43,9 @@ add_executable(yuzu
43 configuration/configure_audio.cpp 43 configuration/configure_audio.cpp
44 configuration/configure_audio.h 44 configuration/configure_audio.h
45 configuration/configure_audio.ui 45 configuration/configure_audio.ui
46 configuration/configure_camera.cpp
47 configuration/configure_camera.h
48 configuration/configure_camera.ui
46 configuration/configure_cpu.cpp 49 configuration/configure_cpu.cpp
47 configuration/configure_cpu.h 50 configuration/configure_cpu.h
48 configuration/configure_cpu.ui 51 configuration/configure_cpu.ui
@@ -254,7 +257,7 @@ endif()
254create_target_directory_groups(yuzu) 257create_target_directory_groups(yuzu)
255 258
256target_link_libraries(yuzu PRIVATE common core input_common video_core) 259target_link_libraries(yuzu PRIVATE common core input_common video_core)
257target_link_libraries(yuzu PRIVATE Boost::boost glad Qt::Widgets) 260target_link_libraries(yuzu PRIVATE Boost::boost glad Qt::Widgets Qt::Multimedia)
258target_link_libraries(yuzu PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) 261target_link_libraries(yuzu PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads)
259 262
260target_include_directories(yuzu PRIVATE ../../externals/Vulkan-Headers/include) 263target_include_directories(yuzu PRIVATE ../../externals/Vulkan-Headers/include)
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp
index 01acda22b..774085809 100644
--- a/src/yuzu/bootmanager.cpp
+++ b/src/yuzu/bootmanager.cpp
@@ -5,6 +5,8 @@
5#include <glad/glad.h> 5#include <glad/glad.h>
6 6
7#include <QApplication> 7#include <QApplication>
8#include <QCameraImageCapture>
9#include <QCameraInfo>
8#include <QHBoxLayout> 10#include <QHBoxLayout>
9#include <QMessageBox> 11#include <QMessageBox>
10#include <QPainter> 12#include <QPainter>
@@ -31,6 +33,7 @@
31#include "core/core.h" 33#include "core/core.h"
32#include "core/cpu_manager.h" 34#include "core/cpu_manager.h"
33#include "core/frontend/framebuffer_layout.h" 35#include "core/frontend/framebuffer_layout.h"
36#include "input_common/drivers/camera.h"
34#include "input_common/drivers/keyboard.h" 37#include "input_common/drivers/keyboard.h"
35#include "input_common/drivers/mouse.h" 38#include "input_common/drivers/mouse.h"
36#include "input_common/drivers/tas_input.h" 39#include "input_common/drivers/tas_input.h"
@@ -801,6 +804,74 @@ void GRenderWindow::TouchEndEvent() {
801 input_subsystem->GetTouchScreen()->ReleaseAllTouch(); 804 input_subsystem->GetTouchScreen()->ReleaseAllTouch();
802} 805}
803 806
807void GRenderWindow::InitializeCamera() {
808 if (!Settings::values.enable_ir_sensor) {
809 return;
810 }
811
812 bool camera_found = false;
813 const QList<QCameraInfo> cameras = QCameraInfo::availableCameras();
814 for (const QCameraInfo& cameraInfo : cameras) {
815 if (Settings::values.ir_sensor_device.GetValue() == cameraInfo.deviceName().toStdString() ||
816 Settings::values.ir_sensor_device.GetValue() == "Auto") {
817 camera = std::make_unique<QCamera>(cameraInfo);
818 camera_found = true;
819 break;
820 }
821 }
822
823 if (!camera_found) {
824 return;
825 }
826
827 camera_capture = std::make_unique<QCameraImageCapture>(camera.get());
828 connect(camera_capture.get(), &QCameraImageCapture::imageCaptured, this,
829 &GRenderWindow::OnCameraCapture);
830 camera->unload();
831 camera->setCaptureMode(QCamera::CaptureViewfinder);
832 camera->load();
833
834 camera_timer = std::make_unique<QTimer>();
835 connect(camera_timer.get(), &QTimer::timeout, [this] { RequestCameraCapture(); });
836 // This timer should be dependent of camera resolution 5ms for every 100 pixels
837 camera_timer->start(100);
838}
839
840void GRenderWindow::FinalizeCamera() {
841 if (camera_timer) {
842 camera_timer->stop();
843 }
844 if (camera) {
845 camera->unload();
846 }
847}
848
849void GRenderWindow::RequestCameraCapture() {
850 if (!Settings::values.enable_ir_sensor) {
851 return;
852 }
853
854 // Idealy one should only call capture but Qt refuses to take a second capture without
855 // stopping the camera
856 camera->stop();
857 camera->start();
858
859 camera_capture->capture();
860}
861
862void GRenderWindow::OnCameraCapture(int requestId, const QImage& img) {
863 constexpr std::size_t camera_width = 320;
864 constexpr std::size_t camera_height = 240;
865 const auto converted =
866 img.scaled(camera_width, camera_height, Qt::AspectRatioMode::IgnoreAspectRatio,
867 Qt::TransformationMode::SmoothTransformation)
868 .mirrored(false, true);
869 std::vector<u32> camera_data{};
870 camera_data.resize(camera_width * camera_height);
871 std::memcpy(camera_data.data(), converted.bits(), camera_width * camera_height * sizeof(u32));
872 input_subsystem->GetCamera()->SetCameraData(camera_width, camera_height, camera_data);
873}
874
804bool GRenderWindow::event(QEvent* event) { 875bool GRenderWindow::event(QEvent* event) {
805 if (event->type() == QEvent::TouchBegin) { 876 if (event->type() == QEvent::TouchBegin) {
806 TouchBeginEvent(static_cast<QTouchEvent*>(event)); 877 TouchBeginEvent(static_cast<QTouchEvent*>(event));
diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h
index 81fe52c0e..346201768 100644
--- a/src/yuzu/bootmanager.h
+++ b/src/yuzu/bootmanager.h
@@ -20,6 +20,8 @@
20 20
21class GRenderWindow; 21class GRenderWindow;
22class GMainWindow; 22class GMainWindow;
23class QCamera;
24class QCameraImageCapture;
23class QKeyEvent; 25class QKeyEvent;
24 26
25namespace Core { 27namespace Core {
@@ -164,6 +166,9 @@ public:
164 void mouseReleaseEvent(QMouseEvent* event) override; 166 void mouseReleaseEvent(QMouseEvent* event) override;
165 void wheelEvent(QWheelEvent* event) override; 167 void wheelEvent(QWheelEvent* event) override;
166 168
169 void InitializeCamera();
170 void FinalizeCamera();
171
167 bool event(QEvent* event) override; 172 bool event(QEvent* event) override;
168 173
169 void focusOutEvent(QFocusEvent* event) override; 174 void focusOutEvent(QFocusEvent* event) override;
@@ -207,6 +212,9 @@ private:
207 void TouchUpdateEvent(const QTouchEvent* event); 212 void TouchUpdateEvent(const QTouchEvent* event);
208 void TouchEndEvent(); 213 void TouchEndEvent();
209 214
215 void RequestCameraCapture();
216 void OnCameraCapture(int requestId, const QImage& img);
217
210 void OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal_size) override; 218 void OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal_size) override;
211 219
212 bool InitializeOpenGL(); 220 bool InitializeOpenGL();
@@ -232,6 +240,10 @@ private:
232 bool first_frame = false; 240 bool first_frame = false;
233 InputCommon::TasInput::TasState last_tas_state; 241 InputCommon::TasInput::TasState last_tas_state;
234 242
243 std::unique_ptr<QCamera> camera;
244 std::unique_ptr<QCameraImageCapture> camera_capture;
245 std::unique_ptr<QTimer> camera_timer;
246
235 Core::System& system; 247 Core::System& system;
236 248
237protected: 249protected:
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 2840bc5eb..1f76e86b9 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -368,6 +368,11 @@ void Config::ReadHidbusValues() {
368 } 368 }
369} 369}
370 370
371void Config::ReadIrCameraValues() {
372 ReadBasicSetting(Settings::values.enable_ir_sensor);
373 ReadBasicSetting(Settings::values.ir_sensor_device);
374}
375
371void Config::ReadAudioValues() { 376void Config::ReadAudioValues() {
372 qt_config->beginGroup(QStringLiteral("Audio")); 377 qt_config->beginGroup(QStringLiteral("Audio"));
373 378
@@ -393,6 +398,7 @@ void Config::ReadControlValues() {
393 ReadTouchscreenValues(); 398 ReadTouchscreenValues();
394 ReadMotionTouchValues(); 399 ReadMotionTouchValues();
395 ReadHidbusValues(); 400 ReadHidbusValues();
401 ReadIrCameraValues();
396 402
397#ifdef _WIN32 403#ifdef _WIN32
398 ReadBasicSetting(Settings::values.enable_raw_input); 404 ReadBasicSetting(Settings::values.enable_raw_input);
@@ -1005,6 +1011,11 @@ void Config::SaveHidbusValues() {
1005 QString::fromStdString(default_param)); 1011 QString::fromStdString(default_param));
1006} 1012}
1007 1013
1014void Config::SaveIrCameraValues() {
1015 WriteBasicSetting(Settings::values.enable_ir_sensor);
1016 WriteBasicSetting(Settings::values.ir_sensor_device);
1017}
1018
1008void Config::SaveValues() { 1019void Config::SaveValues() {
1009 if (global) { 1020 if (global) {
1010 SaveControlValues(); 1021 SaveControlValues();
@@ -1047,6 +1058,7 @@ void Config::SaveControlValues() {
1047 SaveTouchscreenValues(); 1058 SaveTouchscreenValues();
1048 SaveMotionTouchValues(); 1059 SaveMotionTouchValues();
1049 SaveHidbusValues(); 1060 SaveHidbusValues();
1061 SaveIrCameraValues();
1050 1062
1051 WriteGlobalSetting(Settings::values.use_docked_mode); 1063 WriteGlobalSetting(Settings::values.use_docked_mode);
1052 WriteGlobalSetting(Settings::values.vibration_enabled); 1064 WriteGlobalSetting(Settings::values.vibration_enabled);
diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h
index d511b3dbd..a71eabe8e 100644
--- a/src/yuzu/configuration/config.h
+++ b/src/yuzu/configuration/config.h
@@ -68,6 +68,7 @@ private:
68 void ReadTouchscreenValues(); 68 void ReadTouchscreenValues();
69 void ReadMotionTouchValues(); 69 void ReadMotionTouchValues();
70 void ReadHidbusValues(); 70 void ReadHidbusValues();
71 void ReadIrCameraValues();
71 72
72 // Read functions bases off the respective config section names. 73 // Read functions bases off the respective config section names.
73 void ReadAudioValues(); 74 void ReadAudioValues();
@@ -96,6 +97,7 @@ private:
96 void SaveTouchscreenValues(); 97 void SaveTouchscreenValues();
97 void SaveMotionTouchValues(); 98 void SaveMotionTouchValues();
98 void SaveHidbusValues(); 99 void SaveHidbusValues();
100 void SaveIrCameraValues();
99 101
100 // Save functions based off the respective config section names. 102 // Save functions based off the respective config section names.
101 void SaveAudioValues(); 103 void SaveAudioValues();
diff --git a/src/yuzu/configuration/configure_camera.cpp b/src/yuzu/configuration/configure_camera.cpp
new file mode 100644
index 000000000..97febb33c
--- /dev/null
+++ b/src/yuzu/configuration/configure_camera.cpp
@@ -0,0 +1,126 @@
1// Text : Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include <memory>
5#include <QCameraImageCapture>
6#include <QCameraInfo>
7#include <QStandardItemModel>
8#include <QTimer>
9
10#include "input_common/drivers/camera.h"
11#include "input_common/main.h"
12#include "ui_configure_camera.h"
13#include "yuzu/configuration/config.h"
14#include "yuzu/configuration/configure_camera.h"
15
16ConfigureCamera::ConfigureCamera(QWidget* parent, InputCommon::InputSubsystem* input_subsystem_)
17 : QDialog(parent), input_subsystem{input_subsystem_},
18 ui(std::make_unique<Ui::ConfigureCamera>()) {
19 ui->setupUi(this);
20
21 connect(ui->restore_defaults_button, &QPushButton::clicked, this,
22 &ConfigureCamera::RestoreDefaults);
23 connect(ui->preview_button, &QPushButton::clicked, this, &ConfigureCamera::PreviewCamera);
24
25 auto blank_image = QImage(320, 240, QImage::Format::Format_RGB32);
26 blank_image.fill(Qt::black);
27 DisplayCapturedFrame(0, blank_image);
28
29 LoadConfiguration();
30 resize(0, 0);
31}
32
33ConfigureCamera::~ConfigureCamera() = default;
34
35void ConfigureCamera::PreviewCamera() {
36 const auto index = ui->ir_sensor_combo_box->currentIndex();
37 bool camera_found = false;
38 const QList<QCameraInfo> cameras = QCameraInfo::availableCameras();
39 for (const QCameraInfo& cameraInfo : cameras) {
40 if (input_devices[index] == cameraInfo.deviceName().toStdString() ||
41 input_devices[index] == "Auto") {
42 LOG_ERROR(Frontend, "Selected Camera {} {}", cameraInfo.description().toStdString(),
43 cameraInfo.deviceName().toStdString());
44 camera = std::make_unique<QCamera>(cameraInfo);
45 camera_found = true;
46 break;
47 }
48 }
49
50 // Clear previous frame
51 auto blank_image = QImage(320, 240, QImage::Format::Format_RGB32);
52 blank_image.fill(Qt::black);
53 DisplayCapturedFrame(0, blank_image);
54
55 if (!camera_found) {
56 return;
57 }
58
59 camera_capture = std::make_unique<QCameraImageCapture>(camera.get());
60 connect(camera_capture.get(), &QCameraImageCapture::imageCaptured, this,
61 &ConfigureCamera::DisplayCapturedFrame);
62 camera->unload();
63 camera->setCaptureMode(QCamera::CaptureViewfinder);
64 camera->load();
65
66 camera_timer = std::make_unique<QTimer>();
67 connect(camera_timer.get(), &QTimer::timeout, [this] {
68 camera->stop();
69 camera->start();
70
71 camera_capture->capture();
72 });
73
74 camera_timer->start(250);
75}
76
77void ConfigureCamera::DisplayCapturedFrame(int requestId, const QImage& img) {
78 LOG_ERROR(Frontend, "ImageCaptured {} {}", img.width(), img.height());
79 const auto converted = img.scaled(320, 240, Qt::AspectRatioMode::IgnoreAspectRatio,
80 Qt::TransformationMode::SmoothTransformation);
81 ui->preview_box->setPixmap(QPixmap::fromImage(converted));
82}
83
84void ConfigureCamera::changeEvent(QEvent* event) {
85 if (event->type() == QEvent::LanguageChange) {
86 RetranslateUI();
87 }
88
89 QDialog::changeEvent(event);
90}
91
92void ConfigureCamera::RetranslateUI() {
93 ui->retranslateUi(this);
94}
95
96void ConfigureCamera::ApplyConfiguration() {
97 const auto index = ui->ir_sensor_combo_box->currentIndex();
98 Settings::values.ir_sensor_device.SetValue(input_devices[index]);
99}
100
101void ConfigureCamera::LoadConfiguration() {
102 input_devices.clear();
103 ui->ir_sensor_combo_box->clear();
104 input_devices.push_back("Auto");
105 ui->ir_sensor_combo_box->addItem(tr("Auto"));
106 const auto cameras = QCameraInfo::availableCameras();
107 for (const QCameraInfo& cameraInfo : cameras) {
108 input_devices.push_back(cameraInfo.deviceName().toStdString());
109 ui->ir_sensor_combo_box->addItem(cameraInfo.description());
110 }
111
112 const auto current_device = Settings::values.ir_sensor_device.GetValue();
113
114 const auto devices_it = std::find_if(
115 input_devices.begin(), input_devices.end(),
116 [current_device](const std::string& device) { return device == current_device; });
117 const int device_index =
118 devices_it != input_devices.end()
119 ? static_cast<int>(std::distance(input_devices.begin(), devices_it))
120 : 0;
121 ui->ir_sensor_combo_box->setCurrentIndex(device_index);
122}
123
124void ConfigureCamera::RestoreDefaults() {
125 ui->ir_sensor_combo_box->setCurrentIndex(0);
126}
diff --git a/src/yuzu/configuration/configure_camera.h b/src/yuzu/configuration/configure_camera.h
new file mode 100644
index 000000000..af7551c03
--- /dev/null
+++ b/src/yuzu/configuration/configure_camera.h
@@ -0,0 +1,52 @@
1// Text : Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include <memory>
7#include <QDialog>
8
9class QTimer;
10class QCamera;
11class QCameraImageCapture;
12
13namespace InputCommon {
14class InputSubsystem;
15} // namespace InputCommon
16
17namespace Ui {
18class ConfigureCamera;
19}
20
21class ConfigureCamera : public QDialog {
22 Q_OBJECT
23
24public:
25 explicit ConfigureCamera(QWidget* parent, InputCommon::InputSubsystem* input_subsystem_);
26 ~ConfigureCamera() override;
27
28 void ApplyConfiguration();
29
30private:
31 void changeEvent(QEvent* event) override;
32 void RetranslateUI();
33
34 /// Load configuration settings.
35 void LoadConfiguration();
36
37 /// Restore all buttons to their default values.
38 void RestoreDefaults();
39
40 void DisplayCapturedFrame(int requestId, const QImage& img);
41
42 /// Loads and signals the current selected camera to display a frame
43 void PreviewCamera();
44
45 InputCommon::InputSubsystem* input_subsystem;
46
47 std::unique_ptr<QCamera> camera;
48 std::unique_ptr<QCameraImageCapture> camera_capture;
49 std::unique_ptr<QTimer> camera_timer;
50 std::vector<std::string> input_devices;
51 std::unique_ptr<Ui::ConfigureCamera> ui;
52};
diff --git a/src/yuzu/configuration/configure_camera.ui b/src/yuzu/configuration/configure_camera.ui
new file mode 100644
index 000000000..976a9b1ec
--- /dev/null
+++ b/src/yuzu/configuration/configure_camera.ui
@@ -0,0 +1,170 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0">
3 <class>ConfigureCamera</class>
4 <widget class="QDialog" name="ConfigureCamera">
5 <property name="geometry">
6 <rect>
7 <x>0</x>
8 <y>0</y>
9 <width>298</width>
10 <height>339</height>
11 </rect>
12 </property>
13 <property name="windowTitle">
14 <string>Configure Infrared Camera</string>
15 </property>
16 <layout class="QVBoxLayout" name="verticalLayout">
17 <item>
18 <widget class="QLabel" name="label_2">
19 <property name="minimumSize">
20 <size>
21 <width>280</width>
22 <height>0</height>
23 </size>
24 </property>
25 <property name="text">
26 <string>Select where the image of the emulated camera comes from. It may be a virtual camera or a real camera.</string>
27 </property>
28 <property name="wordWrap">
29 <bool>true</bool>
30 </property>
31 </widget>
32 </item>
33 <item>
34 <spacer name="verticalSpacer_2">
35 <property name="orientation">
36 <enum>Qt::Vertical</enum>
37 </property>
38 <property name="sizeType">
39 <enum>QSizePolicy::Fixed</enum>
40 </property>
41 <property name="sizeHint" stdset="0">
42 <size>
43 <width>20</width>
44 <height>20</height>
45 </size>
46 </property>
47 </spacer>
48 </item>
49 <item>
50 <widget class="QGroupBox" name="gridGroupBox">
51 <property name="title">
52 <string>Camera Image Source:</string>
53 </property>
54 <layout class="QGridLayout" name="gridLayout">
55 <item row="0" column="0">
56 <spacer name="horizontalSpacer">
57 <property name="orientation">
58 <enum>Qt::Horizontal</enum>
59 </property>
60 <property name="sizeHint" stdset="0">
61 <size>
62 <width>40</width>
63 <height>20</height>
64 </size>
65 </property>
66 </spacer>
67 </item>
68 <item row="0" column="1">
69 <widget class="QLabel" name="label_3">
70 <property name="text">
71 <string>Input device:</string>
72 </property>
73 </widget>
74 </item>
75 <item row="0" column="2">
76 <widget class="QComboBox" name="ir_sensor_combo_box"/>
77 </item>
78 <item row="0" column="3">
79 <spacer name="horizontalSpacer_2">
80 <property name="orientation">
81 <enum>Qt::Horizontal</enum>
82 </property>
83 <property name="sizeHint" stdset="0">
84 <size>
85 <width>40</width>
86 <height>20</height>
87 </size>
88 </property>
89 </spacer>
90 </item>
91 </layout>
92 </widget>
93 </item><item>
94 <widget class="QGroupBox" name="previewBox">
95 <property name="title">
96 <string>Preview</string>
97 </property>
98 <layout class="QVBoxLayout" name="verticalLayout_3">
99 <item>
100 <widget class="QLabel" name="preview_box">
101 <property name="minimumSize">
102 <size>
103 <width>320</width>
104 <height>240</height>
105 </size>
106 </property>
107 <property name="toolTip">
108 <string>Resolution: 320*240</string>
109 </property>
110 </widget>
111 </item>
112 <item>
113 <widget class="QPushButton" name="preview_button">
114 <property name="text">
115 <string>Click to preview</string>
116 </property>
117 </widget>
118 </item>
119 </layout>
120 </widget>
121 </item>
122 <item>
123 <spacer name="verticalSpacer">
124 <property name="orientation">
125 <enum>Qt::Vertical</enum>
126 </property>
127 <property name="sizeHint" stdset="0">
128 <size>
129 <width>20</width>
130 <height>40</height>
131 </size>
132 </property>
133 </spacer>
134 </item>
135 <item>
136 <layout class="QHBoxLayout" name="horizontalLayout">
137 <item>
138 <widget class="QPushButton" name="restore_defaults_button">
139 <property name="text">
140 <string>Restore Defaults</string>
141 </property>
142 </widget>
143 </item>
144 <item>
145 <widget class="QDialogButtonBox" name="buttonBox">
146 <property name="standardButtons">
147 <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
148 </property>
149 </widget>
150 </item>
151 </layout>
152 </item>
153 </layout>
154 </widget>
155 <resources/>
156 <connections>
157 <connection>
158 <sender>buttonBox</sender>
159 <signal>accepted()</signal>
160 <receiver>ConfigureCamera</receiver>
161 <slot>accept()</slot>
162 </connection>
163 <connection>
164 <sender>buttonBox</sender>
165 <signal>rejected()</signal>
166 <receiver>ConfigureCamera</receiver>
167 <slot>reject()</slot>
168 </connection>
169 </connections>
170</ui>
diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp
index 73d7ba24b..f1b061b13 100644
--- a/src/yuzu/configuration/configure_input.cpp
+++ b/src/yuzu/configuration/configure_input.cpp
@@ -15,6 +15,7 @@
15#include "ui_configure_input.h" 15#include "ui_configure_input.h"
16#include "ui_configure_input_advanced.h" 16#include "ui_configure_input_advanced.h"
17#include "ui_configure_input_player.h" 17#include "ui_configure_input_player.h"
18#include "yuzu/configuration/configure_camera.h"
18#include "yuzu/configuration/configure_debug_controller.h" 19#include "yuzu/configuration/configure_debug_controller.h"
19#include "yuzu/configuration/configure_input.h" 20#include "yuzu/configuration/configure_input.h"
20#include "yuzu/configuration/configure_input_advanced.h" 21#include "yuzu/configuration/configure_input_advanced.h"
@@ -163,6 +164,10 @@ void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem,
163 [this, input_subsystem, &hid_core] { 164 [this, input_subsystem, &hid_core] {
164 CallConfigureDialog<ConfigureRingController>(*this, input_subsystem, hid_core); 165 CallConfigureDialog<ConfigureRingController>(*this, input_subsystem, hid_core);
165 }); 166 });
167 connect(advanced, &ConfigureInputAdvanced::CallCameraDialog,
168 [this, input_subsystem, &hid_core] {
169 CallConfigureDialog<ConfigureCamera>(*this, input_subsystem);
170 });
166 171
167 connect(ui->vibrationButton, &QPushButton::clicked, 172 connect(ui->vibrationButton, &QPushButton::clicked,
168 [this, &hid_core] { CallConfigureDialog<ConfigureVibration>(*this, hid_core); }); 173 [this, &hid_core] { CallConfigureDialog<ConfigureVibration>(*this, hid_core); });
diff --git a/src/yuzu/configuration/configure_input_advanced.cpp b/src/yuzu/configuration/configure_input_advanced.cpp
index f14bdc831..10f841b98 100644
--- a/src/yuzu/configuration/configure_input_advanced.cpp
+++ b/src/yuzu/configuration/configure_input_advanced.cpp
@@ -89,6 +89,7 @@ ConfigureInputAdvanced::ConfigureInputAdvanced(QWidget* parent)
89 [this] { CallMotionTouchConfigDialog(); }); 89 [this] { CallMotionTouchConfigDialog(); });
90 connect(ui->ring_controller_configure, &QPushButton::clicked, this, 90 connect(ui->ring_controller_configure, &QPushButton::clicked, this,
91 [this] { CallRingControllerDialog(); }); 91 [this] { CallRingControllerDialog(); });
92 connect(ui->camera_configure, &QPushButton::clicked, this, [this] { CallCameraDialog(); });
92 93
93#ifndef _WIN32 94#ifndef _WIN32
94 ui->enable_raw_input->setVisible(false); 95 ui->enable_raw_input->setVisible(false);
@@ -136,6 +137,7 @@ void ConfigureInputAdvanced::ApplyConfiguration() {
136 Settings::values.enable_udp_controller = ui->enable_udp_controller->isChecked(); 137 Settings::values.enable_udp_controller = ui->enable_udp_controller->isChecked();
137 Settings::values.controller_navigation = ui->controller_navigation->isChecked(); 138 Settings::values.controller_navigation = ui->controller_navigation->isChecked();
138 Settings::values.enable_ring_controller = ui->enable_ring_controller->isChecked(); 139 Settings::values.enable_ring_controller = ui->enable_ring_controller->isChecked();
140 Settings::values.enable_ir_sensor = ui->enable_ir_sensor->isChecked();
139} 141}
140 142
141void ConfigureInputAdvanced::LoadConfiguration() { 143void ConfigureInputAdvanced::LoadConfiguration() {
@@ -169,6 +171,7 @@ void ConfigureInputAdvanced::LoadConfiguration() {
169 ui->enable_udp_controller->setChecked(Settings::values.enable_udp_controller.GetValue()); 171 ui->enable_udp_controller->setChecked(Settings::values.enable_udp_controller.GetValue());
170 ui->controller_navigation->setChecked(Settings::values.controller_navigation.GetValue()); 172 ui->controller_navigation->setChecked(Settings::values.controller_navigation.GetValue());
171 ui->enable_ring_controller->setChecked(Settings::values.enable_ring_controller.GetValue()); 173 ui->enable_ring_controller->setChecked(Settings::values.enable_ring_controller.GetValue());
174 ui->enable_ir_sensor->setChecked(Settings::values.enable_ir_sensor.GetValue());
172 175
173 UpdateUIEnabled(); 176 UpdateUIEnabled();
174} 177}
diff --git a/src/yuzu/configuration/configure_input_advanced.h b/src/yuzu/configuration/configure_input_advanced.h
index 644e56dd8..fc1230284 100644
--- a/src/yuzu/configuration/configure_input_advanced.h
+++ b/src/yuzu/configuration/configure_input_advanced.h
@@ -29,6 +29,7 @@ signals:
29 void CallTouchscreenConfigDialog(); 29 void CallTouchscreenConfigDialog();
30 void CallMotionTouchConfigDialog(); 30 void CallMotionTouchConfigDialog();
31 void CallRingControllerDialog(); 31 void CallRingControllerDialog();
32 void CallCameraDialog();
32 33
33private: 34private:
34 void changeEvent(QEvent* event) override; 35 void changeEvent(QEvent* event) override;
diff --git a/src/yuzu/configuration/configure_input_advanced.ui b/src/yuzu/configuration/configure_input_advanced.ui
index 14403cb10..fac8cf827 100644
--- a/src/yuzu/configuration/configure_input_advanced.ui
+++ b/src/yuzu/configuration/configure_input_advanced.ui
@@ -2617,6 +2617,20 @@
2617 </property> 2617 </property>
2618 </widget> 2618 </widget>
2619 </item> 2619 </item>
2620 <item row="5" column="0">
2621 <widget class="QCheckBox" name="enable_ir_sensor">
2622 <property name="text">
2623 <string>Infrared Camera</string>
2624 </property>
2625 </widget>
2626 </item>
2627 <item row="5" column="2">
2628 <widget class="QPushButton" name="camera_configure">
2629 <property name="text">
2630 <string>Configure</string>
2631 </property>
2632 </widget>
2633 </item>
2620 </layout> 2634 </layout>
2621 </widget> 2635 </widget>
2622 </item> 2636 </item>
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index a120f2662..08ccc1555 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -1542,6 +1542,8 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t
1542 mouse_hide_timer.start(); 1542 mouse_hide_timer.start();
1543 } 1543 }
1544 1544
1545 render_window->InitializeCamera();
1546
1545 std::string title_name; 1547 std::string title_name;
1546 std::string title_version; 1548 std::string title_version;
1547 const auto res = system->GetGameName(title_name); 1549 const auto res = system->GetGameName(title_name);
@@ -1623,6 +1625,7 @@ void GMainWindow::ShutdownGame() {
1623 tas_label->clear(); 1625 tas_label->clear();
1624 input_subsystem->GetTas()->Stop(); 1626 input_subsystem->GetTas()->Stop();
1625 OnTasStateChanged(); 1627 OnTasStateChanged();
1628 render_window->FinalizeCamera();
1626 1629
1627 // Enable all controllers 1630 // Enable all controllers
1628 system->HIDCore().SetSupportedStyleTag({Core::HID::NpadStyleSet::All}); 1631 system->HIDCore().SetSupportedStyleTag({Core::HID::NpadStyleSet::All});
@@ -2862,6 +2865,12 @@ void GMainWindow::OnConfigure() {
2862 mouse_hide_timer.start(); 2865 mouse_hide_timer.start();
2863 } 2866 }
2864 2867
2868 // Restart camera config
2869 if (emulation_running) {
2870 render_window->FinalizeCamera();
2871 render_window->InitializeCamera();
2872 }
2873
2865 if (!UISettings::values.has_broken_vulkan) { 2874 if (!UISettings::values.has_broken_vulkan) {
2866 renderer_status_button->setEnabled(!emulation_running); 2875 renderer_status_button->setEnabled(!emulation_running);
2867 } 2876 }