/// <summary> /// Called whenever a new environment has been received. /// </summary> /// <param name="ar">The results of the aysnchronous operation.</param> /// <remarks> /// Byte Array to Structure code taken from @cite stackOverflowByte (http://stackoverflow.com/questions/3278827/how-to-convert-structure-to-byte-array-in-c) /// </remarks> private void EnvironmentReceived(IAsyncResult ar) { var environment = new StatusReport(); var size = Marshal.SizeOf(environment); if (disposed) { return; } pipeServer.EndWaitForConnection(ar); var bytes = new List <byte>(); var buffer = new byte[size]; pipeServer.Read(buffer, 0, size); bytes.AddRange(buffer); var array = bytes.ToArray(); var ptr = Marshal.AllocHGlobal(size); Marshal.Copy(array, 0, ptr, size); lock (latestEnvironmentLocker) { var report = (StatusReport)Marshal.PtrToStructure(ptr, typeof(StatusReport)); latestEnvironment = report.Environment; CurrentVector = report.FieldVector; fieldType = report.FieldType; latestBallVelocity = report.BallVelocity; } if (!worker.IsBusy) { worker.RunWorkerAsync(); } Marshal.FreeHGlobal(ptr); pipeServer.Disconnect(); pipeServer.BeginWaitForConnection(EnvironmentReceived, null); }
/// <summary> /// Renders the image based on the <see cref="latestEnvironment"/>. /// </summary> /// <param name="sender">The sender.</param> /// <param name="doWorkEventArgs">The <see cref="System.ComponentModel.DoWorkEventArgs"/> instance containing the event data.</param> /// <remarks> /// Buffers <see cref="latestEnvironment"/> into <see cref="currentEnvironment"/> before rendering, to ensure new incoming /// data doesn't interfere, even if it comes in while still rendering. /// </remarks> private void RenderImage(object sender, DoWorkEventArgs doWorkEventArgs) { int type; // Buffer the environment data lock (latestEnvironmentLocker) { currentEnvironment = latestEnvironment; currentBallVelocity = latestBallVelocity; type = fieldType; } // Create the computation queue (this can't be saved and reused, not sure why) var queue = new ComputeCommandQueue(context, context.Devices[0], ComputeCommandQueueFlags.None); switch (type) { case 0: // Calculate the potential field ComputeField(queue, points); break; case 1: ComputeFinalApproachField(queue, points); break; case 2: ComputePosessionField(queue, points); break; } // Draw a picture of it var bitmap = RenderPoints(queue, points, outCl); // Calculate the field gradients ComputeGradient(queue, gradientPoints); // Draw a picture of them var bitmap2 = RenderPoints(queue, gradientPoints, outGradient); // Anonymous function which refreshes the images shown on the UI. Has to be called on the UI thread to allow access // to the UI controls. Action refresh = () => { using (var stream = new MemoryStream()) { bitmap.Save(stream, ImageFormat.Png); stream.Seek(0, SeekOrigin.Begin); var decoder = BitmapDecoder.Create(stream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad); var writeable = new WriteableBitmap(decoder.Frames.Single()); writeable.Freeze(); FieldImage.Source = writeable; } using (var stream = new MemoryStream()) { bitmap2.Save(stream, ImageFormat.Png); stream.Seek(0, SeekOrigin.Begin); var decoder = BitmapDecoder.Create(stream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad); var writeable = new WriteableBitmap(decoder.Frames.Single()); writeable.Freeze(); GradientImage.Source = writeable; } }; Dispatcher.Invoke(refresh); queue.Finish(); queue.Dispose(); }