protected override void Initialize() { // Create a timer that will simulate the gameloop _timer = new DispatcherTimer(); _timer.Interval = TimeSpan.FromSeconds(1/60); _timer.Tick += TimerTick; _timer.Start(); // Create the graphics options and initialize FRB with them var graphicsOptions = new GraphicsOptions(this, Graphics); graphicsOptions.SuspendDeviceReset(); graphicsOptions.ResolutionWidth = RenderWidth; graphicsOptions.ResolutionHeight = RenderHeight; graphicsOptions.ResumeDeviceReset(); FlatRedBallServices.InitializeFlatRedBall(this, Graphics, graphicsOptions); base.Initialize(); }
/// <summary> /// Initializes a new instance of the <see cref="RecolorBrushApplicator" /> class. /// </summary> /// <param name="sourcePixels">The source pixels.</param> /// <param name="sourceColor">Color of the source.</param> /// <param name="targetColor">Color of the target.</param> /// <param name="threshold">The threshold .</param> /// <param name="options">The options</param> public RecolorBrushApplicator(PixelAccessor <TPixel> sourcePixels, TPixel sourceColor, TPixel targetColor, float threshold, GraphicsOptions options) : base(sourcePixels, options) { this.sourceColor = sourceColor.ToVector4(); this.targetColor = targetColor.ToVector4(); this.targetColorPixel = targetColor; // Lets hack a min max extreams for a color space by letteing the IPackedPixel clamp our values to something in the correct spaces :) TPixel maxColor = default(TPixel); maxColor.PackFromVector4(new Vector4(float.MaxValue)); TPixel minColor = default(TPixel); minColor.PackFromVector4(new Vector4(float.MinValue)); this.threshold = Vector4.DistanceSquared(maxColor.ToVector4(), minColor.ToVector4()) * threshold; }
/// <inheritdoc /> public BrushApplicator <TPixel> CreateApplicator(ImageFrame <TPixel> source, RectangleF region, GraphicsOptions options) { return(new PatternBrushApplicator(source, this.pattern, this.patternVector, options)); }
/// <summary> /// Initializes a new instance of the <see cref="BrushApplicator{TPixel}"/> class. /// </summary> /// <param name="target">The target.</param> /// <param name="options">The options.</param> internal BrushApplicator(ImageFrame <TPixel> target, GraphicsOptions options) { this.Target = target; this.Options = options; this.Blender = PixelOperations <TPixel> .Instance.GetPixelBlender(options); }
/// <summary> /// Applies a radial vignette effect to an image. /// </summary> /// <typeparam name="TPixel">The pixel format.</typeparam> /// <param name="source">The image this method extends.</param> /// <param name="options">The options effecting pixel blending.</param> /// <param name="color">The color to set as the vignette.</param> /// <param name="radiusX">The the x-radius.</param> /// <param name="radiusY">The the y-radius.</param> /// <param name="rectangle"> /// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter. /// </param> /// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns> public static IImageProcessingContext <TPixel> Vignette <TPixel>(this IImageProcessingContext <TPixel> source, GraphicsOptions options, TPixel color, float radiusX, float radiusY, Rectangle rectangle) where TPixel : struct, IPixel <TPixel> => source.VignetteInternal(options, color, radiusX, radiusY, rectangle);
/// <summary> /// Applies a radial vignette effect to an image. /// </summary> /// <typeparam name="TPixel">The pixel format.</typeparam> /// <param name="source">The image this method extends.</param> /// <param name="options">The options effecting pixel blending.</param> /// <param name="color">The color to set as the vignette.</param> /// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns> public static IImageProcessingContext <TPixel> Vignette <TPixel>(this IImageProcessingContext <TPixel> source, GraphicsOptions options, TPixel color) where TPixel : struct, IPixel <TPixel> => source.VignetteInternal(options, color, ValueSize.PercentageOfWidth(.5f), ValueSize.PercentageOfHeight(.5f));
/// <summary> /// Initializes a new instance of the <see cref="ImageBrushApplicator"/> class. /// </summary> /// <param name="target">The target image.</param> /// <param name="image">The image.</param> /// <param name="region">The region.</param> /// <param name="options">The options</param> public ImageBrushApplicator(ImageFrame <TPixel> target, ImageFrame <TPixel> image, RectangleF region, GraphicsOptions options) : base(target, options) { this.source = image; this.xLength = image.Width; this.yLength = image.Height; this.offsetY = (int)MathF.Max(MathF.Floor(region.Top), 0); this.offsetX = (int)MathF.Max(MathF.Floor(region.Left), 0); }
/// <summary> /// Applies a radial vignette effect to an image. /// </summary> /// <typeparam name="TPixel">The pixel format.</typeparam> /// <param name="source">The image this method extends.</param> /// <param name="options">The options effecting pixel blending.</param> /// <param name="radiusX">The the x-radius.</param> /// <param name="radiusY">The the y-radius.</param> /// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns> public static IImageProcessingContext <TPixel> Vignette <TPixel>(this IImageProcessingContext <TPixel> source, GraphicsOptions options, float radiusX, float radiusY) where TPixel : struct, IPixel <TPixel> => source.VignetteInternal(options, NamedColors <TPixel> .Black, radiusX, radiusY);
/// <inheritdoc/> protected override void OnFrameApply(ImageFrame <TPixel> source, Rectangle sourceRectangle, Configuration configuration) { int startX = sourceRectangle.X; int endX = sourceRectangle.Right; int startY = sourceRectangle.Y; int endY = sourceRectangle.Bottom; // Align start/end positions. int minX = Math.Max(0, startX); int maxX = Math.Min(source.Width, endX); int minY = Math.Max(0, startY); int maxY = Math.Min(source.Height, endY); int width = maxX - minX; var workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY); IBrush brush = this.definition.Brush; GraphicsOptions options = this.definition.Options; // If there's no reason for blending, then avoid it. if (this.IsSolidBrushWithoutBlending(out SolidBrush solidBrush)) { ParallelExecutionSettings parallelSettings = configuration.GetParallelSettings().MultiplyMinimumPixelsPerTask(4); TPixel colorPixel = solidBrush.Color.ToPixel <TPixel>(); ParallelHelper.IterateRows( workingRect, parallelSettings, rows => { for (int y = rows.Min; y < rows.Max; y++) { source.GetPixelRowSpan(y).Slice(minX, width).Fill(colorPixel); } }); } else { // Reset offset if necessary. if (minX > 0) { startX = 0; } if (minY > 0) { startY = 0; } using (IMemoryOwner <float> amount = source.MemoryAllocator.Allocate <float>(width)) using (BrushApplicator <TPixel> applicator = brush.CreateApplicator( source, sourceRectangle, options)) { amount.GetSpan().Fill(1f); ParallelHelper.IterateRows( workingRect, configuration, rows => { for (int y = rows.Min; y < rows.Max; y++) { int offsetY = y - startY; int offsetX = minX - startX; applicator.Apply(amount.GetSpan(), offsetX, offsetY); } }); } } }
/// <inheritdoc/> protected override void OnFrameApply(ImageFrame <TPixel> source) { Configuration configuration = this.Configuration; GraphicsOptions options = this.definition.Options; IBrush brush = this.definition.Brush; Region region = this.definition.Region; Rectangle rect = region.Bounds; // Align start/end positions. int minX = Math.Max(0, rect.Left); int maxX = Math.Min(source.Width, rect.Right); int minY = Math.Max(0, rect.Top); int maxY = Math.Min(source.Height, rect.Bottom); if (minX >= maxX) { return; // no effect inside image; } if (minY >= maxY) { return; // no effect inside image; } int maxIntersections = region.MaxIntersections; float subpixelCount = 4; // we need to offset the pixel grid to account for when we outline a path. // basically if the line is [1,2] => [3,2] then when outlining at 1 we end up with a region of [0.5,1.5],[1.5, 1.5],[3.5,2.5],[2.5,2.5] // and this can cause missed fills when not using antialiasing.so we offset the pixel grid by 0.5 in the x & y direction thus causing the# // region to align with the pixel grid. float offset = 0.5f; if (options.Antialias) { offset = 0f; // we are antialiasing skip offsetting as real antialiasing should take care of offset. subpixelCount = options.AntialiasSubpixelDepth; if (subpixelCount < 4) { subpixelCount = 4; } } using (BrushApplicator <TPixel> applicator = brush.CreateApplicator(configuration, options, source, rect)) { int scanlineWidth = maxX - minX; using (IMemoryOwner <float> bBuffer = source.MemoryAllocator.Allocate <float>(maxIntersections)) using (IMemoryOwner <float> bScanline = source.MemoryAllocator.Allocate <float>(scanlineWidth)) { bool scanlineDirty = true; float subpixelFraction = 1f / subpixelCount; float subpixelFractionPoint = subpixelFraction / subpixelCount; Span <float> buffer = bBuffer.Memory.Span; Span <float> scanline = bScanline.Memory.Span; bool isSolidBrushWithoutBlending = this.IsSolidBrushWithoutBlending(out SolidBrush solidBrush); TPixel solidBrushColor = isSolidBrushWithoutBlending ? solidBrush.Color.ToPixel <TPixel>() : default; for (int y = minY; y < maxY; y++) { if (scanlineDirty) { scanline.Clear(); scanlineDirty = false; } float yPlusOne = y + 1; for (float subPixel = y; subPixel < yPlusOne; subPixel += subpixelFraction) { int pointsFound = region.Scan(subPixel + offset, buffer, configuration); if (pointsFound == 0) { // nothing on this line, skip continue; } QuickSort.Sort(buffer.Slice(0, pointsFound)); for (int point = 0; point < pointsFound && point < buffer.Length - 1; point += 2) { // points will be paired up float scanStart = buffer[point] - minX; float scanEnd = buffer[point + 1] - minX; int startX = (int)MathF.Floor(scanStart + offset); int endX = (int)MathF.Floor(scanEnd + offset); if (startX >= 0 && startX < scanline.Length) { for (float x = scanStart; x < startX + 1; x += subpixelFraction) { scanline[startX] += subpixelFractionPoint; scanlineDirty = true; } } if (endX >= 0 && endX < scanline.Length) { for (float x = endX; x < scanEnd; x += subpixelFraction) { scanline[endX] += subpixelFractionPoint; scanlineDirty = true; } } int nextX = startX + 1; endX = Math.Min(endX, scanline.Length); // reduce to end to the right edge nextX = Math.Max(nextX, 0); for (int x = nextX; x < endX; x++) { scanline[x] += subpixelFraction; scanlineDirty = true; } } } if (scanlineDirty) { if (!options.Antialias) { bool hasOnes = false; bool hasZeros = false; for (int x = 0; x < scanlineWidth; x++) { if (scanline[x] >= 0.5) { scanline[x] = 1; hasOnes = true; } else { scanline[x] = 0; hasZeros = true; } } if (isSolidBrushWithoutBlending && hasOnes != hasZeros) { if (hasOnes) { source.GetPixelRowSpan(y).Slice(minX, scanlineWidth).Fill(solidBrushColor); } continue; } } applicator.Apply(scanline, minX, y); } } } } }
/// <summary> /// Initializes a new instance of the <see cref="GlowProcessor{TPixel}" /> class. /// </summary> /// <param name="color">The color or the glow.</param> /// <param name="options">The options effecting blending and composition.</param> public GlowProcessor(TPixel color, GraphicsOptions options) { this.options = options; this.GlowColor = color; this.blender = PixelOperations <TPixel> .Instance.GetPixelBlender(this.options.BlenderMode); }
/// <inheritdoc cref="IBrush{TPixel}" /> public abstract BrushApplicator <TPixel> CreateApplicator( ImageFrame <TPixel> source, RectangleF region, GraphicsOptions options);
/// <summary> /// Flood fills the image with the specified brush. /// </summary> /// <param name="source">The image this method extends.</param> /// <param name="options">The graphics options.</param> /// <param name="brush">The details how to fill the region of interest.</param> /// <returns>The <see cref="Image{TPixel}"/>.</returns> public static IImageProcessingContext Fill( this IImageProcessingContext source, GraphicsOptions options, IBrush brush) => source.ApplyProcessor(new FillProcessor(brush, options));
/// <summary> /// Flood fills the image with in the region with the specified color. /// </summary> /// <param name="source">The image this method extends.</param> /// <param name="options">The options.</param> /// <param name="color">The color.</param> /// <param name="region">The region.</param> /// <returns>The <see cref="Image{TPixel}"/>.</returns> public static IImageProcessingContext Fill( this IImageProcessingContext source, GraphicsOptions options, Color color, Region region) => source.Fill(options, new SolidBrush(color), region);
/// <summary> /// Draws the outline of the polygon with the provided pen. /// </summary> /// <typeparam name="TPixel">The type of the color.</typeparam> /// <param name="source">The image this method extends.</param> /// <param name="options">The options.</param> /// <param name="pen">The pen.</param> /// <param name="path">The path.</param> /// <returns>The <see cref="Image{TPixel}"/>.</returns> public static IImageProcessingContext <TPixel> Draw <TPixel>(this IImageProcessingContext <TPixel> source, GraphicsOptions options, IPen <TPixel> pen, IPath path) where TPixel : struct, IPixel <TPixel> => source.Fill(options, pen.StrokeFill, new ShapePath(path, pen));
/// <summary> /// Flood fills the image in the shape of the provided rectangle with the specified brush. /// </summary> /// <param name="source">The image this method extends.</param> /// <param name="options">The options.</param> /// <param name="color">The color.</param> /// <param name="shape">The shape.</param> /// <returns>The <see cref="Image{TPixel}"/>.</returns> public static IImageProcessingContext Fill( this IImageProcessingContext source, GraphicsOptions options, Color color, RectangleF shape) => source.Fill(options, new SolidBrush(color), shape);
/// <summary> /// Draws the outline of the polygon with the provided brush at the provided thickness. /// </summary> /// <typeparam name="TPixel">The type of the color.</typeparam> /// <param name="source">The image this method extends.</param> /// <param name="options">The options.</param> /// <param name="brush">The brush.</param> /// <param name="thickness">The thickness.</param> /// <param name="path">The shape.</param> /// <returns>The <see cref="Image{TPixel}"/>.</returns> public static IImageProcessingContext <TPixel> Draw <TPixel>(this IImageProcessingContext <TPixel> source, GraphicsOptions options, IBrush <TPixel> brush, float thickness, IPath path) where TPixel : struct, IPixel <TPixel> => source.Draw(options, new Pen <TPixel>(brush, thickness), path);
/// <summary> /// Applies a radial vignette effect to an image. /// </summary> /// <typeparam name="TPixel">The pixel format.</typeparam> /// <param name="source">The image this method extends.</param> /// <param name="options">The options effecting pixel blending.</param> /// <param name="rectangle"> /// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter. /// </param> /// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns> public static IImageProcessingContext <TPixel> Vignette <TPixel>(this IImageProcessingContext <TPixel> source, GraphicsOptions options, Rectangle rectangle) where TPixel : struct, IPixel <TPixel> => source.VignetteInternal(options, NamedColors <TPixel> .Black, ValueSize.PercentageOfWidth(.5f), ValueSize.PercentageOfHeight(.5f), rectangle);
/// <summary> /// Draws the outline of the polygon with the provided brush at the provided thickness. /// </summary> /// <typeparam name="TPixel">The type of the color.</typeparam> /// <param name="source">The image this method extends.</param> /// <param name="options">The options.</param> /// <param name="color">The color.</param> /// <param name="thickness">The thickness.</param> /// <param name="path">The path.</param> /// <returns>The <see cref="Image{TPixel}"/>.</returns> public static IImageProcessingContext <TPixel> Draw <TPixel>(this IImageProcessingContext <TPixel> source, GraphicsOptions options, TPixel color, float thickness, IPath path) where TPixel : struct, IPixel <TPixel> => source.Draw(options, new SolidBrush <TPixel>(color), thickness, path);
private static IImageProcessingContext <TPixel> VignetteInternal <TPixel>(this IImageProcessingContext <TPixel> source, GraphicsOptions options, TPixel color, ValueSize radiusX, ValueSize radiusY) where TPixel : struct, IPixel <TPixel> => source.ApplyProcessor(new VignetteProcessor <TPixel>(color, radiusX, radiusY, options));
/// <summary> /// Initializes a new instance of the <see cref="BackgroundColorProcessor{TPixel}"/> class. /// </summary> /// <param name="color">The <typeparamref name="TPixel"/> to set the background color to.</param> /// <param name="options">The options defining blending algorithm and amount.</param> public BackgroundColorProcessor(TPixel color, GraphicsOptions options) { this.Color = color; this.GraphicsOptions = options; }
/// <summary> /// Flood fills the image in the shape of the provided polygon with the specified brush. /// </summary> /// <param name="source">The image this method extends.</param> /// <param name="options">The options.</param> /// <param name="color">The color.</param> /// <param name="paths">The paths.</param> /// <returns>The <see cref="Image{TPixel}"/>.</returns> public static IImageProcessingContext Fill( this IImageProcessingContext source, GraphicsOptions options, Color color, IPathCollection paths) => source.Fill(options, new SolidBrush(color), paths);
/// <summary> /// Initializes a new instance of the <see cref="ShapeGraphicsOptions"/> class. /// </summary> public ShapeGraphicsOptions() { this.graphicsOptions = new GraphicsOptions(); this.shapeOptions = new ShapeOptions(); }
/// <summary> /// Draws the provided points as an open Bezier path with the supplied pen /// </summary> /// <param name="source">The image this method extends.</param> /// <param name="options">The options.</param> /// <param name="pen">The pen.</param> /// <param name="points">The points.</param> /// <returns>The <see cref="Image{TPixel}"/>.</returns> public static IImageProcessingContext DrawBeziers( this IImageProcessingContext source, GraphicsOptions options, IPen pen, params PointF[] points) => source.Draw(options, pen, new Path(new CubicBezierLineSegment(points)));
/// <inheritdoc /> public BrushApplicator <TPixel> CreateApplicator(PixelAccessor <TPixel> sourcePixels, RectangleF region, GraphicsOptions options) { return(new ImageBrushApplicator(sourcePixels, this.image, region, options)); }
/// <summary> /// Initializes a new instance of the <see cref="PatternBrushApplicator" /> class. /// </summary> /// <param name="source">The source image.</param> /// <param name="pattern">The pattern.</param> /// <param name="patternVector">The patternVector.</param> /// <param name="options">The options</param> public PatternBrushApplicator(ImageFrame <TPixel> source, Fast2DArray <TPixel> pattern, Fast2DArray <Vector4> patternVector, GraphicsOptions options) : base(source, options) { this.pattern = pattern; this.patternVector = patternVector; }
/// <summary> /// Initializes a new instance of the <see cref="ImageBrushApplicator"/> class. /// </summary> /// <param name="image"> /// The image. /// </param> /// <param name="region"> /// The region. /// </param> /// <param name="options">The options</param> /// <param name="sourcePixels"> /// The sourcePixels. /// </param> public ImageBrushApplicator(PixelAccessor <TPixel> sourcePixels, IImageBase <TPixel> image, RectangleF region, GraphicsOptions options) : base(sourcePixels, options) { this.source = image.Lock(); this.xLength = image.Width; this.yLength = image.Height; this.offsetY = (int)MathF.Max(MathF.Floor(region.Top), 0); this.offsetX = (int)MathF.Max(MathF.Floor(region.Left), 0); }
/// <inheritdoc /> public BrushApplicator <TPixel> CreateApplicator(PixelAccessor <TPixel> sourcePixels, RectangleF region, GraphicsOptions options) { return(new RecolorBrushApplicator(sourcePixels, this.SourceColor, this.TargeTPixel, this.Threshold, options)); }
/// <summary> /// Flood fills the image in the shape of the provided rectangle with the specified brush. /// </summary> /// <param name="source">The image this method extends.</param> /// <param name="options">The options.</param> /// <param name="brush">The brush.</param> /// <param name="shape">The shape.</param> /// <returns>The <see cref="Image{TPixel}"/>.</returns> public static IImageProcessingContext Fill( this IImageProcessingContext source, GraphicsOptions options, IBrush brush, RectangleF shape) => source.Fill(options, brush, new RectangularPolygon(shape.X, shape.Y, shape.Width, shape.Height));
/// <summary> /// Draws the given image together with the current one by blending their pixels. /// </summary> /// <typeparam name="TPixel">The pixel format.</typeparam> /// <param name="source">The image this method extends.</param> /// <param name="image">The image to blend with the currently processing image.</param> /// <param name="location">The location to draw the blended image.</param> /// <param name="options">The options containing the blend mode and opacity.</param> /// <returns>The <see cref="Image{TPixel}"/>.</returns> public static IImageProcessingContext <TPixel> DrawImage <TPixel>(this IImageProcessingContext <TPixel> source, Image <TPixel> image, Point location, GraphicsOptions options) where TPixel : struct, IPixel <TPixel> => source.ApplyProcessor(new DrawImageProcessor <TPixel>(image, location, options.ColorBlendingMode, options.AlphaCompositionMode, options.BlendPercentage));
/// <summary> /// Draws the provided points as an open Bezier path with the supplied pen /// </summary> /// <typeparam name="TPixel">The type of the color.</typeparam> /// <param name="source">The image this method extends.</param> /// <param name="pen">The pen.</param> /// <param name="points">The points.</param> /// <param name="options">The options.</param> /// <returns>The <see cref="Image{TPixel}"/>.</returns> public static IImageProcessingContext <TPixel> DrawBeziers <TPixel>(this IImageProcessingContext <TPixel> source, IPen <TPixel> pen, PointF[] points, GraphicsOptions options) where TPixel : struct, IPixel <TPixel> => source.Draw(pen, new Path(new CubicBezierLineSegment(points)), options);