using Annulus; using Azimuth; using Blacklight.Core; using Blacklight.Core.Drawables; using System.Collections.Generic; using UnitTestSharp; using DrawingColor = System.Drawing.Color; namespace Glass.Blacklight.UnitTests { public class BlacklightRendererTests : TestFixture { public class CapturedEntities : EntityContainer.IVisitor { public readonly List> Rectangles = new List>(); void EntityContainer.IVisitor.Visit(in Entity entity) { if (entity.drawable is Rectangle rectangle) { Rectangles.Add(new Entity(rectangle, entity.modelToWorld)); } } } // Shared because the constructor reflects over every loaded assembly to build its dispatch table. private static readonly BlacklightRenderer Renderer = new BlacklightRenderer(); public static List> Draw(SolidColorMaterial material, Rect rect, DrawState drawState) { var cel = new Cel(); Renderer.Render(cel, material, rect, drawState); var captured = new CapturedEntities(); cel.ForEach(captured); return captured.Rectangles; } public static Rect Bounds => Rect.FromPositionAndSize(new Vector(7, 11), new Vector(3, 4)); public class RenderSolidColorMaterialTests : TestFixture { public void ColorBecomesTheFill() { var entities = Draw(new SolidColorMaterial { Color = DrawingColor.Red }, Bounds, new DrawState()); CheckEqual(1, entities.Count); CheckEqual(Colors.Red.ToArgb(), entities[0].drawable.InsideColor.ToArgb()); } public void NoColorFillsWhite() { var entities = Draw(new SolidColorMaterial(), Bounds, new DrawState()); CheckEqual(Colors.White.ToArgb(), entities[0].drawable.InsideColor.ToArgb()); } public void NoColorFallsBackToTheInheritedTint() { var entities = Draw( new SolidColorMaterial(), Bounds, new DrawState { TintColor = DrawingColor.Blue }); CheckEqual(Colors.Blue.ToArgb(), entities[0].drawable.InsideColor.ToArgb()); } public void ColorBeatsTheInheritedTint() { var entities = Draw( new SolidColorMaterial { Color = DrawingColor.Red }, Bounds, new DrawState { TintColor = DrawingColor.Blue }); CheckEqual(Colors.Red.ToArgb(), entities[0].drawable.InsideColor.ToArgb()); } public void AlphaSurvives() { var entities = Draw( new SolidColorMaterial { Color = DrawingColor.FromArgb(128, 0, 0, 0) }, Bounds, new DrawState()); CheckEqual(128, (int)entities[0].drawable.InsideColor.Alpha); } public void DrawsNoShell() { var entities = Draw(new SolidColorMaterial(), Bounds, new DrawState()); CheckEqual((Scalar)0, entities[0].drawable.ShellPixelThickness); CheckEqual((Scalar)0, entities[0].drawable.ShellModelSpaceThickness); } public void CornersLandOnTheRect() { var entities = Draw(new SolidColorMaterial(), Bounds, new DrawState()); AffineMatrix modelToWorld = entities[0].modelToWorld; CheckEqual(new Vector(7, 11), modelToWorld.TransformPoint(Rectangle.TopLeft)); CheckEqual(new Vector(10, 15), modelToWorld.TransformPoint(Rectangle.BottomRight)); } public void IncomingTransformIsComposedIn() { var entities = Draw(new SolidColorMaterial(), Bounds, new DrawState { ModelToWorld = AffineMatrix.BuildFromTranslation(new Vector(100, 200)), }); AffineMatrix modelToWorld = entities[0].modelToWorld; CheckEqual(new Vector(107, 211), modelToWorld.TransformPoint(Rectangle.TopLeft)); CheckEqual(new Vector(110, 215), modelToWorld.TransformPoint(Rectangle.BottomRight)); } public void ZeroWidthRect_DrawsNothing() { CheckEqual(0, Draw( new SolidColorMaterial(), Rect.FromPositionAndSize(new Vector(7, 11), new Vector(0, 4)), new DrawState()).Count); } public void ZeroHeightRect_DrawsNothing() { CheckEqual(0, Draw( new SolidColorMaterial(), Rect.FromPositionAndSize(new Vector(7, 11), new Vector(3, 0)), new DrawState()).Count); } public void NegativeSizedRectDrawsAsItsBoundingBox() { var entities = Draw(new SolidColorMaterial(), Rect.FromPositionAndSize(new Vector(10, 20), new Vector(-4, -6)), new DrawState()); AffineMatrix modelToWorld = entities[0].modelToWorld; CheckEqual(new Vector(6, 14), modelToWorld.TransformPoint(Rectangle.TopLeft)); CheckEqual(new Vector(10, 20), modelToWorld.TransformPoint(Rectangle.BottomRight)); } public void ClipWindowShrinksTheRectangle() { var entities = Draw(new SolidColorMaterial(), Rect.FromPositionAndSize(Vector.Zero, new Vector(10, 10)), new DrawState { ClipWindow = Rect.FromPositionAndSize(new Vector(5, 5), new Vector(10, 10)), }); AffineMatrix modelToWorld = entities[0].modelToWorld; CheckEqual(new Vector(5, 5), modelToWorld.TransformPoint(Rectangle.TopLeft)); CheckEqual(new Vector(10, 10), modelToWorld.TransformPoint(Rectangle.BottomRight)); } public void ClipWindowContainingTheRectLeavesItAlone() { var entities = Draw(new SolidColorMaterial(), Bounds, new DrawState { ClipWindow = Rect.FromPositionAndSize(Vector.Zero, new Vector(100, 100)), }); AffineMatrix modelToWorld = entities[0].modelToWorld; CheckEqual(new Vector(7, 11), modelToWorld.TransformPoint(Rectangle.TopLeft)); CheckEqual(new Vector(10, 15), modelToWorld.TransformPoint(Rectangle.BottomRight)); } public void ClipWindowMissingTheRectDrawsNothing() { var entities = Draw(new SolidColorMaterial(), Rect.FromPositionAndSize(Vector.Zero, new Vector(10, 10)), new DrawState { ClipWindow = Rect.FromPositionAndSize(new Vector(20, 20), new Vector(5, 5)), }); CheckEqual(0, entities.Count); } } } }