1 /*
2 
3 	Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
4 	and the "Aleph One" developers.
5 
6 	This program is free software; you can redistribute it and/or modify
7 	it under the terms of the GNU General Public License as published by
8 	the Free Software Foundation; either version 3 of the License, or
9 	(at your option) any later version.
10 
11 	This program is distributed in the hope that it will be useful,
12 	but WITHOUT ANY WARRANTY; without even the implied warranty of
13 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 	GNU General Public License for more details.
15 
16 	This license is contained in the file "COPYING",
17 	which is included with this source code; it is available online at
18 	http://www.gnu.org/licenses/gpl.html
19 
20 */
21 
22 /*
23  *  mouse_sdl.cpp - Mouse handling, SDL specific implementation
24  *
25  *  May 16, 2002 (Woody Zenfell):
26  *      Configurable mouse sensitivity
27  *      Semi-hacky scheme to let mouse buttons simulate keypresses
28  */
29 
30 #include "cseries.h"
31 #include <math.h>
32 
33 #include "mouse.h"
34 #include "player.h"
35 #include "shell.h"
36 #include "preferences.h"
37 #include "screen.h"
38 
39 #ifdef __APPLE__
40 #include "mouse_cocoa.h"
41 #endif
42 
43 
44 // Global variables
45 static bool mouse_active = false;
46 static uint8 button_mask = 0;		// Mask of enabled buttons
47 static fixed_yaw_pitch mouselook_delta = {0, 0};
48 static _fixed snapshot_delta_scrollwheel;
49 static int snapshot_delta_x, snapshot_delta_y;
50 
51 
52 /*
53  *  Initialize in-game mouse handling
54  */
55 
enter_mouse(short type)56 void enter_mouse(short type)
57 {
58 	if (type != _keyboard_or_game_pad) {
59 #ifdef __APPLE__
60 		if (input_preferences->raw_mouse_input)
61 			OSX_Mouse_Init();
62 #endif
63 		SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_MODE_WARP, input_preferences->raw_mouse_input ? "0" : "1");
64 		SDL_SetRelativeMouseMode(SDL_TRUE);
65 		mouse_active = true;
66 		mouselook_delta = {0, 0};
67 		snapshot_delta_scrollwheel = 0;
68 		snapshot_delta_x = snapshot_delta_y = 0;
69 		button_mask = 0;	// Disable all buttons (so a shot won't be fired if we enter the game with a mouse button down from clicking a GUI widget)
70 		recenter_mouse();
71 	}
72 }
73 
74 
75 /*
76  *  Shutdown in-game mouse handling
77  */
78 
exit_mouse(short type)79 void exit_mouse(short type)
80 {
81 	if (type != _keyboard_or_game_pad) {
82 		SDL_SetRelativeMouseMode(SDL_FALSE);
83 		mouse_active = false;
84 #ifdef __APPLE__
85 		OSX_Mouse_Shutdown();
86 #endif
87 	}
88 }
89 
90 
91 /*
92  *  Calculate new center mouse position when screen size has changed
93  */
94 
recenter_mouse(void)95 void recenter_mouse(void)
96 {
97 	if (mouse_active) {
98 		MainScreenCenterMouse();
99 	}
100 }
101 
MIX(float start,float end,float factor)102 static inline float MIX(float start, float end, float factor)
103 {
104 	return (start * (1.f - factor)) + (end * factor);
105 }
106 
107 /*
108  *  Take a snapshot of the current mouse state
109  */
110 
mouse_idle(short type)111 void mouse_idle(short type)
112 {
113 	if (mouse_active) {
114 #ifdef __APPLE__
115 		// In raw mode, get unaccelerated deltas from HID system
116 		if (input_preferences->raw_mouse_input)
117 			OSX_Mouse_GetMouseMovement(&snapshot_delta_x, &snapshot_delta_y);
118 #endif
119 
120 		// Calculate axis deltas
121 		float dx = snapshot_delta_x;
122 		float dy = -snapshot_delta_y;
123 		snapshot_delta_x = 0;
124 		snapshot_delta_y = 0;
125 
126 		// Mouse inversion
127 		if (TEST_FLAG(input_preferences->modifiers, _inputmod_invert_mouse))
128 			dy = -dy;
129 
130 		// Delta sensitivities
131 		const float angle_per_scaled_delta = 128/66.f; // assuming _mouse_accel_none
132 		float sx = angle_per_scaled_delta * (input_preferences->sens_horizontal / float{FIXED_ONE});
133 		float sy = angle_per_scaled_delta * (input_preferences->sens_vertical / float{FIXED_ONE}) * (input_preferences->classic_vertical_aim ? 0.25f : 1.f);
134 		switch (input_preferences->mouse_accel_type)
135 		{
136 			case _mouse_accel_classic:
137 				sx *= MIX(1.f, (1/32.f) * fabs(dx * sx), input_preferences->mouse_accel_scale);
138 				sy *= MIX(1.f, (1/(input_preferences->classic_vertical_aim ? 8.f : 32.f)) * fabs(dy * sy), input_preferences->mouse_accel_scale);
139 				break;
140 			case _mouse_accel_none:
141 			default:
142 				break;
143 		}
144 
145 		// Angular deltas
146 		const fixed_angle dyaw = static_cast<fixed_angle>(sx * dx * FIXED_ONE);
147 		const fixed_angle dpitch = static_cast<fixed_angle>(sy * dy * FIXED_ONE);
148 
149 		// Push mouselook delta
150 		mouselook_delta = {dyaw, dpitch};
151 	}
152 }
153 
pull_mouselook_delta()154 fixed_yaw_pitch pull_mouselook_delta()
155 {
156 	auto delta = mouselook_delta;
157 	mouselook_delta = {0, 0};
158 	return delta;
159 }
160 
161 
162 void
mouse_buttons_become_keypresses(Uint8 * ioKeyMap)163 mouse_buttons_become_keypresses(Uint8* ioKeyMap)
164 {
165 		uint8 buttons = SDL_GetMouseState(NULL, NULL);
166 		uint8 orig_buttons = buttons;
167 		buttons &= button_mask;				// Mask out disabled buttons
168 
169         for(int i = 0; i < NUM_SDL_REAL_MOUSE_BUTTONS; i++) {
170             ioKeyMap[AO_SCANCODE_BASE_MOUSE_BUTTON + i] =
171                 (buttons & SDL_BUTTON(i+1)) ? SDL_PRESSED : SDL_RELEASED;
172         }
173 		ioKeyMap[AO_SCANCODE_MOUSESCROLL_UP] = (snapshot_delta_scrollwheel > 0) ? SDL_PRESSED : SDL_RELEASED;
174 		ioKeyMap[AO_SCANCODE_MOUSESCROLL_DOWN] = (snapshot_delta_scrollwheel < 0) ? SDL_PRESSED : SDL_RELEASED;
175 		snapshot_delta_scrollwheel = 0;
176 
177         button_mask |= ~orig_buttons;		// A button must be released at least once to become enabled
178 }
179 
180 /*
181  *  Hide/show mouse pointer
182  */
183 
hide_cursor(void)184 void hide_cursor(void)
185 {
186 	SDL_ShowCursor(0);
187 }
188 
show_cursor(void)189 void show_cursor(void)
190 {
191 	SDL_ShowCursor(1);
192 }
193 
194 
mouse_scroll(bool up)195 void mouse_scroll(bool up)
196 {
197 	if (up)
198 		snapshot_delta_scrollwheel += 1;
199 	else
200 		snapshot_delta_scrollwheel -= 1;
201 }
202 
mouse_moved(int delta_x,int delta_y)203 void mouse_moved(int delta_x, int delta_y)
204 {
205 	snapshot_delta_x += delta_x;
206 	snapshot_delta_y += delta_y;
207 }
208