diff options
Diffstat (limited to 'src/yuzu/configuration')
| -rw-r--r-- | src/yuzu/configuration/config.cpp | 36 | ||||
| -rw-r--r-- | src/yuzu/configuration/config.h | 18 | ||||
| -rw-r--r-- | src/yuzu/configuration/configuration_shared.h | 10 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_audio.cpp | 95 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_audio.h | 4 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_audio.ui | 28 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_camera.cpp | 138 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_camera.h | 54 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_camera.ui | 170 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_debug.cpp | 2 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_debug.ui | 11 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_general.cpp | 24 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_general.ui | 81 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_input.cpp | 5 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_input.ui | 2 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_input_advanced.cpp | 3 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_input_advanced.h | 1 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_input_advanced.ui | 14 | 
18 files changed, 520 insertions, 176 deletions
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 9686412d0..1f76e86b9 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -143,8 +143,8 @@ void Config::ReadBasicSetting(Settings::Setting<std::string>& setting) {      }  } -template <typename Type> -void Config::ReadBasicSetting(Settings::Setting<Type>& setting) { +template <typename Type, bool ranged> +void Config::ReadBasicSetting(Settings::Setting<Type, ranged>& setting) {      const QString name = QString::fromStdString(setting.GetLabel());      const Type default_value = setting.GetDefault();      if (qt_config->value(name + QStringLiteral("/default"), false).toBool()) { @@ -164,16 +164,16 @@ void Config::WriteBasicSetting(const Settings::Setting<std::string>& setting) {      qt_config->setValue(name, QString::fromStdString(value));  } -template <typename Type> -void Config::WriteBasicSetting(const Settings::Setting<Type>& setting) { +template <typename Type, bool ranged> +void Config::WriteBasicSetting(const Settings::Setting<Type, ranged>& setting) {      const QString name = QString::fromStdString(setting.GetLabel());      const Type value = setting.GetValue();      qt_config->setValue(name + QStringLiteral("/default"), value == setting.GetDefault());      qt_config->setValue(name, value);  } -template <typename Type> -void Config::WriteGlobalSetting(const Settings::SwitchableSetting<Type>& setting) { +template <typename Type, bool ranged> +void Config::WriteGlobalSetting(const Settings::SwitchableSetting<Type, ranged>& setting) {      const QString name = QString::fromStdString(setting.GetLabel());      const Type& value = setting.GetValue(global);      if (!global) { @@ -368,12 +368,18 @@ void Config::ReadHidbusValues() {      }  } +void Config::ReadIrCameraValues() { +    ReadBasicSetting(Settings::values.enable_ir_sensor); +    ReadBasicSetting(Settings::values.ir_sensor_device); +} +  void Config::ReadAudioValues() {      qt_config->beginGroup(QStringLiteral("Audio"));      if (global) { -        ReadBasicSetting(Settings::values.audio_device_id);          ReadBasicSetting(Settings::values.sink_id); +        ReadBasicSetting(Settings::values.audio_output_device_id); +        ReadBasicSetting(Settings::values.audio_input_device_id);      }      ReadGlobalSetting(Settings::values.volume); @@ -392,6 +398,7 @@ void Config::ReadControlValues() {      ReadTouchscreenValues();      ReadMotionTouchValues();      ReadHidbusValues(); +    ReadIrCameraValues();  #ifdef _WIN32      ReadBasicSetting(Settings::values.enable_raw_input); @@ -668,7 +675,6 @@ void Config::ReadRendererValues() {      ReadGlobalSetting(Settings::values.max_anisotropy);      ReadGlobalSetting(Settings::values.use_speed_limit);      ReadGlobalSetting(Settings::values.speed_limit); -    ReadGlobalSetting(Settings::values.fps_cap);      ReadGlobalSetting(Settings::values.use_disk_shader_cache);      ReadGlobalSetting(Settings::values.gpu_accuracy);      ReadGlobalSetting(Settings::values.use_asynchronous_gpu_emulation); @@ -1005,6 +1011,11 @@ void Config::SaveHidbusValues() {                   QString::fromStdString(default_param));  } +void Config::SaveIrCameraValues() { +    WriteBasicSetting(Settings::values.enable_ir_sensor); +    WriteBasicSetting(Settings::values.ir_sensor_device); +} +  void Config::SaveValues() {      if (global) {          SaveControlValues(); @@ -1028,7 +1039,8 @@ void Config::SaveAudioValues() {      if (global) {          WriteBasicSetting(Settings::values.sink_id); -        WriteBasicSetting(Settings::values.audio_device_id); +        WriteBasicSetting(Settings::values.audio_output_device_id); +        WriteBasicSetting(Settings::values.audio_input_device_id);      }      WriteGlobalSetting(Settings::values.volume); @@ -1046,6 +1058,7 @@ void Config::SaveControlValues() {      SaveTouchscreenValues();      SaveMotionTouchValues();      SaveHidbusValues(); +    SaveIrCameraValues();      WriteGlobalSetting(Settings::values.use_docked_mode);      WriteGlobalSetting(Settings::values.vibration_enabled); @@ -1237,7 +1250,6 @@ void Config::SaveRendererValues() {      WriteGlobalSetting(Settings::values.max_anisotropy);      WriteGlobalSetting(Settings::values.use_speed_limit);      WriteGlobalSetting(Settings::values.speed_limit); -    WriteGlobalSetting(Settings::values.fps_cap);      WriteGlobalSetting(Settings::values.use_disk_shader_cache);      WriteSetting(QString::fromStdString(Settings::values.gpu_accuracy.GetLabel()),                   static_cast<u32>(Settings::values.gpu_accuracy.GetValue(global)), @@ -1421,8 +1433,8 @@ QVariant Config::ReadSetting(const QString& name, const QVariant& default_value)      return result;  } -template <typename Type> -void Config::ReadGlobalSetting(Settings::SwitchableSetting<Type>& setting) { +template <typename Type, bool ranged> +void Config::ReadGlobalSetting(Settings::SwitchableSetting<Type, ranged>& setting) {      QString name = QString::fromStdString(setting.GetLabel());      const bool use_global = qt_config->value(name + QStringLiteral("/use_global"), true).toBool();      setting.SetGlobal(use_global); diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h index 9ca878d23..a71eabe8e 100644 --- a/src/yuzu/configuration/config.h +++ b/src/yuzu/configuration/config.h @@ -68,6 +68,7 @@ private:      void ReadTouchscreenValues();      void ReadMotionTouchValues();      void ReadHidbusValues(); +    void ReadIrCameraValues();      // Read functions bases off the respective config section names.      void ReadAudioValues(); @@ -96,6 +97,7 @@ private:      void SaveTouchscreenValues();      void SaveMotionTouchValues();      void SaveHidbusValues(); +    void SaveIrCameraValues();      // Save functions based off the respective config section names.      void SaveAudioValues(); @@ -159,8 +161,8 @@ private:       *       * @param The setting       */ -    template <typename Type> -    void ReadGlobalSetting(Settings::SwitchableSetting<Type>& setting); +    template <typename Type, bool ranged> +    void ReadGlobalSetting(Settings::SwitchableSetting<Type, ranged>& setting);      /**       * Sets a value to the qt_config using the setting's label and default value. If the config is a @@ -168,8 +170,8 @@ private:       *       * @param The setting       */ -    template <typename Type> -    void WriteGlobalSetting(const Settings::SwitchableSetting<Type>& setting); +    template <typename Type, bool ranged> +    void WriteGlobalSetting(const Settings::SwitchableSetting<Type, ranged>& setting);      /**       * Reads a value from the qt_config using the setting's label and default value and applies the @@ -177,15 +179,15 @@ private:       *       * @param The setting       */ -    template <typename Type> -    void ReadBasicSetting(Settings::Setting<Type>& setting); +    template <typename Type, bool ranged> +    void ReadBasicSetting(Settings::Setting<Type, ranged>& setting);      /** Sets a value from the setting in the qt_config using the setting's label and default value.       *       * @param The setting       */ -    template <typename Type> -    void WriteBasicSetting(const Settings::Setting<Type>& setting); +    template <typename Type, bool ranged> +    void WriteBasicSetting(const Settings::Setting<Type, ranged>& setting);      ConfigType type;      std::unique_ptr<QSettings> qt_config; diff --git a/src/yuzu/configuration/configuration_shared.h b/src/yuzu/configuration/configuration_shared.h index 77802a367..56800b6ff 100644 --- a/src/yuzu/configuration/configuration_shared.h +++ b/src/yuzu/configuration/configuration_shared.h @@ -27,8 +27,9 @@ enum class CheckState {  // ApplyPerGameSetting, given a Settings::Setting and a Qt UI element, properly applies a Setting  void ApplyPerGameSetting(Settings::SwitchableSetting<bool>* setting, const QCheckBox* checkbox,                           const CheckState& tracker); -template <typename Type> -void ApplyPerGameSetting(Settings::SwitchableSetting<Type>* setting, const QComboBox* combobox) { +template <typename Type, bool ranged> +void ApplyPerGameSetting(Settings::SwitchableSetting<Type, ranged>* setting, +                         const QComboBox* combobox) {      if (Settings::IsConfiguringGlobal() && setting->UsingGlobal()) {          setting->SetValue(static_cast<Type>(combobox->currentIndex()));      } else if (!Settings::IsConfiguringGlobal()) { @@ -45,8 +46,9 @@ void ApplyPerGameSetting(Settings::SwitchableSetting<Type>* setting, const QComb  // Sets a Qt UI element given a Settings::Setting  void SetPerGameSetting(QCheckBox* checkbox, const Settings::SwitchableSetting<bool>* setting); -template <typename Type> -void SetPerGameSetting(QComboBox* combobox, const Settings::SwitchableSetting<Type>* setting) { +template <typename Type, bool ranged> +void SetPerGameSetting(QComboBox* combobox, +                       const Settings::SwitchableSetting<Type, ranged>* setting) {      combobox->setCurrentIndex(setting->UsingGlobal() ? ConfigurationShared::USE_GLOBAL_INDEX                                                       : static_cast<int>(setting->GetValue()) +                                                             ConfigurationShared::USE_GLOBAL_OFFSET); diff --git a/src/yuzu/configuration/configure_audio.cpp b/src/yuzu/configuration/configure_audio.cpp index 512bdfc22..19b8b15ef 100644 --- a/src/yuzu/configuration/configure_audio.cpp +++ b/src/yuzu/configuration/configure_audio.cpp @@ -3,8 +3,8 @@  #include <memory> -#include "audio_core/sink.h" -#include "audio_core/sink_details.h" +#include "audio_core/sink/sink.h" +#include "audio_core/sink/sink_details.h"  #include "common/settings.h"  #include "core/core.h"  #include "ui_configure_audio.h" @@ -15,11 +15,11 @@ ConfigureAudio::ConfigureAudio(const Core::System& system_, QWidget* parent)      : QWidget(parent), ui(std::make_unique<Ui::ConfigureAudio>()), system{system_} {      ui->setupUi(this); -    InitializeAudioOutputSinkComboBox(); +    InitializeAudioSinkComboBox();      connect(ui->volume_slider, &QSlider::valueChanged, this,              &ConfigureAudio::SetVolumeIndicatorText); -    connect(ui->output_sink_combo_box, qOverload<int>(&QComboBox::currentIndexChanged), this, +    connect(ui->sink_combo_box, qOverload<int>(&QComboBox::currentIndexChanged), this,              &ConfigureAudio::UpdateAudioDevices);      ui->volume_label->setVisible(Settings::IsConfiguringGlobal()); @@ -30,8 +30,9 @@ ConfigureAudio::ConfigureAudio(const Core::System& system_, QWidget* parent)      SetConfiguration();      const bool is_powered_on = system_.IsPoweredOn(); -    ui->output_sink_combo_box->setEnabled(!is_powered_on); -    ui->audio_device_combo_box->setEnabled(!is_powered_on); +    ui->sink_combo_box->setEnabled(!is_powered_on); +    ui->output_combo_box->setEnabled(!is_powered_on); +    ui->input_combo_box->setEnabled(!is_powered_on);  }  ConfigureAudio::~ConfigureAudio() = default; @@ -40,9 +41,9 @@ void ConfigureAudio::SetConfiguration() {      SetOutputSinkFromSinkID();      // The device list cannot be pre-populated (nor listed) until the output sink is known. -    UpdateAudioDevices(ui->output_sink_combo_box->currentIndex()); +    UpdateAudioDevices(ui->sink_combo_box->currentIndex()); -    SetAudioDeviceFromDeviceID(); +    SetAudioDevicesFromDeviceID();      const auto volume_value = static_cast<int>(Settings::values.volume.GetValue());      ui->volume_slider->setValue(volume_value); @@ -62,32 +63,45 @@ void ConfigureAudio::SetConfiguration() {  }  void ConfigureAudio::SetOutputSinkFromSinkID() { -    [[maybe_unused]] const QSignalBlocker blocker(ui->output_sink_combo_box); +    [[maybe_unused]] const QSignalBlocker blocker(ui->sink_combo_box);      int new_sink_index = 0;      const QString sink_id = QString::fromStdString(Settings::values.sink_id.GetValue()); -    for (int index = 0; index < ui->output_sink_combo_box->count(); index++) { -        if (ui->output_sink_combo_box->itemText(index) == sink_id) { +    for (int index = 0; index < ui->sink_combo_box->count(); index++) { +        if (ui->sink_combo_box->itemText(index) == sink_id) {              new_sink_index = index;              break;          }      } -    ui->output_sink_combo_box->setCurrentIndex(new_sink_index); +    ui->sink_combo_box->setCurrentIndex(new_sink_index);  } -void ConfigureAudio::SetAudioDeviceFromDeviceID() { +void ConfigureAudio::SetAudioDevicesFromDeviceID() {      int new_device_index = -1; -    const QString device_id = QString::fromStdString(Settings::values.audio_device_id.GetValue()); -    for (int index = 0; index < ui->audio_device_combo_box->count(); index++) { -        if (ui->audio_device_combo_box->itemText(index) == device_id) { +    const QString output_device_id = +        QString::fromStdString(Settings::values.audio_output_device_id.GetValue()); +    for (int index = 0; index < ui->output_combo_box->count(); index++) { +        if (ui->output_combo_box->itemText(index) == output_device_id) {              new_device_index = index;              break;          }      } -    ui->audio_device_combo_box->setCurrentIndex(new_device_index); +    ui->output_combo_box->setCurrentIndex(new_device_index); + +    new_device_index = -1; +    const QString input_device_id = +        QString::fromStdString(Settings::values.audio_input_device_id.GetValue()); +    for (int index = 0; index < ui->input_combo_box->count(); index++) { +        if (ui->input_combo_box->itemText(index) == input_device_id) { +            new_device_index = index; +            break; +        } +    } + +    ui->input_combo_box->setCurrentIndex(new_device_index);  }  void ConfigureAudio::SetVolumeIndicatorText(int percentage) { @@ -95,14 +109,13 @@ void ConfigureAudio::SetVolumeIndicatorText(int percentage) {  }  void ConfigureAudio::ApplyConfiguration() { -      if (Settings::IsConfiguringGlobal()) {          Settings::values.sink_id = -            ui->output_sink_combo_box->itemText(ui->output_sink_combo_box->currentIndex()) -                .toStdString(); -        Settings::values.audio_device_id.SetValue( -            ui->audio_device_combo_box->itemText(ui->audio_device_combo_box->currentIndex()) -                .toStdString()); +            ui->sink_combo_box->itemText(ui->sink_combo_box->currentIndex()).toStdString(); +        Settings::values.audio_output_device_id.SetValue( +            ui->output_combo_box->itemText(ui->output_combo_box->currentIndex()).toStdString()); +        Settings::values.audio_input_device_id.SetValue( +            ui->input_combo_box->itemText(ui->input_combo_box->currentIndex()).toStdString());          // Guard if during game and set to game-specific value          if (Settings::values.volume.UsingGlobal()) { @@ -129,21 +142,27 @@ void ConfigureAudio::changeEvent(QEvent* event) {  }  void ConfigureAudio::UpdateAudioDevices(int sink_index) { -    ui->audio_device_combo_box->clear(); -    ui->audio_device_combo_box->addItem(QString::fromUtf8(AudioCore::auto_device_name)); +    ui->output_combo_box->clear(); +    ui->output_combo_box->addItem(QString::fromUtf8(AudioCore::Sink::auto_device_name)); + +    const std::string sink_id = ui->sink_combo_box->itemText(sink_index).toStdString(); +    for (const auto& device : AudioCore::Sink::GetDeviceListForSink(sink_id, false)) { +        ui->output_combo_box->addItem(QString::fromStdString(device)); +    } -    const std::string sink_id = ui->output_sink_combo_box->itemText(sink_index).toStdString(); -    for (const auto& device : AudioCore::GetDeviceListForSink(sink_id)) { -        ui->audio_device_combo_box->addItem(QString::fromStdString(device)); +    ui->input_combo_box->clear(); +    ui->input_combo_box->addItem(QString::fromUtf8(AudioCore::Sink::auto_device_name)); +    for (const auto& device : AudioCore::Sink::GetDeviceListForSink(sink_id, true)) { +        ui->input_combo_box->addItem(QString::fromStdString(device));      }  } -void ConfigureAudio::InitializeAudioOutputSinkComboBox() { -    ui->output_sink_combo_box->clear(); -    ui->output_sink_combo_box->addItem(QString::fromUtf8(AudioCore::auto_device_name)); +void ConfigureAudio::InitializeAudioSinkComboBox() { +    ui->sink_combo_box->clear(); +    ui->sink_combo_box->addItem(QString::fromUtf8(AudioCore::Sink::auto_device_name)); -    for (const char* id : AudioCore::GetSinkIDs()) { -        ui->output_sink_combo_box->addItem(QString::fromUtf8(id)); +    for (const char* id : AudioCore::Sink::GetSinkIDs()) { +        ui->sink_combo_box->addItem(QString::fromUtf8(id));      }  } @@ -164,8 +183,10 @@ void ConfigureAudio::SetupPerGameUI() {          ConfigurationShared::SetHighlight(ui->volume_layout, index == 1);      }); -    ui->output_sink_combo_box->setVisible(false); -    ui->output_sink_label->setVisible(false); -    ui->audio_device_combo_box->setVisible(false); -    ui->audio_device_label->setVisible(false); +    ui->sink_combo_box->setVisible(false); +    ui->sink_label->setVisible(false); +    ui->output_combo_box->setVisible(false); +    ui->output_label->setVisible(false); +    ui->input_combo_box->setVisible(false); +    ui->input_label->setVisible(false);  } diff --git a/src/yuzu/configuration/configure_audio.h b/src/yuzu/configuration/configure_audio.h index 08c278eeb..0d03aae1d 100644 --- a/src/yuzu/configuration/configure_audio.h +++ b/src/yuzu/configuration/configure_audio.h @@ -31,14 +31,14 @@ public:  private:      void changeEvent(QEvent* event) override; -    void InitializeAudioOutputSinkComboBox(); +    void InitializeAudioSinkComboBox();      void RetranslateUI();      void UpdateAudioDevices(int sink_index);      void SetOutputSinkFromSinkID(); -    void SetAudioDeviceFromDeviceID(); +    void SetAudioDevicesFromDeviceID();      void SetVolumeIndicatorText(int percentage);      void SetupPerGameUI(); diff --git a/src/yuzu/configuration/configure_audio.ui b/src/yuzu/configuration/configure_audio.ui index d1ac8ad02..a5bcee415 100644 --- a/src/yuzu/configuration/configure_audio.ui +++ b/src/yuzu/configuration/configure_audio.ui @@ -21,30 +21,44 @@       </property>       <layout class="QVBoxLayout">        <item> -       <layout class="QHBoxLayout" name="_3"> +       <layout class="QHBoxLayout" name="engine_layout">          <item> -         <widget class="QLabel" name="output_sink_label"> +         <widget class="QLabel" name="sink_label">            <property name="text">             <string>Output Engine:</string>            </property>           </widget>          </item>          <item> -         <widget class="QComboBox" name="output_sink_combo_box"/> +         <widget class="QComboBox" name="sink_combo_box"/>          </item>         </layout>        </item>        <item> -       <layout class="QHBoxLayout" name="_2"> +       <layout class="QHBoxLayout" name="output_layout">          <item> -         <widget class="QLabel" name="audio_device_label"> +         <widget class="QLabel" name="output_label">            <property name="text"> -           <string>Audio Device:</string> +           <string>Output Device</string>            </property>           </widget>          </item>          <item> -         <widget class="QComboBox" name="audio_device_combo_box"/> +         <widget class="QComboBox" name="output_combo_box"/> +        </item> +       </layout> +      </item> +      <item> +       <layout class="QHBoxLayout" name="input_layout"> +        <item> +         <widget class="QLabel" name="input_label"> +          <property name="text"> +           <string>Input Device</string> +          </property> +         </widget> +        </item> +        <item> +         <widget class="QComboBox" name="input_combo_box"/>          </item>         </layout>        </item> diff --git a/src/yuzu/configuration/configure_camera.cpp b/src/yuzu/configuration/configure_camera.cpp new file mode 100644 index 000000000..73cdcf3f2 --- /dev/null +++ b/src/yuzu/configuration/configure_camera.cpp @@ -0,0 +1,138 @@ +// 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_INFO(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->start(); + +    pending_snapshots = 0; +    is_virtual_camera = false; + +    camera_timer = std::make_unique<QTimer>(); +    connect(camera_timer.get(), &QTimer::timeout, [this] { +        // If the camera doesn't capture, test for virtual cameras +        if (pending_snapshots > 5) { +            is_virtual_camera = true; +        } +        // Virtual cameras like obs need to reset the camera every capture +        if (is_virtual_camera) { +            camera->stop(); +            camera->start(); +        } +        pending_snapshots++; +        camera_capture->capture(); +    }); + +    camera_timer->start(250); +} + +void ConfigureCamera::DisplayCapturedFrame(int requestId, const QImage& img) { +    LOG_INFO(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)); +    pending_snapshots = 0; +} + +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); +} diff --git a/src/yuzu/configuration/configure_camera.h b/src/yuzu/configuration/configure_camera.h new file mode 100644 index 000000000..db9833b5c --- /dev/null +++ b/src/yuzu/configuration/configure_camera.h @@ -0,0 +1,54 @@ +// 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; + +    bool is_virtual_camera; +    int pending_snapshots; +    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; +}; 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 @@ +<?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> diff --git a/src/yuzu/configuration/configure_debug.cpp b/src/yuzu/configuration/configure_debug.cpp index 343d2aee1..84808f678 100644 --- a/src/yuzu/configuration/configure_debug.cpp +++ b/src/yuzu/configuration/configure_debug.cpp @@ -44,6 +44,7 @@ void ConfigureDebug::SetConfiguration() {      ui->fs_access_log->setEnabled(runtime_lock);      ui->fs_access_log->setChecked(Settings::values.enable_fs_access_log.GetValue());      ui->reporting_services->setChecked(Settings::values.reporting_services.GetValue()); +    ui->dump_audio_commands->setChecked(Settings::values.dump_audio_commands.GetValue());      ui->quest_flag->setChecked(Settings::values.quest_flag.GetValue());      ui->use_debug_asserts->setChecked(Settings::values.use_debug_asserts.GetValue());      ui->use_auto_stub->setChecked(Settings::values.use_auto_stub.GetValue()); @@ -83,6 +84,7 @@ void ConfigureDebug::ApplyConfiguration() {      Settings::values.program_args = ui->homebrew_args_edit->text().toStdString();      Settings::values.enable_fs_access_log = ui->fs_access_log->isChecked();      Settings::values.reporting_services = ui->reporting_services->isChecked(); +    Settings::values.dump_audio_commands = ui->dump_audio_commands->isChecked();      Settings::values.quest_flag = ui->quest_flag->isChecked();      Settings::values.use_debug_asserts = ui->use_debug_asserts->isChecked();      Settings::values.use_auto_stub = ui->use_auto_stub->isChecked(); diff --git a/src/yuzu/configuration/configure_debug.ui b/src/yuzu/configuration/configure_debug.ui index 1152fa6c6..4c16274fc 100644 --- a/src/yuzu/configuration/configure_debug.ui +++ b/src/yuzu/configuration/configure_debug.ui @@ -235,6 +235,16 @@         </widget>        </item>        <item row="1" column="0"> +       <widget class="QCheckBox" name="dump_audio_commands"> +        <property name="text"> +         <string>Dump Audio Commands To Console**</string> +        </property> +        <property name="toolTip"> +         <string>Enable this to output the latest generated audio command list to the console. Only affects games using the audio renderer.</string> +        </property> +       </widget> +      </item> +      <item row="2" column="0">         <widget class="QCheckBox" name="reporting_services">          <property name="text">           <string>Enable Verbose Reporting Services**</string> @@ -325,6 +335,7 @@    <tabstop>disable_loop_safety_checks</tabstop>    <tabstop>fs_access_log</tabstop>    <tabstop>reporting_services</tabstop> +  <tabstop>dump_audio_commands</tabstop>    <tabstop>quest_flag</tabstop>    <tabstop>enable_cpu_debugging</tabstop>    <tabstop>use_debug_asserts</tabstop> diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp index a31fabd3f..2a446205b 100644 --- a/src/yuzu/configuration/configure_general.cpp +++ b/src/yuzu/configuration/configure_general.cpp @@ -27,9 +27,6 @@ ConfigureGeneral::ConfigureGeneral(const Core::System& system_, QWidget* parent)      connect(ui->button_reset_defaults, &QPushButton::clicked, this,              &ConfigureGeneral::ResetDefaults); - -    ui->fps_cap_label->setVisible(Settings::IsConfiguringGlobal()); -    ui->fps_cap_combobox->setVisible(!Settings::IsConfiguringGlobal());  }  ConfigureGeneral::~ConfigureGeneral() = default; @@ -52,8 +49,6 @@ void ConfigureGeneral::SetConfiguration() {      ui->toggle_speed_limit->setChecked(Settings::values.use_speed_limit.GetValue());      ui->speed_limit->setValue(Settings::values.speed_limit.GetValue()); -    ui->fps_cap->setValue(Settings::values.fps_cap.GetValue()); -      ui->button_reset_defaults->setEnabled(runtime_lock);      if (Settings::IsConfiguringGlobal()) { @@ -61,11 +56,6 @@ void ConfigureGeneral::SetConfiguration() {      } else {          ui->speed_limit->setEnabled(Settings::values.use_speed_limit.GetValue() &&                                      use_speed_limit != ConfigurationShared::CheckState::Global); - -        ui->fps_cap_combobox->setCurrentIndex(Settings::values.fps_cap.UsingGlobal() ? 0 : 1); -        ui->fps_cap->setEnabled(!Settings::values.fps_cap.UsingGlobal()); -        ConfigurationShared::SetHighlight(ui->fps_cap_layout, -                                          !Settings::values.fps_cap.UsingGlobal());      }  } @@ -102,8 +92,6 @@ void ConfigureGeneral::ApplyConfiguration() {          UISettings::values.mute_when_in_background = ui->toggle_background_mute->isChecked();          UISettings::values.hide_mouse = ui->toggle_hide_mouse->isChecked(); -        Settings::values.fps_cap.SetValue(ui->fps_cap->value()); -          // Guard if during game and set to game-specific value          if (Settings::values.use_speed_limit.UsingGlobal()) {              Settings::values.use_speed_limit.SetValue(ui->toggle_speed_limit->checkState() == @@ -119,13 +107,6 @@ void ConfigureGeneral::ApplyConfiguration() {                                                        Qt::Checked);              Settings::values.speed_limit.SetValue(ui->speed_limit->value());          } - -        if (ui->fps_cap_combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) { -            Settings::values.fps_cap.SetGlobal(true); -        } else { -            Settings::values.fps_cap.SetGlobal(false); -            Settings::values.fps_cap.SetValue(ui->fps_cap->value()); -        }      }  } @@ -171,9 +152,4 @@ void ConfigureGeneral::SetupPerGameUI() {          ui->speed_limit->setEnabled(ui->toggle_speed_limit->isChecked() &&                                      (use_speed_limit != ConfigurationShared::CheckState::Global));      }); - -    connect(ui->fps_cap_combobox, qOverload<int>(&QComboBox::activated), this, [this](int index) { -        ui->fps_cap->setEnabled(index == 1); -        ConfigurationShared::SetHighlight(ui->fps_cap_layout, index == 1); -    });  } diff --git a/src/yuzu/configuration/configure_general.ui b/src/yuzu/configuration/configure_general.ui index c6ef2ab70..5b90b1109 100644 --- a/src/yuzu/configuration/configure_general.ui +++ b/src/yuzu/configuration/configure_general.ui @@ -28,87 +28,6 @@          <item>           <layout class="QVBoxLayout" name="GeneralVerticalLayout">            <item> -           <widget class="QWidget" name="fps_cap_layout" native="true"> -            <layout class="QHBoxLayout" name="horizontalLayout" stretch="1,1"> -             <property name="leftMargin"> -              <number>0</number> -             </property> -             <property name="topMargin"> -              <number>0</number> -             </property> -             <property name="rightMargin"> -              <number>0</number> -             </property> -             <property name="bottomMargin"> -              <number>0</number> -             </property> -             <item> -              <layout class="QHBoxLayout" name="horizontalLayout_4"> -               <item> -                <widget class="QComboBox" name="fps_cap_combobox"> -                 <property name="currentText"> -                  <string>Use global framerate cap</string> -                 </property> -                 <property name="currentIndex"> -                  <number>0</number> -                 </property> -                 <item> -                  <property name="text"> -                   <string>Use global framerate cap</string> -                  </property> -                 </item> -                 <item> -                  <property name="text"> -                   <string>Set framerate cap:</string> -                  </property> -                 </item> -                </widget> -               </item> -               <item> -                <widget class="QLabel" name="fps_cap_label"> -                 <property name="toolTip"> -                  <string>Requires the use of the FPS Limiter Toggle hotkey to take effect.</string> -                 </property> -                 <property name="text"> -                  <string>Framerate Cap</string> -                 </property> -                </widget> -               </item> -               <item> -                <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> -              </layout> -             </item> -             <item> -              <widget class="QSpinBox" name="fps_cap"> -               <property name="suffix"> -                <string>x</string> -               </property> -               <property name="minimum"> -                <number>1</number> -               </property> -               <property name="maximum"> -                <number>1000</number> -               </property> -               <property name="value"> -                <number>500</number> -               </property> -              </widget> -             </item> -            </layout> -           </widget> -          </item> -          <item>             <layout class="QHBoxLayout" name="horizontalLayout_2">              <item>               <widget class="QCheckBox" name="toggle_speed_limit"> 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 @@  #include "ui_configure_input.h"  #include "ui_configure_input_advanced.h"  #include "ui_configure_input_player.h" +#include "yuzu/configuration/configure_camera.h"  #include "yuzu/configuration/configure_debug_controller.h"  #include "yuzu/configuration/configure_input.h"  #include "yuzu/configuration/configure_input_advanced.h" @@ -163,6 +164,10 @@ void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem,              [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,              [this, &hid_core] { CallConfigureDialog<ConfigureVibration>(*this, hid_core); }); diff --git a/src/yuzu/configuration/configure_input.ui b/src/yuzu/configuration/configure_input.ui index 2707025e7..d51774028 100644 --- a/src/yuzu/configuration/configure_input.ui +++ b/src/yuzu/configuration/configure_input.ui @@ -166,7 +166,7 @@           <item>            <widget class="QRadioButton" name="radioUndocked">             <property name="text"> -            <string>Undocked</string> +            <string>Handheld</string>             </property>            </widget>           </item> 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)              [this] { CallMotionTouchConfigDialog(); });      connect(ui->ring_controller_configure, &QPushButton::clicked, this,              [this] { CallRingControllerDialog(); }); +    connect(ui->camera_configure, &QPushButton::clicked, this, [this] { CallCameraDialog(); });  #ifndef _WIN32      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.controller_navigation = ui->controller_navigation->isChecked();      Settings::values.enable_ring_controller = ui->enable_ring_controller->isChecked(); +    Settings::values.enable_ir_sensor = ui->enable_ir_sensor->isChecked();  }  void ConfigureInputAdvanced::LoadConfiguration() { @@ -169,6 +171,7 @@ void ConfigureInputAdvanced::LoadConfiguration() {      ui->enable_udp_controller->setChecked(Settings::values.enable_udp_controller.GetValue());      ui->controller_navigation->setChecked(Settings::values.controller_navigation.GetValue());      ui->enable_ring_controller->setChecked(Settings::values.enable_ring_controller.GetValue()); +    ui->enable_ir_sensor->setChecked(Settings::values.enable_ir_sensor.GetValue());      UpdateUIEnabled();  } 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:      void CallTouchscreenConfigDialog();      void CallMotionTouchConfigDialog();      void CallRingControllerDialog(); +    void CallCameraDialog();  private:      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 @@                   </property>                  </widget>                 </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>               </widget>              </item>  | 
