/*---------------------------------------------------------------------------* Project: Dolphin Game Pad(Controller) API File: Padclamp.c Copyright (C) 1998-2006 Nintendo. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Log: Padclamp.c,v $ Revision 1.4 2006/09/06 13:51:48 yasuh-to Added clamp parameters. Revision 1.3 2006/08/25 11:28:32 yasuh-to Added new clamp API. Revision 1.2 2006/02/03 00:31:59 yasuh-to Changed include path for RevolutionSDK Revision 1.1.1.1 2005/12/29 06:53:27 hiratsu Initial import. 7 8/20/02 10:28 Shiki Implemented PADClampCircle() based on Steve's code. 6 01/06/18 20:44 Shiki Modified ClampRegion values. 5 01/06/18 16:29 Shiki Updated for production controllers. 4 01/03/21 18:59 Shiki Revised analog trigger clamping code to support DS4 and later. 3 6/13/00 7:28p Shiki Added analog trigger clamping. 2 2/24/00 11:32p Shiki Re-implemented for dolphin controller. 6 9/23/99 4:57p Shiki Renamed 'errno' of PADStatus to 'err'. 4 5/11/99 4:39p Shiki Refreshed include tree. 3 5/07/99 9:15p Shiki Fixed dead-zone clamping. 2 5/06/99 8:18p Shiki Renamed PADNormalize() to PADClamp() 1 5/06/99 7:04p Shiki $NoKeywords: $ *---------------------------------------------------------------------------*/ #include #include #include // Parameters for Dolphin controller typedef struct PADClampRegion { u8 minTrigger; // the play of the trigger u8 maxTrigger; s8 minStick; // the play of the control stick s8 maxStick; s8 xyStick; // max on x = y s8 minSubstick; // the play of the C stick s8 maxSubstick; s8 xySubstick; s8 radStick; // max radius of the control stick s8 radSubstick; // max radius of the C stick } PADClampRegion; // GameCube Standard Controller static const PADClampRegion ClampRegion = { 30, // minTrigger 180, // maxTrigger 15, // minStick 72, // maxStick 40, // xyStick 15, // minSubstick 59, // maxSubstick 31, // xySubstick 56, // radius 44, // radius }; // The following paramaters are more widly than GC's. // We recomend that you use this parameters to use GC Starndard Controller // on RVL, static const PADClampRegion ClampRegion2 = { 30, // minTrigger 180, // maxTrigger 15, // minStick 72, // maxStick 47, // xyStick 15, // minSubstick 59, // maxSubstick 37, // xySubstick 62, // radius 50, // radius }; static const PADClampRegion ClampRegion2Ex = { 0, // minTrigger 180, // maxTrigger 0, // minStick 87, // maxStick 62, // xyStick 0, // minSubstick 74, // maxSubstick 52, // xySubstick 80, // radius 68, // radius }; /*---------------------------------------------------------------------------* Name: ClampStick Description: Adjusts stick movement data within the octagon, or clamps the data to the origin if stick is close to the origin as the play. Arguments: px: pointer to movement data in terms of x-axis py: pointer to movement data in terms of y-axis max: max on y = 0 xy: max on x = y min: deadzone Returns: None. *---------------------------------------------------------------------------*/ static void ClampStick(s8* px, s8* py, s8 max, s8 xy, s8 min) { int x = *px; int y = *py; int signX; int signY; int d; if (0 <= x) { signX = 1; } else { signX = -1; x = -x; } if (0 <= y) { signY = 1; } else { signY = -1; y = -y; } // Clamp dead zone if (x <= min) { x = 0; } else { x -= min; } if (y <= min) { y = 0; } else { y -= min; } if (x == 0 && y == 0) { *px = *py = 0; return; // NOT REACHED HERE } // Clamp outer octagon if (xy * y <= xy * x) { d = xy * x + (max - xy) * y; if (xy * max < d) { x = (s8) (xy * max * x / d); y = (s8) (xy * max * y / d); } } else { d = xy * y + (max - xy) * x; if (xy * max < d) { x = (s8) (xy * max * x / d); y = (s8) (xy * max * y / d); } } *px = (s8) (signX * x); *py = (s8) (signY * y); } /*---------------------------------------------------------------------------* Name: ClampCircle Description: Adjusts stick movement data. Arguments: px: pointer to movement data in terms of x-axis py: pointer to movement data in terms of y-axis radius: max valid radius min: deadzone Returns: None. *---------------------------------------------------------------------------*/ static void ClampCircle(s8* px, s8* py, s8 radius, s8 min) { int x = *px; int y = *py; int squared; int length; // Remove vertical zone if (-min < x && x < min) { x = 0; } else if (0 < x) { x -= min; } else { x += min; } // Remove horizontal zone if (-min < y && y < min) { y = 0; } else if (0 < y) { y -= min; } else { y += min; } // Clamp input to unit circle of radius squared = x*x + y*y; if (radius*radius < squared) { // Vector too long - clamp length = (int) sqrtf(squared); x = (x * radius) / length; y = (y * radius) / length; } *px = (s8)x; *py = (s8)y; } /*---------------------------------------------------------------------------* Name: ClampTrigger Description: Adjusts trigger movement data Arguments: trigger: trigger magnitude min: minimum valid value for trigger max: maximum valid value for trigger Returns: None. *---------------------------------------------------------------------------*/ static void ClampTrigger(u8* trigger, u8 min, u8 max) { if (*trigger <= min) { *trigger = 0; } else { if (max < *trigger) { *trigger = max; } *trigger -= min; } } /*---------------------------------------------------------------------------* Name: PADClamp Description: Clamps game pad status. Arguments: status: array[PAD_MAX_CONTROLLERS] of PADStatus to be clamped. Returns: None. *---------------------------------------------------------------------------*/ void PADClamp(PADStatus* status) { int i; for (i = 0; i < PAD_MAX_CONTROLLERS; i++, status++) { if (status->err != PAD_ERR_NONE) { continue; } ClampStick(&status->stickX, &status->stickY, ClampRegion.maxStick, ClampRegion.xyStick, ClampRegion.minStick); ClampStick(&status->substickX, &status->substickY, ClampRegion.maxSubstick, ClampRegion.xySubstick, ClampRegion.minSubstick); ClampTrigger(&status->triggerLeft, ClampRegion.minTrigger, ClampRegion.maxTrigger); ClampTrigger(&status->triggerRight, ClampRegion.minTrigger, ClampRegion.maxTrigger); } } /*---------------------------------------------------------------------------* Name: PADClampCircle Description: Clamps game pad status. Sticks get clamped to a circle. Arguments: status: array[PAD_MAX_CONTROLLERS] of PADStatus to be clamped. Returns: None. *---------------------------------------------------------------------------*/ void PADClampCircle(PADStatus* status) { int i; for (i = 0; i < PAD_MAX_CONTROLLERS; i++, status++) { if (status->err != PAD_ERR_NONE) { continue; } ClampCircle(&status->stickX, &status->stickY, ClampRegion.radStick, ClampRegion.minStick); ClampCircle(&status->substickX, &status->substickY, ClampRegion.radSubstick, ClampRegion.minSubstick); ClampTrigger(&status->triggerLeft, ClampRegion.minTrigger, ClampRegion.maxTrigger); ClampTrigger(&status->triggerRight, ClampRegion.minTrigger, ClampRegion.maxTrigger); } } /*---------------------------------------------------------------------------* Name: PADClamp2 Description: Clamps game pad status. Arguments: status: array[PAD_MAX_CONTROLLERS] of PADStatus to be clamped. type: clamp type. Returns: None. *---------------------------------------------------------------------------*/ void PADClamp2(PADStatus* status, u32 type) { const PADClampRegion *stkreg; int i; ASSERT( status != NULL ); for (i = 0; i < PAD_MAX_CONTROLLERS; i++, status++) { if (status->err != PAD_ERR_NONE) { continue; } if (type == PAD_STICK_CLAMP_OCTA_WITH_MARGIN) { stkreg = &ClampRegion2; } else { stkreg = &ClampRegion2Ex; } ClampStick(&status->stickX, &status->stickY, stkreg->maxStick, stkreg->xyStick, stkreg->minStick); ClampStick(&status->substickX, &status->substickY, stkreg->maxSubstick, stkreg->xySubstick, stkreg->minSubstick); } } /*---------------------------------------------------------------------------* Name: PADClampCircle2 Description: Clamps game pad status. Sticks get clamped to a circle. Arguments: status: array[PAD_MAX_CONTROLLERS] of PADStatus to be clamped. type: clamp type. Returns: None. *---------------------------------------------------------------------------*/ void PADClampCircle2(PADStatus* status, u32 type) { const PADClampRegion *stkreg; int i; for (i = 0; i < PAD_MAX_CONTROLLERS; i++, status++) { if (status->err != PAD_ERR_NONE) { continue; } if (type == PAD_STICK_CLAMP_CIRCLE_WITH_MARGIN) { stkreg = &ClampRegion2; } else { stkreg = &ClampRegion2Ex; } ClampCircle(&status->stickX, &status->stickY, stkreg->radStick, stkreg->minStick); ClampCircle(&status->substickX, &status->substickY, stkreg->radSubstick, stkreg->minSubstick); } } /*---------------------------------------------------------------------------* Name: PADClampTrigger Description: Clamp the trigger. Arguments: status: array[PAD_MAX_CONTROLLERS] of PADStatus to be clamped. type: clamp type. Returns: None. *---------------------------------------------------------------------------*/ void PADClampTrigger(PADStatus* status, u32 type) { const PADClampRegion *stkreg; int i; for (i = 0; i < PAD_MAX_CONTROLLERS; i++, status++) { if (status->err != PAD_ERR_NONE) { continue; } if (type == PAD_TRIGGER_FIXED_BASE) { stkreg = &ClampRegion2; } else { stkreg = &ClampRegion2Ex; } ClampTrigger(&status->triggerLeft, stkreg->minTrigger, stkreg->maxTrigger); ClampTrigger(&status->triggerRight, stkreg->minTrigger, stkreg->maxTrigger); } }