/** @file vrsettingsdialog.cpp Settings for virtual reality. * * @authors Copyright (c) 2013-2017 Jaakko Keränen * * @par License * GPL: http://www.gnu.org/licenses/gpl.html * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. This program is distributed in the hope that it * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General * Public License for more details. You should have received a copy of the GNU * General Public License along with this program; if not, see: * http://www.gnu.org/licenses */ #include "ui/dialogs/vrsettingsdialog.h" #include "ui/widgets/cvarsliderwidget.h" #include "ui/widgets/cvartogglewidget.h" #include "ui/widgets/cvarchoicewidget.h" #include "render/vr.h" #include "clientapp.h" #include "api_console.h" #include #include #include #include #include "CommandAction" using namespace de; using namespace de::ui; DENG_GUI_PIMPL(VRSettingsDialog) { CVarChoiceWidget *mode; CVarToggleWidget *swapEyes; CVarSliderWidget *dominantEye; CVarSliderWidget *humanHeight; CVarSliderWidget *ipd; VariableSliderWidget *riftDensity; CVarSliderWidget *riftSamples; ButtonWidget *riftReset; ButtonWidget *riftSetup; ButtonWidget *desktopSetup; Impl(Public *i) : Base(i) , riftReset(0) , riftSetup(0) { ScrollAreaWidget &area = self().area(); area.add(mode = new CVarChoiceWidget("rend-vr-mode")); mode->items() << new ChoiceItem(tr("No stereo"), VRConfig::Mono) << new ChoiceItem(tr("Anaglyph (green/magenta)"), VRConfig::GreenMagenta) << new ChoiceItem(tr("Anaglyph (red/cyan)"), VRConfig::RedCyan) << new ChoiceItem(tr("Left eye only"), VRConfig::LeftOnly) << new ChoiceItem(tr("Right eye only"), VRConfig::RightOnly) << new ChoiceItem(tr("Top/bottom"), VRConfig::TopBottom) << new ChoiceItem(tr("Side-by-side"), VRConfig::SideBySide) << new ChoiceItem(tr("Parallel"), VRConfig::Parallel) << new ChoiceItem(tr("Cross-eye"), VRConfig::CrossEye) << new ChoiceItem(tr("Hardware stereo"), VRConfig::QuadBuffered) << new ChoiceItem(tr("Row interleaved"), VRConfig::RowInterleaved) ; if (vrCfg().oculusRift().isEnabled()) { mode->items() << new ChoiceItem(tr("Oculus Rift"), VRConfig::OculusRift); } area.add(swapEyes = new CVarToggleWidget("rend-vr-swap-eyes", tr("Swap Eyes"))); area.add(dominantEye = new CVarSliderWidget("rend-vr-dominant-eye")); area.add(humanHeight = new CVarSliderWidget("rend-vr-player-height")); area.add(riftSamples = new CVarSliderWidget("rend-vr-rift-samples")); area.add(ipd = new CVarSliderWidget("rend-vr-ipd")); ipd->setDisplayFactor(1000); ipd->setPrecision(1); if (vrCfg().oculusRift().isReady()) { area.add(riftDensity = new VariableSliderWidget(App::config("vr.oculusRift.pixelDensity"), Ranged(0.5, 1.0), .01)); riftDensity->setPrecision(2); area.add(riftReset = new ButtonWidget); riftReset->setText(tr("Recenter Tracking")); riftReset->setAction(new CommandAction("resetriftpose")); area.add(riftSetup = new ButtonWidget); riftSetup->setText(tr("Apply Rift Settings")); riftSetup->setAction(new SignalAction(thisPublic, SLOT(autoConfigForOculusRift()))); } area.add(desktopSetup = new ButtonWidget); desktopSetup->setText(tr("Apply Desktop Settings")); desktopSetup->setAction(new SignalAction(thisPublic, SLOT(autoConfigForDesktop()))); } void fetch() { foreach (GuiWidget *child, self().area().childWidgets()) { if (ICVarWidget *w = maybeAs(child)) { w->updateFromCVar(); } } } }; VRSettingsDialog::VRSettingsDialog(String const &name) : DialogWidget(name, WithHeading), d(new Impl(this)) { heading().setText(tr("3D & VR Settings")); heading().setImage(style().images().image("vr")); LabelWidget *modeLabel = LabelWidget::newWithText(tr("Stereo Mode:"), &area()); LabelWidget *heightLabel = LabelWidget::newWithText(tr("Height (m):"), &area()); LabelWidget *ipdLabel = LabelWidget::newWithText(tr("IPD (mm):"), &area()); LabelWidget *dominantLabel = LabelWidget::newWithText(tr("Dominant Eye:"), &area()); // Layout. GridLayout layout(area().contentRule().left(), area().contentRule().top()); layout.setGridSize(2, 0); layout.setColumnAlignment(0, ui::AlignRight); layout << *modeLabel << *d->mode << *heightLabel << *d->humanHeight << *ipdLabel << *d->ipd << *dominantLabel << *d->dominantEye << Const(0) << *d->swapEyes; #ifdef DENG_HAVE_OCULUS_API LabelWidget *ovrLabel = LabelWidget::newWithText(_E(D) + tr("Oculus Rift"), &area()); LabelWidget *sampleLabel = LabelWidget::newWithText(tr("Multisampling:"), &area()); ovrLabel->setFont("separator.label"); ovrLabel->margins().setTop("gap"); sampleLabel->setTextLineAlignment(ui::AlignRight); layout.setCellAlignment(Vector2i(0, 5), ui::AlignLeft); layout.append(*ovrLabel, 2); LabelWidget *utilLabel = LabelWidget::newWithText(tr("Utilities:"), &area()); if (vrCfg().oculusRift().isReady()) { layout << *sampleLabel << *d->riftSamples << *LabelWidget::newWithText(tr("Pixel Density:"), &area()) << *d->riftDensity; layout << *utilLabel << *d->riftReset << Const(0) << *d->riftSetup << Const(0) << *d->desktopSetup; } else { layout << *utilLabel << *d->desktopSetup; } #endif area().setContentSize(layout); buttons() << new DialogButtonItem(DialogWidget::Default | DialogWidget::Accept, tr("Close")) << new DialogButtonItem(DialogWidget::Action, tr("Reset to Defaults"), new SignalAction(this, SLOT(resetToDefaults()))); d->fetch(); } void VRSettingsDialog::resetToDefaults() { Con_SetInteger("rend-vr-mode", VRConfig::Mono); Con_SetInteger("rend-vr-swap-eyes", 0); Con_SetFloat ("rend-vr-dominant-eye", 0); Con_SetFloat ("rend-vr-player-height", 1.75f); Con_SetFloat ("rend-vr-ipd", 0.064f); Con_SetFloat ("rend-vr-rift-latency", 0.030f); Con_SetInteger("rend-vr-rift-samples", 2); d->fetch(); } void VRSettingsDialog::autoConfigForOculusRift() { //Con_Execute(CMDS_DDAY, "setfullres 1280 800", false, false); Con_Execute(CMDS_DDAY, "bindcontrol lookpitch head-pitch", false, false); Con_Execute(CMDS_DDAY, "bindcontrol yawbody head-yaw", false, false); /// @todo This would be a good use case for cvar overriding. -jk Con_SetInteger("rend-vr-mode", VRConfig::OculusRift); App::config().set("window.main.fsaa", false); Con_SetFloat ("vid-gamma", 1.176f); Con_SetFloat ("vid-contrast", 1.186f); Con_SetFloat ("vid-bright", .034f); Con_SetFloat ("view-bob-height", .2f); Con_SetFloat ("msg-scale", 1); Con_SetFloat ("hud-scale", 1); d->fetch(); ClientApp::vr().oculusRift().moveWindowToScreen(OculusRift::HMDScreen); } void VRSettingsDialog::autoConfigForDesktop() { Con_SetInteger("rend-vr-mode", VRConfig::Mono); Con_SetFloat ("vid-gamma", 1); Con_SetFloat ("vid-contrast", 1); Con_SetFloat ("vid-bright", 0); Con_SetFloat ("view-bob-height", 1); Con_SetFloat ("msg-scale", .8f); Con_SetFloat ("hud-scale", .6f); d->fetch(); ClientApp::vr().oculusRift().moveWindowToScreen(OculusRift::DefaultScreen); }