1 /*---------------------------------------------------------------------------*
2 Project: Dolphin Game Pad(Controller) API
3 File: Padclamp.c
4
5 Copyright (C) 1998-2006 Nintendo. All rights reserved.
6
7 These coded instructions, statements, and computer programs contain
8 proprietary information of Nintendo of America Inc. and/or Nintendo
9 Company Ltd., and are protected by Federal copyright law. They may
10 not be disclosed to third parties or copied or duplicated in any form,
11 in whole or in part, without the prior written consent of Nintendo.
12
13 $Log: Padclamp.c,v $
14 Revision 1.2 02/03/2006 00:31:59 yasuh-to
15 Changed include path for RevolutionSDK
16
17 Revision 1.1.1.1 2005/12/29 06:53:27 hiratsu
18 Initial import.
19
20 7 8/20/02 10:28:00 Shiki
21 Implemented PADClampCircle() based on Steve's code.
22
23 6 01/06/18 20:44 Shiki
24 Modified ClampRegion values.
25
26 5 01/06/18 16:29 Shiki
27 Updated for production controllers.
28
29 4 01/03/21 18:59 Shiki
30 Revised analog trigger clamping code to support DS4 and later.
31
32 3 6/13/00 7:28p Shiki
33 Added analog trigger clamping.
34
35 2 2/24/00 11:32p Shiki
36 Re-implemented for dolphin controller.
37
38 6 9/23/99 4:57p Shiki
39 Renamed 'errno' of PADStatus to 'err'.
40
41 4 5/11/99 4:39p Shiki
42 Refreshed include tree.
43
44 3 5/07/99 9:15p Shiki
45 Fixed dead-zone clamping.
46
47 2 5/06/99 8:18p Shiki
48 Renamed PADNormalize() to PADClamp()
49
50 1 5/06/99 7:04p Shiki
51
52 $NoKeywords: $
53 *---------------------------------------------------------------------------*/
54
55 #include <math.h>
56 #include <revolution/os.h>
57 #include <revolution/pad.h>
58
59 // Parameters for Dolphin controller
60
61 typedef struct PADClampRegion
62 {
63 u8 minTrigger; // the play of the trigger
64 u8 maxTrigger;
65 s8 minStick; // the play of the control stick
66 s8 maxStick;
67 s8 xyStick; // max on x = y
68 s8 minSubstick; // the play of the C stick
69 s8 maxSubstick;
70 s8 xySubstick;
71
72 s8 radStick; // max radius of the control stick
73 s8 radSubstick; // max radius of the C stick
74 } PADClampRegion;
75
76 #ifndef EMU
77
78 // GameCube Standard Controller
79 static const PADClampRegion ClampRegion =
80 {
81 30, // minTrigger
82 180, // maxTrigger
83
84 15, // minStick
85 72, // maxStick
86 40, // xyStick
87
88 15, // minSubstick
89 59, // maxSubstick
90 31, // xySubstick
91
92 56,
93 44,
94 };
95
96 #else // EMU
97
98 // Mac emulator
99 static const PADClampRegion ClampRegion =
100 {
101 40, // minTrigger
102 190, // maxTrigger
103
104 35, // minStick
105 79, // maxStick
106 47, // xyStick
107
108 35, // minSubstick
109 66, // maxSubstick
110 38, // xySubstick
111
112 56,
113 44
114 };
115
116 #endif // EMU
117
118 /*---------------------------------------------------------------------------*
119 Name: ClampStick
120
121 Description: Adjusts stick movement data within the octagon, or clamps
122 the data to the origin if stick is close to the origin as
123 the play.
124
125 Arguments: px pointer to movement data in terms of x-axis
126 py pointer to movement data in terms of y-axis
127 max max on y = 0
128 xy max on x = y
129 min deadzone
130
131 Returns: None.
132 *---------------------------------------------------------------------------*/
ClampStick(s8 * px,s8 * py,s8 max,s8 xy,s8 min)133 static void ClampStick(s8* px, s8* py, s8 max, s8 xy, s8 min)
134 {
135 int x = *px;
136 int y = *py;
137 int signX;
138 int signY;
139 int d;
140
141 if (0 <= x)
142 {
143 signX = 1;
144 }
145 else
146 {
147 signX = -1;
148 x = -x;
149 }
150
151 if (0 <= y)
152 {
153 signY = 1;
154 }
155 else
156 {
157 signY = -1;
158 y = -y;
159 }
160
161 // Clamp dead zone
162 if (x <= min)
163 {
164 x = 0;
165 }
166 else
167 {
168 x -= min;
169 }
170 if (y <= min)
171 {
172 y = 0;
173 }
174 else
175 {
176 y -= min;
177 }
178
179 if (x == 0 && y == 0)
180 {
181 *px = *py = 0;
182 return;
183 // NOT REACHED HERE
184 }
185
186 // Clamp outer octagon
187 if (xy * y <= xy * x)
188 {
189 d = xy * x + (max - xy) * y;
190 if (xy * max < d)
191 {
192 x = (s8) (xy * max * x / d);
193 y = (s8) (xy * max * y / d);
194 }
195 }
196 else
197 {
198 d = xy * y + (max - xy) * x;
199 if (xy * max < d)
200 {
201 x = (s8) (xy * max * x / d);
202 y = (s8) (xy * max * y / d);
203 }
204 }
205
206 *px = (s8) (signX * x);
207 *py = (s8) (signY * y);
208 }
209
210 /*---------------------------------------------------------------------------*
211 Name: ClampCircle
212
213 Description: Adjusts stick movement data.
214
215 Arguments: px pointer to movement data in terms of x-axis
216 py pointer to movement data in terms of y-axis
217 radius max valid radius
218 min deadzone
219
220 Returns: None.
221 *---------------------------------------------------------------------------*/
ClampCircle(s8 * px,s8 * py,s8 radius,s8 min)222 static void ClampCircle(s8* px, s8* py, s8 radius, s8 min)
223 {
224 int x = *px;
225 int y = *py;
226 int squared;
227 int length;
228
229 // Remove vertical zone
230 if (-min < x && x < min)
231 {
232 x = 0;
233 }
234 else if (0 < x)
235 {
236 x -= min;
237 }
238 else
239 {
240 x += min;
241 }
242
243 // Remove horizontal zone
244 if (-min < y && y < min)
245 {
246 y = 0;
247 }
248 else if (0 < y)
249 {
250 y -= min;
251 }
252 else
253 {
254 y += min;
255 }
256
257 // Clamp input to unit circle of radius
258 squared = x*x + y*y;
259 if (radius*radius < squared)
260 {
261 // Vector too long - clamp
262 length = (int) sqrtf(squared);
263 x = (x * radius) / length;
264 y = (y * radius) / length;
265 }
266
267 *px = (s8)x;
268 *py = (s8)y;
269 }
270
271 /*---------------------------------------------------------------------------*
272 Name: ClampTrigger
273
274 Description: Adjusts trigger movement data
275
276 Arguments: trigger trigger magnitude
277 min minimum valid value for trigger
278 max maximum valid value for trigger
279
280 Returns: None.
281 *---------------------------------------------------------------------------*/
ClampTrigger(u8 * trigger,u8 min,u8 max)282 static void ClampTrigger(u8* trigger, u8 min, u8 max)
283 {
284 if (*trigger <= min)
285 {
286 *trigger = 0;
287 }
288 else
289 {
290 if (max < *trigger)
291 {
292 *trigger = max;
293 }
294 *trigger -= min;
295 }
296 }
297
298 /*---------------------------------------------------------------------------*
299 Name: PADClamp
300
301 Description: Clamps game pad status.
302
303 Arguments: status array[PAD_MAX_CONTROLLERS] of PADStatus to be
304 clamped.
305
306 Returns: None.
307 *---------------------------------------------------------------------------*/
PADClamp(PADStatus * status)308 void PADClamp(PADStatus* status)
309 {
310 int i;
311
312 for (i = 0; i < PAD_MAX_CONTROLLERS; i++, status++)
313 {
314 if (status->err != PAD_ERR_NONE)
315 {
316 continue;
317 }
318 ClampStick(&status->stickX,
319 &status->stickY,
320 ClampRegion.maxStick,
321 ClampRegion.xyStick,
322 ClampRegion.minStick);
323 ClampStick(&status->substickX,
324 &status->substickY,
325 ClampRegion.maxSubstick,
326 ClampRegion.xySubstick,
327 ClampRegion.minSubstick);
328 ClampTrigger(&status->triggerLeft,
329 ClampRegion.minTrigger,
330 ClampRegion.maxTrigger);
331 ClampTrigger(&status->triggerRight,
332 ClampRegion.minTrigger,
333 ClampRegion.maxTrigger);
334 }
335 }
336
337 /*---------------------------------------------------------------------------*
338 Name: PADClampCircle
339
340 Description: Clamps game pad status. Sticks get clamped to a circle.
341
342 Arguments: status array[PAD_MAX_CONTROLLERS] of PADStatus to be
343 clamped.
344
345 Returns: None.
346 *---------------------------------------------------------------------------*/
PADClampCircle(PADStatus * status)347 void PADClampCircle(PADStatus* status)
348 {
349 int i;
350
351 for (i = 0; i < PAD_MAX_CONTROLLERS; i++, status++)
352 {
353 if (status->err != PAD_ERR_NONE)
354 {
355 continue;
356 }
357 ClampCircle(&status->stickX, &status->stickY,
358 ClampRegion.radStick,
359 ClampRegion.minStick);
360 ClampCircle(&status->substickX, &status->substickY,
361 ClampRegion.radSubstick,
362 ClampRegion.minSubstick);
363 ClampTrigger(&status->triggerLeft,
364 ClampRegion.minTrigger,
365 ClampRegion.maxTrigger);
366 ClampTrigger(&status->triggerRight,
367 ClampRegion.minTrigger,
368 ClampRegion.maxTrigger);
369 }
370 }
371