// =========================================================================== //  ©2013-2026 WebSupergoo. All rights reserved. // //  This source code is for use exclusively with the ABCpdf product with //  which it is distributed, under the terms of the license for that //  product. Details can be found at // //    http://www.websupergoo.com/ // //  This copyright notice must not be deleted and must be reproduced alongside //  any sections of code extracted from this module. // =========================================================================== using System; using System.IO; using System.Collections.Generic; using System.Windows; using System.Windows.Controls; using System.Windows.Media; using System.Windows.Media.Imaging; using System.ComponentModel; using System.Runtime.InteropServices; namespace Glue3DUtilities {   #region Info   /// <summary>   /// Follow steps 1a or 1b and then 2 to use this custom control in a XAML file.   ///   /// Step 1a) Using this custom control in a XAML file that exists in the current project.   /// Add this XmlNamespace attribute to the root element of the markup file where it is   /// to be used:   ///   ///     xmlns:MyNamespace="clr-namespace:Glue3DUtilities"   ///   ///   /// Step 1b) Using this custom control in a XAML file that exists in a different project.   /// Add this XmlNamespace attribute to the root element of the markup file where it is   /// to be used:   ///   ///     xmlns:MyNamespace="clr-namespace:Glue3DUtilities;assembly=Glue3DUtilities"   ///   /// You will also need to add a project reference from the project where the XAML file lives   /// to this project and Rebuild to avoid compilation errors:   ///   ///     Right click on the target project in the Solution Explorer and   ///     "Add Reference"->"Projects"->[Browse to and select this project]   ///   ///   /// Step 2)   /// Go ahead and use your control in the XAML file.   ///   ///     <MyNamespace:Render3DControl/>   ///   /// </summary>   ///   #endregion   /// <summary>A control that allows rendering 3D models</summary>   public class Render3DControl : Control, INotifyPropertyChanged   {     #region MemberStructs     /// <summary>Describes a camera by it's key properties</summary>     public struct CameraInfo     {       /// <summary>Name of the camera</summary>       public string cameraName;       /// <summary>The mode of the camera (how it can move)</summary>       public WebSupergoo.ECameraMode cameraMode;       /// <summary>Whether the camera uses orthogonal or perspective projection</summary>       public bool isOrtho;       /// <summary>Whether the camera can be modified</summary>       public bool isModifiable;     }     /// <summary>Info on a newly opened file</summary>     public struct FileOpenInfo     {       /// <summary>The name of the file that the scene originates from</summary>       public string originalFilename;       /// <summary>The scene handle that the renderer uses internally</summary>       public UInt32 sceneHandle;       /// <summary>The list of available cameras (by name)</summary>       public string[] availableCameras;       /// <summary>Information about the currently active camera</summary>       public CameraInfo activeCameraInfo;       /// <summary>The lighting scheme that is used for the scene</summary>       public WebSupergoo.ELightingScheme lightingScheme;     }     #endregion     #region Delegates     /// <summary>Delegate which gets called when the camera changed</summary>     public delegate void DelegateCameraChanged(CameraInfo camInfo, bool success);     /// <summary>Delegate the gets called when the list of available cameras is received</summary>     public delegate void DelegateCameraListReceived(string[] camNames);     #endregion     #region MemberVariables     #region PrivateMembers     private Border m_borderElement = null;     private Render3DHost m_renderHost = null;     private System.Windows.Controls.Image m_placeholderImage = null;     private ImageSource m_placeholderImageSource = null;     private IntPtr m_renderProxy = IntPtr.Zero;     private bool m_isInDesignMode = false;     private string m_currentSceneFilename = null;     private UInt32 m_currentSceneHandle = 0;     private bool m_hasCSAASupport = false;     private WebSupergoo.DelegateOnActiveCameraChanged m_currentCamDelegate = null;     private WebSupergoo.DelegateStrList m_currentCamListDelegate = null;     private WebSupergoo.DelegateLoadComplete m_loadCompleteDelegate = null;     private WebSupergoo.DelegateUnloadComplete m_unloadCompleteDelegate = null;     private WebSupergoo.DelegateLoadProgress m_loadProgressDelegate = null;     private WebSupergoo.DelegateExportComplete m_exportCompleteDelegate = null;     private bool m_loadViewFilesOnSceneOpen = true;     private Renderer.GLVersionInfo m_versionInfo = new Renderer.GLVersionInfo();     #endregion     #region PublicMembers     /// <summary>Eventhandler for property changed events</summary>     public event PropertyChangedEventHandler PropertyChanged;     /// <summary>Whether Coverage Sampled Antialiasing (CSAA) is availabe (Note: Only on Nvidia graphics cards)</summary>     public bool HasCSAASupport     {       get { return m_hasCSAASupport; }       private set { Utilities.SetPropertyAndNotify(this.PropertyChanged, ref m_hasCSAASupport, value, () => HasCSAASupport); }     }     /// <summary>The list of available antialiasing modes (each AA mode described by an UInt32, with the lower word representing the color samples, and higher word the  coverage samples</summary>     public UInt32[] AvailableAntiAliasingModes { get; private set; }     /// <summary>The list of available Anisotropy modes (affects image quality of textures)</summary>     public UInt32[] AvialableAnisotropyModes { get; private set; }     /// <summary>Whether view files (text files containing PDF view annotations (3DV)) should be loaded upon scene opening (if available next to the scene file)</summary>     public bool LoadViewFilesOnSceneOpen     {       get { return m_loadViewFilesOnSceneOpen; }       private set { Utilities.SetPropertyAndNotify(this.PropertyChanged, ref m_loadViewFilesOnSceneOpen, value, () => LoadViewFilesOnSceneOpen); }     }     /// <summary>Access the version info of OpenGL and GLSL (will only return actual values after the renderer was initialized)</summary>     public Renderer.GLVersionInfo VersionInfo     {       get { return m_versionInfo; }       private set { m_versionInfo = value; }     }     #endregion     #endregion     #region CustomEvents     #region RenderProxyReadyEvent     /// <summary>Event arguments for RenderProxyReady event</summary>     public class RenderProxyReadyEventArgs : EventArgs     {       /// <summary>Constructor</summary>       public RenderProxyReadyEventArgs(string proxyName)       {         this.Name = proxyName;       }       /// <summary>Name of the RenderProxy instance</summary>       public string Name { get; private set; }     }     /// <summary>Delegate for RenderProxyReady event</summary>     public delegate void RenderProxyReadyEventHandler(object sender, RenderProxyReadyEventArgs fe);     /// <summary>RenderProxyReady event, fired when the render proxy was initialized</summary>     public event RenderProxyReadyEventHandler RenderProxyReadyEvent;     #endregion     #region FileOpeningEvent     /// <summary>Event arguments for FileOpening event</summary>     public class FileOpeningEventArgs : EventArgs     {       /// <summary>Constructor</summary>       public FileOpeningEventArgs(string filename)       {         this.Filename = filename;       }       /// <summary>Name of the file to be opened</summary>       public string Filename { get; private set; }     }     /// <summary>Delegate for FileOpening event</summary>     public delegate void FileOpeningEventHandler(object sender, FileOpeningEventArgs fe);     /// <summary>FileOpening event, fired when it starts loading a scene</summary>     public event FileOpeningEventHandler FileOpeningEvent;     #endregion     #region FileOpenedEvent     /// <summary>Event arguments for FileOpened event</summary>     public class FileOpenedEventArgs : EventArgs     {       /// <summary>Constructor</summary>       public FileOpenedEventArgs(FileOpenInfo openInfo, bool success)       {         this.OpenInfo = openInfo;         this.Success = success;       }       /// <summary>Extra info about the opened file</summary>       public FileOpenInfo OpenInfo { get; private set; }       /// <summary>Whether the file was opened successfully</summary>       public bool Success { get; private set; }     }     /// <summary>Delegate for FileOpened event</summary>     public delegate void FileOpenedEventHandler(object sender, FileOpenedEventArgs fe);     /// <summary>FileOpened event, fired when it finished loading a scene</summary>     public event FileOpenedEventHandler FileOpenedEvent;     #endregion     #region FileClosingEvent     /// <summary>Event arguments for FileClosing event</summary>     public class FileClosingEventArgs : EventArgs     {       /// <summary>Constructor</summary>       public FileClosingEventArgs(string filename)       {         this.Filename = filename;       }       /// <summary>Name of the file to be closed</summary>       public string Filename { get; private set; }     }     /// <summary>Delegate for FileClosing event</summary>     public delegate void FileClosingEventHandler(object sender, FileClosingEventArgs fe);     /// <summary>FileOpened event, fired when it starts unloading a scene</summary>     public event FileClosingEventHandler FileClosingEvent;     #endregion     #region FileClosedEvent     /// <summary>Event arguments for FileClosed event</summary>     public class FileClosedEventArgs : EventArgs     {     }     /// <summary>Delegate for FileClosed event</summary>     public delegate void FileClosedEventHandler(object sender, FileClosedEventArgs fe);     /// <summary>FileClosed event, fired when it finished unloading a scene</summary>     public event FileClosedEventHandler FileClosedEvent;     #endregion     #region FileProgressEvent     /// <summary>Event arguments for FileProgress event</summary>     public class FileProgressEventArgs : EventArgs     {       /// <summary>Constructor</summary>       public FileProgressEventArgs(float percent)       {         this.Percent = percent;       }       /// <summary>The current percentage of the loading process</summary>       public float Percent { get; private set; }     }     /// <summary>Delegate for FileProgress event</summary>     public delegate void FileProgressEventHandler(object sender, FileProgressEventArgs fe);     /// <summary>FileProgress event, fired many times during the loading process of a file</summary>     public event FileProgressEventHandler FileProgressEvent;     #endregion     #region FileExportEvent     /// <summary>Event arguments for FileExport event</summary>     public class FileExportEventArgs : EventArgs     {       /// <summary>Constructor</summary>       public FileExportEventArgs(string filename)       {         this.Filename = filename;       }       /// <summary>Name of the target file to be exported to</summary>       public string Filename { get; private set; }     }     /// <summary>Delegate for FileExport event</summary>     public delegate void FileExportEventHandler(object sender, FileExportEventArgs fe);     /// <summary>FileExport event, fired when an export is started</summary>     public event FileExportEventHandler FileExportEvent;     #endregion     #region FileExportedEvent     /// <summary>Event arguments for FileExported event</summary>     public class FileExportedEventArgs : EventArgs     {       /// <summary>Constructor</summary>       public FileExportedEventArgs(WebSupergoo.ExportSceneResult exportResult, bool success)       {         SceneHandle = exportResult.sceneHandle;         if(exportResult.exportData != null && exportResult.exportDataSize > 0) {           ExportData = new byte[exportResult.exportDataSize];           Marshal.Copy(exportResult.exportData, ExportData, 0, (int)exportResult.exportDataSize);         }         UserData = exportResult.userData;         Success = success;       }       /// <summary>Handle of scene that was exported (just for reference)</summary>       public uint SceneHandle { get; private set; }       /// <summary>The export data (if exportFilename is not set, it will use exportData and exportDataSize to write the data to)</summary>       public byte[] ExportData { get; private set; }       /// <summary>The user data that was passed in</summary>       public IntPtr UserData { get; private set; }       /// <summary>Whether the scene was successfully exported</summary>       public bool Success { get; private set; }     }     /// <summary>Delegate for FileExported event</summary>     public delegate void FileExportedEventHandler(object sender, FileExportedEventArgs fe);     /// <summary>FileExported event, fired when an export has finished</summary>     public event FileExportedEventHandler FileExportedEvent;     #endregion     #region LightingSchemeChangedEvent     /// <summary>Event arguments for LightingSchemeChanged event</summary>     public class LightingSchemeChangedEventArgs : EventArgs     {       /// <summary>Constructor</summary>       public LightingSchemeChangedEventArgs(WebSupergoo.ELightingScheme newScheme)       {         this.LightingScheme = newScheme;       }       /// <summary>The lighting scheme in use now</summary>       public WebSupergoo.ELightingScheme LightingScheme { get; private set; }     }     /// <summary>Delegate for LightingSchemeChanged event</summary>     public delegate void LightingSchemeChangedEventHandler(object sender, LightingSchemeChangedEventArgs fe);     /// <summary>LightingSchemeChanged event, fired when a lighting scheme has changed</summary>     public event LightingSchemeChangedEventHandler LightingSchemeChangedEvent;     #endregion     #region ContentSelectEvent     /// <summary>Event arguments for ContentSelect3DStream event</summary>     public class ContentSelect3DStreamEventArgs : EventArgs     {       /// <summary>Constructor</summary>       public ContentSelect3DStreamEventArgs(List<PdfUtilities.StreamInfo> available3DStreams)       {         this.Content = available3DStreams;       }       /// <summary>The available 3D content (D3DStreams)</summary>       public List<PdfUtilities.StreamInfo> Content { get; private set; }     }     /// <summary>Delegate for ContentSelect3DStream event</summary>     public delegate int ContentSelect3DStreamEventHandler(object sender, ContentSelect3DStreamEventArgs ce);     /// <summary>ContentSelectEvent event, fired when trying to open a scene with more than one 3DStream available</summary>     public event ContentSelect3DStreamEventHandler Select3DStreamEvent;     #endregion     #region CameraSelectEvent     /// <summary>Event arguments for CameraSelectEvent event</summary>     public class CameraSelectEventArgs : EventArgs     {       /// <summary>Constructor</summary>       public CameraSelectEventArgs(List<PdfUtilities.ViewInfo> available3DViews)       {         this.Views = available3DViews;       }       /// <summary>The available 3D view info</summary>       public List<PdfUtilities.ViewInfo> Views { get; private set; }     }     /// <summary>Delegate for CameraSelect event</summary>     public delegate int CameraSelectEventHandler(object sender, CameraSelectEventArgs ce);     /// <summary>CameraSelect event, fired when it starts loading a scene which has more than one view info available</summary>     public event CameraSelectEventHandler SelectCameraEvent;     #endregion     #endregion     #region Properties     #region DependencyProperties     /// <summary>DependencyProperty for the lighting scheme</summary>     public static readonly DependencyProperty LightingSchemeProperty =                 DependencyProperty.Register("LightingScheme",                                              typeof(WebSupergoo.ELightingScheme),                                              typeof(Render3DControl),                                              new FrameworkPropertyMetadata(WebSupergoo.ELightingScheme.LightingScheme_CAD,                                                                             FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,                                                                             OnLightingSchemePropertyChanged));     /// <summary>DependencyProperty for the antialiasing mode</summary>     public static readonly DependencyProperty AntiAliasingProperty =                 DependencyProperty.Register("AntiAliasing",                                              typeof(UInt32),                                              typeof(Render3DControl),                                              new FrameworkPropertyMetadata((UInt32)0,                                                                             FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,                                                                             OnAntiAliasingPropertyChanged));     /// <summary>DependencyProperty for the anisotropic filtering mode</summary>     public static readonly DependencyProperty AnisotropyProperty =                 DependencyProperty.Register("AnisotropicFiltering",                                              typeof(UInt32),                                              typeof(Render3DControl),                                              new FrameworkPropertyMetadata((UInt32)0,                                                                             FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,                                                                             OnAnisotropyPropertyChanged));     /// <summary>DependencyProperty for the scene filename</summary>     public static readonly DependencyProperty SceneFilenameProperty =                 DependencyProperty.Register("SceneFilename",                                              typeof(string),                                              typeof(Render3DControl),                                              new FrameworkPropertyMetadata(string.Empty,                                                                             FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,                                                                             OnSceneFilenamePropertyChanged));     /// <summary>DependencyProperty for the loading image</summary>     public static readonly DependencyProperty LoadingImageProperty =                 DependencyProperty.Register("LoadingImage",                                              typeof(ImageSource),                                              typeof(Render3DControl),                                              new FrameworkPropertyMetadata(null,                                                                             FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,                                                                             OnLoadingImagePropertyChanged));     /// <summary>DependencyProperty for the background color</summary>     public static readonly DependencyProperty BackgroundColorProperty =                 DependencyProperty.Register("BackgroundColor",                                              typeof(System.Windows.Media.Color),                                              typeof(Render3DControl),                                              new FrameworkPropertyMetadata(System.Windows.Media.Color.FromRgb(0, 0, 0),                                                                             FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,                                                                             OnBackgroundColorPropertyChanged));     /// <summary>DependencyProperty for whether to show the world axis</summary>     public static readonly DependencyProperty ShowWorldAxisProperty =                 DependencyProperty.Register("ShowWorldAxis",                                              typeof(bool),                                              typeof(Render3DControl),                                              new FrameworkPropertyMetadata(false,                                                                             FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,                                                                             OnShowWorldAxisPropertyChanged));     /// <summary>DependencyProperty for whether to show the world grid</summary>     public static readonly DependencyProperty ShowWorldGridProperty =                 DependencyProperty.Register("ShowWorldGrid",                                              typeof(bool),                                              typeof(Render3DControl),                                              new FrameworkPropertyMetadata(false,                                                                             FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,                                                                             OnShowWorldGridPropertyChanged));     /// <summary>DependencyProperty for whether to show the scene enclosing bounding box</summary>     public static readonly DependencyProperty ShowSceneBBoxProperty =                 DependencyProperty.Register("ShowSceneBBox",                                              typeof(bool),                                              typeof(Render3DControl),                                              new FrameworkPropertyMetadata(false,                                                                             FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,                                                                             OnShowSceneBBoxPropertyChanged));     /// <summary>DependencyProperty for whether to show individual model bounding boxes</summary>     public static readonly DependencyProperty ShowModelBBoxesProperty =                 DependencyProperty.Register("ShowModelBBoxes",                                              typeof(bool),                                              typeof(Render3DControl),                                              new FrameworkPropertyMetadata(false,                                                                             FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,                                                                             OnShowModelBBoxesPropertyChanged));     #endregion     /// <summary>Sets the lighting scheme</summary>     [Description("Sets the lighting scheme"),     Category("3D Settings")]     public WebSupergoo.ELightingScheme LightingScheme     {       get { return (WebSupergoo.ELightingScheme)GetValue(LightingSchemeProperty); }       set { SetValue(LightingSchemeProperty, value); }     }     /// <summary>Sets the antialiasing mode for the frame buffoer object (FBO) that is being rendered to (packed UInt32)</summary>     [Description("Sets the antialiasing mode for the FBO that is being rendered to (packed UInt32)"),     Category("3D Settings")]     public UInt32 AntiAliasing     {       get { return (UInt32)GetValue(AntiAliasingProperty); }       set { SetValue(AntiAliasingProperty, value); }     }     /// <summary>Sets the anisotropic filtering mode</summary>     [Description("Sets the anisotropic filtering for the scene"),     Category("3D Settings")]     public UInt32 AnisotropicFiltering     {       get { return (UInt32)GetValue(AnisotropyProperty); }       set { SetValue(AnisotropyProperty, value); }     }     /// <summary>Sets the scene filename (to load a new scene, if empty will unload the current scene)</summary>     [Description("Sets the scene to be loaded, or empty to unload a scene"),     Category("3D Settings")]     public string SceneFilename     {       get { return (string)GetValue(SceneFilenameProperty); }       set { SetValue(SceneFilenameProperty, value); }     }     /// <summary>Sets the image to be displayed while un/loading scenes</summary>     [Description("Sets the image to be displayed while un/loading scenes"),     Category("3D Settings")]     public ImageSource LoadingImage     {       get { return (ImageSource)GetValue(LoadingImageProperty); }       set { SetValue(LoadingImageProperty, value); }     }     /// <summary>Sets the background color of a scene</summary>     [Description("Sets the background color to be applied to a scene"), Category("3D Settings")]     public System.Windows.Media.Color BackgroundColor     {       get { return (System.Windows.Media.Color)GetValue(BackgroundColorProperty); }       set { SetValue(BackgroundColorProperty, value); }     }     /// <summary>Sets the visibility of the world axis</summary>     [Description("Sets Visibility of World Axis"), Category("3D Settings")]     public bool ShowWorldAxis     {       get { return (bool)GetValue(ShowWorldAxisProperty); }       set { SetValue(ShowWorldAxisProperty, value); }     }     /// <summary>Sets the visibility of the world grid</summary>     [Description("Sets Visibility of World Grid"), Category("3D Settings")]     public bool ShowWorldGrid     {       get { return (bool)GetValue(ShowWorldGridProperty); }       set { SetValue(ShowWorldGridProperty, value); }     }     /// <summary>Sets the visibility of the scene enclosing bounding box</summary>     [Description("Sets Visibility of Scene Bounding Box"), Category("3D Settings")]     public bool ShowSceneBBox     {       get { return (bool)GetValue(ShowSceneBBoxProperty); }       set { SetValue(ShowSceneBBoxProperty, value); }     }     /// <summary>Sets the visibility of bounding boxes for the individual models</summary>     [Description("Sets Visibility of individual model Bounding Boxes"), Category("3D Settings")]     public bool ShowModelBBoxes     {       get { return (bool)GetValue(ShowModelBBoxesProperty); }       set { SetValue(ShowModelBBoxesProperty, value); }     }     #endregion     #region StaticConstructor     /// <summary>Static constructor to override the control metadata</summary>     static Render3DControl()     {       DefaultStyleKeyProperty.OverrideMetadata(typeof(Render3DControl), new FrameworkPropertyMetadata(typeof(Render3DControl)));     }     #endregion     #region ControlRelated     /// <summary>Override the OnApplyTemplage of the Control base class, to set up various values and handlers</summary>     public override void OnApplyTemplate()     {       if (DesignerProperties.GetIsInDesignMode(this))         m_isInDesignMode = true;       m_borderElement = GetTemplateChild("RenderHostBorder") as Border;       this.AllowDrop = true;       this.Drop += new DragEventHandler(Render3DControl_Drop);       this.Loaded += new RoutedEventHandler(OnControlLoaded);       base.OnApplyTemplate();     }     /// <summary>Handle file drop events</summary>     void Render3DControl_Drop(object sender, DragEventArgs e)     {       if (e.Data.GetDataPresent(DataFormats.FileDrop))       {         string[] filenames = e.Data.GetData(DataFormats.FileDrop, true) as string[];         // debug         for (int i = 0; i < filenames.Length; ++i)           Log.Info("Dropped file into render control: " + filenames[i]);         // only open first one         if (filenames.Length > 0)         {           string ext = System.IO.Path.GetExtension(filenames[0]).ToLower();           SceneFilename = filenames[0];         }       }     }     /// <summary>Helper function to create a placeholder image object</summary>     private void CreatePlaceholderImageObject()     {       if (m_placeholderImage == null)       {         m_placeholderImage = new System.Windows.Controls.Image();         m_placeholderImage.Width = m_borderElement.ActualWidth;         m_placeholderImage.Height = m_borderElement.ActualHeight;       }     }     /// <summary>Handle the Loaded event of the control</summary>     private void OnControlLoaded(object sender, RoutedEventArgs e)     {       // set up border element       m_borderElement.Background = System.Windows.Media.Brushes.Black;       m_borderElement.BorderBrush = System.Windows.Media.Brushes.Yellow;       // prepare placeholder image       CreatePlaceholderImageObject();       // in design mode set a background image       if (m_isInDesignMode)       {         m_borderElement.Child = m_placeholderImage;         LoadScene(SceneFilename);       }       // otherwise load the real view       else       {         m_renderHost = new Render3DHost(m_borderElement.ActualWidth, m_borderElement.ActualHeight);         if (m_renderHost != null)         {           m_borderElement.Child = m_renderHost;           m_renderProxy = m_renderHost.RenderProxy;           // get properties                               HasCSAASupport = (m_renderHost.ProxyFlags & (UInt32)WebSupergoo.ERenderProxyFlags.RenderProxyFlags_SupportsCSAA) != 0;           AntiAliasing = ((UInt32)m_renderHost.AntialiasingCoverageSamples << 16) | (UInt32)m_renderHost.AntialiasingColorSamples;           if (m_renderHost.AvailableAAModes != null && m_renderHost.AvailableAAModes.Length > 0)           {             AvailableAntiAliasingModes = new UInt32[m_renderHost.AvailableAAModes.Length];             Array.Copy(m_renderHost.AvailableAAModes, AvailableAntiAliasingModes, m_renderHost.AvailableAAModes.Length);           }           AnisotropicFiltering = m_renderHost.Anisotropy;           if (m_renderHost.AnisotropyModes != null && m_renderHost.AnisotropyModes.Length > 0)           {             AvialableAnisotropyModes = new UInt32[m_renderHost.AnisotropyModes.Length];             Array.Copy(m_renderHost.AnisotropyModes, AvialableAnisotropyModes, m_renderHost.AnisotropyModes.Length);           }           m_versionInfo = Renderer.GetVersionInfo(m_renderProxy);           // apply properties           SetBackgroundColor(BackgroundColor);           // load scene           LoadScene(SceneFilename);           // fire event           RenderProxyReadyEventArgs proxyArgs = new RenderProxyReadyEventArgs(m_renderHost.ProxyName);           RenderProxyReadyEvent(this, proxyArgs);         }       }     }     #endregion     #region PropertyChangedCallbacks     /// <summary>Callback when the lighting scheme changed</summary>     private static void OnLightingSchemePropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)     {       Render3DControl r3DControl = source as Render3DControl;       WebSupergoo.ELightingScheme lightScheme = (WebSupergoo.ELightingScheme)e.NewValue;       r3DControl.SetLightingScheme(lightScheme);     }     /// <summary>Callback when the antialiasing mode changed</summary>     private static void OnAntiAliasingPropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)     {       Render3DControl r3DControl = source as Render3DControl;       UInt32 packedAAMode = (UInt32)e.NewValue;       r3DControl.SetAntialiasingMode(packedAAMode);     }     /// <summary>Callback when the anisotropic filtering mode changed</summary>     private static void OnAnisotropyPropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)     {       Render3DControl r3DControl = source as Render3DControl;       UInt32 anisotropy = (UInt32)e.NewValue;       r3DControl.SetAnisotropicFiltering(anisotropy);     }     /// <summary>Callback when the scene filename property changed, to trigger un/loading a scene</summary>     private static void OnSceneFilenamePropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)     {       Render3DControl r3DControl = source as Render3DControl;       string newFilename = (string)e.NewValue;       r3DControl.LoadScene(newFilename);     }     /// <summary>Callback when the loading image changed</summary>     private static void OnLoadingImagePropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)     {       Render3DControl r3DControl = source as Render3DControl;       r3DControl.m_placeholderImageSource = (ImageSource)e.NewValue;     }     /// <summary>Callback when the background color changed</summary>     private static void OnBackgroundColorPropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)     {       Render3DControl r3DControl = source as Render3DControl;       r3DControl.SetBackgroundColor((System.Windows.Media.Color)e.NewValue);     }     /// <summary>Callback when the show world axis property changed</summary>     private static void OnShowWorldAxisPropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)     {       Render3DControl r3DControl = source as Render3DControl;       r3DControl.SetShowWorldAxis((bool)e.NewValue);     }     /// <summary>Callback when the show world grid property changed</summary>     private static void OnShowWorldGridPropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)     {       Render3DControl r3DControl = source as Render3DControl;       r3DControl.SetShowWorldGrid((bool)e.NewValue);     }     /// <summary>Callback when the property for showing the scene enclosing bounding box changed</summary>     private static void OnShowSceneBBoxPropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)     {       Render3DControl r3DControl = source as Render3DControl;       r3DControl.SetShowSceneBoundingBox((bool)e.NewValue);     }     /// <summary>Callback when the property for showing individual model bounding boxes changed</summary>     private static void OnShowModelBBoxesPropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)     {       Render3DControl r3DControl = source as Render3DControl;       r3DControl.SetShowModelBoundingBoxes((bool)e.NewValue);     }     #endregion     #region SceneRelated     /// <summary>Helper function to create scene flags from currently set properties</summary>     private UInt32 GetSceneFlagsFromProperties()     {       UInt32 outFlags = 0;       if (ShowWorldAxis)         outFlags |= (UInt32)WebSupergoo.EViewFlags.ViewParams_ShowAxis;       if (ShowWorldGrid)         outFlags |= (UInt32)WebSupergoo.EViewFlags.ViewParams_ShowGrid;       if (ShowSceneBBox)         outFlags |= (UInt32)WebSupergoo.EViewFlags.ViewParams_ShowSceneBBox;       if (ShowModelBBoxes)         outFlags |= (UInt32)WebSupergoo.EViewFlags.ViewParams_ShowModelBBoxes;       if (LoadViewFilesOnSceneOpen)         outFlags |= (UInt32)WebSupergoo.EViewFlags.ViewParams_LoadViewFiles | (UInt32)WebSupergoo.EViewFlags.ViewParams_ViewFilesOverride;       return outFlags;     }     /// <summary>Helper function to load a scene (depending on whether we are in design mode or not)</summary>     private void LoadScene(string newSceneFilename)     {       if (m_isInDesignMode)         LoadScenePlaceholder(newSceneFilename);       else         LoadSceneFromFile(newSceneFilename);     }     /// <summary>Implement loading a scene from file, and potentially unloading previously loaded scenes</summary>     private void LoadSceneFromFile(string newSceneFilename)     {       if (m_renderProxy != IntPtr.Zero)       {         if (newSceneFilename == null || newSceneFilename.Length == 0)         {           FileClosingEventArgs closeArgs = new FileClosingEventArgs(m_currentSceneFilename);           FileClosingEvent(this, closeArgs);           m_unloadCompleteDelegate = new WebSupergoo.DelegateUnloadComplete((sceneHandle) =>           {             // reset name             m_currentSceneFilename = null;             m_currentSceneHandle = 0;             FileClosedEventArgs closeArgs0 = new FileClosedEventArgs();             Application.Current.Dispatcher.Invoke(new Action<FileClosedEventArgs>((fe) => {               // fire event               FileClosedEvent(this, fe);             }), new object[] { closeArgs0 });             m_unloadCompleteDelegate = null;           });           Dll_Glue3D.CloseScene(m_renderProxy, m_unloadCompleteDelegate);         } else         {           if (File.Exists(newSceneFilename))           {             // check if we have to close first             if (m_currentSceneFilename != null && m_currentSceneFilename.Length > 0)             {               // just fire off the closing/closed events, and reset name, as it will be handled internally in dll anyway               FileClosingEventArgs closingArgs = new FileClosingEventArgs(m_currentSceneFilename);               FileClosingEvent(this, closingArgs);               FileClosedEventArgs closedArgs = new FileClosedEventArgs();               FileClosedEvent(this, closedArgs);               m_currentSceneFilename = string.Empty;             }             FileOpeningEventArgs openArgs = new FileOpeningEventArgs(newSceneFilename);             FileOpeningEvent(this, openArgs);             // put placeholder image meanwhile             m_placeholderImage.Source = m_placeholderImageSource;             m_borderElement.Child = m_placeholderImage;             // our delegate for when loading is completed             m_loadCompleteDelegate = new WebSupergoo.DelegateLoadComplete((loadResult, success) => {               // get result structure, if available               WebSupergoo.LoadSceneResult castedResult = new WebSupergoo.LoadSceneResult();               if(loadResult != IntPtr.Zero)                 castedResult = (WebSupergoo.LoadSceneResult)Marshal.PtrToStructure(loadResult, typeof(WebSupergoo.LoadSceneResult));               WebSupergoo.ActiveCameraInfo castedCamInfo = new WebSupergoo.ActiveCameraInfo();               if(castedResult.activeCameraInfo != IntPtr.Zero)                 castedCamInfo = (WebSupergoo.ActiveCameraInfo)Marshal.PtrToStructure(castedResult.activeCameraInfo, typeof(WebSupergoo.ActiveCameraInfo));               // store name and handle               m_currentSceneFilename = Dll_Glue3D.StringFromDll(castedResult.sceneFilename, castedResult.sceneFilenameLen);               m_currentSceneHandle = castedResult.sceneHandle;               // create FileOpenInfo               FileOpenInfo openInfo = new FileOpenInfo();               openInfo.originalFilename = m_currentSceneFilename;               openInfo.sceneHandle = castedResult.sceneHandle;               openInfo.lightingScheme = (WebSupergoo.ELightingScheme)castedResult.lightingScheme;               openInfo.availableCameras = Dll_Glue3D.StringArrayFromDll(castedResult.availableCameras,                 castedResult.availableCameraLens, castedResult.availableCameraCount);               openInfo.activeCameraInfo = new CameraInfo();               if(castedResult.activeCameraInfo != IntPtr.Zero) {                 openInfo.activeCameraInfo.cameraName = Dll_Glue3D.StringFromDll(castedCamInfo.cameraName, castedCamInfo.cameraNameLen);                 openInfo.activeCameraInfo.cameraMode = (WebSupergoo.ECameraMode)castedCamInfo.cameraMode;                 openInfo.activeCameraInfo.isModifiable = castedCamInfo.isModifiable != 0;                 openInfo.activeCameraInfo.isOrtho = castedCamInfo.isOrtho != 0;               }               FileOpenedEventArgs openArgs0 = new FileOpenedEventArgs(openInfo, success);               Application.Current.Dispatcher.Invoke(new Action<FileOpenedEventArgs>((fe) => {                 // set render host as child again                 m_borderElement.Child = m_renderHost;                 // fire event                 FileOpenedEvent(this, fe);               }), new object[] { openArgs0 });               m_loadCompleteDelegate = null;               m_loadProgressDelegate = null;             });             // delegate for progress updates             m_loadProgressDelegate = new WebSupergoo.DelegateLoadProgress(OnLoadSceneProgress);             string ext = System.IO.Path.GetExtension(newSceneFilename).ToLower();             bool isPDF = (ext == ".pdf");             PdfUtilities.ExtractionResult extRes;             PdfUtilities.StreamInfo selectedStream = null;             if (isPDF)             {               if (PdfUtilities.ExtractAll3DData(newSceneFilename, out extRes) && extRes.Streams.Count > 0 && Select3DStreamEvent != null)               {                 ContentSelect3DStreamEventArgs selectArgs = new ContentSelect3DStreamEventArgs(extRes.Streams);                 int userSelection = Select3DStreamEvent(this, selectArgs);                 if (userSelection >= 0 && userSelection < extRes.Streams.Count)                 {                   selectedStream = extRes.Streams[userSelection];                 }               }             }             GCHandle streamHandle = new GCHandle(), viewsHandle = new GCHandle();             GCHandle[] handles = null;             try             {               // set up loading parameters               WebSupergoo.LoadSceneParams loadParams = new WebSupergoo.LoadSceneParams();               if (isPDF && selectedStream != null && selectedStream.Stream != null)               {                 loadParams.flags = (UInt32)WebSupergoo.ELoadParamFlags.LoadParam_Input_RawData;                 byte[] streamData = selectedStream.Stream;                 streamHandle = SafeUtils.GCHandle_Alloc(streamData, GCHandleType.Pinned);                 loadParams.sceneData = SafeUtils.GCHandle_AddrOfPinnedObject(ref streamHandle);                 loadParams.sceneDataSize = (uint)streamData.Length;                 // add all the view infos                 if (selectedStream.Views.Count > 0)                 {                   // select default view                   int camSelection = 0;                   if (selectedStream.Views.Count > 1 && SelectCameraEvent != null)                   {                     CameraSelectEventArgs selectArgs = new CameraSelectEventArgs(selectedStream.Views);                     camSelection = SelectCameraEvent(this, selectArgs);                     if (camSelection < 0 || camSelection >= selectedStream.Views.Count)                       camSelection = 0;                   }                   loadParams.viewData.defaultViewIndex = (UInt32)camSelection;                   loadParams.viewData.flags = (UInt32)WebSupergoo.ELoadViewFlags.LoadView_StringData;                   Utilities.PinViews(selectedStream.Views, out handles);                   IntPtr[] viewInfos = new IntPtr[handles.Length];                   viewsHandle = SafeUtils.GCHandle_Alloc(viewInfos, GCHandleType.Pinned);                   loadParams.viewData.viewInfos = SafeUtils.GCHandle_AddrOfPinnedObject(ref viewsHandle);                   loadParams.viewData.viewInfoCount = viewInfos.Length;                   for (int i = 0; i < handles.Length; ++i)                   {                     viewInfos[i] = SafeUtils.GCHandle_AddrOfPinnedObject(ref handles[i]);                   }                 }               }               else               {                 loadParams.flags = (UInt32)WebSupergoo.ELoadParamFlags.LoadParam_Input_Filename;                 loadParams.sceneFilename = newSceneFilename;               }               loadParams.progressCallback = m_loadProgressDelegate;               WebSupergoo.ViewParams viewParams = new WebSupergoo.ViewParams();               viewParams.flags = GetSceneFlagsFromProperties();               viewParams.backgroundColor = Utilities.Color2Int(BackgroundColor);               viewParams.lightingScheme = (UInt32)LightingScheme;               Dll_Glue3D.LoadScene(m_renderProxy, loadParams, viewParams, m_loadCompleteDelegate);             }             finally             {               if (streamHandle.IsAllocated)                 SafeUtils.GCHandle_Free(ref streamHandle);               if (viewsHandle.IsAllocated)                 SafeUtils.GCHandle_Free(ref viewsHandle);               if (handles != null)               {                 for (int i = 0; i < handles.Length; ++i)                 {                   if (handles[i].IsAllocated)                     SafeUtils.GCHandle_Free(ref handles[i]);                 }               }             }           }         }       }     }     /// <summary>Handler for LoadProgress events</summary>     private void OnLoadSceneProgress(WebSupergoo.ProgressInfo progress)     {       Application.Current.Dispatcher.Invoke((Action)delegate       {         // fire event         FileProgressEventArgs evArg = new FileProgressEventArgs(progress.currentProgress);         FileProgressEvent(this, evArg);       });     }     /// <summary>Helper function to load a scene placeholder in design mode</summary>     private void LoadScenePlaceholder(string newSceneFilename)     {       if (m_placeholderImage != null)       {         if (newSceneFilename == null || newSceneFilename.Length == 0 || !File.Exists(newSceneFilename))         {           m_placeholderImage.Source = null;         } else         {           // add placeholder           //m_placeholderImage.Source = Utilities.GetImageSourceFromResource("Glue3DUtilities", "placeholder.png");           m_placeholderImage.Source = m_placeholderImageSource;           // load real one if possible           WebSupergoo.CaptureParams parms = new WebSupergoo.CaptureParams();           //parms.loadParams = new WebSupergoo.LoadSceneParams();           parms.loadParams.flags = (UInt32)WebSupergoo.ELoadParamFlags.LoadParam_Input_Filename;           parms.loadParams.sceneHandle = 0;           parms.loadParams.sceneFilename = newSceneFilename;           parms.viewParams.flags = GetSceneFlagsFromProperties();           parms.viewParams.cameraName = string.Empty;           parms.viewParams.backgroundColor = Utilities.Color2Int(BackgroundColor);           parms.flags = (UInt32)WebSupergoo.ECaptureFlags.Capture_To_Memory | (UInt32)WebSupergoo.ECaptureFlags.Capture_UnloadAfterCapture;           parms.captureFilename = string.Empty;           parms.width = Convert.ToUInt32(m_placeholderImage.Width);           parms.height = Convert.ToUInt32(m_placeholderImage.Height);           OnCaptureFinished onCaptureFinished = new OnCaptureFinished(this);           SceneCapture.DoCapture(ref parms, new SceneCapture.DlgCaptureFinished(onCaptureFinished.CaptureFinished));         }       }     }     private sealed class OnCaptureFinished {       private Render3DControl _control;       private uint _flags;       private string _captureFilename;       private byte[] _pixelData;       private int _width, _height;       public OnCaptureFinished(Render3DControl control) {         _control = control;       }       public Action<bool> CaptureFinished(WebSupergoo.CaptureResult captureResult, bool captureSuccess) {         // not in main thread         if(captureSuccess) {           _flags = captureResult.flags;           if((_flags & (UInt32)WebSupergoo.ECaptureResultFlags.CaptureResult_CaptureFile_Set) != 0) {             _captureFilename = Dll_Glue3D.StringFromDll(captureResult.captureFilename, captureResult.captureFilenameLen);           } else if((_flags & (UInt32)WebSupergoo.ECaptureResultFlags.CaptureResult_CaptureMemory_Set) != 0) {             // create byte array from data             _pixelData = new byte[captureResult.dataSize];             Marshal.Copy(captureResult.data, _pixelData, 0, (int)captureResult.dataSize);             _width = (int)captureResult.width;             _height = (int)captureResult.height;           }         }         return Invoke;       }       public void Invoke(bool captureSuccess) {         // in main thread         // cannot access pointers in WebSupergoo.CaptureResult         if(captureSuccess) {           if((_flags & (UInt32)WebSupergoo.ECaptureResultFlags.CaptureResult_CaptureFile_Set) != 0) {             BitmapImage src = new BitmapImage();             src.BeginInit();             src.UriSource = new Uri(_captureFilename);             src.CacheOption = BitmapCacheOption.OnLoad;             src.EndInit();             _control.m_placeholderImage.Source = src;           } else if((_flags & (UInt32)WebSupergoo.ECaptureResultFlags.CaptureResult_CaptureMemory_Set) != 0) {             // create image             BitmapSource bmpSource = BitmapSource.Create(_width, _height,               96.0, 96.0, PixelFormats.Bgra32, null, _pixelData, _width*4);             // set it             _control.m_placeholderImage.Source = bmpSource;           }         } else {           _control.m_placeholderImage.Source = null;         }       }     }     /// <summary>Helper function to set the antialiasing mode on the renderer</summary>     private void SetAntialiasingMode(UInt32 packedAAMode)     {       if (m_renderProxy != IntPtr.Zero)         Dll_Glue3D.SetProperty_Int32(m_renderProxy, WebSupergoo.EProperty.Prop_Renderer_FBOAntialiasingMode, (Int32)packedAAMode);     }     /// <summary>Helper to get the antialiasing mode from the renderer</summary>     private UInt32 GetAntialiasingMode()     {       UInt32 packedAAMode = 0;       if (m_renderProxy != IntPtr.Zero)       {         packedAAMode = (UInt32)Dll_Glue3D.GetProperty_Int32(m_renderProxy, WebSupergoo.EProperty.Prop_Renderer_FBOAntialiasingMode);       }       return packedAAMode;     }     /// <summary>Helper to set the anisotropic filtering on the renderer</summary>     private void SetAnisotropicFiltering(UInt32 anisotropy)     {       if (m_renderProxy != IntPtr.Zero)         Dll_Glue3D.SetProperty_Int32(m_renderProxy, WebSupergoo.EProperty.Prop_Renderer_AnisotropicFiltering, (Int32)anisotropy);     }     /// <summary>Helper function to get the anisotropic filtering mode from the renderer</summary>     private UInt32 GetAnisotropicFiltering()     {       UInt32 anistropy = 0;       if (m_renderProxy != IntPtr.Zero)         anistropy = (UInt32)Dll_Glue3D.GetProperty_Int32(m_renderProxy, WebSupergoo.EProperty.Prop_Renderer_AnisotropicFiltering);       return anistropy;     }     /// <summary>Helper to set the lighting scheme on the renderer</summary>     private void SetLightingScheme(WebSupergoo.ELightingScheme lightScheme)     {       if (m_renderProxy != IntPtr.Zero)       {         Dll_Glue3D.SetProperty_Int32(m_renderProxy, WebSupergoo.EProperty.Prop_Renderer_LightingScheme, (Int32)lightScheme);         // fire event         LightingSchemeChangedEventArgs evArg = new LightingSchemeChangedEventArgs(lightScheme);         LightingSchemeChangedEvent(this, evArg);       }     }     /// <summary>Helper to get the lighting scheme from the renderer</summary>     private WebSupergoo.ELightingScheme GetLightingScheme()     {       if (m_renderProxy != IntPtr.Zero)         return (WebSupergoo.ELightingScheme)Dll_Glue3D.GetProperty_Int32(m_renderProxy, WebSupergoo.EProperty.Prop_Renderer_LightingScheme);       else         return WebSupergoo.ELightingScheme.LightingScheme_None;     }     /// <summary>Helper to set the background color on the renderer</summary>     private void SetBackgroundColor(System.Windows.Media.Color bgColor)     {       if (m_renderProxy != IntPtr.Zero)       {         Int32 col = (Int32)Utilities.Color2Int(bgColor);         Dll_Glue3D.SetProperty_Int32(m_renderProxy, WebSupergoo.EProperty.Prop_Renderer_BackgroundColor, col);       }     }     /// <summary>Helper to get the background color from the renderer</summary>     private System.Windows.Media.Color GetBackgroundColor()     {       System.Windows.Media.Color bgCol = new System.Windows.Media.Color();       if (m_renderProxy != IntPtr.Zero)       {         Int32 col = Dll_Glue3D.GetProperty_Int32(m_renderProxy, WebSupergoo.EProperty.Prop_Renderer_BackgroundColor);         bgCol = Utilities.UInt2Color((UInt32)col);       }       return bgCol;     }     /// <summary>Helper to set the visibility of the world axis</summary>     private void SetShowWorldAxis(bool newValue)     {       if (m_renderProxy != IntPtr.Zero)         Dll_Glue3D.SetProperty_Bool(m_renderProxy, WebSupergoo.EProperty.Prop_Scene_ShowAxis, newValue);     }     /// <summary>Helper to get the visibility of the world axis</summary>     private bool GetShowWorldAxis()     {       if (m_renderProxy != IntPtr.Zero)         return Dll_Glue3D.GetProperty_Bool(m_renderProxy, WebSupergoo.EProperty.Prop_Scene_ShowAxis);       return false;     }     /// <summary>Helper to set the visibility of the world grid</summary>     private void SetShowWorldGrid(bool newValue)     {       if (m_renderProxy != IntPtr.Zero)         Dll_Glue3D.SetProperty_Bool(m_renderProxy, WebSupergoo.EProperty.Prop_Scene_ShowGrid, newValue);     }     /// <summary>Helper to get the visibility of the world grid</summary>     private bool GetShowWorldGrid()     {       if (m_renderProxy != IntPtr.Zero)         return Dll_Glue3D.GetProperty_Bool(m_renderProxy, WebSupergoo.EProperty.Prop_Scene_ShowGrid);       return false;     }     /// <summary>Helper to set the visibility of the scene enclosing bounding box</summary>     private void SetShowSceneBoundingBox(bool newValue)     {       if (m_renderProxy != IntPtr.Zero)         Dll_Glue3D.SetProperty_Bool(m_renderProxy, WebSupergoo.EProperty.Prop_Scene_ShowBoundingBox, newValue);     }     /// <summary>Helper to get the visibility of the scene enclosing bounding box</summary>     private bool GetShowSceneBoundingBox()     {       if (m_renderProxy != IntPtr.Zero)         return Dll_Glue3D.GetProperty_Bool(m_renderProxy, WebSupergoo.EProperty.Prop_Scene_ShowBoundingBox);       return false;     }     /// <summary>Helper to set the visibility of the model boundinx boxes</summary>     private void SetShowModelBoundingBoxes(bool newValue)     {       if (m_renderProxy != IntPtr.Zero)         Dll_Glue3D.SetProperty_Bool(m_renderProxy, WebSupergoo.EProperty.Prop_Model_ShowBoundingBoxes, newValue);     }     /// <summary>Helper to get the visibility of the model bounding boxes</summary>     private bool GetShowModelBoundingBoxes()     {       if (m_renderProxy != IntPtr.Zero)         return Dll_Glue3D.GetProperty_Bool(m_renderProxy, WebSupergoo.EProperty.Prop_Model_ShowBoundingBoxes);       return false;     }     #endregion     #region Camera     /// <summary>Helper to get the list of available cameras, to be sent to the provided delegate</summary>     public void GetAvailableCameras(DelegateCameraListReceived camListReceivedCB)     {       if (m_renderProxy != IntPtr.Zero && m_currentCamListDelegate == null)       {         m_currentCamListDelegate = new WebSupergoo.DelegateStrList((field, camNames, camLens, camNameCount) =>         {           string[] list = Dll_Glue3D.StringArrayFromDll(camNames, camLens, camNameCount);           Application.Current.Dispatcher.Invoke(new DelegateCameraListReceived((resultNames) =>           {             if (camListReceivedCB != null)               camListReceivedCB(resultNames);             m_currentCamListDelegate = null;           }), new object[] { list });         });         Dll_Glue3D.GetAvailableCameras(m_renderProxy, m_currentCamListDelegate);       }     }     /// <summary>Helper to activate the specified camera</summary>     public void ActivateCamera(WebSupergoo.ECameraActivationType activationType, string cameraName, DelegateCameraChanged camChangedCB)     {       if (m_renderProxy != IntPtr.Zero && m_currentCamDelegate == null)       {         m_currentCamDelegate = new WebSupergoo.DelegateOnActiveCameraChanged((inCamInfo, inSuccess) =>         {           CameraInfo outputInfo = new CameraInfo();           if (inCamInfo != IntPtr.Zero)           {             WebSupergoo.ActiveCameraInfo castedResult = (WebSupergoo.ActiveCameraInfo)Marshal.PtrToStructure(inCamInfo, typeof(WebSupergoo.ActiveCameraInfo));             outputInfo.cameraName = Dll_Glue3D.StringFromDll(castedResult.cameraName, castedResult.cameraNameLen);             outputInfo.cameraMode = (WebSupergoo.ECameraMode)castedResult.cameraMode;             outputInfo.isModifiable = castedResult.isModifiable == 0 ? false : true;             outputInfo.isOrtho = castedResult.isOrtho == 0 ? false : true;           }           // dispatch to main thread           Application.Current.Dispatcher.Invoke(new DelegateCameraChanged((resultStruct, result) =>           {             if (camChangedCB != null)               camChangedCB(resultStruct, result);             m_currentCamDelegate = null;           }), new object[] { outputInfo, inSuccess });         });         Dll_Glue3D.ActivateCamera(m_renderProxy, activationType, cameraName, m_currentCamDelegate);       }     }     /// <summary>Helper to activate the first camera in the list of available cameras</summary>     public void ActivateFirstCamera(DelegateCameraChanged callback)     {       ActivateCamera(WebSupergoo.ECameraActivationType.ActivateCamera_First, string.Empty, callback);     }     /// <summary>Helper to activate the next camera in the list of available cameras</summary>     public void ActivateNextCamera(DelegateCameraChanged callback)     {       ActivateCamera(WebSupergoo.ECameraActivationType.ActivateCamera_Next, string.Empty, callback);     }     /// <summary>Helper to activate the camera designated as default camera</summary>     public void ActivateDefaultCamera(DelegateCameraChanged callback)     {       ActivateCamera(WebSupergoo.ECameraActivationType.ActivateCamera_Default, string.Empty, callback);     }     /// <summary>Helper to activate a camera by name</summary>     public void ActivateCamera(string cameraName, DelegateCameraChanged callback)     {       ActivateCamera(WebSupergoo.ECameraActivationType.ActivateCamera_ByName, cameraName, callback);     }     /// <summary>Helper to write a screenshot of the scene -as it is currently rendered- to the specified file</summary>     public void Screenshot(string filename)     {       Dll_Glue3D.Screenshot(m_renderProxy, filename);     }     /// <summary>Helper to load a view from the specified file (file has to be a text based file, containing PDF 3DView annotation info)</summary>     public void LoadViewFileForScene(string filename, DelegateCameraChanged callback)     {       if (m_renderProxy != IntPtr.Zero && m_currentCamDelegate == null)       {         m_currentCamDelegate = new WebSupergoo.DelegateOnActiveCameraChanged((inCamInfo, inSuccess) =>         {           CameraInfo outputInfo = new CameraInfo();           if (inCamInfo != IntPtr.Zero)           {             WebSupergoo.ActiveCameraInfo castedResult = (WebSupergoo.ActiveCameraInfo)Marshal.PtrToStructure(inCamInfo, typeof(WebSupergoo.ActiveCameraInfo));             outputInfo.cameraName = Dll_Glue3D.StringFromDll(castedResult.cameraName, castedResult.cameraNameLen);             outputInfo.cameraMode = (WebSupergoo.ECameraMode)castedResult.cameraMode;             outputInfo.isModifiable = castedResult.isModifiable == 0 ? false : true;             outputInfo.isOrtho = castedResult.isOrtho == 0 ? false : true;           }           // dispatch to main thread           Application.Current.Dispatcher.Invoke(new DelegateCameraChanged((resultStruct, result) =>           {             if (callback != null)               callback(resultStruct, result);             m_currentCamDelegate = null;           }), new object[] { outputInfo, inSuccess });         });         Dll_Glue3D.LoadViewInfoFromFile(m_renderProxy, filename, true, m_currentCamDelegate);       }     }     /// <summary>Helper to load a view from the specified PDF file (if available)</summary>     public void LoadViewFromPDF(string filename, DelegateCameraChanged callback)     {       if (m_renderProxy != IntPtr.Zero && m_currentCamDelegate == null)       {         string ext = System.IO.Path.GetExtension(filename).ToLower();         if (ext == ".pdf")         {           PdfUtilities.ExtractionResult extRes;           if (PdfUtilities.ExtractAll3DViews(filename, out extRes) && extRes.Streams.Count > 0 && extRes.ViewsProcessed > 0 && SelectCameraEvent != null)           {             // find the stream we want to use, if necessary, ask the user             PdfUtilities.StreamInfo useStream = null;             if (extRes.Streams.Count > 1 && Select3DStreamEvent != null)             {               ContentSelect3DStreamEventArgs selectStreamArgs = new ContentSelect3DStreamEventArgs(extRes.Streams);               int selectedStream = Select3DStreamEvent(this, selectStreamArgs);               if (selectedStream < 0 || selectedStream >= extRes.Streams.Count)                 return;               useStream = extRes.Streams[selectedStream];             }             else               useStream = extRes.Streams[0];             // safety             if (useStream == null)               return;             // find the views for that stream             CameraSelectEventArgs selectArgs = new CameraSelectEventArgs(useStream.Views);             int userSelection = SelectCameraEvent(this, selectArgs);             if (userSelection >= 0 && userSelection < useStream.Views.Count)             {               string viewInfo = useStream.Views[userSelection].View;               m_currentCamDelegate = new WebSupergoo.DelegateOnActiveCameraChanged((inCamInfo, inSuccess) =>               {                 CameraInfo outputInfo = new CameraInfo();                 if (inCamInfo != IntPtr.Zero)                 {                   WebSupergoo.ActiveCameraInfo castedResult = (WebSupergoo.ActiveCameraInfo)Marshal.PtrToStructure(inCamInfo, typeof(WebSupergoo.ActiveCameraInfo));                   outputInfo.cameraName = Dll_Glue3D.StringFromDll(castedResult.cameraName, castedResult.cameraNameLen);                   outputInfo.cameraMode = (WebSupergoo.ECameraMode)castedResult.cameraMode;                   outputInfo.isModifiable = castedResult.isModifiable == 0 ? false : true;                   outputInfo.isOrtho = castedResult.isOrtho == 0 ? false : true;                 }                 // dispatch to main thread                 Application.Current.Dispatcher.Invoke(new DelegateCameraChanged((resultStruct, result) =>                 {                   if (callback != null)                     callback(resultStruct, result);                   m_currentCamDelegate = null;                 }), new object[] { outputInfo, inSuccess });               });               Dll_Glue3D.LoadViewInfoFromString(m_renderProxy, viewInfo, true, m_currentCamDelegate);             }           }         }       }     }     #endregion     #region Export     /// <summary>Export a scene to PRC</summary>     public void ExportSceneToPRC(string targetFilename, string sourceFilename)     {       if (m_renderProxy != IntPtr.Zero)       {         // send event that we start exporting         FileExportEventArgs exportArgs = new FileExportEventArgs(targetFilename);         FileExportEvent(this, exportArgs);         // dispatch to main thread         m_exportCompleteDelegate = new WebSupergoo.DelegateExportComplete((exportResult, success) =>         {           // get result structure, if available           WebSupergoo.ExportSceneResult castedResult = new WebSupergoo.ExportSceneResult();           if(exportResult != IntPtr.Zero)             castedResult = (WebSupergoo.ExportSceneResult)Marshal.PtrToStructure(exportResult, typeof(WebSupergoo.ExportSceneResult));           FileExportedEventArgs exportArgs0 = new FileExportedEventArgs(castedResult, success);           Application.Current.Dispatcher.Invoke(new Action<FileExportedEventArgs>((fe) => {             // testing write to file from received buffer data             if(fe.ExportData!=null) {               string targetFile = m_currentSceneFilename + ".prc";               File.WriteAllBytes(targetFile, fe.ExportData);             }             // fire event             FileExportedEvent(this, fe);           }), new object[] { exportArgs0 });           m_exportCompleteDelegate = null;         });         // trigger export         bool testWriteToMemory = false;         WebSupergoo.ExportSceneParams exportParams = new WebSupergoo.ExportSceneParams();         if( sourceFilename.Length == 0 )         {           exportParams.loadParams.flags = (UInt32)WebSupergoo.ELoadParamFlags.LoadParam_Input_SceneHandle;           exportParams.loadParams.sceneHandle = m_currentSceneHandle;         }         else         {           exportParams.loadParams.flags = (UInt32)WebSupergoo.ELoadParamFlags.LoadParam_Input_Filename;           exportParams.loadParams.sceneFilename = sourceFilename;         }         exportParams.loadParams.userData = IntPtr.Zero;         exportParams.exportFlags = (UInt32)(WebSupergoo.EExportFlags.ExportFormat_PRC | WebSupergoo.EExportFlags.ExportTexturesJPEG);         if( !testWriteToMemory )           exportParams.exportFilename = targetFilename;         Dll_Glue3D.ExportScene(m_renderProxy, exportParams, m_exportCompleteDelegate);       }     }     #endregion   } }