Gamecube Controller Centering (#21)

* implement gc controller centering on boot

* add clamp macros too

* format

---------

Co-authored-by: someone2639 <someone2639@gmail.com>
This commit is contained in:
someone2639
2025-09-13 22:26:44 -04:00
committed by GitHub
parent ca00332bb3
commit 4858ea84dd
5 changed files with 80 additions and 18 deletions

View File

@@ -93,6 +93,14 @@ typedef struct {
} cStickMap;
} OSContButtonMap;
typedef struct {
s8 initialized;
u8 stick_x;
u8 stick_y;
u8 c_stick_x;
u8 c_stick_y;
} OSContCenterMapping;
typedef struct {
void* address; /* Ram pad Address: 11 bits */
u8 databuffer[32]; /* address of the data buffer */

View File

@@ -21,4 +21,42 @@
#define STACK_START(stack) ((u8*)(stack) + sizeof(stack))
#ifndef MIN
#define MIN(a, b) \
({ \
__auto_type _a = (a); \
__auto_type _b = (b); \
_a < _b ? _a : _b; \
})
#endif // MIN
#ifndef MAX
#define MAX(a, b) \
({ \
__auto_type _a = (a); \
__auto_type _b = (b); \
_a > _b ? _a : _b; \
})
#endif // MAX
// Integer limits and clamping
#define S8_MAX 127
#define S8_MIN -128
#define U8_MAX 255
#define S16_MAX 32767
#define S16_MIN -32768
#define U16_MAX 65535
#define S32_MAX 2147483647
#define S32_MIN -2147483648
#define U32_MAX 4294967295
// Clamp a value inbetween a range
#define CLAMP(x, low, high) MIN(MAX((x), (low)), (high))
// Clamp a value to the range of a specific data type
#define CLAMP_U8(x) CLAMP((x), 0, U8_MAX)
#define CLAMP_S8(x) CLAMP((x), S8_MIN, S8_MAX)
#define CLAMP_U16(x) CLAMP((x), 0, U16_MAX)
#define CLAMP_S16(x) CLAMP((x), S16_MIN, S16_MAX)
#endif

View File

@@ -10,8 +10,6 @@ static int writeHostInitialized = FALSE;
static OSMesgQueue writeHostMesgQueue ALIGNED(0x8);
static OSMesg writeHostMesgBuf[1];
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
void osWriteHost(void* dramAddr, u32 nbytes) {
u8* tPtr = dramAddr;
u32 sent;
@@ -32,7 +30,7 @@ void osWriteHost(void* dramAddr, u32 nbytes) {
}
while (nbytes != 0) {
count = MIN(nbytes, 0x8000);
count = MIN(nbytes, 0x8000U);
dCount[0] = (count & 0xFF0000) >> 0x10;
dCount[1] = (count & 0xFF00) >> 8;

View File

@@ -9,6 +9,8 @@ static void __osPackReadData(void);
static u16 __osTranslateGCNButtons(u16, s32, s32);
static u16 __osTranslateN64Buttons(u16);
static OSContCenterMapping __osControllerCenters[MAXCONTROLLERS] = { 0 };
static OSContButtonMap __osDefaultControllerMap = {
.buttonMap = {
.l_jpad = L_JPAD,
@@ -64,21 +66,37 @@ void osContGetReadData(OSContPad* data) {
for (i = 0; i < __osMaxControllers; i++, data++) {
if (__osControllerTypes[i] == CONT_TYPE_GCN) {
s32 stick_x, stick_y, c_stick_x, c_stick_y;
readformatgcn = *(__OSContGCNShortPollFormat*)ptr;
// The analog stick data is encoded unsigned, with (0, 0) being the bottom left of the stick plane,
// compared to the N64 where (0, 0) is the center. We correct it here so that the end user does not
// have to account for this discrepancy.
stick_x = ((s32)readformatgcn.stick_x) - 128;
stick_y = ((s32)readformatgcn.stick_y) - 128;
data->stick_x = stick_x;
data->stick_y = stick_y;
c_stick_x = ((s32)readformatgcn.c_stick_x) - 128;
c_stick_y = ((s32)readformatgcn.c_stick_y) - 128;
data->c_stick_x = c_stick_x;
data->c_stick_y = c_stick_y;
data->button = __osTranslateGCNButtons(readformatgcn.button, c_stick_x, c_stick_y);
data->l_trig = readformatgcn.l_trig;
data->r_trig = readformatgcn.r_trig;
data->errno = CHNL_ERR(readformatgcn);
if (data->errno == 0) {
// The analog stick data is encoded unsigned, with (0, 0) being the bottom left of the stick plane,
// compared to the N64 where (0, 0) is the center. We correct it here so that the end user does not
// have to account for this discrepancy.
if (!__osControllerCenters[i].initialized) {
__osControllerCenters[i].initialized = TRUE;
__osControllerCenters[i].stick_x = readformatgcn.stick_x;
__osControllerCenters[i].stick_y = readformatgcn.stick_y;
__osControllerCenters[i].c_stick_x = readformatgcn.c_stick_x;
__osControllerCenters[i].c_stick_y = readformatgcn.c_stick_y;
}
stick_x = CLAMP_S8(((s32)readformatgcn.stick_x) - __osControllerCenters[i].stick_x);
stick_y = CLAMP_S8(((s32)readformatgcn.stick_y) - __osControllerCenters[i].stick_y);
data->stick_x = stick_x;
data->stick_y = stick_y;
c_stick_x = CLAMP_S8(((s32)readformatgcn.c_stick_x) - __osControllerCenters[i].c_stick_x);
c_stick_y = CLAMP_S8(((s32)readformatgcn.c_stick_y) - __osControllerCenters[i].c_stick_y);
data->c_stick_x = c_stick_x;
data->c_stick_y = c_stick_y;
data->button = __osTranslateGCNButtons(readformatgcn.button, c_stick_x, c_stick_y);
data->l_trig = readformatgcn.l_trig;
data->r_trig = readformatgcn.r_trig;
} else {
__osControllerCenters[i].initialized = FALSE;
}
ptr += sizeof(__OSContGCNShortPollFormat);
} else {
readformat = *(__OSContReadFormat*)ptr;

View File

@@ -35,7 +35,7 @@ s32 osContInit(OSMesgQueue* mq, u8* bitpattern, OSContStatus* data) {
osRecvMesg(&timerMesgQueue, &dummy, OS_MESG_BLOCK);
}
__osMaxControllers = 4;
__osMaxControllers = MAXCONTROLLERS;
__osPackRequestData(CONT_CMD_REQUEST_STATUS);