1 /*---------------------------------------------------------------------------*
2   Project:     KPAD library
3   File:        KPAD.c
4   Programmers: Keizo Ohta
5                HIRATSU Daisuke
6 
7   Copyright 2005-2006 Nintendo.  All rights reserved.
8 
9   These coded instructions, statements, and computer programs contain
10   proprietary information of Nintendo of America Inc. and/or Nintendo
11   Company Ltd., and are protected by Federal copyright law.  They may
12   not be disclosed to third parties or copied or duplicated in any form,
13   in whole or in part, without the prior written consent of Nintendo.
14  *---------------------------------------------------------------------------*/
15 
16 #include <revolution/kpad.h>
17 #include "KPADinside.h"
18 
19 #include <revolution.h>
20 #include <math.h>
21 
22 #include <revolution/revodefs.h>
23 REVOLUTION_LIB_VERSION(KPAD);
24 
25 
26 
27 /*******************************************************
28         VARIABLE
29  *******************************************************/
30 //----- Initial values for �c�o�c calibration
31 static Vec2     icenter_org = { 0.000f, 0.000f } ;      // Center coordinate of the 2 marks on CMOS
32 static f32      idist_org = 1.000f ;                    // Distance after calibration (in meters)
33 static Vec2     iaccXY_nrm_hori = { 0.000f,-1.000f } ;  // XY acceleration direction when the controller is in the horizontal plane
34 static Vec2     isec_nrm_hori   = { 1.000f, 0.000f } ;  // Direction from left mark to right mark when the controller is in the horizontal plane
35 f32             kp_obj_interval = 0.200f ;              // Distance between both marks (in meters)
36 
37 //----- Various adjustments
38 f32             kp_acc_horizon_pw   = 0.050f ;  // Conditions when calculating the rotation from the acceleration
39 f32             kp_ah_circle_radius = 0.070f ;  // Radius used to determine if the controller is at rest
40 f32             kp_ah_circle_pw     = 0.060f ;  // Sensitivity conditions used to determine if the controller is at rest
41 u16             kp_ah_circle_ct     = 100 ;     // Count for determining if the controller is at rest
42 
43 //----- Numeric values viewed as errors
44 f32             kp_err_outside_frame = 0.050f ; // Peripheral width where center of gravity coordinates are disabled (peripheral light may not be entirely displayed)
45 f32             kp_err_dist_min ;               // Automatically calculate minimum operation distance (in meters)
46 f32             kp_err_dist_max      = 3.000f ; // Maximum operation distance (in meters)
47 f32             kp_err_dist_speed    = 0.040f ; // Allowable range of variation in distance (in meters)
48 f32             kp_err_first_inpr    = 0.900f ; // Inner product of acceleration slope and object inclination when selecting first two points
49 f32             kp_err_next_inpr     = 0.900f ; // Allowable range in variation of inclination (inner product)
50 f32             kp_err_acc_inpr      = 0.900f ; // Allowable range of inner product with acceleration slope when controller has been brought to rest
51 f32             kp_err_up_inpr       = 0.700f ; // Allowable range of inner product when controller is facing up
52 f32             kp_err_near_pos      = 0.100f ; // Distance from last point when selecting the next point
53 
54 //----- Internal processing
55 static Vec2     kobj_frame_min, kobj_frame_max ;        // Range in which center of gravity coordinate is enabled
56 static f32      kp_err_dist_speed_1 ;                   // Inverse
57 static f32      kp_err_dist_speedM_1 ;                  // Inverse having negative value
58 static f32      kp_ah_circle_radius2 ;                  // Raised to the 2nd power
59 static f32      kp_dist_vv1 ;                           // Constant
60 
61 static s32      kp_fs_fstick_min  =  15 ;   // Set nunchaku unit stick clamp
62 static s32      kp_fs_fstick_max  =  71 ;
63 static s32      kp_cl_stick_min   =  60 ;   // Classic Controller unit stick clamp settings
64 static s32      kp_cl_stick_max   = 308 ;
65 static s32      kp_cl_trigger_min =  30 ;   // Classic Controller unit analog trigger clamp settings
66 static s32      kp_cl_trigger_max = 180 ;
67 static s32      kp_gc_mstick_min  =  15 ;   // Set old GC3D stick clamp
68 static s32      kp_gc_mstick_max  =  77 ;
69 static s32      kp_gc_cstick_min  =  15 ;   // Set old GCC stick clamp
70 static s32      kp_gc_cstick_max  =  64 ;
71 static s32      kp_gc_trigger_min =  30 ;   // Set old GC analog trigger clamp
72 static s32      kp_gc_trigger_max = 180 ;
73 static f32      kp_rm_acc_max     = 3.4f ;  // Remote acceleration clamp settings
74 static f32      kp_fs_acc_max     = 2.1f ;  // Nunchuk acceleration clamp settings
75 
76 
77 //----- �j�o�`�c unit
78 KPADInsideStatus        inside_kpads[ WPAD_MAX_CONTROLLERS ] ;
79 
80 //----- Zero vector
81 static Vec2 Vec2_0={0.0f, 0.0f};
82 
83 
84 /*******************************************************************************
85         Set analog data clamp
86 *******************************************************************************/
KPADSetFSStickClamp(s8 min,s8 max)87 void KPADSetFSStickClamp( s8 min, s8 max )
88 {
89     kp_fs_fstick_min = (s32)min ;
90     kp_fs_fstick_max = (s32)max ;
91 }
92 
93 
94 /*******************************************************************************
95         Get WPADStatus ring buffer
96  *******************************************************************************/
KPADGetWPADRingBuffer(s32 chan)97 WPADStatus *KPADGetWPADRingBuffer( s32 chan )
98 {
99     ASSERT((0 <= chan) && (chan < WPAD_MAX_CONTROLLERS));
100     return ( (WPADStatus*)inside_kpads[ chan ].wpad_ring_bf ) ;
101 }
102 
KPADGetWPADFSRingBuffer(s32 chan)103 WPADFSStatus *KPADGetWPADFSRingBuffer( s32 chan )
104 {
105     ASSERT((0 <= chan) && (chan < WPAD_MAX_CONTROLLERS));
106     return ( (WPADFSStatus*)inside_kpads[ chan ].wpad_ring_bf ) ;
107 }
108 
KPADGetWPADCLRingBuffer(s32 chan)109 WPADCLStatus *KPADGetWPADCLRingBuffer( s32 chan )
110 {
111     ASSERT((0 <= chan) && (chan < WPAD_MAX_CONTROLLERS));
112     return ( (WPADCLStatus*)inside_kpads[ chan ].wpad_ring_bf ) ;
113 }
114 
115 /*******************************************************************************
116         Set conditions for button repeat
117  *******************************************************************************/
KPADSetBtnRepeat(s32 chan,f32 delay_sec,f32 pulse_sec)118 void KPADSetBtnRepeat( s32 chan, f32 delay_sec, f32 pulse_sec )
119 {
120     ASSERT((0 <= chan) && (chan < WPAD_MAX_CONTROLLERS));
121     if ( pulse_sec ) {
122         //----- Set repeat flag
123         inside_kpads[ chan ].btn_repeat_delay = (u16)(s32)( delay_sec * 200.0f + 0.5f ) ;
124         inside_kpads[ chan ].btn_repeat_pulse = (u16)(s32)( pulse_sec * 200.0f + 0.5f ) ;
125         inside_kpads[ chan ].btn_cl_repeat_delay = (u16)(s32)( delay_sec * 200.0f + 0.5f ) ;
126         inside_kpads[ chan ].btn_cl_repeat_pulse = (u16)(s32)( pulse_sec * 200.0f + 0.5f ) ;
127     } else {
128         //----- Unset repeat flag
129         inside_kpads[ chan ].btn_repeat_delay = KPAD_BTN_NO_RPT_DELAY ;
130         inside_kpads[ chan ].btn_repeat_pulse = 0 ;
131         inside_kpads[ chan ].btn_cl_repeat_delay = KPAD_BTN_NO_RPT_DELAY ;
132         inside_kpads[ chan ].btn_cl_repeat_pulse = 0 ;
133     }
134 
135     //----- Reset
136     inside_kpads[ chan ].btn_repeat_time = 0 ;
137     inside_kpads[ chan ].btn_repeat_next = inside_kpads[ chan ].btn_repeat_delay ;
138     inside_kpads[ chan ].btn_cl_repeat_time = 0 ;
139     inside_kpads[ chan ].btn_cl_repeat_next = inside_kpads[ chan ].btn_cl_repeat_delay ;
140 }
141 
142 
143 /*******************************************************************************
144         Set distance between markers (in meters)
145  *******************************************************************************/
KPADSetObjInterval(f32 interval)146 void KPADSetObjInterval( f32 interval )
147 {
148     kp_obj_interval = interval ;
149 
150     //----- Minimum �c�o�c operation distance (set so that the distance between marks is half the lens diameter)
151     kp_err_dist_min = kp_obj_interval / KPAD_CMOS_HFOV_TAN ;
152 
153     //----- Constant used to calculate distances
154     kp_dist_vv1 = kp_obj_interval / KPAD_CMOS_HFOV_TAN ;
155 }
156 
157 
158 /*******************************************************************************
159         Set parameters
160  *******************************************************************************/
KPADSetPosParam(s32 chan,f32 play_radius,f32 sensitivity)161 void KPADSetPosParam( s32 chan, f32 play_radius, f32 sensitivity )
162 {
163     ASSERT((0 <= chan) && (chan < WPAD_MAX_CONTROLLERS));
164     inside_kpads[ chan ].pos_play_radius = play_radius ;
165     inside_kpads[ chan ].pos_sensitivity = sensitivity ;
166 }
167 
KPADSetHoriParam(s32 chan,f32 play_radius,f32 sensitivity)168 void KPADSetHoriParam( s32 chan, f32 play_radius, f32 sensitivity )
169 {
170     ASSERT((0 <= chan) && (chan < WPAD_MAX_CONTROLLERS));
171     inside_kpads[ chan ].hori_play_radius = play_radius ;
172     inside_kpads[ chan ].hori_sensitivity = sensitivity ;
173 }
174 
KPADSetDistParam(s32 chan,f32 play_radius,f32 sensitivity)175 void KPADSetDistParam( s32 chan, f32 play_radius, f32 sensitivity )
176 {
177     ASSERT((0 <= chan) && (chan < WPAD_MAX_CONTROLLERS));
178     inside_kpads[ chan ].dist_play_radius = play_radius ;
179     inside_kpads[ chan ].dist_sensitivity = sensitivity ;
180 }
181 
KPADSetAccParam(s32 chan,f32 play_radius,f32 sensitivity)182 void KPADSetAccParam( s32 chan, f32 play_radius, f32 sensitivity )
183 {
184     ASSERT((0 <= chan) && (chan < WPAD_MAX_CONTROLLERS));
185     inside_kpads[ chan ].acc_play_radius = play_radius ;
186     inside_kpads[ chan ].acc_sensitivity = sensitivity ;
187 }
188 
189 
190 /*******************************************************************************
191         Find an easy-to-use scale value based on the calibrated center position
192  *******************************************************************************/
calc_dpd2pos_scale(KPADInsideStatus * kp)193 static void calc_dpd2pos_scale( KPADInsideStatus *kp )
194 {
195     f32             sx,sy ;
196 
197 
198     //----- Distance the controller is moved up/down/left/right
199     sx = 1.0f ;                                     // Horizontal
200     sy = (f32)KPAD_DPD_RESO_WY / (f32)KPAD_DPD_RESO_WX ;    // Vertical
201 
202     //----- Maximum distance the controller can be moved
203     kp->dpd2pos_scale = sqrtf( sx * sx + sy * sy ) ;// Diagonal line
204 
205     //----- Correct the horizontal range of movement
206     if ( kp->center_org.x < 0.0f ) {
207         sx += kp->center_org.x ;
208     } else {
209         sx -= kp->center_org.x ;
210     }
211 
212     //----- Correct the vertical range of movement
213     if ( kp->center_org.y < 0.0f ) {
214         sy += kp->center_org.y ;
215     } else {
216         sy -= kp->center_org.y ;
217     }
218 
219     //----- Scale that can handle the longest distance possible when a small range of movement is allowed
220     if ( sx < sy ) {
221         kp->dpd2pos_scale /= sx ;
222     } else {
223         kp->dpd2pos_scale /= sy ;
224     }
225 }
226 
227 
228 /*******************************************************************************
229         Initialize KPAD
230  *******************************************************************************/
reset_kpad(KPADInsideStatus * kp)231 static void reset_kpad( KPADInsideStatus *kp )
232 {
233     KPADObject      *op ;
234     KPADStatus      *sp = &kp->status ;
235     KPADEXStatus    *ep = &sp->ex_status ;
236 
237 
238     //----- Clear button data
239     sp->hold = sp->trig = sp->release = 0x00000000 ;
240     kp->btn_repeat_time = 0 ;
241     kp->btn_repeat_next = kp->btn_repeat_delay ;
242 
243     //----- Clear DPD data
244     sp->dpd_valid_fg = 0 ;          // Invalid
245     kp->dpd_valid2_ct = 0 ;
246 
247     sp->pos = sp->vec = Vec2_0 ;
248     sp->speed = 0.0f ;
249 
250     sp->horizon.x = kp->acc_horizon.x = kp->obj_horizon.x = 1.0f ;
251     sp->horizon.y = kp->acc_horizon.y = kp->obj_horizon.y = 0.0f ;
252     sp->hori_vec = Vec2_0 ;
253     sp->hori_speed = 0.0f ;
254 
255     sp->acc_vertical.x = 1.0f ;
256     sp->acc_vertical.y = 0.0f ;
257 
258     sp->dist = kp->dist_org ;
259     sp->dist_vec = sp->dist_speed = 0.0f ;
260 
261     kp->sec_dist = sp->dist ;
262     kp->sec_length = kp->trust_sec_length = kp_dist_vv1 / kp->sec_dist ;
263     kp->sec_nrm = kp->sec_nrm_hori ;
264 
265     //----- Clear acceleration data
266     sp->acc.x = sp->acc.z = 0.0f ;
267     sp->acc.y = -1.0f ;
268     sp->acc_value = 1.0f ;
269     sp->acc_speed = 0.0f ;
270     kp->hard_acc = sp->acc ;
271 
272     kp->ah_circle_pos = kp->acc_horizon ;
273     kp->ah_circle_ct = kp_ah_circle_ct ;
274 
275     //----- Clear data of each object
276     kp->valid_objs = 0 ;
277 
278     op = &kp->kobj_sample[ WPAD_DPD_MAX_OBJECTS - 1 ] ;
279     do {
280         op->error_fg = -1 ;     // Not displayed
281     } while ( --op >= kp->kobj_sample ) ;
282 
283     op = &kp->kobj_regular[ KPAD_USE_OBJECTS - 1 ] ;
284     do {
285         op->error_fg = -1 ;     // Not displayed
286     } while ( --op >= kp->kobj_regular ) ;
287 
288     //----- Miscellaneous
289     kp->wpad_ring_idx = -1 ;        // Process end of ring buffer
290     kp->work_ct = 0 ;               // Number of times DPD processing is performed per game frame
291 
292     sp->wpad_err = WPAD_ERR_NONE ;  // Since there is no error for the time being
293 
294     if ( kp->wpad_chan_no < 0 ) {
295         WPADStopMotor( kp->wpad_chan_no + WPAD_MAX_CONTROLLERS ) ;
296     } else {
297         WPADStopMotor( kp->wpad_chan_no ) ;
298     }
299 
300     //----- Clear extended controller information
301     switch( sp->dev_type ) {
302     case WPAD_DEV_FREESTYLE:
303         //----- Nunchaku unit
304         ep->fs.stick = Vec2_0 ;
305         ep->fs.acc.x = ep->fs.acc.z = 0.0f ;
306         ep->fs.acc.y = -1.0f ;
307         ep->fs.acc_value = 1.0f ;
308         ep->fs.acc_speed = 0.0f ;
309         break ;
310 
311     case WPAD_DEV_CLASSIC:
312         //----- for a Classic Controller unit
313         ep->cl.lstick = Vec2_0;
314         ep->cl.rstick = Vec2_0;
315         ep->cl.ltrigger = ep->cl.rtrigger = 0.0f;
316         ep->cl.hold = ep->cl.trig = ep->cl.release = 0x00000000 ;
317         kp->btn_cl_repeat_time = 0 ;
318         kp->btn_cl_repeat_next = kp->btn_cl_repeat_delay ;
319 
320     default:
321         break ;
322     }
323 }
324 
325 
326 /*******************************************************************************
327         Calibrate
328  *******************************************************************************/
KPADCalibrateDPD(s32 chan)329 s32 KPADCalibrateDPD( s32 chan )
330 {
331     KPADInsideStatus        *kp = &inside_kpads[ chan ] ;
332     KPADStatus              *sp = &kp->status ;
333     KPADObject              *op1, *op2 ;
334     f32                     f1, vx,vy ;
335 
336     ASSERT((0 <= chan) && (chan < WPAD_MAX_CONTROLLERS));
337 
338     if ( kp->valid_objs != KPAD_USE_OBJECTS ) return ( kp->valid_objs ) ;
339 
340     /***********************************************************************
341                 Acceleration after calibration
342      ***********************************************************************/
343     vx = kp->hard_acc.x ;
344     vy = kp->hard_acc.y ;
345     f1 = sqrtf( vx * vx + vy * vy ) ;
346     if ( f1 <= 0.5f ) return (-1) ;         // Abnormal acceleration
347     kp->accXY_nrm_hori.x = vx / f1 ;
348     kp->accXY_nrm_hori.y = vy / f1 ;
349 
350     /***********************************************************************
351                 Object position after calibration
352      ***********************************************************************/
353     //----- Determine the order of marks by position
354     op1 = kp->kobj_sample ;
355     while ( op1->error_fg != 0 ) ++op1 ;
356     op2 = op1 + 1 ;
357     while ( op2->error_fg != 0 ) ++op2 ;
358 
359     if ( op1->center.x < op2->center.x )      goto LABEL_cp12 ;
360     else if ( op2->center.x < op1->center.x ) goto LABEL_cp21 ;
361     else if ( op2->center.y < op1->center.y ) goto LABEL_cp21 ;
362 
363 LABEL_cp12:
364     kp->kobj_regular[0] = *op1 ;
365     kp->kobj_regular[1] = *op2 ;
366     goto LABEL_cpend ;
367 
368 LABEL_cp21:
369     kp->kobj_regular[0] = *op2 ;
370     kp->kobj_regular[1] = *op1 ;
371 
372 LABEL_cpend:
373 
374     //kp->center_org.x = ( kp->kobj_regular[0].center.x + kp->kobj_regular[1].center.x ) * 0.5f ;
375     //kp->center_org.y = ( kp->kobj_regular[0].center.y + kp->kobj_regular[1].center.y ) * 0.5f ;
376     //kp->center_org.x = kp->center_org.y = 0.0f ;
377     calc_dpd2pos_scale( kp ) ;
378 
379     //----- Section direction when the controller is horizontal
380     vx = kp->kobj_regular[KPAD_USE_OBJECTS-1].center.x - kp->kobj_regular[0].center.x ;
381     vy = kp->kobj_regular[KPAD_USE_OBJECTS-1].center.y - kp->kobj_regular[0].center.y ;
382     f1 = 1.0f / sqrtf( vx * vx + vy * vy ) ;        // Should not become zero
383     kp->sec_nrm_hori.x = vx * f1 ;
384     kp->sec_nrm_hori.y = vy * f1 ;
385 
386     /***********************************************************************
387                 Distance after calibration
388      ***********************************************************************/
389     kp->dist_org = kp_dist_vv1 * f1 ;
390 
391     /***********************************************************************
392                 Miscellaneous
393      ***********************************************************************/
394     sp->dpd_valid_fg = 0 ;  // Invalid for the time being
395 
396     return ( kp->valid_objs ) ;
397 }
398 
399 
400 /*******************************************************************************
401         Calibrate
402 *******************************************************************************/
KPADSetSensorHeight(s32 chan,f32 level)403 void KPADSetSensorHeight( s32 chan, f32 level )
404 {
405     KPADInsideStatus        *kp = &inside_kpads[ chan ] ;
406 
407     kp->center_org.x = 0.0f ;
408     kp->center_org.y = -level ;
409     calc_dpd2pos_scale( kp ) ;
410 }
411 
412 /*******************************************************************************
413         interpolation based on Sensor Bar position
414 *******************************************************************************/
KPADGetCalibratedDPD(Vec2 * dst,const Vec2 * src)415 void KPADGetCalibratedDPD( Vec2* dst, const Vec2* src )
416 {
417     f32 result_y;
418     const f32 overlay = 0.25f;
419     const f32 half    = ( 1.0f + overlay ) / 2.0f;
420     const f32 offset  = half - overlay;
421 
422     if ( WPAD_SENSOR_BAR_POS_TOP == WPADGetSensorBarPosition() )
423     {
424         // when the DPD marker is above
425         result_y = ( src->y - offset ) / half;
426     }
427     else
428     {
429         // when the DPD marker is below
430         result_y = ( src->y + offset ) / half;
431     }
432 
433     if ( dst != src )
434     {
435         *dst = *src;
436     }
437 
438     dst->y = result_y;
439 }
440 
441 
442 /*******************************************************************************
443         Repeat processing for digital buttons
444 *******************************************************************************/
calc_button_repeat(KPADInsideStatus * kp,KPADStatus * sp,u32 dev_type)445 static void calc_button_repeat( KPADInsideStatus *kp, KPADStatus *sp, u32 dev_type )
446 {
447     if ( dev_type == WPAD_DEV_CLASSIC ) {
448         if ( sp->ex_status.cl.trig != 0 || sp->ex_status.cl.release != 0 ) {
449             //----- Reset due to change in button status
450             kp->btn_cl_repeat_time = 0 ;
451             kp->btn_cl_repeat_next = kp->btn_cl_repeat_delay ;
452 
453             //----- Set flag even when first being held (only when a repeat setting is used)
454             if ( sp->ex_status.cl.trig && kp->btn_cl_repeat_pulse ) {
455                 sp->ex_status.cl.hold |= KPAD_BUTTON_RPT ;
456             }
457         } else if ( sp->ex_status.cl.hold != 0 ) {
458             //----- Time goes on since button is being held without change in button status
459             kp->btn_cl_repeat_time += kp->work_ct ;
460             if ( kp->btn_cl_repeat_time >= KPAD_BTN_NO_RPT_DELAY ) {
461                 kp->btn_cl_repeat_time -= KPAD_BTN_NO_RPT_DELAY ;
462             }
463 
464             //----- Set flag when repeat time is reached
465             if ( kp->btn_cl_repeat_time >= kp->btn_cl_repeat_next ) {
466                 sp->ex_status.cl.hold |= KPAD_BUTTON_RPT ;
467 
468                 //Set the following repeat time
469                 kp->btn_cl_repeat_next += kp->btn_cl_repeat_pulse ;
470 
471                 //----- Loop here if the time exceeds the allowed range
472                 if ( kp->btn_cl_repeat_time >= KPAD_BTN_RPT_TIME_MAX ) {
473                     kp->btn_cl_repeat_time -= KPAD_BTN_RPT_TIME_MAX ;
474                     kp->btn_cl_repeat_next -= KPAD_BTN_RPT_TIME_MAX ;
475                 }
476             }
477         }
478     } else {
479         if ( sp->trig != 0 || sp->release != 0 ) {
480             //----- Reset due to change in button status
481             kp->btn_repeat_time = 0 ;
482             kp->btn_repeat_next = kp->btn_repeat_delay ;
483 
484             //----- Set flag even when first being held (only when a repeat setting is used)
485             if ( sp->trig && kp->btn_repeat_pulse ) {
486                 sp->hold |= KPAD_BUTTON_RPT ;
487             }
488 
489         } else if ( sp->hold != 0 ) {
490             //----- Time goes on since button is being held without change in button status
491             kp->btn_repeat_time += kp->work_ct ;
492             if ( kp->btn_repeat_time >= KPAD_BTN_NO_RPT_DELAY ) {
493                 kp->btn_repeat_time -= KPAD_BTN_NO_RPT_DELAY ;
494             }
495 
496             //----- Set flag when repeat time is reached
497             if ( kp->btn_repeat_time >= kp->btn_repeat_next ) {
498                 sp->hold |= KPAD_BUTTON_RPT ;
499 
500                 //Set the following repeat time
501                 kp->btn_repeat_next += kp->btn_repeat_pulse ;
502 
503                 //----- Loop here if the time exceeds the allowed range
504                 if ( kp->btn_repeat_time >= KPAD_BTN_RPT_TIME_MAX ) {
505                     kp->btn_repeat_time -= KPAD_BTN_RPT_TIME_MAX ;
506                     kp->btn_repeat_next -= KPAD_BTN_RPT_TIME_MAX ;
507                 }
508             }
509         }
510     }
511 }
512 
513 
514 /*******************************************************************************
515         Process for loading KPAD button data
516  *******************************************************************************/
read_kpad_button(KPADInsideStatus * kp,void * vp,u32 dev_type)517 static void read_kpad_button( KPADInsideStatus *kp, void *vp, u32 dev_type )
518 {
519     KPADStatus      *sp = &kp->status ;
520     KPADEXStatus    *ep = &kp->status.ex_status;
521     u32             old_fg, change_fg ;
522     u32             cl_old_fg, cl_change_fg;
523     WPADStatus      *wp ;
524     WPADFSStatus    *fp ;
525     WPADCLStatus    *cp ;
526 
527 
528     if ( kp->wpad_chan_no < 0 ) return ;
529 
530     //----- Save previous value
531     old_fg = sp->hold & KPAD_BUTTON_MASK ;
532     if ( dev_type == WPAD_DEV_CLASSIC )
533     {
534         cl_old_fg = ep->cl.hold & KPAD_BUTTON_MASK;
535     }
536 
537     //----- Load data
538     if ( dev_type == WPAD_DEV_FREESTYLE ) {
539             fp = (WPADFSStatus*)vp ;
540 
541         if ( fp->err != WPAD_ERR_NONE ) {
542             //----- Disables the port if the controller is disconnected
543             if ( fp->err == WPAD_ERR_NO_CONTROLLER ) {
544                 kp->wpad_chan_no -= WPAD_MAX_CONTROLLERS ;
545                 reset_kpad( kp ) ;
546                 return ;
547             }
548             //----- Inherits the previous status for other errors
549         } else {
550             //----- Load new value
551             sp->hold = (u32)fp->button ;
552         }
553     } else if ( dev_type == WPAD_DEV_CLASSIC ) {
554         cp = (WPADCLStatus*)vp;
555 
556         if ( cp->err != WPAD_ERR_NONE ) {
557             //----- Disables the port if the controller is disconnected
558             if ( cp->err == WPAD_ERR_NO_CONTROLLER ) {
559                 kp->wpad_chan_no -= WPAD_MAX_CONTROLLERS ;
560                 reset_kpad( kp );
561                 return ;
562             }
563             //----- Inherits the previous status for other errors
564         } else {
565             //----- Load new value
566             sp->hold    = (u32)cp->button ;
567             ep->cl.hold = (u32)cp->clButton;
568         }
569     } else {
570         wp = (WPADStatus*)vp ;
571 
572         if ( wp->err != WPAD_ERR_NONE ) {
573             //----- Disables the port if the controller is disconnected
574             if ( wp->err == WPAD_ERR_NO_CONTROLLER ) {
575                 kp->wpad_chan_no -= WPAD_MAX_CONTROLLERS ;
576                 reset_kpad( kp ) ;
577                 return ;
578             }
579             //----- Inherits the previous status for other errors
580         } else {
581             //----- Load new value
582             sp->hold = (u32)wp->button ;
583         }
584     }
585 
586     //----- Process button status
587     change_fg = sp->hold ^ old_fg ;    // Change button
588     sp->trig = change_fg & sp->hold ;  // Held button
589     sp->release = change_fg & old_fg ; // Released button
590 
591     //----- Repeat processing
592     calc_button_repeat( kp, sp, WPAD_DEV_CORE ) ;
593 
594     if ( dev_type == WPAD_DEV_CLASSIC )
595     {
596         cl_change_fg = ep->cl.hold ^ cl_old_fg ;
597         ep->cl.trig = cl_change_fg & ep->cl.hold ;
598         ep->cl.release = cl_change_fg & cl_old_fg ;
599 
600         calc_button_repeat( kp, sp, WPAD_DEV_CLASSIC );
601     }
602 
603 }
604 
605 
606 /*******************************************************************************
607         Sensitivity processing for acceleration
608  *******************************************************************************/
calc_acc(KPADInsideStatus * kp,f32 * acc,f32 acc2)609 static void calc_acc( KPADInsideStatus *kp, f32 *acc, f32 acc2 )
610 {
611     f32             f1,f2 ;
612 
613 
614     //----- Amount short of target value
615     f2 = acc2 - *acc ;
616     if ( f2 < 0.0f ) {
617         f1 = -f2 ;
618     } else {
619         f1 = f2 ;
620     }
621 
622     //----- Calculate interpolation inside/outside play radius
623     if ( f1 >= kp->acc_play_radius ) {
624         //----- Apply 100% sensitivity if outside the play radius
625         f1 = 1.0f ;
626     } else {
627         //----- Weaken sensitivity as the target is approached if inside the play radius
628         f1 /= kp->acc_play_radius ;
629         f1 *= f1 ;      // Raised to the 2nd power
630         f1 *= f1 ;      // Raised to the 4th power
631     }
632     f1 *= kp->acc_sensitivity ;
633 
634     //----- Interpolate
635     *acc += f1 * f2 ;
636 }
637 
638 
639 /*******************************************************************************
640         Calculate orientation of controller based on acceleration
641  *******************************************************************************/
calc_acc_horizon(KPADInsideStatus * kp)642 static void calc_acc_horizon( KPADInsideStatus *kp )
643 {
644     f32             f1, vx,vy, ax,ay ;
645 
646 
647     //----- Normalization of XY acceleration
648     f1 = sqrtf( kp->hard_acc.x * kp->hard_acc.x + kp->hard_acc.y * kp->hard_acc.y ) ;
649     if ( f1 == 0.0f || f1 >= 2.0f ) return ;
650     ax = kp->hard_acc.x / f1 ;
651     ay = kp->hard_acc.y / f1 ;
652 
653     //----- Power increases as the length of XY acceleration approaches 1
654     if ( f1 > 1.0f ) {
655         f1 = 2.0f - f1 ;
656     }
657     f1 *= f1 * kp_acc_horizon_pw ;
658 
659     //----- Target orientation
660     vx = kp->accXY_nrm_hori.x * ax + kp->accXY_nrm_hori.y * ay ;
661     vy = kp->accXY_nrm_hori.y * ax - kp->accXY_nrm_hori.x * ay ;
662 
663     //----- Approach
664     ax = ( vx - kp->acc_horizon.x ) * f1 + kp->acc_horizon.x ;
665     ay = ( vy - kp->acc_horizon.y ) * f1 + kp->acc_horizon.y ;
666 
667     //----- Normalize
668     f1 = sqrtf( ax * ax + ay * ay ) ;
669     if ( f1 == 0.0f ) return ;
670     kp->acc_horizon.x = ax / f1 ;
671     kp->acc_horizon.y = ay / f1 ;
672 
673 
674     //----- Update coordinates to use for determining the controller is at rest
675     kp->ah_circle_pos.x += ( kp->acc_horizon.x - kp->ah_circle_pos.x ) * kp_ah_circle_pw ;
676     kp->ah_circle_pos.y += ( kp->acc_horizon.y - kp->ah_circle_pos.y ) * kp_ah_circle_pw ;
677 
678     vx = kp->acc_horizon.x - kp->ah_circle_pos.x ;
679     vy = kp->acc_horizon.y - kp->ah_circle_pos.y ;
680     if ( vx*vx + vy*vy <= kp_ah_circle_radius2 ) {
681         if ( kp->ah_circle_ct ) -- kp->ah_circle_ct ;
682     } else {
683         kp->ah_circle_ct = kp_ah_circle_ct ;
684     }
685 }
686 
calc_acc_vertical(KPADInsideStatus * kp)687 static void calc_acc_vertical( KPADInsideStatus *kp )
688 {
689     KPADStatus      *sp = &kp->status ;
690     f32             f1,f2, ax,ay ;
691 
692 
693     //----- Target orientation
694     ax = sqrtf( f2 = kp->hard_acc.x * kp->hard_acc.x + kp->hard_acc.y * kp->hard_acc.y ) ;
695     ay = - kp->hard_acc.z ;
696     f1 = sqrtf( f2 + ay * ay ) ;
697     if ( f1 == 0.0f || f1 >= 2.0f ) return ;
698     ax /= f1 ;
699     ay /= f1 ;
700 
701     //----- Power increases as the length of acceleration approaches 1
702     if ( f1 > 1.0f ) {
703         f1 = 2.0f - f1 ;
704     }
705     f1 *= f1 * kp_acc_horizon_pw ;
706 
707     //----- Approach
708     ax = ( ax - sp->acc_vertical.x ) * f1 + sp->acc_vertical.x ;
709     ay = ( ay - sp->acc_vertical.y ) * f1 + sp->acc_vertical.y ;
710 
711     //----- Normalize
712     f1 = sqrtf( ax * ax + ay * ay ) ;
713     if ( f1 == 0.0f ) return ;
714     sp->acc_vertical.x = ax / f1 ;
715     sp->acc_vertical.y = ay / f1 ;
716 }
717 
718 
719 /*******************************************************************************
720         Process for loading KPAD acceleration data
721  *******************************************************************************/
clamp_acc(f32 acc,f32 clamp)722 static f32 clamp_acc( f32 acc, f32 clamp )
723 {
724 	if ( acc < 0.0f ) {
725 		if ( acc < -clamp ) return ( -clamp ) ;
726 	} else {
727 		if ( acc > clamp ) return ( clamp ) ;
728 	}
729 	return ( acc ) ;
730 }
731 
read_kpad_acc(KPADInsideStatus * kp,void * vp,u32 dev_type,s32 chan)732 static void read_kpad_acc( KPADInsideStatus *kp, void *vp, u32 dev_type, s32 chan )
733 {
734     KPADStatus      *sp = &kp->status ;
735     Vec             vec ;
736     WPADStatus      *wp ;
737     WPADFSStatus    *fp ;
738     u32             type ;
739 
740     // �����ɗ����Ă���l�́AWPADGetAccGravityUnit()�ɂ���ē�����
741     // ���m�Ȓl�Ƃ���قǑ傫������Ă͂��Ȃ��͂��B
742     f32    acc_scale_x = 1.0f/100;
743     f32    acc_scale_y = 1.0f/100;
744     f32    acc_scale_z = 1.0f/100;
745     f32 fs_acc_scale_x = 1.0f/200;
746     f32 fs_acc_scale_y = 1.0f/200;
747     f32 fs_acc_scale_z = 1.0f/200;
748 
749     if(WPADProbe(chan, &type)==WPAD_ERR_NONE)
750     {
751         // �R���g���[������1G�̒l���擾���A�‘̍��̋z�����˂炤�B
752         WPADAcc core1G = {1, 1, 1};
753         WPADGetAccGravityUnit( chan, WPAD_DEV_CORE, &core1G);
754         if(core1G.x * core1G.y * core1G.z != 0){    // �o�O�΍�
755             acc_scale_x    = 1.0f / core1G.x;
756             acc_scale_y    = 1.0f / core1G.y;
757             acc_scale_z    = 1.0f / core1G.z;
758         }
759 
760         if ( dev_type == WPAD_DEV_FREESTYLE ) {
761             WPADAcc fs1G = {1, 1, 1};
762             WPADGetAccGravityUnit( chan, WPAD_DEV_FREESTYLE, &fs1G);
763             if(fs1G.x * fs1G.y * fs1G.z != 0){     // �o�O�΍�
764                 fs_acc_scale_x    = 1.0f / fs1G.x;
765                 fs_acc_scale_y    = 1.0f / fs1G.y;
766                 fs_acc_scale_z    = 1.0f / fs1G.z;
767             }
768         }
769     }
770 
771     if ( kp->wpad_chan_no < 0 ) return ;
772 
773     //----- Load data
774     if ( dev_type == WPAD_DEV_FREESTYLE ) {
775         fp = (WPADFSStatus*)vp ;
776 
777         if ( fp->err != WPAD_ERR_NONE ) {
778             //----- Disables the port if the controller is disconnected
779             if ( fp->err == WPAD_ERR_NO_CONTROLLER ) {
780                 kp->wpad_chan_no -= WPAD_MAX_CONTROLLERS ;
781                 reset_kpad( kp ) ;
782                 return ;
783             }
784         } else {
785             //----- Update raw values
786             kp->hard_acc.x = clamp_acc( (f32)(s32)-fp->accX * acc_scale_x, kp_rm_acc_max ) ;
787             kp->hard_acc.y = clamp_acc( (f32)(s32)-fp->accZ * acc_scale_z, kp_rm_acc_max ) ;
788             kp->hard_acc.z = clamp_acc( (f32)(s32) fp->accY * acc_scale_y, kp_rm_acc_max ) ;
789         }
790     } else {
791         wp = (WPADStatus*)vp ;
792 
793         if ( wp->err != WPAD_ERR_NONE ) {
794             //----- Disables the port if the controller is disconnected
795             if ( wp->err == WPAD_ERR_NO_CONTROLLER ) {
796                 kp->wpad_chan_no -= WPAD_MAX_CONTROLLERS ;
797                 reset_kpad( kp ) ;
798                 return ;
799             }
800         } else {
801             //----- Update raw values
802             kp->hard_acc.x = clamp_acc( (f32)(s32)-wp->accX * acc_scale_x, kp_rm_acc_max ) ;
803             kp->hard_acc.y = clamp_acc( (f32)(s32)-wp->accZ * acc_scale_z, kp_rm_acc_max ) ;
804             kp->hard_acc.z = clamp_acc( (f32)(s32) wp->accY * acc_scale_y, kp_rm_acc_max ) ;
805         }
806     }
807 
808     //----- Save temporarily
809     vec = sp->acc ;
810 
811     //----- Acceleration sensitivity processing for the application
812     calc_acc( kp, &sp->acc.x, kp->hard_acc.x ) ;
813     calc_acc( kp, &sp->acc.y, kp->hard_acc.y ) ;
814     calc_acc( kp, &sp->acc.z, kp->hard_acc.z ) ;
815     sp->acc_value = sqrtf( sp->acc.x * sp->acc.x + sp->acc.y * sp->acc.y + sp->acc.z * sp->acc.z ) ;
816 
817     //----- Amount of change in acceleration for the application
818     vec.x -= sp->acc.x ;
819     vec.y -= sp->acc.y ;
820     vec.z -= sp->acc.z ;
821     sp->acc_speed = sqrtf( vec.x * vec.x + vec.y * vec.y + vec.z * vec.z ) ;
822 
823     //----- Calculate orientation of controller based on raw velocity
824     calc_acc_horizon( kp ) ;
825     calc_acc_vertical( kp ) ;
826 
827 
828     /***********************************************************************
829             Load acceleration for nunchaku unit
830     ***********************************************************************/
831     if ( dev_type != WPAD_DEV_FREESTYLE ) return ;
832 
833     //----- Save temporarily
834     vec = sp->ex_status.fs.acc ;
835 
836     //----- Acceleration sensitivity processing for the application
837     calc_acc( kp, &sp->ex_status.fs.acc.x, clamp_acc( (f32)(s32)-fp->fsAccX * fs_acc_scale_x, kp_fs_acc_max ) ) ;
838     calc_acc( kp, &sp->ex_status.fs.acc.y, clamp_acc( (f32)(s32)-fp->fsAccZ * fs_acc_scale_z, kp_fs_acc_max ) ) ;
839     calc_acc( kp, &sp->ex_status.fs.acc.z, clamp_acc( (f32)(s32) fp->fsAccY * fs_acc_scale_y, kp_fs_acc_max ) ) ;
840     sp->ex_status.fs.acc_value = sqrtf( sp->ex_status.fs.acc.x * sp->ex_status.fs.acc.x + sp->ex_status.fs.acc.y * sp->ex_status.fs.acc.y + sp->ex_status.fs.acc.z * sp->ex_status.fs.acc.z ) ;
841 
842     //----- Amount of change in acceleration for the application
843     vec.x -= sp->ex_status.fs.acc.x ;
844     vec.y -= sp->ex_status.fs.acc.y ;
845     vec.z -= sp->ex_status.fs.acc.z ;
846     sp->ex_status.fs.acc_speed = sqrtf( vec.x * vec.x + vec.y * vec.y + vec.z * vec.z ) ;
847 }
848 
849 
850 /*******************************************************************************
851         Convert WPAD object to KPAD
852  *******************************************************************************/
get_kobj(KPADInsideStatus * kp,void * vp,u32 dev_type)853 static void get_kobj( KPADInsideStatus *kp, void *vp, u32 dev_type )
854 {
855     const f32       dpd_scale = 2.0f / (f32)KPAD_DPD_RESO_WX ;
856     const f32       dpd_cx = (f32)( KPAD_DPD_RESO_WX - 1 ) / (f32)KPAD_DPD_RESO_WX ;
857     const f32       dpd_cy = (f32)( KPAD_DPD_RESO_WY - 1 ) / (f32)KPAD_DPD_RESO_WX ;
858 
859     DPDObject       *wobj_p ;
860     KPADObject      *kobj_p ;
861 
862 
863     //----- Store data
864     if ( dev_type == WPAD_DEV_FREESTYLE ) {
865         wobj_p = &((WPADFSStatus*)vp)->obj[ WPAD_DPD_MAX_OBJECTS - 1 ] ;
866     } else if ( dev_type == WPAD_DEV_CLASSIC ) {
867         wobj_p = &((WPADCLStatus*)vp)->obj[ WPAD_DPD_MAX_OBJECTS - 1 ] ;
868     } else {
869         wobj_p = &((WPADStatus*)vp)->obj[ WPAD_DPD_MAX_OBJECTS - 1 ] ;
870     }
871     kobj_p = &kp->kobj_sample[ WPAD_DPD_MAX_OBJECTS - 1 ] ;
872     do {
873         if ( wobj_p->size ) {
874             //----- Valid object
875             kobj_p->center.x = (f32)(s32)wobj_p->x * dpd_scale - dpd_cx ;
876             kobj_p->center.y = (f32)(s32)wobj_p->y * dpd_scale - dpd_cy ;
877 
878             kobj_p->error_fg = 0 ;  // Displayed
879             kobj_p->state_fg = 0 ;  // Normal
880         } else {
881             //----- Invalid object
882             kobj_p->error_fg = -1 ; // Not displayed
883         }
884 
885         -- wobj_p ;
886     } while ( --kobj_p >= kp->kobj_sample ) ;
887 }
888 
889 
890 /*******************************************************************************
891         Invalidate object outside frame
892  *******************************************************************************/
check_kobj_outside_frame(KPADObject * kobj_t)893 static void check_kobj_outside_frame( KPADObject *kobj_t )
894 {
895     KPADObject      *kobj_p = &kobj_t[ WPAD_DPD_MAX_OBJECTS - 1 ] ;
896 
897     do {
898         if ( kobj_p->error_fg < 0 ) continue ;
899 
900         if ( kobj_p->center.x <= kobj_frame_min.x || kobj_p->center.x >= kobj_frame_max.x ||
901              kobj_p->center.y <= kobj_frame_min.y || kobj_p->center.y >= kobj_frame_max.y ) {
902             kobj_p->error_fg |= 1 ;
903         }
904     } while ( --kobj_p >= kobj_t ) ;
905 }
906 
907 
908 /*******************************************************************************
909         Invalidate object with same coordinates
910  *******************************************************************************/
check_kobj_same_position(KPADObject * kobj_t)911 static void check_kobj_same_position( KPADObject *kobj_t )
912 {
913     KPADObject      *op1, *op2 ;
914 
915 
916     op1 = kobj_t ;
917     do {
918         if ( op1->error_fg != 0 ) continue ;
919 
920         op2 = op1 + 1 ;
921         do {
922             if ( op2->error_fg != 0 ) continue ;
923 
924             if ( op1->center.x == op2->center.x && op1->center.y == op2->center.y ) {
925                 op2->error_fg |= 2 ;    // Take as an error only on one side
926             }
927         } while ( ++op2 <= &kobj_t[ WPAD_DPD_MAX_OBJECTS - 1 ] ) ;
928     } while ( ++op1 < &kobj_t[ WPAD_DPD_MAX_OBJECTS - 1 ] ) ;
929 }
930 
931 
932 /*******************************************************************************
933         Calculate controller orientation based on two points (returns distance from TV)
934  *******************************************************************************/
calc_horizon(KPADInsideStatus * kp,Vec2 * p1,Vec2 * p2,Vec2 * hori)935 static f32 calc_horizon( KPADInsideStatus *kp, Vec2 *p1, Vec2 *p2, Vec2 *hori )
936 {
937     f32             f1, vx,vy ;
938 
939 
940     vx = p2->x - p1->x ;
941     vy = p2->y - p1->y ;
942     f1 = 1.0f / sqrtf( vx * vx + vy * vy ) ;        // Should not become zero
943     vx *= f1 ;
944     vy *= f1 ;
945 
946     hori->x = kp->sec_nrm_hori.x * vx + kp->sec_nrm_hori.y * vy ;
947     hori->y = kp->sec_nrm_hori.y * vx - kp->sec_nrm_hori.x * vy ;
948 
949     return ( kp_dist_vv1 * f1 ) ;
950 }
951 
952 
953 /*******************************************************************************
954         First, select two marks
955  *******************************************************************************/
select_2obj_first(KPADInsideStatus * kp)956 static s8 select_2obj_first( KPADInsideStatus *kp )
957 {
958     KPADObject      *op1,*op2, *rp1,*rp2 ;
959     Vec2            hori ;
960     f32             f1, max = kp_err_first_inpr ;
961 
962     op1 = kp->kobj_sample ;
963     do {
964         if ( op1->error_fg != 0 ) continue ;
965 
966         op2 = op1 + 1 ;
967         do {
968             if ( op2->error_fg != 0 ) continue ;
969 
970             f1 = calc_horizon( kp, &op1->center, &op2->center, &hori ) ;
971 
972             //----- Check the operating distance range
973             if ( f1 <= kp_err_dist_min || f1 >= kp_err_dist_max ) continue ;
974 
975             f1 = kp->acc_horizon.x * hori.x + kp->acc_horizon.y * hori.y ;
976             if ( f1 < 0.0f ) {
977                 if ( -f1 > max ) {
978                     max = -f1 ;
979                     rp1 = op2 ;
980                     rp2 = op1 ;
981                 }
982             } else {
983                 if ( f1 > max ) {
984                     max = f1 ;
985                     rp1 = op1 ;
986                     rp2 = op2 ;
987                 }
988             }
989 
990         } while ( ++op2 <= &kp->kobj_sample[ WPAD_DPD_MAX_OBJECTS - 1 ] ) ;
991     } while ( ++op1 < &kp->kobj_sample[ WPAD_DPD_MAX_OBJECTS - 1 ] ) ;
992 
993     //----- Confirm as regular marks?
994     if ( max == kp_err_first_inpr ) return (0) ;
995 
996     kp->kobj_regular[0] = *rp1 ;
997     kp->kobj_regular[1] = *rp2 ;
998 
999     return (2) ;            // Two marks recognized
1000 }
1001 
1002 
1003 /*******************************************************************************
1004         Next, select two marks using only section information
1005  *******************************************************************************/
select_2obj_continue(KPADInsideStatus * kp)1006 static s8 select_2obj_continue( KPADInsideStatus *kp )
1007 {
1008     KPADObject      *op1,*op2, *rp1,*rp2 ;
1009     Vec2            nrm ;
1010     s32             rev_fg ;
1011     f32             f1,f2, vx,vy, min = 2.0f ;
1012 
1013 
1014     //----- Search for the previous slope and the closest two points in distance
1015     op1 = kp->kobj_sample ;
1016     do {
1017         if ( op1->error_fg != 0 ) continue ;
1018 
1019         op2 = op1 + 1 ;
1020         do {
1021             if ( op2->error_fg != 0 ) continue ;
1022 
1023             //----- Calculate direction
1024             vx = op2->center.x - op1->center.x ;
1025             vy = op2->center.y - op1->center.y ;
1026             f1 = 1.0f / sqrtf( vx*vx + vy*vy ) ;    // Should not be zero
1027             nrm.x = vx * f1 ;
1028             nrm.y = vy * f1 ;
1029 
1030             //----- Check the operating distance range
1031             f1 *= kp_dist_vv1 ;             // Distance
1032             if ( f1 <= kp_err_dist_min || f1 >= kp_err_dist_max ) continue ;
1033 
1034             //----- Check the amount of change in distance
1035             f1 -= kp->sec_dist ;
1036             if ( f1 < 0.0f ) {
1037                 f1 *= kp_err_dist_speedM_1 ;
1038             } else {
1039                 f1 *= kp_err_dist_speed_1 ;
1040             }
1041             if ( f1 >= 1.0f ) continue ;    // Distance error rate
1042 
1043             //----- Check the amount of change in slope
1044             f2 = kp->sec_nrm.x * nrm.x + kp->sec_nrm.y * nrm.y ;
1045             if ( f2 < 0.0f ) {
1046                 f2 = -f2 ;
1047                 rev_fg = 1 ;    // Handled by reversing orientation (op2 -> op1)
1048             } else {
1049                 rev_fg = 0 ;    // Handled as-is (op1 -> op2)
1050             }
1051             if ( f2 <= kp_err_next_inpr ) continue ;
1052             f2 = ( 1.0f - f2 ) / ( 1.0f - kp_err_next_inpr ) ;      // Slope error rate
1053 
1054             //----- Record the object with the smallest error
1055             f1 += f2 ;      // Make determination by adding the distance error rate and slope error rate
1056             if ( f1 < min ) {
1057                 min = f1 ;
1058                 if ( rev_fg ) {
1059                     rp1 = op2 ;
1060                     rp2 = op1 ;
1061                 } else {
1062                     rp1 = op1 ;
1063                     rp2 = op2 ;
1064                 }
1065             }
1066 
1067         } while ( ++op2 <= &kp->kobj_sample[ WPAD_DPD_MAX_OBJECTS - 1 ] ) ;
1068     } while ( ++op1 < &kp->kobj_sample[ WPAD_DPD_MAX_OBJECTS - 1 ] ) ;
1069 
1070     //----- Confirm as regular marks?
1071     if ( min == 2.0f ) return (0) ;
1072 
1073     kp->kobj_regular[0] = *rp1 ;
1074     kp->kobj_regular[1] = *rp2 ;
1075 
1076     return (2) ;            // Two marks recognized
1077 }
1078 
1079 
1080 /*******************************************************************************
1081         First, select one mark
1082  *******************************************************************************/
select_1obj_first(KPADInsideStatus * kp)1083 static s8 select_1obj_first( KPADInsideStatus *kp )
1084 {
1085     KPADObject      *op1 ;
1086     f32             vx,vy ;
1087     Vec2            p1,p2 ;
1088 
1089 
1090     //----- Find section direction
1091     vx = kp->sec_nrm_hori.x * kp->acc_horizon.x + kp->sec_nrm_hori.y * kp->acc_horizon.y ;
1092     vy = kp->sec_nrm_hori.y * kp->acc_horizon.x - kp->sec_nrm_hori.x * kp->acc_horizon.y ;
1093 
1094     //----- Find section vector
1095     vx *= kp->trust_sec_length ;
1096     vy *= kp->trust_sec_length ;
1097 
1098     //----- Search for a point where the predicted point lies on the outside
1099     op1 = kp->kobj_sample ;
1100     do {
1101         if ( op1->error_fg != 0 ) continue ;
1102 
1103         p1.x = op1->center.x - vx ;     // Predicted point on the left
1104         p1.y = op1->center.y - vy ;
1105         p2.x = op1->center.x + vx ;     // Predicted point on the right
1106         p2.y = op1->center.y + vy ;
1107 
1108         if ( p1.x <= kobj_frame_min.x || p1.x >= kobj_frame_max.x ||
1109              p1.y <= kobj_frame_min.y || p1.y >= kobj_frame_max.y ) {
1110             //----- If the predicted point on the left is on the outside, the predicted point on the right must be on the inside
1111             if ( p2.x > kobj_frame_min.x && p2.x < kobj_frame_max.x &&
1112                  p2.y > kobj_frame_min.y && p2.y < kobj_frame_max.y ) {
1113                 //----- op1 might be the right mark
1114                 kp->kobj_regular[1] = *op1 ;
1115 
1116                 kp->kobj_regular[0].center = p1 ;
1117                 kp->kobj_regular[0].error_fg = 0 ;
1118                 kp->kobj_regular[0].state_fg = -1 ;
1119 
1120                 return (-1) ;   // Tentative recognition of one mark
1121             }
1122         } else {
1123             //----- If the predicted point on the left is on the inside, the predicted point on the right must be on the outside
1124             if ( p2.x <= kobj_frame_min.x || p2.x >= kobj_frame_max.x ||
1125                  p2.y <= kobj_frame_min.y || p2.y >= kobj_frame_max.y ) {
1126                 //----- op1 might be the left mark
1127                 kp->kobj_regular[0] = *op1 ;
1128 
1129                 kp->kobj_regular[1].center = p2 ;
1130                 kp->kobj_regular[1].error_fg = 0 ;
1131                 kp->kobj_regular[1].state_fg = -1 ;
1132 
1133                 return (-1) ;   // Tentative recognition of one mark
1134             }
1135         }
1136 
1137     } while ( ++op1 < &kp->kobj_sample[ WPAD_DPD_MAX_OBJECTS ] ) ;
1138 
1139     return (0) ;
1140 }
1141 
1142 
1143 /*******************************************************************************
1144         Next, select one mark
1145  *******************************************************************************/
select_1obj_continue(KPADInsideStatus * kp)1146 static s8 select_1obj_continue( KPADInsideStatus *kp )
1147 {
1148     KPADObject      *op1,*op2, *rp1,*rp2 ;
1149     f32             f1, vx,vy ;
1150     f32             min = kp_err_near_pos * kp_err_near_pos ;
1151 
1152 
1153     //----- Select the mark closest to the past regular mark
1154     op1 = kp->kobj_regular ;
1155     do {
1156         if ( op1->error_fg != 0 ) continue ;
1157         if ( op1->state_fg != 0 ) continue ;    // Predicted point no good
1158 
1159         op2 = kp->kobj_sample ;
1160         do {
1161             if ( op2->error_fg != 0 ) continue ;
1162 
1163             vx = op1->center.x - op2->center.x ;
1164             vy = op1->center.y - op2->center.y ;
1165             f1 = vx * vx + vy * vy ;
1166             if ( f1 < min ) {
1167                 min = f1 ;
1168                 rp1 = op1 ;
1169                 rp2 = op2 ;
1170             }
1171         } while ( ++op2 < &kp->kobj_sample[ WPAD_DPD_MAX_OBJECTS ] ) ;
1172     } while ( ++op1 < &kp->kobj_regular[ KPAD_USE_OBJECTS ] ) ;
1173 
1174     //----- Confirm as regular marks?
1175     if ( min == kp_err_near_pos * kp_err_near_pos ) return (0) ;
1176 
1177     *rp1 = *rp2 ;
1178 
1179     //----- Calculate orientation based on velocity
1180     kp->sec_nrm.x = kp->sec_nrm_hori.x * kp->acc_horizon.x + kp->sec_nrm_hori.y * kp->acc_horizon.y ;
1181     kp->sec_nrm.y = kp->sec_nrm_hori.y * kp->acc_horizon.x - kp->sec_nrm_hori.x * kp->acc_horizon.y ;
1182 
1183     //----- Calculate the coordinates of the predicted point
1184     vx = kp->sec_length * kp->sec_nrm.x ;
1185     vy = kp->sec_length * kp->sec_nrm.y ;
1186     if ( rp1 == &kp->kobj_regular[0] ) {
1187         kp->kobj_regular[1].center.x = rp1->center.x + vx ;
1188         kp->kobj_regular[1].center.y = rp1->center.y + vy ;
1189         kp->kobj_regular[1].error_fg = 0 ;
1190         kp->kobj_regular[1].state_fg = -1 ;
1191     } else {
1192         kp->kobj_regular[0].center.x = rp1->center.x - vx ;
1193         kp->kobj_regular[0].center.y = rp1->center.y - vy ;
1194         kp->kobj_regular[0].error_fg = 0 ;
1195         kp->kobj_regular[0].state_fg = -1 ;
1196     }
1197 
1198     if ( kp->status.dpd_valid_fg < 0 ) {
1199         return (-1) ;   // Tentative recognition of one mark
1200     } else {
1201         return (1) ;    // One mark recognized
1202     }
1203 }
1204 
1205 
1206 /*******************************************************************************
1207         Calculate orientation of controller based on the object
1208  *******************************************************************************/
calc_obj_horizon(KPADInsideStatus * kp)1209 static void calc_obj_horizon( KPADInsideStatus *kp )
1210 {
1211     f32             f1, vx,vy ;
1212 
1213 
1214     vx = kp->kobj_regular[1].center.x - kp->kobj_regular[0].center.x ;
1215     vy = kp->kobj_regular[1].center.y - kp->kobj_regular[0].center.y ;
1216     kp->sec_length = sqrtf( vx * vx + vy * vy ) ;   // Should not become zero
1217 
1218     f1 = 1.0f / kp->sec_length ;
1219     kp->sec_dist = kp_dist_vv1 * f1 ;
1220 
1221     kp->sec_nrm.x = ( vx *= f1 ) ;
1222     kp->sec_nrm.y = ( vy *= f1 ) ;
1223 
1224     kp->obj_horizon.x = kp->sec_nrm_hori.x * vx + kp->sec_nrm_hori.y * vy ;
1225     kp->obj_horizon.y = kp->sec_nrm_hori.y * vx - kp->sec_nrm_hori.x * vy ;
1226 }
1227 
1228 
1229 /*******************************************************************************
1230         Update variables used in the application
1231  *******************************************************************************/
calc_dpd_variable(KPADInsideStatus * kp,s8 valid_fg_next)1232 static void calc_dpd_variable( KPADInsideStatus *kp, s8 valid_fg_next )
1233 {
1234     KPADStatus      *sp = &kp->status ;
1235     f32             f1,f2, dist ;
1236     Vec2            pos, vec ;
1237 
1238 
1239     if ( valid_fg_next == 0 ) {
1240         sp->dpd_valid_fg = 0 ;
1241         return ;
1242     }
1243 
1244     /***********************************************************************
1245                 Calculate the orientation of the controller
1246      ***********************************************************************/
1247     //----- Calculate the target value
1248     pos.x = kp->sec_nrm_hori.x * kp->sec_nrm.x + kp->sec_nrm_hori.y * kp->sec_nrm.y ;
1249     pos.y = kp->sec_nrm_hori.y * kp->sec_nrm.x - kp->sec_nrm_hori.x * kp->sec_nrm.y ;
1250 
1251     //----- Take sensitivity and play into account when approaching the target value
1252     if ( sp->dpd_valid_fg == 0 ) {
1253         //----- Initialize using unchanged values during initial pointing
1254         sp->horizon = pos ;
1255         sp->hori_vec = Vec2_0 ;
1256         sp->hori_speed = 0.0f ;
1257     } else {
1258         //----- Amount short of target value
1259         vec.x = pos.x - sp->horizon.x ;
1260         vec.y = pos.y - sp->horizon.y ;
1261         f1 = sqrtf( vec.x * vec.x + vec.y * vec.y ) ;
1262 
1263         //----- Calculate interpolation inside/outside play radius
1264         if ( f1 >= kp->hori_play_radius ) {
1265             //----- Apply 100% sensitivity if outside the play radius
1266             f1 = 1.0f ;
1267         } else {
1268             //----- Weaken sensitivity as the target is approached if inside the play radius
1269             f1 /= kp->hori_play_radius ;
1270             f1 *= f1 ;      // Raised to the 2nd power
1271             f1 *= f1 ;      // Raised to the 4th power
1272         }
1273         f1 *= kp->hori_sensitivity ;
1274 
1275         //----- Interpolate
1276         vec.x = f1 * vec.x + sp->horizon.x ;
1277         vec.y = f1 * vec.y + sp->horizon.y ;
1278         f1 = sqrtf( vec.x * vec.x + vec.y * vec.y ) ;   // Normalize vector slope
1279         vec.x /= f1 ;
1280         vec.y /= f1 ;
1281 
1282         sp->hori_vec.x = vec.x - sp->horizon.x ;
1283         sp->hori_vec.y = vec.y - sp->horizon.y ;
1284         sp->hori_speed = sqrtf( sp->hori_vec.x * sp->hori_vec.x + sp->hori_vec.y * sp->hori_vec.y ) ;
1285 
1286         sp->horizon = vec ;
1287     }
1288 
1289     /***********************************************************************
1290                 Calculate the distance to the TV
1291      ***********************************************************************/
1292     //----- Calculate the target value
1293     dist = kp_dist_vv1 / kp->sec_length ;
1294 
1295     //----- Take sensitivity and play into account when approaching the target value
1296     if ( sp->dpd_valid_fg == 0 ) {
1297         //----- Initialize using unchanged values during initial pointing
1298         sp->dist = dist ;
1299         sp->dist_vec = 0.0f ;
1300         sp->dist_speed = 0.0f ;
1301     } else {
1302         //----- Amount short of target value
1303         f2 = dist - sp->dist ;
1304         if ( f2 < 0.0f ) {
1305             f1 = -f2 ;
1306         } else {
1307             f1 = f2 ;
1308         }
1309 
1310         //----- Calculate interpolation inside/outside play radius
1311         if ( f1 >= kp->dist_play_radius ) {
1312             //----- Apply 100% sensitivity if outside the play radius
1313             f1 = 1.0f ;
1314         } else {
1315             //----- Weaken sensitivity as the target is approached if inside the play radius
1316             f1 /= kp->dist_play_radius ;
1317             f1 *= f1 ;      // Raised to the 2nd power
1318             f1 *= f1 ;      // Raised to the 4th power
1319         }
1320         f1 *= kp->dist_sensitivity ;
1321 
1322         //----- Interpolate
1323         sp->dist_vec = f1 * f2 ;
1324         if ( sp->dist_vec < 0.0f ) {
1325             sp->dist_speed = -sp->dist_vec ;
1326         } else {
1327             sp->dist_speed = sp->dist_vec ;
1328         }
1329 
1330         sp->dist += sp->dist_vec ;
1331     }
1332 
1333     /***********************************************************************
1334                 Calculate the pointing position
1335      ***********************************************************************/
1336     //----- Coordinate of center point between two marks
1337     pos.x = ( kp->kobj_regular[0].center.x + kp->kobj_regular[1].center.x ) * 0.5f ;
1338     pos.y = ( kp->kobj_regular[0].center.y + kp->kobj_regular[1].center.y ) * 0.5f ;
1339 
1340     //----- Rotate by the amount the controller is twisted
1341     f1 =  kp->sec_nrm.x * kp->sec_nrm_hori.x + kp->sec_nrm.y * kp->sec_nrm_hori.y ;
1342     f2 = -kp->sec_nrm.y * kp->sec_nrm_hori.x + kp->sec_nrm.x * kp->sec_nrm_hori.y ;
1343     vec.x = f1 * pos.x - f2 * pos.y ;
1344     vec.y = f2 * pos.x + f1 * pos.y ;
1345 
1346     //----- Scaling by correcting center position
1347     vec.x = ( kp->center_org.x - vec.x ) * kp->dpd2pos_scale ;
1348     vec.y = ( kp->center_org.y - vec.y ) * kp->dpd2pos_scale ;
1349 
1350     //----- Convert to gravity-oriented coordinate system during calibration
1351     pos.x = -kp->accXY_nrm_hori.y * vec.x + kp->accXY_nrm_hori.x * vec.y ;
1352     pos.y = -kp->accXY_nrm_hori.x * vec.x - kp->accXY_nrm_hori.y * vec.y ;
1353 
1354     //----- Take sensitivity and play into account when approaching the target value
1355     if ( sp->dpd_valid_fg == 0 ) {
1356         //----- Initialize using unchanged values during initial pointing
1357         sp->pos = pos ;
1358         sp->vec = Vec2_0 ;
1359         sp->speed = 0.0f ;
1360     } else {
1361         //----- Amount short of target value
1362         vec.x = pos.x - sp->pos.x ;
1363         vec.y = pos.y - sp->pos.y ;
1364         f1 = sqrtf( vec.x * vec.x + vec.y * vec.y ) ;
1365 
1366         //----- Calculate interpolation inside/outside play radius
1367         if ( f1 >= kp->pos_play_radius ) {
1368             //----- Apply 100% sensitivity if outside the play radius
1369             f1 = 1.0f ;
1370         } else {
1371             //----- Weaken sensitivity as the target is approached if inside the play radius
1372             f1 /= kp->pos_play_radius ;
1373             f1 *= f1 ;      // Raised to the 2nd power
1374             f1 *= f1 ;      // Raised to the 4th power
1375         }
1376         f1 *= kp->pos_sensitivity ;
1377 
1378         //----- Interpolate
1379         sp->vec.x = f1 * vec.x ;
1380         sp->vec.y = f1 * vec.y ;
1381         sp->speed = sqrtf( sp->vec.x * sp->vec.x + sp->vec.y * sp->vec.y ) ;
1382 
1383         sp->pos.x += sp->vec.x ;
1384         sp->pos.y += sp->vec.y ;
1385     }
1386 
1387     /***********************************************************************
1388                 Update flags
1389      ***********************************************************************/
1390     sp->dpd_valid_fg = valid_fg_next ;
1391 }
1392 
1393 
1394 /*******************************************************************************
1395         Process for loading KPAD DPD data
1396  *******************************************************************************/
read_kpad_dpd(KPADInsideStatus * kp,void * vp,u32 dev_type)1397 static void read_kpad_dpd( KPADInsideStatus *kp, void *vp, u32 dev_type )
1398 {
1399     KPADStatus      *sp = &kp->status ;
1400     KPADObject      *op1 ;
1401     s8              valid_fg_next ;
1402     WPADStatus      *wp ;
1403     WPADFSStatus    *fp ;
1404     WPADCLStatus    *cp ;
1405 
1406 
1407     if ( kp->wpad_chan_no < 0 ) return ;
1408 
1409     /***********************************************************************
1410                 Convert WPAD object to KPAD
1411      ***********************************************************************/
1412     if ( dev_type == WPAD_DEV_FREESTYLE ) {
1413         fp = (WPADFSStatus*)vp ;
1414 
1415         if ( fp->err != WPAD_ERR_NONE ) {
1416             //----- Disables the port if the controller is disconnected
1417             if ( fp->err == WPAD_ERR_NO_CONTROLLER ) {
1418                 kp->wpad_chan_no -= WPAD_MAX_CONTROLLERS ;
1419                 reset_kpad( kp ) ;
1420                 return ;
1421             }
1422             //----- Inherits the previous status for other errors
1423         } else {
1424             //----- Convert WPAD object to KPAD
1425             get_kobj( kp, fp, WPAD_DEV_FREESTYLE ) ;
1426         }
1427     } else if ( dev_type == WPAD_DEV_CLASSIC ) {
1428         cp = (WPADCLStatus*)vp ;
1429 
1430         if ( cp->err != WPAD_ERR_NONE ) {
1431             //----- Disables the port if the controller is disconnected
1432             if ( cp->err == WPAD_ERR_NO_CONTROLLER ) {
1433                 kp->wpad_chan_no -= WPAD_MAX_CONTROLLERS ;
1434                 reset_kpad( kp ) ;
1435                 return ;
1436             }
1437             //----- Inherits the previous status for other errors
1438         } else {
1439             //----- Convert WPAD object to KPAD
1440             get_kobj( kp, cp, WPAD_DEV_CLASSIC ) ;
1441         }
1442 
1443     } else {
1444         wp = (WPADStatus*)vp ;
1445 
1446         if ( wp->err != WPAD_ERR_NONE ) {
1447             //----- Disables the port if the controller is disconnected
1448             if ( wp->err == WPAD_ERR_NO_CONTROLLER ) {
1449                 kp->wpad_chan_no -= WPAD_MAX_CONTROLLERS ;
1450                 reset_kpad( kp ) ;
1451                 return ;
1452             }
1453             //----- Inherits the previous status for other errors
1454         } else {
1455             //----- Convert WPAD object to KPAD
1456             get_kobj( kp, wp, WPAD_DEV_CORE ) ;
1457         }
1458     }
1459 
1460     /***********************************************************************
1461                 Select out normal objects
1462      ***********************************************************************/
1463     //----- Omit strange objects
1464     check_kobj_outside_frame( kp->kobj_sample ) ;   // Invalidate object outside frame
1465     check_kobj_same_position( kp->kobj_sample ) ;   // Invalidate objects with same coordinates
1466 
1467     //----- Check how many are being displayed
1468     kp->valid_objs = 0 ;
1469     op1 = &kp->kobj_sample[ WPAD_DPD_MAX_OBJECTS - 1 ] ;
1470     do {
1471         if ( op1->error_fg == 0 ) ++ kp->valid_objs ;
1472     } while ( --op1 >= kp->kobj_sample ) ;
1473 
1474     //----- Validation processing
1475     if ( sp->acc_vertical.x <= kp_err_up_inpr ) goto LABEL_select_NG ;
1476 
1477     if ( sp->dpd_valid_fg == 2 || sp->dpd_valid_fg == -2 ) {
1478         //----- Validated two objects on last pass
1479         if ( kp->valid_objs >= 2 )
1480         {
1481             valid_fg_next = select_2obj_continue( kp );
1482             if ( valid_fg_next ) goto LABEL_select_OK ;
1483         }
1484         if ( kp->valid_objs >= 1 )
1485         {
1486             valid_fg_next = select_1obj_continue( kp );
1487             if ( valid_fg_next ) goto LABEL_select_OK ;
1488         }
1489     } else if ( sp->dpd_valid_fg == 1 || sp->dpd_valid_fg == -1 ) {
1490         //----- Validated previous one object
1491         if ( kp->valid_objs >= 2 )
1492         {
1493             valid_fg_next = select_2obj_first( kp );
1494             if ( valid_fg_next ) goto LABEL_select_OK ;
1495         }
1496         if ( kp->valid_objs >= 1 )
1497         {
1498             valid_fg_next = select_1obj_continue( kp );
1499             if ( valid_fg_next ) goto LABEL_select_OK ;
1500         }
1501     } else {
1502         //----- Couldn't validate any objects
1503         if ( kp->valid_objs >= 2 )
1504         {
1505             valid_fg_next = select_2obj_first( kp );
1506 
1507             if ( valid_fg_next ) goto LABEL_select_OK ;
1508         }
1509         if ( kp->valid_objs == 1 )
1510         {
1511             valid_fg_next = select_1obj_first( kp );
1512             if ( valid_fg_next ) goto LABEL_select_OK ;
1513         }
1514     }
1515 
1516 LABEL_select_NG:
1517 
1518     valid_fg_next = 0 ;     // Could not be selected
1519 
1520 LABEL_select_OK:        // Could perhaps be selected
1521 
1522     //----- Update section data if the object could be selected
1523     if ( valid_fg_next ) {
1524         //----- Calculate data for the two points and the object orientation
1525         calc_obj_horizon( kp ) ;
1526 
1527         //----- Error if clearly different from the acceleration slope
1528         if ( kp->ah_circle_ct == 0 ) {
1529             if ( kp->obj_horizon.x * kp->acc_horizon.x + kp->obj_horizon.y * kp->acc_horizon.y <= kp_err_acc_inpr ) {
1530                 valid_fg_next = 0 ;     // Invalid as suspected
1531 
1532                 kp->kobj_regular[0].error_fg =
1533                   kp->kobj_regular[1].error_fg = 1 ;
1534             }
1535         }
1536 
1537         //----- Count for two consecutive valid points
1538         if ( sp->dpd_valid_fg == 2 && valid_fg_next == 2 ) {
1539             if ( kp->dpd_valid2_ct == 200 ) {
1540                 kp->trust_sec_length = kp->sec_length ;
1541             } else {
1542                 ++ kp->dpd_valid2_ct ;
1543             }
1544         } else {
1545             kp->dpd_valid2_ct = 0 ;
1546         }
1547     } else {
1548         kp->dpd_valid2_ct = 0 ;
1549     }
1550 
1551     //----- Update variables used in the application
1552     calc_dpd_variable( kp, valid_fg_next ) ;
1553 }
1554 
1555 
1556 /*******************************************************************************
1557         Process analog trigger clamp
1558 *******************************************************************************/
clamp_trigger(f32 * trigger,s32 tr,s32 min,s32 max)1559 static void clamp_trigger( f32 *trigger, s32 tr, s32 min, s32 max )
1560 {
1561     if ( tr <= min ) {
1562         *trigger = 0.0f ;
1563     } else if ( tr >= max ) {
1564         *trigger = 1.0f ;
1565     } else {
1566         *trigger = (f32)( tr - min ) / (f32)( max - min ) ;
1567     }
1568 }
1569 
1570 
1571 /*******************************************************************************
1572         Process stick clamp
1573 *******************************************************************************/
clamp_stick(Vec2 * stick,s32 sx,s32 sy,s32 min,s32 max)1574 static void clamp_stick( Vec2 *stick, s32 sx, s32 sy, s32 min, s32 max )
1575 {
1576     f32     length ;
1577     f32     fx = (f32)sx ;
1578     f32     fy = (f32)sy ;
1579     f32     fmin = (f32)min ;
1580     f32     fmax = (f32)max ;
1581 
1582 
1583     length = sqrtf( fx * fx + fy * fy ) ;
1584 
1585     if ( length <= fmin ) {
1586         stick->x = stick->y = 0.0f ;
1587 
1588     } else if ( length >= fmax ) {
1589         stick->x = fx / length ;
1590         stick->y = fy / length ;
1591 
1592     } else {
1593         length = ( length - fmin ) / ( fmax - fmin ) / length ;
1594         stick->x = fx * length ;
1595         stick->y = fy * length ;
1596     }
1597 }
1598 
1599 
1600 /*******************************************************************************
1601         Load old GC controller
1602 *******************************************************************************/
read_dolphin(s32 chan,KPADStatus * kstatus)1603 static void read_dolphin( s32 chan, KPADStatus *kstatus )
1604 {
1605     PADStatus   pstatus ;
1606     u32         old_fg, change_fg ;
1607 
1608     ASSERT((0 <= chan) && (chan < WPAD_MAX_CONTROLLERS));
1609 
1610     WPADRead( chan, &pstatus ) ;
1611     if ( pstatus.err != PAD_ERR_NONE ) return ;
1612 
1613     //----- Process analog data
1614     clamp_stick( &kstatus->ex_status.gc.stick, pstatus.stickX, pstatus.stickY, kp_gc_mstick_min, kp_gc_mstick_max ) ;
1615     clamp_stick( &kstatus->ex_status.gc.substick, pstatus.substickX, pstatus.substickY, kp_gc_cstick_min, kp_gc_cstick_max ) ;
1616 
1617     clamp_trigger( &kstatus->ex_status.gc.ltrigger, pstatus.triggerLeft, kp_gc_trigger_min, kp_gc_trigger_max ) ;
1618     clamp_trigger( &kstatus->ex_status.gc.rtrigger, pstatus.triggerRight, kp_gc_trigger_min, kp_gc_trigger_max ) ;
1619 
1620     //----- Process button data
1621     old_fg = kstatus->hold & KPAD_BUTTON_MASK ; // Save last value
1622     kstatus->hold = (u32)pstatus.button ;       // Load new value
1623 
1624     change_fg = kstatus->hold ^ old_fg ;        // Change button
1625     kstatus->trig = change_fg & kstatus->hold ; // Held button
1626     kstatus->release = change_fg & old_fg ;     // Released button
1627 
1628     //----- Repeat processing
1629     calc_button_repeat( &inside_kpads[ chan ], kstatus, 0 ) ;
1630 }
1631 
1632 
1633 /*******************************************************************************
1634         Read the stick information
1635 *******************************************************************************/
read_kpad_stick(KPADInsideStatus * kp,void * vp)1636 static void read_kpad_stick( KPADInsideStatus *kp, void *vp )
1637 {
1638     KPADStatus   *sp = &kp->status ;
1639     WPADFSStatus *fp;
1640     WPADCLStatus *cp;
1641 
1642     //----- Error check
1643     if ( kp->wpad_chan_no < 0 ) return ;
1644 
1645     if ( sp->dev_type == WPAD_DEV_FREESTYLE ) {
1646         fp = (WPADFSStatus*)vp;
1647 
1648         if ( fp->err != WPAD_ERR_NONE ) {
1649             //----- Disables the port if the controller is disconnected
1650             if ( fp->err == WPAD_ERR_NO_CONTROLLER ) {
1651                 kp->wpad_chan_no -= WPAD_MAX_CONTROLLERS ;
1652                 reset_kpad( kp ) ;
1653                 return ;
1654             }
1655         }
1656 
1657         //----- Process stick data
1658         clamp_stick( &sp->ex_status.fs.stick, fp->fsStickX, fp->fsStickY, kp_fs_fstick_min, kp_fs_fstick_max ) ;
1659     } else if ( sp->dev_type == WPAD_DEV_CLASSIC ) {
1660         cp = (WPADCLStatus*)vp;
1661 
1662         if ( cp->err != WPAD_ERR_NONE ) {
1663             //----- Disables the port if the controller is disconnected
1664             if ( cp->err == WPAD_ERR_NO_CONTROLLER ) {
1665                 kp->wpad_chan_no -= WPAD_MAX_CONTROLLERS ;
1666                 reset_kpad( kp ) ;
1667                 return ;
1668             }
1669         }
1670 
1671         //----- Process stick data
1672         clamp_stick( &sp->ex_status.cl.lstick, cp->clLStickX, cp->clLStickY, kp_cl_stick_min, kp_cl_stick_max ) ;
1673         clamp_stick( &sp->ex_status.cl.rstick, cp->clRStickX, cp->clRStickY, kp_cl_stick_min, kp_cl_stick_max ) ;
1674         clamp_trigger( &sp->ex_status.cl.ltrigger, cp->clTriggerL, kp_cl_trigger_min, kp_cl_trigger_max ) ;
1675         clamp_trigger( &sp->ex_status.cl.rtrigger, cp->clTriggerR, kp_cl_trigger_min, kp_cl_trigger_max ) ;
1676 
1677     }
1678 }
1679 
1680 
1681 /*******************************************************************************
1682         Device check (wpad_chan_no is modified)
1683 *******************************************************************************/
check_device(s32 chan,KPADInsideStatus * kp)1684 static s32 check_device( s32 chan, KPADInsideStatus *kp )
1685 {
1686     u32 type ;
1687     s32 err ;
1688 
1689     ASSERT((0 <= chan) && (chan < WPAD_MAX_CONTROLLERS));
1690 
1691     err = WPADProbe( chan, &type ) ;
1692 
1693     if ( err == WPAD_ERR_NO_CONTROLLER ) {
1694         //----- Nothing found
1695         if ( kp->wpad_chan_no >= 0 ) {
1696             //----- Pause auto sampling
1697             WPADSetAutoSamplingBuf( chan, NULL, 0 ) ;
1698             kp->wpad_chan_no = (s16)( chan - WPAD_MAX_CONTROLLERS ) ;
1699             kp->status.dev_type = WPAD_DEV_UNKNOWN ;
1700         }
1701         return ( -1 ) ; // Unconnected
1702     } else if ( err != WPAD_ERR_NONE ) {
1703         //----- Check impossible
1704         return ( 0 ) ;  // Assume no problem for the time being
1705 
1706     } else if ( type == kp->status.dev_type ) {
1707         //----- No problem with the same device as before
1708         return ( 0 ) ;  // No problem
1709     }
1710 
1711     /***********************************************************************
1712             Device has changed
1713     ***********************************************************************/
1714     //----- Pause auto sampling
1715     WPADSetAutoSamplingBuf( chan, NULL, 0 ) ;
1716 
1717     //----- Initialize new device
1718     switch ( type ) {
1719     case WPAD_DEV_CORE:
1720         WPADControlDpd( chan, WPAD_DPD_EXP, NULL ) ;
1721         WPADSetDataFormat( chan, WPAD_FMT_CORE_ACC_DPD);
1722         WPADSetAutoSamplingBuf( chan, kp->wpad_ring_bf, KPAD_RING_BUFS ) ;
1723         break ;
1724     case WPAD_DEV_FREESTYLE:
1725         WPADControlDpd( chan, WPAD_DPD_STD, NULL ) ;
1726         WPADSetDataFormat( chan, WPAD_FMT_FREESTYLE_ACC_DPD ) ;
1727         WPADSetAutoSamplingBuf( chan, kp->wpad_ring_bf, KPAD_RING_BUFS ) ;
1728         break ;
1729     case WPAD_DEV_CLASSIC:
1730         WPADControlDpd( chan, WPAD_DPD_STD, NULL ) ;
1731         WPADSetDataFormat( chan, WPAD_FMT_CLASSIC_ACC_DPD ) ;
1732         WPADSetAutoSamplingBuf( chan, kp->wpad_ring_bf, KPAD_RING_BUFS ) ;
1733         break;
1734 #if 0
1735     case WPAD_DEV_DOLPHIN:
1736         WPADSetDataFormat( chan, WPAD_FMT_DOLPHIN ) ;
1737         break ;
1738 #endif
1739     default:
1740         kp->wpad_chan_no = (s16)( chan - WPAD_MAX_CONTROLLERS ) ;
1741         return ( -1 ) ; // Unexpected device
1742     }
1743 
1744     //Switch to enabled
1745     kp->wpad_chan_no = (s16)chan ;
1746     kp->status.dev_type = type ;
1747     reset_kpad( kp ) ;
1748 
1749     return ( 1 ) ;  // Change has occured with device
1750 }
1751 
1752 
1753 /*******************************************************************************
1754         READ KPAD (return the number of loaded buffers)
1755  *******************************************************************************/
KPADRead(s32 chan,KPADStatus samplingBufs[],u32 length)1756 s32 KPADRead( s32 chan, KPADStatus samplingBufs[], u32 length )
1757 {
1758     KPADInsideStatus        *kp = &inside_kpads[ chan ] ;
1759     KPADStatus              *sp ;
1760     WPADStatus              *wp ;
1761     WPADFSStatus            *fp ;
1762     WPADCLStatus            *cp ;
1763     s32                     idx, idx_old, idx_now ;
1764     s32                     sample_ct, copy_ct ;
1765 
1766     ASSERT((0 <= chan) && (chan < WPAD_MAX_CONTROLLERS));
1767 
1768     /***************************************************************
1769             Set device type
1770     ***************************************************************/
1771     sp = &samplingBufs[ length - 1 ] ;
1772     do {
1773         sp->dev_type = kp->status.dev_type ;
1774     } while ( --sp >= samplingBufs ) ;
1775 
1776     /***************************************************************
1777             Check device
1778     ***************************************************************/
1779     if ( check_device( chan, kp ) ) {
1780         //----- Does nothing if there have been changes and the device is unconnected
1781         return ( 0 ) ;
1782     }
1783 
1784     /***************************************************************
1785             Extended controller processing
1786     ***************************************************************/
1787     if ( kp->status.dev_type != WPAD_DEV_CORE &&
1788          kp->status.dev_type != WPAD_DEV_FREESTYLE &&
1789          kp->status.dev_type != WPAD_DEV_CLASSIC) {
1790         //----- a device other than known ones
1791         ASSERT("Unknown device.");
1792         return ( 0 ) ;
1793     }
1794 
1795     /***************************************************************
1796                 Check the ring buffer inside the scope of current processing
1797      ***************************************************************/
1798     //----- idx_old: Previously processed buffer -> idx_now: Most recent buffer
1799     if( kp->wpad_chan_no >= 0 ) {
1800         idx_now = (s32)WPADGetLatestIndexInBuf( kp->wpad_chan_no ) ;
1801     } else {
1802         idx_now = (s32)WPADGetLatestIndexInBuf( kp->wpad_chan_no + WPAD_MAX_CONTROLLERS ) ;
1803     }
1804 
1805     idx_old = kp->wpad_ring_idx ;
1806     if ( idx_old < 0 ) {            // At start of processing
1807         idx_old = idx_now - 1 ;
1808         if ( idx_old < 0 ) idx_old = KPAD_RING_BUFS - 1 ;
1809     }
1810     kp->wpad_ring_idx = (s16)idx_now ;
1811 
1812     //----- Check the number of internal processes
1813     sample_ct = idx_now - idx_old ;
1814     if ( sample_ct == 0 ) {
1815         return (0) ;            // Still no data to be processed
1816     } else if ( sample_ct < 0 ) {
1817         sample_ct += KPAD_RING_BUFS ;
1818     }
1819 
1820     //----- Check the number of times data is saved to the buffer
1821     if ( sample_ct < length ) {
1822         copy_ct = sample_ct ;
1823     } else {
1824         copy_ct = (s32)length ;
1825     }
1826 
1827     /***************************************************************
1828                 Processing performed for each frame sampled
1829      ***************************************************************/
1830     sp = &samplingBufs[ copy_ct ] ;         // Continue saving with old data at the rear
1831     kp->work_ct = 0 ;
1832     idx = idx_old ;
1833     if ( kp->status.dev_type == WPAD_DEV_CORE ) {
1834         do {
1835             //----- Get SDK ring buffer
1836             if ( ++idx == KPAD_RING_BUFS ) idx = 0 ;
1837             wp = &((WPADStatus*)kp->wpad_ring_bf)[ idx ] ;
1838 
1839             //----- Copy error code
1840             kp->status.wpad_err = wp->err ;
1841 
1842             //----- Load acceleration and DPD data
1843             read_kpad_acc( kp, wp, WPAD_DEV_CORE, chan ) ;
1844             read_kpad_dpd( kp, wp, WPAD_DEV_CORE ) ;
1845 
1846             //----- Copy to KPAD buffer
1847             if ( kp->work_ct >= sample_ct - copy_ct ) {
1848                 -- sp ;                 // Backup storage buffer
1849                 *sp = kp->status ;      // Actually, button data is copied unnecessarily
1850             }
1851         } while ( ++ kp->work_ct < sample_ct ) ;
1852     } else if ( kp->status.dev_type == WPAD_DEV_FREESTYLE) {
1853         do {
1854             //----- Get SDK ring buffer
1855             if ( ++idx == KPAD_RING_BUFS ) idx = 0 ;
1856             fp = &((WPADFSStatus*)kp->wpad_ring_bf)[ idx ] ;
1857 
1858             //----- Copy error code
1859             kp->status.wpad_err = fp->err ;
1860 
1861             //----- Load acceleration and DPD data
1862             read_kpad_acc( kp, fp, WPAD_DEV_FREESTYLE, chan ) ;
1863             read_kpad_dpd( kp, fp, WPAD_DEV_FREESTYLE ) ;
1864             read_kpad_stick( kp, fp ) ;
1865 
1866             //----- Copy to KPAD buffer
1867             if ( kp->work_ct >= sample_ct - copy_ct ) {
1868                 -- sp ;                 // Backup storage buffer
1869                 *sp = kp->status ;      // Actually, button data is copied unnecessarily
1870             }
1871         } while ( ++ kp->work_ct < sample_ct ) ;
1872     } else if ( kp->status.dev_type == WPAD_DEV_CLASSIC ) {
1873         do {
1874             //----- Get SDK ring buffer
1875             if ( ++idx == KPAD_RING_BUFS ) idx = 0 ;
1876             cp = &((WPADCLStatus*)kp->wpad_ring_bf)[ idx ] ;
1877 
1878             //----- Copy error code
1879             kp->status.wpad_err = cp->err ;
1880 
1881             //----- Load acceleration and DPD data
1882             read_kpad_acc( kp, cp, WPAD_DEV_CLASSIC, chan ) ;
1883             read_kpad_dpd( kp, cp, WPAD_DEV_CLASSIC ) ;
1884             read_kpad_stick( kp, cp ) ;
1885 
1886             //----- Copy to KPAD buffer
1887             if ( kp->work_ct >= sample_ct - copy_ct ) {
1888                 -- sp ;                 // Backup storage buffer
1889                 *sp = kp->status ;      // Actually, button data is copied unnecessarily
1890             }
1891         } while ( ++ kp->work_ct < sample_ct ) ;
1892     }
1893 
1894 
1895     /***************************************************************
1896                 Processing performed for each game frame
1897      ***************************************************************/
1898     //----- Load button data
1899     if ( kp->status.dev_type == WPAD_DEV_CORE ) {
1900         read_kpad_button( kp, wp, WPAD_DEV_CORE ) ;
1901     } else if ( kp->status.dev_type == WPAD_DEV_FREESTYLE ) {
1902         read_kpad_button( kp, fp, WPAD_DEV_FREESTYLE ) ;
1903     } else if ( kp->status.dev_type == WPAD_DEV_CLASSIC ) {
1904         read_kpad_button( kp, cp, WPAD_DEV_CLASSIC ) ;
1905     }
1906 
1907     //----- Copy to buffer
1908     idx = copy_ct ;
1909     do {
1910         sp->hold    = kp->status.hold    ;
1911         sp->trig    = kp->status.trig    ;
1912         sp->release = kp->status.release ;
1913         ++ sp ;         // Proceed forward because we're at the start of the storage buffer
1914 
1915         if ( kp->status.dev_type == WPAD_DEV_CLASSIC ) {
1916             sp->ex_status.cl.hold    = kp->status.ex_status.cl.hold;
1917             sp->ex_status.cl.trig    = kp->status.ex_status.cl.trig;
1918             sp->ex_status.cl.release = kp->status.ex_status.cl.release;
1919         }
1920     } while ( --idx != 0 ) ;
1921 
1922     return ( copy_ct ) ;
1923 }
1924 
1925 
1926 /*******************************************************************************
1927         INIT KPAD
1928  *******************************************************************************/
KPADInit(void)1929 void KPADInit( void )
1930 {
1931     s32             i ;
1932     KPADInsideStatus        *kp ;
1933 
1934     //----- WPAD
1935     WPADInit() ;
1936     while (WPADGetStatus() != WPAD_STATE_SETUP)
1937       ;
1938 
1939     //----- KPAD
1940     i = 0 ;
1941     do {
1942         kp = &inside_kpads[i] ;
1943 
1944         //----- Check device
1945         kp->status.dev_type = WPAD_DEV_UNKNOWN ;
1946         kp->wpad_chan_no = (s16)( i - WPAD_MAX_CONTROLLERS ) ;
1947         (void)check_device( i, kp ) ;
1948 
1949         //----- Initialize KPAD calibration value
1950         kp->dist_org = idist_org ;
1951         kp->accXY_nrm_hori = iaccXY_nrm_hori ;
1952         kp->sec_nrm_hori = isec_nrm_hori ;
1953         kp->center_org = icenter_org ;
1954         calc_dpd2pos_scale( kp ) ;
1955 
1956         //----- Initialize KPAD pointing conditions
1957         kp->pos_play_radius  =
1958           kp->hori_play_radius =
1959             kp->dist_play_radius =
1960               kp->acc_play_radius = 0.0f ;
1961 
1962         kp->pos_sensitivity  =
1963           kp->hori_sensitivity =
1964             kp->dist_sensitivity =
1965               kp->acc_sensitivity = 1.0f ;
1966 
1967         //----- Initialize without button repeat
1968         kp->btn_repeat_delay = KPAD_BTN_NO_RPT_DELAY ;
1969         kp->btn_repeat_pulse = 0 ;
1970 
1971         kp->btn_cl_repeat_delay = KPAD_BTN_NO_RPT_DELAY ;
1972         kp->btn_cl_repeat_pulse = 0 ;
1973 
1974     } while ( ++i < WPAD_MAX_CONTROLLERS ) ;
1975 
1976     //----- Initialize values
1977     KPADReset() ;
1978     OSRegisterVersion(__KPADVersion);
1979 }
1980 
1981 
1982 /*******************************************************************************
1983         RESET KPAD
1984  *******************************************************************************/
KPADReset(void)1985 void KPADReset( void )
1986 {
1987     KPADInsideStatus        *kp ;
1988 
1989 
1990     //----- Recalculate constants
1991     KPADSetObjInterval( kp_obj_interval ) ;
1992 
1993     kobj_frame_min.x = -1.0f + kp_err_outside_frame ;
1994     kobj_frame_max.x =  1.0f - kp_err_outside_frame ;
1995     kobj_frame_min.y = -((f32)KPAD_DPD_RESO_WY/KPAD_DPD_RESO_WX) + kp_err_outside_frame ;
1996     kobj_frame_max.y =  ((f32)KPAD_DPD_RESO_WY/KPAD_DPD_RESO_WX) - kp_err_outside_frame ;
1997 
1998     kp_err_dist_speed_1  =  1.0f /  kp_err_dist_speed ;
1999     kp_err_dist_speedM_1 = -1.0f /  kp_err_dist_speed ;
2000     kp_ah_circle_radius2 = kp_ah_circle_radius * kp_ah_circle_radius ;
2001 
2002 
2003     //----- Reset entire KPAD
2004     kp = &inside_kpads[ WPAD_MAX_CONTROLLERS - 1 ] ;
2005     do {
2006         reset_kpad( kp ) ;
2007     } while ( --kp >= inside_kpads ) ;
2008 }
2009