/*---------------------------------------------------------------------------* 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.2 02/03/2006 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:00 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; #ifndef EMU // GameCube Standard Controller static const PADClampRegion ClampRegion = { 30, // minTrigger 180, // maxTrigger 15, // minStick 72, // maxStick 40, // xyStick 15, // minSubstick 59, // maxSubstick 31, // xySubstick 56, 44, }; #else // EMU // Mac emulator static const PADClampRegion ClampRegion = { 40, // minTrigger 190, // maxTrigger 35, // minStick 79, // maxStick 47, // xyStick 35, // minSubstick 66, // maxSubstick 38, // xySubstick 56, 44 }; #endif // EMU /*---------------------------------------------------------------------------* 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); } }