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