/// <summary> /// Process a remote method invocation request from one display to another hosted on another surface. /// </summary> /// <param name="pDisplay">The display which called this api function.</param> /// <param name="pSurface">The surface which this display is hosted on.</param> /// <param name="sTargetSurface">The target surface which contains the display we want to call the function on.</param> /// <param name="sRemoteFunction">The name of the function on the active display on the target surface we want to call.</param> /// <param name="lArguments">A list of arguments to pass to that function.</param> /// <returns></returns> public static bool ProcessRMICall(Display pDisplay, Surface pSurface, String sTargetSurface, String sRemoteFunction, Awesomium.Core.JSValue[] lArguments) { // Check the display and surface are valid. if (pDisplay == null) throw new ArgumentNullException("Cannot process a display API request without a display."); if (pSurface == null) throw new ArgumentNullException("Cannot process a display API request without a surface."); // Check we have a valid request handler. if (sTargetSurface == null || sTargetSurface.Length == 0) { Log.Write("Cannot process a cross-surface RMI call without a target surface name.", pDisplay.ToString(), Log.Type.DisplayWarning); return false; } // Check for a valid remote function. if (sRemoteFunction == null || sRemoteFunction.Length == 0) { Log.Write("Cannot process a cross-surface RMI call without a target function name.", pDisplay.ToString(), Log.Type.DisplayWarning); return false; } // Attempt to find the target surface. var pTargetSurface = Authority.FindSurface(sTargetSurface); if (pTargetSurface == null) { Log.Write("Surface '"+sTargetSurface+"' not found. Cannot process a cross-surface RMI call without a valid target surface.", pDisplay.ToString(), Log.Type.DisplayWarning); return false; } // Check there is a display on the surface. if (pTargetSurface.ActiveDisplay != null) { // Insert the calling surface name into the first argument. var l = new List<Awesomium.Core.JSValue>(lArguments); l.Insert(0, pSurface.Identifier); // Call the function on it and pass the data. pTargetSurface.ActiveDisplay.AsyncCallGlobalFunction(sRemoteFunction, l.ToArray()); return true; } // Otherwise we didn't do it. Log.Write("Could not process a cross-surface RMI call because the target surface did not have an active display.", pDisplay.ToString(), Log.Type.DisplayWarning); return false; }
/// <summary> /// Delete a display. /// </summary> /// <param name="pDisplay">The display we want to delete.</param> public static void DeleteDisplay(Display pDisplay) { // Check we have good data. if (pDisplay == null) throw new ArgumentNullException("Cannot delete a null display."); if (pDisplay.IsDeleted()) throw new ArgumentNullException("Cannot delete a deleted display."); // Remove it from its surface, if attached. var pSurface = pDisplay.ActiveSurface; if (pSurface != null) { pSurface.Authority_DetachDisplay(pDisplay); } // Release any resources created for it. pDisplay.Authority_Delete(); // Remove it from the list of displays. Authority._ActiveDisplays.Remove(pDisplay); // Log the happening. That is a weird film btw. Log.Write("Display '"+pDisplay.ToString()+"' deleted.", AUTHORITY_LOG_SOURCE, Log.Type.DisplayInfo); }
/// <summary> /// Process a display request. For example the calling JS would look like: Authority.request(handlername, somedata). /// </summary> /// <param name="pDisplay">The display which called this api function.</param> /// <param name="pSurface">The surface which this display is hosted on.</param> /// <param name="sRequestHandler">The name of the request handler.</param> /// <param name="dArguments">The table of arguments which were given in the data parameter.</param> /// <returns>True if the request was sucessfully handled. False if not.</returns> public static bool ProcessRequest(Display pDisplay, Surface pSurface, String sRequestHandler, Awesomium.Core.JSObject dArguments) { // Check the display and surface are valid. if (pDisplay == null) throw new ArgumentNullException("Cannot process a display API request without a display."); if (pSurface == null) throw new ArgumentNullException("Cannot process a display API request without a surface."); // Check we have a valid request handler. if (sRequestHandler == null || sRequestHandler.Length == 0) { Log.Write("Cannot process a display API request without a handler name.", pDisplay.ToString(), Log.Type.DisplayWarning); return false; } // Make the request handler lower case. sRequestHandler = sRequestHandler.ToLower(); // Search the bound request handlers. DisplayAPI.IRequest pHandler = null; if (dRequestHandlers.TryGetValue(sRequestHandler, out pHandler)) { // If one is found, process the request and return the success condition. return pHandler.ProcessRequest(pDisplay, pSurface, dArguments); } // No handler for request. Log.Write("Authority could not find handler for request '" + sRequestHandler + "'.", pDisplay.ToString(), Log.Type.DisplayWarning); return false; }
/// <summary> /// Remove a display from its current surface. Use with care. /// </summary> /// <remarks>N.B You must call 'pDisplay.Delete()' when you are finished with it if you don't put it back on a surface.</remarks> /// <param name="pDisplay">The display we want to remove from its surface.</param> public static void RemoveDisplay(Display pDisplay) { // Check we have good data. if (pDisplay == null) throw new ArgumentNullException("Cannot remove a null display."); if (pDisplay.IsDeleted()) throw new ArgumentNullException("Cannot remove a deleted display."); // Remove the view from the current surface. var pOldSurface = pDisplay.ActiveSurface; if (pOldSurface != null) pDisplay.ActiveSurface.Authority_DetachDisplay(pDisplay); // Remove it from the list of displays. Authority._ActiveDisplays.Remove(pDisplay); // Write a log message. Log.Write("Display '"+pDisplay.ToString()+"' removed.", AUTHORITY_LOG_SOURCE, Log.Type.DisplayInfo); }
/// <summary> /// Move a display from one surface to another. /// </summary> /// <param name="pDisplay">The display we want to move.</param> /// <param name="pNewSurface">The surface we want to move it too.</param> public static void MoveDisplay(Display pDisplay, Surface pNewSurface) { // Check we have good data. if (pDisplay == null) throw new ArgumentNullException("Cannot move a null display."); if (pNewSurface == null) throw new ArgumentNullException("Cannot move display to a null surface."); if (pDisplay.IsDeleted()) throw new ArgumentNullException("Cannot move a deleted display."); if (pNewSurface.IsDeleted()) throw new ArgumentNullException("Cannot move display to a deleted surface."); // Drop if the new and old are the same. if (pDisplay.ActiveSurface == pNewSurface) return; // Check we can move to the new surface. if (pNewSurface.ActiveDisplay != null) throw new Exception("Cannot move a display to the new surface because it is currently occupied."); // Remove the view from the current surface. var pOldSurface = pDisplay.ActiveSurface; if (pOldSurface != null) pDisplay.ActiveSurface.Authority_DetachDisplay(pDisplay); // Attach it to the new one. pNewSurface.Authority_AttachDisplay(pDisplay); // Write a log message. Log.Write("Display moved from '" + pOldSurface.ToString()+ "' to '"+pNewSurface.ToString()+"'.", AUTHORITY_LOG_SOURCE, Log.Type.DisplayInfo); }
/// <summary> /// Show a display on a given surface. /// </summary> /// <remarks>This will throw exceptions if this is not possible. Ensure neither the display is already open or the surface is occupied.</remarks> /// <param name="pDisplay">The display to show.</param> /// <param name="pSurface">The surface to show it on.</param> public static void ShowDisplay(Display pDisplay, Surface pSurface) { // Check we have good data. if (pDisplay == null) throw new ArgumentNullException("Cannot show null display."); if (pSurface == null) throw new ArgumentNullException("Cannot show display on a null surface."); if (pDisplay.IsDeleted()) throw new ArgumentNullException("Cannot show a deleted display."); if (pSurface.IsDeleted()) throw new ArgumentNullException("Cannot show display on a deleted surface."); // Check neither the display or surface are occupied. if (pDisplay.ActiveSurface != null) throw new Exception("Cannot show this display because it is already active somewhere else."); if (pSurface.ActiveDisplay != null) throw new Exception("Cannot show a display on this surface because it is currently occupied."); // Attach it to the surface. pSurface.Authority_AttachDisplay(pDisplay); Authority._ActiveDisplays.Add(pDisplay); // Write a log message. Log.Write("Attached display '"+pDisplay.ToString()+"' to surface '"+pSurface.Identifier+"'", AUTHORITY_LOG_SOURCE, Log.Type.DisplayInfo); }
/// <summary> /// Attempt to load calibration data from a file. /// </summary> /// <param name="bCalibration">Do we want to load hardware and calibration settings.</param> /// <param name="bSurfaces">Do we want to load surface data.</param> /// <param name="bDisplays">Do we want to load displays.</param> /// <param name="sFile">The file we want to load the data from.</param> private void Load(bool bCalibration, bool bSurfaces, bool bDisplays, String sFile) { // Open the XML file and parse out the data we are interested in. var pDocument = XDocument.Load(sFile); #region Load Calibration Data if (bCalibration) { // Parse the surfaces from the file. var dCalibration = (from item in pDocument.Root.Elements("calibration") select new { MonitorDevice = item.Element("monitor").Value, KinectDevice = item.Element("kinect").Value, KinectImage = (from pt in item.Element("kinectimage").Elements("point") select PointFromString(pt.Value)).ToArray(), ProjectedImage = (from pt in item.Element("projectedimage").Elements("point") select PointFromString(pt.Value)).ToArray(), }).FirstOrDefault(); // Check we have calibration data. if (dCalibration != null) { #region Load Screen // If we already have a monitor selected. if (SelectedScreen != null) { // If the device names are the same, all is well. if (SelectedScreen.DeviceName != dCalibration.MonitorDevice) { // We have one selected already, log and bail. Log.Write("Screen already selected. Ignoring '" + dCalibration.MonitorDevice + "'.", "Application", Log.Type.AppWarning); } // See if we can complete step 1. TryCompleteStep1(false); } // If we don't have a montior selected. else { // Attempt to find a montor with a matching device name. var lAvailable = Utilities.MonitorDetection.QueryDisplays(); foreach (var pMonitor in lAvailable) { if (pMonitor.DeviceName == dCalibration.MonitorDevice) { SelectedScreen = pMonitor; TryCompleteStep1(false); break; } } // If we didn't manage to select a screen, make a note in the log. if (SelectedScreen == null) { Log.Write("Could not find screen that matches the one in the file. You will need to choose another one.", "Application", Log.Type.AppWarning); } } #endregion #region Load Kinect // If we already have a kinect selected. if (SelectedKinect != null) { // If the device names are the same, all is well. if (SelectedKinect.DeviceConnectionId != dCalibration.KinectDevice) { // We have one selected already, log and bail. Log.Write("Kinect already selected. Ignoring '" + dCalibration.KinectDevice + "'.", "Application", Log.Type.AppWarning); } // See if we can complete step 1. TryCompleteStep1(false); } // If we don't have a kinect selected. else { // Attempt to find a montor with a matching device name. var lAvailable = KinectSensor.KinectSensors; foreach (var pKinect in lAvailable) { if (pKinect.DeviceConnectionId == dCalibration.KinectDevice) { SelectedKinect = pKinect; TryCompleteStep1(false); break; } } // If we didn't manage to select a screen, make a note in the log. if (SelectedKinect == null) { Log.Write("Could not find kinect that matches the one in the file. You will need to choose another one.", "Application", Log.Type.AppWarning); } } #endregion #region Load Calibration Settings // If we are NOT calibrated but are ready to be used. if (bCalibrated == false && SelectedKinect != null && SelectedScreen != null) { Calibrate(dCalibration.ProjectedImage, dCalibration.KinectImage); } // If we ARE calibrated and are ready to be used. else if (bCalibrated == true && SelectedKinect != null && SelectedScreen != null) { // Do we want to overwrite the existing calibration. var hResult = MessageBox.Show("Do you want to overwrite current calibration with imported one?", "Ubi Displays", MessageBoxButton.YesNo, MessageBoxImage.Question); if (hResult == MessageBoxResult.Yes) { Calibrate(dCalibration.ProjectedImage, dCalibration.KinectImage); } } // Otherwise we are not ready! else { Log.Write("Cannot import calibration because hardware is not selected.", "Application", Log.Type.AppWarning); } #endregion } } #endregion // Only import these if we are calibrated. if (!bCalibrated && (bSurfaces || bDisplays)) { Log.Write("Cannot import surfaces and displays. Please calibrate and try again.", "Application", Log.Type.AppWarning); return; } #region Load Surfaces if (bSurfaces) { // Parse the surfaces from the file. var lSurfaces = from item in pDocument.Root.Elements("surface") select new { Identifier = item.Element("name").Value, InjectMT = (item.Element("inject_multitouch").Value.ToLower() == "true") ? true : false, Projector = (from pt in item.Element("projector").Elements("point") select PointFromString(pt.Value)).ToArray(), Sensor = (from pt in item.Element("sensorspace").Elements("point") select Vector3FromString(pt.Value)).ToArray(), KinectImage = (from pt in item.Element("image").Elements("point") select PointFromString(pt.Value)).ToArray(), }; // For each surface, register one with the authority. foreach (var dSurfaceData in lSurfaces) { // Check the surface name is good. if (dSurfaceData.Identifier == null || dSurfaceData.Identifier == "") { Log.Write("Cannot import surface. Surface is missing a name.", "Application", Log.Type.AppWarning); continue; } // If the name is already taken, bail. if (Authority.FindSurface(dSurfaceData.Identifier) != null) { Log.Write("Cannot import surface '" + dSurfaceData.Identifier + "'. Surface with the same name already exists.", "Application", Log.Type.AppWarning); continue; } // Check we have valid data. if ((dSurfaceData.Projector == null || dSurfaceData.Projector.Length != 4) || (dSurfaceData.Sensor == null || dSurfaceData.Sensor.Length != 4) || (dSurfaceData.KinectImage == null || dSurfaceData.KinectImage.Length != 4)) { Log.Write("Cannot import surface '" + dSurfaceData.Identifier + "'. It does not contain valid data.", "Application", Log.Type.AppWarning); continue; } // Create the surface. var pSurface = new Model.Surface(dSurfaceData.Identifier); pSurface.AttemptMultiTouchInject = dSurfaceData.InjectMT; pSurface.SetSpatialProperties(dSurfaceData.Projector, dSurfaceData.Sensor, dSurfaceData.KinectImage); Authority.RegisterSurface(pSurface); } } #endregion #region Load Displays if (bDisplays) { // For each display in the surface file, attach it to the surface. var lDisplays = from item in pDocument.Root.Elements("display") select new { SurfaceName = item.Element("surfacename").Value, LoadInstruction = item.Element("loadinstruction").Value, Resolution = PointFromString(item.Element("resolution").Value), }; // Create the displays. foreach (var dDisplayData in lDisplays) { // Find the surface to place it on. var pSurface = Authority.FindSurface(dDisplayData.SurfaceName); if (pSurface == null) { Log.Write("Cannot import display '" + dDisplayData.LoadInstruction + "'. Could not find host surface '" + dDisplayData.SurfaceName + "'.", "Application", Log.Type.AppWarning); continue; } // Create the display. var pDisplay = new Display(dDisplayData.LoadInstruction, dDisplayData.Resolution); // Disable debug mode on the surface. pSurface.ShowDebug = false; // Show the display. Authority.ShowDisplay(pDisplay, pSurface); } } #endregion }
/// <summary> /// Called to handle something being dropped on the image. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void HandleDisplay_Drop(object sender, DragEventArgs e) { // Not dragging anymore. bDraggingFile = false; // Bail if not a file. var sFile = "http://google.com"; if (e.Data.GetDataPresent(DataFormats.FileDrop)) { // Select the file to load. string[] tFilePaths = (string[])(e.Data.GetData(DataFormats.FileDrop)); if (tFilePaths.Length != 1) return; sFile = tFilePaths[0]; } else if (e.Data.GetDataPresent(DataFormats.StringFormat)) { sFile = e.Data.GetData(DataFormats.StringFormat) as String; if (sFile == null || (!sFile.StartsWith("http") && !sFile.StartsWith("file"))) return; } // Find which polygon we have dropped on. var pClick = e.GetPosition(_vidManage); // Check to see if our point is contained by any of our surfaces. UbiDisplays.Model.Surface pSurface = null; foreach (var s in Authority.Surfaces) { List<Point> lPoints = new List<Point>(); lPoints.Add(new Point(s.KinectSpace[0].X, s.KinectSpace[0].Y)); lPoints.Add(new Point(s.KinectSpace[1].X, s.KinectSpace[1].Y)); lPoints.Add(new Point(s.KinectSpace[2].X, s.KinectSpace[2].Y)); lPoints.Add(new Point(s.KinectSpace[3].X, s.KinectSpace[3].Y)); // If we have dropped it into this polygon. if (Utilities.Polygon.IsPointInPolygon(pClick.X, pClick.Y, lPoints)) { pSurface = s; break; } } // If we have missed all the surfaces. if (pSurface == null) return; // If there is already something on the surface, remove it. if (pSurface.ActiveDisplay != null) { Authority.DeleteDisplay(pSurface.ActiveDisplay); } // Create a new display. var pDisplay = new Display(sFile); Authority.ShowDisplay(pDisplay, pSurface); pSurface.ShowDebug = false; // Ensure debug mode is turned off. // TODO //pSurface.DebugMode = false; // Remove the polygons. foreach (var pPoly in lDragPolygons) _pzManage.Children.Remove(pPoly); lDragPolygons.Clear(); }