private static void DrawFieldSprtDoIt(byte[] pixels, double[] ink, bool[] blocked, int size, byte[] colorZFront, byte[] colorZBack, AxisFor pixelX, AxisFor pixelY, AxisFor pixelZ) { List<Mapping_2D_1D> flattened = new List<Mapping_2D_1D>(); // Setup the pixel array //for (int y2D = pixelY.Start; pixelY.IsPos ? y2D <= pixelY.Stop : y2D >= pixelY.Stop; y2D += pixelY.Increment) foreach (int y2D in pixelY.Iterate()) { int offsetY = pixelY.GetValueForOffset(y2D) * size; //for (int x2D = pixelX.Start; pixelX.IsPos ? x2D <= pixelX.Stop : x2D >= pixelX.Stop; x2D += pixelX.Increment) foreach (int x2D in pixelX.Iterate()) { int offset = offsetY + pixelX.GetValueForOffset(x2D); flattened.Add(new Mapping_2D_1D(x2D, y2D, offset)); } } // Each pixel of the output bitmap can be added up independently, so employ some threading flattened.AsParallel().ForAll(o => { //TODO: Color is 6.5 times slower than byte array List<byte[]> colorColumn = new List<byte[]>(); for (int z2D = pixelZ.Start; pixelZ.IsPos ? z2D <= pixelZ.Stop : z2D >= pixelZ.Stop; z2D += pixelZ.Increment) { int x = -1, y = -1, z = -1; pixelX.Set3DIndex(ref x, ref y, ref z, o.X); pixelY.Set3DIndex(ref x, ref y, ref z, o.Y); pixelZ.Set3DIndex(ref x, ref y, ref z, z2D); int index = FluidField3D.Get1DIndex(x, y, z, size); if (blocked[index]) { // Blocked cells are all white, so save the overlay method a bit of work, and throw out everything behind this colorColumn.Clear(); colorColumn.Add(new byte[] { 255, 255, 255, 255 }); continue; } double inkCell = ink[index]; if (Math1D.IsNearZero(inkCell)) { continue; } byte[] depthColor = UtilityWPF.AlphaBlend(colorZBack, colorZFront, UtilityCore.GetScaledValue_Capped(0, 1, 0, size - 1, z)); int alpha = Convert.ToInt32(Math.Round(inkCell * 255)); if (alpha < 0) { alpha = 0; } else if (alpha > 255) { alpha = 255; } colorColumn.Add(new byte[] { Convert.ToByte(alpha), depthColor[1], depthColor[2], depthColor[3] }); } byte[] color = colorColumn.Count > 0 ? UtilityWPF.OverlayColors(colorColumn) : new byte[] { 0, 0, 0, 0 }; pixels[o.Offset1D * 4 + 0] = color[3]; // Blue pixels[o.Offset1D * 4 + 1] = color[2]; // Green pixels[o.Offset1D * 4 + 2] = color[1]; // Red pixels[o.Offset1D * 4 + 3] = color[0]; // Alpha }); }
/// <summary> /// Shifts values (the new margins get zero) /// </summary> /// <param name="sweep">The other axis (if x's are getting shifted, then do it for each y)</param> /// <param name="shift">The row/column that has values changing. ex: [x] = [x+1]</param> private void TranslateValues(AxisFor sweep, AxisFor shift) { int amount; if (!int.TryParse(txtMoveAmount.Text, out amount)) { amount = 1; } amount *= shift.IsPos ? 1 : -1; foreach (int sweepIndex in sweep.Iterate()) { foreach (int shiftIndex in shift.Iterate()) { int toX = -1; int toY = -1; sweep.Set2DIndex(ref toX, ref toY, sweepIndex); shift.Set2DIndex(ref toX, ref toY, shiftIndex); int fromX = -1; int fromY = -1; sweep.Set2DIndex(ref fromX, ref fromY, sweepIndex); shift.Set2DIndex(ref fromX, ref fromY, shiftIndex + amount); double value = 0; if (fromX >= 0 && fromX < _width && fromY >= 0 && fromY < _height) { value = _values[fromY * _width + fromX]; } _values[toY * _width + toX] = value; } } RebuildBars(); PixelValueChanged(); }
private static Convolution2D CopyRect(double[] values, int width, AxisFor edge, AxisFor orth, bool shouldRotate180) { if (shouldRotate180) { return CopyRect(values, width, new AxisFor(edge.Axis, edge.Stop, edge.Start), new AxisFor(orth.Axis, orth.Stop, orth.Start), false); } double[] retVal = new double[edge.Length * orth.Length]; int index = 0; foreach (int orthIndex in orth.Iterate()) { int x = -1; int y = -1; orth.Set2DIndex(ref x, ref y, orthIndex); foreach (int edgeIndex in edge.Iterate()) { edge.Set2DIndex(ref x, ref y, edgeIndex); retVal[index] = values[(y * width) + x]; index++; } } return new Convolution2D(retVal, edge.Length, orth.Length, false); }
/// <summary> /// For each pixel in this row, pick a random pixel from a box above /// </summary> /// <remarks> /// At each pixel, this draws from a box of size orthDepth x (edgeDepth*2)+1 /// </remarks> /// <param name="orthIndex">The row being copied to</param> private static void CopyRandomPixels(double[] values, int width, int orthIndex, int orthInc, int orthDepth, int edgeDepth, AxisFor orth, AxisFor edge, Random rand) { // See how many rows to randomly pull from int orthDepthStart = orthIndex + orthInc; int orthDepthStop = orthIndex + (orthDepth * orthInc); UtilityCore.MinMax(ref orthDepthStart, ref orthDepthStop); int orthAdd = orthInc < 0 ? 1 : 0; foreach (int edgeIndex in edge.Iterate()) { // Figure out which column to pull from int toEdge = -1; do { toEdge = rand.Next(edgeIndex - edgeDepth, edgeIndex + edgeDepth + 1); } while (!edge.IsBetween(toEdge)); // Figure out which row to pull from int toOrth = rand.Next(orthDepthStart, orthDepthStop) + orthAdd; // From XY int fromX = -1; int fromY = -1; orth.Set2DIndex(ref fromX, ref fromY, toOrth); edge.Set2DIndex(ref fromX, ref fromY, toEdge); // To XY int toX = -1; int toY = -1; orth.Set2DIndex(ref toX, ref toY, orthIndex); edge.Set2DIndex(ref toX, ref toY, edgeIndex); // Copy pixel values[(toY * width) + toX] = values[(fromY * width) + fromX]; } }
//TODO: Implement this properly private static void ExtendCorner(double[] values, int width, AxisFor orth, AxisFor edge) { Random rand = StaticRandom.GetRandomForThread(); foreach (int edgeIndex in edge.Iterate()) { foreach (int orthIndex in orth.Iterate()) { int x = -1; int y = -1; orth.Set2DIndex(ref x, ref y, orthIndex); edge.Set2DIndex(ref x, ref y, edgeIndex); values[(y * width) + x] = rand.Next(256); } } }
private static void ExtendEdge(double[] values, int width, int orthHeight, AxisFor orth, AxisFor edge) { const int EDGEDEPTH = 4; int ORTHDEPTH = Math.Min(5, orthHeight) + 1; const int EDGEMIDOFFSET = 5; // This isn't worth implementing, you just get a pixelated band //const int GAUSSOPACITYDIST = 1; // how many pixels before the gaussian is full strength Random rand = StaticRandom.GetRandomForThread(); Convolution2D gauss = Convolutions.GetGaussian(3); // Figure out which direction to copy rows from int orthInc = GetOrthIncrement(orth); #region Edge midpoint range // Each row, a random midpoint is chosen. This way, an artifact won't be created down the middle. // mid start and stop are the range of possible values that the random midpoint can be from int edgeMidStart = edge.Start; int edgeMidStop = edge.Stop; UtilityCore.MinMax(ref edgeMidStart, ref edgeMidStop); edgeMidStart += EDGEMIDOFFSET; edgeMidStop -= EDGEMIDOFFSET; #endregion foreach (int orthIndex in orth.Iterate()) { CopyRandomPixels(values, width, orthIndex, orthInc, ORTHDEPTH, EDGEDEPTH, orth, edge, rand); OverlayBlurredPixels(values, width, orthHeight, orthIndex, orthInc, edgeMidStart, edgeMidStop, orth, edge, gauss, /*GAUSSOPACITYDIST,*/ rand); } }