프로젝트

일반

사용자정보

통계
| 개정판:

t1 / TFDContents / Assets / KinectScripts / InteractionManager.cs @ 3

이력 | 보기 | 이력해설 | 다운로드 (35.5 KB)

1
using UnityEngine;
2
using UnityEngine.UI;
3
//using Windows.Kinect;
4

    
5
using System.Collections;
6
using System.Collections.Generic;
7
using System.Runtime.InteropServices;
8
using System;
9
using System.IO;
10

    
11

    
12
/// <summary>
13
/// This interface needs to be implemented by all interaction listeners
14
/// </summary>
15
public interface InteractionListenerInterface
16
{
17
	/// <summary>
18
	/// Invoked when hand grip is detected.
19
	/// </summary>
20
	/// <param name="userId">User ID</param>
21
	/// <param name="userIndex">User index</param>
22
	/// <param name="isRightHand">Whether it is the right hand or not</param>
23
	/// <param name="isHandInteracting">Whether this hand is the interacting one or not</param>
24
	/// <param name="handScreenPos">Hand screen position, including depth (Z)</param>
25
	void HandGripDetected(long userId, int userIndex, bool isRightHand, bool isHandInteracting, Vector3 handScreenPos);
26

    
27
	/// <summary>
28
	/// Invoked when hand release is detected.
29
	/// </summary>
30
	/// <param name="userId">User ID</param>
31
	/// <param name="userIndex">User index</param>
32
	/// <param name="isRightHand">Whether it is the right hand or not</param>
33
	/// <param name="isHandInteracting">Whether this hand is the interacting one or not</param>
34
	/// <param name="handScreenPos">Hand screen position, including depth (Z)</param>
35
	void HandReleaseDetected(long userId, int userIndex, bool isRightHand, bool isHandInteracting, Vector3 handScreenPos);
36

    
37
	/// <summary>
38
	/// Invoked when hand click is detected.
39
	/// </summary>
40
	/// <returns><c>true</c>, if the click detection must be restarted, <c>false</c> otherwise.</returns>
41
	/// <param name="userId">User ID</param>
42
	/// <param name="userIndex">User index</param>
43
	/// <param name="isRightHand">Whether it is the right hand or not</param>
44
	/// <param name="handScreenPos">Hand screen position, including depth (Z)</param>
45
	bool HandClickDetected(long userId, int userIndex, bool isRightHand, Vector3 handScreenPos);
46
}
47

    
48

    
49
/// <summary>
50
/// Interaction manager is component that controls the hand cursor and manages the hand interactions.
51
/// </summary>
52
public class InteractionManager : MonoBehaviour 
53
{
54
	/// <summary>
55
	/// The hand event types.
56
	/// </summary>
57
	public enum HandEventType : int
58
    {
59
        None = 0,
60
        Grip = 1,
61
        Release = 2
62
    }
63

    
64
	[Tooltip("Index of the player, tracked by this component. 0 means the 1st player, 1 - the 2nd one, 2 - the 3rd one, etc.")]
65
	public int playerIndex = 0;
66
	
67
	[Tooltip("The image that may be used to show the hand-moved cursor on the screen or not. The sprite textures below need to be set too.")]
68
	public Image guiHandCursor;
69

    
70
	[Tooltip("Hand-cursor sprite texture, for the hand-grip state.")]
71
	public Sprite gripHandTexture;
72
	[Tooltip("Hand-cursor sprite texture, for the hand-release state.")]
73
	public Sprite releaseHandTexture;
74
	[Tooltip("Hand-cursor sprite texture, for the non-tracked state.")]
75
	public Sprite normalHandTexture;
76

    
77
	[Tooltip("Whether the cursor should overlay user's hand on screen or not.")]
78
	public bool handOverlayCursor = false;
79

    
80
	[Tooltip("Smooth factor for cursor movement.")]
81
	public float smoothFactor = 10f;
82
	
83
	[Tooltip("Whether the hand clicks (i.e. hand staying in place for ~2 seconds) are enabled or not.")]
84
	public bool allowHandClicks = true;
85
	
86
	[Tooltip("Whether the hand pushes need to be considered as clicks or not.")]
87
	public bool allowPushToClick = true;
88

    
89
	[Tooltip("Whether the hand cursor and interactions control the mouse cursor or not.")]
90
	public bool controlMouseCursor = false;
91

    
92
	[Tooltip("Whether the hand grips and releases control mouse dragging or not.")]
93
	public bool controlMouseDrag = false;
94

    
95
	// Bool to specify whether to convert Unity screen coordinates to full screen mouse coordinates
96
	//public bool convertMouseToFullScreen = false;
97
	
98
	[Tooltip("List of the interaction listeners in the scene. If the list is empty, the available interaction listeners will be detected at scene start up.")]
99
	public List<MonoBehaviour> interactionListeners;
100

    
101
	[Tooltip("GUI-Text to display the interaction-manager debug messages.")]
102
	public GUIText debugText;
103

    
104
	// tracked userId
105
	private long playerUserID = 0;
106
	private long lastUserID = 0;
107

    
108
	// hand press properties
109
	private bool isLeftHandPrimary = false;
110
	private bool isRightHandPrimary = false;
111
	
112
	private bool isLeftHandPress = false;
113
	private bool isRightHandPress = false;
114

    
115
	private float lastLeftHandPressTime = 0f;
116
	private float lastRightHandPressTime = 0f;
117

    
118
	private float leftHandPressProgress = 0f;
119
	private float rightHandPressProgress = 0f;
120

    
121
	// cursor properties
122
	private Vector3 cursorScreenPos = Vector3.zero;
123
	private bool dragInProgress = false;
124
	
125
	private Image cursorProgressBar;
126
	private float cursorClickProgress = 0f;
127

    
128
	// hand states
129
	private KinectInterop.HandState leftHandState = KinectInterop.HandState.Unknown;
130
	private KinectInterop.HandState rightHandState = KinectInterop.HandState.Unknown;
131

    
132
	// left hand properties
133
	private HandEventType leftHandEvent = HandEventType.None;
134
	private HandEventType lastLeftHandEvent = HandEventType.Release;
135

    
136
	private Vector3 leftHandPos = Vector3.zero;
137
	private Vector3 leftHandScreenPos = Vector3.zero;
138
	private Vector3 leftIboxLeftBotBack = Vector3.zero;
139
	private Vector3 leftIboxRightTopFront = Vector3.zero;
140
	private bool isleftIboxValid = false;
141
	private bool isLeftHandInteracting = false;
142
	private float leftHandInteractingSince = 0f;
143

    
144
	// left hand click properties
145
	private Vector3 lastLeftHandPos = Vector3.zero;
146
	private float lastLeftHandClickTime = 0f;
147
	private bool isLeftHandClick = false;
148
	private float leftHandClickProgress = 0f;
149

    
150
	// left hand properties
151
	private HandEventType rightHandEvent = HandEventType.None;
152
	private HandEventType lastRightHandEvent = HandEventType.Release;
153

    
154
	private Vector3 rightHandPos = Vector3.zero;
155
	private Vector3 rightHandScreenPos = Vector3.zero;
156
	private Vector3 rightIboxLeftBotBack = Vector3.zero;
157
	private Vector3 rightIboxRightTopFront = Vector3.zero;
158
	private bool isRightIboxValid = false;
159
	private bool isRightHandInteracting = false;
160
	private float rightHandInteractingSince = 0f;
161

    
162
	// right hand click properties
163
	private Vector3 lastRightHandPos = Vector3.zero;
164
	private float lastRightHandClickTime = 0f;
165
	private bool isRightHandClick = false;
166
	private float rightHandClickProgress = 0f;
167

    
168
	// Bool to keep track whether Kinect and Interaction library have been initialized
169
	private bool interactionInited = false;
170
	
171
	// The single instance of FacetrackingManager
172
	private static InteractionManager instance;
173

    
174
	
175
	/// <summary>
176
	/// Gets the single InteractionManager instance.
177
	/// </summary>
178
	/// <value>The InteractionManager instance.</value>
179
    public static InteractionManager Instance
180
    {
181
        get
182
        {
183
            return instance;
184
        }
185
    }
186
	
187
	/// <summary>
188
	/// Determines whether the InteractionManager was successfully initialized.
189
	/// </summary>
190
	/// <returns><c>true</c> if InteractionManager was successfully initialized; otherwise, <c>false</c>.</returns>
191
	public bool IsInteractionInited()
192
	{
193
		return interactionInited;
194
	}
195
	
196
	/// <summary>
197
	/// Gets the current user ID, or 0 if no user is currently tracked.
198
	/// </summary>
199
	/// <returns>The user ID</returns>
200
	public long GetUserID()
201
	{
202
		return playerUserID;
203
	}
204
	
205
	/// <summary>
206
	/// Gets the current left hand event (none, grip or release).
207
	/// </summary>
208
	/// <returns>The current left hand event.</returns>
209
	public HandEventType GetLeftHandEvent()
210
	{
211
		return leftHandEvent;
212
	}
213
	
214
	/// <summary>
215
	/// Gets the last detected left hand event (grip or release).
216
	/// </summary>
217
	/// <returns>The last left hand event.</returns>
218
	public HandEventType GetLastLeftHandEvent()
219
	{
220
		return lastLeftHandEvent;
221
	}
222
	
223
	/// <summary>
224
	/// Gets the current normalized viewport position of the left hand, in range [0, 1].
225
	/// </summary>
226
	/// <returns>The left hand viewport position.</returns>
227
	public Vector3 GetLeftHandScreenPos()
228
	{
229
		return leftHandScreenPos;
230
	}
231
	
232
	/// <summary>
233
	/// Determines whether the left hand is primary for the user.
234
	/// </summary>
235
	/// <returns><c>true</c> if the left hand is primary for the user; otherwise, <c>false</c>.</returns>
236
	public bool IsLeftHandPrimary()
237
	{
238
		return isLeftHandPrimary;
239
	}
240
	
241
	/// <summary>
242
	/// Determines whether the left hand is pressing.
243
	/// </summary>
244
	/// <returns><c>true</c> if the left hand is pressing; otherwise, <c>false</c>.</returns>
245
	public bool IsLeftHandPress()
246
	{
247
		return isLeftHandPress;
248
	}
249
	
250
	/// <summary>
251
	/// Determines whether a left hand click is detected, false otherwise.
252
	/// </summary>
253
	/// <returns><c>true</c> if a left hand click is detected; otherwise, <c>false</c>.</returns>
254
	public bool IsLeftHandClickDetected()
255
	{
256
		if(isLeftHandClick)
257
		{
258
			isLeftHandClick = false;
259
			cursorClickProgress = leftHandClickProgress = 0f;
260
			lastLeftHandPos = Vector3.zero;
261

    
262
			lastLeftHandClickTime = Time.realtimeSinceStartup;
263
			lastLeftHandPressTime = Time.realtimeSinceStartup;
264
			
265
			return true;
266
		}
267
		
268
		return false;
269
	}
270

    
271
	/// <summary>
272
	/// Gets the left hand click progress, in range [0, 1].
273
	/// </summary>
274
	/// <returns>The left hand click progress.</returns>
275
	public float GetLeftHandClickProgress()
276
	{
277
		return leftHandClickProgress;
278
	}
279
	
280
	/// <summary>
281
	/// Gets the current right hand event (none, grip or release).
282
	/// </summary>
283
	/// <returns>The current right hand event.</returns>
284
	public HandEventType GetRightHandEvent()
285
	{
286
		return rightHandEvent;
287
	}
288
	
289
	/// <summary>
290
	/// Gets the last detected right hand event (grip or release).
291
	/// </summary>
292
	/// <returns>The last right hand event.</returns>
293
	public HandEventType GetLastRightHandEvent()
294
	{
295
		return lastRightHandEvent;
296
	}
297
	
298
	/// <summary>
299
	/// Gets the current normalized viewport position of the right hand, in range [0, 1].
300
	/// </summary>
301
	/// <returns>The right hand viewport position.</returns>
302
	public Vector3 GetRightHandScreenPos()
303
	{
304
		return rightHandScreenPos;
305
	}
306
	
307
	/// <summary>
308
	/// Determines whether the right hand is primary for the user.
309
	/// </summary>
310
	/// <returns><c>true</c> if the right hand is primary for the user; otherwise, <c>false</c>.</returns>
311
	public bool IsRightHandPrimary()
312
	{
313
		return isRightHandPrimary;
314
	}
315
	
316
	/// <summary>
317
	/// Determines whether the right hand is pressing.
318
	/// </summary>
319
	/// <returns><c>true</c> if the right hand is pressing; otherwise, <c>false</c>.</returns>
320
	public bool IsRightHandPress()
321
	{
322
		return isRightHandPress;
323
	}
324
	
325
	/// <summary>
326
	/// Determines whether a right hand click is detected, false otherwise.
327
	/// </summary>
328
	/// <returns><c>true</c> if a right hand click is detected; otherwise, <c>false</c>.</returns>
329
	public bool IsRightHandClickDetected()
330
	{
331
		if(isRightHandClick)
332
		{
333
			isRightHandClick = false;
334
			cursorClickProgress = rightHandClickProgress = 0f;
335
			lastRightHandPos = Vector3.zero;
336

    
337
			lastRightHandClickTime = Time.realtimeSinceStartup;
338
			lastRightHandPressTime = Time.realtimeSinceStartup;
339
			
340
			return true;
341
		}
342
		
343
		return false;
344
	}
345

    
346
	/// <summary>
347
	/// Gets the right hand click progress, in range [0, 1].
348
	/// </summary>
349
	/// <returns>The right hand click progress.</returns>
350
	public float GetRightHandClickProgress()
351
	{
352
		return rightHandClickProgress;
353
	}
354
	
355
	/// <summary>
356
	/// Gets the current cursor normalized viewport position.
357
	/// </summary>
358
	/// <returns>The cursor viewport position.</returns>
359
	public Vector3 GetCursorPosition()
360
	{
361
		return cursorScreenPos;
362
	}
363

    
364
	/// <summary>
365
	/// Gets the cursor click progress, in range [0, 1].
366
	/// </summary>
367
	/// <returns>The right hand click progress.</returns>
368
	public float GetCursorClickProgress()
369
	{
370
		return cursorClickProgress;
371
	}
372

    
373

    
374
	//----------------------------------- end of public functions --------------------------------------//
375

    
376
	void Awake()
377
	{
378
		instance = this;
379
	}
380

    
381

    
382
	void Start() 
383
	{
384
		// get the progress bar reference if any
385
		GameObject objProgressBar = guiHandCursor && guiHandCursor.gameObject.transform.childCount > 0 ? guiHandCursor.transform.GetChild(0).gameObject : null;
386
		cursorProgressBar = objProgressBar ? objProgressBar.GetComponent<Image>() : null;
387

    
388
		interactionInited = true;
389

    
390
		// try to automatically detect the available interaction listeners in the scene
391
		if(interactionListeners.Count == 0)
392
		{
393
			MonoBehaviour[] monoScripts = FindObjectsOfType(typeof(MonoBehaviour)) as MonoBehaviour[];
394

    
395
			foreach(MonoBehaviour monoScript in monoScripts)
396
			{
397
//				if(typeof(InteractionListenerInterface).IsAssignableFrom(monoScript.GetType()) &&
398
//					monoScript.enabled)
399
				if((monoScript is InteractionListenerInterface) && monoScript.enabled)
400
				{
401
					interactionListeners.Add(monoScript);
402
				}
403
			}
404
		}
405

    
406
	}
407
	
408
	void OnDestroy()
409
	{
410
		interactionInited = false;
411
		instance = null;
412
	}
413
	
414
	void Update () 
415
	{
416
		KinectManager kinectManager = KinectManager.Instance;
417
		
418
		// update Kinect interaction
419
		if(kinectManager && kinectManager.IsInitialized())
420
		{
421
			playerUserID = kinectManager.GetUserIdByIndex(playerIndex);
422
			
423
			if(playerUserID != 0)
424
			{
425
				lastUserID = playerUserID;
426
				HandEventType handEvent = HandEventType.None;
427
				
428
				// get the left hand state
429
				leftHandState = kinectManager.GetLeftHandState(playerUserID);
430
				
431
				// check if the left hand is interacting
432
				isleftIboxValid = kinectManager.GetLeftHandInteractionBox(playerUserID, ref leftIboxLeftBotBack, ref leftIboxRightTopFront, isleftIboxValid);
433
				//bool bLeftHandPrimaryNow = false;
434

    
435
				// was the left hand interacting till now
436
				bool wasLeftHandInteracting = isLeftHandInteracting;
437

    
438
				if(isleftIboxValid && //bLeftHandPrimaryNow &&
439
				   kinectManager.GetJointTrackingState(playerUserID, (int)KinectInterop.JointType.HandLeft) != KinectInterop.TrackingState.NotTracked)
440
				{
441
					leftHandPos = kinectManager.GetJointPosition(playerUserID, (int)KinectInterop.JointType.HandLeft);
442
					leftHandScreenPos.z = Mathf.Clamp01((leftIboxLeftBotBack.z - leftHandPos.z) / (leftIboxLeftBotBack.z - leftIboxRightTopFront.z));
443

    
444
					if (!handOverlayCursor) 
445
					{
446
						leftHandScreenPos.x = Mathf.Clamp01((leftHandPos.x - leftIboxLeftBotBack.x) / (leftIboxRightTopFront.x - leftIboxLeftBotBack.x));
447
						leftHandScreenPos.y = Mathf.Clamp01((leftHandPos.y - leftIboxLeftBotBack.y) / (leftIboxRightTopFront.y - leftIboxLeftBotBack.y));
448

    
449
						isLeftHandInteracting = (leftHandPos.x >= (leftIboxLeftBotBack.x - 1.0f)) && (leftHandPos.x <= (leftIboxRightTopFront.x + 0.5f)) &&
450
							(leftHandPos.y >= (leftIboxLeftBotBack.y - 0.1f)) && (leftHandPos.y <= (leftIboxRightTopFront.y + 0.7f)) &&
451
							(leftIboxLeftBotBack.z >= leftHandPos.z) && (leftIboxRightTopFront.z * 0.8f <= leftHandPos.z);
452
					}
453
					else
454
					{
455
						isLeftHandInteracting = GetHandOverlayScreenPos (kinectManager, (int)KinectInterop.JointType.HandLeft, ref leftHandScreenPos) &&
456
							(leftHandPos.y >= (leftIboxLeftBotBack.y - 0.15f)) && (leftHandPos.y <= (leftIboxRightTopFront.y + 0.7f)) &&
457
							(leftIboxLeftBotBack.z >= leftHandPos.z) && (leftIboxRightTopFront.z * 0.8f <= leftHandPos.z);
458
					}
459

    
460
					//bLeftHandPrimaryNow = isLeftHandInteracting;
461
					// start interacting?
462
					if(!wasLeftHandInteracting && isLeftHandInteracting)
463
					{
464
						leftHandInteractingSince = Time.realtimeSinceStartup;
465
					}
466

    
467
					// check for left press
468
					isLeftHandPress = leftHandScreenPos.z > 0.99f; // ((leftIboxRightTopFront.z - 0.1f) >= leftHandPos.z);
469
					leftHandPressProgress = (Time.realtimeSinceStartup - lastLeftHandPressTime) >= KinectInterop.Constants.ClickStayDuration && 
470
												leftHandScreenPos.z >= 0.7f ? (leftHandScreenPos.z - 0.7f) / 0.3f : 0f;
471

    
472
					// check for left hand click
473
					if(!dragInProgress && isLeftHandInteracting && 
474
						((allowHandClicks && ((leftHandPos - lastLeftHandPos).magnitude < KinectInterop.Constants.ClickMaxDistance)) ||
475
							(allowPushToClick && leftHandPressProgress > 0f)))
476
					{
477
						if((allowHandClicks && (Time.realtimeSinceStartup - lastLeftHandClickTime) >= KinectInterop.Constants.ClickStayDuration) ||
478
							(allowPushToClick && leftHandPressProgress > 0.99f && isLeftHandPress))
479
						{
480
							if(!isLeftHandClick)
481
							{
482
								isLeftHandClick = true;
483
								cursorClickProgress = leftHandClickProgress = 1f;
484

    
485
								foreach(InteractionListenerInterface listener in interactionListeners)
486
								{
487
									if (listener.HandClickDetected (playerUserID, playerIndex, false, leftHandScreenPos)) 
488
									{
489
										isLeftHandClick = false;
490
										cursorClickProgress = leftHandClickProgress = 0f;
491
										lastLeftHandPos = Vector3.zero;
492

    
493
										lastLeftHandClickTime = Time.realtimeSinceStartup;
494
										lastLeftHandPressTime = Time.realtimeSinceStartup;
495
									}
496
								}
497

    
498
								if(controlMouseCursor)
499
								{
500
									MouseControl.MouseClick();
501

    
502
									isLeftHandClick = false;
503
									cursorClickProgress = leftHandClickProgress = 0f;
504
									lastLeftHandPos = Vector3.zero;
505

    
506
									lastLeftHandClickTime = Time.realtimeSinceStartup;
507
									lastLeftHandPressTime = Time.realtimeSinceStartup;
508
								}
509
							}
510
						}
511
						else
512
						{
513
							// show progress after the 1st half of the needed duration
514
							float leftHandTimeProgress = allowHandClicks && (Time.realtimeSinceStartup - lastLeftHandClickTime) >= (KinectInterop.Constants.ClickStayDuration / 2f) ? 
515
								((Time.realtimeSinceStartup - lastLeftHandClickTime - (KinectInterop.Constants.ClickStayDuration / 2f)) * 2f / KinectInterop.Constants.ClickStayDuration) : 0f;
516
							cursorClickProgress = leftHandClickProgress = allowPushToClick && leftHandScreenPos.z >= 0.7f ? leftHandPressProgress : leftHandTimeProgress;
517
						}
518
					}
519
					else
520
					{
521
						isLeftHandClick = false;
522
						leftHandClickProgress = 0f;
523
						lastLeftHandPos = leftHandPos;
524
						lastLeftHandClickTime = Time.realtimeSinceStartup;
525
					}
526
				}
527
				else
528
				{
529
					isLeftHandInteracting = false;
530
					isLeftHandPress = false;
531
					leftHandPressProgress = 0f;
532
				}
533
				
534
				// get the right hand state
535
				rightHandState = kinectManager.GetRightHandState(playerUserID);
536

    
537
				// check if the right hand is interacting
538
				isRightIboxValid = kinectManager.GetRightHandInteractionBox(playerUserID, ref rightIboxLeftBotBack, ref rightIboxRightTopFront, isRightIboxValid);
539
				//bool bRightHandPrimaryNow = false;
540

    
541
				// was the right hand interacting till now
542
				bool wasRightHandInteracting = isRightHandInteracting;
543

    
544
				if(isRightIboxValid && //bRightHandPrimaryNow &&
545
				   kinectManager.GetJointTrackingState(playerUserID, (int)KinectInterop.JointType.HandRight) != KinectInterop.TrackingState.NotTracked)
546
				{
547
					rightHandPos = kinectManager.GetJointPosition(playerUserID, (int)KinectInterop.JointType.HandRight);
548
					rightHandScreenPos.z = Mathf.Clamp01((rightIboxLeftBotBack.z - rightHandPos.z) / (rightIboxLeftBotBack.z - rightIboxRightTopFront.z));
549

    
550
					if (!handOverlayCursor) 
551
					{
552
						rightHandScreenPos.x = Mathf.Clamp01((rightHandPos.x - rightIboxLeftBotBack.x) / (rightIboxRightTopFront.x - rightIboxLeftBotBack.x));
553
						rightHandScreenPos.y = Mathf.Clamp01((rightHandPos.y - rightIboxLeftBotBack.y) / (rightIboxRightTopFront.y - rightIboxLeftBotBack.y));
554

    
555
						isRightHandInteracting = (rightHandPos.x >= (rightIboxLeftBotBack.x - 0.5f)) && (rightHandPos.x <= (rightIboxRightTopFront.x + 1.0f)) &&
556
							(rightHandPos.y >= (rightIboxLeftBotBack.y - 0.1f)) && (rightHandPos.y <= (rightIboxRightTopFront.y + 0.7f)) &&
557
							(rightIboxLeftBotBack.z >= rightHandPos.z) && (rightIboxRightTopFront.z * 0.8f <= rightHandPos.z);
558
					}
559
					else
560
					{
561
						isRightHandInteracting = GetHandOverlayScreenPos(kinectManager, (int)KinectInterop.JointType.HandRight, ref rightHandScreenPos) &&
562
							(rightHandPos.y >= (rightIboxLeftBotBack.y - 0.15f)) && (rightHandPos.y <= (rightIboxRightTopFront.y + 0.7f)) &&
563
							(rightIboxLeftBotBack.z >= rightHandPos.z) && (rightIboxRightTopFront.z * 0.8f <= rightHandPos.z);
564
					}
565

    
566
					//bRightHandPrimaryNow = isRightHandInteracting;
567
					if(!wasRightHandInteracting && isRightHandInteracting)
568
					{
569
						rightHandInteractingSince = Time.realtimeSinceStartup;
570
					}
571
					
572
					// check for right press
573
					isRightHandPress = rightHandScreenPos.z > 0.99f; // ((rightIboxRightTopFront.z - 0.1f) >= rightHandPos.z);
574
					rightHandPressProgress = (Time.realtimeSinceStartup - lastRightHandPressTime) >= KinectInterop.Constants.ClickStayDuration &&
575
												rightHandScreenPos.z >= 0.7f ? (rightHandScreenPos.z - 0.7f) / 0.3f : 0f;
576

    
577
					// check for right hand click
578
					if(!dragInProgress && isRightHandInteracting && 
579
						((allowHandClicks && ((rightHandPos - lastRightHandPos).magnitude < KinectInterop.Constants.ClickMaxDistance)) ||
580
							(allowPushToClick && rightHandPressProgress > 0f)))
581
					{
582
						if((allowHandClicks && (Time.realtimeSinceStartup - lastRightHandClickTime) >= KinectInterop.Constants.ClickStayDuration) ||
583
							(allowPushToClick && rightHandPressProgress > 0.99f && isRightHandPress))
584
						{
585
							if(!isRightHandClick)
586
							{
587
								isRightHandClick = true;
588
								cursorClickProgress = rightHandClickProgress = 1f;
589
								
590
								foreach(InteractionListenerInterface listener in interactionListeners)
591
								{
592
									if (listener.HandClickDetected (playerUserID, playerIndex, true, rightHandScreenPos)) 
593
									{
594
										isRightHandClick = false;
595
										cursorClickProgress = rightHandClickProgress = 0f;
596
										lastRightHandPos = Vector3.zero;
597

    
598
										lastRightHandClickTime = Time.realtimeSinceStartup;
599
										lastRightHandPressTime = Time.realtimeSinceStartup;
600
									}
601
								}
602

    
603
								if(controlMouseCursor)
604
								{
605
									MouseControl.MouseClick();
606

    
607
									isRightHandClick = false;
608
									cursorClickProgress = rightHandClickProgress = 0f;
609
									lastRightHandPos = Vector3.zero;
610

    
611
									lastRightHandClickTime = Time.realtimeSinceStartup;
612
									lastRightHandPressTime = Time.realtimeSinceStartup;
613
								}
614
							}
615
						}
616
						else
617
						{
618
							// show progress after the 1st half of the needed duration
619
							float rightHandTimeProgress = allowHandClicks && (Time.realtimeSinceStartup - lastRightHandClickTime) >= (KinectInterop.Constants.ClickStayDuration / 2f) ? 
620
								((Time.realtimeSinceStartup - lastRightHandClickTime - (KinectInterop.Constants.ClickStayDuration / 2f)) * 2f / KinectInterop.Constants.ClickStayDuration) : 0f;
621
							cursorClickProgress = rightHandClickProgress = allowPushToClick && rightHandScreenPos.z >= 0.7f ? rightHandPressProgress : rightHandTimeProgress;
622
						}
623
					}
624
					else
625
					{
626
						isRightHandClick = false;
627
						rightHandClickProgress = 0f;
628
						lastRightHandPos = rightHandPos;
629
						lastRightHandClickTime = Time.realtimeSinceStartup;
630
					}
631
				}
632
				else
633
				{
634
					isRightHandInteracting = false;
635
					isRightHandPress = false;
636
					rightHandPressProgress = 0f;
637
				}
638

    
639
				// stop the cursor click progress, if both left and right hand are not clicking
640
				if (leftHandClickProgress == 0f && rightHandClickProgress == 0f && cursorClickProgress > 0f) 
641
				{
642
					cursorClickProgress = 0f;
643
				}
644

    
645
				// if both hands are interacting, check which one interacts longer than the other
646
				if(isLeftHandInteracting && isRightHandInteracting)
647
				{
648
					if(rightHandInteractingSince <= leftHandInteractingSince)
649
						isLeftHandInteracting = false;
650
					else
651
						isRightHandInteracting = false;
652
				}
653

    
654
				// if left hand just stopped interacting, send extra non-interaction event
655
				if (wasLeftHandInteracting && !isLeftHandInteracting) 
656
				{
657
					foreach(InteractionListenerInterface listener in interactionListeners)
658
					{
659
						if(lastLeftHandEvent == HandEventType.Grip)
660
							listener.HandReleaseDetected (playerUserID, playerIndex, false, true, leftHandScreenPos);
661
					}
662

    
663
					lastLeftHandEvent = HandEventType.Release;
664
				}
665

    
666

    
667
				// if right hand just stopped interacting, send extra non-interaction event
668
				if (wasRightHandInteracting && !isRightHandInteracting) 
669
				{
670
					foreach(InteractionListenerInterface listener in interactionListeners)
671
					{
672
						if(lastRightHandEvent == HandEventType.Grip)
673
							listener.HandReleaseDetected (playerUserID, playerIndex, true, true, rightHandScreenPos);
674
					}
675

    
676
					lastRightHandEvent = HandEventType.Release;
677
				}
678

    
679

    
680
				// process left hand
681
				handEvent = HandStateToEvent(leftHandState, lastLeftHandEvent);
682

    
683
				if((isLeftHandInteracting != isLeftHandPrimary) || (isRightHandInteracting != isRightHandPrimary))
684
				{
685
					if(controlMouseCursor && dragInProgress)
686
					{
687
						MouseControl.MouseRelease();
688
						dragInProgress = false;
689
					}
690
					
691
					lastLeftHandEvent = HandEventType.Release;
692
					lastRightHandEvent = HandEventType.Release;
693
				}
694
				
695
				if(controlMouseCursor && (handEvent != lastLeftHandEvent))
696
				{
697
					if(controlMouseDrag && !dragInProgress && (handEvent == HandEventType.Grip))
698
					{
699
						dragInProgress = true;
700
						MouseControl.MouseDrag();
701
					}
702
					else if(dragInProgress && (handEvent == HandEventType.Release))
703
					{
704
						MouseControl.MouseRelease();
705
						dragInProgress = false;
706
					}
707
				}
708
				
709
				leftHandEvent = handEvent;
710
				if(handEvent != HandEventType.None)
711
				{
712
					// no clicks, while hand grip is detected
713
					if (leftHandEvent == HandEventType.Grip && leftHandClickProgress > 0f) 
714
					{
715
						cursorClickProgress = leftHandClickProgress = 0f;
716
						lastLeftHandClickTime = Time.realtimeSinceStartup;
717
					}
718

    
719
					if (leftHandEvent != lastLeftHandEvent) 
720
					{
721
						// invoke interaction listeners
722
						foreach(InteractionListenerInterface listener in interactionListeners)
723
						{
724
							if(leftHandEvent == HandEventType.Grip)
725
								listener.HandGripDetected (playerUserID, playerIndex, false, isLeftHandInteracting, leftHandScreenPos);
726
							else if(leftHandEvent == HandEventType.Release)
727
								listener.HandReleaseDetected (playerUserID, playerIndex, false, isLeftHandInteracting, leftHandScreenPos);
728
						}
729
					}
730

    
731
					lastLeftHandEvent = handEvent;
732
				}
733
				
734
				// if the hand is primary, set the cursor position
735
				if(isLeftHandInteracting)
736
				{
737
					isLeftHandPrimary = true;
738

    
739
					if(leftHandClickProgress < 0.8f)  // stop the cursor after 80% click progress
740
					{
741
						float smooth = smoothFactor * Time.deltaTime;
742
						if(smooth == 0f) smooth = 1f;
743
						
744
						cursorScreenPos = Vector3.Lerp(cursorScreenPos, leftHandScreenPos, smooth);
745
					}
746

    
747
					// move mouse-only if there is no cursor texture
748
					if(controlMouseCursor && 
749
						(!guiHandCursor || (!gripHandTexture && !releaseHandTexture && !normalHandTexture)))
750
					{
751
						MouseControl.MouseMove(cursorScreenPos, debugText);
752
					}
753
				}
754
				else
755
				{
756
					isLeftHandPrimary = false;
757
				}
758

    
759

    
760
				// process right hand
761
				handEvent = HandStateToEvent(rightHandState, lastRightHandEvent);
762

    
763
				if(controlMouseCursor && (handEvent != lastRightHandEvent))
764
				{
765
					if(controlMouseDrag && !dragInProgress && (handEvent == HandEventType.Grip))
766
					{
767
						dragInProgress = true;
768
						MouseControl.MouseDrag();
769
					}
770
					else if(dragInProgress && (handEvent == HandEventType.Release))
771
					{
772
						MouseControl.MouseRelease();
773
						dragInProgress = false;
774
					}
775
				}
776
				
777
				rightHandEvent = handEvent;
778
				if(handEvent != HandEventType.None)
779
				{
780
					// no clicks, while hand grip is detected
781
					if (rightHandEvent == HandEventType.Grip && rightHandClickProgress > 0f) 
782
					{
783
						cursorClickProgress = rightHandClickProgress = 0f;
784
						lastRightHandClickTime = Time.realtimeSinceStartup;
785
					}
786

    
787
					if (rightHandEvent != lastRightHandEvent) 
788
					{
789
						// invoke interaction listeners
790
						foreach(InteractionListenerInterface listener in interactionListeners)
791
						{
792
							if(rightHandEvent == HandEventType.Grip)
793
								listener.HandGripDetected (playerUserID, playerIndex, true, isRightHandInteracting, rightHandScreenPos);
794
							else if(rightHandEvent == HandEventType.Release)
795
								listener.HandReleaseDetected (playerUserID, playerIndex, true, isRightHandInteracting, rightHandScreenPos);
796
						}
797
					}
798

    
799
					lastRightHandEvent = handEvent;
800
				}	
801
				
802
				// if the hand is primary, set the cursor position
803
				if(isRightHandInteracting)
804
				{
805
					isRightHandPrimary = true;
806

    
807
					if(rightHandClickProgress < 0.8f)  // stop the cursor after 80% click progress
808
					{
809
						float smooth = smoothFactor * Time.deltaTime;
810
						if(smooth == 0f) smooth = 1f;
811
						
812
						cursorScreenPos = Vector3.Lerp(cursorScreenPos, rightHandScreenPos, smooth);
813
					}
814

    
815
					// move mouse-only if there is no cursor texture
816
					if(controlMouseCursor && 
817
						(!guiHandCursor || (!gripHandTexture && !releaseHandTexture && !normalHandTexture)))
818
					{
819
						MouseControl.MouseMove(cursorScreenPos, debugText);
820
					}
821
				}
822
				else
823
				{
824
					isRightHandPrimary = false;
825
				}
826

    
827
			}
828
			else
829
			{
830
				// send release events
831
				if (lastLeftHandEvent == HandEventType.Grip || lastRightHandEvent == HandEventType.Grip) 
832
				{
833
					foreach(InteractionListenerInterface listener in interactionListeners)
834
					{
835
						if(lastLeftHandEvent == HandEventType.Grip)
836
							listener.HandReleaseDetected (lastUserID, playerIndex, false, true, leftHandScreenPos);
837
						if(lastRightHandEvent == HandEventType.Grip)
838
							listener.HandReleaseDetected (lastUserID, playerIndex, true, true, leftHandScreenPos);
839
					}
840
				}
841

    
842
				leftHandState = KinectInterop.HandState.NotTracked;
843
				rightHandState = KinectInterop.HandState.NotTracked;
844
				
845
				isLeftHandPrimary = isRightHandPrimary = false;
846
				isLeftHandInteracting = isRightHandInteracting = false;
847
				leftHandInteractingSince = rightHandInteractingSince = 0f;
848

    
849
				isLeftHandClick = isRightHandClick = false;
850
				cursorClickProgress = leftHandClickProgress = rightHandClickProgress = 0f;
851
				lastLeftHandClickTime = lastRightHandClickTime = Time.realtimeSinceStartup;
852
				lastLeftHandPressTime = lastRightHandPressTime = Time.realtimeSinceStartup;
853

    
854
				isLeftHandPress = false;
855
				isRightHandPress = false;
856

    
857
				leftHandPressProgress = 0f;
858
				rightHandPressProgress = 0f;
859
				
860
				leftHandEvent = HandEventType.None;
861
				rightHandEvent = HandEventType.None;
862
				
863
				lastLeftHandEvent = HandEventType.Release;
864
				lastRightHandEvent = HandEventType.Release;
865

    
866
				if(controlMouseCursor && dragInProgress)
867
				{
868
					MouseControl.MouseRelease();
869
					dragInProgress = false;
870
				}
871
			}
872

    
873
			// update cursor texture and position
874
			UpdateGUI();
875
		}
876
		
877
	}
878

    
879

    
880
	// updates cursor texture and position
881
	private void UpdateGUI()
882
	{
883
		if(!interactionInited)
884
			return;
885
		
886
		// display debug information
887
		if(debugText)
888
		{
889
			string sGuiText = string.Empty;
890

    
891
			//if(isLeftHandPrimary)
892
			{
893
				sGuiText += "L.Hand" + (isLeftHandInteracting ? "*: " : " : ") + leftHandScreenPos.ToString();
894
				
895
				if(lastLeftHandEvent == HandEventType.Grip)
896
				{
897
					sGuiText += "  LeftGrip";
898
				}
899
				else if(lastLeftHandEvent == HandEventType.Release)
900
				{
901
					sGuiText += "  LeftRelease";
902
				}
903
				
904
				if(isLeftHandClick)
905
				{
906
					sGuiText += "  LeftClick";
907
				}
908
//				else if(leftHandClickProgress > 0.5f)
909
//				{
910
//					sGuiText += String.Format("  {0:F0}%", leftHandClickProgress * 100);
911
//				}
912
				
913
				if(isLeftHandPress)
914
				{
915
					sGuiText += "  LeftPress";
916
				}
917

    
918
				//sGuiText += " " + leftHandClickProgress;
919
			}
920
			
921
			//if(isRightHandPrimary)
922
			{
923
				sGuiText += "\nR.Hand" + (isRightHandInteracting ? "*: " : " : ") + rightHandScreenPos.ToString();
924
				
925
				if(lastRightHandEvent == HandEventType.Grip)
926
				{
927
					sGuiText += "  RightGrip";
928
				}
929
				else if(lastRightHandEvent == HandEventType.Release)
930
				{
931
					sGuiText += "  RightRelease";
932
				}
933
				
934
				if(isRightHandClick)
935
				{
936
					sGuiText += "  RightClick";
937
				}
938
//				else if(rightHandClickProgress > 0.5f)
939
//				{
940
//					sGuiText += String.Format("  {0:F0}%", rightHandClickProgress * 100);
941
//				}
942

    
943
				if(isRightHandPress)
944
				{
945
					sGuiText += "  RightPress";
946
				}
947

    
948
				//sGuiText += " " + rightHandClickProgress;
949
			}
950
			
951
			debugText.text = sGuiText;
952
		}
953
		
954
		// display the cursor status and position
955
		if(guiHandCursor)
956
		{
957
			Sprite cursorTexture = null;
958
			
959
			if(isLeftHandPrimary)
960
			{
961
				if(lastLeftHandEvent == HandEventType.Grip)
962
					cursorTexture = gripHandTexture;
963
				else if(lastLeftHandEvent == HandEventType.Release)
964
					cursorTexture = releaseHandTexture;
965
			}
966
			else if(isRightHandPrimary)
967
			{
968
				if(lastRightHandEvent == HandEventType.Grip)
969
					cursorTexture = gripHandTexture;
970
				else if(lastRightHandEvent == HandEventType.Release)
971
					cursorTexture = releaseHandTexture;
972
			}
973
			
974
			if(cursorTexture == null)
975
			{
976
				cursorTexture = normalHandTexture;
977
			}
978
			
979
			if((cursorTexture != null) /**&& (isLeftHandPrimary || isRightHandPrimary)*/)
980
			{
981
				Vector2 posSprite; 
982

    
983
				if(controlMouseCursor)
984
				{
985
					MouseControl.MouseMove(cursorScreenPos, debugText);
986
					posSprite = new Vector2(Input.mousePosition.x, Input.mousePosition.y);
987
				}
988
				else 
989
				{
990
					Rect rectCanvas = guiHandCursor.canvas.pixelRect;
991
					posSprite = new Vector2(cursorScreenPos.x * rectCanvas.width, cursorScreenPos.y * rectCanvas.height); 
992
				}
993

    
994
				guiHandCursor.sprite = cursorTexture;
995
				guiHandCursor.rectTransform.position = posSprite;
996

    
997
				if (cursorProgressBar) 
998
				{
999
					cursorProgressBar.fillAmount = cursorClickProgress;
1000
				}
1001
			}
1002
		}
1003
	}
1004

    
1005

    
1006
	// estimates screen cursor overlay position for the given hand
1007
	private bool GetHandOverlayScreenPos(KinectManager kinectManager, int iHandJointIndex, ref Vector3 handScreenPos)
1008
	{
1009
		Vector3 posJointRaw = kinectManager.GetJointKinectPosition(playerUserID, iHandJointIndex);
1010

    
1011
		if(posJointRaw != Vector3.zero)
1012
		{
1013
			Vector2 posDepth = kinectManager.MapSpacePointToDepthCoords(posJointRaw);
1014
			ushort depthValue = kinectManager.GetDepthForPixel((int)posDepth.x, (int)posDepth.y);
1015

    
1016
			if(posDepth != Vector2.zero && depthValue > 0)
1017
			{
1018
				// depth pos to color pos
1019
				Vector2 posColor = kinectManager.MapDepthPointToColorCoords(posDepth, depthValue);
1020

    
1021
				if(!float.IsInfinity(posColor.x) && !float.IsInfinity(posColor.y))
1022
				{
1023
					// get the color image x-offset and width (use the portrait background, if available)
1024
					float colorWidth = kinectManager.GetColorImageWidth();
1025
					float colorOfsX = 0f;
1026

    
1027
					PortraitBackground portraitBack = PortraitBackground.Instance;
1028
					if(portraitBack && portraitBack.enabled)
1029
					{
1030
						colorWidth = kinectManager.GetColorImageHeight() * kinectManager.GetColorImageHeight() / kinectManager.GetColorImageWidth();
1031
						colorOfsX = (kinectManager.GetColorImageWidth() - colorWidth) / 2f;
1032
					}
1033

    
1034
					float xScaled = (posColor.x - colorOfsX) / colorWidth;
1035
					float yScaled = posColor.y / kinectManager.GetColorImageHeight();
1036

    
1037
					handScreenPos.x = xScaled;
1038
					handScreenPos.y = 1f - yScaled;
1039

    
1040
					return true;
1041
				}
1042
			}
1043
		}
1044

    
1045
		return false;
1046
	}
1047

    
1048

    
1049
	// converts hand state to hand event type
1050
	public static HandEventType HandStateToEvent(KinectInterop.HandState handState, HandEventType lastEventType)
1051
	{
1052
		switch(handState)
1053
		{
1054
		case KinectInterop.HandState.Open:
1055
			return HandEventType.Release;
1056

    
1057
		case KinectInterop.HandState.Closed:
1058
		case KinectInterop.HandState.Lasso:
1059
			return HandEventType.Grip;
1060

    
1061
		case KinectInterop.HandState.Unknown:
1062
			return lastEventType;
1063
		}
1064

    
1065
		return HandEventType.None;
1066
	}
1067

    
1068

    
1069
}