===========================
HOOPS/WPF Integration Guide
===========================

Introduction
============

The HOOPS/WPF integration consists of a connection between HOOPS/3dGS and the WPF Window and User Control GUI objects. This document describes how to use the HOOPS/WPF integration to build a .NET WPF application that incorporates the HOOPS/3DF components. Some familiarity with .NET, WPF, HOOPS/3dGS and HOOPS/MVO is assumed.

Developers should start by compiling and running the basic *wpf_simple* application as the starting point for their application. This is the primary example for .NET WPF developers wishing to incorporate the HOOPS/3DF components into either existing or new .NET applications. The readable source code is located in the *<hoops>/demo/dotnet/wpf_simple* directory.


Platform/Compiler Support
=========================

The HOOPS/WPF integration is supported under Microsoft Visual Studio with .NET Framework 4.0.


Compilation and Runtime Information
===================================

The following steps are required to compile and run a HOOPS/WPF based application:

* **Compiling:** Your application must reference the HOOPS/3DF C# wrapper classes.

	* *hoops_cs.dll*
	* *hics_cs.dll*
	* *hoops_mvo_cs.dll*
	* *hoops_stream_cs.dll*
	* *hoops_wpf_cs.dll*

* Executing: Ensure that the following native DLLs are in your application's directory or in your PATH.

	  * *hoops_vc.dll*
	  * *hcs.dll*
	  * *hics.dll*
	  * *hoops_mvo_mgk_vc.dll*
	  * *hcsmvo.dll*
	  * *hoops_stream_vc.dll*
	  * *hcsstream.dll*
	  * *hoops_wpf_cs.dll*
	  * *d3dcompiler_.dll*
	

The above files are located in your *<VISUALIZE_INSTALL_DIR>/bin/<platform>* directory.


Component-Object Relationships
==============================

This section discusses the relationship between .NET WPF and HOOPS/3DF components. Building an application with both these toolkits minimally involves using the following objects from each component.


WPF
---

A .NET WPF application typically has a window object that contains controls displaying information from one document.


HOOPS/WPF
---------

There should be at least one set of ``hoops_base::HPanel`` and ``hoops_base::HWindow`` objects, where the panel gets attached to the window. You usually create a custom panel and window derived from ``HPanel`` and ``HWindow``. These two classes can be found in *<VISUALIZE_INSTALL_DIR>/Dev_Tools/hoops_wpf/source/*.


HOOPS/MVO
---------

``HBaseModel``, ``HBaseView``, and an operator class derived from ``HBaseOperator``. Applications that want to implement selection of geometry will also need a ``HSelectionSet`` object. These objects are all connected by private data members which store pointers to other objects in the following manner: 

.. image:: images/HOOPS_WPF_Architecture.gif


Steps to Building an Application with .NET WPF and HOOPS
========================================================

Programming with an object oriented GUI framework like .NET WPF involves creating a set of objects and defining the ways in which they are connected, the manner in which they send and receive messages, and then launching the framework's event loop. Building an application using .NET WPF and HOOPS/3DF specifically requires creation and initialization of:

* :ref:`.NET WPF Application objects <prog_guide/misc/wpf_integration:Creating and Initializing the Application>`
* :ref:`HOOPS/WPF objects <prog_guide/misc/wpf_integration:Creating and Initializing HOOPS/WPF Objects>`
* :ref:`HOOPS/MVO objects <prog_guide/misc/wpf_integration:Creating and Initializing HOOPS/MVO Objects>`


Creating and Initializing the Application
=========================================

A .NET WPF application usually creates a ``Application`` object which implements the function ``AppStartup``. The *wpf_simple* application does this in it's primary *App.xaml.cs* source file as follows::

	public partial class App : Application
	{
		void AppStartup(object sender, StartupEventArgs args)
		{
			WPFSimpleWindow mainForm = new WPFSimpleWindow();
			mainForm.Show();
		}
	}


Creating and Initializing HOOPS/WPF Objects
===========================================

The HOOPS/WPF integration consists of a customized WPF Window and User Control called ``HWindow`` and ``HPanel``, as diagrammed up above. (Again, the panel will get attached to the window.) As many pairs of these objects can be created as needed to implement the GUI's design. Your application should define custom ``HWindow`` and ``HPanel`` classes, as shown in *wpf_simple* source.

Custom ``SimpleWPFPanel`` definition taken from the *wpf_simple* project's *SimpleWPFPanel.cs* source file::

	public partial class SimpleWPFPanel : HPanel
	{
			
		// Constructor which calls the Init() method of the class  
		public SimpleWPFPanel(): base()
		{
			InitializeComponent();
		}

		// This method will set up the default HOOPS/MVO view for the panel and attach a HOOPS/MVO default operator 
		public void InitializeComponent()
		{
			// contents reviewed later
		}
	}

Here is custom ``WPFSimpleWindow`` definition taken from the *wpf_simple* project's *SimpleHWindow.xaml.cs* source file. Note that it creates the custom ``WPFSimpleWindow`` object and initializes the window::

	public partial class WPFSimpleWindow : HWindow
	{
		...
		
		 // Sets up the panel and window 
		   private void Init()
			{
				//Checking to see if an instance of WindowsFormsHost has been created to host the panel
				if(is_host_added == 0)
				{
					m_pHPanel = new SimpleWPFPanel();

					/**********************************************************************************
					/*	To use the HOOPS/WPF Panel in your WPF application, it is critial that you    *
					/*	MUST assign the panel as a child of your instance of WindowsFormsHost.  Then, *
					/*	you MUST add the WindowsFormsHost to your application in the desired location.*
					***********************************************************************************/
					m_pWinFormsHost.Child = m_pHPanel;

					CanvasGrid.Children.Add(m_pWinFormsHost);
					is_host_added = 1;
				}

				// first set up the window, then set the axis triad options
				m_pHPanel.m_pHModel.Flush();
				m_pHPanel.m_pHView.Update();
				m_pHPanel.m_pHView.SetAxisMode(AxisMode.AxisOn);
				m_pHPanel.m_pHView.AdjustAxisWindow();
				
				...
			}
		
		...
	}

Finally, we can note that the File->New and File->Open methods in ``WPFSimpleWindow`` will create a new custom ``WPFSimpleWindow`` object::

	public partial class WPFSimpleWindow : HWindow
	{
			...
			
		private void New_Click(object sender, RoutedEventArgs e)
		{
			WPFSimpleWindow newWindow = new WPFSimpleWindow();
			newWindow.Init();
			newWindow.Show();
		}

		private void Open_Click(object sender, RoutedEventArgs e)
		{
			WPFSimpleWindow newWindow = new WPFSimpleWindow();            
			newWindow.Init();
			newWindow.Load_File(sender, e);
			newWindow.Show();
		}
			
		private void Load_File(object sender, RoutedEventArgs e)
		{
			//Creating the Open File Dialog
			openFileDialog = new OpenFileDialog();
			openFileDialog.Title = "Load";
			openFileDialog.Filter = "HMF/HSF files (*.hmf, *.hsf)|*.hmf;*.hsf" + "|All files (*.*)|*.*";

			//Showing the File Dialog
			Nullable<bool> result = openFileDialog.ShowDialog();
			
			if (result == true)
			{
			   //Loading the file into the HOOPS Database
			   m_pHPanel.m_pHModel.Flush();
			   m_pHPanel.m_pHModel.Read(openFileDialog.FileName);

			   m_pHPanel.m_pHView.FitWorld(); // This resets the camera so that it views the extents of the                                                                                                        scene
			   m_pHPanel.m_pHView.Update();
			}
		}
					
			...
	}


Creating and Initializing HOOPS/MVO Objects
===========================================

HDB
---

One global pointer to a HOOPS/MVO HDB object should be declared and initialized in your application's main class. The *wpf_simple* app does this in the main ``WPFSimpleWindow`` constructor (located in *SimpleHWindow.xaml.cs*)::

	public partial class WPFSimpleWindow : HWindow
	{
		....
		 
		// Constructor which initializes hoops database and GUI features of the main window */
		 public WPFSimpleWindow()
		 {
			...

			m_pHDB = new HDB();
			m_pHDB.Init();

			...
		}
	}


HBaseModel
----------

Multiple ``HBaseModel`` objects can be created as needed. The *wpf_simple* app creates one for every ``SimpleWPFPanel`` object (i.e., there is a one-to-one mapping of ``HBaseModel`` to ``SimpleWPFPanel`` objects) and does so in the ``SimpleWPFPanel::InitializeComponent``::

	public partial class SimpleWPFPanel : HPanel
	{
		...

		public void InitializeComponent()
		{
			...
			
			m_pHModel = new HSimpleModel();
			m_pHModel.Init();
				
			...
		}
		...
	}

  
HBaseView
---------

Multiple ``HBaseView`` objects can be created as needed, with one object usually being created for each ``SimpleWPFPanel``. The ``HBaseView`` needs a valid native GUI window id  passed to its constructor on object creation; this information is used to connect a HOOPS/3dGS output driver instance to a ``SimpleWPFPanel``. This requires that the ``SimpleWPFPanel``, to which the ``HBaseView`` will be attached, already exist prior to creating the ``HBaseView`` object.

Your app should create the ``HBaseView`` object in your overloaded ``SimpleWPFPanel::InitializeComponent`` method. Here is the *wpf_simple* example taken from *SimpleHPanel.cs*::

	public partial class SimpleWPFPanel : HPanel
	{
		...

		public void InitializeComponent()
		{
			...
				
			m_pHView = new HSimpleView(m_pHModel, "?picture" + winid, "dx11", "", winid);
			m_pHView.Init();
				
			...
		}
		...
	}

NOTE: A texture sharing limitation in WPF does not support a non-default GPU (cf. "gpu preference" Driver Option).


HSelectionSet
-------------

The ``HBaseView`` class and ``SimpleWPFPanel`` class contain pointers to a ``HSelectionSet`` object. A selection set class would typically be created and initialized during ``SimpleWPFPanel`` initialization. After creation, it's important to pass the ``HSelectionSet`` operator into ``HBaseView`` by calling ``HBaseView::SetSelection``. The *wpf_simple* app does this in the overloaded method of ``SimpleWPFPanel::InitializeComponent`` method::

	public partial class SimpleWPFPanel : HPanel
	{
		...

		public void InitializeComponent()
		{
			...

			// view and model initialization goes here, and was discussed previously
			
			// Set up the custom HSelectionSet object
				m_pHSelection = new HSimpleSelectionSet(m_pHView);
				m_pHView.SetSelection(m_pHSelection);
				m_pHView.GetSelection().Init();
			 
			...
		}
	}


HBaseOperator
-------------

The ``HBaseView`` class and ``SimpleWPFPanel`` class contains pointers to a ``HBaseOperator`` object. A default operator would typically be created and initialized during ``SimpleWPFPanel`` initialization. After creating, you should set it to be the current operator by calling the utility method ``SimpleWPFPanel::SetCurrentOperator``. The *wpf_simple* app does this in the overloaded method of ``SimpleWPFPanel::InitializeComponent`` method::

	public partial class SimpleWPFPanel : HPanel
	{
		...

		public void InitializeComponent()
		{
			...
			
			// Set the default operator
			m_pHOperator = new HOpCameraManipulate(m_pHView);
			m_pHView.SetCurrentOperator((HBaseOperator)m_pHOperator);
			 
			...
		}

	}
