diff --git a/src/citra/config.cpp b/src/citra/config.cpp index b4e3a2ce9..ce51b687b 100644 --- a/src/citra/config.cpp +++ b/src/citra/config.cpp @@ -155,14 +155,20 @@ void Config::ReadValues() { sdl2_config->Get("Camera", "camera_outer_right_name", "blank"); Settings::values.camera_config[OuterRightCamera] = sdl2_config->Get("Camera", "camera_outer_right_config", ""); + Settings::values.camera_flip[OuterRightCamera] = + sdl2_config->GetInteger("Camera", "camera_outer_right_flip", 0); Settings::values.camera_name[InnerCamera] = sdl2_config->Get("Camera", "camera_inner_name", "blank"); Settings::values.camera_config[InnerCamera] = sdl2_config->Get("Camera", "camera_inner_config", ""); + Settings::values.camera_flip[InnerCamera] = + sdl2_config->GetInteger("Camera", "camera_inner_flip", 0); Settings::values.camera_name[OuterLeftCamera] = sdl2_config->Get("Camera", "camera_outer_left_name", "blank"); Settings::values.camera_config[OuterLeftCamera] = sdl2_config->Get("Camera", "camera_outer_left_config", ""); + Settings::values.camera_flip[OuterLeftCamera] = + sdl2_config->GetInteger("Camera", "camera_outer_left_flip", 0); // Miscellaneous Settings::values.log_filter = sdl2_config->Get("Miscellaneous", "log_filter", "*:Info"); diff --git a/src/citra/default_ini.h b/src/citra/default_ini.h index 7179d6f94..4a17eb6ca 100644 --- a/src/citra/default_ini.h +++ b/src/citra/default_ini.h @@ -178,13 +178,19 @@ camera_outer_right_name = # A config string for the right outer camera. Its meaning is defined by the camera engine camera_outer_right_config = +# The image flip to apply +# 0: None (default), 1: Horizontal, 2: Vertical, 3: Reverse +camera_outer_right_flip = + # ... for the left outer camera camera_outer_left_name = camera_outer_left_config = +camera_outer_left_flip = # ... for the inner camera camera_inner_name = camera_inner_config = +camera_inner_flip = [Miscellaneous] # A filter which removes logs below a certain logging level. diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt index 4e0fcdbeb..7b0d0eaac 100644 --- a/src/citra_qt/CMakeLists.txt +++ b/src/citra_qt/CMakeLists.txt @@ -13,8 +13,8 @@ add_executable(citra-qt camera/camera_util.h camera/still_image_camera.cpp camera/still_image_camera.h - camera/qt_camera_factory.cpp - camera/qt_camera_factory.h + camera/qt_camera_base.cpp + camera/qt_camera_base.h camera/qt_multimedia_camera.cpp camera/qt_multimedia_camera.h citra-qt.rc diff --git a/src/citra_qt/camera/qt_camera_base.cpp b/src/citra_qt/camera/qt_camera_base.cpp new file mode 100644 index 000000000..69593ab51 --- /dev/null +++ b/src/citra_qt/camera/qt_camera_base.cpp @@ -0,0 +1,58 @@ +// Copyright 2018 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include "citra_qt/camera/camera_util.h" +#include "citra_qt/camera/qt_camera_base.h" + +namespace Camera { + +QtCameraInterface::QtCameraInterface(const Service::CAM::Flip& flip) { + using namespace Service::CAM; + flip_horizontal = basic_flip_horizontal = (flip == Flip::Horizontal) || (flip == Flip::Reverse); + flip_vertical = basic_flip_vertical = (flip == Flip::Vertical) || (flip == Flip::Reverse); +} + +void QtCameraInterface::SetFormat(Service::CAM::OutputFormat output_format) { + output_rgb = output_format == Service::CAM::OutputFormat::RGB565; +} + +void QtCameraInterface::SetResolution(const Service::CAM::Resolution& resolution) { + width = resolution.width; + height = resolution.height; +} + +void QtCameraInterface::SetFlip(Service::CAM::Flip flip) { + using namespace Service::CAM; + flip_horizontal = basic_flip_horizontal ^ (flip == Flip::Horizontal || flip == Flip::Reverse); + flip_vertical = basic_flip_vertical ^ (flip == Flip::Vertical || flip == Flip::Reverse); +} + +void QtCameraInterface::SetEffect(Service::CAM::Effect effect) { + if (effect != Service::CAM::Effect::None) { + NGLOG_ERROR(Service_CAM, "Unimplemented effect {}", static_cast(effect)); + } +} + +std::vector QtCameraInterface::ReceiveFrame() { + return CameraUtil::ProcessImage(QtReceiveFrame(), width, height, output_rgb, flip_horizontal, + flip_vertical); +} + +std::unique_ptr QtCameraFactory::CreatePreview(const std::string& config, + int width, int height, + const Service::CAM::Flip& flip) { + std::unique_ptr camera = Create(config, flip); + + if (camera->IsPreviewAvailable()) { + return camera; + } + QMessageBox::critical( + nullptr, QObject::tr("Error"), + (config.empty() ? QObject::tr("Couldn't load the camera") + : QObject::tr("Couldn't load %1").arg(QString::fromStdString(config)))); + return nullptr; +} + +} // namespace Camera diff --git a/src/citra_qt/camera/qt_camera_base.h b/src/citra_qt/camera/qt_camera_base.h new file mode 100644 index 000000000..6c6095a28 --- /dev/null +++ b/src/citra_qt/camera/qt_camera_base.h @@ -0,0 +1,36 @@ +// Copyright 2018 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include "core/frontend/camera/factory.h" + +namespace Camera { + +// Base class for camera interfaces of citra_qt +class QtCameraInterface : public CameraInterface { +public: + QtCameraInterface(const Service::CAM::Flip& flip); + void SetResolution(const Service::CAM::Resolution&) override; + void SetFlip(Service::CAM::Flip) override; + void SetEffect(Service::CAM::Effect) override; + void SetFormat(Service::CAM::OutputFormat) override; + std::vector ReceiveFrame() override; + virtual QImage QtReceiveFrame() = 0; + +private: + int width, height; + bool output_rgb; + bool flip_horizontal, flip_vertical; + bool basic_flip_horizontal, basic_flip_vertical; +}; + +// Base class for camera factories of citra_qt +class QtCameraFactory : public CameraFactory { + std::unique_ptr CreatePreview(const std::string& config, int width, int height, + const Service::CAM::Flip& flip) override; +}; + +} // namespace Camera diff --git a/src/citra_qt/camera/qt_camera_factory.cpp b/src/citra_qt/camera/qt_camera_factory.cpp deleted file mode 100644 index fa78591ba..000000000 --- a/src/citra_qt/camera/qt_camera_factory.cpp +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2018 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include "citra_qt/camera/qt_camera_factory.h" - -namespace Camera { - -std::unique_ptr QtCameraFactory::CreatePreview(const std::string& config, - int width, int height) const { - std::unique_ptr camera = Create(config); - - if (camera->IsPreviewAvailable()) { - return camera; - } - QMessageBox::critical( - nullptr, QObject::tr("Error"), - (config.empty() ? QObject::tr("Couldn't load the camera") - : QObject::tr("Couldn't load %1").arg(QString::fromStdString(config)))); - return nullptr; -} - -} // namespace Camera diff --git a/src/citra_qt/camera/qt_camera_factory.h b/src/citra_qt/camera/qt_camera_factory.h deleted file mode 100644 index 7efc21b58..000000000 --- a/src/citra_qt/camera/qt_camera_factory.h +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2018 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include "core/frontend/camera/factory.h" - -namespace Camera { - -// Base class for camera factories of citra_qt -class QtCameraFactory : public CameraFactory { - std::unique_ptr CreatePreview(const std::string& config, int width, - int height) const override; -}; - -} // namespace Camera diff --git a/src/citra_qt/camera/qt_multimedia_camera.cpp b/src/citra_qt/camera/qt_multimedia_camera.cpp index 6c2668df6..76a21453d 100644 --- a/src/citra_qt/camera/qt_multimedia_camera.cpp +++ b/src/citra_qt/camera/qt_multimedia_camera.cpp @@ -46,8 +46,9 @@ bool QtCameraSurface::present(const QVideoFrame& frame) { return true; } -QtMultimediaCamera::QtMultimediaCamera(const std::string& camera_name) - : handler(QtMultimediaCameraHandler::GetHandler()) { +QtMultimediaCamera::QtMultimediaCamera(const std::string& camera_name, + const Service::CAM::Flip& flip) + : QtCameraInterface(flip), handler(QtMultimediaCameraHandler::GetHandler(camera_name)) { if (handler->thread() == QThread::currentThread()) { handler->CreateCamera(camera_name); } else { @@ -73,10 +74,6 @@ void QtMultimediaCamera::StopCapture() { handler->StopCamera(); } -void QtMultimediaCamera::SetFormat(Service::CAM::OutputFormat output_format) { - output_rgb = output_format == Service::CAM::OutputFormat::RGB565; -} - void QtMultimediaCamera::SetFrameRate(Service::CAM::FrameRate frame_rate) { const std::array FrameRateList = { /* Rate_15 */ QCamera::FrameRateRange(15, 15), @@ -96,57 +93,49 @@ void QtMultimediaCamera::SetFrameRate(Service::CAM::FrameRate frame_rate) { auto framerate = FrameRateList[static_cast(frame_rate)]; - handler->settings.setMinimumFrameRate(framerate.minimumFrameRate); - handler->settings.setMinimumFrameRate(framerate.maximumFrameRate); -} - -void QtMultimediaCamera::SetResolution(const Service::CAM::Resolution& resolution) { - width = resolution.width; - height = resolution.height; -} - -void QtMultimediaCamera::SetFlip(Service::CAM::Flip flip) { - using namespace Service::CAM; - flip_horizontal = (flip == Flip::Horizontal) || (flip == Flip::Reverse); - flip_vertical = (flip == Flip::Vertical) || (flip == Flip::Reverse); -} - -void QtMultimediaCamera::SetEffect(Service::CAM::Effect effect) { - if (effect != Service::CAM::Effect::None) { - NGLOG_ERROR(Service_CAM, "Unimplemented effect {}", static_cast(effect)); + if (handler->camera->supportedViewfinderFrameRateRanges().contains(framerate)) { + handler->settings.setMinimumFrameRate(framerate.minimumFrameRate); + handler->settings.setMaximumFrameRate(framerate.maximumFrameRate); } } -std::vector QtMultimediaCamera::ReceiveFrame() { +QImage QtMultimediaCamera::QtReceiveFrame() { QMutexLocker locker(&handler->camera_surface.mutex); - return CameraUtil::ProcessImage(handler->camera_surface.current_frame, width, height, - output_rgb, flip_horizontal, flip_vertical); + return handler->camera_surface.current_frame; } bool QtMultimediaCamera::IsPreviewAvailable() { return handler->CameraAvailable(); } -std::unique_ptr QtMultimediaCameraFactory::Create( - const std::string& config) const { - return std::make_unique(config); +std::unique_ptr QtMultimediaCameraFactory::Create(const std::string& config, + const Service::CAM::Flip& flip) { + return std::make_unique(config, flip); } std::array, 3> QtMultimediaCameraHandler::handlers; std::array QtMultimediaCameraHandler::status; +std::unordered_map> + QtMultimediaCameraHandler::loaded; + void QtMultimediaCameraHandler::Init() { for (auto& handler : handlers) { handler = std::make_shared(); } } -std::shared_ptr QtMultimediaCameraHandler::GetHandler() { +std::shared_ptr QtMultimediaCameraHandler::GetHandler( + const std::string& camera_name) { + if (loaded.count(camera_name)) { + return loaded.at(camera_name); + } for (int i = 0; i < handlers.size(); i++) { if (!status[i]) { NGLOG_INFO(Service_CAM, "Successfully got handler {}", i); status[i] = true; + loaded.emplace(camera_name, handlers[i]); return handlers[i]; } } @@ -161,6 +150,12 @@ void QtMultimediaCameraHandler::ReleaseHandler( NGLOG_INFO(Service_CAM, "Successfully released handler {}", i); status[i] = false; handlers[i]->started = false; + for (auto it = loaded.begin(); it != loaded.end(); it++) { + if (it->second == handlers[i]) { + loaded.erase(it); + break; + } + } break; } } @@ -178,6 +173,7 @@ void QtMultimediaCameraHandler::CreateCamera(const std::string& camera_name) { settings.setMinimumFrameRate(30); settings.setMaximumFrameRate(30); camera->setViewfinder(&camera_surface); + camera->load(); } void QtMultimediaCameraHandler::StopCamera() { diff --git a/src/citra_qt/camera/qt_multimedia_camera.h b/src/citra_qt/camera/qt_multimedia_camera.h index 103aff8a0..14242c554 100644 --- a/src/citra_qt/camera/qt_multimedia_camera.h +++ b/src/citra_qt/camera/qt_multimedia_camera.h @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -13,7 +14,7 @@ #include #include #include "citra_qt/camera/camera_util.h" -#include "citra_qt/camera/qt_camera_factory.h" +#include "citra_qt/camera/qt_camera_base.h" #include "core/frontend/camera/interface.h" class GMainWindow; @@ -36,30 +37,24 @@ private: class QtMultimediaCameraHandler; /// This class is only an interface. It just calls QtMultimediaCameraHandler. -class QtMultimediaCamera final : public CameraInterface { +class QtMultimediaCamera final : public QtCameraInterface { public: - QtMultimediaCamera(const std::string& camera_name); + QtMultimediaCamera(const std::string& camera_name, const Service::CAM::Flip& flip); ~QtMultimediaCamera(); void StartCapture() override; void StopCapture() override; - void SetResolution(const Service::CAM::Resolution&) override; - void SetFlip(Service::CAM::Flip) override; - void SetEffect(Service::CAM::Effect) override; - void SetFormat(Service::CAM::OutputFormat) override; void SetFrameRate(Service::CAM::FrameRate frame_rate) override; - std::vector ReceiveFrame() override; + QImage QtReceiveFrame() override; bool IsPreviewAvailable() override; private: std::shared_ptr handler; - int width, height; - bool output_rgb; - bool flip_horizontal, flip_vertical; }; class QtMultimediaCameraFactory final : public QtCameraFactory { public: - std::unique_ptr Create(const std::string& config) const override; + std::unique_ptr Create(const std::string& config, + const Service::CAM::Flip& flip) override; }; class QtMultimediaCameraHandler final : public QObject { @@ -68,7 +63,7 @@ class QtMultimediaCameraHandler final : public QObject { public: /// Creates the global handler. Must be called in UI thread. static void Init(); - static std::shared_ptr GetHandler(); + static std::shared_ptr GetHandler(const std::string& camera_name); static void ReleaseHandler(const std::shared_ptr& handler); /** @@ -98,6 +93,7 @@ private: static std::array, 3> handlers; static std::array status; + static std::unordered_map> loaded; friend class QtMultimediaCamera; // For access to camera_surface (and camera) }; diff --git a/src/citra_qt/camera/still_image_camera.cpp b/src/citra_qt/camera/still_image_camera.cpp index ab0d18308..e02d0d0d3 100644 --- a/src/citra_qt/camera/still_image_camera.cpp +++ b/src/citra_qt/camera/still_image_camera.cpp @@ -5,47 +5,36 @@ #include #include #include +#include #include "citra_qt/camera/still_image_camera.h" namespace Camera { -StillImageCamera::StillImageCamera(QImage image_) : image(std::move(image_)) {} +StillImageCamera::StillImageCamera(QImage image_, const Service::CAM::Flip& flip) + : QtCameraInterface(flip), image(std::move(image_)) {} + +StillImageCamera::~StillImageCamera() { + StillImageCameraFactory::last_path.clear(); +} void StillImageCamera::StartCapture() {} void StillImageCamera::StopCapture() {} -void StillImageCamera::SetFormat(Service::CAM::OutputFormat output_format) { - output_rgb = output_format == Service::CAM::OutputFormat::RGB565; -} - -void StillImageCamera::SetResolution(const Service::CAM::Resolution& resolution) { - width = resolution.width; - height = resolution.height; -} - -void StillImageCamera::SetFlip(Service::CAM::Flip flip) { - using namespace Service::CAM; - flip_horizontal = (flip == Flip::Horizontal) || (flip == Flip::Reverse); - flip_vertical = (flip == Flip::Vertical) || (flip == Flip::Reverse); -} - -void StillImageCamera::SetEffect(Service::CAM::Effect effect) { - if (effect != Service::CAM::Effect::None) { - NGLOG_ERROR(Service_CAM, "Unimplemented effect {}", static_cast(effect)); - } -} - -std::vector StillImageCamera::ReceiveFrame() { - return CameraUtil::ProcessImage(image, width, height, output_rgb, flip_horizontal, - flip_vertical); +QImage StillImageCamera::QtReceiveFrame() { + return image; } bool StillImageCamera::IsPreviewAvailable() { return !image.isNull(); } -const std::string StillImageCameraFactory::getFilePath() { +std::string StillImageCameraFactory::last_path; + +const std::string StillImageCameraFactory::GetFilePath() const { + if (!last_path.empty()) { + return last_path; + } QList types = QImageReader::supportedImageFormats(); QList temp_filters; for (QByteArray type : types) { @@ -53,21 +42,29 @@ const std::string StillImageCameraFactory::getFilePath() { } QString filter = QObject::tr("Supported image files (%1)").arg(temp_filters.join(" ")); - - return QFileDialog::getOpenFileName(nullptr, QObject::tr("Open File"), ".", filter) - .toStdString(); + last_path = + QFileDialog::getOpenFileName(nullptr, QObject::tr("Open File"), ".", filter).toStdString(); + return last_path; } -std::unique_ptr StillImageCameraFactory::Create(const std::string& config) const { +std::unique_ptr StillImageCameraFactory::Create(const std::string& config, + const Service::CAM::Flip& flip) { std::string real_config = config; if (config.empty()) { - real_config = getFilePath(); + // call GetFilePath() in UI thread (note: StillImageCameraFactory itself is initialized in + // UI thread, so we can just pass in "this" here) + if (thread() == QThread::currentThread()) { + real_config = GetFilePath(); + } else { + QMetaObject::invokeMethod(this, "GetFilePath", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(std::string, real_config)); + } } QImage image(QString::fromStdString(real_config)); if (image.isNull()) { NGLOG_ERROR(Service_CAM, "Couldn't load image \"{}\"", real_config.c_str()); } - return std::make_unique(image); + return std::make_unique(image, flip); } } // namespace Camera diff --git a/src/citra_qt/camera/still_image_camera.h b/src/citra_qt/camera/still_image_camera.h index c54d367e8..19ca044f0 100644 --- a/src/citra_qt/camera/still_image_camera.h +++ b/src/citra_qt/camera/still_image_camera.h @@ -7,37 +7,39 @@ #include #include #include "citra_qt/camera/camera_util.h" -#include "citra_qt/camera/qt_camera_factory.h" +#include "citra_qt/camera/qt_camera_base.h" #include "core/frontend/camera/interface.h" namespace Camera { -class StillImageCamera final : public CameraInterface { +class StillImageCamera final : public QtCameraInterface { public: - StillImageCamera(QImage image); + StillImageCamera(QImage image, const Service::CAM::Flip& flip); + ~StillImageCamera(); void StartCapture() override; void StopCapture() override; - void SetResolution(const Service::CAM::Resolution&) override; - void SetFlip(Service::CAM::Flip) override; - void SetEffect(Service::CAM::Effect) override; - void SetFormat(Service::CAM::OutputFormat) override; void SetFrameRate(Service::CAM::FrameRate frame_rate) override {} - std::vector ReceiveFrame() override; + QImage QtReceiveFrame() override; bool IsPreviewAvailable() override; private: QImage image; - int width, height; - bool output_rgb; - bool flip_horizontal, flip_vertical; }; -class StillImageCameraFactory final : public QtCameraFactory { +class StillImageCameraFactory final : public QObject, public QtCameraFactory { + Q_OBJECT + public: - std::unique_ptr Create(const std::string& config) const override; + std::unique_ptr Create(const std::string& config, + const Service::CAM::Flip& flip) override; + + Q_INVOKABLE const std::string GetFilePath() const; private: - static const std::string getFilePath(); + /// Record the path chosen to avoid multiple prompt problem + static std::string last_path; + + friend class StillImageCamera; }; } // namespace Camera diff --git a/src/citra_qt/configuration/config.cpp b/src/citra_qt/configuration/config.cpp index bdb296659..e5d252c81 100644 --- a/src/citra_qt/configuration/config.cpp +++ b/src/citra_qt/configuration/config.cpp @@ -128,14 +128,19 @@ void Config::ReadValues() { qt_config->value("camera_outer_right_name", "blank").toString().toStdString(); Settings::values.camera_config[OuterRightCamera] = qt_config->value("camera_outer_right_config", "").toString().toStdString(); + Settings::values.camera_flip[OuterRightCamera] = + qt_config->value("camera_outer_right_flip", "0").toInt(); Settings::values.camera_name[InnerCamera] = qt_config->value("camera_inner_name", "blank").toString().toStdString(); Settings::values.camera_config[InnerCamera] = qt_config->value("camera_inner_config", "").toString().toStdString(); + Settings::values.camera_flip[InnerCamera] = qt_config->value("camera_inner_flip", "").toInt(); Settings::values.camera_name[OuterLeftCamera] = qt_config->value("camera_outer_left_name", "blank").toString().toStdString(); Settings::values.camera_config[OuterLeftCamera] = qt_config->value("camera_outer_left_config", "").toString().toStdString(); + Settings::values.camera_flip[OuterLeftCamera] = + qt_config->value("camera_outer_left_flip", "").toInt(); qt_config->endGroup(); qt_config->beginGroup("Data Storage"); @@ -317,14 +322,17 @@ void Config::SaveValues() { QString::fromStdString(Settings::values.camera_name[OuterRightCamera])); qt_config->setValue("camera_outer_right_config", QString::fromStdString(Settings::values.camera_config[OuterRightCamera])); + qt_config->setValue("camera_outer_right_flip", Settings::values.camera_flip[OuterRightCamera]); qt_config->setValue("camera_inner_name", QString::fromStdString(Settings::values.camera_name[InnerCamera])); qt_config->setValue("camera_inner_config", QString::fromStdString(Settings::values.camera_config[InnerCamera])); + qt_config->setValue("camera_inner_flip", Settings::values.camera_flip[InnerCamera]); qt_config->setValue("camera_outer_left_name", QString::fromStdString(Settings::values.camera_name[OuterLeftCamera])); qt_config->setValue("camera_outer_left_config", QString::fromStdString(Settings::values.camera_config[OuterLeftCamera])); + qt_config->setValue("camera_outer_left_flip", Settings::values.camera_flip[OuterLeftCamera]); qt_config->endGroup(); qt_config->beginGroup("Data Storage"); diff --git a/src/citra_qt/configuration/configure_camera.cpp b/src/citra_qt/configuration/configure_camera.cpp index ca6db4623..e9d964b3a 100644 --- a/src/citra_qt/configuration/configure_camera.cpp +++ b/src/citra_qt/configuration/configure_camera.cpp @@ -27,14 +27,7 @@ ConfigureCamera::ConfigureCamera(QWidget* parent) // Load settings camera_name = Settings::values.camera_name; camera_config = Settings::values.camera_config; - for (auto&& item : camera_name) { - if (item == "opencv") { - QMessageBox::critical(this, tr("Error"), - tr("Sorry, Citra has removed support for OpenCV cameras.\n\nYour " - "existing OpenCV cameras have been replaced with Blank.")); - item = "blank"; - } - } + camera_flip = Settings::values.camera_flip; QList cameras = QCameraInfo::availableCameras(); for (const QCameraInfo& cameraInfo : cameras) { ui->system_camera->addItem(cameraInfo.deviceName()); @@ -98,6 +91,8 @@ void ConfigureCamera::connectEvents() { connect(ui->system_camera, static_cast(&QComboBox::currentIndexChanged), this, [=] { stopPreviewing(); }); + connect(ui->camera_flip, static_cast(&QComboBox::currentIndexChanged), + this, [=] { stopPreviewing(); }); } void ConfigureCamera::updateCameraMode() { @@ -148,6 +143,8 @@ void ConfigureCamera::updateImageSourceUI() { } ui->system_camera_label->setHidden(image_source != 2); ui->system_camera->setHidden(image_source != 2); + ui->camera_flip_label->setHidden(image_source == 0); + ui->camera_flip->setHidden(image_source == 0); } void ConfigureCamera::recordConfig() { @@ -166,10 +163,12 @@ void ConfigureCamera::recordConfig() { if (current_selected == CameraPosition::RearBoth) { camera_name[0] = camera_name[2] = implementation; camera_config[0] = camera_config[2] = config; + camera_flip[0] = camera_flip[2] = ui->camera_flip->currentIndex(); } else if (current_selected != CameraPosition::Null) { int index = static_cast(current_selected); camera_name[index] = implementation; camera_config[index] = config; + camera_flip[index] = ui->camera_flip->currentIndex(); } current_selected = getCameraSelection(); } @@ -187,9 +186,9 @@ void ConfigureCamera::startPreviewing() { ui->preview_box->setToolTip(tr("Resolution: ") + QString::number(preview_width) + "*" + QString::number(preview_height)); // Load previewing camera - previewing_camera = - Camera::CreateCameraPreview(camera_name[camera_selection], camera_config[camera_selection], - preview_width, preview_height); + previewing_camera = Camera::CreateCameraPreview( + camera_name[camera_selection], camera_config[camera_selection], preview_width, + preview_height, static_cast(camera_flip[camera_selection])); if (!previewing_camera) { stopPreviewing(); return; @@ -262,6 +261,7 @@ void ConfigureCamera::setConfiguration() { } else { ui->camera_file->setText(QString::fromStdString(camera_config[index])); } + ui->camera_flip->setCurrentIndex(camera_flip[index]); updateImageSourceUI(); } @@ -288,6 +288,7 @@ void ConfigureCamera::applyConfiguration() { stopPreviewing(); Settings::values.camera_name = camera_name; Settings::values.camera_config = camera_config; + Settings::values.camera_flip = camera_flip; Settings::Apply(); } diff --git a/src/citra_qt/configuration/configure_camera.h b/src/citra_qt/configuration/configure_camera.h index 5621de7ef..0aa55996e 100644 --- a/src/citra_qt/configuration/configure_camera.h +++ b/src/citra_qt/configuration/configure_camera.h @@ -47,6 +47,7 @@ private: std::unique_ptr ui; std::array camera_name; std::array camera_config; + std::array camera_flip; int timer_id = 0; int preview_width = 0; int preview_height = 0; diff --git a/src/citra_qt/configuration/configure_camera.ui b/src/citra_qt/configuration/configure_camera.ui index cd4d2e108..46c56b266 100644 --- a/src/citra_qt/configuration/configure_camera.ui +++ b/src/citra_qt/configuration/configure_camera.ui @@ -1,257 +1,347 @@ - - ConfigureCamera - - + ConfigureCamera + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + + Camera + + - - - Camera + + + + + Select the camera to configure - - - - - - - Select the camera to configure - - - Camera to configure: - - - - - - - Select the camera to configure - - - - Front - - - - - Rear - - - - - - - - - - - - Select the camera mode (single or double) - - - Camera mode: - - - - - - - Select the camera mode (single or double) - - - - Single (2D) - - - - - Double (3D) - - - - - - - - - - - - Select the position of camera to configure - - - Camera position: - - - - - - - Select the position of camera to configure - - - - Left - - - - - Right - - - - - - - - + + Camera to configure: + + + + + + + Select the camera to configure + + + + Front + + + + + Rear + + + + + - - - Configuration + + + + + Select the camera mode (single or double) - - - - - - - Select where the image of the emulated camera comes from. It may be an image or a real camera. - - - Camera Image Source: - - - - - - - Select where the image of the emulated camera come from. It may be an image or a real camera. - - - - Blank (blank) - - - - - Still Image (image) - - - - - System Camera (qt) - - - - - - - - - - - - QFrame::NoFrame - - - File: - - - - - - - - - - ... - - - - - - - - - - - QFrame::NoFrame - - - Camera: - - - - - - - - <Default> - - - - - - - - - - Prompt before load - - - - - + + Camera mode: + + + + + + + Select the camera mode (single or double) + + + + Single (2D) + + + + + Double (3D) + + + + + - - - Preview + + + + + Select the position of camera to configure - - - - - - 512 - 384 - - - - Resolution: 512*384 - - - - - - - - - - Click to preview - - - - - + + Camera position: + + + + + + + Select the position of camera to configure + + + + Left + + + + + Right + + + + + + + + + + + + + Configuration + + + + + + + + Select where the image of the emulated camera comes from. It may be an image or a real camera. + + + Camera Image Source: + + + + + + + Select where the image of the emulated camera comes from. It may be an image or a real camera. + + + + Blank (blank) + + + + + Still Image (image) + + + + + System Camera (qt) + + + + + - - - Qt::Vertical + + + + + QFrame::NoFrame - - - 20 - 40 - + + File: - + + + + + + + + + ... + + + + - - - - + + + + + + QFrame::NoFrame + + + Select the system camera to use + + + Camera: + + + + + + + + 0 + 0 + + + + + 250 + 16777215 + + + + Select the system camera to use + + + + <Default> + + + + + + + + + + + + QFrame::NoFrame + + + Select the image flip to apply + + + Flip: + + + + + + + true + + + + 0 + 0 + + + + + 800 + 16777215 + + + + Select the image flip to apply + + + + None + + + + + Horizontal + + + + + Vertical + + + + + Reverse + + + + + + + + + + Select an image file every time before the camera is loaded + + + Prompt before load + + + + + + + + + + Preview + + + + + + + 512 + 384 + + + + Resolution: 512*384 + + + + + + + + + + Click to preview + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + diff --git a/src/core/frontend/camera/factory.cpp b/src/core/frontend/camera/factory.cpp index f0434cdad..619fa3974 100644 --- a/src/core/frontend/camera/factory.cpp +++ b/src/core/frontend/camera/factory.cpp @@ -17,28 +17,29 @@ void RegisterFactory(const std::string& name, std::unique_ptr fac factories[name] = std::move(factory); } -std::unique_ptr CreateCamera(const std::string& name, const std::string& config) { +std::unique_ptr CreateCamera(const std::string& name, const std::string& config, + const Service::CAM::Flip& flip) { auto pair = factories.find(name); if (pair != factories.end()) { - return pair->second->Create(config); + return pair->second->Create(config, flip); } if (name != "blank") { - LOG_ERROR(Service_CAM, "Unknown camera \"%s\"", name.c_str()); + NGLOG_ERROR(Service_CAM, "Unknown camera {}", name); } return std::make_unique(); } std::unique_ptr CreateCameraPreview(const std::string& name, const std::string& config, int width, - int height) { + int height, const Service::CAM::Flip& flip) { auto pair = factories.find(name); if (pair != factories.end()) { - return pair->second->CreatePreview(config, width, height); + return pair->second->CreatePreview(config, width, height, flip); } if (name != "blank") { - LOG_ERROR(Service_CAM, "Unknown camera \"%s\"", name.c_str()); + NGLOG_ERROR(Service_CAM, "Unknown camera {}", name); } return std::make_unique(); } diff --git a/src/core/frontend/camera/factory.h b/src/core/frontend/camera/factory.h index 840be7022..0fe9f314f 100644 --- a/src/core/frontend/camera/factory.h +++ b/src/core/frontend/camera/factory.h @@ -18,22 +18,26 @@ public: * Creates a camera object based on the configuration string. * @param config Configuration string to create the camera. The implementation can decide the * meaning of this string. + * @param flip The image flip to apply * @returns a unique_ptr to the created camera object. */ - virtual std::unique_ptr Create(const std::string& config) const = 0; + virtual std::unique_ptr Create(const std::string& config, + const Service::CAM::Flip& flip) = 0; /** * Creates a camera object for preview based on the configuration string. * @param config Configuration string to create the camera. The implementation can decide the * meaning of this string. + * @param flip The image flip to apply * @returns a unique_ptr to the created camera object. * Note: The default implementation for this is to call Create(). Derived classes may have other - * Implementations. For example, A dialog may be used instead of LOG_ERROR when error + * Implementations. For example, A dialog may be used instead of NGLOG_ERROR when error * occurs. */ virtual std::unique_ptr CreatePreview(const std::string& config, int width, - int height) const { - return Create(config); + int height, + const Service::CAM::Flip& flip) { + return Create(config, flip); } }; @@ -50,7 +54,8 @@ void RegisterFactory(const std::string& name, std::unique_ptr fac * @param config Configuration string to create the camera. The meaning of this string is * defined by the factory. */ -std::unique_ptr CreateCamera(const std::string& name, const std::string& config); +std::unique_ptr CreateCamera(const std::string& name, const std::string& config, + const Service::CAM::Flip& flip); /** * Creates a camera from the factory for previewing. @@ -60,6 +65,6 @@ std::unique_ptr CreateCamera(const std::string& name, const std */ std::unique_ptr CreateCameraPreview(const std::string& name, const std::string& config, int width, - int height); + int height, const Service::CAM::Flip& flip); } // namespace Camera diff --git a/src/core/hle/service/cam/cam.cpp b/src/core/hle/service/cam/cam.cpp index 3328dcf8e..78cdb23e8 100644 --- a/src/core/hle/service/cam/cam.cpp +++ b/src/core/hle/service/cam/cam.cpp @@ -1041,8 +1041,9 @@ void Module::ReloadCameraDevices() { } void Module::LoadCameraImplementation(CameraConfig& camera, int camera_id) { - camera.impl = Camera::CreateCamera(Settings::values.camera_name[camera_id], - Settings::values.camera_config[camera_id]); + camera.impl = Camera::CreateCamera( + Settings::values.camera_name[camera_id], Settings::values.camera_config[camera_id], + static_cast(Settings::values.camera_flip[camera_id])); camera.impl->SetFlip(camera.contexts[0].flip); camera.impl->SetEffect(camera.contexts[0].effect); camera.impl->SetFormat(camera.contexts[0].format); diff --git a/src/core/settings.h b/src/core/settings.h index b57a1cbed..5ce4811af 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -140,6 +140,7 @@ struct Values { // Camera std::array camera_name; std::array camera_config; + std::array camera_flip; // Debugging bool use_gdbstub;