ExampleApplication.vb

From Axiom

Jump to: navigation, search

' This file was created from ExampleApplication.h (Ogle v1.2.3) by trejs
' for use with Axiom's tutorials.
'
' It still has some flaws. See the "// TODO" lines to begin with.
' But better that than no tutorials at all :)
'
' 2006-12-26: Fixed the mouse button issue, code now compatible with 0.7.1.0-RC2. / trejs
' 2007-08-17: Updated for compatibility with 0.7.2.0 / borrillis 
' 2009-01-19: Translated to VB / wleader

#Region " Namespace Declaration "
Imports System
Imports System.Data
Imports System.Collections.Generic

Imports Axiom
Imports Axiom.Core
Imports Axiom.Graphics
Imports Axiom.Configuration
Imports Axiom.Math
Imports Axiom.Overlays
Imports Axiom.Input
#End Region

Namespace ExampleApplication
    Public Class ExampleApplication
#Region " Configure Console "
        ' Code originally from the command-line demo launcher. Mostly rewritten.
        '
        ' If you only want the configuration menu, just copy this class into your application.
        ' See how it's used in ExampleApplication.Configure().
        Private Class ConfigureConsole
#Region " Types "
            Public Enum DialogResult
                [Continue]
                Run
                [Exit]
            End Enum
#End Region
#Region " Private Fields "
            ' Currently selected system
            Private m_currentSystem As RenderSystem

            ' Holds the list of possible rendersystems
            Private m_renderSystems As ConfigOption
			
            ' Menu items
            Private m_currentMenuItems As New List(Of ConfigOption)
			
            ' Currently selected item
            Private m_currentOption As ConfigOption
			
            ' Options for the currently selected system
            Private m_currentSystemOptions As New List(Of ConfigOption)
#End Region
#Region " Properties "
            ''' <summary>
            ''' Gets the selected rendersystem (and all the values of options set for it)
            ''' </summary>
            Public ReadOnly Property RenderSystem() As RenderSystem
                Get
                    Return m_currentSystem
                End Get
            End Property
#End Region
#Region " Constructor "
            Public Sub New()
                ' Set current RenderSystem to first in list
                m_currentSystem = Root.Instance.RenderSystems(0)

                ' Create rendersystem option and get possible values
                m_renderSystems = New ConfigOption("Render System", m_currentSystem.Name, False)
                Dim R As RenderSystem
                For Each R In Root.Instance.RenderSystems
                    m_renderSystems.PossibleValues.Add(R.ToString)
                Next

                BuildCurrentSystemOptions()
            End Sub
#End Region
#Region " Public Methods "
            Public Function Show() As DialogResult
                While True
                    ' Clear menu buffer
                    m_currentMenuItems.Clear()

                    ' Build menu
                    If IsNothing(m_currentOption) Then 'Main Menu
                        ' Build menu from m_currentOptions
                        Dim C As ConfigOption
                        For Each C In m_currentSystemOptions
                            m_currentMenuItems.Add(C)
                        Next
                    Else 'option menu
                        ' Add possible values for this option
                        Dim value As Object
                        For Each value In m_currentOption.PossibleValues
                            m_currentMenuItems.Add(New ConfigOption(value.ToString, String.Empty, False))
                        Next
                    End If

                    ' Display menu
                    DisplayOptions()

                    ' Handle next keypress (waits for user input)
                    Dim Result As DialogResult = HandleNextKeyPress()

                    ' Check if we're exiting the configure console
                    If Result <> DialogResult.Continue Then
                        Console.Clear()
                        Return Result
                    End If
				End While
            End Function
#End Region
#Region " Private Methods "
            Private Sub BuildCurrentSystemOptions()
                ' Make sure its empty
                m_currentSystemOptions.Clear()

                ' Add RenderSystem options to the list.
                m_currentSystemOptions.Add(m_renderSystems)

                ' Browse and add options of current rendersystem
                Dim C As ConfigOption
                For Each C In m_currentSystem.ConfigOptions
                    m_currentSystemOptions.Add(C)
                Next
            End Sub


            Private Function IsDigit(ByRef digit As Integer, ByVal Key As ConsoleKey)
                Dim Str As String = Key.ToString
                If Str.Length = 2 And Char.IsDigit(Str.Substring(1)) Then
                    digit = Integer.Parse(Str.Substring(1)) ' Numbers are returend like "D5"
                    Return True
                End If
                Return False
            End Function

            Private Function HandleNextKeyPress() As DialogResult
                ' Wait for key and then read it without echo to the console
                Dim Key As ConsoleKey = Console.ReadKey(True).Key

                ' if the currentoption.Name is null, then we're in the main menu.
                If IsNothing(m_currentOption) Then
                    'Escape exits, Enter Runs
                    If Key = ConsoleKey.Escape Then
                        Return ConfigureConsole.DialogResult.Exit
                    ElseIf Key = ConsoleKey.Enter Then
                        ' Save options for current system.
                        For I As Integer = 0 To m_currentSystemOptions.Count - 1
                            Dim Opt As ConfigOption = m_currentSystemOptions(I)
                            m_currentSystem.ConfigOptions(Opt.Name) = Opt
                        Next
                        Return ConfigureConsole.DialogResult.Run
                    Else
                        ' Check for selection
                        Dim selection As Integer = 0
                        If IsDigit(selection, Key) And selection < m_currentMenuItems.Count Then
                            m_currentOption = m_currentMenuItems(selection)
                        End If
                    End If
                Else
                    ' Esc: Return to main menu
                    If Key = ConsoleKey.Escape Then
                        m_currentOption = Nothing
                    End If

                    ' Check if the current key is a digit, and if that digit is within the possible values
                    Dim selection As Integer = 0

                    If IsDigit(selection, Key) And selection < m_currentMenuItems.Count Then
                        ' Check if we're about to change render system
                        If m_currentOption.Name = "Render System" Then
                            m_currentSystem = Root.Instance.RenderSystems(selection)
                            m_renderSystems = m_currentOption
                            BuildCurrentSystemOptions()
                            m_currentOption = Nothing ' Reset current option (to show main-menu)
						Else
                            m_currentOption.Value = m_currentOption.PossibleValues(selection)
                            ' Set the selected value
                            For I As Integer = 0 To m_currentSystemOptions.Count - 1
                                If m_currentSystemOptions(I).Name = m_currentOption.Name Then
                                    m_currentSystemOptions(I) = m_currentOption
                                End If
                            Next
                            m_currentOption = Nothing ' Reset current option (to show main-menu)
                        End If
                    End If
                End If

                Return ConfigureConsole.DialogResult.Continue
            End Function

            Private Sub DisplayOptions()
                Console.Clear()
                Console.WriteLine("Axiom Engine Configuration")
                Console.WriteLine("==========================")

                If Not IsNothing(m_currentOption) AndAlso Not IsNothing(m_currentOption.Name) Then
                    Console.WriteLine("Available settings for {0}.\n", m_currentOption.Name)
                End If

                ' Load Render Subsystem Options
                Dim i As Integer = 0
                For Each C As ConfigOption In m_currentMenuItems
                    ' If this is a possible-value of an option (and not a list of options in the main-menu)
                    ' we need to display it's name but not the current value (it doesn't have any).
                    If IsNothing(m_currentOption) OrElse IsNothing(m_currentOption.Name) Then
                        Console.WriteLine("{0}      | {1}", i + 1, C.ToString)
                    Else
                        Console.WriteLine("{0}      | {1}", i + 1, C.Name)
                    End If
                    i += 1
                Next

                If IsNothing(m_currentOption) OrElse IsNothing(m_currentOption.Name) Then
                    Console.WriteLine()
                    Console.WriteLine("Enter  | Saves changes.")
                    Console.WriteLine("ESC    | Exits.")
                End If

                Console.Write("\nSelect option: ")
            End Sub

#End Region
        End Class
#End Region

#Region " Private Fields "
        Private m_configFile As String = "EngineConfig.xml"
        Private m_logFile As String = "AxiomExample.log"
        Private m_lastOverlayUpdate As Long = -1000
        Private m_moveScale As Single = 0
        Private m_rotScale As Single = 0
        Private m_moveSpeed As Single = 100
        Private m_rotateSpeed As Single = 36
        Private m_rotateVector As New Vector2(0, 0)
        Private m_translateVector As New Vector3(0, 0, 0)
        Private m_root As Root
        Private m_camera As Camera
        Private m_sceneManager As SceneManager
        Private m_renderWindow As RenderWindow
        Private m_inputReader As InputReader
#End Region
#Region " Protected Properties"
        ''' <summary>
        ''' Root (Axiom.Core.Root)
        ''' </summary>
        Protected Property Root() As Root
            Get
                Return m_root
            End Get
            Set(ByVal value As Root)
                m_root = value
            End Set
        End Property
        ''' <summary>
        ''' Camera (Axiom.Core.Camera)
        ''' </summary>
        Protected Property Camera() As Camera
            Get
                Return m_camera
            End Get
            Set(ByVal value As Camera)
                m_camera = value
            End Set
        End Property
        ''' <summary>
        ''' SceneManager (Axiom.Core.SceneManager)
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Protected Property SceneManager() As SceneManager
            Get
                Return m_sceneManager
            End Get
            Set(ByVal value As SceneManager)
                m_sceneManager = value
            End Set
        End Property
        ''' <summary>
        ''' RenderWindow (Axiom.Graphics.RenderWindow)
        ''' </summary>
        Protected Property RenderWindow() As RenderWindow
            Get
                Return m_renderWindow
            End Get
            Set(ByVal value As RenderWindow)
                m_renderWindow = value
            End Set
        End Property
        ''' <summary>
        ''' InputReader (Axiom.Input.InputReader)
        ''' </summary>
        Protected Property InputReader() As InputReader
            Get
                Return m_inputReader
            End Get
            Set(ByVal value As InputReader)
                m_inputReader = value
            End Set
        End Property
#End Region
#Region " Public Properties "
        ''' <summary>
        ''' Gets or set the config file name and path
        ''' </summary>
        Public Property ConfigFile() As String
            Get
                Return m_configFile
            End Get
            Set(ByVal value As String)
                m_configFile = value
            End Set
        End Property
        ''' <summary>
        ''' Gets or sets the config file name and path
        ''' </summary>
        Public Property LogFile() As String
            Get
                Return m_logFile
            End Get
            Set(ByVal value As String)
                m_logFile = value
            End Set
        End Property
#End Region
#Region " Init Methods "
        ''' <summary>
        ''' Starts the example
        ''' </summary>
        Public Overridable Sub Run()
            Try
                If Setup() Then
                    m_root.StartRendering()
                End If
            Catch ex As System.Reflection.ReflectionTypeLoadException
                ' This catches directx missing (or too old) to log :)
                For I As Integer = 0 To ex.LoaderExceptions.Length - 1
                    If Not IsNothing(LogManager.Instance) Then
                        LogManager.Instance.Write(ex.LoaderExceptions(I).Message)
                    End If
                Next
            Catch Ex As Exception
                If Not IsNothing(LogManager.Instance) Then
                    LogManager.Instance.Write(Ex.ToString)
                End If
            End Try
            ' TODO: Memory cleanup here..
        End Sub
        ''' <summary>
        ''' Initalizes the application
        ''' </summary>
        ''' <returns>True if successfull, False to exit the application</returns>
        ''' <remarks></remarks>
        Protected Overridable Function Setup() As Boolean
            m_root = New Root(ConfigFile, LogFile)

            SetupResources()

            ' Run config utility, exit program if it returns false
            If Not Configure() Then
                Return False
            Else
                m_renderWindow = Root.Instance.Initialize(True)
            End If

            ' Initalize input
            m_inputReader = PlatformManager.Instance.CreateInputReader()
            m_inputReader.Initialize(m_renderWindow, True, True, False, True)

            ChooseSceneManager()
            CreateCamera()
            CreateViewports()

            ' Set default mipmap level (NB some APIs ignore this)
            TextureManager.Instance.DefaultNumMipMaps = 5

            ' Create any resource listeners (for loading screens)
            CreateResourceListener()

            ' Add some event handlers
            RegisterEventHandlers()

            ' Lastly, create the scene
            CreateScene()

            Return True

        End Function
        ''' <summary>
        ''' Adds the searchpaths from "EngineConfig.xml" to resources
        ''' </summary>
        Protected Overridable Sub SetupResources()
            Dim config As New EngineConfig()
            config.ReadXml(ConfigFile)
            For Each row As EngineConfig.FilePathRow In config.FilePath
                ResourceManager.AddCommonArchive(row.src, row.type)
            Next
        End Sub
        ''' <summary>
        ''' Configures the application
        ''' </summary>
        ''' <returns>True if successfull, False to exit the application</returns>
        Protected Overridable Function Configure() As Boolean
            Dim cc As ConfigureConsole = New ConfigureConsole
            If cc.Show = ConfigureConsole.DialogResult.Exit Then
                Return False
            End If

            ' Set selected rendersystem
            m_root.RenderSystem = cc.RenderSystem

            Return True
        End Function
        ''' <summary>
        ''' Chooses scene manager (SceneType.Generic)
        ''' </summary>
        Protected Overridable Sub ChooseSceneManager()
            ' Create a generic scene manager
            m_sceneManager = m_root.SceneManagers.GetSceneManager(SceneType.Generic)
        End Sub
        ''' <summary>
        ''' Creates a camera at 500 in the Z direction that looks at -300 in the Z direction
        ''' </summary>
        Protected Overridable Sub CreateCamera()
            ' Create the camera
            m_camera = m_sceneManager.CreateCamera("PlayerCam")

            ' Position it at 500 in the Z direction
            m_camera.Position = New Vector3(0, 0, 500)

            ' Look back along -Z
            m_camera.LookAt(New Vector3(0, 0, -300))
            m_camera.Near = 5
        End Sub
        ''' <summary>
        ''' Creates a viewport using mCamera
        ''' </summary>
        ''' <remarks></remarks>
        Protected Overridable Sub CreateViewports()
            ' Create one viewport, entire window
            Dim vp As Viewport = m_renderWindow.AddViewport(m_camera)
            vp.BackgroundColor = ColorEx.Black

            ' Alter the camera aspect ratio to match the viewport
            m_camera.AspectRatio = vp.ActualWidth / vp.ActualHeight
        End Sub
        ''' <summary>
        ''' Optional override method where you can create resource listeners (e.g. for loading screens)
        ''' </summary>
        ''' <remarks></remarks>
        Protected Overridable Sub CreateResourceListener()

        End Sub
        ''' <summary>
        ''' Registers event handlers and calls InitOverlay()
        ''' </summary>
        Protected Overridable Sub RegisterEventHandlers()
            AddHandler m_root.FrameStarted, AddressOf UpdateInput
            AddHandler m_root.FrameStarted, AddressOf UpdateOverlay
            AddHandler m_root.FrameStarted, AddressOf FrameStarted
            AddHandler m_root.FrameEnded, AddressOf FrameEnded
            
            ' Create debug overlay
            InitOverlay()
        End Sub
        ''' <summary>
        ''' Initalizes the debug overlay (fps, etc..)
        ''' </summary>
        ''' <remarks></remarks>
        Protected Overridable Sub InitOverlay()
            Dim o As Overlay = OverlayManager.Instance.GetByName("Core/DebugOverlay")
            If IsNothing(o) Then
                Throw New Exception("Could not find overlay named 'Core/DebugOverlay'.")
            End If
            o.Show()
        End Sub
        ''' <summary>
        ''' Creates the Scene
        ''' </summary>
        Protected Overridable Sub CreateScene()

        End Sub
#End Region
#Region " Event Handlers "
        ''' <summary>
        ''' This is run before each frame.
        ''' </summary>
        Protected Overridable Sub FrameStarted(ByVal source As Object, ByVal e As FrameEventArgs)

        End Sub
        ''' <summary>
        ''' This is run after each frame
        ''' </summary>
        Protected Overridable Sub FrameEnded(ByVal source As Object, ByVal e As FrameEventArgs)

        End Sub
        ''' <summary>
        ''' Checks for input and handles it.
        ''' </summary>
        Protected Overridable Sub UpdateInput(ByVal source As Object, ByVal e As FrameEventArgs)
            m_inputReader.Capture()

            ' Reset vectors
            m_rotateVector.x = 0
            m_translateVector.x = 0
            m_rotateVector.y = 0
            m_translateVector.y = 0
            m_translateVector.z = 0

            ' Move
            m_moveScale = m_moveSpeed * e.TimeSinceLastFrame

            ' Rotate
            m_rotScale = m_rotateSpeed * e.TimeSinceLastFrame

            ' Move forward and back
            If m_inputReader.IsKeyPressed(KeyCodes.W) Or m_inputReader.IsKeyPressed(KeyCodes.Up) Then
                m_translateVector.z = -m_moveScale
            ElseIf m_inputReader.IsKeyPressed(KeyCodes.S) Or m_inputReader.IsKeyPressed(KeyCodes.Down) Then
                m_translateVector.z = m_moveScale
            End If

            ' Move left and right
            If m_inputReader.IsKeyPressed(KeyCodes.A) Then
                m_translateVector.x = -m_moveScale
            ElseIf m_inputReader.IsKeyPressed(KeyCodes.D) Then
                m_translateVector.x = m_moveScale
            End If

            ' Move up and down
            If m_inputReader.IsKeyPressed(KeyCodes.PageUp) Then
                m_translateVector.y = m_moveScale
            ElseIf m_inputReader.IsKeyPressed(KeyCodes.PageDown) Then
                m_translateVector.y = -m_moveScale
            End If

            ' Rotate left and right
            If m_inputReader.IsKeyPressed(KeyCodes.Left) Then
                m_rotateVector.x = -m_rotScale
            ElseIf m_inputReader.IsKeyPressed(KeyCodes.Right) Then
                m_rotateVector.x = m_rotScale
            End If

            ' Right mouse button pressed
            If m_inputReader.IsMousePressed(MouseButtons.Right) Then
                ' Translate
                m_translateVector.x += m_inputReader.RelativeMouseX * 0.13F
                m_translateVector.y -= m_inputReader.RelativeMouseY * 0.13F
            ElseIf m_inputReader.IsMousePressed(MouseButtons.Left) Then
                ' Apply mouse rotation
                m_rotateVector.x += m_inputReader.RelativeMouseX * 0.13F
                m_rotateVector.y += m_inputReader.RelativeMouseY * 0.13F
            End If

            ' Apply changes
            m_camera.Yaw(-m_rotateVector.x)
            m_camera.Pitch(-m_rotateVector.y)
            m_camera.MoveRelative(m_translateVector)

            ' TODO: what about window-closing-event?
            If m_inputReader.IsKeyPressed(KeyCodes.Escape) Then
                Root.Instance.QueueEndRendering()

                ' TODO: Find a better way
                If IsNothing(m_root) Then
                    ' remove event handlers
                    '  engine.FrameStarted -= new FrameEvent( OnFrameStarted );
                    ' engine.FrameEnded -= new FrameEvent( OnFrameEnded );
                    m_root.Dispose()
                End If

                m_sceneManager.RemoveAllCameras()
                m_sceneManager.RemoveCamera(m_camera)
                m_camera = Nothing
                Root.Instance.RenderSystem.DetachRenderTarget(m_renderWindow)
                m_renderWindow.Dispose()
            End If
        End Sub
        ''' <summary>
        ''' Updates the debug overlay
        ''' </summary>
        Protected Overridable Sub UpdateOverlay(ByVal source As Object, ByVal e As FrameEventArgs)
            If (Root.Instance.Timer.Milliseconds - m_lastOverlayUpdate >= 1000) Then

                m_lastOverlayUpdate = Root.Instance.Timer.Milliseconds

                Dim element As OverlayElement = OverlayElementManager.Instance.GetElement("Core/DebugText")
                element.Text = m_renderWindow.DebugText

                element = OverlayElementManager.Instance.GetElement("Core/CurrFps")
                element.Text = String.Format("Current FPS: {0}", Root.Instance.CurrentFPS)

                element = OverlayElementManager.Instance.GetElement("Core/BestFps")
                element.Text = String.Format("Best FPS: {0}", Root.Instance.BestFPS)

                element = OverlayElementManager.Instance.GetElement("Core/WorstFps")
                element.Text = String.Format("Worst FPS: {0}", Root.Instance.WorstFPS)

                element = OverlayElementManager.Instance.GetElement("Core/AverageFps")
                element.Text = String.Format("Average FPS: {0}", Root.Instance.AverageFPS)

                element = OverlayElementManager.Instance.GetElement("Core/NumTris")
                element.Text = String.Format("Triangle Count: {0}", m_sceneManager.TargetRenderSystem.FacesRendered)
            End If
        End Sub
#End Region
    End Class
End Namespace

Personal tools