1 /************************************************************************************
2
3 AstroMenace
4 Hardcore 3D space scroll-shooter with spaceship upgrade possibilities.
5 Copyright (c) 2006-2019 Mikhail Kurinnoi, Viewizard
6
7
8 AstroMenace is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 AstroMenace is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with AstroMenace. If not, see <https://www.gnu.org/licenses/>.
20
21
22 Website: https://viewizard.com/
23 Project: https://github.com/viewizard/astromenace
24 E-mail: viewizard@viewizard.com
25
26 *************************************************************************************/
27
28 // TODO move to SDL_GetTicks() usage
29
30 // TODO add support for SDL_INIT_HAPTIC (force feedback)
31
32 // NOTE SDL2 also provide SDL_INIT_GAMECONTROLLER now
33
34 /*
35 At this time we don't provide menu options to choose joystick, first one (with index 0) will be used by default.
36 Which Joystick should be used, could be configured via config file, "JoystickNum" parameter.
37 */
38
39 #include "../core/core.h"
40 #include "../config/config.h"
41 #include "platform.h"
42
43 // NOTE switch to nested namespace definition (namespace A::B::C { ... }) (since C++17)
44 namespace viewizard {
45 namespace astromenace {
46
47 namespace {
48
49 SDL_Joystick *Joystick{nullptr};
50 int JoystickAxisX{0};
51 int JoystickAxisY{0};
52 int JoystickButtonsQuantity{0};
53 std::vector<bool> JoystickButtons{};
54
55 float JoystickCurrentTime{0.0f};
56 float JoystickTimeDelta{0.0f};
57
58 } // unnamed namespace
59
60
61 /*
62 * Joystick (re)initialization.
63 */
JoystickInit(float InitialTime)64 bool JoystickInit(float InitialTime)
65 {
66 JoystickClose(); // since we could reinit joystick, close it first
67
68 if (SDL_NumJoysticks() <= 0)
69 return false;
70
71 std::cout << "Found Joystick(s):\n";
72 for (int i = 0; i < SDL_NumJoysticks(); i++) {
73 std::cout << "Joystick Name " << i << ": " << SDL_JoystickNameForIndex(i) << "\n";
74 }
75
76 if (GameConfig().JoystickNum >= SDL_NumJoysticks())
77 ChangeGameConfig().JoystickNum = 0;
78
79 Joystick = SDL_JoystickOpen(GameConfig().JoystickNum);
80
81 if (Joystick) {
82 std::cout << "Opened Joystick " << GameConfig().JoystickNum << "\n"
83 << "Joystick Name: " << SDL_JoystickNameForIndex(GameConfig().JoystickNum) << "\n"
84 << "Joystick Number of Axes: " << SDL_JoystickNumAxes(Joystick) << "\n"
85 << "Joystick Number of Buttons: " << SDL_JoystickNumButtons(Joystick) << "\n"
86 << "Joystick Number of Balls: " << SDL_JoystickNumBalls(Joystick) << "\n\n";
87 } else {
88 std::cerr << __func__ << "(): " << "SDL_JoystickOpen() failed: " << SDL_GetError() << "\n";
89 std::cout << "Couldn't open Joystick " << GameConfig().JoystickNum << "\n\n";
90 return false;
91 }
92
93 JoystickCurrentTime = InitialTime;
94 JoystickTimeDelta = 0.0f;
95
96 JoystickAxisX = SDL_JoystickGetAxis(Joystick, 0);
97 JoystickAxisY = SDL_JoystickGetAxis(Joystick, 1);
98 JoystickButtonsQuantity = SDL_JoystickNumButtons(Joystick);
99 JoystickButtons.resize(JoystickButtonsQuantity, false);
100
101 return true;
102 }
103
104 /*
105 * Close joystick.
106 */
JoystickClose()107 void JoystickClose()
108 {
109 if (!Joystick)
110 return;
111
112 if (SDL_JoystickGetAttached(Joystick))
113 SDL_JoystickClose(Joystick);
114
115 Joystick = nullptr;
116 JoystickButtons.clear();
117 }
118
119 /*
120 * Check current joystick status (opened or not).
121 */
isJoystickAvailable()122 bool isJoystickAvailable()
123 {
124 return Joystick;
125 }
126
127 /*
128 * Get current opened joystick buttons quantity.
129 */
GetJoystickButtonsQuantity()130 int GetJoystickButtonsQuantity()
131 {
132 if (!Joystick)
133 return 0;
134
135 return JoystickButtonsQuantity;
136 }
137
138 /*
139 * Set joystick button status.
140 */
SetJoystickButton(int ButtonNumber,bool ButtonStatus)141 void SetJoystickButton(int ButtonNumber, bool ButtonStatus)
142 {
143 if (!Joystick ||
144 // we may have config that was made previously with another joystick
145 // don't change game's config, just ignore this buttons check
146 (ButtonNumber < 0) ||
147 (ButtonNumber >= JoystickButtonsQuantity))
148 return;
149
150 JoystickButtons[ButtonNumber] = ButtonStatus;
151 }
152
153 /*
154 * Get joystick button status.
155 */
GetJoystickButton(int ButtonNumber)156 bool GetJoystickButton(int ButtonNumber)
157 {
158 if (!Joystick ||
159 // we may have config that was made previously with another joystick
160 // don't change game's config, just ignore this buttons check
161 (ButtonNumber < 0) ||
162 (ButtonNumber >= JoystickButtonsQuantity))
163 return false;
164
165 return JoystickButtons[ButtonNumber];
166 }
167
168 /*
169 * Emulate mouse movements.
170 */
JoystickEmulateMouseMovement(float Time)171 void JoystickEmulateMouseMovement(float Time)
172 {
173 if (!Joystick)
174 return;
175
176 JoystickTimeDelta = Time - JoystickCurrentTime;
177 JoystickCurrentTime = Time;
178
179 int X = SDL_JoystickGetAxis(Joystick, 0);
180 int Y = SDL_JoystickGetAxis(Joystick, 1);
181
182 // JoystickDeadZone: [0, 10]
183 // min/max joystick axis value: -32768/32767
184 // we are using 3000 here, since dead zone should not be same small/big as min/max joystick axis values
185 if (abs(X) < (GameConfig().JoystickDeadZone * 3000))
186 X = 0;
187 if (abs(Y) < (GameConfig().JoystickDeadZone * 3000))
188 Y = 0;
189
190 if ((JoystickAxisX != X) || (JoystickAxisY != Y)) {
191 JoystickAxisX = 0;
192 JoystickAxisY = 0;
193
194 // InternalWidth here, since during one second we should move cursor from left to right
195 int Xsm{static_cast<int>(GameConfig().InternalWidth * (X / 32768.0f) * JoystickTimeDelta)};
196 int Ysm{static_cast<int>(GameConfig().InternalWidth * (Y / 32768.0f) * JoystickTimeDelta)};
197
198 vw_SetMousePosRel(Xsm, Ysm);
199 }
200 }
201
202 /*
203 * Provide joystick button's name - "ButtonN", where N is number.
204 */
JoystickButtonName(int ButtonNum)205 std::string JoystickButtonName(int ButtonNum)
206 {
207 if (ButtonNum < 0)
208 return "?";
209
210 // ButtonNum + 1, since buttons index start from 0
211 return vw_GetText("Button") + std::to_string(ButtonNum + 1);
212 }
213
214 } // astromenace namespace
215 } // viewizard namespace
216