Public Class Cube
    Inherits Shape


    Public Property TopLeftFront As Vector3
    Public Property BottomLeftFront As Vector3
    Public Property TopRightFront As Vector3
    Public Property BottomRightFront As Vector3
    Public Property TopLeftBack As Vector3
    Public Property BottomLeftBack As Vector3
    Public Property TopRightBack As Vector3
    Public Property BottomRightBack As Vector3

    Public Property FrontNormal As Vector3
    Public Property BackNormal As Vector3
    Public Property TopNormal As Vector3
    Public Property BottomNormal As Vector3
    Public Property LeftNormal As Vector3
    Public Property RightNormal As Vector3


    Sub New(size As Vector3)
        MyBase.New(size)
        Me._NumberOfTriangles = 12
        Me.CreateGeometry()
    End Sub

    Public Overrides Sub CreateVectors()
        Dim vSize As Vector3 = Me.Size / 2
        Dim position As New Vector3(0)
        Me.TopLeftFront = position + (New Vector3(-1.0F, 1.0F, -1.0F) * vSize)
        Me.BottomLeftFront = position + (New Vector3(-1.0F, -1.0F, -1.0F) * vSize)
        Me.TopRightFront = position + (New Vector3(1.0F, 1.0F, -1.0F) * vSize)
        Me.BottomRightFront = position + (New Vector3(1.0F, -1.0F, -1.0F) * vSize)

        Me.TopLeftBack = position + (New Vector3(-1.0F, 1.0F, 1.0F) * vSize)
        Me.BottomLeftBack = position + (New Vector3(-1.0F, -1.0F, 1.0F) * vSize)
        Me.TopRightBack = position + (New Vector3(1.0F, 1.0F, 1.0F) * vSize)
        Me.BottomRightBack = position + (New Vector3(1.0F, -1.0F, 1.0F) * vSize)
    End Sub

    Public Overrides Sub CreateNormals()
        Dim vSize As Vector3 = Me.Size / 2
        FrontNormal = New Vector3(0.0F, 0.0F, -1.0F) * vSize
        BackNormal = New Vector3(0.0F, 0.0F, 1.0F) * vSize
        TopNormal = New Vector3(0.0F, 1.0F, 0.0F) * vSize
        BottomNormal = New Vector3(0.0F, -1.0F, 0.0F) * vSize
        LeftNormal = New Vector3(-1.0F, 0.0F, 0.0F) * vSize
        RightNormal = New Vector3(1.0F, 0.0F, 0.0F) * vSize
    End Sub

    Public Overrides Sub FillVerticesList()
        Me._VerticesList.Clear()
        Dim vSize As Vector3 = Me.Size / 2
       
        Dim textureTopLeft As Vector2 = New Vector2(0.5F * vSize.X, 0.0F * vSize.Y)
        Dim textureTopRight As Vector2 = New Vector2(0.0F * vSize.X, 0.0F * vSize.Y)
        Dim textureBottomLeft As Vector2 = New Vector2(0.5F * vSize.X, 0.5F * vSize.Y)
        Dim textureBottomRight As Vector2 = New Vector2(0.0F * vSize.X, 0.5F * vSize.Y)

        Dim textureTopLeftZ As Vector2 = New Vector2(0.5F * vSize.Z, 0.0F * vSize.Y)
        Dim textureTopRightZ As Vector2 = New Vector2(0.0F * vSize.Z, 0.0F * vSize.Y)
        Dim textureBottomLeftZ As Vector2 = New Vector2(0.5F * vSize.Z, 0.5F * vSize.Y)
        Dim textureBottomRightZ As Vector2 = New Vector2(0.0F * vSize.Z, 0.5F * vSize.Y)

        Dim textureTopLeftXZ As Vector2 = New Vector2(0.5F * vSize.X, 0.0F * vSize.Z)
        Dim textureTopRightXZ As Vector2 = New Vector2(0.0F * vSize.X, 0.0F * vSize.Z)
        Dim textureBottomLeftXZ As Vector2 = New Vector2(0.5F * vSize.X, 0.5F * vSize.Z)
        Dim textureBottomRightXZ As Vector2 = New Vector2(0.0F * vSize.X, 0.5F * vSize.Z)

        'front face
        MyBase._VerticesList.Add(New VertexPositionNormalTexture(TopLeftFront, frontNormal, textureTopLeft))
        MyBase._VerticesList.Add(New VertexPositionNormalTexture(BottomLeftFront, frontNormal, textureBottomLeft))
        MyBase._VerticesList.Add(New VertexPositionNormalTexture(TopRightFront, frontNormal, textureTopRight))
        MyBase._VerticesList.Add(New VertexPositionNormalTexture(BottomLeftFront, frontNormal, textureBottomLeft))
        MyBase._VerticesList.Add(New VertexPositionNormalTexture(BottomRightFront, frontNormal, textureBottomRight))
        MyBase._VerticesList.Add(New VertexPositionNormalTexture(TopRightFront, frontNormal, textureTopRight))

        'Back face.
        MyBase._VerticesList.Add(New VertexPositionNormalTexture(TopLeftBack, backNormal, textureTopRight))
        MyBase._VerticesList.Add(New VertexPositionNormalTexture(TopRightBack, backNormal, textureTopLeft))
        MyBase._VerticesList.Add(New VertexPositionNormalTexture(BottomLeftBack, backNormal, textureBottomRight))
        MyBase._VerticesList.Add(New VertexPositionNormalTexture(BottomLeftBack, backNormal, textureBottomRight))
        MyBase._VerticesList.Add(New VertexPositionNormalTexture(TopRightBack, backNormal, textureTopLeft))
        MyBase._VerticesList.Add(New VertexPositionNormalTexture(BottomRightBack, backNormal, textureBottomLeft))

        ' Top face.
        MyBase._VerticesList.Add(New VertexPositionNormalTexture(TopLeftFront, topNormal, textureBottomLeftXZ))
        MyBase._VerticesList.Add(New VertexPositionNormalTexture(TopRightBack, topNormal, textureTopRightXZ))
        MyBase._VerticesList.Add(New VertexPositionNormalTexture(TopLeftBack, topNormal, textureTopLeftXZ))
        MyBase._VerticesList.Add(New VertexPositionNormalTexture(TopLeftFront, topNormal, textureBottomLeftXZ))
        MyBase._VerticesList.Add(New VertexPositionNormalTexture(TopRightFront, topNormal, textureBottomRightXZ))
        MyBase._VerticesList.Add(New VertexPositionNormalTexture(TopRightBack, topNormal, textureTopRightXZ))

        ' Bottom face. 
        MyBase._VerticesList.Add(New VertexPositionNormalTexture(BottomLeftFront, bottomNormal, textureTopLeftXZ))
        MyBase._VerticesList.Add(New VertexPositionNormalTexture(BottomLeftBack, bottomNormal, textureBottomLeftXZ))
        MyBase._VerticesList.Add(New VertexPositionNormalTexture(BottomRightBack, bottomNormal, textureBottomRightXZ))
        MyBase._VerticesList.Add(New VertexPositionNormalTexture(BottomLeftFront, bottomNormal, textureTopLeftXZ))
        MyBase._VerticesList.Add(New VertexPositionNormalTexture(BottomRightBack, bottomNormal, textureBottomRightXZ))
        MyBase._VerticesList.Add(New VertexPositionNormalTexture(BottomRightFront, bottomNormal, textureTopRightXZ))

        ' Left face.
        MyBase._VerticesList.Add(New VertexPositionNormalTexture(TopLeftFront, leftNormal, textureTopRightZ))
        MyBase._VerticesList.Add(New VertexPositionNormalTexture(BottomLeftBack, leftNormal, textureBottomLeftZ))
        MyBase._VerticesList.Add(New VertexPositionNormalTexture(BottomLeftFront, leftNormal, textureBottomRightZ))
        MyBase._VerticesList.Add(New VertexPositionNormalTexture(TopLeftBack, leftNormal, textureTopLeftZ))
        MyBase._VerticesList.Add(New VertexPositionNormalTexture(BottomLeftBack, leftNormal, textureBottomLeftZ))
        MyBase._VerticesList.Add(New VertexPositionNormalTexture(TopLeftFront, leftNormal, textureTopRightZ))

        ' Right face. 
        MyBase._VerticesList.Add(New VertexPositionNormalTexture(TopRightFront, rightNormal, textureTopLeftZ))
        MyBase._VerticesList.Add(New VertexPositionNormalTexture(BottomRightFront, rightNormal, textureBottomLeftZ))
        MyBase._VerticesList.Add(New VertexPositionNormalTexture(BottomRightBack, rightNormal, textureBottomRightZ))
        MyBase._VerticesList.Add(New VertexPositionNormalTexture(TopRightBack, rightNormal, textureTopRightZ))
        MyBase._VerticesList.Add(New VertexPositionNormalTexture(TopRightFront, rightNormal, textureTopLeftZ))
        MyBase._VerticesList.Add(New VertexPositionNormalTexture(BottomRightBack, rightNormal, textureBottomRightZ))

    End Sub

    Public Overrides Sub Translate(translateMatrix As Microsoft.Xna.Framework.Matrix)
        With Me
            .TopLeftFront = Vector3.Transform(.TopLeftFront, translateMatrix)
            .BottomLeftFront = Vector3.Transform(.BottomLeftFront, translateMatrix)
            .TopRightFront = Vector3.Transform(.TopRightFront, translateMatrix)
            .BottomRightFront = Vector3.Transform(.BottomRightFront, translateMatrix)
            .TopLeftBack = Vector3.Transform(.TopLeftBack, translateMatrix)
            .BottomLeftBack = Vector3.Transform(.BottomLeftBack, translateMatrix)
            .TopRightBack = Vector3.Transform(.TopRightBack, translateMatrix)
            .BottomRightBack = Vector3.Transform(.BottomRightBack, translateMatrix)
        End With
    End Sub

    Public Overrides Sub RotateVectors(o As Shape, deleg As RotationDeleg, degrees As Single)
        Dim r As Single = MathHelper.ToRadians(degrees)
        With DirectCast(o, Cube)
            .TopLeftFront = Vector3.Transform(.TopLeftFront, deleg.Invoke(r))
            .BottomLeftFront = Vector3.Transform(.BottomLeftFront, deleg.Invoke(r))
            .TopRightFront = Vector3.Transform(.TopRightFront, deleg.Invoke(r))
            .BottomRightFront = Vector3.Transform(.BottomRightFront, deleg.Invoke(r))
            .TopLeftBack = Vector3.Transform(.TopLeftBack, deleg.Invoke(r))
            .BottomLeftBack = Vector3.Transform(.BottomLeftBack, deleg.Invoke(r))
            .TopRightBack = Vector3.Transform(.TopRightBack, deleg.Invoke(r))
            .BottomRightBack = Vector3.Transform(.BottomRightBack, deleg.Invoke(r))
        End With
    End Sub

    Public Function GetVectors() As List(Of Vector3)
        Dim l As New List(Of Vector3)
        With Me
            l.Add(.TopLeftFront)
            l.Add(.BottomLeftFront)
            l.Add(.TopRightFront)
            l.Add(.BottomRightFront)
            l.Add(.TopLeftBack)
            l.Add(.BottomLeftBack)
            l.Add(.TopRightBack)
            l.Add(.BottomRightBack)
        End With
        Return l
    End Function

    Public Overrides Function GetBoundingBoxForObject(o As WorldObject) As Microsoft.Xna.Framework.BoundingBox
        Return Me.GetBoundingBoxForObject(o, o.Size)
    End Function

    Public Overloads Function GetBoundingBoxForObject(o As WorldObject, size As Vector3) As Microsoft.Xna.Framework.BoundingBox
        Dim s As New Cube(size)
        'rotate the shape to match the rotation of the object
        Me.RotateVectors(s, Axis.X, o.RotationX)
        Me.RotateVectors(s, Axis.Y, o.RotationY)
        Me.RotateVectors(s, Axis.Z, o.RotationZ)
        'translate the vectors of the shape to match the position of the object
        s.Translate(Matrix.CreateTranslation(o.Position))
        Dim bboxPoints(1) As Vector3
        bboxPoints(0) = s.BottomLeftBack
        bboxPoints(1) = s.TopRightFront
        Return BoundingBox.CreateFromPoints(bboxPoints)
    End Function
End Class
