Beispiel #1
0
        void canvas_Draw(CanvasControl sender, CanvasDrawEventArgs args)
        {
            // We animate the source image by changing which character is highlighted in yellow.
            // Therefore there can be two changed regions: the highlighted character has changed from
            // white to yellow, while the previous highlight has changed from yellow back to white.

            // Look up the bounds of the two changed characters.
            var highlightBounds = GetCharacterBounds(highlightedCharacter);
            var previousBounds  = GetCharacterBounds(previousHighlight);

            // Tell our effects that the highlighted character region has changed.
            blurEffect.InvalidateSourceRectangle(args.DrawingSession, 0, highlightBounds);
            shadowEffect.InvalidateSourceRectangle(args.DrawingSession, 0, highlightBounds);

            // Query what part of the output image will change as a result.
            var highlightInvalidRects = compositeEffect.GetInvalidRectangles(args.DrawingSession);
            var highlightInvalidUnion = GetRectangleUnion(highlightInvalidRects);

            // Also tell the effects about the previously highlighted character.
            blurEffect.InvalidateSourceRectangle(args.DrawingSession, 0, previousBounds);
            shadowEffect.InvalidateSourceRectangle(args.DrawingSession, 0, previousBounds);

            // Query the output region again. This will return a superset of highlightInvalidRects,
            // as it now accounts for the change to previousBounds as well as highlightBounds.
            var totalInvalidRects = compositeEffect.GetInvalidRectangles(args.DrawingSession);
            var totalInvalidUnion = GetRectangleUnion(totalInvalidRects);

            // We can also look up in the opposite direction: given that we are going to redraw only
            // the totalInvalidUnion area, what portion of each source image is needed to do that?
            // When using filter kernels like blur, this will be larger than just highlightBounds+previousBounds.
            var requiredSourceRects = compositeEffect.GetRequiredSourceRectangles(args.DrawingSession,
                                                                                  totalInvalidUnion,
                                                                                  new ICanvasEffect[] { blurEffect, shadowEffect },
                                                                                  new uint[] { 0, 0 },
                                                                                  new Rect[2] {
                sourceRenderTarget.Bounds, sourceRenderTarget.Bounds
            });

            // How about if we were going to redraw only highlightBounds, skipping previousBounds?
            // (we don't actually do this, but do display what source regions it would require).
            var blurSourceRect   = compositeEffect.GetRequiredSourceRectangle(args.DrawingSession, highlightInvalidUnion, blurEffect, 0, sourceRenderTarget.Bounds);
            var shadowSourceRect = compositeEffect.GetRequiredSourceRectangle(args.DrawingSession, highlightInvalidUnion, shadowEffect, 0, sourceRenderTarget.Bounds);

            // Draw text into the source rendertarget.
            using (var drawingSession = sourceRenderTarget.CreateDrawingSession())
            {
                // To make sure the correct requiredSourceRects were reported, we clear the background outside
                // that region to magenta. If everything is working correctly, this should never be picked up by
                // effect drawing, as we only leave magenta in the areas we don't expect the effects to read from.
                drawingSession.Clear(Colors.Magenta);

                // Clear the requiredSourceRects to transparent.
                drawingSession.Blend = CanvasBlend.Copy;

                foreach (var r in requiredSourceRects)
                {
                    drawingSession.FillRectangle(r, Colors.Transparent);
                }

                // Draw the text characters.
                drawingSession.Blend = CanvasBlend.SourceOver;

                for (int i = 0; i < characterLayouts.Count; i++)
                {
                    var color = (i == highlightedCharacter) ? Colors.Yellow : Colors.White;

                    drawingSession.DrawTextLayout(characterLayouts[i], characterPositions[i], color);
                }
            }

            // Draw the effect graph (which reads from sourceRenderTarget) into destRenderTarget.
            using (var drawingSession = destRenderTarget.CreateDrawingSession())
            {
                // Slightly darken down the existing contents of the output rendertarget. This causes everything
                // except totalInvalidUnion to gradually fade out, so we can see which areas are getting redrawn.
                // If this FillRectangle was removed, the result of redrawing only the changed region would be
                // identical to if we redrew the whole thing every time (by removing the CreateLayer call).
                drawingSession.FillRectangle(destRenderTarget.Bounds, Color.FromArgb(16, 0, 0, 0));

                // Clip our drawing to the totalInvalidUnion rectangle,
                // which should be the only part of the output that has changed.
                using (var layer = drawingSession.CreateLayer(1, totalInvalidUnion))
                {
                    drawingSession.Clear(Colors.CornflowerBlue);
                    drawingSession.DrawImage(compositeEffect, totalInvalidUnion, totalInvalidUnion);
                }
            }

            if (!ThumbnailGenerator.IsDrawingThumbnail)
            {
                args.DrawingSession.Transform = Matrix3x2.CreateTranslation(gap, gap);

                // Display sourceRenderTarget.
                args.DrawingSession.DrawImage(sourceRenderTarget);

                // Display highlightBounds, blurSourceRect, and shadowSourceRect.
                args.DrawingSession.DrawRectangle(highlightBounds, Colors.Gray);
                args.DrawingSession.DrawRectangle(blurSourceRect, Colors.Blue);
                args.DrawingSession.DrawRectangle(shadowSourceRect, Colors.Blue);
            }

            args.DrawingSession.Transform = Matrix3x2.CreateTranslation(gap, gap * 2 + height);

            // Display destRenderTarget.
            args.DrawingSession.DrawImage(destRenderTarget);

            // Display highlightInvalidRects.
            foreach (var i in highlightInvalidRects)
            {
                args.DrawingSession.DrawRectangle(i, Colors.DarkBlue);
            }

            previousHighlight = highlightedCharacter;

            // When generating thumbnails, repeat the first draw a bunch of times to reach a more interesting image.
            if (ThumbnailGenerator.IsDrawingThumbnail && highlightedCharacter < characterLayouts.Count * 5 / 6)
            {
                highlightedCharacter++;
                canvas_Draw(sender, args);
            }
        }