Browse Source

Implemented some sort of dirty rectangle finding for rotated viewports

Equbuxu 1 year ago
parent
commit
1d17239d5c

+ 2 - 0
src/PixiEditor.AvaloniaUI/Views/Main/ViewportControls/Viewport.axaml

@@ -122,8 +122,10 @@
                         Height="{Binding RealDimensions.Y, ElementName=vpUc}"
                         Height="{Binding RealDimensions.Y, ElementName=vpUc}"
                         Surface="{Binding TargetBitmap, ElementName=vpUc}"
                         Surface="{Binding TargetBitmap, ElementName=vpUc}"
                         Scale="{Binding Scale, ElementName=zoombox, Mode=OneWay}"
                         Scale="{Binding Scale, ElementName=zoombox, Mode=OneWay}"
+                        Dimensions="{Binding Dimensions, ElementName=zoombox, Mode=OneWay}"
                         Document="{Binding Document, ElementName=vpUc, Mode=OneWay}"
                         Document="{Binding Document, ElementName=vpUc, Mode=OneWay}"
                         ContentPosition="{Binding CanvasPos, ElementName=zoombox, Mode=OneWay}"
                         ContentPosition="{Binding CanvasPos, ElementName=zoombox, Mode=OneWay}"
+                        Center="{Binding Center, ElementName=zoombox, Mode=OneWay}"
                         Angle="{Binding RotateTransformAngle, ElementName=zoombox, Mode=OneWay}"
                         Angle="{Binding RotateTransformAngle, ElementName=zoombox, Mode=OneWay}"
                         ui1:RenderOptionsBindable.BitmapInterpolationMode="{Binding Scale, Converter={converters:ScaleToBitmapScalingModeConverter}, ElementName=zoombox}"
                         ui1:RenderOptionsBindable.BitmapInterpolationMode="{Binding Scale, Converter={converters:ScaleToBitmapScalingModeConverter}, ElementName=zoombox}"
                         FlowDirection="LeftToRight">
                         FlowDirection="LeftToRight">

+ 68 - 49
src/PixiEditor.AvaloniaUI/Views/Visuals/Scene.cs

@@ -24,6 +24,12 @@ internal class Scene : OpenGlControlBase
 
 
     public static readonly StyledProperty<VecI> ContentPositionProperty = AvaloniaProperty.Register<Scene, VecI>(
     public static readonly StyledProperty<VecI> ContentPositionProperty = AvaloniaProperty.Register<Scene, VecI>(
         nameof(ContentPosition));
         nameof(ContentPosition));
+    
+    public static readonly StyledProperty<VecD> CenterProperty = AvaloniaProperty.Register<Scene, VecD>(
+        nameof(Center));
+    
+    public static readonly StyledProperty<VecD> DimensionsProperty = AvaloniaProperty.Register<Scene, VecD>(
+        nameof(Dimensions));
 
 
     public static readonly StyledProperty<DocumentViewModel> DocumentProperty = AvaloniaProperty.Register<Scene, DocumentViewModel>(
     public static readonly StyledProperty<DocumentViewModel> DocumentProperty = AvaloniaProperty.Register<Scene, DocumentViewModel>(
         nameof(Document));
         nameof(Document));
@@ -48,6 +54,18 @@ internal class Scene : OpenGlControlBase
         get => GetValue(ContentPositionProperty);
         get => GetValue(ContentPositionProperty);
         set => SetValue(ContentPositionProperty, value);
         set => SetValue(ContentPositionProperty, value);
     }
     }
+    
+    public VecD Center
+    {
+        get => GetValue(CenterProperty);
+        set => SetValue(CenterProperty, value);
+    }
+    
+    public VecD Dimensions
+    {
+        get => GetValue(DimensionsProperty);
+        set => SetValue(DimensionsProperty, value);
+    }
 
 
     public double Scale
     public double Scale
     {
     {
@@ -61,7 +79,7 @@ internal class Scene : OpenGlControlBase
         set => SetValue(SurfaceProperty, value);
         set => SetValue(SurfaceProperty, value);
     }
     }
 
 
-    public Rect FinalBounds => new Rect(100, 100, Bounds.Width - 200, Bounds.Height - 200);
+    public Rect FinalBounds => new Rect((Bounds.Width - Bounds.Width/2 )/2, (Bounds.Height - Bounds.Height/2 )/2, Bounds.Width/2, Bounds.Height/2);
 
 
     private SKSurface _outputSurface;
     private SKSurface _outputSurface;
     private SKPaint _paint = new SKPaint();
     private SKPaint _paint = new SKPaint();
@@ -93,6 +111,8 @@ internal class Scene : OpenGlControlBase
         GRGlFramebufferInfo frameBuffer = new GRGlFramebufferInfo(0, SKColorType.Rgba8888.ToGlSizedFormat());
         GRGlFramebufferInfo frameBuffer = new GRGlFramebufferInfo(0, SKColorType.Rgba8888.ToGlSizedFormat());
         GRBackendRenderTarget desc = new GRBackendRenderTarget((int)Bounds.Width, (int)Bounds.Height, 4, 0, frameBuffer);
         GRBackendRenderTarget desc = new GRBackendRenderTarget((int)Bounds.Width, (int)Bounds.Height, 4, 0, frameBuffer);
         _outputSurface = SKSurface.Create(gr, desc, GRSurfaceOrigin.BottomLeft, SKImageInfo.PlatformColorType);
         _outputSurface = SKSurface.Create(gr, desc, GRSurfaceOrigin.BottomLeft, SKImageInfo.PlatformColorType);
+        
+        //FinalBounds = new(dime)
     }
     }
 
 
     protected override void OnOpenGlRender(GlInterface gl, int fb)
     protected override void OnOpenGlRender(GlInterface gl, int fb)
@@ -106,44 +126,42 @@ internal class Scene : OpenGlControlBase
         canvas.Clear(SKColors.Transparent);
         canvas.Clear(SKColors.Transparent);
 
 
         var scale = CalculateFinalScale();
         var scale = CalculateFinalScale();
+        float radians = (float)(Angle * Math.PI / 180);
 
 
         /*canvas.RotateDegrees((float)Angle, ContentPosition.X, ContentPosition.Y);
         /*canvas.RotateDegrees((float)Angle, ContentPosition.X, ContentPosition.Y);
         canvas.Scale(scale, scale, ContentPosition.X, ContentPosition.Y);
         canvas.Scale(scale, scale, ContentPosition.X, ContentPosition.Y);
 
 
         canvas.Translate(ContentPosition.X, ContentPosition.Y);*/
         canvas.Translate(ContentPosition.X, ContentPosition.Y);*/
 
 
-        float radians = (float)(Angle * Math.PI / 180);
-        VecD topLeft = SurfaceToViewport(new VecI(0, 0), scale, radians);
-        VecD bottomRight = SurfaceToViewport(Surface.Size, scale, radians);
-        VecD topRight = SurfaceToViewport(new VecI(Surface.Size.X, 0), scale, radians);
-        VecD bottomLeft = SurfaceToViewport(new VecI(0, Surface.Size.Y), scale, radians);
+        
+        RectD viewport = new(FinalBounds.X, FinalBounds.Y, FinalBounds.Width, FinalBounds.Height);
 
 
-        bool topLeftWithinBounds = IsWithinBounds(topLeft, FinalBounds);
-        bool bottomRightWithinBounds = IsWithinBounds(bottomRight, FinalBounds);
-        bool topRightWithinBounds = IsWithinBounds(topRight, FinalBounds);
-        bool bottomLeftWithinBounds = IsWithinBounds(bottomLeft, FinalBounds);
-
-        int withinBoundsCount = 0;
-        if (topLeftWithinBounds) withinBoundsCount++;
-        if (bottomRightWithinBounds) withinBoundsCount++;
-        if (topRightWithinBounds) withinBoundsCount++;
-        if (bottomLeftWithinBounds) withinBoundsCount++;
-
-        RectD viewport = new RectD(FinalBounds.X, FinalBounds.Y, FinalBounds.Width, FinalBounds.Height);
-        RectD canvasViewRectAabb = RectD.CreateAABB(topLeft, bottomRight, topRight, bottomLeft);
-
-        bool isViewportContained = canvasViewRectAabb.IntersectsWithInclusive(viewport);
-
-        _paint.Color = SKColors.Green;
-        canvas.DrawCircle((float)topLeft.X, (float)topLeft.Y, 5, _paint);
-        canvas.DrawCircle((float)bottomRight.X, (float)bottomRight.Y, 5, _paint);
-        canvas.DrawCircle((float)topRight.X, (float)topRight.Y, 5, _paint);
-        canvas.DrawCircle((float)bottomLeft.X, (float)bottomLeft.Y, 5, _paint);
 
 
         _paint.Color = SKColors.Blue;
         _paint.Color = SKColors.Blue;
         DrawDebugRect(canvas, viewport);
         DrawDebugRect(canvas, viewport);
-
-        if (withinBoundsCount == 0 && !isViewportContained)
+        
+
+        ShapeCorners surfaceInViewportSpace = SurfaceToViewport(new RectI(VecI.Zero, Surface.Size), scale, radians);
+        RectI surfaceBoundsInViewportSpace = (RectI)surfaceInViewportSpace.AABBBounds.RoundOutwards();
+        RectI viewportBoundsInViewportSpace = (RectI)(new RectD(FinalBounds.X, FinalBounds.Y, FinalBounds.Width, FinalBounds.Height)).RoundOutwards();
+        RectI firstIntersectionInViewportSpace = surfaceBoundsInViewportSpace.Intersect(viewportBoundsInViewportSpace);
+        ShapeCorners firstIntersectionInSurfaceSpace = ViewportToSurface(firstIntersectionInViewportSpace, scale, radians);
+        RectI firstIntersectionBoundsInSurfaceSpace = (RectI)firstIntersectionInSurfaceSpace.AABBBounds.RoundOutwards();
+        
+        ShapeCorners viewportInSurfaceSpace = new ShapeCorners(Center, Dimensions / 2).AsRotated(-radians, Center);
+        RectD viewportBoundsInSurfaceSpace = viewportInSurfaceSpace.AABBBounds;
+        RectD surfaceBoundsInSurfaceSpace = new(VecD.Zero, Surface.Size);
+        RectI secondIntersectionInSurfaceSpace = (RectI)viewportBoundsInSurfaceSpace.Intersect(surfaceBoundsInSurfaceSpace).RoundOutwards();
+        //ShapeCorners secondIntersectionInViewportSpace = SurfaceToViewport(secondIntersectionInSurfaceSpace, scale, radians);
+        //RectI secondIntersectionBoundsInViewportSpace = (RectI)secondIntersectionInViewportSpace.AABBBounds.RoundOutwards();
+        //
+        //RectI combinedIntersectionInViewportSpace = firstIntersectionInViewportSpace.Intersect(secondIntersectionBoundsInViewportSpace);
+        //ShapeCorners combinedIntersectionInSurfaceSpace = ViewportToSurface(combinedIntersectionInViewportSpace, scale, radians);
+        //RectI combinedIntersectionBoundsInSurfaceSpace = (RectI)combinedIntersectionInSurfaceSpace.AABBBounds.RoundOutwards();
+
+        RectI surfaceRectToRender = firstIntersectionBoundsInSurfaceSpace.Intersect(secondIntersectionInSurfaceSpace);
+
+        if (surfaceRectToRender.IsZeroOrNegativeArea)
         {
         {
             canvas.Restore();
             canvas.Restore();
             canvas.Flush();
             canvas.Flush();
@@ -151,20 +169,6 @@ internal class Scene : OpenGlControlBase
             return;
             return;
         }
         }
 
 
-        RectI surfaceRectToRender = new RectI(0, 0, Surface.Size.X, Surface.Size.Y);
-
-        if(withinBoundsCount < 4)
-        {
-            var topLeftCorner = new CornerInViewport(topLeft, topLeftWithinBounds, VecI.Zero);
-            var topRightCorner = new CornerInViewport(topRight, topRightWithinBounds, new VecI(Surface.Size.X, 0));
-            var bottomRightCorner = new CornerInViewport(bottomRight, bottomRightWithinBounds, Surface.Size);
-            var bottomLeftCorner = new CornerInViewport(bottomLeft, bottomLeftWithinBounds, new VecI(0, Surface.Size.Y));
-
-            CornersInViewport cornersInViewport = new CornersInViewport(topLeftCorner, topRightCorner, bottomRightCorner, bottomLeftCorner);
-
-            surfaceRectToRender = cornersInViewport.ShrinkToViewport(surfaceRectToRender, IsSurfaceWithinViewportBounds);
-        }
-
         canvas.RotateDegrees((float)Angle, ContentPosition.X, ContentPosition.Y);
         canvas.RotateDegrees((float)Angle, ContentPosition.X, ContentPosition.Y);
         canvas.Scale(scale, scale, ContentPosition.X, ContentPosition.Y);
         canvas.Scale(scale, scale, ContentPosition.X, ContentPosition.Y);
 
 
@@ -173,8 +177,8 @@ internal class Scene : OpenGlControlBase
 
 
         _paint.Color = SKColors.Red;
         _paint.Color = SKColors.Red;
         DrawDebugRect(canvas, (RectD)surfaceRectToRender);
         DrawDebugRect(canvas, (RectD)surfaceRectToRender);
-        /*using Image snapshot = Surface.DrawingSurface.Snapshot(surfaceRectToRender);
-        canvas.DrawImage((SKImage)snapshot.Native, surfaceRectToRender.X, surfaceRectToRender.Y, _paint);*/
+        using Image snapshot = Surface.DrawingSurface.Snapshot((RectI)surfaceRectToRender);
+        canvas.DrawImage((SKImage)snapshot.Native, (float)surfaceRectToRender.X, (float)surfaceRectToRender.Y, _paint);
 
 
         canvas.Restore();
         canvas.Restore();
 
 
@@ -191,11 +195,26 @@ internal class Scene : OpenGlControlBase
         canvas.DrawLine((float)rect.X, (float)rect.Bottom, (float)rect.X, (float)rect.Y, _paint);
         canvas.DrawLine((float)rect.X, (float)rect.Bottom, (float)rect.X, (float)rect.Y, _paint);
     }
     }
 
 
-    private RectI ViewportToSurface(RectD viewportRect, float scale, float angleRadians)
+    private ShapeCorners ViewportToSurface(RectI viewportRect, float scale, float angleRadians)
     {
     {
-        VecI start = ViewportToSurface(viewportRect.TopLeft, scale, angleRadians);
-        VecI end = ViewportToSurface(viewportRect.BottomRight, scale, angleRadians);
-        return RectI.FromTwoPoints(start, end);
+        return new ShapeCorners()
+        {
+            TopLeft = ViewportToSurface(viewportRect.TopLeft, scale, angleRadians),
+            TopRight = ViewportToSurface(viewportRect.TopRight, scale, angleRadians),
+            BottomLeft = ViewportToSurface(viewportRect.BottomLeft, scale, angleRadians),
+            BottomRight = ViewportToSurface(viewportRect.BottomRight, scale, angleRadians),
+        };
+    }
+    
+    private ShapeCorners SurfaceToViewport(RectI viewportRect, float scale, float angleRadians)
+    {
+        return new ShapeCorners()
+        {
+            TopLeft = SurfaceToViewport(viewportRect.TopLeft, scale, angleRadians),
+            TopRight = SurfaceToViewport(viewportRect.TopRight, scale, angleRadians),
+            BottomLeft = SurfaceToViewport(viewportRect.BottomLeft, scale, angleRadians),
+            BottomRight = SurfaceToViewport(viewportRect.BottomRight, scale, angleRadians),
+        };
     }
     }
 
 
     private bool IsWithinBounds(VecD point, Rect bounds)
     private bool IsWithinBounds(VecD point, Rect bounds)