Imports System
Imports System.Linq
Imports System.Windows
Imports System.Windows.Media
Imports System.Windows.Media.Imaging

Imports Microsoft.Kinect

''' <summary>
''' Interaction logic for MainWindow.xaml
''' </summary>
''' <remarks></remarks>
Class MainWindow
#Region "メンバー変数"
    Private _KinectDevice As KinectSensor
    Private _DepthImage As WriteableBitmap
    Private _DepthImageRect As Int32Rect
    Private _DepthPixelData() As Short
    Private _DepthImageStride As Integer
    Private _TotalFrames As Integer
    Private _StartFrameTime As DateTime
#End Region


#Region "コンストラクタ"
    Sub New()

        ' この呼び出しはデザイナーで必要です。
        InitializeComponent()

        ' InitializeComponent() 呼び出しの後で初期化を追加します。
        AddHandler KinectSensor.KinectSensors.StatusChanged, AddressOf KinectSensors_StatusChanged
        Me.KinectDevice = KinectSensor.KinectSensors.FirstOrDefault(Function(x)
                                                                        Return x.Status = KinectStatus.Connected
                                                                    End Function)
    End Sub
#End Region


#Region "メソッド"
    Private Sub KinectSensors_StatusChanged(sender As Object, e As StatusChangedEventArgs)
        Select Case e.Status
            Case KinectStatus.Initializing,
                KinectStatus.Connected,
                KinectStatus.NotPowered,
                KinectStatus.NotReady,
                KinectStatus.DeviceNotGenuine
                Me.KinectDevice = e.Sensor
            Case KinectStatus.Disconnected
                'TODO: Give the user feedback to plug-in a Kinect device.                    
                Me.KinectDevice = Nothing
            Case Else
                'TODO: Show an error state
        End Select
    End Sub


    Private Sub KinectDevice_DepthFrameReady(sender As Object, e As DepthImageFrameReadyEventArgs)
        Using frame As DepthImageFrame = e.OpenDepthImageFrame
            If frame IsNot Nothing Then
                frame.CopyPixelDataTo(Me._DepthPixelData)
                CreateBetterShadesOfGray(frame, Me._DepthPixelData)
                CalculatePlayerSize(frame, Me._DepthPixelData)
            End If
            Me._TotalFrames += 1
            FramesPerSecondElement.Text = String.Format("{0:0} fps",
                                                        (Me._TotalFrames / DateTime.Now.Subtract(Me._StartFrameTime).TotalSeconds))
        End Using
    End Sub


    Private Sub CreateBetterShadesOfGray(depthFrame As DepthImageFrame, pixelData() As Short)
        Dim depth As Integer
        Dim gray As Integer
        Const bytesPerPixel As Integer = 4
        Dim enhPixelData(depthFrame.Width * depthFrame.Height * bytesPerPixel - 1) As Byte
        Const loThreshold As Integer = 1200
        Const hiThreshold As Integer = 3800


        For i As Integer = 0 To pixelData.Length - 1
            Dim j As Integer = i * bytesPerPixel
            depth = pixelData(i) >> DepthImageFrame.PlayerIndexBitmaskWidth

            If depth < loThreshold OrElse depth > hiThreshold Then
                gray = &HFF
            Else
                gray = 255 - (255 * depth / &HFFF)
            End If
            enhPixelData(j + 0) = CType(gray, Byte)
            enhPixelData(j + 1) = CType(gray, Byte)
            enhPixelData(j + 2) = CType(gray, Byte)
        Next

        Me._DepthImage.WritePixels(Me._DepthImageRect,
                                   enhPixelData,
                                   Me._DepthImageStride,
                                   0)
    End Sub


    Private Sub CalculatePlayerSize(depthFrame As DepthImageFrame, pixelData() As Short)
        Dim depth As Integer
        Dim playerIndex As Integer
        Dim pixelIndex As Integer
        Dim bytesPerPixel As Integer = depthFrame.BytesPerPixel
        Dim players(6 - 1) As PlayerDepthData


        'First pass - Calculate stats from the pixel data
        For row As Integer = 0 To depthFrame.Height - 1
            For col As Integer = 0 To depthFrame.Width - 1
                pixelIndex = col + (row * depthFrame.Width)
                depth = pixelData(pixelIndex) >> DepthImageFrame.PlayerIndexBitmaskWidth

                If depth <> 0 Then
                    playerIndex = (pixelData(pixelIndex) And DepthImageFrame.PlayerIndexBitmask) - 1

                    If playerIndex > -1 Then
                        If players(playerIndex) Is Nothing Then
                            players(playerIndex) = New PlayerDepthData(playerIndex + 1,
                                                                       depthFrame.Width,
                                                                       depthFrame.Height)
                        End If

                        players(playerIndex).UpdateData(col, row, depth)
                    End If
                End If
            Next
        Next

        PlayerDepthData.ItemsSource = players
    End Sub
#End Region


#Region "プロパティ"
    Public Property KinectDevice As KinectSensor
        Get
            Return Me._KinectDevice
        End Get
        Set(value As KinectSensor)
            If Me._KinectDevice IsNot value Then
                'Uninitialize
                If Me._KinectDevice IsNot Nothing Then
                    Me._KinectDevice.Stop()
                    RemoveHandler Me._KinectDevice.DepthFrameReady, AddressOf KinectDevice_DepthFrameReady
                    Me._KinectDevice.DepthStream.Disable()
                    Me._KinectDevice.SkeletonStream.Disable()
                End If

                Me._KinectDevice = value

                'Initialize
                If Me._KinectDevice IsNot Nothing Then
                    If Me._KinectDevice.Status = KinectStatus.Connected Then
                        Me._KinectDevice.SkeletonStream.Enable()
                        Me._KinectDevice.DepthStream.Enable()

                        Dim depthStream As DepthImageStream = Me._KinectDevice.DepthStream
                        Me._DepthImage = New WriteableBitmap(depthStream.FrameWidth,
                                                             depthStream.FrameHeight,
                                                             96,
                                                             96,
                                                             PixelFormats.Bgr32,
                                                             Nothing)
                        Me._DepthImageRect = New Int32Rect(0,
                                                           0,
                                                           Math.Ceiling(Me._DepthImage.Width),
                                                           Math.Ceiling(Me._DepthImage.Height))
                        Me._DepthImageStride = depthStream.FrameWidth * 4
                        ReDim Me._DepthPixelData(depthStream.FramePixelDataLength - 1)
                        Me.Depth_Image.Source = Me._DepthImage

                        AddHandler Me._KinectDevice.DepthFrameReady, AddressOf KinectDevice_DepthFrameReady
                        Me._KinectDevice.Start()

                        Me._StartFrameTime = DateTime.Now
                    End If
                End If
            End If
        End Set
    End Property
#End Region

End Class
