// ===========================================================================
// ©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.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
using Glue3DUtilities;
namespace Viewer3D
{
/// <summary>Interaction logic for MainWindow.xaml</summary>
public partial class MainWindow : Window
{
#region Members
private Application m_app;
private Window m_window;
private List<MenuItem> m_viewMenu = new List<MenuItem>();
private WebSupergoo.DelegateLogging m_loggingHook = null;
#endregion
/// <summary>MainWindow constructor</summary>
public MainWindow()
{
InitializeComponent();
}
/// <summary>Handler for window initialized event, to set up various event handlers and logging etc</summary>
private void Window_Initialized(object sender, EventArgs e)
{
// general
m_app = System.Windows.Application.Current;
m_window = m_app.MainWindow;
OpenGLRenderControl.RenderProxyReadyEvent += new Render3DControl.RenderProxyReadyEventHandler(OpenGLRenderControl_RenderProxyReadyEvent);
OpenGLRenderControl.FileOpeningEvent += new Render3DControl.FileOpeningEventHandler(OpenGLRenderControl_FileOpeningEvent);
OpenGLRenderControl.FileOpenedEvent += new Render3DControl.FileOpenedEventHandler(OpenGLRenderControl_FileOpenedEvent);
OpenGLRenderControl.FileClosingEvent += new Render3DControl.FileClosingEventHandler(OpenGLRenderControl_FileClosingEvent);
OpenGLRenderControl.FileClosedEvent += new Render3DControl.FileClosedEventHandler(OpenGLRenderControl_FileClosedEvent);
OpenGLRenderControl.FileProgressEvent += new Render3DControl.FileProgressEventHandler(OpenGLRenderControl_FileProgressEvent);
OpenGLRenderControl.FileExportEvent += new Render3DControl.FileExportEventHandler(OpenGLRenderControl_FileExportEvent);
OpenGLRenderControl.FileExportedEvent += new Render3DControl.FileExportedEventHandler(OpenGLRenderControl_FileExportedEvent);
OpenGLRenderControl.LightingSchemeChangedEvent += new Render3DControl.LightingSchemeChangedEventHandler(OpenGLRenderControl_LightingSchemeChangedEvent);
OpenGLRenderControl.Select3DStreamEvent += new Render3DControl.ContentSelect3DStreamEventHandler(OpenGLRenderControl_OnSelect3DStreamCallback);
OpenGLRenderControl.SelectCameraEvent += new Render3DControl.CameraSelectEventHandler(OpenGLRenderControl_OnCameraSelectCallback);
OpenGLRenderControl.LoadingImage = Utilities.GetImageSourceFromResource("Viewer3D", "Images/placeholder.png");
// logging test (demonstrate logging hook)
m_loggingHook = new WebSupergoo.DelegateLogging(LogMessageHook);
Log.SetLoggingHook(IntPtr.Zero, m_loggingHook);
Log.Info("MainWindow initialized..");
}
/// <summary>Handler for RenderProxyReady event, to retrieve various renderer settings and adjust the UI accordingly</summary>
void OpenGLRenderControl_RenderProxyReadyEvent(object sender, Render3DControl.RenderProxyReadyEventArgs fe)
{
Log.Info("OpenGLRenderControl_RenderProxyReadyEvent for '" + fe.Name + "'");
// write OpenGL version
Log.Message("Using OpenGL " + OpenGLRenderControl.VersionInfo.version_GL.major + "." + OpenGLRenderControl.VersionInfo.version_GL.minor +
", and GLSL " + OpenGLRenderControl.VersionInfo.version_GLSL.major + "." + OpenGLRenderControl.VersionInfo.version_GLSL.minor);
if (OpenGLRenderControl.AvailableAntiAliasingModes != null)
{
foreach (UInt32 currMode in OpenGLRenderControl.AvailableAntiAliasingModes)
{
UInt32 colSmpl = (currMode & 0x0000FFFF);
UInt32 covSmpl = (currMode & 0xFFFF0000) >> 16;
string modeName = colSmpl.ToString() + "xMSAA";
if (covSmpl > 1)
modeName += " + " + covSmpl.ToString() + "xCSAA";
//Log.Info("OpenGLRenderControl_RenderProxyReadyEvent with AA mode '" + modeName + "'");
MenuItem aaItem = new MenuItem();
aaItem.Header = modeName;
aaItem.IsCheckable = true;
Binding aaBinding = new Binding("AntiAliasing");
aaBinding.Source = OpenGLRenderControl;
aaBinding.Converter = new UInt32ToBooleanConverter();
aaBinding.ConverterParameter = (UInt32)currMode;
aaItem.SetBinding(MenuItem.IsCheckedProperty, aaBinding);
AntialiasingMenu.Items.Add(aaItem);
}
}
if (OpenGLRenderControl.AvialableAnisotropyModes != null)
{
foreach (UInt32 currMode in OpenGLRenderControl.AvialableAnisotropyModes)
{
string anisoName = currMode.ToString() + "x";
MenuItem anisoItem = new MenuItem();
anisoItem.Header = anisoName;
anisoItem.IsCheckable = true;
Binding aaBinding = new Binding("AnisotropicFiltering");
aaBinding.Source = OpenGLRenderControl;
aaBinding.Converter = new UInt32ToBooleanConverter();
aaBinding.ConverterParameter = (UInt32)currMode;
anisoItem.SetBinding(MenuItem.IsCheckedProperty, aaBinding);
AnisotropyMenu.Items.Add(anisoItem);
}
}
}
/// <summary>Example log message hook for custom logging (print to the window's status line)</summary>
void LogMessageHook(IntPtr userData, Int32 level, string msg)
{
App.Current.Dispatcher.Invoke((Action)delegate
{
if (Status_Info != null)
Status_Info.Text = msg;
});
}
/// <summary>Handler for the FileProgress event, to display the loading progress</summary>
void OpenGLRenderControl_FileProgressEvent(object sender, Render3DControl.FileProgressEventArgs fe)
{
if (fe.Percent < 100.0f)
Status_Info.Text = string.Format("Loading...{0:F1}%", fe.Percent);
else
Status_Info.Text = "Ready";
}
/// <summary>Handler for the FileOpening event, sent when it begins loading a file</summary>
void OpenGLRenderControl_FileOpeningEvent(object sender, Render3DControl.FileOpeningEventArgs fe)
{
MainMenu.IsEnabled = false;
}
/// <summary>Handler for FileOpened event, when it finished loading a file</summary>
void OpenGLRenderControl_FileOpenedEvent(object sender, Render3DControl.FileOpenedEventArgs fe)
{
MainMenu.IsEnabled = true;
if (fe.Success)
{
CameraChangedCallback(fe.OpenInfo.activeCameraInfo, true);
LightingSchemeChangedCallback(Utilities.LightingSchemeToString(fe.OpenInfo.lightingScheme), true);
CameraListReceivedCallback(fe.OpenInfo.availableCameras);
}
}
/// <summary>Handler for FileClosing event, when it starts unloading a file</summary>
void OpenGLRenderControl_FileClosingEvent(object sender, Render3DControl.FileClosingEventArgs fe)
{
MainMenu.IsEnabled = false;
foreach (MenuItem currItem in m_viewMenu)
ViewMenu.Items.Remove(currItem);
m_viewMenu.Clear();
}
/// <summary>Handler for FileClosed event, when it finished unloading a file</summary>
void OpenGLRenderControl_FileClosedEvent(object sender, Render3DControl.FileClosedEventArgs fe)
{
MainMenu.IsEnabled = true;
}
/// <summary>Handler for FileExport event, when it starts exporting a scene</summary>
void OpenGLRenderControl_FileExportEvent(object sender, Render3DControl.FileExportEventArgs fe)
{
MainMenu.IsEnabled = false;
}
/// <summary>Handle for FileExported event, when it finished exporting a scene</summary>
void OpenGLRenderControl_FileExportedEvent(object sender, Render3DControl.FileExportedEventArgs fe)
{
MainMenu.IsEnabled = true;
if( fe.Success )
{
Log.Info("File successfully exported to PRC.");
}
}
/// <summary>Handler for view menu items that have been clicked</summary>
void ViewItem_Click(object sender, RoutedEventArgs e)
{
MenuItem item = e.Source as MenuItem;
string itemText = item.Header as string;
OpenGLRenderControl.ActivateCamera(itemText, CameraChangedCallback);
}
/// <summary>Handler for receiving the list of available cameras</summary>
private void OnCameraNamesReceived(string[] camNames)
{
if (camNames != null)
{
for (UInt32 i = 0; i < camNames.Length; ++i)
Log.Info("Camera " + i + ": " + camNames[i]);
}
}
/// <summary>Handler for WindowClosing event</summary>
private void Window_Closing(object sender, EventArgs e)
{
Log.SetLoggingHook(IntPtr.Zero, null);
}
/// <summary>Handler for WindowClosed event</summary>
private void Window_Closed(object sender, EventArgs e)
{
Log.Info("Window_Closed");
}
/// <summary>Helper function to display a file dialog for opening a scene, and triggering the actual scene loading</summary>
private void OpenSceneWithFileDialog()
{
string filename = Utilities.Get3DFileDialogResult();
if (filename.Length > 0)
OpenGLRenderControl.SceneFilename = filename;
}
/// <summary>Helper function to display a file dialog for opening view files (text files containing PDF 3DView annotation info), and triggering the loading of the view file</summary>
private void LoadViewForScene()
{
string filename = Utilities.GetViewFileDialogResult();
if (filename.Length > 0)
OpenGLRenderControl.LoadViewFileForScene(filename, CameraChangedCallback);
}
private void LoadViewForSceneFromPDF()
{
string filename = Utilities.GetPDFFileDialogResult();
if (filename.Length > 0)
OpenGLRenderControl.LoadViewFromPDF(filename, CameraChangedCallback);
}
/// <summary>Helper function to close the currently open scene</summary>
private void CloseCurrentScene()
{
if (OpenGLRenderControl != null)
OpenGLRenderControl.SceneFilename = string.Empty;
}
/// <summary>Helper for exporting a scene to PRC</summary>
private void ExportSceneWithFileDialog()
{
string sourceFile = string.Empty;
if (OpenGLRenderControl.SceneFilename.Length == 0)
{
sourceFile = Utilities.Get3DFileDialogResult();
if (sourceFile == null || sourceFile.Length == 0)
return;
}
string filename = Utilities.GetSaveToPRCFileDialogResult();
if (filename.Length > 0)
{
OpenGLRenderControl.ExportSceneToPRC(filename, sourceFile);
}
}
/// <summary>Helper for extracting 3D Data from a PDF file</summary>
private void Extract3DDataFromPDF()
{
string sourceFile = Utilities.GetPDFFileDialogResult();
if (sourceFile != null)
{
if (PdfUtilities.ExtractAll3DDataToFiles(sourceFile))
{
Log.Info("Successfully extracted 3D data from '" + sourceFile + "'");
}
else
{
Log.Error("Failed to extract 3D data from '" + sourceFile + "'");
}
}
}
/// <summary>Handler for CameraChanged events</summary>
private void CameraChangedCallback(Render3DControl.CameraInfo camInfo, bool success)
{
if (success)
{
Status_CameraName.Text = camInfo.cameraName;
if (camInfo.cameraMode == WebSupergoo.ECameraMode.CameraMode_Target)
Status_CameraType.Text = "Target";
else if (camInfo.cameraMode == WebSupergoo.ECameraMode.CameraMode_Free)
Status_CameraType.Text = "Free";
else
Status_CameraType.Text = "Static";
Status_CameraOrtho.Text = camInfo.isOrtho ? "Ortho" : "";
AddNewCameraViewItem(camInfo.cameraName);
}
}
/// <summary>Handler for CameraListReceived events</summary>
private void CameraListReceivedCallback(string[] camNames)
{
foreach (string currCam in camNames)
{
AddNewCameraViewItem(currCam);
}
}
private void AddNewCameraViewItem(string cameraName)
{
// check for duplicates
foreach (MenuItem currItem in m_viewMenu)
{
string itemText = currItem.Header as string;
if (itemText == cameraName)
return;
}
// add new item
MenuItem viewItem = new MenuItem();
viewItem.Header = cameraName;
viewItem.Click += new RoutedEventHandler(ViewItem_Click);
ViewMenu.Items.Add(viewItem);
m_viewMenu.Add(viewItem);
}
/// <summary>Handler for Select3DStream events</summary>
private int OpenGLRenderControl_OnSelect3DStreamCallback(object sender, Render3DControl.ContentSelect3DStreamEventArgs ce)
{
if (ce.Content != null )
{
if (ce.Content.Count > 1) // more than one item available, let user choose
{
List<string> choices = new List<string>();
for (int i = 0; i < ce.Content.Count; ++i)
choices.Add(ce.Content[i].Path);
UserSelection selectWindow = new UserSelection("Select 3D Stream", choices);
selectWindow.ShowDialog();
return selectWindow.UserSelectionIndex;
}
else // only one item available anyway
return 0;
}
return -1;
}
/// <summary>Handler for SelectCamera events</summary>
private int OpenGLRenderControl_OnCameraSelectCallback(object sender, Render3DControl.CameraSelectEventArgs ce)
{
if (ce.Views != null)
{
if (ce.Views.Count > 1) // more than one item available, let user choose
{
List<string> choices = new List<string>();
for (int i = 0; i < ce.Views.Count; ++i)
choices.Add(ce.Views[i].Path);
UserSelection selectWindow = new UserSelection("Select 3D View", choices);
selectWindow.ShowDialog();
return selectWindow.UserSelectionIndex;
}
else // only one item available anyway
return 0;
}
return -1;
}
/// <summary>Handler for LightingSchemeChanged events</summary>
void OpenGLRenderControl_LightingSchemeChangedEvent(object sender, Render3DControl.LightingSchemeChangedEventArgs fe)
{
Status_LightScheme.Text = Utilities.LightingSchemeToString(fe.LightingScheme);
}
/// <summary>Callback for changed lighting schemes</summary>
private void LightingSchemeChangedCallback(string lightingSchemeName, bool success)
{
if (success)
{
Status_LightScheme.Text = lightingSchemeName;
}
}
/// <summary>Helper function to open the About window</summary>
private void OpenAboutWindow()
{
Renderer.GLVersionInfo v = OpenGLRenderControl.VersionInfo;
About aboutWindow = new About(v);
aboutWindow.ShowDialog();
}
/// <summary>Helper function to handle menu item clicks</summary>
private void MenuItem_Click(object sender, RoutedEventArgs e)
{
MenuItem item = e.Source as MenuItem;
switch (item.Name)
{
case "File_Open":
OpenSceneWithFileDialog();
break;
case "File_Close":
CloseCurrentScene();
break;
case "File_Export":
ExportSceneWithFileDialog();
break;
case "File_Extract":
Extract3DDataFromPDF();
break;
case "File_Quit":
Application.Current.Shutdown();
break;
case "View_NextCamera":
OpenGLRenderControl.ActivateNextCamera(CameraChangedCallback);
break;
case "View_FirstCamera":
OpenGLRenderControl.ActivateFirstCamera(CameraChangedCallback);
break;
case "View_DefaultCamera":
OpenGLRenderControl.ActivateDefaultCamera(CameraChangedCallback);
break;
case "View_Screenshot":
OpenGLRenderControl.Screenshot(string.Empty);
break;
case "View_LoadFromFile":
LoadViewForScene();
break;
case "View_LoadFromPDF":
LoadViewForSceneFromPDF();
break;
case "Help_About":
OpenAboutWindow();
break;
default:
Log.Error("MenuItem_Click: Invalid item name: " + item.Name);
break;
}
}
}
}