// Make sure to kill the Kinect on quitting.
    void OnApplicationQuit()
    {
        if(KinectInitialized)
        {
            // Shutdown OpenNI
            KinectWrapper.NuiShutdown();
            instance = null;

        //			interactionManager.StopInteraction();
        }
    }
    //----------------------------------- end of public functions --------------------------------------//
    void Start()
    {
        CalibrationText = GameObject.Find("CalibrationText");
        int hr = 0;

        try
        {
            hr = KinectWrapper.NuiInitialize(KinectWrapper.NuiInitializeFlags.UsesDepthAndPlayerIndex |
                KinectWrapper.NuiInitializeFlags.UsesSkeleton |
                (ComputeColorMap ? KinectWrapper.NuiInitializeFlags.UsesColor : 0));
            if (hr != 0)
            {
                throw new Exception("NuiInitialize Failed");
            }

            hr = KinectWrapper.NuiSkeletonTrackingEnable(IntPtr.Zero, 8);  // 0, 12,8
            if (hr != 0)
            {
                throw new Exception("Cannot initialize Skeleton Data");
            }

            depthStreamHandle = IntPtr.Zero;
            if(ComputeUserMap)
            {
                hr = KinectWrapper.NuiImageStreamOpen(KinectWrapper.NuiImageType.DepthAndPlayerIndex,
                    KinectWrapper.Constants.ImageResolution, 0, 2, IntPtr.Zero, ref depthStreamHandle);
                if (hr != 0)
                {
                    throw new Exception("Cannot open depth stream");
                }
            }

            colorStreamHandle = IntPtr.Zero;
            if(ComputeColorMap)
            {
                hr = KinectWrapper.NuiImageStreamOpen(KinectWrapper.NuiImageType.Color,
                    KinectWrapper.Constants.ImageResolution, 0, 2, IntPtr.Zero, ref colorStreamHandle);
                if (hr != 0)
                {
                    throw new Exception("Cannot open color stream");
                }
            }

            // set kinect elevation angle
            KinectWrapper.NuiCameraElevationSetAngle(SensorAngle);

            // init skeleton structures
            skeletonFrame = new KinectWrapper.NuiSkeletonFrame()
                            {
                                SkeletonData = new KinectWrapper.NuiSkeletonData[KinectWrapper.Constants.NuiSkeletonCount]
                            };

            // values used to pass to smoothing function
            smoothParameters = new KinectWrapper.NuiTransformSmoothParameters();

            switch(smoothing)
            {
                case Smoothing.Default:
                    smoothParameters.fSmoothing = 0.5f;
                    smoothParameters.fCorrection = 0.5f;
                    smoothParameters.fPrediction = 0.5f;
                    smoothParameters.fJitterRadius = 0.05f;
                    smoothParameters.fMaxDeviationRadius = 0.04f;
                    break;
                case Smoothing.Medium:
                    smoothParameters.fSmoothing = 0.5f;
                    smoothParameters.fCorrection = 0.1f;
                    smoothParameters.fPrediction = 0.5f;
                    smoothParameters.fJitterRadius = 0.1f;
                    smoothParameters.fMaxDeviationRadius = 0.1f;
                    break;
                case Smoothing.Aggressive:
                    smoothParameters.fSmoothing = 0.7f;
                    smoothParameters.fCorrection = 0.3f;
                    smoothParameters.fPrediction = 1.0f;
                    smoothParameters.fJitterRadius = 1.0f;
                    smoothParameters.fMaxDeviationRadius = 1.0f;
                    break;
            }

            // init the tracking state filter
            trackingStateFilter = new TrackingStateFilter[KinectWrapper.Constants.NuiSkeletonMaxTracked];
            for(int i = 0; i < trackingStateFilter.Length; i++)
            {
                trackingStateFilter[i] = new TrackingStateFilter();
                trackingStateFilter[i].Init();
            }

            // init the bone orientation filter
            boneOrientationFilter = new BoneOrientationsFilter[KinectWrapper.Constants.NuiSkeletonMaxTracked];
            for(int i = 0; i < boneOrientationFilter.Length; i++)
            {
                boneOrientationFilter[i] = new BoneOrientationsFilter();
                boneOrientationFilter[i].Init();
            }

            // init the clipped legs filter
            clippedLegsFilter = new ClippedLegsFilter[KinectWrapper.Constants.NuiSkeletonMaxTracked];
            for(int i = 0; i < clippedLegsFilter.Length; i++)
            {
                clippedLegsFilter[i] = new ClippedLegsFilter();
            }

            // init the bone orientation constraints
            boneConstraintsFilter = new BoneOrientationsConstraint();
            boneConstraintsFilter.AddDefaultConstraints();
            // init the self intersection constraints
            selfIntersectionConstraint = new SelfIntersectionConstraint();

            // create arrays for joint positions and joint orientations
            int skeletonJointsCount = (int)KinectWrapper.NuiSkeletonPositionIndex.Count;

            player1JointsTracked = new bool[skeletonJointsCount];
            player2JointsTracked = new bool[skeletonJointsCount];
            player1PrevTracked = new bool[skeletonJointsCount];
            player2PrevTracked = new bool[skeletonJointsCount];

            player1JointsPos = new Vector3[skeletonJointsCount];
            player2JointsPos = new Vector3[skeletonJointsCount];

            player1JointsOri = new Matrix4x4[skeletonJointsCount];
            player2JointsOri = new Matrix4x4[skeletonJointsCount];

            //create the transform matrix that converts from kinect-space to world-space
            Quaternion quatTiltAngle = new Quaternion();
            quatTiltAngle.eulerAngles = new Vector3(-SensorAngle, 0.0f, 0.0f);

            float heightAboveHips = SensorHeight - 1.0f;

            // transform matrix - kinect to world
            kinectToWorld.SetTRS(new Vector3(0.0f, heightAboveHips, 0.0f), quatTiltAngle, Vector3.one);
            flipMatrix = Matrix4x4.identity;
            flipMatrix[2, 2] = -1;

            instance = this;
            // roger> DontDestroyOnLoad(gameObject); // comment this, we want to reset and reopen kinect every time
        }
        catch (Exception e)
        {
            string message = e.Message + " - " + KinectWrapper.GetNuiErrorString(hr);
            Debug.LogError(message);
            if(CalibrationText != null)
                CalibrationText.guiText.text = message;

            return;
        }

        if(ComputeUserMap)
        {
            // Initialize depth & label map related stuff
            usersMapSize = KinectWrapper.GetDepthWidth() * KinectWrapper.GetDepthHeight();
            usersLblTex = new Texture2D(KinectWrapper.GetDepthWidth(), KinectWrapper.GetDepthHeight());
            usersMapColors = new Color[usersMapSize];
            // roger> user map size
            usersMapRect = new Rect(Screen.width, Screen.height - usersLblTex.height / 2, -usersLblTex.width / 2, usersLblTex.height / 2);
            //usersMapRect = new Rect(0, 0, Screen.width, Screen.height);

            usersDepthMap = new short[usersMapSize];
            usersHistogramMap = new float[5000];
        }

        if(ComputeColorMap)
        {
            // Initialize color map related stuff
            usersClrTex = new Texture2D(KinectWrapper.GetDepthWidth(), KinectWrapper.GetDepthHeight());
            //usersClrColors = new Color[usersMapSize];
            usersClrRect = new Rect(Screen.width, Screen.height - usersClrTex.height / 2, -usersClrTex.width / 2, usersClrTex.height / 2);

            if(ComputeUserMap)
                usersMapRect.x -= usersClrTex.width / 2;

            colorImage = new Color32[KinectWrapper.GetDepthWidth() * KinectWrapper.GetDepthHeight()];
        }

        // Initialize user list to contain ALL users.
        allUsers = new List<uint>();

        // Pull the AvatarController from each of the players Avatars.
        Player1Controllers = new List<TrainingAvatarController>();
        Player2Controllers = new List<TrainingAvatarController>();

        // Add each of the avatars' controllers into a list for each player.
        foreach(GameObject avatar in Player1Avatars)
        {
            if(avatar.activeInHierarchy)
            {
                Player1Controllers.Add(avatar.GetComponent<TrainingAvatarController>());
            }
        }

        foreach(GameObject avatar in Player2Avatars)
        {
            if(avatar.activeInHierarchy)
            {
                Player2Controllers.Add(avatar.GetComponent<TrainingAvatarController>());
            }
        }

        // GUI Text.
        if(CalibrationText != null)
        {
            CalibrationText.guiText.text = "WAITING FOR USERS";
        }

        Debug.Log("Waiting for users.");

        KinectInitialized = true;
    }