'***************************************************************************************
' 
' File name: M3dgra.cpp
' Location: See Matrox Example Launcher in the MIL Control Center
' 
'
' Synopsis: This program contains an example Of how To use 3D graphics In MIL.
'
' Copyright (C) Matrox Electronic Systems Ltd., 1992-2020.
' All Rights Reserved
'****************************************************************************

Imports Microsoft.VisualBasic
Imports System
Imports System.Threading

Imports Matrox.MatroxImagingLibrary

Module M3dgra
    '----------------------------------------------------------------------------
    'Example description.
    '----------------------------------------------------------------------------
    Sub PrintHeader()
        Console.WriteLine("[EXAMPLE NAME] ")
        Console.WriteLine("M3ddisp  ")
        Console.WriteLine()
        Console.WriteLine("[SYNOPSIS] ")
        Console.WriteLine("This example demonstrates how to use MIL 3D displays.")
        Console.WriteLine()
        Console.WriteLine("[MODULES USED] ")
        Console.WriteLine("Modules used: application, system, buffer, 3D display, 3D graphics.")
        Console.WriteLine()
        Console.WriteLine("Press <Enter> to continue.")
        Console.WriteLine()
        Console.ReadKey()
    End Sub

    '*****************************************************************************
    ' Constants.
    '*****************************************************************************
    Private ReadOnly BACKGROUND_IMAGE_FILE As String = MIL.M_IMAGE_PATH + "imaginglogo.mim"

    Private ReadOnly PI As Double = 3.1415926535897931


    '--------------------------------------------------------------
    Sub Main()
        Dim MilApplication, MilSystem, MilDisplay3d, MilContainerId1, MilContainerId2 As MIL_ID
        Dim MatrixTranslate1, MatrixTranslate2, InitialViewpointMatrix, MatrixGrid As MIL_ID
        MilDisplay3d = MIL.M_NULL
        MilContainerId1 = MIL.M_NULL
        MilContainerId2 = MIL.M_NULL
        MatrixTranslate1 = MIL.M_NULL
        MatrixTranslate2 = MIL.M_NULL
        InitialViewpointMatrix = MIL.M_NULL
        MatrixGrid = MIL.M_NULL
        Dim GridLabel, AxisLabel, ContainerLabel1, ContainerLabel2 As Long
        Dim AxisLength As Double

        ' Print Header. 
        PrintHeader()

        ' Allocate the MIL application.
        MilApplication = MIL.MappAlloc(MIL.M_NULL, MIL.M_DEFAULT, MIL.M_NULL)

        ' Allocate the MIL system.
        MilSystem = MIL.MsysAlloc(MIL.M_DEFAULT, MIL.M_SYSTEM_HOST, MIL.M_DEFAULT, MIL.M_DEFAULT, MIL.M_NULL)

        ' Allocate the MIL 3D Display.
        MIL.MappControl(MIL.M_DEFAULT, MIL.M_ERROR, MIL.M_PRINT_DISABLE)
        MilDisplay3d = MIL.M3ddispAlloc(MilSystem, MIL.M_DEFAULT, "M_DEFAULT", MIL.M_DEFAULT, MIL.M_NULL)
        MIL.MappControl(MIL.M_DEFAULT, MIL.M_ERROR, MIL.M_PRINT_ENABLE)

        ' Make sure we meet the minimum requirements for the 3d display.
        If MilDisplay3d = 0 Then
            Console.WriteLine("The current system does not support the 3D display.")
            Console.WriteLine("Press <ENTER> to end.")
            Console.WriteLine()
            Console.ReadKey()
            Return
        End If

        ' Show the display.
        Dim MilGraphicList3d As MIL_ID = MIL.M_NULL
        MIL.M3ddispInquire(MilDisplay3d, MIL.M_3D_GRAPHIC_LIST_ID, MilGraphicList3d)

      '                                                   X,     Y,     Z
      MIL.M3ddispSetView(MilDisplay3d, MIL.M_VIEWPOINT, 100.0, 75.0, 75.0, MIL.M_DEFAULT)
      MIL.M3ddispSetView(MilDisplay3d, MIL.M_UP_VECTOR, 0.0, 0.0, 1.0, MIL.M_DEFAULT)
        MIL.M3ddispSelect(MilDisplay3d, MIL.M_NULL, MIL.M_OPEN, MIL.M_DEFAULT)

        ' Draw an axis And a grid.
        Console.WriteLine("MIL 3D displays can be used with 0, 1 or many point clouds.")
        Console.WriteLine("This allows you to show only the content of the display's graphics list.")
        Console.WriteLine("In this case, an axis and a grid are shown.")
        Console.WriteLine()

        AxisLength = 15.0
        AxisLabel = MIL.M3dgraAxis(MilGraphicList3d, MIL.M_ROOT_NODE, MIL.M_DEFAULT, AxisLength, "", MIL.M_DEFAULT, MIL.M_DEFAULT)

        ' Draw a grid to be displayed.
        MatrixGrid = MIL.M3dgeoAlloc(MilSystem, MIL.M_TRANSFORMATION_MATRIX, MIL.M_DEFAULT, MIL.M_NULL)
        MIL.M3dgeoMatrixSetTransform(MatrixGrid, MIL.M_TRANSLATION, AxisLength, AxisLength * 1.5, 0.0, MIL.M_DEFAULT, MIL.M_DEFAULT)
        GridLabel = MIL.M3dgraGrid(MilGraphicList3d, AxisLabel, MIL.M_SIZE_AND_SPACING, MatrixGrid, AxisLength * 2, AxisLength * 3, 5.0, 5.0, MIL.M_DEFAULT)
        MIL.M3dgraControl(MilGraphicList3d, GridLabel, MIL.M_FILL_COLOR, MIL.M_COLOR_WHITE)
        MIL.M3dgraControl(MilGraphicList3d, GridLabel, MIL.M_COLOR, MIL.M_COLOR_BLACK)
        MIL.M3dgraControl(MilGraphicList3d, GridLabel, MIL.M_OPACITY, 20)

        ' Translate both point clouds.
        MatrixTranslate1 = MIL.M3dgeoAlloc(MilSystem, MIL.M_TRANSFORMATION_MATRIX, MIL.M_DEFAULT, MIL.M_NULL)
        MIL.M3dgeoMatrixSetTransform(MatrixTranslate1, MIL.M_TRANSLATION, AxisLength, AxisLength * 2.2, 0.0, MIL.M_DEFAULT, MIL.M_DEFAULT)
        MatrixTranslate2 = MIL.M3dgeoAlloc(MilSystem, MIL.M_TRANSFORMATION_MATRIX, MIL.M_DEFAULT, MIL.M_NULL)
        MIL.M3dgeoMatrixSetTransform(MatrixTranslate2, MIL.M_TRANSLATION, AxisLength, AxisLength * 0.75, 0.0, MIL.M_DEFAULT, MIL.M_DEFAULT)

        ' Save viewpoint.
        InitialViewpointMatrix = MIL.M3dgeoAlloc(MilSystem, MIL.M_TRANSFORMATION_MATRIX, MIL.M_DEFAULT, MIL.M_NULL)

        Console.WriteLine("Use the mouse to set the 3D view in the display.")
        Console.WriteLine("   - Left click and drag   : Orbit around the interest point.")
        Console.WriteLine("   - Right click and drag  : Translates in the screen's plane.")
        Console.WriteLine("   - Middle click and drag : Roll.")
        Console.WriteLine("   - Mouse wheel           : Zoom in, Zoom out.")
        Console.WriteLine()
        Console.WriteLine("The resulting 3D view will be stored in a matrix using M3ddispCopy")
        Console.WriteLine("snd will be reused later.")
        Console.WriteLine("Press <Enter> to copy the current 3D view And continue.")
        Console.ReadKey()
        MIL.M3ddispCopy(MilDisplay3d, InitialViewpointMatrix, MIL.M_VIEW_MATRIX, MIL.M_DEFAULT)

        Console.WriteLine("Two point clouds have been added using M3ddispSelect.")
        Console.WriteLine()

        ' Generate a first meshed point cloud container.
        MilContainerId1 = Generate3DContainer(MilSystem)

        ' Clone the first to a second container.
        MilContainerId2 = MIL.MbufClone(MilContainerId1, MIL.M_DEFAULT, MIL.M_DEFAULT, MIL.M_DEFAULT, MIL.M_DEFAULT, MIL.M_DEFAULT, MIL.M_COPY_SOURCE_DATA, MIL.M_NULL)

        ' Select the containers to the 3D display And keep their corresponding labels in the graphics list of the 3D display.
        ContainerLabel1 = MIL.M3ddispSelect(MilDisplay3d, MilContainerId1, MIL.M_ADD, MIL.M_DEFAULT)
        ContainerLabel2 = MIL.M3ddispSelect(MilDisplay3d, MilContainerId2, MIL.M_ADD, MIL.M_DEFAULT)

        ' Move the second container.
        MIL.M3dgraCopy(MatrixTranslate1, MIL.M_DEFAULT, MilGraphicList3d, ContainerLabel1, MIL.M_TRANSFORMATION_MATRIX, MIL.M_DEFAULT)
        MIL.M3dgraCopy(MatrixTranslate2, MIL.M_DEFAULT, MilGraphicList3d, ContainerLabel2, MIL.M_TRANSFORMATION_MATRIX, MIL.M_DEFAULT)

        ' Setting the viewpoint.
        Console.WriteLine("Many options exist to change the display's viewpoint.")
        Console.WriteLine("Press <Enter> to set the viewpoint, interest point and up vector.")
        Console.WriteLine()
        Console.ReadKey()
        MIL.M3ddispControl(MilDisplay3d, MIL.M_UPDATE, MIL.M_DISABLE)
        '                                                            X,                Y,                 Z
        MIL.M3ddispSetView(MilDisplay3d, MIL.M_VIEWPOINT, AxisLength * 3.0, AxisLength, AxisLength * 10.0, MIL.M_DEFAULT)
        MIL.M3ddispSetView(MilDisplay3d, MIL.M_INTEREST_POINT, AxisLength, AxisLength, 0.0, MIL.M_DEFAULT)
        MIL.M3ddispSetView(MilDisplay3d, MIL.M_UP_VECTOR, -1.0, 0.0, 0.0, MIL.M_DEFAULT)

        MIL.M3ddispControl(MilDisplay3d, MIL.M_UPDATE, MIL.M_ENABLE)

        ' Show the options to move the view.
        Console.WriteLine("The view parameters can be either specific values or values composed")
        Console.WriteLine("with the current 3D view.")
        Console.WriteLine("Different options will be shown: ")
        Console.WriteLine(" -Move the viewpoint, relative to its current position, while keeping")
        Console.WriteLine("  the interest point constant.")
        Console.WriteLine("Press <Enter> to continue.")
        Console.ReadKey()

        Dim i As Integer = 0
        While i < 100
            Thread.Sleep(1)
            Dim Sign As Double = 1.0
            If i < 50 Then
                Sign = -1.0
            End If
            MIL.M3ddispSetView(MilDisplay3d, MIL.M_VIEWPOINT + MIL.M_COMPOSE_WITH_CURRENT, 0.0, Sign * 3.0, 0.0, MIL.M_DEFAULT)
            i += 1
        End While

        ' Show the effect of moving only interest point.
        Console.WriteLine(" -Move the interest point while keeping the viewpoint constant.")
        Console.WriteLine("Press <Enter> to continue.")
        Console.ReadKey()

        i = 0
        While i < 100
            Thread.Sleep(1)
            Dim Sign As Double = 1.0
            If i < 50 Then
                Sign = -1.0
            End If
            MIL.M3ddispSetView(MilDisplay3d, MIL.M_INTEREST_POINT + MIL.M_COMPOSE_WITH_CURRENT, 0.0, Sign * 0.5, 0.0, MIL.M_DEFAULT)
            i += 1
        End While

        ' Reset the point of view.
        MIL.M3ddispControl(MilDisplay3d, MIL.M_UPDATE, MIL.M_DISABLE)
        '                                                            X,                Y,                 Z
        MIL.M3ddispSetView(MilDisplay3d, MIL.M_VIEWPOINT, AxisLength * 3.0, AxisLength, AxisLength * 10.0, MIL.M_DEFAULT)
        MIL.M3ddispSetView(MilDisplay3d, MIL.M_INTEREST_POINT, AxisLength, AxisLength, 0.0, MIL.M_DEFAULT)
        MIL.M3ddispSetView(MilDisplay3d, MIL.M_UP_VECTOR, -1.0, 0.0, 0.0, MIL.M_DEFAULT)
        MIL.M3ddispControl(MilDisplay3d, MIL.M_UPDATE, MIL.M_ENABLE)

        ' Rotate up vector.
        Console.WriteLine(" -Modify the up vector (the same can be done by modifying the roll value).")
        Console.WriteLine("Press <Enter> to continue.")
        Console.ReadKey()

        i = 0
        While i <= 100
            Thread.Sleep(1)
            Dim Sign As Double = 1.0
            If i < 50 Then
                Sign = -1.0
            End If
            MIL.M3ddispSetView(MilDisplay3d, MIL.M_UP_VECTOR, Math.Cos((2.0 * PI * i / 100.0) + PI), Math.Sin((2.0 * PI * i / 100.0)), 0.0, MIL.M_DEFAULT)
            i += 1
        End While


        ' Translate the viewpoint And interestpoint.
        Console.WriteLine(" -Translate both the view And interest point.")
        Console.WriteLine("Press <Enter> to continue.")
        Console.ReadKey()

        i = 0
        While i < 50
            Thread.Sleep(1)
            MIL.M3ddispSetView(MilDisplay3d, MIL.M_TRANSLATE, 0.0, 1.0, 0.0, MIL.M_DEFAULT)
            i += 1
        End While

        i = 0
        While i < 50
            Thread.Sleep(1)
            MIL.M3ddispSetView(MilDisplay3d, MIL.M_TRANSLATE, 0.0, -0.95, 0.05, MIL.M_DEFAULT)
            i += 1
        End While

        ' Zoom.
        Console.WriteLine(" -Zoom in And out.         ")
        Console.WriteLine("Press <Enter> to continue.")
        Console.ReadKey()

        i = 0
        While i < 100
            Thread.Sleep(1)
            Dim Zoom As Double = 1.01
            If i < 50 Then
                Zoom = 0.99
            End If
            MIL.M3ddispSetView(MilDisplay3d, MIL.M_ZOOM, Zoom, MIL.M_DEFAULT, MIL.M_DEFAULT, MIL.M_DEFAULT)
            i += 1
        End While

        ' Azimuth And Elevation.
        Console.WriteLine(" -Modify the azimuth And the elevation.")
        Console.WriteLine("Press <Enter> to continue.")
        Console.ReadKey()

        i = 0
        While i < 50
            Thread.Sleep(1)
            MIL.M3ddispSetView(MilDisplay3d, MIL.M_ELEVATION + MIL.M_COMPOSE_WITH_CURRENT, Math.Cos((PI * i / 50.0) + PI), MIL.M_DEFAULT, MIL.M_DEFAULT, MIL.M_DEFAULT)
            i += 1
        End While

        i = 0
        While i < 50
            Thread.Sleep(1)
            MIL.M3ddispSetView(MilDisplay3d, MIL.M_AZIMUTH + MIL.M_COMPOSE_WITH_CURRENT, Math.Cos((PI * i / 50.0) + PI), MIL.M_DEFAULT, MIL.M_DEFAULT, MIL.M_DEFAULT)
            i += 1
        End While


        ' Viewbox.
        Console.WriteLine(" -Set the view to something that includes everything in the scene.")
        Console.WriteLine("Press <Enter> to continue.")
        Console.ReadKey()

        MIL.M3ddispSetView(MilDisplay3d, MIL.M_VIEW_BOX, MIL.M_WHOLE_SCENE, MIL.M_DEFAULT, MIL.M_DEFAULT, MIL.M_DEFAULT)

        ' Predefined orientations.
        Console.WriteLine(" -Set the view to a view from the top.")
        Console.WriteLine("Press <Enter> to continue.")
        Console.ReadKey()
        MIL.M3ddispSetView(MilDisplay3d, MIL.M_VIEW_ORIENTATION, MIL.M_TOP_VIEW, MIL.M_DEFAULT, MIL.M_DEFAULT, MIL.M_DEFAULT)

        Console.WriteLine(" -Set the view to a view from below.")
        Console.WriteLine("Press <Enter> to continue.")
        Console.ReadKey()
        MIL.M3ddispSetView(MilDisplay3d, MIL.M_VIEW_ORIENTATION, MIL.M_BOTTOM_VIEW, MIL.M_DEFAULT, MIL.M_DEFAULT, MIL.M_DEFAULT)

        Console.WriteLine(" -Set the view to a view from the side.")
        Console.WriteLine("Press <Enter> to continue.")
        Console.ReadKey()
        MIL.M3ddispSetView(MilDisplay3d, MIL.M_VIEW_ORIENTATION, MIL.M_LEFT_VIEW, MIL.M_DEFAULT, MIL.M_DEFAULT, MIL.M_DEFAULT)

        Console.WriteLine(" -Set the view to an angled view from the top.")
        Console.WriteLine("Press <Enter> to continue.")
        Console.ReadKey()
        MIL.M3ddispSetView(MilDisplay3d, MIL.M_VIEW_ORIENTATION, MIL.M_TOP_TILTED, MIL.M_DEFAULT, MIL.M_DEFAULT, MIL.M_DEFAULT)

        Console.WriteLine(" -Set the view to an angled view from below.")
        Console.WriteLine("Press <Enter> to continue.")
        Console.ReadKey()
        MIL.M3ddispSetView(MilDisplay3d, MIL.M_VIEW_ORIENTATION, MIL.M_BOTTOM_TILTED, MIL.M_DEFAULT, MIL.M_DEFAULT, MIL.M_DEFAULT)

        ' Restore copied view.
        Console.WriteLine("Press <Enter> to restore the previously copied view.")
        Console.WriteLine()
        Console.ReadKey()
        MIL.M3ddispCopy(InitialViewpointMatrix, MilDisplay3d, MIL.M_VIEW_MATRIX, MIL.M_DEFAULT)

        Console.WriteLine("The display's background color can be set to a solid color,")
        Console.WriteLine("a gradient, or an image.")
        Console.WriteLine("Press <Enter> to change the background color.")
        Console.WriteLine()
        Console.ReadKey()

        MIL.M3ddispControl(MilDisplay3d, MIL.M_BACKGROUND_MODE, MIL.M_SINGLE_COLOR)
        MIL.M3ddispControl(MilDisplay3d, MIL.M_BACKGROUND_COLOR, MIL.M_RGB888(50, 150, 125))

        Console.WriteLine("Press <Enter> to apply a gradient to the background.")
        Console.WriteLine()
        Console.ReadKey()

        MIL.M3ddispControl(MilDisplay3d, MIL.M_BACKGROUND_MODE, MIL.M_GRADIENT_VERTICAL)

        MIL.M3ddispControl(MilDisplay3d, MIL.M_BACKGROUND_COLOR, MIL.M_COLOR_DARK_BLUE)
        MIL.M3ddispControl(MilDisplay3d, MIL.M_BACKGROUND_COLOR_GRADIENT, MIL.M_COLOR_DARK_YELLOW)

        Console.WriteLine("Press <Enter> to use an image for the display's background.")
        Console.WriteLine()
        Console.ReadKey()

        Dim Image As MIL_ID = MIL.M_NULL
        MIL.MbufRestore(BACKGROUND_IMAGE_FILE, MilSystem, Image)

        ' Make the image darker.
        MIL.MimShift(Image, Image, -1)
        MIL.M3ddispCopy(Image, MilDisplay3d, MIL.M_BACKGROUND_IMAGE, MIL.M_DEFAULT)
        MIL.M3ddispControl(MilDisplay3d, MIL.M_BACKGROUND_MODE, MIL.M_BACKGROUND_IMAGE)

      Console.WriteLine("A gyroscope indicating interaction with the 3d display can be permanently")
      Console.WriteLine("visible. Its appearance can also be modified.")
      Console.WriteLine("Press <Enter> to make the gyroscope permanently visible.")
      Console.WriteLine()
      Console.ReadKey()
      MIL.M3ddispControl(MilDisplay3d, MIL.M_ROTATION_INDICATOR, MIL.M_ENABLE)
      MIL.M3ddispControl(MilDisplay3d, MIL.M_BACKGROUND_MODE, MIL.M_SINGLE_COLOR)
      MIL.M3ddispControl(MilDisplay3d, MIL.M_BACKGROUND_COLOR, MIL.M_RGB888(50, 150, 125))

      Console.WriteLine("Many keys are assigned to interactive actions.")
      Console.WriteLine("   Arrows : Orbit around the interest point.")
      Console.WriteLine("   Ctrl   : Speed modifier for the arrow keys.")
      Console.WriteLine("   Alt    : Action modifier for the arrow keys. Press Alt and Up/Down arrow for ")
      Console.WriteLine("            zooming  press Alt and Left/Right arrow for rolling.")
      Console.WriteLine("   Shift  : Modifies the arrows' function, moving the screen's plane instead.")
      Console.WriteLine("   1 - 8  : Specify the predefined viewpoint. Press a number key.")

        Console.WriteLine("Set focus to the 3D display window to use the keyboard.")

        Console.WriteLine("Press <Enter> to end.")
        Console.WriteLine()
        Console.ReadKey()


        MIL.MbufFree(Image)
        MIL.MbufFree(MilContainerId1)
        MIL.MbufFree(MilContainerId2)
        MIL.M3dgeoFree(MatrixGrid)
        MIL.M3dgeoFree(MatrixTranslate1)
        MIL.M3dgeoFree(MatrixTranslate2)
        MIL.M3dgeoFree(InitialViewpointMatrix)
        MIL.M3ddispFree(MilDisplay3d)
        MIL.MsysFree(MilSystem)
        MIL.MappFree(MilApplication)
    End Sub

    Function Generate3DContainer(MilSystem As MIL_ID) As MIL_ID
        ' Use a SDCF to acquire a MIL container with 3D data.
        Dim MilContainer3D As MIL_ID = MIL.M_NULL
        Dim MilDigitizer As MIL_ID = MIL.MdigAlloc(MilSystem, MIL.M_DEFAULT, "M_3D_SIMULATOR", MIL.M_DEFAULT, MIL.M_NULL)
        MIL.MbufAllocDefault(MilSystem, MilDigitizer, MIL.M_GRAB + MIL.M_DISP, MIL.M_DEFAULT, MIL.M_DEFAULT, MilContainer3D)
        MIL.MdigGrab(MilDigitizer, MilContainer3D)
        MIL.MdigFree(MilDigitizer)
        Return MilContainer3D
    End Function


End Module