using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using Blacklight.Core; using Azimuth; using Blacklight.Core.Drawables; using Annulus; namespace Slipstream.Testbed { public partial class MainWindow : Form { public Slipstream.FluidWorld world; Blacklight.Core.Cameras.MicroscopeCamera camera; private long ms; public MainWindow() { InitializeComponent(); camera = new Blacklight.Core.Cameras.MicroscopeCamera(viewport.DrawableSurface); viewport.DrawableSurface.Invalidated += delegate(object sender, EventArgs e) { Draw(); }; GameThread = new System.Threading.Thread(delegate() { while (true) { if (world != null && (turnOnSingleStep || !pauseCheckbox.Checked)) { lock (locker) { var body = world.BoundaryBodies.First(); cycleCount+=1.0/60.0; Scalar period = 10; Scalar angularVelocity = (1.0 / period) * (2 * Math.PI); var newPos = new Vector(100 * Math.Cos(angularVelocity * cycleCount), 0); var velocity = new Vector(100 * angularVelocity * -Math.Sin(angularVelocity * cycleCount), 0); body.Position = newPos; body.LinearVelocity = velocity; //body.Orientation = cycleCount * angularVelocity * 2; //body.AngularVelocity = angularVelocity * 2; var startTime = System.Diagnostics.Stopwatch.StartNew(); world.IntegrateVortonMotion(1.0 / 60.0); world.EnforceBoundaryConditions(); world.IntegrateTracerParticles(1.0 / 60.0, out totalEnergyCount); ms = startTime.ElapsedMilliseconds; } } if (turnOnSingleStep) { pauseCheckbox.Checked = true; turnOnSingleStep = false; } System.Threading.Thread.Sleep(0); } }); GameThread.Start(); } private List vortonDrawables = new List(); private List particleDrawables = new List(); private List bodyDrawables = new List(); private System.Threading.Thread GameThread = null; private void Draw() { List vortonPositions; List vortonVorticity; List particlePositions; List boundaryBodySilhouettes; List boundaryBodyTransforms; List> boundaryBodyControlPoints; List> panelSourceStrengths; List> panelLengths; lock (locker) { vortonPositions = world.Vortons.Select(x => x.Position).ToList(); particlePositions = world.TracerParticles.Select(x => x.Position).ToList(); vortonVorticity = world.Vortons.Select(x => x.Vorticity).ToList(); boundaryBodySilhouettes = world.BoundaryBodies.Select(x => x.Silhouette).ToList(); boundaryBodyTransforms = world.BoundaryBodies.Select(x => new Matrix(x.Orientation, x.Position, 1)).ToList(); boundaryBodyControlPoints = world.BoundaryBodies.Select(x => x._group.PanelTransforms.ToList()).ToList(); panelSourceStrengths = world.BoundaryBodies.Select(x => (IList)x._group.SourceStrengths.ToList()).ToList(); panelLengths = world.BoundaryBodies.Select(x => x._group.PanelLengths.ToList()).ToList(); } Scene _scene = new Scene(); Cel _cel = new Cel(); _scene.Cels.Add(_cel); Scalar vortonCount = (Scalar)(world.Vortons.Count()); // Display panels { for (int i = 0; i < boundaryBodySilhouettes.Count; ++i) { var perimeter = boundaryBodySilhouettes[i].Edges.Sum(x => x.Direction.Length()); if (bodyDrawables.Count == i) { var collage = new Blacklight.Core.Drawables.Collage(); var silhouette = new Blacklight.Core.Drawables.Ellipse(); //.Polygon(boundaryBodySilhouettes[i]); silhouette.InsideColor = new Blacklight.Core.Color(0.5, 0.25, 0, 1); silhouette.ShellColor = new Blacklight.Core.Color(0, 0, 0, 1); silhouette.ShellPixelThickness = 0; silhouette.ShellModelSpaceThickness = 0.01; silhouette.Antialiased = true; silhouette.SmoothBorder = false; collage.AddDrawable(silhouette); for (int j = 0; j < panelSourceStrengths[i].Count; ++j) { var panel = new Blacklight.Core.Drawables.Rectangle { InsideColor = new Blacklight.Core.Color(0, 0, 0, 1), ShellColor = new Blacklight.Core.Color(0, 0, 0, 1), ShellPixelThickness = 0, ShellModelSpaceThickness = 0, Antialiased = true, SmoothBorder = false, }; collage.AddDrawable(panel); } bodyDrawables.Add(collage); } // Update the panel strengths Scalar drawPanels = displayPanels.Checked ? 1 : 0; { for (int j = 1; j < bodyDrawables[i].Drawables.Count; ++j) { var panel = bodyDrawables[i].GetDrawable(j); var primitive = (Blacklight.Core.Drawables.Rectangle)panel.Key; var strength = panelSourceStrengths[i][j - 1]; if (strength == 0) { primitive.InsideColor = new Blacklight.Core.Color(0, 1, 0, drawPanels); } else if (strength < 0) { primitive.InsideColor = new Blacklight.Core.Color(1, 1, 0, drawPanels); } else { primitive.InsideColor = new Blacklight.Core.Color(0, 1, 1, drawPanels); } var scale = Math.Sqrt(Math.Abs(strength / 1e2) + .001); bodyDrawables[i].SetTransformOnDrawable(j, boundaryBodyControlPoints[i][j - 1] * new Matrix(new Vector(panelLengths[i][j-1] / 2 * 0.95, 0), new Vector(0, scale), new Vector(0, 0)) ); } } var entity = new Entity { drawable = bodyDrawables[i], modelToWorld = boundaryBodyTransforms[i], }; _cel.AddEntity(entity); } } if (displayVortons.Checked == true) { for (int i = 0; i < vortonPositions.Count; ++i) { if (vortonDrawables.Count <= i) { var ellipse = new Blacklight.Core.Drawables.Ellipse { InsideColor = new Blacklight.Core.Color(0, 0, (i / vortonCount), 1), ShellColor = new Blacklight.Core.Color(0, 0, (i / vortonCount), 1), ShellPixelThickness = 0, ShellModelSpaceThickness = 0, Antialiased = true, SmoothBorder = false, }; vortonDrawables.Add(ellipse); } if (vortonVorticity[i] == 0) { vortonDrawables[i].InsideColor = new Blacklight.Core.Color(0, 1, 0, 1); } else if (vortonVorticity[i] < 0) { vortonDrawables[i].InsideColor = new Blacklight.Core.Color(1, 0, 0, 1); } else { vortonDrawables[i].InsideColor = new Blacklight.Core.Color(0, 0, 1, 1); } _cel.AddEntity(new Entity { drawable = vortonDrawables[i], modelToWorld = Matrix.BuildFromTranslation(vortonPositions[i]) * Matrix.BuildFromScale(Math.Sqrt(Math.Abs(vortonVorticity[i] / 5e3)) + .1), }); } } for (int i = 0; i < particlePositions.Count; ++i) { if (particleDrawables.Count <= i) { var ellipse = new Blacklight.Core.Drawables.Ellipse { InsideColor = new Blacklight.Core.Color(0, 0.84, 0.84, 1), ShellColor = new Blacklight.Core.Color(0, 0.25, 0.25, 1), ShellPixelThickness = 0, ShellModelSpaceThickness = 0.25, Antialiased = true, SmoothBorder = false, }; var collage = new Blacklight.Core.Drawables.Collage(); collage.AddDrawable(ellipse, Matrix.BuildFromTranslation(Vector.Zero) * Matrix.BuildFromScale(1)); //collage.AddDrawable(ellipse, Matrix.BuildFromTranslation(Vector.UnitX)); //collage.AddDrawable(ellipse, Matrix.BuildFromTranslation(-Vector.UnitX)); //collage.AddDrawable(ellipse, Matrix.BuildFromTranslation(Vector.UnitY)); //collage.AddDrawable(ellipse, Matrix.BuildFromTranslation(-Vector.UnitY)); particleDrawables.Add(collage); } _cel.AddEntity(new Entity { drawable = particleDrawables[i], modelToWorld = Matrix.BuildFromTranslation(particlePositions[i]), }); } viewport.DrawableSurface.FrameReset(); viewport.DrawableSurface.DrawScene(_scene, camera); viewport.DrawableSurface.SubmitDrawCalls(); } private System.Diagnostics.Stopwatch lastUpdate = null; private void GameLoopTimer_Tick(object sender, EventArgs e) { Draw(); if (lastUpdate == null) { lastUpdate = System.Diagnostics.Stopwatch.StartNew(); } if (lastUpdate.ElapsedMilliseconds >= 250) { lastUpdate = System.Diagnostics.Stopwatch.StartNew(); this.totalEnergy.Text = "Total Energy: " + totalEnergyCount.ToString("F3"); this.cyclesPerSec.Text = "Cycles/sec: " + (1000 / (Scalar)ms).ToString("F1"); } } private object locker = new object(); private Scalar totalEnergyCount = 0; private void MainWindow_FormClosing(object sender, FormClosingEventArgs e) { if (GameThread != null) { GameThread.Abort(); GameThread = null; } } Scalar cycleCount = 0; private void resetButton_Click(object sender, EventArgs e) { lock (locker) { Program.ResetWorld(world); cycleCount = 0; } } private static volatile bool turnOnSingleStep = false; private void singleStep_Click(object sender, EventArgs e) { lock (locker) { turnOnSingleStep = true; } } } }