mirror of
				https://git.tardis.systems/mirrors/yuzu
				synced 2025-10-30 18:24:15 +01:00 
			
		
		
		
	yuzu: Hook qt camera to camera driver
This commit is contained in:
		
							parent
							
								
									f19e7be6e8
								
							
						
					
					
						commit
						cc83e0a600
					
				| @ -196,7 +196,7 @@ if(ENABLE_QT) | |||||||
|     # Check for system Qt on Linux, fallback to bundled Qt |     # Check for system Qt on Linux, fallback to bundled Qt | ||||||
|     if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux") |     if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux") | ||||||
|         if (NOT YUZU_USE_BUNDLED_QT) |         if (NOT YUZU_USE_BUNDLED_QT) | ||||||
|             find_package(Qt5 ${QT_VERSION} COMPONENTS Widgets DBus) |             find_package(Qt5 ${QT_VERSION} COMPONENTS Widgets DBus Multimedia) | ||||||
|         endif() |         endif() | ||||||
|         if (NOT Qt5_FOUND OR YUZU_USE_BUNDLED_QT) |         if (NOT Qt5_FOUND OR YUZU_USE_BUNDLED_QT) | ||||||
|             # Check for dependencies, then enable bundled Qt download |             # Check for dependencies, then enable bundled Qt download | ||||||
| @ -300,9 +300,9 @@ if(ENABLE_QT) | |||||||
|         set(YUZU_QT_NO_CMAKE_SYSTEM_PATH "NO_CMAKE_SYSTEM_PATH") |         set(YUZU_QT_NO_CMAKE_SYSTEM_PATH "NO_CMAKE_SYSTEM_PATH") | ||||||
|     endif() |     endif() | ||||||
|     if ((${CMAKE_SYSTEM_NAME} STREQUAL "Linux") AND YUZU_USE_BUNDLED_QT) |     if ((${CMAKE_SYSTEM_NAME} STREQUAL "Linux") AND YUZU_USE_BUNDLED_QT) | ||||||
|         find_package(Qt5 ${QT_VERSION} REQUIRED COMPONENTS Widgets Concurrent DBus ${QT_PREFIX_HINT} ${YUZU_QT_NO_CMAKE_SYSTEM_PATH}) |         find_package(Qt5 ${QT_VERSION} REQUIRED COMPONENTS Widgets Concurrent Multimedia DBus ${QT_PREFIX_HINT} ${YUZU_QT_NO_CMAKE_SYSTEM_PATH}) | ||||||
|     else() |     else() | ||||||
|         find_package(Qt5 ${QT_VERSION} REQUIRED COMPONENTS Widgets Concurrent ${QT_PREFIX_HINT} ${YUZU_QT_NO_CMAKE_SYSTEM_PATH}) |         find_package(Qt5 ${QT_VERSION} REQUIRED COMPONENTS Widgets Concurrent Multimedia ${QT_PREFIX_HINT} ${YUZU_QT_NO_CMAKE_SYSTEM_PATH}) | ||||||
|     endif() |     endif() | ||||||
|     if (YUZU_USE_QT_WEB_ENGINE) |     if (YUZU_USE_QT_WEB_ENGINE) | ||||||
|         find_package(Qt5 REQUIRED COMPONENTS WebEngineCore WebEngineWidgets) |         find_package(Qt5 REQUIRED COMPONENTS WebEngineCore WebEngineWidgets) | ||||||
|  | |||||||
| @ -10,11 +10,13 @@ function(copy_yuzu_Qt5_deps target_dir) | |||||||
|     set(Qt5_PLATFORMS_DIR "${Qt5_DIR}/../../../plugins/platforms/") |     set(Qt5_PLATFORMS_DIR "${Qt5_DIR}/../../../plugins/platforms/") | ||||||
|     set(Qt5_PLATFORMTHEMES_DIR "${Qt5_DIR}/../../../plugins/platformthemes/") |     set(Qt5_PLATFORMTHEMES_DIR "${Qt5_DIR}/../../../plugins/platformthemes/") | ||||||
|     set(Qt5_PLATFORMINPUTCONTEXTS_DIR "${Qt5_DIR}/../../../plugins/platforminputcontexts/") |     set(Qt5_PLATFORMINPUTCONTEXTS_DIR "${Qt5_DIR}/../../../plugins/platforminputcontexts/") | ||||||
|  |     set(Qt5_MEDIASERVICE_DIR "${Qt5_DIR}/../../../plugins/mediaservice/") | ||||||
|     set(Qt5_XCBGLINTEGRATIONS_DIR "${Qt5_DIR}/../../../plugins/xcbglintegrations/") |     set(Qt5_XCBGLINTEGRATIONS_DIR "${Qt5_DIR}/../../../plugins/xcbglintegrations/") | ||||||
|     set(Qt5_STYLES_DIR "${Qt5_DIR}/../../../plugins/styles/") |     set(Qt5_STYLES_DIR "${Qt5_DIR}/../../../plugins/styles/") | ||||||
|     set(Qt5_IMAGEFORMATS_DIR "${Qt5_DIR}/../../../plugins/imageformats/") |     set(Qt5_IMAGEFORMATS_DIR "${Qt5_DIR}/../../../plugins/imageformats/") | ||||||
|     set(Qt5_RESOURCES_DIR "${Qt5_DIR}/../../../resources/") |     set(Qt5_RESOURCES_DIR "${Qt5_DIR}/../../../resources/") | ||||||
|     set(PLATFORMS ${DLL_DEST}plugins/platforms/) |     set(PLATFORMS ${DLL_DEST}plugins/platforms/) | ||||||
|  |     set(MEDIASERVICE ${DLL_DEST}mediaservice/) | ||||||
|     set(STYLES ${DLL_DEST}plugins/styles/) |     set(STYLES ${DLL_DEST}plugins/styles/) | ||||||
|     set(IMAGEFORMATS ${DLL_DEST}plugins/imageformats/) |     set(IMAGEFORMATS ${DLL_DEST}plugins/imageformats/) | ||||||
|     if (MSVC) |     if (MSVC) | ||||||
| @ -22,6 +24,7 @@ function(copy_yuzu_Qt5_deps target_dir) | |||||||
|             Qt5Core$<$<CONFIG:Debug>:d>.* |             Qt5Core$<$<CONFIG:Debug>:d>.* | ||||||
|             Qt5Gui$<$<CONFIG:Debug>:d>.* |             Qt5Gui$<$<CONFIG:Debug>:d>.* | ||||||
|             Qt5Widgets$<$<CONFIG:Debug>:d>.* |             Qt5Widgets$<$<CONFIG:Debug>:d>.* | ||||||
|  |             Qt5Multimedia$<$<CONFIG:Debug>:d>.* | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|         if (YUZU_USE_QT_WEB_ENGINE) |         if (YUZU_USE_QT_WEB_ENGINE) | ||||||
| @ -53,6 +56,10 @@ function(copy_yuzu_Qt5_deps target_dir) | |||||||
|             qjpeg$<$<CONFIG:Debug>:d>.* |             qjpeg$<$<CONFIG:Debug>:d>.* | ||||||
|             qgif$<$<CONFIG:Debug>:d>.* |             qgif$<$<CONFIG:Debug>:d>.* | ||||||
|         ) |         ) | ||||||
|  |         windows_copy_files(yuzu ${Qt5_MEDIASERVICE_DIR} ${MEDIASERVICE} | ||||||
|  |             dsengine$<$<CONFIG:Debug>:d>.* | ||||||
|  |             wmfengine$<$<CONFIG:Debug>:d>.* | ||||||
|  |         ) | ||||||
|     else() |     else() | ||||||
|         set(Qt5_DLLS |         set(Qt5_DLLS | ||||||
|             "${Qt5_DLL_DIR}libQt5Core.so.5" |             "${Qt5_DLL_DIR}libQt5Core.so.5" | ||||||
|  | |||||||
| @ -43,6 +43,9 @@ add_executable(yuzu | |||||||
|     configuration/configure_audio.cpp |     configuration/configure_audio.cpp | ||||||
|     configuration/configure_audio.h |     configuration/configure_audio.h | ||||||
|     configuration/configure_audio.ui |     configuration/configure_audio.ui | ||||||
|  |     configuration/configure_camera.cpp | ||||||
|  |     configuration/configure_camera.h | ||||||
|  |     configuration/configure_camera.ui | ||||||
|     configuration/configure_cpu.cpp |     configuration/configure_cpu.cpp | ||||||
|     configuration/configure_cpu.h |     configuration/configure_cpu.h | ||||||
|     configuration/configure_cpu.ui |     configuration/configure_cpu.ui | ||||||
| @ -254,7 +257,7 @@ endif() | |||||||
| create_target_directory_groups(yuzu) | create_target_directory_groups(yuzu) | ||||||
| 
 | 
 | ||||||
| target_link_libraries(yuzu PRIVATE common core input_common video_core) | target_link_libraries(yuzu PRIVATE common core input_common video_core) | ||||||
| target_link_libraries(yuzu PRIVATE Boost::boost glad Qt::Widgets) | target_link_libraries(yuzu PRIVATE Boost::boost glad Qt::Widgets Qt::Multimedia) | ||||||
| target_link_libraries(yuzu PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) | target_link_libraries(yuzu PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) | ||||||
| 
 | 
 | ||||||
| target_include_directories(yuzu PRIVATE ../../externals/Vulkan-Headers/include) | target_include_directories(yuzu PRIVATE ../../externals/Vulkan-Headers/include) | ||||||
|  | |||||||
| @ -5,6 +5,8 @@ | |||||||
| #include <glad/glad.h> | #include <glad/glad.h> | ||||||
| 
 | 
 | ||||||
| #include <QApplication> | #include <QApplication> | ||||||
|  | #include <QCameraImageCapture> | ||||||
|  | #include <QCameraInfo> | ||||||
| #include <QHBoxLayout> | #include <QHBoxLayout> | ||||||
| #include <QMessageBox> | #include <QMessageBox> | ||||||
| #include <QPainter> | #include <QPainter> | ||||||
| @ -31,6 +33,7 @@ | |||||||
| #include "core/core.h" | #include "core/core.h" | ||||||
| #include "core/cpu_manager.h" | #include "core/cpu_manager.h" | ||||||
| #include "core/frontend/framebuffer_layout.h" | #include "core/frontend/framebuffer_layout.h" | ||||||
|  | #include "input_common/drivers/camera.h" | ||||||
| #include "input_common/drivers/keyboard.h" | #include "input_common/drivers/keyboard.h" | ||||||
| #include "input_common/drivers/mouse.h" | #include "input_common/drivers/mouse.h" | ||||||
| #include "input_common/drivers/tas_input.h" | #include "input_common/drivers/tas_input.h" | ||||||
| @ -801,6 +804,74 @@ void GRenderWindow::TouchEndEvent() { | |||||||
|     input_subsystem->GetTouchScreen()->ReleaseAllTouch(); |     input_subsystem->GetTouchScreen()->ReleaseAllTouch(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void GRenderWindow::InitializeCamera() { | ||||||
|  |     if (!Settings::values.enable_ir_sensor) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     bool camera_found = false; | ||||||
|  |     const QList<QCameraInfo> cameras = QCameraInfo::availableCameras(); | ||||||
|  |     for (const QCameraInfo& cameraInfo : cameras) { | ||||||
|  |         if (Settings::values.ir_sensor_device.GetValue() == cameraInfo.deviceName().toStdString() || | ||||||
|  |             Settings::values.ir_sensor_device.GetValue() == "Auto") { | ||||||
|  |             camera = std::make_unique<QCamera>(cameraInfo); | ||||||
|  |             camera_found = true; | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (!camera_found) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     camera_capture = std::make_unique<QCameraImageCapture>(camera.get()); | ||||||
|  |     connect(camera_capture.get(), &QCameraImageCapture::imageCaptured, this, | ||||||
|  |             &GRenderWindow::OnCameraCapture); | ||||||
|  |     camera->unload(); | ||||||
|  |     camera->setCaptureMode(QCamera::CaptureViewfinder); | ||||||
|  |     camera->load(); | ||||||
|  | 
 | ||||||
|  |     camera_timer = std::make_unique<QTimer>(); | ||||||
|  |     connect(camera_timer.get(), &QTimer::timeout, [this] { RequestCameraCapture(); }); | ||||||
|  |     // This timer should be dependent of camera resolution 5ms for every 100 pixels
 | ||||||
|  |     camera_timer->start(100); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void GRenderWindow::FinalizeCamera() { | ||||||
|  |     if (camera_timer) { | ||||||
|  |         camera_timer->stop(); | ||||||
|  |     } | ||||||
|  |     if (camera) { | ||||||
|  |         camera->unload(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void GRenderWindow::RequestCameraCapture() { | ||||||
|  |     if (!Settings::values.enable_ir_sensor) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Idealy one should only call capture but Qt refuses to take a second capture without
 | ||||||
|  |     // stopping the camera
 | ||||||
|  |     camera->stop(); | ||||||
|  |     camera->start(); | ||||||
|  | 
 | ||||||
|  |     camera_capture->capture(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void GRenderWindow::OnCameraCapture(int requestId, const QImage& img) { | ||||||
|  |     constexpr std::size_t camera_width = 320; | ||||||
|  |     constexpr std::size_t camera_height = 240; | ||||||
|  |     const auto converted = | ||||||
|  |         img.scaled(camera_width, camera_height, Qt::AspectRatioMode::IgnoreAspectRatio, | ||||||
|  |                    Qt::TransformationMode::SmoothTransformation) | ||||||
|  |             .mirrored(false, true); | ||||||
|  |     std::vector<u32> camera_data{}; | ||||||
|  |     camera_data.resize(camera_width * camera_height); | ||||||
|  |     std::memcpy(camera_data.data(), converted.bits(), camera_width * camera_height * sizeof(u32)); | ||||||
|  |     input_subsystem->GetCamera()->SetCameraData(camera_width, camera_height, camera_data); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| bool GRenderWindow::event(QEvent* event) { | bool GRenderWindow::event(QEvent* event) { | ||||||
|     if (event->type() == QEvent::TouchBegin) { |     if (event->type() == QEvent::TouchBegin) { | ||||||
|         TouchBeginEvent(static_cast<QTouchEvent*>(event)); |         TouchBeginEvent(static_cast<QTouchEvent*>(event)); | ||||||
|  | |||||||
| @ -20,6 +20,8 @@ | |||||||
| 
 | 
 | ||||||
| class GRenderWindow; | class GRenderWindow; | ||||||
| class GMainWindow; | class GMainWindow; | ||||||
|  | class QCamera; | ||||||
|  | class QCameraImageCapture; | ||||||
| class QKeyEvent; | class QKeyEvent; | ||||||
| 
 | 
 | ||||||
| namespace Core { | namespace Core { | ||||||
| @ -164,6 +166,9 @@ public: | |||||||
|     void mouseReleaseEvent(QMouseEvent* event) override; |     void mouseReleaseEvent(QMouseEvent* event) override; | ||||||
|     void wheelEvent(QWheelEvent* event) override; |     void wheelEvent(QWheelEvent* event) override; | ||||||
| 
 | 
 | ||||||
|  |     void InitializeCamera(); | ||||||
|  |     void FinalizeCamera(); | ||||||
|  | 
 | ||||||
|     bool event(QEvent* event) override; |     bool event(QEvent* event) override; | ||||||
| 
 | 
 | ||||||
|     void focusOutEvent(QFocusEvent* event) override; |     void focusOutEvent(QFocusEvent* event) override; | ||||||
| @ -207,6 +212,9 @@ private: | |||||||
|     void TouchUpdateEvent(const QTouchEvent* event); |     void TouchUpdateEvent(const QTouchEvent* event); | ||||||
|     void TouchEndEvent(); |     void TouchEndEvent(); | ||||||
| 
 | 
 | ||||||
|  |     void RequestCameraCapture(); | ||||||
|  |     void OnCameraCapture(int requestId, const QImage& img); | ||||||
|  | 
 | ||||||
|     void OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal_size) override; |     void OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal_size) override; | ||||||
| 
 | 
 | ||||||
|     bool InitializeOpenGL(); |     bool InitializeOpenGL(); | ||||||
| @ -232,6 +240,10 @@ private: | |||||||
|     bool first_frame = false; |     bool first_frame = false; | ||||||
|     InputCommon::TasInput::TasState last_tas_state; |     InputCommon::TasInput::TasState last_tas_state; | ||||||
| 
 | 
 | ||||||
|  |     std::unique_ptr<QCamera> camera; | ||||||
|  |     std::unique_ptr<QCameraImageCapture> camera_capture; | ||||||
|  |     std::unique_ptr<QTimer> camera_timer; | ||||||
|  | 
 | ||||||
|     Core::System& system; |     Core::System& system; | ||||||
| 
 | 
 | ||||||
| protected: | protected: | ||||||
|  | |||||||
| @ -368,6 +368,11 @@ void Config::ReadHidbusValues() { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void Config::ReadIrCameraValues() { | ||||||
|  |     ReadBasicSetting(Settings::values.enable_ir_sensor); | ||||||
|  |     ReadBasicSetting(Settings::values.ir_sensor_device); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void Config::ReadAudioValues() { | void Config::ReadAudioValues() { | ||||||
|     qt_config->beginGroup(QStringLiteral("Audio")); |     qt_config->beginGroup(QStringLiteral("Audio")); | ||||||
| 
 | 
 | ||||||
| @ -393,6 +398,7 @@ void Config::ReadControlValues() { | |||||||
|     ReadTouchscreenValues(); |     ReadTouchscreenValues(); | ||||||
|     ReadMotionTouchValues(); |     ReadMotionTouchValues(); | ||||||
|     ReadHidbusValues(); |     ReadHidbusValues(); | ||||||
|  |     ReadIrCameraValues(); | ||||||
| 
 | 
 | ||||||
| #ifdef _WIN32 | #ifdef _WIN32 | ||||||
|     ReadBasicSetting(Settings::values.enable_raw_input); |     ReadBasicSetting(Settings::values.enable_raw_input); | ||||||
| @ -1005,6 +1011,11 @@ void Config::SaveHidbusValues() { | |||||||
|                  QString::fromStdString(default_param)); |                  QString::fromStdString(default_param)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void Config::SaveIrCameraValues() { | ||||||
|  |     WriteBasicSetting(Settings::values.enable_ir_sensor); | ||||||
|  |     WriteBasicSetting(Settings::values.ir_sensor_device); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void Config::SaveValues() { | void Config::SaveValues() { | ||||||
|     if (global) { |     if (global) { | ||||||
|         SaveControlValues(); |         SaveControlValues(); | ||||||
| @ -1047,6 +1058,7 @@ void Config::SaveControlValues() { | |||||||
|     SaveTouchscreenValues(); |     SaveTouchscreenValues(); | ||||||
|     SaveMotionTouchValues(); |     SaveMotionTouchValues(); | ||||||
|     SaveHidbusValues(); |     SaveHidbusValues(); | ||||||
|  |     SaveIrCameraValues(); | ||||||
| 
 | 
 | ||||||
|     WriteGlobalSetting(Settings::values.use_docked_mode); |     WriteGlobalSetting(Settings::values.use_docked_mode); | ||||||
|     WriteGlobalSetting(Settings::values.vibration_enabled); |     WriteGlobalSetting(Settings::values.vibration_enabled); | ||||||
|  | |||||||
| @ -68,6 +68,7 @@ private: | |||||||
|     void ReadTouchscreenValues(); |     void ReadTouchscreenValues(); | ||||||
|     void ReadMotionTouchValues(); |     void ReadMotionTouchValues(); | ||||||
|     void ReadHidbusValues(); |     void ReadHidbusValues(); | ||||||
|  |     void ReadIrCameraValues(); | ||||||
| 
 | 
 | ||||||
|     // Read functions bases off the respective config section names.
 |     // Read functions bases off the respective config section names.
 | ||||||
|     void ReadAudioValues(); |     void ReadAudioValues(); | ||||||
| @ -96,6 +97,7 @@ private: | |||||||
|     void SaveTouchscreenValues(); |     void SaveTouchscreenValues(); | ||||||
|     void SaveMotionTouchValues(); |     void SaveMotionTouchValues(); | ||||||
|     void SaveHidbusValues(); |     void SaveHidbusValues(); | ||||||
|  |     void SaveIrCameraValues(); | ||||||
| 
 | 
 | ||||||
|     // Save functions based off the respective config section names.
 |     // Save functions based off the respective config section names.
 | ||||||
|     void SaveAudioValues(); |     void SaveAudioValues(); | ||||||
|  | |||||||
							
								
								
									
										126
									
								
								src/yuzu/configuration/configure_camera.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								src/yuzu/configuration/configure_camera.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,126 @@ | |||||||
|  | // Text : Copyright 2022 yuzu Emulator Project
 | ||||||
|  | // SPDX-License-Identifier: GPL-3.0-or-later
 | ||||||
|  | 
 | ||||||
|  | #include <memory> | ||||||
|  | #include <QCameraImageCapture> | ||||||
|  | #include <QCameraInfo> | ||||||
|  | #include <QStandardItemModel> | ||||||
|  | #include <QTimer> | ||||||
|  | 
 | ||||||
|  | #include "input_common/drivers/camera.h" | ||||||
|  | #include "input_common/main.h" | ||||||
|  | #include "ui_configure_camera.h" | ||||||
|  | #include "yuzu/configuration/config.h" | ||||||
|  | #include "yuzu/configuration/configure_camera.h" | ||||||
|  | 
 | ||||||
|  | ConfigureCamera::ConfigureCamera(QWidget* parent, InputCommon::InputSubsystem* input_subsystem_) | ||||||
|  |     : QDialog(parent), input_subsystem{input_subsystem_}, | ||||||
|  |       ui(std::make_unique<Ui::ConfigureCamera>()) { | ||||||
|  |     ui->setupUi(this); | ||||||
|  | 
 | ||||||
|  |     connect(ui->restore_defaults_button, &QPushButton::clicked, this, | ||||||
|  |             &ConfigureCamera::RestoreDefaults); | ||||||
|  |     connect(ui->preview_button, &QPushButton::clicked, this, &ConfigureCamera::PreviewCamera); | ||||||
|  | 
 | ||||||
|  |     auto blank_image = QImage(320, 240, QImage::Format::Format_RGB32); | ||||||
|  |     blank_image.fill(Qt::black); | ||||||
|  |     DisplayCapturedFrame(0, blank_image); | ||||||
|  | 
 | ||||||
|  |     LoadConfiguration(); | ||||||
|  |     resize(0, 0); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ConfigureCamera::~ConfigureCamera() = default; | ||||||
|  | 
 | ||||||
|  | void ConfigureCamera::PreviewCamera() { | ||||||
|  |     const auto index = ui->ir_sensor_combo_box->currentIndex(); | ||||||
|  |     bool camera_found = false; | ||||||
|  |     const QList<QCameraInfo> cameras = QCameraInfo::availableCameras(); | ||||||
|  |     for (const QCameraInfo& cameraInfo : cameras) { | ||||||
|  |         if (input_devices[index] == cameraInfo.deviceName().toStdString() || | ||||||
|  |             input_devices[index] == "Auto") { | ||||||
|  |             LOG_ERROR(Frontend, "Selected Camera {} {}", cameraInfo.description().toStdString(), | ||||||
|  |                       cameraInfo.deviceName().toStdString()); | ||||||
|  |             camera = std::make_unique<QCamera>(cameraInfo); | ||||||
|  |             camera_found = true; | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Clear previous frame
 | ||||||
|  |     auto blank_image = QImage(320, 240, QImage::Format::Format_RGB32); | ||||||
|  |     blank_image.fill(Qt::black); | ||||||
|  |     DisplayCapturedFrame(0, blank_image); | ||||||
|  | 
 | ||||||
|  |     if (!camera_found) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     camera_capture = std::make_unique<QCameraImageCapture>(camera.get()); | ||||||
|  |     connect(camera_capture.get(), &QCameraImageCapture::imageCaptured, this, | ||||||
|  |             &ConfigureCamera::DisplayCapturedFrame); | ||||||
|  |     camera->unload(); | ||||||
|  |     camera->setCaptureMode(QCamera::CaptureViewfinder); | ||||||
|  |     camera->load(); | ||||||
|  | 
 | ||||||
|  |     camera_timer = std::make_unique<QTimer>(); | ||||||
|  |     connect(camera_timer.get(), &QTimer::timeout, [this] { | ||||||
|  |         camera->stop(); | ||||||
|  |         camera->start(); | ||||||
|  | 
 | ||||||
|  |         camera_capture->capture(); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     camera_timer->start(250); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ConfigureCamera::DisplayCapturedFrame(int requestId, const QImage& img) { | ||||||
|  |     LOG_ERROR(Frontend, "ImageCaptured {} {}", img.width(), img.height()); | ||||||
|  |     const auto converted = img.scaled(320, 240, Qt::AspectRatioMode::IgnoreAspectRatio, | ||||||
|  |                                       Qt::TransformationMode::SmoothTransformation); | ||||||
|  |     ui->preview_box->setPixmap(QPixmap::fromImage(converted)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ConfigureCamera::changeEvent(QEvent* event) { | ||||||
|  |     if (event->type() == QEvent::LanguageChange) { | ||||||
|  |         RetranslateUI(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     QDialog::changeEvent(event); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ConfigureCamera::RetranslateUI() { | ||||||
|  |     ui->retranslateUi(this); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ConfigureCamera::ApplyConfiguration() { | ||||||
|  |     const auto index = ui->ir_sensor_combo_box->currentIndex(); | ||||||
|  |     Settings::values.ir_sensor_device.SetValue(input_devices[index]); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ConfigureCamera::LoadConfiguration() { | ||||||
|  |     input_devices.clear(); | ||||||
|  |     ui->ir_sensor_combo_box->clear(); | ||||||
|  |     input_devices.push_back("Auto"); | ||||||
|  |     ui->ir_sensor_combo_box->addItem(tr("Auto")); | ||||||
|  |     const auto cameras = QCameraInfo::availableCameras(); | ||||||
|  |     for (const QCameraInfo& cameraInfo : cameras) { | ||||||
|  |         input_devices.push_back(cameraInfo.deviceName().toStdString()); | ||||||
|  |         ui->ir_sensor_combo_box->addItem(cameraInfo.description()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     const auto current_device = Settings::values.ir_sensor_device.GetValue(); | ||||||
|  | 
 | ||||||
|  |     const auto devices_it = std::find_if( | ||||||
|  |         input_devices.begin(), input_devices.end(), | ||||||
|  |         [current_device](const std::string& device) { return device == current_device; }); | ||||||
|  |     const int device_index = | ||||||
|  |         devices_it != input_devices.end() | ||||||
|  |             ? static_cast<int>(std::distance(input_devices.begin(), devices_it)) | ||||||
|  |             : 0; | ||||||
|  |     ui->ir_sensor_combo_box->setCurrentIndex(device_index); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ConfigureCamera::RestoreDefaults() { | ||||||
|  |     ui->ir_sensor_combo_box->setCurrentIndex(0); | ||||||
|  | } | ||||||
							
								
								
									
										52
									
								
								src/yuzu/configuration/configure_camera.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								src/yuzu/configuration/configure_camera.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,52 @@ | |||||||
|  | // Text : Copyright 2022 yuzu Emulator Project
 | ||||||
|  | // SPDX-License-Identifier: GPL-3.0-or-later
 | ||||||
|  | 
 | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <memory> | ||||||
|  | #include <QDialog> | ||||||
|  | 
 | ||||||
|  | class QTimer; | ||||||
|  | class QCamera; | ||||||
|  | class QCameraImageCapture; | ||||||
|  | 
 | ||||||
|  | namespace InputCommon { | ||||||
|  | class InputSubsystem; | ||||||
|  | } // namespace InputCommon
 | ||||||
|  | 
 | ||||||
|  | namespace Ui { | ||||||
|  | class ConfigureCamera; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | class ConfigureCamera : public QDialog { | ||||||
|  |     Q_OBJECT | ||||||
|  | 
 | ||||||
|  | public: | ||||||
|  |     explicit ConfigureCamera(QWidget* parent, InputCommon::InputSubsystem* input_subsystem_); | ||||||
|  |     ~ConfigureCamera() override; | ||||||
|  | 
 | ||||||
|  |     void ApplyConfiguration(); | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     void changeEvent(QEvent* event) override; | ||||||
|  |     void RetranslateUI(); | ||||||
|  | 
 | ||||||
|  |     /// Load configuration settings.
 | ||||||
|  |     void LoadConfiguration(); | ||||||
|  | 
 | ||||||
|  |     /// Restore all buttons to their default values.
 | ||||||
|  |     void RestoreDefaults(); | ||||||
|  | 
 | ||||||
|  |     void DisplayCapturedFrame(int requestId, const QImage& img); | ||||||
|  | 
 | ||||||
|  |     /// Loads and signals the current selected camera to display a frame
 | ||||||
|  |     void PreviewCamera(); | ||||||
|  | 
 | ||||||
|  |     InputCommon::InputSubsystem* input_subsystem; | ||||||
|  | 
 | ||||||
|  |     std::unique_ptr<QCamera> camera; | ||||||
|  |     std::unique_ptr<QCameraImageCapture> camera_capture; | ||||||
|  |     std::unique_ptr<QTimer> camera_timer; | ||||||
|  |     std::vector<std::string> input_devices; | ||||||
|  |     std::unique_ptr<Ui::ConfigureCamera> ui; | ||||||
|  | }; | ||||||
							
								
								
									
										170
									
								
								src/yuzu/configuration/configure_camera.ui
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										170
									
								
								src/yuzu/configuration/configure_camera.ui
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,170 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <ui version="4.0"> | ||||||
|  |  <class>ConfigureCamera</class> | ||||||
|  |  <widget class="QDialog" name="ConfigureCamera"> | ||||||
|  |   <property name="geometry"> | ||||||
|  |    <rect> | ||||||
|  |     <x>0</x> | ||||||
|  |     <y>0</y> | ||||||
|  |     <width>298</width> | ||||||
|  |     <height>339</height> | ||||||
|  |    </rect> | ||||||
|  |   </property> | ||||||
|  |   <property name="windowTitle"> | ||||||
|  |    <string>Configure Infrared Camera</string> | ||||||
|  |   </property> | ||||||
|  |   <layout class="QVBoxLayout" name="verticalLayout"> | ||||||
|  |    <item> | ||||||
|  |     <widget class="QLabel" name="label_2"> | ||||||
|  |      <property name="minimumSize"> | ||||||
|  |       <size> | ||||||
|  |        <width>280</width> | ||||||
|  |        <height>0</height> | ||||||
|  |       </size> | ||||||
|  |      </property> | ||||||
|  |      <property name="text"> | ||||||
|  |       <string>Select where the image of the emulated camera comes from. It may be a virtual camera or a real camera.</string> | ||||||
|  |      </property> | ||||||
|  |      <property name="wordWrap"> | ||||||
|  |       <bool>true</bool> | ||||||
|  |      </property> | ||||||
|  |     </widget> | ||||||
|  |    </item> | ||||||
|  |    <item> | ||||||
|  |     <spacer name="verticalSpacer_2"> | ||||||
|  |      <property name="orientation"> | ||||||
|  |       <enum>Qt::Vertical</enum> | ||||||
|  |      </property> | ||||||
|  |      <property name="sizeType"> | ||||||
|  |       <enum>QSizePolicy::Fixed</enum> | ||||||
|  |      </property> | ||||||
|  |      <property name="sizeHint" stdset="0"> | ||||||
|  |       <size> | ||||||
|  |        <width>20</width> | ||||||
|  |        <height>20</height> | ||||||
|  |       </size> | ||||||
|  |      </property> | ||||||
|  |     </spacer> | ||||||
|  |    </item> | ||||||
|  |    <item> | ||||||
|  |     <widget class="QGroupBox" name="gridGroupBox"> | ||||||
|  |      <property name="title"> | ||||||
|  |       <string>Camera Image Source:</string> | ||||||
|  |      </property> | ||||||
|  |      <layout class="QGridLayout" name="gridLayout"> | ||||||
|  |       <item row="0" column="0"> | ||||||
|  |        <spacer name="horizontalSpacer"> | ||||||
|  |         <property name="orientation"> | ||||||
|  |          <enum>Qt::Horizontal</enum> | ||||||
|  |         </property> | ||||||
|  |         <property name="sizeHint" stdset="0"> | ||||||
|  |          <size> | ||||||
|  |           <width>40</width> | ||||||
|  |           <height>20</height> | ||||||
|  |          </size> | ||||||
|  |         </property> | ||||||
|  |        </spacer> | ||||||
|  |       </item> | ||||||
|  |        <item row="0" column="1"> | ||||||
|  |          <widget class="QLabel" name="label_3"> | ||||||
|  |            <property name="text"> | ||||||
|  |              <string>Input device:</string> | ||||||
|  |            </property> | ||||||
|  |          </widget> | ||||||
|  |        </item> | ||||||
|  |        <item row="0" column="2"> | ||||||
|  |          <widget class="QComboBox" name="ir_sensor_combo_box"/> | ||||||
|  |        </item> | ||||||
|  |       <item row="0" column="3"> | ||||||
|  |        <spacer name="horizontalSpacer_2"> | ||||||
|  |         <property name="orientation"> | ||||||
|  |          <enum>Qt::Horizontal</enum> | ||||||
|  |         </property> | ||||||
|  |         <property name="sizeHint" stdset="0"> | ||||||
|  |          <size> | ||||||
|  |           <width>40</width> | ||||||
|  |           <height>20</height> | ||||||
|  |          </size> | ||||||
|  |         </property> | ||||||
|  |        </spacer> | ||||||
|  |       </item> | ||||||
|  |      </layout> | ||||||
|  |     </widget> | ||||||
|  |    </item><item> | ||||||
|  |     <widget class="QGroupBox" name="previewBox"> | ||||||
|  |      <property name="title"> | ||||||
|  |       <string>Preview</string> | ||||||
|  |      </property> | ||||||
|  |      <layout class="QVBoxLayout" name="verticalLayout_3"> | ||||||
|  |       <item> | ||||||
|  |        <widget class="QLabel" name="preview_box"> | ||||||
|  |          <property name="minimumSize"> | ||||||
|  |            <size> | ||||||
|  |              <width>320</width> | ||||||
|  |              <height>240</height> | ||||||
|  |            </size> | ||||||
|  |          </property> | ||||||
|  |         <property name="toolTip"> | ||||||
|  |          <string>Resolution: 320*240</string> | ||||||
|  |         </property> | ||||||
|  |        </widget> | ||||||
|  |       </item> | ||||||
|  |       <item> | ||||||
|  |        <widget class="QPushButton" name="preview_button"> | ||||||
|  |         <property name="text"> | ||||||
|  |          <string>Click to preview</string> | ||||||
|  |         </property> | ||||||
|  |        </widget> | ||||||
|  |       </item> | ||||||
|  |      </layout> | ||||||
|  |     </widget> | ||||||
|  |    </item> | ||||||
|  |    <item> | ||||||
|  |     <spacer name="verticalSpacer"> | ||||||
|  |      <property name="orientation"> | ||||||
|  |       <enum>Qt::Vertical</enum> | ||||||
|  |      </property> | ||||||
|  |      <property name="sizeHint" stdset="0"> | ||||||
|  |       <size> | ||||||
|  |        <width>20</width> | ||||||
|  |        <height>40</height> | ||||||
|  |       </size> | ||||||
|  |      </property> | ||||||
|  |     </spacer> | ||||||
|  |    </item> | ||||||
|  |    <item> | ||||||
|  |     <layout class="QHBoxLayout" name="horizontalLayout"> | ||||||
|  |      <item> | ||||||
|  |       <widget class="QPushButton" name="restore_defaults_button"> | ||||||
|  |        <property name="text"> | ||||||
|  |         <string>Restore Defaults</string> | ||||||
|  |        </property> | ||||||
|  |       </widget> | ||||||
|  |      </item> | ||||||
|  |      <item> | ||||||
|  |       <widget class="QDialogButtonBox" name="buttonBox"> | ||||||
|  |        <property name="standardButtons"> | ||||||
|  |         <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> | ||||||
|  |        </property> | ||||||
|  |       </widget> | ||||||
|  |      </item> | ||||||
|  |     </layout> | ||||||
|  |    </item> | ||||||
|  |   </layout> | ||||||
|  |  </widget> | ||||||
|  |  <resources/> | ||||||
|  |  <connections> | ||||||
|  |   <connection> | ||||||
|  |    <sender>buttonBox</sender> | ||||||
|  |    <signal>accepted()</signal> | ||||||
|  |    <receiver>ConfigureCamera</receiver> | ||||||
|  |    <slot>accept()</slot> | ||||||
|  |   </connection> | ||||||
|  |   <connection> | ||||||
|  |    <sender>buttonBox</sender> | ||||||
|  |    <signal>rejected()</signal> | ||||||
|  |    <receiver>ConfigureCamera</receiver> | ||||||
|  |    <slot>reject()</slot> | ||||||
|  |    </connection> | ||||||
|  |  </connections> | ||||||
|  | </ui> | ||||||
| @ -15,6 +15,7 @@ | |||||||
| #include "ui_configure_input.h" | #include "ui_configure_input.h" | ||||||
| #include "ui_configure_input_advanced.h" | #include "ui_configure_input_advanced.h" | ||||||
| #include "ui_configure_input_player.h" | #include "ui_configure_input_player.h" | ||||||
|  | #include "yuzu/configuration/configure_camera.h" | ||||||
| #include "yuzu/configuration/configure_debug_controller.h" | #include "yuzu/configuration/configure_debug_controller.h" | ||||||
| #include "yuzu/configuration/configure_input.h" | #include "yuzu/configuration/configure_input.h" | ||||||
| #include "yuzu/configuration/configure_input_advanced.h" | #include "yuzu/configuration/configure_input_advanced.h" | ||||||
| @ -163,6 +164,10 @@ void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem, | |||||||
|             [this, input_subsystem, &hid_core] { |             [this, input_subsystem, &hid_core] { | ||||||
|                 CallConfigureDialog<ConfigureRingController>(*this, input_subsystem, hid_core); |                 CallConfigureDialog<ConfigureRingController>(*this, input_subsystem, hid_core); | ||||||
|             }); |             }); | ||||||
|  |     connect(advanced, &ConfigureInputAdvanced::CallCameraDialog, | ||||||
|  |             [this, input_subsystem, &hid_core] { | ||||||
|  |                 CallConfigureDialog<ConfigureCamera>(*this, input_subsystem); | ||||||
|  |             }); | ||||||
| 
 | 
 | ||||||
|     connect(ui->vibrationButton, &QPushButton::clicked, |     connect(ui->vibrationButton, &QPushButton::clicked, | ||||||
|             [this, &hid_core] { CallConfigureDialog<ConfigureVibration>(*this, hid_core); }); |             [this, &hid_core] { CallConfigureDialog<ConfigureVibration>(*this, hid_core); }); | ||||||
|  | |||||||
| @ -89,6 +89,7 @@ ConfigureInputAdvanced::ConfigureInputAdvanced(QWidget* parent) | |||||||
|             [this] { CallMotionTouchConfigDialog(); }); |             [this] { CallMotionTouchConfigDialog(); }); | ||||||
|     connect(ui->ring_controller_configure, &QPushButton::clicked, this, |     connect(ui->ring_controller_configure, &QPushButton::clicked, this, | ||||||
|             [this] { CallRingControllerDialog(); }); |             [this] { CallRingControllerDialog(); }); | ||||||
|  |     connect(ui->camera_configure, &QPushButton::clicked, this, [this] { CallCameraDialog(); }); | ||||||
| 
 | 
 | ||||||
| #ifndef _WIN32 | #ifndef _WIN32 | ||||||
|     ui->enable_raw_input->setVisible(false); |     ui->enable_raw_input->setVisible(false); | ||||||
| @ -136,6 +137,7 @@ void ConfigureInputAdvanced::ApplyConfiguration() { | |||||||
|     Settings::values.enable_udp_controller = ui->enable_udp_controller->isChecked(); |     Settings::values.enable_udp_controller = ui->enable_udp_controller->isChecked(); | ||||||
|     Settings::values.controller_navigation = ui->controller_navigation->isChecked(); |     Settings::values.controller_navigation = ui->controller_navigation->isChecked(); | ||||||
|     Settings::values.enable_ring_controller = ui->enable_ring_controller->isChecked(); |     Settings::values.enable_ring_controller = ui->enable_ring_controller->isChecked(); | ||||||
|  |     Settings::values.enable_ir_sensor = ui->enable_ir_sensor->isChecked(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ConfigureInputAdvanced::LoadConfiguration() { | void ConfigureInputAdvanced::LoadConfiguration() { | ||||||
| @ -169,6 +171,7 @@ void ConfigureInputAdvanced::LoadConfiguration() { | |||||||
|     ui->enable_udp_controller->setChecked(Settings::values.enable_udp_controller.GetValue()); |     ui->enable_udp_controller->setChecked(Settings::values.enable_udp_controller.GetValue()); | ||||||
|     ui->controller_navigation->setChecked(Settings::values.controller_navigation.GetValue()); |     ui->controller_navigation->setChecked(Settings::values.controller_navigation.GetValue()); | ||||||
|     ui->enable_ring_controller->setChecked(Settings::values.enable_ring_controller.GetValue()); |     ui->enable_ring_controller->setChecked(Settings::values.enable_ring_controller.GetValue()); | ||||||
|  |     ui->enable_ir_sensor->setChecked(Settings::values.enable_ir_sensor.GetValue()); | ||||||
| 
 | 
 | ||||||
|     UpdateUIEnabled(); |     UpdateUIEnabled(); | ||||||
| } | } | ||||||
|  | |||||||
| @ -29,6 +29,7 @@ signals: | |||||||
|     void CallTouchscreenConfigDialog(); |     void CallTouchscreenConfigDialog(); | ||||||
|     void CallMotionTouchConfigDialog(); |     void CallMotionTouchConfigDialog(); | ||||||
|     void CallRingControllerDialog(); |     void CallRingControllerDialog(); | ||||||
|  |     void CallCameraDialog(); | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     void changeEvent(QEvent* event) override; |     void changeEvent(QEvent* event) override; | ||||||
|  | |||||||
| @ -2617,6 +2617,20 @@ | |||||||
|                  </property> |                  </property> | ||||||
|                 </widget> |                 </widget> | ||||||
|                </item> |                </item> | ||||||
|  |                <item row="5" column="0"> | ||||||
|  |                 <widget class="QCheckBox" name="enable_ir_sensor"> | ||||||
|  |                  <property name="text"> | ||||||
|  |                   <string>Infrared Camera</string> | ||||||
|  |                  </property> | ||||||
|  |                 </widget> | ||||||
|  |                </item> | ||||||
|  |                <item row="5" column="2"> | ||||||
|  |                 <widget class="QPushButton" name="camera_configure"> | ||||||
|  |                  <property name="text"> | ||||||
|  |                   <string>Configure</string> | ||||||
|  |                  </property> | ||||||
|  |                 </widget> | ||||||
|  |                </item> | ||||||
|               </layout> |               </layout> | ||||||
|              </widget> |              </widget> | ||||||
|             </item> |             </item> | ||||||
|  | |||||||
| @ -1542,6 +1542,8 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t | |||||||
|         mouse_hide_timer.start(); |         mouse_hide_timer.start(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     render_window->InitializeCamera(); | ||||||
|  | 
 | ||||||
|     std::string title_name; |     std::string title_name; | ||||||
|     std::string title_version; |     std::string title_version; | ||||||
|     const auto res = system->GetGameName(title_name); |     const auto res = system->GetGameName(title_name); | ||||||
| @ -1623,6 +1625,7 @@ void GMainWindow::ShutdownGame() { | |||||||
|     tas_label->clear(); |     tas_label->clear(); | ||||||
|     input_subsystem->GetTas()->Stop(); |     input_subsystem->GetTas()->Stop(); | ||||||
|     OnTasStateChanged(); |     OnTasStateChanged(); | ||||||
|  |     render_window->FinalizeCamera(); | ||||||
| 
 | 
 | ||||||
|     // Enable all controllers
 |     // Enable all controllers
 | ||||||
|     system->HIDCore().SetSupportedStyleTag({Core::HID::NpadStyleSet::All}); |     system->HIDCore().SetSupportedStyleTag({Core::HID::NpadStyleSet::All}); | ||||||
| @ -2862,6 +2865,12 @@ void GMainWindow::OnConfigure() { | |||||||
|         mouse_hide_timer.start(); |         mouse_hide_timer.start(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     // Restart camera config
 | ||||||
|  |     if (emulation_running) { | ||||||
|  |         render_window->FinalizeCamera(); | ||||||
|  |         render_window->InitializeCamera(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     if (!UISettings::values.has_broken_vulkan) { |     if (!UISettings::values.has_broken_vulkan) { | ||||||
|         renderer_status_button->setEnabled(!emulation_running); |         renderer_status_button->setEnabled(!emulation_running); | ||||||
|     } |     } | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user