using Amphora; using Annulus; using Azimuth; using Blacklight.Core; using Blacklight.Core.Cameras; using Blacklight.Core.Drawables; using Glass.Blacklight; using System; using Prism; namespace Glass.Testbed.TestCases.Layout { /// /// A nameplate pinned to the Arrow in the game scene. /// public class WorldAnchorTestCase : TestCase { private static readonly Vector ArrowHome = new Vector(120, -70); private const double ArrowOrbitRadius = 60; private const double ArrowOrbitSecondsPerTurn = 9; private readonly World world; private Arrow arrow; private EntityHandle arrowHandle; private WorldAnchoredPanel arrowNameplate; private TextMaterial anchorReadoutMaterial; private double arrowOrbitPhase; public WorldAnchorTestCase(World world) { this.world = world; } protected override void Populate() { arrow = new Arrow(5, 2) { InsideColor = new Color(0.5, 0.5, 0), ShellColor = new Color(0.75, 0.75, 0), ShellModelSpaceThickness = 0, ShellPixelThickness = 3, }; arrowHandle = world.cel.AddEntity(arrow, new AffineMatrix(0, ArrowHome)); AddCaption("The nameplate tracks the world.arrow as the world.arrow orbits"); AddCaption("Drag to pan and wheel to zoom"); // Use a Panel rather than a Label, since the text changes every frame. anchorReadoutMaterial = Widgets.Caption("anchor: measuring..."); Panel anchorReadout = anchorReadoutMaterial.BuildControl(Constraints.Unbounded); anchorReadout.Bounds = ContentAggregator.NewRow(anchorReadout.Bounds.Height); Add(anchorReadout); Material nameplateMaterial = UiPacksheetMaterials.YellowPanel; var nameplateLabel = new Label(Widgets.ButtonLabelStyle, "world.arrow", Constraints.Unbounded); Vector nameplateSize = nameplateMaterial.BoundsSizeFor(nameplateLabel.Bounds.Size); arrowNameplate = new WorldAnchoredPanel( point => world.camera.WorldToWorldOf(world.uiWorld.camera).TransformPoint(point)) { DebugName = "world.arrow nameplate", Material = nameplateMaterial, Bounds = Rect.FromPositionAndSize(Vector.Zero, nameplateSize), WorldPosition = ArrowHome, OffsetFromAnchor = new Vector(-nameplateSize.X / 2, -nameplateSize.Y - 14), }; nameplateLabel.FillParent(arrowNameplate); Add(arrowNameplate); } /// /// Walks the arrow around its home position so the nameplate has something to track without the user /// having to drag the camera. /// public override void Update(Duration elapsed) { arrowOrbitPhase += elapsed.TotalSeconds / ArrowOrbitSecondsPerTurn * 2 * Math.PI; Amphora.PortableMath.SinCosOfRadians(arrowOrbitPhase, out double sin, out double cos); Vector position = ArrowHome + new Vector(cos * ArrowOrbitRadius, sin * ArrowOrbitRadius); var entity = new Entity(arrow, new AffineMatrix(arrowOrbitPhase, position)); world.cel.ReplaceEntity(arrowHandle, ref entity); arrowNameplate.WorldPosition = position; Vector glassPosition = world.camera.WorldToWorldOf(world.uiWorld.camera).TransformPoint(position); anchorReadoutMaterial.Text = $"anchor: world ({position.X:F0}, {position.Y:F0})" + $" -> glass ({glassPosition.X:F0}, {glassPosition.Y:F0})"; } } }