Zelda64Recomp/src/recomp/cont.cpp

136 lines
4.1 KiB
C++

#include "../ultramodern/ultramodern.hpp"
#include "recomp_helpers.h"
static ultramodern::input_callbacks_t input_callbacks;
void set_input_callbacks(const ultramodern::input_callbacks_t& callbacks) {
input_callbacks = callbacks;
}
static int max_controllers = 0;
extern "C" void osContInit_recomp(uint8_t* rdram, recomp_context* ctx) {
PTR(void) bitpattern = _arg<1, PTR(void)>(rdram, ctx);
PTR(void) status = _arg<2, PTR(void)>(rdram, ctx);
// Set bit 0 to indicate that controller 0 is present
MEM_B(0, bitpattern) = 0x01;
// Mark controller 0 as present
MEM_H(0, status) = 0x0005; // type: CONT_TYPE_NORMAL (from joybus)
MEM_B(2, status) = 0x00; // status: 0 (from joybus)
MEM_B(3, status) = 0x00; // errno: 0 (from libultra)
max_controllers = 4;
// Mark controllers 1-3 as not connected
for (size_t controller = 1; controller < max_controllers; controller++) {
// Libultra doesn't write status or type for absent controllers
MEM_B(4 * controller + 3, status) = 0x80 >> 4; // errno: CONT_NO_RESPONSE_ERROR >> 4
}
_return<s32>(ctx, 0);
}
extern "C" void osContStartReadData_recomp(uint8_t* rdram, recomp_context* ctx) {
if (input_callbacks.poll_input) {
input_callbacks.poll_input();
}
ultramodern::send_si_message();
}
extern "C" void osContGetReadData_recomp(uint8_t* rdram, recomp_context* ctx) {
PTR(void) pad = _arg<0, PTR(void)>(rdram, ctx);
uint16_t buttons = 0;
float x = 0.0f;
float y = 0.0f;
if (input_callbacks.get_input) {
input_callbacks.get_input(&buttons, &x, &y);
}
if (max_controllers > 0) {
// button
MEM_H(0, pad) = buttons;
// stick_x
MEM_B(2, pad) = (int8_t)(127 * x);
// stick_y
MEM_B(3, pad) = (int8_t)(127 * y);
// errno
MEM_B(4, pad) = 0;
}
for (int controller = 1; controller < max_controllers; controller++) {
MEM_B(6 * controller + 4, pad) = 0x80 >> 4; // errno: CONT_NO_RESPONSE_ERROR >> 4
}
}
extern "C" void osContStartQuery_recomp(uint8_t * rdram, recomp_context * ctx) {
ultramodern::send_si_message();
}
extern "C" void osContGetQuery_recomp(uint8_t * rdram, recomp_context * ctx) {
PTR(void) status = _arg<0, PTR(void)>(rdram, ctx);
// Mark controller 0 as present
MEM_H(0, status) = 0x0005; // type: CONT_TYPE_NORMAL (from joybus)
MEM_B(2, status) = 0x01; // status: 0x01 (from joybus, indicates that a pak is plugged into the controller)
MEM_B(3, status) = 0x00; // errno: 0 (from libultra)
// Mark controllers 1-3 as not connected
for (size_t controller = 1; controller < max_controllers; controller++) {
// Libultra doesn't write status or type for absent controllers
MEM_B(4 * controller + 3, status) = 0x80 >> 4; // errno: CONT_NO_RESPONSE_ERROR >> 4
}
}
extern "C" void osContSetCh_recomp(uint8_t* rdram, recomp_context* ctx) {
max_controllers = std::min(_arg<0, u8>(rdram, ctx), u8(4));
_return<s32>(ctx, 0);
}
extern "C" void __osMotorAccess_recomp(uint8_t* rdram, recomp_context* ctx) {
PTR(void) pfs = _arg<0, PTR(void)>(rdram, ctx);
s32 flag = _arg<1, s32>(rdram, ctx);
s32 channel = MEM_W(8, pfs);
// Only respect accesses to controller 0.
if (channel == 0) {
input_callbacks.set_rumble(flag);
}
_return<s32>(ctx, 0);
}
extern "C" void osMotorInit_recomp(uint8_t* rdram, recomp_context* ctx) {
PTR(void) pfs = _arg<1, PTR(void)>(rdram, ctx);
s32 channel = _arg<2, s32>(rdram, ctx);
MEM_W(8, pfs) = channel;
_return<s32>(ctx, 0);
}
extern "C" void osMotorStart_recomp(uint8_t* rdram, recomp_context* ctx) {
PTR(void) pfs = _arg<0, PTR(void)>(rdram, ctx);
s32 channel = MEM_W(8, pfs);
// Only respect accesses to controller 0.
if (channel == 0) {
input_callbacks.set_rumble(true);
}
_return<s32>(ctx, 0);
}
extern "C" void osMotorStop_recomp(uint8_t* rdram, recomp_context* ctx) {
PTR(void) pfs = _arg<0, PTR(void)>(rdram, ctx);
s32 channel = MEM_W(8, pfs);
// Only respect accesses to controller 0.
if (channel == 0) {
input_callbacks.set_rumble(false);
}
_return<s32>(ctx, 0);
}