Files
ss/src/egg/core/eggController.cpp
T
elijah-thomas774 e4b1c30f47 Pad stuff
2025-06-15 14:40:59 -04:00

585 lines
15 KiB
C++

#include "egg/core/eggController.h"
#include "egg/core/eggAllocator.h"
#include "egg/core/eggExpHeap.h"
#include "egg/core/eggSystem.h"
#include "egg/math/eggMath.h"
#include "egg/math/eggVector.h"
#include "rvl/WPAD/WPAD.h"
#include "string.h"
#include "rvl/VI.h" // IWYU pragma: export
namespace EGG {
NullController null_controller;
CoreControllerMgr *CoreControllerMgr::sInstance;
CoreControllerMgr::T__Disposer *CoreControllerMgr::T__Disposer::sStaticDisposer;
CoreControllerFactory CoreControllerMgr::sCoreControllerFactory;
CoreControllerConnectCallback CoreControllerMgr::sConnectCallback;
// This controls whether EggController registers an allocator within the WPAD driver
bool CoreControllerMgr::sUseBuiltinWpadAllocator;
s32 CoreControllerMgr::sWPADWorkSize = 0x32000;
void CoreStatus::init() {
memset(this, 0, sizeof(CoreStatus));
}
u32 CoreStatus::getFSStickButton() {
f32 stick = getFSStickX();
u32 result = 0;
if (!(-0.25f < stick) || !(stick < 0.25f)) {
if (stick <= -0.5f) {
result = 0;
result |= 0x40000;
} else if (stick >= 0.5f) {
result = 0;
result |= 0x80000;
}
}
stick = getFSStickY();
if (!(-0.25f < stick) || !(stick < 0.25f)) {
if (stick <= -0.5f) {
result &= ~0x10000;
result |= 0x20000;
} else if (stick >= 0.5f) {
result &= ~0x20000;
result |= 0x10000;
}
}
return result;
}
CoreController::CoreController() : mDpdPosPrev(), mStableAccel(), mFlag(0) {
mRumbleMgr = nullptr;
mFSStickHold = 0;
mFSStickTrig = 0;
mFSStickRelease = 0;
sceneReset();
mFlag.makeAllZero();
}
void CoreController::sceneReset() {
mAccelPrev.set(0.0, 0.0, 0.0);
mDpdPosPrev.x = 0.0f;
mDpdPosPrev.y = 0.0f;
mIdleTime = 0;
mPostureMatrixPrev.makeIdentity();
mPostureMatrix.makeIdentity();
mStableFrame = 10;
mStableMag = 0.13;
mStableAccel.set(0.0, 0.0, 0.0);
mStableFlags = 0;
mStableTimer[2] = 0;
mStableTimer[1] = 0;
mStableTimer[0] = 0;
mSimpleRumblePattern = 0;
mSimpleRumbleFrame = 0;
mEnableSimpleRumble = false;
mSimpleRumbleSize = 0x20;
mSimpleRumbleIndex = 0x1f;
stopRumbleMgr();
}
Vector2f CoreController::getDpdRawPos() {
return Vector2f(mCoreStatus[0].pos.x, mCoreStatus[0].pos.y);
}
f32 CoreController::getDpdDistance() {
return mCoreStatus[0].dist;
}
s32 CoreController::getDpdValidFlag() {
return mCoreStatus[0].getDPDValidFlag();
}
void CoreController::startMotor() {
WPADControlMotor(mChannelID, WPAD_MOTOR_RUMBLE);
}
void CoreController::stopMotor() {
WPADControlMotor(mChannelID, WPAD_MOTOR_STOP);
}
void CoreController::createRumbleMgr(u8 numUnits) {
mRumbleMgr = new ControllerRumbleMgr();
mRumbleMgr->createUnit(numUnits, this);
}
void CoreController::startPatternRumble(const char *pattern, int duration, bool bGrabActive) {
if (mRumbleMgr) {
mRumbleMgr->startPattern(pattern, duration, bGrabActive);
}
}
void CoreController::stopRumbleMgr() {
if (mRumbleMgr) {
mRumbleMgr->stop();
}
}
CoreStatus *CoreController::getCoreStatus(int idx) {
return &mCoreStatus[idx];
}
void CoreController::calc_posture_matrix(Matrix34f &posture, bool checkStable) {
if (checkStable && !isStable(7)) {
return;
}
Vector3f acc = -getAccel();
Vector3f vy = acc;
vy.normalise();
Vector3f vz(0.0f, 0.0f, 1.0f);
Vector3f vx(1.0f, 0.0f, 0.0f);
Vector3f bx, by, bz;
mPostureMatrixPrev.getBase(0, bx);
mPostureMatrixPrev.getBase(1, by);
mPostureMatrixPrev.getBase(2, bz);
Vector3f vz_n(0.0f, 0.0f, -1.0f);
Vector3f vx_n(-1.0f, 0.0f, 0.0f);
if (vz.dot(bz) < vz_n.dot(bz)) {
vz = vz_n;
}
if (vx.dot(bx) < vx_n.dot(bx)) {
vx = vx_n;
}
if (Math<f32>::abs(vy.dot(vz)) < Math<f32>::abs(vy.dot(vx))) {
vx = vy.cross(vz);
vx.normalise();
vz = vx.cross(vy);
vz.normalise();
} else {
vz = vx.cross(vy);
vz.normalise();
vx = vy.cross(vz);
vx.normalise();
}
posture.setBase(0, vx);
posture.setBase(1, vy);
posture.setBase(2, vz);
}
void CoreController::beginFrame(PADStatus *padStatus) {
s32 kpad_result;
mKPADReadLength = KPADReadEx(mChannelID, mCoreStatus, 0x10, &kpad_result);
if (mKPADReadLength == 0 && kpad_result == WPAD_ERR_NO_CONTROLLER) {
mKPADReadLength = 1;
}
WPADDeviceType dev_type;
switch (WPADProbe(mChannelID, &dev_type)) {
case WPAD_ERR_OK: {
if ((u32)dev_type == WPAD_DEV_NOT_FOUND) {
mFlag.resetBit(0);
} else {
mFlag.setBit(0);
}
} break;
case WPAD_ERR_NO_CONTROLLER: {
mFlag.resetBit(0);
} break;
}
if (mKPADReadLength > 0) {
CoreStatus *pStatus = mCoreStatus;
u32 prev_held = mFSStickHold;
if (pStatus->isFreestyle()) {
mFSStickHold = pStatus->getFSStickButton();
} else {
mFSStickHold = 0;
}
mFSStickTrig = mFSStickHold & ~prev_held;
mFSStickRelease = prev_held & ~mFSStickHold;
pStatus->hold &= ~0xF0000;
pStatus->trig &= ~0xF0000;
pStatus->release &= ~0xF0000;
pStatus->hold |= (mFSStickHold & 0xF0000);
pStatus->trig |= (mFSStickTrig & 0xF0000);
pStatus->release |= (mFSStickRelease & 0xF0000);
}
mPostureMatrixPrev.copyFrom(mPostureMatrix);
mStableFlags = 0;
Vector3f acc = mCoreStatus->getAccel();
for (int i = 0; i < 3; i++) {
if (acc(i) - mAccelPrev(i) < mStableMag) {
if (mStableFrame <= ++mStableTimer[i]) {
mStableTimer[i] = mStableFrame;
mStableFlags |= (1 << i);
mStableAccel(i) = acc(i);
}
} else {
mStableFlags &= ~(1 << i);
mStableTimer[i] = 0;
}
}
calc_posture_matrix(mPostureMatrix, true);
if (mEnableSimpleRumble) {
if (mSimpleRumblePattern & (1 << mSimpleRumbleIndex)) {
startMotor();
} else {
stopMotor();
}
if (mSimpleRumbleIndex == 0) {
mSimpleRumbleIndex = mSimpleRumbleSize - 1;
} else {
mSimpleRumbleIndex = mSimpleRumbleIndex - 1;
}
if (--mSimpleRumbleFrame == 0) {
stopMotor();
mEnableSimpleRumble = false;
}
}
if (mRumbleMgr) {
mRumbleMgr->calc();
}
bool increment = true;
if (mCoreStatus->getHold() != 0) {
increment = false;
}
if (increment) {
Vector3f diff = (mAccelPrev - mCoreStatus->getAccel());
if (diff.squaredLength() > 0.01f) {
increment = false;
}
}
if (increment) {
Vector2f diff = (mDpdPosPrev - getDpdRawPos());
if (diff.squaredLength() > 0.05f) {
increment = false;
}
}
if (increment) {
// I dont know what this is for...
// if no interaction, this increments? (30fps -> 2hrs)
if (mIdleTime < 216000) {
mIdleTime++;
}
} else {
mIdleTime = 0;
}
}
void CoreController::endFrame() {
mAccelPrev = *reinterpret_cast<Vector3f *>(&mCoreStatus[0].acc);
mDpdPosPrev = getDpdRawPos();
}
/* 0x80499AC0 */
f32 CoreController::getFreeStickX() const {
if (mCoreStatus->getDevType() == WPAD_DEV_CORE) {
return 0.0f;
}
return mCoreStatus[0].getFSStickX();
}
/* 0x80499AE0 */
f32 CoreController::getFreeStickY() const {
if (mCoreStatus->getDevType() == WPAD_DEV_CORE) {
return 0.0f;
}
return mCoreStatus[0].getFSStickY();
}
/* 0x80499B00 */
CoreControllerMgr::T__Disposer::~T__Disposer() {
if (this == CoreControllerMgr::T__Disposer::sStaticDisposer) {
deleteInstance();
}
}
/* 0x80499B80 */
CoreControllerMgr *CoreControllerMgr::createInstance() {
if (CoreControllerMgr::sInstance == nullptr) {
CoreControllerMgr *mgr = new CoreControllerMgr();
CoreControllerMgr::sInstance = mgr;
CoreControllerMgr::T__Disposer::sStaticDisposer = &mgr->mDisposer;
}
return CoreControllerMgr::sInstance;
}
/* 0x80499BD0 */
void CoreControllerMgr::deleteInstance() {
CoreControllerMgr::sInstance = nullptr;
CoreControllerMgr::T__Disposer::sStaticDisposer = nullptr;
}
/* 0x80499BE0 */
EGG::CoreController *CoreControllerMgr::getNthController(int n) {
return mControllers(n);
}
namespace {
static Allocator *sAllocator;
void *alloc(size_t size) {
return sAllocator->alloc(size);
}
int free(void *ptr) {
sAllocator->free(ptr);
return 1;
}
} // namespace
/* 0x80499CD0 */
void CoreControllerMgr::connectCallback(s32 a1, s32 a2) {
CoreControllerConnectArg args = {a1, a2};
if (sConnectCallback != nullptr) {
(sConnectCallback)(args);
}
}
/* 0x80499D10 */
CoreControllerMgr::CoreControllerMgr() {
const int idxes[] = {0, 1, 2, 3};
if (sUseBuiltinWpadAllocator == false) {
Heap *heap = ExpHeap::create(sWPADWorkSize, BaseSystem::mConfigData->mRootHeapMem2, 0);
heap->mName = "EGG::CoreControllerMgr";
sAllocator = new Allocator(heap, 0x20);
WPADRegisterAllocator(alloc, free);
}
KPADInitEx(field_0x20, 0x40);
beginFrame();
endFrame();
VIWaitForRetrace();
for (int i = 0; i < 4; i++) {
KPADSetConnectCallback(idxes[i], connectCallback);
}
mControllers.allocate(4, 0);
for (int i = 0; i < 4; i++) {
if (sCoreControllerFactory != nullptr) {
mControllers(i) = (sCoreControllerFactory)();
} else {
mControllers(i) = new CoreController();
}
}
mDevTypes.allocate(4, 0);
for (int i = 0; i < 4; i++) {
mControllers(i)->mChannelID = idxes[i];
mDevTypes(i) = (eCoreDevType)0xfd;
}
field_0x10A0 = nullptr;
}
/* 0x8049A130 */
void CoreControllerMgr::beginFrame() {
for (int i = 0; i < mControllers.getSize(); ++i) {
mControllers(i)->beginFrame(NULL);
}
}
/* 0x8049A1E0 */
void CoreControllerMgr::endFrame() {
for (int i = 0; i < mControllers.getSize(); i++) {
mControllers(i)->endFrame();
WPADDeviceType dev_type;
s32 result = WPADProbe(i, &dev_type);
WPADDeviceType res_dev_type;
if (result == WPAD_ERR_OK) {
res_dev_type = dev_type;
} else if (result == WPAD_ERR_NO_CONTROLLER) {
res_dev_type = WPAD_DEV_NOT_FOUND;
} else {
continue;
}
if (field_0x10A0) {
if (res_dev_type != mDevTypes(i)) {
s32 sp0C[3];
sp0C[0] = res_dev_type;
sp0C[1] = mDevTypes(i);
sp0C[2] = i;
field_0x10A0->v_08(sp0C);
}
}
mDevTypes(i) = (eCoreDevType)res_dev_type;
}
}
/* 0x8049A3B0 */
void ControllerRumbleUnit::init() {
mRumblePattern = nullptr;
mRumblePatternPtr = nullptr;
mRumbleFrame = 0;
mRumbleValue = 0.0f;
mRumblePower = 0.0f;
mFlags.makeAllZero();
}
/* 0x8049A3E0 */
void ControllerRumbleUnit::startPattern(const char *pattern, int duration) {
mRumblePattern = pattern;
mRumblePatternPtr = pattern;
mFlags.value &= 0xef;
mFlags.value &= 0xdf;
if (duration < 0) {
mFlags.set(0x10);
} else if (duration > 0) {
mFlags.set(0x30);
}
mRumbleFrame = duration;
mFlags.setBit(0);
mFlags.resetBit(1);
mFlags.setBit(3);
}
/* 0x8049A440 */
f32 ControllerRumbleUnit::calc() {
f32 result = 0.0f;
if (mFlags.onBit(3)) {
if (mFlags.onBit(0)) {
char x = *++mRumblePatternPtr;
if (x == '\0') {
if (mFlags.onBit(4)) {
mRumblePatternPtr = mRumblePattern;
} else {
mFlags.resetBit(3);
}
} else if (x == '*') {
result = 1.0f;
}
if (mFlags.offBit(5)) {
return result;
}
if (--mRumbleFrame > 0) {
return result;
}
mFlags.resetBit(3);
return result;
} else {
f32 intensity = mRumbleValue + mRumblePower;
mRumbleValue = intensity;
if (intensity >= 1.0f) {
result = 1.0f;
mRumbleValue = 0.0f;
}
if (mFlags.onBit(2)) {
return result;
}
if (--mRumbleFrame > 0) {
return result;
}
}
mFlags.resetBit(3);
return result;
} else {
return -1.0f;
}
}
/* 0x8049A530 */
ControllerRumbleMgr::ControllerRumbleMgr() {
mController = nullptr;
List_Init(&mActiveUnitList, offsetof(ControllerRumbleUnit, mNode));
List_Init(&mStoppedUnitList, offsetof(ControllerRumbleUnit, mNode));
}
/* 0x8049A590 */
void ControllerRumbleMgr::createUnit(u8 numUnits, CoreController *ctrl) {
for (u8 created = 0; created < numUnits; created++) {
ControllerRumbleUnit *unit = new ControllerRumbleUnit();
List_Append(&mStoppedUnitList, unit);
}
mController = ctrl;
}
/* 0x8049A620 */
void ControllerRumbleMgr::stop() {
mController->stopMotor();
while (List_GetSize(&mActiveUnitList) != 0) {
ControllerRumbleUnit *unit = static_cast<ControllerRumbleUnit *>(List_GetNext(&mActiveUnitList, nullptr));
List_Remove(&mActiveUnitList, unit);
List_Append(&mStoppedUnitList, unit);
}
}
/* 0x8049A690 */
void ControllerRumbleMgr::calc() {
if (List_GetSize(&mActiveUnitList) != 0) {
void *object = List_GetFirst(&mActiveUnitList);
f32 acc = 0.0f;
while (object != nullptr) {
ControllerRumbleUnit *unit = static_cast<ControllerRumbleUnit *>(object);
f32 x = unit->calc();
void *nextObject = List_GetNext(&mActiveUnitList, object);
if (x < 0.0f) {
List_Remove(&mActiveUnitList, object);
List_Append(&mStoppedUnitList, object);
} else {
acc += x;
}
object = nextObject;
}
if (acc >= 1.0f) {
mController->startMotor();
} else {
mController->stopMotor();
}
}
}
/* 0x8049A7A0 */
void ControllerRumbleMgr::startPattern(const char *pattern, int duration, bool bGrabActive) {
EGG::ControllerRumbleUnit *unit = getUnitFromList(bGrabActive);
if (unit) {
unit->startPattern(pattern, duration);
}
}
/* 0x8049A7F0 */
ControllerRumbleUnit *ControllerRumbleMgr::getUnitFromList(bool bGrabActive) {
void *first = List_GetFirst(&this->mStoppedUnitList);
if (first) {
List_Remove(&mStoppedUnitList, first);
List_Append(&mActiveUnitList, first);
} else if (bGrabActive && (first = List_GetFirst(&mActiveUnitList), first != nullptr)) {
List_Remove(&mActiveUnitList, first);
List_Append(&mActiveUnitList, first);
}
return static_cast<ControllerRumbleUnit *>(first);
}
} // namespace EGG