1 /**
2 * Mandelbulber v2, a 3D fractal generator ,=#MKNmMMKmmßMNWy,
3 * ,B" ]L,,p%%%,,,§;, "K
4 * Copyright (C) 2016-21 Mandelbulber Team §R-==%w["'~5]m%=L.=~5N
5 * ,=mm=§M ]=4 yJKA"/-Nsaj "Bw,==,,
6 * This file is part of Mandelbulber. §R.r= jw",M Km .mM FW ",§=ß., ,TN
7 * ,4R =%["w[N=7]J '"5=],""]]M,w,-; T=]M
8 * Mandelbulber is free software: §R.ß~-Q/M=,=5"v"]=Qf,'§"M= =,M.§ Rz]M"Kw
9 * you can redistribute it and/or §w "xDY.J ' -"m=====WeC=\ ""%""y=%"]"" §
10 * modify it under the terms of the "§M=M =D=4"N #"%==A%p M§ M6 R' #"=~.4M
11 * GNU General Public License as §W =, ][T"]C § § '§ e===~ U !§[Z ]N
12 * published by the 4M",,Jm=,"=e~ § § j]]""N BmM"py=ßM
13 * Free Software Foundation, ]§ T,M=& 'YmMMpM9MMM%=w=,,=MT]M m§;'§,
14 * either version 3 of the License, TWw [.j"5=~N[=§%=%W,T ]R,"=="Y[LFT ]N
15 * or (at your option) TW=,-#"%=;[ =Q:["V"" ],,M.m == ]N
16 * any later version. J§"mr"] ,=,," =="""J]= M"M"]==ß"
17 * §= "=C=4 §"eM "=B:m|4"]#F,§~
18 * Mandelbulber is distributed in "9w=,,]w em%wJ '"~" ,=,,ß"
19 * the hope that it will be useful, . "K= ,=RMMMßM"""
20 * but WITHOUT ANY WARRANTY; .'''
21 * without even the implied warranty
22 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
23 *
24 * See the GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with Mandelbulber. If not, see <http://www.gnu.org/licenses/>.
27 *
28 * ###########################################################################
29 *
30 * Authors: Krzysztof Marczak (buddhi1980@gmail.com), Robert Pancoast (RobertPancoast77@gmail.com)
31 *
32 * These objects enable control of flight animation using a gamepad controller.
33 */
34
35 #include "dock_gamepad.h"
36
37 #include "ui_dock_gamepad.h"
38
39 #include "src/automated_widgets.hpp"
40 #include "src/interface.hpp"
41 #include "src/rendered_image_widget.hpp"
42 #include "src/write_log.hpp"
43
cDockGamepad(QWidget * parent)44 cDockGamepad::cDockGamepad(QWidget *parent) : QWidget(parent), ui(new Ui::cDockGamepad)
45 {
46 ui->setupUi(this);
47 automatedWidgets = new cAutomatedWidgets(this);
48 automatedWidgets->ConnectSignalsForSlidersInWindow(this);
49 ConnectSignals();
50
51 #ifdef USE_GAMEPAD
52 QList<int> deviceIds = QGamepadManager::instance()->connectedGamepads();
53 if (deviceIds.size() > 0) gamepad.setDeviceId(deviceIds[0]);
54 populateGamepadList();
55 #endif
56 }
57
~cDockGamepad()58 cDockGamepad::~cDockGamepad()
59 {
60 delete ui;
61 }
62
ConnectSignals() const63 void cDockGamepad::ConnectSignals() const
64 {
65 #ifdef USE_GAMEPAD
66 connect(ui->comboBox_gamepad_device, SIGNAL(currentIndexChanged(int)), this,
67 SLOT(slotChangeGamepadIndex(int)));
68
69 // Left Joystick controls Look Angle
70 connect(&gamepad, SIGNAL(axisLeftYChanged(double)), this, SLOT(slotGamepadLook()));
71 connect(&gamepad, SIGNAL(axisLeftXChanged(double)), this, SLOT(slotGamepadLook()));
72
73 // Right Joystick controls Movement Direction
74 connect(&gamepad, SIGNAL(axisRightXChanged(double)), this, SLOT(slotGamepadMove()));
75 connect(&gamepad, SIGNAL(axisRightYChanged(double)), this, SLOT(slotGamepadMove()));
76
77 // Left and Right Triggers control Reverse and Accelerator
78 connect(&gamepad, SIGNAL(buttonL2Changed(double)), this, SLOT(slotGamepadMove()));
79 connect(&gamepad, SIGNAL(buttonR2Changed(double)), this, SLOT(slotGamepadMove()));
80
81 // Start Button will pause the flight
82 connect(&gamepad, SIGNAL(buttonStartChanged(bool)), this, SLOT(slotGamepadPause(bool)));
83
84 // Left and Right Shoulder Buttons control Roll Rotation
85 connect(&gamepad, SIGNAL(buttonL1Changed(bool)), this, SLOT(slotGamepadRoll()));
86 connect(&gamepad, SIGNAL(buttonR1Changed(bool)), this, SLOT(slotGamepadRoll()));
87
88 // A and B buttons control the Movement Speed
89 connect(&gamepad, SIGNAL(buttonAChanged(bool)), this, SLOT(slotGamepadSpeed()));
90 connect(&gamepad, SIGNAL(buttonBChanged(bool)), this, SLOT(slotGamepadSpeed()));
91
92 connect(QGamepadManager::instance(), SIGNAL(gamepadConnected(int)), this,
93 SLOT(slotGamePadDeviceChanged()));
94 connect(QGamepadManager::instance(), SIGNAL(gamepadDisconnected(int)), this,
95 SLOT(slotGamePadDeviceChanged()));
96 #endif // USE_GAMEPAD
97 }
98
99 #ifdef USE_GAMEPAD
slotChangeGamepadIndex(int index)100 void cDockGamepad::slotChangeGamepadIndex(int index)
101 {
102 QList<int> deviceIds = QGamepadManager::instance()->connectedGamepads();
103 if (index < deviceIds.size() && index >= 0)
104 {
105 gamepad.setDeviceId(deviceIds[index]);
106 WriteLog("Gamepad - slotChangeGamepadIndex: " + QString::number(index), 2);
107 }
108 }
109
slotGamePadDeviceChanged() const110 void cDockGamepad::slotGamePadDeviceChanged() const
111 {
112 populateGamepadList();
113 }
114
populateGamepadList() const115 void cDockGamepad::populateGamepadList() const
116 {
117 ui->comboBox_gamepad_device->clear();
118 QList<int> deviceIds = QGamepadManager::instance()->connectedGamepads();
119
120 for (int i = 0; i < deviceIds.size(); i++)
121 {
122 QGamepad gp(deviceIds[i]);
123 QString deviceName = gp.name();
124 if (deviceName == "") deviceName = "Device #" + QString::number(i);
125 WriteLog("Gamepad - device list changed", 2);
126 ui->comboBox_gamepad_device->addItem(deviceName, i);
127 }
128 if (deviceIds.size() == 0)
129 {
130 ui->comboBox_gamepad_device->setEnabled(false);
131 ui->label_gamepad_no_device->show();
132 }
133 else
134 {
135 ui->comboBox_gamepad_device->setEnabled(true);
136 ui->label_gamepad_no_device->hide();
137 }
138 }
139
slotGamepadLook() const140 void cDockGamepad::slotGamepadLook() const
141 {
142 if (ui->groupCheck_gamepad_enabled->isChecked())
143 {
144 // Joystick Axis values vary from -1 to 0 to 1
145 const double pitch = gamepad.axisLeftX();
146 const double yaw = gamepad.axisLeftY();
147 WriteLog("Gamepad - slotGamepadLook-Yaw | value: " + QString::number(yaw), 3);
148 WriteLog("Gamepad - slotGamepadLook-Pitch | value: " + QString::number(pitch), 3);
149 ui->sl_gamepad_angle_yaw->setValue(int(100 * yaw));
150 ui->sl_gamepad_angle_pitch->setValue(int(100 * pitch));
151 const double sensitivity = 0.5;
152 CVector2<double> yawPitch(pitch, yaw);
153 yawPitch = yawPitch.Deadband() * sensitivity;
154 emit gMainInterface->renderedImage->YawAndPitchChanged(yawPitch);
155 }
156 }
157
slotGamepadMove() const158 void cDockGamepad::slotGamepadMove() const
159 {
160 if (ui->groupCheck_gamepad_enabled->isChecked())
161 {
162 // Joystick Axis values vary from -1 to 0 to 1
163 // -1 for down, and 1 for up, 0 for neutral
164 // Invert the Y Axis for right Joystick
165 const double x = gamepad.axisRightX();
166 const double y = gamepad.axisRightY() * -1.0;
167 CVector2<double> strafe(x, y);
168 double sensitivity = 5.0;
169 strafe = strafe.Deadband() * sensitivity;
170 const bool joystick = fabs(strafe.x) > 0 || fabs(strafe.y) > 0;
171 // Trigger values vary from 0 to 1
172 const double reverse = gamepad.buttonL2();
173 const double forward = gamepad.buttonR2();
174 double z = forward - reverse / 2.0;
175 const bool trigger = fabs(z) > 0;
176 WriteLog("Gamepad - slotGamepadMove-X | value: " + QString::number(x), 3);
177 WriteLog("Gamepad - slotGamepadMove-Y | value: " + QString::number(y), 3);
178 WriteLog("Gamepad - slotGamepadMove-Z | value: " + QString::number(z), 3);
179 ui->sl_gamepad_movement_x->setValue(int(100 * x));
180 ui->sl_gamepad_movement_y->setValue(int(100 * y));
181 ui->sl_gamepad_movement_z->setValue(int(100 * z));
182 // Maintain z-axis speed
183 sensitivity = 1 / 10.0;
184 const double threshold = .001;
185 z = z * sensitivity;
186 // Forward Accelerate [threshold to 1 / sensitivity]
187 if (fabs(z) < threshold && z >= 0.0) z = threshold;
188 // Reverse Backwards [-threshold to -1 / sensitivity]
189 if (fabs(z) < threshold && z <= 0.0) z = -threshold;
190 if (joystick) emit gMainInterface->renderedImage->StrafeChanged(strafe / 2.0);
191 if (trigger) emit gMainInterface->renderedImage->SpeedSet(z / 2.0);
192 }
193 }
194
slotGamepadPause(bool value)195 void cDockGamepad::slotGamepadPause(bool value)
196 {
197 if (ui->groupCheck_gamepad_enabled->isChecked())
198 {
199 if (!value)
200 {
201 WriteLog("Gamepad - slotGamepadPause | activated", 3);
202 emit gMainInterface->renderedImage->Pause();
203 }
204 }
205 }
206
slotGamepadRoll() const207 void cDockGamepad::slotGamepadRoll() const
208 {
209 if (ui->groupCheck_gamepad_enabled->isChecked())
210 {
211 // Button values are either false to true
212 double value = 0;
213 if (gamepad.buttonL1()) value += 1;
214 if (gamepad.buttonR1()) value -= 1;
215 WriteLog("Gamepad - slotGamepadRoll | value: " + QString::number(value), 3);
216 ui->sl_gamepad_angle_roll->setValue(int(100 * value));
217 emit gMainInterface->renderedImage->RotationChanged(value);
218 }
219 }
220
slotGamepadSpeed() const221 void cDockGamepad::slotGamepadSpeed() const
222 {
223 if (ui->groupCheck_gamepad_enabled->isChecked())
224 {
225 // Button values are either false to true
226 double value = 0;
227 if (gamepad.buttonA()) value += 1;
228 if (gamepad.buttonB()) value -= 1;
229 WriteLog("Gamepad - slotGamepadSpeed | value: " + QString::number(value), 3);
230 ui->sl_gamepad_movement_z->setValue(int(100 * value));
231 if (gamepad.buttonA() != gamepad.buttonB())
232 {
233 if (gamepad.buttonA())
234 {
235 emit gMainInterface->renderedImage->SpeedChanged(1.1);
236 }
237 else
238 {
239 emit gMainInterface->renderedImage->SpeedChanged(0.9);
240 }
241 }
242 }
243 }
244
245 #endif // USE_GAMEPAD
246