1#include "controller/seadControllerBase.h"
2
3namespace sead
4{
5const f32 ControllerBase::cStickHoldThresholdDefault = 0.5f;
6const f32 ControllerBase::cStickReleaseThresholdDefault = 0.25f;
7
8const Vector2f ControllerBase::cInvalidPointer(Mathf::minNumber(), Mathf::minNumber());
9const Vector2i ControllerBase::cInvalidPointerS32(Mathi::minNumber(), Mathi::minNumber());
10
11ControllerBase::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
35void 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
77void 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
130u32 ControllerBase::getPadHoldCount(s32 bit) const
131{
132 SEAD_ASSERT(bit < mPadBitMax);
133 return mPadHoldCounts[bit];
134}
135
136void 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
150void 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
164void 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
178void ControllerBase::setPointerBound(const BoundBox2f& bound)
179{
180 mPointerBound.set(min: bound.getMin(), max: bound.getMax());
181 mPointerFlag.set(cPointerUnkFlag3);
182}
183
184u32 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
239bool ControllerBase::isIdleBase_()
240{
241 return getHoldMask() == 0 && mPointerFlag.isOff(val: 1) && mLeftStick.isZero() &&
242 mRightStick.isZero() && mLeftAnalogTrigger == 0.0f && mRightAnalogTrigger == 0.0f;
243}
244
245void 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
264u32 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