RenderTests.cs 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. using Avalonia.Headless.XUnit;
  2. using Avalonia.Threading;
  3. using ChunkyImageLib;
  4. using ChunkyImageLib.DataHolders;
  5. using Drawie.Backend.Core;
  6. using Drawie.Backend.Core.Bridge;
  7. using Drawie.Backend.Core.ColorsImpl;
  8. using Drawie.Backend.Core.Numerics;
  9. using Drawie.Backend.Core.Surfaces;
  10. using Drawie.Numerics;
  11. using PixiEditor.ChangeableDocument.Rendering.ContextData;
  12. using PixiEditor.Models.IO;
  13. using PixiEditor.Models.Position;
  14. using Xunit.Abstractions;
  15. using Color = Drawie.Backend.Core.ColorsImpl.Color;
  16. namespace PixiEditor.Tests;
  17. public class RenderTests : FullPixiEditorTest
  18. {
  19. private readonly ITestOutputHelper _testOutputHelper;
  20. public RenderTests(ITestOutputHelper testOutputHelper)
  21. {
  22. _testOutputHelper = testOutputHelper;
  23. }
  24. [AvaloniaTheory]
  25. [InlineData("Fibi")]
  26. [InlineData("Pond")]
  27. [InlineData("SmlPxlCircShadWithMask")]
  28. [InlineData("SmallPixelArtCircleShadow")]
  29. [InlineData("SmlPxlCircShadWithMaskClipped")]
  30. [InlineData("SmlPxlCircShadWithMaskClippedInFolder")]
  31. [InlineData("VectorRectangleClippedToCircle")]
  32. [InlineData("VectorRectangleClippedToCircleShadowFilter")]
  33. [InlineData("VectorRectangleClippedToCircleMasked")]
  34. [InlineData("BlendingLinearSrgb")]
  35. [InlineData("BlendingSrgb")]
  36. [InlineData("VectorWithSepiaFilter")]
  37. [InlineData("VectorWithSepiaFilterSrgb")]
  38. [InlineData("VectorWithSepiaFilterChained")]
  39. [InlineData("Offset")]
  40. [InlineData("Scale")]
  41. [InlineData("Skew")]
  42. [InlineData("Rotation")]
  43. [InlineData("MatrixChain")]
  44. [InlineData("GpuOffset", "Offset")]
  45. [InlineData("GpuScale")]
  46. [InlineData("GpuSkew")]
  47. [InlineData("GpuMatrixChain")]
  48. public void TestThatPixiFilesRenderTheSameResultAsSavedPng(string fileName, string? resultName = null)
  49. {
  50. if (!DrawingBackendApi.Current.IsHardwareAccelerated)
  51. {
  52. _testOutputHelper.WriteLine("Skipping the test because hardware acceleration is not enabled.");
  53. return;
  54. }
  55. string pixiFile = Path.Combine("TestFiles", "RenderTests", fileName + ".pixi");
  56. string pngFile = Path.Combine("TestFiles", "RenderTests", (resultName ?? fileName) + ".png");
  57. var document = Importer.ImportDocument(pixiFile);
  58. Assert.NotNull(pngFile);
  59. var result = document.TryRenderWholeImage(0);
  60. Assert.True(result is { IsT1: true, AsT1: not null }); // Check if rendering was successful
  61. using var image = result.AsT1;
  62. using var snapshot = image.DrawingSurface.Snapshot();
  63. using var encoded = snapshot.Encode();
  64. using var renderedToCompare = Surface.Load(encoded.AsSpan().ToArray());
  65. using var toCompareTo = Importer.ImportImage(pngFile, document.SizeBindable);
  66. Assert.NotNull(toCompareTo);
  67. Assert.True(PixelCompare(renderedToCompare, toCompareTo));
  68. }
  69. [AvaloniaTheory]
  70. [InlineData("SingleLayer")]
  71. [InlineData("SingleLayerWithMask")]
  72. [InlineData("LayerWithMaskClipped")]
  73. [InlineData("LayerWithMaskClippedHighDpiPresent")]
  74. [InlineData("LayerWithMaskClippedInFolder")]
  75. [InlineData("LayerWithMaskClippedInFolderWithMask")]
  76. public void TestThatHalfResolutionScalesRenderCorrectly(string pixiName)
  77. {
  78. string pixiFile = Path.Combine("TestFiles", "ResolutionTests", pixiName + ".pixi");
  79. var document = Importer.ImportDocument(pixiFile);
  80. ViewportInfo info = new ViewportInfo(
  81. 0,
  82. document.SizeBindable / 2f,
  83. document.SizeBindable,
  84. new ViewportData(),
  85. new PointerInfo(),
  86. new KeyboardInfo(),
  87. new EditorData(),
  88. null, "DEFAULT", SamplingOptions.Default, document.SizeBindable, ChunkResolution.Half,
  89. Guid.NewGuid(), false, false, () => { });
  90. using var output = document.SceneRenderer.RenderScene(info, new AffectedArea());
  91. Color expectedColor = Colors.Yellow;
  92. using Surface surface = Surface.ForDisplay(document.SizeBindable);
  93. surface.DrawingSurface.Canvas.DrawSurface(output.DrawingSurface, 0, 0);
  94. Assert.True(AllPixelsAreColor(surface, expectedColor));
  95. }
  96. private static bool PixelCompare(Surface image, Surface compareTo)
  97. {
  98. if (image.Size != compareTo.Size)
  99. {
  100. return false;
  101. }
  102. using Surface compareSurface1 = new Surface(image.Size);
  103. using Surface compareSurface2 = new Surface(image.Size);
  104. compareSurface1.DrawingSurface.Canvas.DrawSurface(image.DrawingSurface, 0, 0);
  105. compareSurface2.DrawingSurface.Canvas.DrawSurface(compareTo.DrawingSurface, 0, 0);
  106. var imageData1 = compareSurface1.PeekPixels();
  107. var imageData2 = compareSurface2.PeekPixels();
  108. if (imageData1.Width != imageData2.Width || imageData1.Height != imageData2.Height)
  109. {
  110. return false;
  111. }
  112. for (int y = 0; y < imageData1.Height; y++)
  113. {
  114. for (int x = 0; x < imageData1.Width; x++)
  115. {
  116. var pixel1 = imageData1.GetPixelColor(x, y);
  117. var pixel2 = imageData2.GetPixelColor(x, y);
  118. if (pixel1 != pixel2)
  119. {
  120. return false;
  121. }
  122. }
  123. }
  124. return true;
  125. }
  126. private static bool AllPixelsAreColor(Surface image, Color color)
  127. {
  128. var imageData = image.PeekPixels();
  129. for (int y = 0; y < imageData.Height; y++)
  130. {
  131. for (int x = 0; x < imageData.Width; x++)
  132. {
  133. var pixel = imageData.GetPixelColor(x, y);
  134. if (pixel != color)
  135. {
  136. return false;
  137. }
  138. }
  139. }
  140. return true;
  141. }
  142. }