2018-05-11 19:42:23 +02:00
|
|
|
// Copyright 2018 Citra Emulator Project
|
|
|
|
// Licensed under GPLv2 or any later version
|
|
|
|
// Refer to the license.txt file included.
|
|
|
|
|
|
|
|
#include <memory>
|
|
|
|
#include <QCameraInfo>
|
|
|
|
#include <QDirIterator>
|
|
|
|
#include <QFileDialog>
|
|
|
|
#include <QImageReader>
|
|
|
|
#include <QMessageBox>
|
|
|
|
#include <QWidget>
|
|
|
|
#include "citra_qt/configuration/configure_camera.h"
|
2019-08-15 06:38:54 +02:00
|
|
|
#include "citra_qt/uisettings.h"
|
2018-05-11 19:42:23 +02:00
|
|
|
#include "core/core.h"
|
|
|
|
#include "core/settings.h"
|
|
|
|
#include "ui_configure_camera.h"
|
|
|
|
|
|
|
|
const std::array<std::string, 3> ConfigureCamera::Implementations = {
|
|
|
|
"blank", /* Blank */
|
|
|
|
"image", /* Image */
|
|
|
|
"qt" /* System Camera */
|
|
|
|
};
|
|
|
|
|
|
|
|
ConfigureCamera::ConfigureCamera(QWidget* parent)
|
|
|
|
: QWidget(parent), ui(std::make_unique<Ui::ConfigureCamera>()) {
|
|
|
|
ui->setupUi(this);
|
|
|
|
// Load settings
|
|
|
|
camera_name = Settings::values.camera_name;
|
|
|
|
camera_config = Settings::values.camera_config;
|
2018-05-20 03:07:37 +02:00
|
|
|
camera_flip = Settings::values.camera_flip;
|
2018-05-11 19:42:23 +02:00
|
|
|
QList<QCameraInfo> cameras = QCameraInfo::availableCameras();
|
|
|
|
for (const QCameraInfo& cameraInfo : cameras) {
|
|
|
|
ui->system_camera->addItem(cameraInfo.deviceName());
|
|
|
|
}
|
2019-05-26 06:39:23 +02:00
|
|
|
UpdateCameraMode();
|
|
|
|
SetConfiguration();
|
|
|
|
ConnectEvents();
|
2018-05-11 19:42:23 +02:00
|
|
|
ui->preview_box->setHidden(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
ConfigureCamera::~ConfigureCamera() {
|
2019-05-26 06:39:23 +02:00
|
|
|
StopPreviewing();
|
2018-05-11 19:42:23 +02:00
|
|
|
}
|
|
|
|
|
2019-05-26 06:39:23 +02:00
|
|
|
void ConfigureCamera::ConnectEvents() {
|
2018-05-11 19:42:23 +02:00
|
|
|
connect(ui->image_source,
|
|
|
|
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, [this] {
|
2019-05-26 06:39:23 +02:00
|
|
|
StopPreviewing();
|
|
|
|
UpdateImageSourceUI();
|
2018-05-11 19:42:23 +02:00
|
|
|
});
|
|
|
|
connect(ui->camera_selection,
|
|
|
|
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, [this] {
|
2019-05-26 06:39:23 +02:00
|
|
|
StopPreviewing();
|
|
|
|
if (GetCameraSelection() != current_selected) {
|
|
|
|
RecordConfig();
|
2018-05-11 19:42:23 +02:00
|
|
|
}
|
|
|
|
if (ui->camera_selection->currentIndex() == 1) {
|
|
|
|
ui->camera_mode->setCurrentIndex(1); // Double
|
|
|
|
if (camera_name[0] == camera_name[2] && camera_config[0] == camera_config[2]) {
|
|
|
|
ui->camera_mode->setCurrentIndex(0); // Single
|
|
|
|
}
|
|
|
|
}
|
2019-05-26 06:39:23 +02:00
|
|
|
UpdateCameraMode();
|
|
|
|
SetConfiguration();
|
2018-05-11 19:42:23 +02:00
|
|
|
});
|
|
|
|
connect(ui->camera_mode, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
|
|
|
|
this, [this] {
|
2019-05-26 06:39:23 +02:00
|
|
|
StopPreviewing();
|
2018-05-11 19:42:23 +02:00
|
|
|
ui->camera_position_label->setVisible(ui->camera_mode->currentIndex() == 1);
|
|
|
|
ui->camera_position->setVisible(ui->camera_mode->currentIndex() == 1);
|
2019-05-26 06:39:23 +02:00
|
|
|
current_selected = GetCameraSelection();
|
2018-05-11 19:42:23 +02:00
|
|
|
});
|
|
|
|
connect(ui->camera_position,
|
|
|
|
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, [this] {
|
2019-05-26 06:39:23 +02:00
|
|
|
StopPreviewing();
|
|
|
|
if (GetCameraSelection() != current_selected) {
|
|
|
|
RecordConfig();
|
2018-05-11 19:42:23 +02:00
|
|
|
}
|
2019-05-26 06:39:23 +02:00
|
|
|
SetConfiguration();
|
2018-05-11 19:42:23 +02:00
|
|
|
});
|
2019-05-26 06:39:23 +02:00
|
|
|
connect(ui->toolButton, &QToolButton::clicked, this, &ConfigureCamera::OnToolButtonClicked);
|
|
|
|
connect(ui->preview_button, &QPushButton::clicked, this, [=] { StartPreviewing(); });
|
2018-05-11 19:42:23 +02:00
|
|
|
connect(ui->prompt_before_load, &QCheckBox::stateChanged, this, [this](int state) {
|
|
|
|
ui->camera_file->setDisabled(state == Qt::Checked);
|
|
|
|
ui->toolButton->setDisabled(state == Qt::Checked);
|
|
|
|
if (state == Qt::Checked) {
|
2019-07-26 21:11:14 +02:00
|
|
|
ui->camera_file->setText(QString{});
|
2018-05-11 19:42:23 +02:00
|
|
|
}
|
|
|
|
});
|
2019-05-26 06:39:23 +02:00
|
|
|
connect(ui->camera_file, &QLineEdit::textChanged, this, [=] { StopPreviewing(); });
|
2018-05-11 19:42:23 +02:00
|
|
|
connect(ui->system_camera,
|
|
|
|
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
|
2019-05-26 06:39:23 +02:00
|
|
|
[=] { StopPreviewing(); });
|
2018-05-20 03:07:37 +02:00
|
|
|
connect(ui->camera_flip, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
|
2019-05-26 06:39:23 +02:00
|
|
|
this, [=] { StopPreviewing(); });
|
2018-05-11 19:42:23 +02:00
|
|
|
}
|
|
|
|
|
2019-05-26 06:39:23 +02:00
|
|
|
void ConfigureCamera::UpdateCameraMode() {
|
|
|
|
CameraPosition pos = GetCameraSelection();
|
2018-05-11 19:42:23 +02:00
|
|
|
// Set the visibility of the camera mode selection widgets
|
|
|
|
if (pos == CameraPosition::RearBoth) {
|
|
|
|
ui->camera_position->setHidden(true);
|
|
|
|
ui->camera_position_label->setHidden(true);
|
|
|
|
ui->camera_mode->setHidden(false);
|
|
|
|
ui->camera_mode_label->setHidden(false);
|
|
|
|
} else {
|
|
|
|
ui->camera_position->setHidden(pos == CameraPosition::Front);
|
|
|
|
ui->camera_position_label->setHidden(pos == CameraPosition::Front);
|
|
|
|
ui->camera_mode->setHidden(pos == CameraPosition::Front);
|
|
|
|
ui->camera_mode_label->setHidden(pos == CameraPosition::Front);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-26 06:39:23 +02:00
|
|
|
void ConfigureCamera::UpdateImageSourceUI() {
|
2018-05-11 19:42:23 +02:00
|
|
|
int image_source = ui->image_source->currentIndex();
|
|
|
|
switch (image_source) {
|
|
|
|
case 0: /* blank */
|
|
|
|
case 2: /* system camera */
|
|
|
|
ui->prompt_before_load->setHidden(true);
|
|
|
|
ui->prompt_before_load->setChecked(false);
|
|
|
|
ui->camera_file_label->setHidden(true);
|
|
|
|
ui->camera_file->setHidden(true);
|
2019-07-26 21:11:14 +02:00
|
|
|
ui->camera_file->setText(QString{});
|
2018-05-11 19:42:23 +02:00
|
|
|
ui->toolButton->setHidden(true);
|
|
|
|
break;
|
|
|
|
case 1: /* still image */
|
|
|
|
ui->prompt_before_load->setHidden(false);
|
|
|
|
ui->camera_file_label->setHidden(false);
|
|
|
|
ui->camera_file->setHidden(false);
|
|
|
|
ui->toolButton->setHidden(false);
|
2019-05-26 06:39:23 +02:00
|
|
|
if (camera_config[GetSelectedCameraIndex()].empty()) {
|
2018-05-11 19:42:23 +02:00
|
|
|
ui->prompt_before_load->setChecked(true);
|
|
|
|
ui->camera_file->setDisabled(true);
|
|
|
|
ui->toolButton->setDisabled(true);
|
2019-07-26 21:11:14 +02:00
|
|
|
ui->camera_file->setText(QString{});
|
2018-05-11 19:42:23 +02:00
|
|
|
} else {
|
|
|
|
ui->camera_file->setDisabled(false);
|
|
|
|
ui->toolButton->setDisabled(false);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
2018-06-29 13:18:07 +02:00
|
|
|
LOG_ERROR(Service_CAM, "Unknown image source {}", image_source);
|
2018-05-11 19:42:23 +02:00
|
|
|
}
|
|
|
|
ui->system_camera_label->setHidden(image_source != 2);
|
|
|
|
ui->system_camera->setHidden(image_source != 2);
|
2018-05-20 03:07:37 +02:00
|
|
|
ui->camera_flip_label->setHidden(image_source == 0);
|
|
|
|
ui->camera_flip->setHidden(image_source == 0);
|
2018-05-11 19:42:23 +02:00
|
|
|
}
|
|
|
|
|
2019-05-26 06:39:23 +02:00
|
|
|
void ConfigureCamera::RecordConfig() {
|
2018-05-11 19:42:23 +02:00
|
|
|
std::string implementation = Implementations[ui->image_source->currentIndex()];
|
|
|
|
int image_source = ui->image_source->currentIndex();
|
|
|
|
std::string config;
|
|
|
|
if (image_source == 2) { /* system camera */
|
|
|
|
if (ui->system_camera->currentIndex() == 0) {
|
|
|
|
config = "";
|
|
|
|
} else {
|
|
|
|
config = ui->system_camera->currentText().toStdString();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
config = ui->camera_file->text().toStdString();
|
|
|
|
}
|
|
|
|
if (current_selected == CameraPosition::RearBoth) {
|
|
|
|
camera_name[0] = camera_name[2] = implementation;
|
|
|
|
camera_config[0] = camera_config[2] = config;
|
2018-05-20 03:07:37 +02:00
|
|
|
camera_flip[0] = camera_flip[2] = ui->camera_flip->currentIndex();
|
2018-05-11 19:42:23 +02:00
|
|
|
} else if (current_selected != CameraPosition::Null) {
|
|
|
|
int index = static_cast<int>(current_selected);
|
|
|
|
camera_name[index] = implementation;
|
|
|
|
camera_config[index] = config;
|
2018-05-20 03:07:37 +02:00
|
|
|
camera_flip[index] = ui->camera_flip->currentIndex();
|
2018-05-11 19:42:23 +02:00
|
|
|
}
|
2019-05-26 06:39:23 +02:00
|
|
|
current_selected = GetCameraSelection();
|
2018-05-11 19:42:23 +02:00
|
|
|
}
|
|
|
|
|
2019-05-26 06:39:23 +02:00
|
|
|
void ConfigureCamera::StartPreviewing() {
|
|
|
|
current_selected = GetCameraSelection();
|
|
|
|
RecordConfig();
|
|
|
|
int camera_selection = GetSelectedCameraIndex();
|
|
|
|
StopPreviewing();
|
2018-05-11 19:42:23 +02:00
|
|
|
// Init preview box
|
|
|
|
ui->preview_box->setHidden(false);
|
|
|
|
ui->preview_button->setHidden(true);
|
|
|
|
preview_width = ui->preview_box->size().width();
|
|
|
|
preview_height = preview_width * 0.75;
|
|
|
|
ui->preview_box->setToolTip(tr("Resolution: ") + QString::number(preview_width) + "*" +
|
|
|
|
QString::number(preview_height));
|
|
|
|
// Load previewing camera
|
2018-05-20 03:07:37 +02:00
|
|
|
previewing_camera = Camera::CreateCameraPreview(
|
|
|
|
camera_name[camera_selection], camera_config[camera_selection], preview_width,
|
|
|
|
preview_height, static_cast<Service::CAM::Flip>(camera_flip[camera_selection]));
|
2018-05-11 19:42:23 +02:00
|
|
|
if (!previewing_camera) {
|
2019-05-26 06:39:23 +02:00
|
|
|
StopPreviewing();
|
2018-05-11 19:42:23 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
previewing_camera->SetResolution(
|
|
|
|
{static_cast<u16>(preview_width), static_cast<u16>(preview_height)});
|
|
|
|
previewing_camera->SetEffect(Service::CAM::Effect::None);
|
|
|
|
previewing_camera->SetFlip(Service::CAM::Flip::None);
|
|
|
|
previewing_camera->SetFormat(Service::CAM::OutputFormat::RGB565);
|
|
|
|
previewing_camera->SetFrameRate(Service::CAM::FrameRate::Rate_30);
|
|
|
|
previewing_camera->StartCapture();
|
|
|
|
|
|
|
|
timer_id = startTimer(1000 / 30);
|
|
|
|
}
|
|
|
|
|
2019-05-26 06:39:23 +02:00
|
|
|
void ConfigureCamera::StopPreviewing() {
|
2018-05-11 19:42:23 +02:00
|
|
|
ui->preview_box->setHidden(true);
|
|
|
|
ui->preview_button->setHidden(false);
|
|
|
|
|
|
|
|
if (previewing_camera) {
|
|
|
|
previewing_camera->StopCapture();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (timer_id != 0) {
|
|
|
|
killTimer(timer_id);
|
|
|
|
timer_id = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ConfigureCamera::timerEvent(QTimerEvent* event) {
|
|
|
|
if (event->timerId() != timer_id) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!previewing_camera) {
|
|
|
|
killTimer(timer_id);
|
|
|
|
timer_id = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
std::vector<u16> frame = previewing_camera->ReceiveFrame();
|
|
|
|
int width = ui->preview_box->size().width();
|
|
|
|
int height = width * 0.75;
|
|
|
|
if (width != preview_width || height != preview_height) {
|
2019-05-26 06:39:23 +02:00
|
|
|
StopPreviewing();
|
2018-05-11 19:42:23 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
QImage image(width, height, QImage::Format::Format_RGB16);
|
|
|
|
std::memcpy(image.bits(), frame.data(), width * height * sizeof(u16));
|
|
|
|
ui->preview_box->setPixmap(QPixmap::fromImage(image));
|
|
|
|
}
|
|
|
|
|
2019-05-26 06:39:23 +02:00
|
|
|
void ConfigureCamera::SetConfiguration() {
|
|
|
|
int index = GetSelectedCameraIndex();
|
2019-07-14 19:26:06 +02:00
|
|
|
for (std::size_t i = 0; i < Implementations.size(); i++) {
|
2018-05-11 19:42:23 +02:00
|
|
|
if (Implementations[i] == camera_name[index]) {
|
|
|
|
ui->image_source->setCurrentIndex(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (camera_name[index] == "image") {
|
|
|
|
ui->camera_file->setDisabled(camera_config[index].empty());
|
|
|
|
ui->toolButton->setDisabled(camera_config[index].empty());
|
|
|
|
if (camera_config[index].empty()) {
|
2019-07-26 21:11:14 +02:00
|
|
|
ui->camera_file->setText(QString{});
|
2018-05-11 19:42:23 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (camera_name[index] == "qt") {
|
|
|
|
ui->system_camera->setCurrentIndex(0);
|
|
|
|
if (!camera_config[index].empty()) {
|
|
|
|
ui->system_camera->setCurrentText(QString::fromStdString(camera_config[index]));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ui->camera_file->setText(QString::fromStdString(camera_config[index]));
|
|
|
|
}
|
2018-05-20 03:07:37 +02:00
|
|
|
ui->camera_flip->setCurrentIndex(camera_flip[index]);
|
2019-05-26 06:39:23 +02:00
|
|
|
UpdateImageSourceUI();
|
2018-05-11 19:42:23 +02:00
|
|
|
}
|
|
|
|
|
2019-05-26 06:39:23 +02:00
|
|
|
void ConfigureCamera::OnToolButtonClicked() {
|
|
|
|
StopPreviewing();
|
2018-06-28 16:35:12 +02:00
|
|
|
QList<QByteArray> types = QImageReader::supportedImageFormats();
|
|
|
|
QList<QString> temp_filters;
|
|
|
|
for (const QByteArray& type : types) {
|
2019-07-26 21:11:14 +02:00
|
|
|
temp_filters << QString("*." + QString::fromUtf8(type));
|
2018-05-11 19:42:23 +02:00
|
|
|
}
|
2019-07-26 21:11:14 +02:00
|
|
|
QString filter = tr("Supported image files (%1)").arg(temp_filters.join(QStringLiteral(" ")));
|
|
|
|
QString path = QFileDialog::getOpenFileName(this, tr("Open File"), QStringLiteral("."), filter);
|
2018-05-11 19:42:23 +02:00
|
|
|
if (!path.isEmpty()) {
|
|
|
|
ui->camera_file->setText(path);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-26 06:39:23 +02:00
|
|
|
void ConfigureCamera::ApplyConfiguration() {
|
|
|
|
RecordConfig();
|
|
|
|
StopPreviewing();
|
2018-05-11 19:42:23 +02:00
|
|
|
Settings::values.camera_name = camera_name;
|
|
|
|
Settings::values.camera_config = camera_config;
|
2018-05-20 03:07:37 +02:00
|
|
|
Settings::values.camera_flip = camera_flip;
|
2018-05-11 19:42:23 +02:00
|
|
|
}
|
|
|
|
|
2019-05-26 06:39:23 +02:00
|
|
|
ConfigureCamera::CameraPosition ConfigureCamera::GetCameraSelection() {
|
2018-05-11 19:42:23 +02:00
|
|
|
switch (ui->camera_selection->currentIndex()) {
|
|
|
|
case 0: // Front
|
|
|
|
return CameraPosition::Front;
|
|
|
|
case 1: // Rear
|
|
|
|
if (ui->camera_mode->currentIndex() == 0) {
|
|
|
|
// Single (2D) mode
|
|
|
|
return CameraPosition::RearBoth;
|
|
|
|
} else {
|
|
|
|
// Double (3D) mode
|
|
|
|
return (ui->camera_position->currentIndex() == 0) ? CameraPosition::RearLeft
|
|
|
|
: CameraPosition::RearRight;
|
|
|
|
}
|
|
|
|
default:
|
2018-06-29 13:18:07 +02:00
|
|
|
LOG_ERROR(Frontend, "Unknown camera selection");
|
2018-05-11 19:42:23 +02:00
|
|
|
return CameraPosition::Front;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-26 06:39:23 +02:00
|
|
|
int ConfigureCamera::GetSelectedCameraIndex() {
|
|
|
|
CameraPosition pos = GetCameraSelection();
|
2018-05-11 19:42:23 +02:00
|
|
|
int camera_selection = static_cast<int>(pos);
|
|
|
|
if (pos == CameraPosition::RearBoth) { // Single Mode
|
|
|
|
camera_selection = 0; // Either camera is the same, so we return RearRight
|
|
|
|
}
|
|
|
|
return camera_selection;
|
|
|
|
}
|
|
|
|
|
2019-05-26 06:39:23 +02:00
|
|
|
void ConfigureCamera::RetranslateUI() {
|
2018-05-11 19:42:23 +02:00
|
|
|
ui->retranslateUi(this);
|
|
|
|
}
|