ICanvasImage CreateCheckerBoard(CanvasControl control) { var color1 = Color.FromArgb(255, 254, 254, 254); var color2 = Color.FromArgb(255, 250, 250, 250); Color[] twoByTwoChecker = { color1, color2, color2, color1 }; var checker = new DpiCompensationEffect { Source = new ScaleEffect { Source = new BorderEffect { Source = CanvasBitmap.CreateFromColors(control, twoByTwoChecker, 2, 2), ExtendX = CanvasEdgeBehavior.Wrap, ExtendY = CanvasEdgeBehavior.Wrap }, Scale = new Vector2(8, 8), InterpolationMode = CanvasImageInterpolation.NearestNeighbor } }; return(checker); }
private void GameCanvasDraw(ICanvasAnimatedControl sender, CanvasAnimatedDrawEventArgs args) { if (!ViewModel.IsGameInitialized || GameCanvas == null) { return; } var dpiCompensationEffect = new DpiCompensationEffect { Source = currentSurface, SourceDpi = new Vector2(GameCanvas.Dpi) }; var transformEffect = new Transform2DEffect { Source = dpiCompensationEffect, InterpolationMode = CanvasImageInterpolation.NearestNeighbor, TransformMatrix = GetDisplayTransform(sender) }; args.DrawingSession.DrawImage(transformEffect); }
void CreateEffects() { // The Game of Life is a cellular automaton with very simple rules. // Each cell (pixel) can be either alive (white) or dead (black). // The state is updated by: // // - for each cell, count how many of its 8 neighbors are alive // - if less than two, the cell dies from loneliness // - if exactly two, the cell keeps its current state // - if exactly three, the cell become alive // - if more than three, the cell dies from overcrowding // Step 1: use a convolve matrix to count how many neighbors are alive. This filter // also includes the state of the current cell, but with a lower weighting. The result // is an arithmetic encoding where (value / 2) indicates how many neighbors are alive, // and (value % 2) is the state of the cell itself. This is divided by 18 to make it // fit within 0-1 color range. countNeighborsEffect = new ConvolveMatrixEffect { KernelMatrix = new float[] { 2, 2, 2, 2, 1, 2, 2, 2, 2 }, Divisor = 18, BorderMode = EffectBorderMode.Hard, }; // Step 2: use a color transfer table to map the different states produced by the // convolve matrix to whether the cell should live or die. Each pair of entries in // this table corresponds to a certain number of live neighbors. The first of the // pair is the result if the current cell is dead, or the second if it is alive. float[] transferTable = { 0, 0, // 0 live neighbors -> dead cell 0, 0, // 1 live neighbors -> dead cell 0, 1, // 2 live neighbors -> cell keeps its current state 1, 1, // 3 live neighbors -> live cell 0, 0, // 4 live neighbors -> dead cell 0, 0, // 5 live neighbors -> dead cell 0, 0, // 6 live neighbors -> dead cell 0, 0, // 7 live neighbors -> dead cell 0, 0, // 8 live neighbors -> dead cell }; liveOrDieEffect = new DiscreteTransferEffect { Source = countNeighborsEffect, RedTable = transferTable, GreenTable = transferTable, BlueTable = transferTable, }; // Step 3: the algorithm is implemented in terms of white = live, // black = dead, but we invert these colors before displaying the // result, just 'cause I think it looks better that way. invertEffect = new LinearTransferEffect { RedSlope = -1, RedOffset = 1, GreenSlope = -1, GreenOffset = 1, BlueSlope = -1, BlueOffset = 1, }; // Step 4: insert our own DPI compensation effect to stop the system trying to // automatically convert DPI for us. The Game of Life simulation always works // in pixels (96 DPI) regardless of display DPI. Normally, the system would // handle this mismatch automatically and scale the image up as needed to fit // higher DPI displays. We don't want that behavior here, because it would use // a linear filter while we want nearest neighbor. So we insert a no-op DPI // converter of our own. This overrides the default adjustment by telling the // system the source image is already the same DPI as the destination canvas // (even though it really isn't). We'll handle any necessary scaling later // ourselves, using Transform2DEffect to control the interpolation mode. var dpiCompensationEffect = new DpiCompensationEffect { Source = invertEffect, SourceDpi = new Vector2(canvas.Dpi), }; // Step 5: a transform matrix scales up the simulation rendertarget and moves // it to the right part of the screen. This uses nearest neighbor filtering // to avoid unwanted blurring of the cell shapes. transformEffect = new Transform2DEffect { Source = dpiCompensationEffect, InterpolationMode = CanvasImageInterpolation.NearestNeighbor, }; }
ICanvasImage CreateCheckerBoard(CanvasControl control) { var color1 = Color.FromArgb(255, 254, 254, 254); var color2 = Color.FromArgb(255, 250, 250, 250); Color[] twoByTwoChecker = { color1, color2, color2, color1 }; var checker = new DpiCompensationEffect { Source = new ScaleEffect { Source = new BorderEffect { Source = CanvasBitmap.CreateFromColors(control, twoByTwoChecker, 2, 2), ExtendX = CanvasEdgeBehavior.Wrap, ExtendY = CanvasEdgeBehavior.Wrap }, Scale = new Vector2(8, 8), InterpolationMode = CanvasImageInterpolation.NearestNeighbor } }; return checker; }