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.4 09/06/2006 13:51:48 yasuh-to
15 Added clamp parameters.
16
17 Revision 1.3 08/25/2006 11:28:32 yasuh-to
18 Added new clamp API.
19
20 Revision 1.2 02/03/2006 00:31:59 yasuh-to
21 Changed include path for RevolutionSDK
22
23 Revision 1.1.1.1 2005/12/29 06:53:27 hiratsu
24 Initial import.
25
26 7 8/20/02 10:28:00 Shiki
27 Implemented PADClampCircle() based on Steve's code.
28
29 6 01/06/18 20:44 Shiki
30 Modified ClampRegion values.
31
32 5 01/06/18 16:29 Shiki
33 Updated for production controllers.
34
35 4 01/03/21 18:59 Shiki
36 Revised analog trigger clamping code to support DS4 and later.
37
38 3 6/13/00 7:28p Shiki
39 Added analog trigger clamping.
40
41 2 2/24/00 11:32p Shiki
42 Re-implemented for dolphin controller.
43
44 6 9/23/99 4:57p Shiki
45 Renamed 'errno' of PADStatus to 'err'.
46
47 4 5/11/99 4:39p Shiki
48 Refreshed include tree.
49
50 3 5/07/99 9:15p Shiki
51 Fixed dead-zone clamping.
52
53 2 5/06/99 8:18p Shiki
54 Renamed PADNormalize() to PADClamp()
55
56 1 5/06/99 7:04p Shiki
57
58 $NoKeywords: $
59 *---------------------------------------------------------------------------*/
60
61 #include <math.h>
62 #include <revolution/os.h>
63 #include <revolution/pad.h>
64
65 // Parameters for Dolphin controller
66
67 typedef struct PADClampRegion
68 {
69 u8 minTrigger; // the play of the trigger
70 u8 maxTrigger;
71 s8 minStick; // the play of the control stick
72 s8 maxStick;
73 s8 xyStick; // max on x = y
74 s8 minSubstick; // the play of the C stick
75 s8 maxSubstick;
76 s8 xySubstick;
77
78 s8 radStick; // max radius of the control stick
79 s8 radSubstick; // max radius of the C stick
80 } PADClampRegion;
81
82 // GameCube Standard Controller
83 static const PADClampRegion ClampRegion =
84 {
85 30, // minTrigger
86 180, // maxTrigger
87
88 15, // minStick
89 72, // maxStick
90 40, // xyStick
91
92 15, // minSubstick
93 59, // maxSubstick
94 31, // xySubstick
95
96 56, // radius
97 44, // radius
98 };
99
100 // The following paramaters are more widly than GC's.
101 // We recomend that you use this parameters to use GC Starndard Controller
102 // on RVL,
103 static const PADClampRegion ClampRegion2 =
104 {
105 30, // minTrigger
106 180, // maxTrigger
107
108 15, // minStick
109 72, // maxStick
110 47, // xyStick
111
112 15, // minSubstick
113 59, // maxSubstick
114 37, // xySubstick
115
116 62, // radius
117 50, // radius
118 };
119
120 static const PADClampRegion ClampRegion2Ex =
121 {
122 0, // minTrigger
123 180, // maxTrigger
124
125 0, // minStick
126 87, // maxStick
127 62, // xyStick
128
129 0, // minSubstick
130 74, // maxSubstick
131 52, // xySubstick
132
133 80, // radius
134 68, // radius
135 };
136
137 /*---------------------------------------------------------------------------*
138 Name: ClampStick
139
140 Description: Adjusts stick movement data within the octagon, or clamps
141 the data to the origin if stick is close to the origin as
142 the play.
143
144 Arguments: px: pointer to movement data in terms of x-axis
145 py: pointer to movement data in terms of y-axis
146 max: max on y = 0
147 xy: max on x = y
148 min: deadzone
149
150 Returns: None.
151 *---------------------------------------------------------------------------*/
ClampStick(s8 * px,s8 * py,s8 max,s8 xy,s8 min)152 static void ClampStick(s8* px, s8* py, s8 max, s8 xy, s8 min)
153 {
154 int x = *px;
155 int y = *py;
156 int signX;
157 int signY;
158 int d;
159
160 if (0 <= x)
161 {
162 signX = 1;
163 }
164 else
165 {
166 signX = -1;
167 x = -x;
168 }
169
170 if (0 <= y)
171 {
172 signY = 1;
173 }
174 else
175 {
176 signY = -1;
177 y = -y;
178 }
179
180 // Clamp dead zone
181 if (x <= min)
182 {
183 x = 0;
184 }
185 else
186 {
187 x -= min;
188 }
189 if (y <= min)
190 {
191 y = 0;
192 }
193 else
194 {
195 y -= min;
196 }
197
198 if (x == 0 && y == 0)
199 {
200 *px = *py = 0;
201 return;
202 // NOT REACHED HERE
203 }
204
205 // Clamp outer octagon
206 if (xy * y <= xy * x)
207 {
208 d = xy * x + (max - xy) * y;
209 if (xy * max < d)
210 {
211 x = (s8) (xy * max * x / d);
212 y = (s8) (xy * max * y / d);
213 }
214 }
215 else
216 {
217 d = xy * y + (max - xy) * x;
218 if (xy * max < d)
219 {
220 x = (s8) (xy * max * x / d);
221 y = (s8) (xy * max * y / d);
222 }
223 }
224
225 *px = (s8) (signX * x);
226 *py = (s8) (signY * y);
227 }
228
229 /*---------------------------------------------------------------------------*
230 Name: ClampCircle
231
232 Description: Adjusts stick movement data.
233
234 Arguments: px: pointer to movement data in terms of x-axis
235 py: pointer to movement data in terms of y-axis
236 radius: max valid radius
237 min: deadzone
238
239 Returns: None.
240 *---------------------------------------------------------------------------*/
ClampCircle(s8 * px,s8 * py,s8 radius,s8 min)241 static void ClampCircle(s8* px, s8* py, s8 radius, s8 min)
242 {
243 int x = *px;
244 int y = *py;
245 int squared;
246 int length;
247
248 // Remove vertical zone
249 if (-min < x && x < min)
250 {
251 x = 0;
252 }
253 else if (0 < x)
254 {
255 x -= min;
256 }
257 else
258 {
259 x += min;
260 }
261
262 // Remove horizontal zone
263 if (-min < y && y < min)
264 {
265 y = 0;
266 }
267 else if (0 < y)
268 {
269 y -= min;
270 }
271 else
272 {
273 y += min;
274 }
275
276 // Clamp input to unit circle of radius
277 squared = x*x + y*y;
278 if (radius*radius < squared)
279 {
280 // Vector too long - clamp
281 length = (int) sqrtf(squared);
282 x = (x * radius) / length;
283 y = (y * radius) / length;
284 }
285
286 *px = (s8)x;
287 *py = (s8)y;
288 }
289
290 /*---------------------------------------------------------------------------*
291 Name: ClampTrigger
292
293 Description: Adjusts trigger movement data
294
295 Arguments: trigger: trigger magnitude
296 min: minimum valid value for trigger
297 max: maximum valid value for trigger
298
299 Returns: None.
300 *---------------------------------------------------------------------------*/
ClampTrigger(u8 * trigger,u8 min,u8 max)301 static void ClampTrigger(u8* trigger, u8 min, u8 max)
302 {
303 if (*trigger <= min)
304 {
305 *trigger = 0;
306 }
307 else
308 {
309 if (max < *trigger)
310 {
311 *trigger = max;
312 }
313 *trigger -= min;
314 }
315 }
316
317 /*---------------------------------------------------------------------------*
318 Name: PADClamp
319
320 Description: Clamps game pad status.
321
322 Arguments: status: array[PAD_MAX_CONTROLLERS] of PADStatus to be
323 clamped.
324
325 Returns: None.
326 *---------------------------------------------------------------------------*/
PADClamp(PADStatus * status)327 void PADClamp(PADStatus* status)
328 {
329 int i;
330
331 for (i = 0; i < PAD_MAX_CONTROLLERS; i++, status++)
332 {
333 if (status->err != PAD_ERR_NONE)
334 {
335 continue;
336 }
337 ClampStick(&status->stickX,
338 &status->stickY,
339 ClampRegion.maxStick,
340 ClampRegion.xyStick,
341 ClampRegion.minStick);
342 ClampStick(&status->substickX,
343 &status->substickY,
344 ClampRegion.maxSubstick,
345 ClampRegion.xySubstick,
346 ClampRegion.minSubstick);
347 ClampTrigger(&status->triggerLeft,
348 ClampRegion.minTrigger,
349 ClampRegion.maxTrigger);
350 ClampTrigger(&status->triggerRight,
351 ClampRegion.minTrigger,
352 ClampRegion.maxTrigger);
353 }
354 }
355
356 /*---------------------------------------------------------------------------*
357 Name: PADClampCircle
358
359 Description: Clamps game pad status. Sticks get clamped to a circle.
360
361 Arguments: status: array[PAD_MAX_CONTROLLERS] of PADStatus to be
362 clamped.
363
364 Returns: None.
365 *---------------------------------------------------------------------------*/
PADClampCircle(PADStatus * status)366 void PADClampCircle(PADStatus* status)
367 {
368 int i;
369
370 for (i = 0; i < PAD_MAX_CONTROLLERS; i++, status++)
371 {
372 if (status->err != PAD_ERR_NONE)
373 {
374 continue;
375 }
376 ClampCircle(&status->stickX, &status->stickY,
377 ClampRegion.radStick,
378 ClampRegion.minStick);
379 ClampCircle(&status->substickX, &status->substickY,
380 ClampRegion.radSubstick,
381 ClampRegion.minSubstick);
382 ClampTrigger(&status->triggerLeft,
383 ClampRegion.minTrigger,
384 ClampRegion.maxTrigger);
385 ClampTrigger(&status->triggerRight,
386 ClampRegion.minTrigger,
387 ClampRegion.maxTrigger);
388 }
389 }
390
391 /*---------------------------------------------------------------------------*
392 Name: PADClamp2
393
394 Description: Clamps game pad status.
395
396 Arguments: status: array[PAD_MAX_CONTROLLERS] of PADStatus to be
397 clamped.
398 type: clamp type.
399
400 Returns: None.
401 *---------------------------------------------------------------------------*/
PADClamp2(PADStatus * status,u32 type)402 void PADClamp2(PADStatus* status, u32 type)
403 {
404 const PADClampRegion *stkreg;
405 int i;
406
407 ASSERT( status != NULL );
408
409 for (i = 0; i < PAD_MAX_CONTROLLERS; i++, status++)
410 {
411 if (status->err != PAD_ERR_NONE)
412 {
413 continue;
414 }
415
416 if (type == PAD_STICK_CLAMP_OCTA_WITH_MARGIN)
417 {
418 stkreg = &ClampRegion2;
419 }
420 else
421 {
422 stkreg = &ClampRegion2Ex;
423 }
424
425
426 ClampStick(&status->stickX,
427 &status->stickY,
428 stkreg->maxStick,
429 stkreg->xyStick,
430 stkreg->minStick);
431 ClampStick(&status->substickX,
432 &status->substickY,
433 stkreg->maxSubstick,
434 stkreg->xySubstick,
435 stkreg->minSubstick);
436 }
437 }
438
439 /*---------------------------------------------------------------------------*
440 Name: PADClampCircle2
441
442 Description: Clamps game pad status. Sticks get clamped to a circle.
443
444 Arguments: status: array[PAD_MAX_CONTROLLERS] of PADStatus to be
445 clamped.
446 type: clamp type.
447
448 Returns: None.
449 *---------------------------------------------------------------------------*/
PADClampCircle2(PADStatus * status,u32 type)450 void PADClampCircle2(PADStatus* status, u32 type)
451 {
452 const PADClampRegion *stkreg;
453 int i;
454
455 for (i = 0; i < PAD_MAX_CONTROLLERS; i++, status++)
456 {
457 if (status->err != PAD_ERR_NONE)
458 {
459 continue;
460 }
461 if (type == PAD_STICK_CLAMP_CIRCLE_WITH_MARGIN)
462 {
463 stkreg = &ClampRegion2;
464 }
465 else
466 {
467 stkreg = &ClampRegion2Ex;
468 }
469
470 ClampCircle(&status->stickX, &status->stickY,
471 stkreg->radStick,
472 stkreg->minStick);
473 ClampCircle(&status->substickX, &status->substickY,
474 stkreg->radSubstick,
475 stkreg->minSubstick);
476 }
477 }
478
479 /*---------------------------------------------------------------------------*
480 Name: PADClampTrigger
481
482 Description: Clamp the trigger.
483
484 Arguments: status: array[PAD_MAX_CONTROLLERS] of PADStatus to be
485 clamped.
486 type: clamp type.
487
488 Returns: None.
489 *---------------------------------------------------------------------------*/
PADClampTrigger(PADStatus * status,u32 type)490 void PADClampTrigger(PADStatus* status, u32 type)
491 {
492 const PADClampRegion *stkreg;
493 int i;
494
495 for (i = 0; i < PAD_MAX_CONTROLLERS; i++, status++)
496 {
497 if (status->err != PAD_ERR_NONE)
498 {
499 continue;
500 }
501 if (type == PAD_TRIGGER_FIXED_BASE)
502 {
503 stkreg = &ClampRegion2;
504 }
505 else
506 {
507 stkreg = &ClampRegion2Ex;
508 }
509
510 ClampTrigger(&status->triggerLeft,
511 stkreg->minTrigger,
512 stkreg->maxTrigger);
513 ClampTrigger(&status->triggerRight,
514 stkreg->minTrigger,
515 stkreg->maxTrigger);
516 }
517 }
518
519
520