| 1 | #include "controller/seadControllerBase.h" |
| 2 | |
| 3 | namespace sead |
| 4 | { |
| 5 | const f32 ControllerBase::cStickHoldThresholdDefault = 0.5f; |
| 6 | const f32 ControllerBase::cStickReleaseThresholdDefault = 0.25f; |
| 7 | |
| 8 | const Vector2f ControllerBase::cInvalidPointer(Mathf::minNumber(), Mathf::minNumber()); |
| 9 | const Vector2i ControllerBase::cInvalidPointerS32(Mathi::minNumber(), Mathi::minNumber()); |
| 10 | |
| 11 | ControllerBase::ControllerBase(s32 padBitMax, s32 leftStickCrossStartBit, |
| 12 | s32 rightStickCrossStartBit, s32 touchKeyBit) |
| 13 | : mPadTrig(), mPadRelease(), mPadRepeat(), mPointerFlag(), mPointerS32(cInvalidPointerS32), |
| 14 | mPointerBound(), mLeftStickHoldThreshold(0.5f), mRightStickHoldThreshold(0.5f), |
| 15 | mLeftStickReleaseThreshold(0.25f), mRightStickReleaseThreshold(0.25f), mPadBitMax(padBitMax), |
| 16 | mLeftStickCrossStartBit(leftStickCrossStartBit), |
| 17 | mRightStickCrossStartBit(rightStickCrossStartBit), mTouchKeyBit(touchKeyBit), mIdleFrame(0), |
| 18 | mPadHold(), mPointer(cInvalidPointer), mLeftStick(0.0f, 0.0f), mRightStick(0.0f, 0.0f), |
| 19 | mLeftAnalogTrigger(0.0f), mRightAnalogTrigger(0.0f) |
| 20 | { |
| 21 | if (cPadIdx_MaxBase < padBitMax) |
| 22 | { |
| 23 | SEAD_ASSERT_MSG(false, "illegal padBitMax[%d]" , padBitMax); |
| 24 | mPadBitMax = cPadIdx_MaxBase; |
| 25 | } |
| 26 | |
| 27 | for (u32 i = 0; i < cPadIdx_MaxBase; i++) |
| 28 | { |
| 29 | mPadRepeatDelays[i] = 30; |
| 30 | mPadRepeatPulses[i] = 1; |
| 31 | mPadHoldCounts[i] = 0; |
| 32 | } |
| 33 | } |
| 34 | |
| 35 | void ControllerBase::setPointerWithBound_(bool is_on, bool touchkey_hold, const Vector2f& pos) |
| 36 | { |
| 37 | if (is_on) |
| 38 | { |
| 39 | if (!mPointerBound.isUndef()) |
| 40 | { |
| 41 | if (mPointerBound.isInside(p: pos)) |
| 42 | { |
| 43 | mPointer.x = pos.x - mPointerBound.getMin().x; |
| 44 | mPointer.y = pos.y - mPointerBound.getMin().y; |
| 45 | } |
| 46 | else |
| 47 | { |
| 48 | is_on = false; |
| 49 | } |
| 50 | } |
| 51 | else |
| 52 | { |
| 53 | mPointer.x = pos.x; |
| 54 | mPointer.y = pos.y; |
| 55 | } |
| 56 | } |
| 57 | |
| 58 | mPointerFlag.change(val: cPointerOn, on: is_on); |
| 59 | |
| 60 | if (mTouchKeyBit >= 0) |
| 61 | { |
| 62 | mPadHold.changeBit(bit: mTouchKeyBit, on: is_on && touchkey_hold); |
| 63 | } |
| 64 | |
| 65 | if (mPointerFlag.isOn(val: cPointerUnkFlag3)) |
| 66 | { |
| 67 | if (mPointerFlag.isOff(val: cPointerOn)) |
| 68 | { |
| 69 | mPointer.x = cInvalidPointer.x; |
| 70 | mPointer.y = cInvalidPointer.y; |
| 71 | } |
| 72 | |
| 73 | mPointerFlag.reset(val: cPointerUnkFlag3); |
| 74 | } |
| 75 | } |
| 76 | |
| 77 | void ControllerBase::updateDerivativeParams_(u32 prev_hold, bool prev_pointer_on) |
| 78 | { |
| 79 | u32 stick_hold = 0; |
| 80 | |
| 81 | if (mLeftStickCrossStartBit >= 0) |
| 82 | { |
| 83 | stick_hold |= getStickHold_(prev_hold, stick: mLeftStick, hold_threshold: mLeftStickHoldThreshold, |
| 84 | release_threshold: mLeftStickReleaseThreshold, start_bit: mLeftStickCrossStartBit); |
| 85 | } |
| 86 | |
| 87 | if (mRightStickCrossStartBit >= 0) |
| 88 | { |
| 89 | stick_hold |= getStickHold_(prev_hold, stick: mRightStick, hold_threshold: mRightStickHoldThreshold, |
| 90 | release_threshold: mRightStickReleaseThreshold, start_bit: mRightStickCrossStartBit); |
| 91 | } |
| 92 | |
| 93 | mPadHold.setDirect((mPadHold.getDirect() & ~createStickCrossMask_()) | stick_hold); |
| 94 | |
| 95 | mPadTrig.setDirect(~prev_hold & mPadHold.getDirect()); |
| 96 | mPadRelease.setDirect(prev_hold & ~mPadHold.getDirect()); |
| 97 | mPadRepeat.setDirect(0); |
| 98 | |
| 99 | for (s32 i = 0; i < mPadBitMax; i++) |
| 100 | { |
| 101 | if (mPadHold.isOnBit(bit: i)) |
| 102 | { |
| 103 | if (mPadRepeatPulses[i]) |
| 104 | { |
| 105 | if (mPadHoldCounts[i] == mPadRepeatDelays[i]) |
| 106 | mPadRepeat.setBit(i); |
| 107 | |
| 108 | else if (mPadRepeatDelays[i] < mPadHoldCounts[i] && |
| 109 | (mPadHoldCounts[i] - mPadRepeatDelays[i]) % mPadRepeatPulses[i] == 0) |
| 110 | { |
| 111 | mPadRepeat.setBit(i); |
| 112 | } |
| 113 | } |
| 114 | |
| 115 | mPadHoldCounts[i]++; |
| 116 | } |
| 117 | else |
| 118 | { |
| 119 | mPadHoldCounts[i] = 0; |
| 120 | } |
| 121 | } |
| 122 | |
| 123 | mPointerFlag.change(val: cPointerOnNow, on: !prev_pointer_on && mPointerFlag.isOn(val: cPointerOn)); |
| 124 | mPointerFlag.change(val: cPointerOffNow, on: prev_pointer_on && mPointerFlag.isOff(val: cPointerOn)); |
| 125 | |
| 126 | mPointerS32.x = (s32)mPointer.x; |
| 127 | mPointerS32.y = (s32)mPointer.y; |
| 128 | } |
| 129 | |
| 130 | u32 ControllerBase::getPadHoldCount(s32 bit) const |
| 131 | { |
| 132 | SEAD_ASSERT(bit < mPadBitMax); |
| 133 | return mPadHoldCounts[bit]; |
| 134 | } |
| 135 | |
| 136 | void ControllerBase::setPadRepeat(u32 mask, u8 delay_frame, u8 pulse_frame) |
| 137 | { |
| 138 | BitFlag32 pad_to_set(mask); |
| 139 | |
| 140 | for (s32 i = 0; i < mPadBitMax; i++) |
| 141 | { |
| 142 | if (pad_to_set.isOnBit(bit: i)) |
| 143 | { |
| 144 | mPadRepeatDelays[i] = delay_frame; |
| 145 | mPadRepeatPulses[i] = pulse_frame; |
| 146 | } |
| 147 | } |
| 148 | } |
| 149 | |
| 150 | void ControllerBase::setLeftStickCrossThreshold(f32 hold, f32 release) |
| 151 | { |
| 152 | if (hold >= release) |
| 153 | { |
| 154 | mLeftStickHoldThreshold = hold; |
| 155 | mLeftStickReleaseThreshold = release; |
| 156 | } |
| 157 | else |
| 158 | { |
| 159 | SEAD_ASSERT_MSG(false, "hold[%f] must be larger than or equal to release[%f]." , hold, |
| 160 | release); |
| 161 | } |
| 162 | } |
| 163 | |
| 164 | void ControllerBase::setRightStickCrossThreshold(f32 hold, f32 release) |
| 165 | { |
| 166 | if (hold >= release) |
| 167 | { |
| 168 | mRightStickHoldThreshold = hold; |
| 169 | mRightStickReleaseThreshold = release; |
| 170 | } |
| 171 | else |
| 172 | { |
| 173 | SEAD_ASSERT_MSG(false, "hold[%f] must be larger than or equal to release[%f]." , hold, |
| 174 | release); |
| 175 | } |
| 176 | } |
| 177 | |
| 178 | void ControllerBase::setPointerBound(const BoundBox2f& bound) |
| 179 | { |
| 180 | mPointerBound.set(min: bound.getMin(), max: bound.getMax()); |
| 181 | mPointerFlag.set(cPointerUnkFlag3); |
| 182 | } |
| 183 | |
| 184 | u32 ControllerBase::getStickHold_(u32 prev_hold, const Vector2f& stick, f32 hold_threshold, |
| 185 | f32 release_threshold, s32 start_bit) |
| 186 | { |
| 187 | f32 length = stick.length(); |
| 188 | |
| 189 | if (length < release_threshold || |
| 190 | (length < hold_threshold && |
| 191 | (prev_hold & (1 << (start_bit + cCrossUp) | 1 << (start_bit + cCrossDown) | |
| 192 | 1 << (start_bit + cCrossLeft) | 1 << (start_bit + cCrossRight))) == 0)) |
| 193 | { |
| 194 | return 0; |
| 195 | } |
| 196 | else |
| 197 | { |
| 198 | u32 angle = Mathf::atan2Idx(y: stick.y, x: stick.x); |
| 199 | |
| 200 | if (angle < 0x10000000) |
| 201 | { |
| 202 | return 1 << (start_bit + cCrossRight); |
| 203 | } |
| 204 | else if (angle < 0x30000000) |
| 205 | { |
| 206 | return 1 << (start_bit + cCrossRight) | 1 << (start_bit + cCrossUp); |
| 207 | } |
| 208 | else if (angle < 0x50000000) |
| 209 | { |
| 210 | return 1 << (start_bit + cCrossUp); |
| 211 | } |
| 212 | else if (angle < 0x70000000) |
| 213 | { |
| 214 | return 1 << (start_bit + cCrossLeft) | 1 << (start_bit + cCrossUp); |
| 215 | } |
| 216 | else if (angle < 0x90000000) |
| 217 | { |
| 218 | return 1 << (start_bit + cCrossLeft); |
| 219 | } |
| 220 | else if (angle < 0xb0000000) |
| 221 | { |
| 222 | return 1 << (start_bit + cCrossLeft) | 1 << (start_bit + cCrossDown); |
| 223 | } |
| 224 | else if (angle < 0xd0000000) |
| 225 | { |
| 226 | return 1 << (start_bit + cCrossDown); |
| 227 | } |
| 228 | else if (angle < 0xf0000000) |
| 229 | { |
| 230 | return 1 << (start_bit + cCrossRight) | 1 << (start_bit + cCrossDown); |
| 231 | } |
| 232 | else |
| 233 | { |
| 234 | return 1 << (start_bit + cCrossRight); |
| 235 | } |
| 236 | } |
| 237 | } |
| 238 | |
| 239 | bool ControllerBase::isIdleBase_() |
| 240 | { |
| 241 | return getHoldMask() == 0 && mPointerFlag.isOff(val: 1) && mLeftStick.isZero() && |
| 242 | mRightStick.isZero() && mLeftAnalogTrigger == 0.0f && mRightAnalogTrigger == 0.0f; |
| 243 | } |
| 244 | |
| 245 | void ControllerBase::setIdleBase_() |
| 246 | { |
| 247 | mPadHold.makeAllZero(); |
| 248 | mPadTrig.makeAllZero(); |
| 249 | mPadRelease.makeAllZero(); |
| 250 | mPadRepeat.makeAllZero(); |
| 251 | mPointerFlag.makeAllZero(); |
| 252 | |
| 253 | for (s32 i = 0; i < mPadBitMax; i++) |
| 254 | mPadHoldCounts[i] = 0; |
| 255 | |
| 256 | mPointer = cInvalidPointer; |
| 257 | mPointerS32 = cInvalidPointerS32; |
| 258 | mLeftStick.set(x_: 0.0f, y_: 0.0f); |
| 259 | mRightStick.set(x_: 0.0f, y_: 0.0f); |
| 260 | mLeftAnalogTrigger = 0.0f; |
| 261 | mRightAnalogTrigger = 0.0f; |
| 262 | } |
| 263 | |
| 264 | u32 ControllerBase::createStickCrossMask_() |
| 265 | { |
| 266 | BitFlag32 mask; |
| 267 | |
| 268 | if (mLeftStickCrossStartBit >= 0) |
| 269 | { |
| 270 | mask.setBit(mLeftStickCrossStartBit + cCrossUp); |
| 271 | mask.setBit(mLeftStickCrossStartBit + cCrossDown); |
| 272 | mask.setBit(mLeftStickCrossStartBit + cCrossLeft); |
| 273 | mask.setBit(mLeftStickCrossStartBit + cCrossRight); |
| 274 | } |
| 275 | |
| 276 | if (mRightStickCrossStartBit >= 0) |
| 277 | { |
| 278 | mask.setBit(mRightStickCrossStartBit + cCrossUp); |
| 279 | mask.setBit(mRightStickCrossStartBit + cCrossDown); |
| 280 | mask.setBit(mRightStickCrossStartBit + cCrossLeft); |
| 281 | mask.setBit(mRightStickCrossStartBit + cCrossRight); |
| 282 | } |
| 283 | |
| 284 | return mask.getDirect(); |
| 285 | } |
| 286 | |
| 287 | } // namespace sead |
| 288 | |