Jump to content

pascal

Members
  • Posts

    17
  • Joined

  • Last visited

  • Days Won

    3

Posts posted by pascal

  1. Version 2 available!

    Added some extra features.

    - Now contains more properties to sort on, including complete randomness.  It includes all of the following: RGB, Red, Green, Blue, Alpha, Hue, Saturation, Value, Lightness, Luma, Minimum and Random. The previous Value setting is now RGB, with the current Value being the value of the pixel's HSV color.

    - Added Edge detection as an extra interval function besides Threshold. This can be used to keep the overall shapes of objects in the image.

    - Re-ordered the UI

    • Like 2
    • Upvote 2
  2. Pixel Sort

     

    This plugin can be used to create a glitchy effect by sorting pixels.

    - Use the interval parameters to change the intensity of the effect.

    - It can sort in either horizontal or vertical direction.

    - It can sort based on multiple properties, such as value, hue, saturation or individual color channels.

    Note: if multiple pixels have the same property, the order might appear to be random.

     

    demo2.jpg.261c8a383d14d07b9c6d8bad9a0e0fd0.jpg

     

    Download

    Located in: Effects > Distort > Pixel Sort

    PixelSort.zip

     

    Code

    Spoiler
    #region UICodes
    ListBoxControl<Sorter> SORTER = 0; // Sorter|RGB
    ListBoxControl<Direction> DIRECTION = 0; // Direction|Row
    IntSliderControl MIN = 60; // [0,255] Interval min
    IntSliderControl MAX = 180; // [0,255] Interval max
    ListBoxControl<Interval> INTERVAL = 0; // Interval|Threshold|Edge detection
    CheckboxControl INVERT = false; // Invert interval
    CheckboxControl FLIP = false; // {!RANDOM} Flip sorting order
    CheckboxControl RANDOM = false; // Random sorting order
    ReseedButtonControl SEED = 0; // {RANDOM} Reseed
    #endregion
    
    private enum Sorter { RGB, Red, Green, Blue, Alpha, Hue, Saturation, Value, Lightness, Luma, Minimum, Random }
    private enum Direction { Row, Column }
    private enum Interval { Threshold, Edge }
    private readonly Comparer<Vector2Int32> comparer = Comparer<Vector2Int32>.Create((a, b) => a.Y.CompareTo(b.Y));
    private bool[,] mask = null;
    private int[,] sortMap = null;
    private Random random = null;
    
    public void PreRender(Surface dst, Surface src)
    {
        Rectangle selection = EnvironmentParameters.SelectionBounds;
        Surface wrk = new Surface(selection.Size);
        Surface wrkDst = new Surface(wrk.Size);
        wrk.CopySurface(src, selection);
        wrkDst.CopySurface(wrk);
    
        this.random = new Random(SEED);
        this.mask = GetIntervalMask(wrk, MIN, MAX, INTERVAL);
        Func<ColorBgra, int> mapper = GetMapper(SORTER);
        this.sortMap = GetSortMap(wrk, mapper, FLIP);
        Action<Surface, Surface>[] actions = DIRECTION switch {
            Direction.Row => GetSortActionsX(wrk.Height),
            _ => GetSortActionsY(wrk.Width)
        };
        
        System.Threading.Tasks.Parallel.ForEach(actions, action =>
        {
            if (IsCancelRequested) return;
            action(wrk, wrkDst);
        });
    
        dst.CopySurface(wrkDst, selection.Location);
    }
    
    
    private Func<ColorBgra, int> GetMapper(Sorter sorter)
    {
        Func<ColorBgra, int> result = sorter switch
        {
            Sorter.Red => c => c.R,
            Sorter.Green => c => c.G,
            Sorter.Blue => c => c.B,
            Sorter.Hue => c => HsvColor.FromColor(c.ToColor()).Hue,
            Sorter.Saturation => c => HsvColor.FromColor(c.ToColor()).Saturation,
            Sorter.Alpha => c => c.A,
            Sorter.Value => Value,
            Sorter.Lightness => Lightness,
            Sorter.Luma => Luma,
            Sorter.Minimum => Minimum,
            Sorter.Random => c => random.Next(),
            _ => Average
        };
        return result;
    }
    
    
    private Action<Surface, Surface>[] GetSortActionsX(int rows)
    {
        var actions = new Action<Surface, Surface>[rows];
        for (int y = 0; y < rows; y++)
        {
            int tmp = y;
            actions[y] = (s, d) => SortRow(s, d, tmp);
        }
        return actions;
    }
    
    
    private Action<Surface, Surface>[] GetSortActionsY(int columns)
    {
        var actions = new Action<Surface, Surface>[columns];
        for (int x = 0; x < columns; x++)
        {
            int tmp = x;
            actions[x] = (s, d) => SortColumn(s, d, tmp);
        }
        return actions;
    }
    
    
    private void SortRow(Surface src, Surface dst, int y)
    {
        for (int x = 0; x < src.Width;)
        {
            int start = NextTrueX(x, y, src.Width);
            int end = NextFalseX(start, y, src.Width);
            if (IsCancelRequested) return;
            if (start < end - 1)
            {
                SortRowSection(y, start, end, src, dst);
            }
            x = end + 1;
        }
    }
    
    
    private void SortColumn(Surface src, Surface dst, int x)
    {
        for (int y = 0; y < src.Height;)
        {
            int start = NextTrueY(x, y, src.Height);
            int end = NextFalseY(x, start, src.Height);
            if (IsCancelRequested) return;
            if (start < end - 1)
            {
                SortColumnSection(x, start, end, src, dst);
            }
            y = end + 1;
        }
    }
    
    
    private int NextTrueX(int x, int y, int maxX)
    {
        while (!mask[x,y])
        {
            x++;
            if (x >= maxX)
            {
                return maxX - 1;
            }
        }
        return x;
    }
    
    
    private int NextFalseX(int x, int y, int maxX)
    {
        while (mask[x,y])
        {
            x++;
            if (x >= maxX)
            {
                return maxX;
            }
        }
        return x;
    }
    
    
    private int NextTrueY(int x, int y, int maxY)
    {
        while (!mask[x,y])
        {
            y++;
            if (y >= maxY)
            {
                return maxY - 1;
            }
        }
        return y;
    }
    
    
    private int NextFalseY(int x, int y, int maxY)
    {
        while (mask[x,y])
        {
            y++;
            if (y >= maxY)
            {
                return maxY;
            }
        }
        return y;
    }
    
    
    private bool[,] GetIntervalMask(Surface src, int min, int max, Interval interval)
    {
        return interval switch {
            Interval.Edge => GetEdgeMask(src, min, max),
            _ => GetThresholdMask(src, min, max)
        };
    }
    
    private bool[,] GetThresholdMask(Surface src, int min, int max)
    {
        bool[,] result = new bool[src.Width, src.Height];
        min *= 3; max *= 3;
    
        for (int y = 0; y < src.Height; y++)
        {
            for (int x = 0; x < src.Width; x++)
            {
                float l = Average(src[x,y]);
                result[x,y] = (min <= l && l <= max) ^ INVERT;
            }
        }
    
        return result;
    }
    
    private bool[,] GetEdgeMask(Surface src, int min, int max)
    {
        bool[,] result = new bool[src.Width, src.Height];
    
        for (int y = 0; y < src.Height; y++)
        {
            for (int x = 0; x < src.Width; x++)
            {
                if (!src.Bounds.Contains(x + 1, y + 1))
                {
                    result[x,y] = (min <= 127 && 127 <= max) ^ INVERT;
                    continue;
                }
    
                ColorBgra cp = src[x,y];
                ColorBgra np = src[x + 1, y + 1];
                int r = np.R - cp.R;
                int g = np.G - cp.G;
                int b = np.B - cp.B;
                int mx = Math.Max(Math.Max(r, g), b);
                int mn = Math.Min(Math.Min(r, g), b);
                int m = Math.Abs(mn) > Math.Abs(mx) ? mn : mx;
                int l = Math.Clamp(127 + m * 3, 0, 255);
    
                result[x,y] = (min <= l && l <= max) ^ INVERT;
            }
        }
    
        return result;
    }
    
    
    private void SortRowSection(int y, int x0, int x1, Surface src, Surface dst)
    {
        int size = x1 - x0;
        Vector2Int32[] array = new Vector2Int32[size];
        for (int x = x0; x < x1; x++)
        {
            array[x - x0] = new Vector2Int32(x, this.sortMap[x, y]);
        }
    
        if (RANDOM && random.Next(0, 2) == 0) Array.Sort(array, Reverse(comparer));
        else Array.Sort(array, comparer);
    
        if (IsCancelRequested) return;
    
        for (int x = x0; x < x1; x++)
        {
            Vector2Int32 p = array[x - x0];
            dst[x, y] = src[p.X, y];
        }
    }
    
    
    private void SortColumnSection(int x, int y0, int y1, Surface src, Surface dst)
    {
        int size = y1 - y0;
        Vector2Int32[] array = new Vector2Int32[size];
        for (int y = y0; y < y1; y++)
        {
            array[y - y0] = new Vector2Int32(y, this.sortMap[x, y]);
        }
    
        if (RANDOM && random.Next(0, 2) == 0) Array.Sort(array, Reverse(comparer));
        else Array.Sort(array, comparer);
    
        if (IsCancelRequested) return;
    
        for (int y = y0; y < y1; y++)
        {
            Vector2Int32 p = array[y - y0];
            dst[x, y] = src[x, p.X];
        }
    
    }
    
    
    private int[,] GetSortMap(Surface src, Func<ColorBgra, int> mapper, bool flip)
    {
        var result = new int[src.Width, src.Height];
        for (int y = 0; y < src.Height; y++)
        {
            for (int x = 0; x < src.Width; x++)
            {
                int val = mapper(src[x,y]);
                if (flip) val = -val;
                result[x,y] = val;
            }
        }
        return result;
    }
    
    
    private int Average(ColorBgra c)
    {
        return c.R + c.G + c.B;
    }
    
    private int Lightness(ColorBgra c)
    {
        return Value(c) + Minimum(c);
    }
    
    private int Value(ColorBgra c)
    {
        return Math.Max(c.R, Math.Max(c.G, c.B));
    }
    
    private int Minimum(ColorBgra c)
    {
        return Math.Min(c.R, Math.Min(c.G, c.B));
    }
    
    private int Luma(ColorBgra c)
    {
        return 2126 * c.R + 7152 * c.G + 722 * c.B;
    }
    
    
    private Comparer<T> Reverse<T>(Comparer<T> comp)
    {
        return Comparer<T>.Create((a, b) => comp.Compare(b, a));
    }
    
    
    public void Render(Surface dst, Surface src, Rectangle rect) {}

     

    • Like 2
    • Thanks 1
    • Upvote 2
  3. Smooth Julia Fractal

    This plugin is able to render any fractal from the Julia set. As opposed to my previous plugin Advanced Julia Fractal, this new plugin makes use of normalized iteration counting to blend smoothly between colors. Increasing Iterations and Quality will result in a high quality fractal. The exposure controls can be used to fix the brightness. As always, you can use my other plugin Duotone Gradient Mapping to add coloring.

     

    sample.jpg.49038985f5016f64b912401d9a597f96.jpg

    Download

    Located in: Effects > Render > Smooth Julia Fractal

    smoothfractal.zip

     

    Code

    Spoiler
    #region UICode
    DoubleSliderControl CONSTANT_A = 0; // [-2,2] Real constant
    DoubleSliderControl CONSTANT_B = 0; // [-2,2] Imaginary constant
    DoubleSliderControl ZOOM = 20; // [1,1000] Zoom
    DoubleSliderControl OFFSET_X = 0; // [-2,2] Offset X
    DoubleSliderControl OFFSET_Y = 0; // [-2,2] Offset Y
    IntSliderControl ITER = 100; // [1,500] Iterations
    DoubleSliderControl MIN_V = 0.0; // [-10.0, 0.0] Min exposure
    DoubleSliderControl MAX_V = 1.0; // [0.001, 100.0] Max exposure
    IntSliderControl QUALITY = 0; // [0,5] Quality
    #endregion
    
    void Render(Surface dst, Surface src, Rectangle rect)
    {
        Rectangle selection = EnvironmentParameters.SelectionBounds;
        ColorBgra currentPixel;
        int samples = 1 + QUALITY * 2;
        int qmin = -(samples / 2);
        int qmax = samples + qmin;
        double zoom = ZOOM * ZOOM;
        double multiplier = (MAX_V - MIN_V) * 255.0 / (double) (samples * ITER);
        double min = MIN_V * 255.0;
    
        double[] sampleOffsets = new double[samples];
        for (int i = 0; i < samples; i++)
        {
            sampleOffsets[i] = (i + qmin) / (samples * zoom);
        }
    
        for (int y = rect.Top; y < rect.Bottom; y++)
        {
            if (IsCancelRequested) return;
            for (int x = rect.Left; x < rect.Right; x++)
            {
                currentPixel = src[x,y];
                
                double value = 0.0;
                double fx = (x - selection.Left - selection.Width / 2.0) / zoom;
                double fy = (y - selection.Top - selection.Height / 2.0) / zoom;
    
                foreach (double offset in sampleOffsets)
                {
                    double newX = fx + offset + OFFSET_X;
                    double newY = fy + offset + OFFSET_Y;
    
                    value += smoothFractalValue(newX, newY, ITER);
                }
    
                double mapped = value * multiplier + min;
                byte lightness =  (byte) Math.Clamp(mapped, 0.0, 255.0);
    
                currentPixel.R = lightness;
                currentPixel.G = lightness;
                currentPixel.B = lightness;
                
                dst[x,y] = currentPixel;
            }
        }
    }
    
    
    double smoothFractalValue(double a, double b, int n)
    {
        double smoothValue = 0.0;
        
        for (int i = 0; i < n && a * a + b * b < 8.0; i++)
        {
            double p = a;
            a = a * a - b * b + CONSTANT_A;
            b = 2 * p * b + CONSTANT_B;
    
            smoothValue += Math.Exp(-Math.Sqrt(a * a + b * b));
        }
    
        return smoothValue;
    }

     

    • Like 2
    • Upvote 2
  4. Version 5 available

    - The new version is more accurate than before. It converts the RGB values to the LMS color space and takes gamma correction into account.

    - Protanomaly, deuteranomaly, tritanomaly and achromatomaly are removed from the plugin because those were just blending between normal vision and the corresponding deficiency.

    - The deficiency 'Blue-Cone Monochromacy' was added as a second type of monochromacy.

    • Like 2
    • Upvote 1
  5. Hi,

    I recently wanted to edit a post and change some attachments in that post. However, it tells me the maximum amount of attachments for that post has been reached, even though I removed all of the attachments in the post. It also gives me a link to see all the attachments I have ever uploaded, but there seems to be no option to delete any attachments. On top of that, it says the specific attachments are still in the post, even though this is not the case.

    Is there a way I can remove any of my unused or old attachments?

    • Like 1
  6. Hello.

    This plugin can be used to generate a Voronoi texture. It comes with color options, different render options and some other settings that I considered to be useful.

     

     voronoi.zip

    The plugin can be found in Effects > Render > Voronoi

     

    Preview

    demo1.jpg.a8c6b72593688d4e95cb8f95fe7b00c8.jpgdemo2.jpg.10aebd1c0481ba2488305ab03eb5108e.jpgdemo3.jpg.6fc26e28567d37a6b9803006b27da22a.jpgdemo4.jpg.2bb5eee2f03c25cdf1ab67cbbaf964fa.jpgdemo5.jpg.32a782558262bd2a9f7ad9c47319242c.jpg

     

    Code

    Spoiler
    // Name: Voronoi
    // Submenu: Render
    // Author: pascal
    // Title: Render Voronoi
    // Version: 1.0
    // Desc: Generate a Voronoi texture
    // Keywords:
    // URL:
    // Help:
    #region UICode
    ColorWheelControl col1 = ColorBgra.FromBgr(0,0,0); // Cell Color
    ColorWheelControl col2 = ColorBgra.FromBgr(255,255,255); // Line Color
    ListBoxControl mode = 0; // Mode|Cells|Lines|Crystals|Solid
    IntSliderControl amount = 15; //[1,100] Count
    IntSliderControl size = 200; //[1,1000] Size
    IntSliderControl detail = 0; //[0,5] Detail
    IntSliderControl bright = 0; //[-100,100] Bias
    IntSliderControl contr = 0; //[-100,100] Contrast
    IntSliderControl seed = 0; //[0,1000] Seed
    #endregion
    
    //global variables
    tile[,] tiles;
    Rectangle bnds;
    int tilesize;
    int cols, rows;
    
    
    void PreRender(Surface dst, Surface src)
    {
        bnds = EnvironmentParameters.SelectionBounds;
    
        //divide canvas into tiles
        tilesize = (int)Math.Ceiling(bnds.Width / (float)amount);
        cols = amount + 4;
        rows = (int)Math.Ceiling(bnds.Height * amount / (float)bnds.Width) + 4;
        tiles = new tile[cols, rows];
    
        //generate random point for each tile and store tile
        for(int i = 0; i < cols; i++)
        {
            for(int j = 0; j < rows; j++)
            {
                Random random = new Random(seed++*(j+1)*(i+1));
                int tleft = (i-2)*tilesize;
                int tright = (i-1)*tilesize;
                int ttop = (j-2)*tilesize;
                int tbottom = (j-1)*tilesize;
                int randx = random.Next(tleft,tright);
                int randy = random.Next(ttop,tbottom);
    
                rect tilebounds = new rect(tleft,tright,ttop,tbottom);
                tile t = new tile(tilebounds,new point(randx, randy));
                tiles[i,j] = t;
            }
        }
    }
    
    
    void Render(Surface dst, Surface src, Rectangle rect)
    {
        for(int y = rect.Top; y < rect.Bottom; y++)
        {
            for(int x = rect.Left; x < rect.Right; x++)
            {
    
                //get the corresponding tile index
                int ix = clamp(x / tilesize + 2, 2, cols - 4);
                int iy = clamp(y / tilesize + 2, 2, rows - 4);
                var points = new point[25];
    
                //get the 25 nearest points based on the surrounding tiles
                for(int i = -2; i <= 2; i++)
                {
                    for(int j = -2; j <= 2; j++)
                    {
                        tile currentTile = tiles[ix + i, iy + j];
                        points[(i + 2) + 5 * (j + 2)] = currentTile.point;
                    }
                }
    
                //calculate the distance to each point
                int[] dist = new int[points.Count()];
                for(int i = 0; i < dist.Count(); i++)
                {
                    int diffX = points[i].x - x;
                    int diffY = points[i].y - y;
                    dist[i] = diffX*diffX + diffY*diffY;
                }
                //sort the distances and store each index in idx[]
                int[] idx = Enumerable.Range(0, dist.Count()).ToArray();
                Array.Sort<int>(idx, (a, b) => dist[a].CompareTo(dist[b]));
    
                double col = 0;
    //LINE MODE
                if(mode == 1)
                {
                    //get 3 nearest points
                    var p1 = points[idx[detail]];
                    var p2 = points[idx[detail+1]];
                    var p3 = points[idx[detail+2]];
                    
                    //main line
                    double distanceSquared = distanceToMidLine(x, y, p1, p2);
                    if(distanceSquared <= size/50.0)
                    {
                        //smooth line edges
                        col = Math.Max(col, map((float)distanceSquared, size/50f, 0, 0, 1));
                    }
                    
                    //fill in gaps in some lines
                    distanceSquared = distanceToMidLine(x, y, p1, p3);
                    if(distanceSquared <= size/50.0)
                    {
                        col = Math.Max(col, map((float)distanceSquared, size/50f, 0, 0, 1));
                    }
    
                    //round line ends
                    var e = midPoint(p1, p2, p3);
                    double distToEndSquared = (e.x - x) * (e.x - x) + (e.y - y) * (e.y - y);
                    if(distToEndSquared <= size/50.0)
                    {
                        //draw circle at line edge
                        col = Math.Max(col, map(distToEndSquared, size/50.0, 0, 0, 1));
                    } 
                }
    //CRYSTAL MODE
                else if(mode == 2)
                {
                    //closest 2 points
                    var p1 = points[idx[detail]];
                    var p2 = points[idx[detail+1]];
                    int dist1 = (p1.x - x) * (p1.x - x) + (p1.y - y) * (p1.y - y);
                    int dist2 = (p2.x - x) * (p2.x - x) + (p2.y - y) * (p2.y - y);
                    //difference in distance
                    int diff = dist2 - dist1;
                    col = 1f - Math.Max(0, Math.Min(1, diff / 25f / size));
                }
    //SOLID MODE
                else if (mode == 3)
                {
                    //get closest point
                    var p1 = points[idx[detail]];
                    //random value with closest point as seed
                    Random random = new Random(p1.x * p1.y);
                    float diff = (float)random.NextDouble();
                    col = Math.Max(0, Math.Min(1, diff));
                }
    //CELLS MODE
                else
                {
                    //get closest point
                    var p = points[idx[detail]];
                    //calculated distance squared
                    int distX = p.x - x;
                    int distY = p.y - y;
                    int diff = distX*distX + distY*distY;
                    //value based on distance
                    col = Math.Max(0, Math.Min(1, diff / 25f / size));
                }
    
                //apply bias (brightness) and contrast
                col = brightness(col, bright/100f);
                col = contrast(col, contr/50f);
                //calculate color values
                byte R = limit(col*col2.R + (1f-col)*col1.R);
                byte G = limit(col*col2.G + (1f-col)*col1.G);
                byte B = limit(col*col2.B + (1f-col)*col1.B);
                dst[x, y] = ColorBgra.FromBgr(B, G, R);
            }
        }
    }
    
    
    byte limit(double val)
    {
        //limit byte between 0 and 255
        return Math.Max((byte)0, Math.Min((byte)255, (byte)val));
    }
    
    
    int clamp(int val, int min, int max)
    {
        //clamp value between min and max
        return Math.Max(min, Math.Min(val, max));
    }
    
    
    double map(double val, double min0, double max0, double min1, double max1)
    {
        //map value to a new domain
        return min1 + (val - min0) / (max0 - min0) * (max1 - min1);
    }
    
    
    double brightness(double val, double bri)
    {
        //apply a brightness effect to the value
        if(bri == 0f) return val;
        if(bri > 0)
        {
            return 1 - Math.Pow(1 - val, 1 + bri);
        }
        else
        {
            return Math.Pow(val, 1 - bri);
        }
    }
    
    
    double contrast(double val, double con)
    {
        //apply a contrast effect to the value
        if(con == 0f) return val;
        if(con > 0)
        {
            if(val < 0.5)
            {
                return Math.Pow(2 * val, 1 + con) / 2.0;
            }
            else
            {
                return 1 - Math.Pow(-2 * val + 2, 1 + con) / 2.0;
            }
        }
        else
        {
            if(val < 0.5)
            {
                return 0.5 - Math.Pow(-2 * val + 1, 1 - con) / 2.0;
            }
            else
            {
                return 0.5 + Math.Pow(2 * val - 1, 1 - con) / 2.0;
            }
        }
    }
    
    
    point midPoint(point p1, point p2, point p3)
    {
        //matrix calculations to find the midpoint of a circle through 3 points
        int m1 = (p1.x * p1.x + p1.y * p1.y);
        int m2 = (p2.x * p2.x + p2.y * p2.y);
        int m3 = (p3.x * p3.x + p3.y * p3.y);
        int xm1 =
            m1 * p2.y + m2 * p3.y + m3 * p1.y -
            m1 * p3.y - m2 * p1.y - m3 * p2.y;
        int xm2 =
            p1.x * p2.y + p2.x * p3.y + p3.x * p1.y -
            p1.x * p3.y - p2.x * p1.y - p3.x * p2.y;
        int x = (int)(xm1 / (float)xm2 / 2f);
        int ym1 =
            m1 * p2.x + m2 * p3.x + m3 * p1.x -
            m1 * p3.x - m2 * p1.x - m3 * p2.x;
        int y = (int)(ym1 / (float)xm2 / -2f);
        return new point(x, y);
    }
    
    
    double distanceToMidLine(int x, int y, point p1, point p2)
    {
        //calculate middle point
        double mx = (p1.x + p2.x) / 2.0;
        double my = (p1.y + p2.y) / 2.0;
        if(p1.x == p2.x) return (y - my) * (y - my);
        if(p1.y == p2.y) return (x - mx) * (x - mx);
        //generate line
        double a = (p2.x - p1.x) / (double)(p2.y - p1.y);
        double b = my + a * mx;
        //calculate distance form pixel to line
        double top = (a * x + y - b);
        return top * top / (a * a + 1);
    }
    
    
    class rect
    {
        public int left, right, top, bottom;
    
        public rect(int l, int r, int t, int b)
        {
            left = l;
            right = r;
            top = t;
            bottom = b;
        }
    }
    
    
    class point
    {
        public int x, y;
    
        public point(int a, int b)
        {
            x = a;
            y = b;
        }
    }
    
    
    class tile
    {
        public rect bounds;
        public point point;
    
        public tile(rect b, point p)
        {
            bounds = b;
            point = p;
        }
    }

     

    • Like 2
    • Upvote 2
  7. Hello.

    It has been a while, but I'm back with another plugin: Perlin Waves.

    This plugin uses Perlin noise to generate a wave texture. It comes with a lot of configurable options.

    I hope you like it!

     

    Download: perlinwaves.zip

    11-11-2021 update: bug fix and changed alpha settings

    Effect can be found in Effects > Render > Perlin Waves

     

    Preview:

    demo2.jpg.09948a522b9287bdb44a8401aeb7a044.jpg

     

    Code:

    A part of the code comes from this Perlin noise implementation

    Spoiler
    // Name: Perlin Waves
    // Submenu: Render
    // Author: pascal
    // Title: Generate Perlin Waves
    // Version: 1.0
    // Desc:
    // Keywords:
    // URL:
    // Help:
    #region UICode
    ColorWheelControl col1 = ColorBgra.FromBgr(0, 0, 0); // Line Color
    ColorWheelControl col2 = ColorBgra.FromBgr(255, 255, 255); // Background Color
    IntSliderControl zoom = 50; // [1,200] Zoom
    IntSliderControl rotate = 0; // [0,1000] Move
    IntSliderControl width = 10; // [1,1000] Thickness
    IntSliderControl seed = 1; // [1,1000] Seed
    IntSliderControl smooth = 2; // [0,2] Interpolation
    IntSliderControl height = 50; // [0,100] Height
    IntSliderControl contr = 0; // [0,100] Contrast
    ListBoxControl alpha = 0; // Alpha Mode|Overlay|Preserve|Preserve Inverted|Transparent|Transparent Inverted|Blend|Blend Inverted|Clip|Clip Inverted
    #endregion
    
    
    class vector{
        public float x;
        public float y;
    }
    
    
    void Render(Surface dst, Surface src, Rectangle rect)
    {
        for(int y = rect.Top; y < rect.Bottom; y++)
        {
            for(int x = rect.Left; x < rect.Right; x++)
            {
                if(IsCancelRequested) return;
    
                float val = (perlin(x / (float)zoom, y / (float)zoom) + 1) / 2f;
                float col = 0;
                float w = width / 1000f;
                float h = contrastR(height / 100f, 2);
    
                if(val > h - w && val < h + w)
                {
                    if(val < h)
                    {
                        col = contrast(map(val, h - w, h, 0, 1), contr * contr / 100f);
                    }
                    else
                    {
                        col = contrast(map(val, h + w, h, 0, 1), contr * contr / 100f);
                    }
                }
    
                ColorBgra cp = new ColorBgra();
                cp.R = limit(col * col1.R + (1 - col) * col2.R);
                cp.G = limit(col * col1.G + (1 - col) * col2.G);
                cp.B = limit(col * col1.B + (1 - col) * col2.B);
    
                switch(alpha)
                {
                    case 1:
                    cp.A = src[x, y].A;
                    break;
                    case 2:
                    cp.A = limit(255-src[x, y].A);
                    break;
                    case 3:
                    cp = col1;
                    cp.A = limit(col * 255);
                    break;
                    case 4:
                    cp = col2;
                    cp.A = limit((1 - col) * 255);
                    break;
                    case 5:
                    cp = col1;
                    cp.A = limit(col * 255);
                    cp = blend(cp, src[x, y]);
                    break;
                    case 6:
                    cp = col2;
                    cp.A = limit((1 - col) * 255);
                    cp = blend(cp, src[x, y]);
                    break;
                    case 7:
                    cp = col1;
                    cp.A = limit(col * src[x, y].A);
                    break;
                    case 8:
                    cp = col2;
                    cp.A = limit((1 - col) * src[x, y].A);
                    break;
                    default:
                    cp.A = (byte)255;
                    break;
                }
    
                dst[x, y] = cp;
            }
        }
    }
    
    
    byte limit(float x)
    {
        return (byte)Math.Max(0, Math.Min(255, x));
    }
    
    
    float map(float val, float min0, float max0, float min1, float max1)
    {
        return min1 + (val - min0) / (max0 - min0) * (max1 - min1);
    }
    
    
    float contrast(float val, float con)
    {
        if(val < 0.5)
        {
            return (float)(Math.Pow(2 * val, 1 + con) / 2);
        }
        else
        {
            return (float)(1 - Math.Pow(-2 * val + 2, 1 + con) / 2);
        }
    
    }
    
    
    float contrastR(float val, float con)
    {
        if(con == 0f) return val;
        if(val < 0.5)
        {
            return (float)(0.5 - Math.Pow(-2 * val + 1, 1 + con) / 2);
        }
        else
        {
            return (float)(0.5 + Math.Pow(2 * val - 1, 1 + con) / 2);
        }
    }
    
    
    ColorBgra blend(ColorBgra a, ColorBgra b)
    {
        if(a.A == 0 && b.A == 0) return ColorBgra.FromBgra(0, 0, 0, 0);
    
        float alpha = a.A / 255f;
        float alphaB = b.A / 255f;
        float alpha0 = alpha + alphaB * (1 - alpha);
    
        byte R = limit((a.R * alpha + b.R * alphaB * (1 - alpha)) / alpha0);
        byte G = limit((a.G * alpha + b.G * alphaB * (1 - alpha)) / alpha0);
        byte B = limit((a.B * alpha + b.B * alphaB * (1 - alpha)) / alpha0);
        byte A = limit(alpha0 * 255);
    
        return ColorBgra.FromBgra(B, G, R, A);
    }
    
    
    vector randomGradient(int ix, int iy)
    {
        uint w = (uint)seed;
        uint s = w / 2;
        uint a = (uint)ix; uint b = (uint)iy;
        a *= 3284157443; b ^= a << (int) s | a >> (int)(w - s);
        b *= 1911520717; a ^= b << (int) s | b >> (int)(w - s);
        a *= 2048419325;
        float random = (float)(a * (3.14159265 / ~(~0u >> 1)) + rotate / 1000f * Math.Tau);
        vector v = new vector();
        v.x = (float)Math.Sin(random);
        v.y = (float)Math.Cos(random);
        return v;
    }
    
    
    float dotGridGradient(int ix, int iy, float x, float y)
    {
        vector gradient = randomGradient(ix, iy);
        float dx = x - (float)ix;
        float dy = y - (float)iy;
        return (dx*gradient.x + dy*gradient.y);
    }
    
    
    float interpolate(float a0, float a1, float w)
    {
        if (0.0 > w) return a0;
        if (1.0 < w) return a1;
        switch(smooth){
            case 0:
                return (float)((a1 - a0) * w + a0);
            case 1:
                return (float)((a1 - a0) * (3.0 - w * 2.0) * w * w + a0);
            default:
                return (float)((a1 - a0) * ((w * (w * 6.0 - 15.0) + 10.0) * w * w * w) + a0);
        } 
    }
    
    
    float perlin(float x, float y)
    {
        int x0 = (int)x;
        int x1 = x0 + 1;
        int y0 = (int)y;
        int y1 = y0 + 1;
    
        float sx = x - (float)x0;
        float sy = y - (float)y0;
    
        float n0, n1, ix0, ix1, value;
    
        n0 = dotGridGradient(x0, y0, x, y);
        n1 = dotGridGradient(x1, y0, x, y);
        ix0 = interpolate(n0, n1, sx);
    
        n0 = dotGridGradient(x0, y1, x, y);
        n1 = dotGridGradient(x1, y1, x, y);
        ix1 = interpolate(n0, n1, sx);
    
        value = interpolate(ix0, ix1, sy);
        return value;
    }

     

    • Like 3
    • Thanks 1
    • Upvote 3
  8. This plugin can be used to render Julia set fractals using a variety of settings. Adding color options would have made the UI too big, but it can be achieved using my Duotone Gradient Mapping plugin.

    I hope you enjoy this one!

     

    Download:

     Advanced Julia Fractal.zip

    Can be found in Effects > Render > Advanced Julia Fractal

     

    Previews:

    1135822739_ajfdemo3.jpg.bfd546537346501184ebcc9428c2e8c8.jpg

     510867675_ajfdemo.jpg.07ed616f59e563f0ddb5eed18490d125.jpg17228949_ajfdemo2.jpg.9e20193e9e7c9b761de0a86cb04ad033.jpg

    Code:

    (Made in a few hours, so there is probably a lot to improve)

    // Name: Advanced Julia Fractal
    // Submenu: Render
    // Author: Pascal
    // Title: Advanced Julia Fractal
    // Version: 1.0.0
    // Desc:
    // Keywords:
    // URL:
    // Help:
    #region UICode
    IntSliderControl ca = 0; //[-300,300] Real part of constant
    IntSliderControl cb = 0; //[-300,300] Imaginary part of constant
    IntSliderControl zoom = 5000; // [1,100000] Zoom
    IntSliderControl xoff = 0; // [-10000,10000] Offset X
    IntSliderControl yoff = 0; // [-10000,10000] Offset Y
    IntSliderControl iterations = 50; //[1,200] Iterations
    IntSliderControl type = 0; //[0,3] Render type
    CheckboxControl innerCol = false; //Inner color
    CheckboxControl invert = false; //Invert
    CheckboxControl trans = false; //Transparency
    CheckboxControl invertTrans = false; //Invert Transparency
    IntSliderControl thresh = 0; //[0,1000] Clean
    IntSliderControl bright = 0; //[-100,100] Brightness
    IntSliderControl contr = 0; //[0,100] Contrast
    CheckboxControl alpha = false; //Preserve alpha
    #endregion
    
    public void Render(Surface dst, Surface src, Rectangle rect)
    {
        Rectangle selection = EnvironmentParameters.SelectionBounds;
        int sw = selection.Right-selection.Left;
        int sh = selection.Bottom-selection.Top;
        int dw = selection.Left;
        int dh = selection.Top;
    
        ColorBgra CurrentPixel;
        for (int y = rect.Top; y < rect.Bottom; y++)
        {
            if (IsCancelRequested) return;
            for (int x = rect.Left; x < rect.Right; x++)
            {
                if (IsCancelRequested) return;
                CurrentPixel = src[x,y];
                
                double a = x-dw;
                double b = y-dh;
                double ca = this.ca/100f;
                double cb = this.cb/200f;
                double dx = (double)xoff;
                double dy = (double)yoff;
                double zoom = Math.Pow(this.zoom/100000f,2)*100000f;
                float val = fractal(
                    (a-sw/2)/zoom + dx/10000f,
                    (b-sh/2)/zoom + dy/10000f,
                    ca,
                    cb,
                    iterations,
                    type
                );
    
                double thresh = this.thresh/1000f;
                if(val<thresh || innerCol && val >= (iterations-1)/(float)iterations){
                    val=0;
                }
    
                if(invert){
                    val = 1-val;
                }
    
                val+= bright/100f;
                val = limit(val,0,1);
                val = contrast(val,contr);
                val = limit(val,0,1);
    
                CurrentPixel.R = (byte)limit(val*255,0,255);
                CurrentPixel.G = (byte)limit(val*255,0,255);
                CurrentPixel.B = (byte)limit(val*255,0,255);
    
                byte A = CurrentPixel.A;
                CurrentPixel.A = 255;
                if(trans){
                    if(!invert^invertTrans){
                        CurrentPixel.A = CurrentPixel.R;
                    }
                    else{
                        CurrentPixel.A = (byte)(255-CurrentPixel.R);
                    }
                }
                if(alpha){
                    CurrentPixel.A = (byte)(CurrentPixel.A*A/255);
                }
    
                dst[x,y] = CurrentPixel;
            }
        }
    }
    
    private float fractal(double x, double y,double ca, double cb, int n, int type){
        if(type == 0 && x*x+y*y<n && n>0){
            return fractal(x*x-y*y+ca,2*x*y+cb,ca,cb,--n,type);
            }
        if(type == 1 && Math.Abs(x+y)<2 && n>0){
            return fractal(x*x-y*y+ca,2*x*y+cb,ca,cb,--n,type);
            }
        if(type == 2 && y<2 && n>0){
            return fractal(x*x-y*y+ca,2*x*y+cb,ca,cb,--n,type);
        }
        if(type == 3 && x<2 && n>0){
            return fractal(x*x-y*y+ca,2*x*y+cb,ca,cb,--n,type);
        }
        else{
            return 1-n/(float)iterations;
        }
    }
    
    private float limit(float v, int min, int max){
        if(v>max)v=max;
        else if(v<min)v=min;
        return v;
    }
    
    private float contrast(float x, double c){
        double y;
        c = Math.Pow(c/2,3);
        if(x <= .5f){
            y = .5f * Math.Pow(2*x, (c/500)+1);
        }
        else{
            y = 1 - .5f * Math.Pow(2 - 2*x, (c/500)+1);
        }
        return (float)y;
    }

     

    • Like 3
    • Upvote 6
  9. [April 22th 2023] Version 2 available!

     

    Back with my second plugin. This time I made a plugin that can be used to easily and quickly create a gradient mapping effect using 2 colors. I know pyrochild already made a gradient mapping tool, but this is just a simplified version using only 2 colors for dark and light tones. I added some options for post processing as well, like contrast and blending mode.

     

    sample.jpg.31e3c2dc513b4a594604f52b2ca51ee8.jpg

     

    Download

    Location: Effects > Color > Duotone Gradient Map

    duotonegradientmap.zip

     

    Code

    Spoiler
    #region UICode
    ColorWheelControl DARK = ColorBgra.FromBgr(0, 0, 0); // Dark
    ColorWheelControl LIGHT = ColorBgra.FromBgr(255, 255, 255); // Light
    IntSliderControl CONTRAST = 0; // [-100,100] Contrast
    ListBoxControl<BlendMode> BLEND = 0; // Blending mode|Normal
    IntSliderControl MIX = 100; // [0,100] Mix
    #endregion
    enum BlendMode
    {
        Normal, Multiply, Screen, Darken, Lighten, Overlay, Additive
    }
    
    Func<byte, byte, byte> blender = null;
    
    void PreRender(Surface dst, Surface src)
    {
        blender = BLEND switch
            {
                BlendMode.Multiply => BlendMult,
                BlendMode.Screen => BlendScreen,
                BlendMode.Darken => BlendDarken,
                BlendMode.Lighten => BlendLighten,
                BlendMode.Overlay => BlendOverlay,
                BlendMode.Additive => BlendAdd,
                _ => BlendNormal
            };
    }
    
    void Render(Surface dst, Surface src, Rectangle rect)
    {
        double mix = MIX / 100.0;
        double contrast = CONTRAST / 10.0;
        
        ColorBgra c;
        for (int y = rect.Top; y < rect.Bottom; y++)
        {
            if (IsCancelRequested) return;
            for (int x = rect.Left; x < rect.Right; x++)
            {
                c = src[x,y];
                double value = Contrast((c.R + c.G + c.B) / 765.0, contrast);
                ColorBgra n = Mix(DARK, LIGHT, value);
                n = ApplyBlend(c, n, blender);
                n = Mix(c, n, mix);
                n.A = c.A;
                dst[x,y] = n;
            }
        }
    }
    
    double Contrast(double x, double p)
    {
        if (p == 0)
        {
            return x;
        }
        if (p > 0)
        {
            return x < 0.5
                ? 0.5 * Math.Pow(2.0 * x, p + 1.0)
                : 1.0 - 0.5 * Math.Pow(2.0 - 2.0 * x, p + 1.0);
        }
        else {
            return x < 0.5
                ? 0.5 - 0.5 * Math.Pow(1.0 - 2.0 * x, 1.0 - p)
                : 0.5 + 0.5 * Math.Pow(2.0 * x - 1.0, 1.0 - p);
        }
    }
    
    ColorBgra Mix(ColorBgra a, ColorBgra b, double value)
    {
        return ColorBgra.FromBgr(
            Mix(a.B, b.B, value),
            Mix(a.G, b.G, value),
            Mix(a.R, b.R, value)
        );
    }
    
    byte Mix(byte a, byte b, double value)
    {
        double output = (1.0 - value) * a + value * b;
        return (byte) Math.Clamp(output, 0.0, 255.0);
    }
    
    ColorBgra ApplyBlend(ColorBgra a, ColorBgra b, Func<byte, byte, byte> f)
    {
        return ColorBgra.FromBgr(
            f(a.B, b.B), 
            f(a.G, b.G),
            f(a.R, b.R)
        );
    }
    
    byte BlendNormal(byte a, byte b)
    {
        return b;
    }
    
    byte BlendDarken(byte a, byte b)
    {
        return Math.Min(a, b);
    }
    
    byte BlendLighten(byte a, byte b)
    {
        return Math.Max(a, b);
    }
    
    byte BlendMult(byte a, byte b)
    {
        return (byte) Math.Clamp(a * b * 0.0039215686, 0.0, 255.0);
    }
    
    byte BlendScreen(byte a, byte b)
    {
        return (byte) (255 - BlendMult((byte) (255 - a), (byte) (255 - b)));
    }
    
    byte BlendOverlay(byte a, byte b)
    {
        return (byte) (a < 127
            ? 2 * BlendMult(a, b)
            : 2 * BlendScreen(a, b));
    }
    
    byte BlendAdd(byte a, byte b)
    {
        return (byte) Math.Clamp(a + b, 0, 255);
    }

     

    • Like 2
    • Thanks 1
    • Upvote 1
  10. [June 28th 2022] Version 5 available!

     

    This plugin can be used to simulate certain colorblindness types such as: protanopia, deuteranopia, tritanopia, achromatopsia and blue-cone monochromacy.

     

    Download:

    colorblindness.zip

    Can be found in Effects > Color > Colorblindness

    Note: if you have an older version installed, remove it manually from the Paint.NET Effects folder. The old version is called colorblindness4.dll.

    The new version does not include the version number in the name.

     

    Preview:

    demo.thumb.jpg.b1d66071ceef7d13ec23c6849b35cc1e.jpg

     

    Code:

    Spoiler
    #region UICode
    ListBoxControl<Deficiency> type = Deficiency.Default; //Color blindness type|Protanopia|Deuteranopia|Tritanopia|Achromatopsia|Blue-Cone Monochromacy|Normal Vision
    #endregion
    
    enum Deficiency
    {
        [LmsMatrix(
            0,  1.05118294,  -0.05116099,
            0,  1,            0,
            0,  0,            1)]
        Protanopia,
    
        [LmsMatrix(
            1,         0,  0,
            0.9513092, 0,  0.04866992,
            0,         0,  1)]
        Deuteranopia,
    
        [LmsMatrix(
            1,           0,          0,
            0,           1,          0,
           -0.86744736, 1.86727089,  0)]
        Tritanopia,
    
        [LmsMatrix(
            0.4,  0.6,  0,
            0.4,  0.6,  0,
            0.4,  0.6,  0)]
        Achromatopsia,
    
        [LmsMatrix(
            0, 0, 1,
            0, 0, 1,
            0, 0, 1
        )]
        Blue_Cone_Monochromacy,
        
        [LmsMatrix(
            1,  0,  0,
            0,  1,  0,
            0,  0,  1)]
        Default
    }
    
    static double[,] toLmsMatrix = toMatrix(3, 3,
        0.31399022, 0.63951294, 0.04649755,
        0.15537241, 0.75789446, 0.08670142,
        0.01775239, 0.10944209, 0.87256922);
    
    static double[,] toLinearRgbMatrix = toMatrix(3, 3,
        5.47221206, -4.6419601, 0.16963708,
        -1.1252419, 2.29317094, -0.1678952,
        0.02980165, -0.19318073, 1.16364789);
    
    class LmsMatrix: Attribute
    {
        public double[,] matrix {get; private set;}
    
        internal LmsMatrix(params double[] matrix)
        {
            this.matrix = toMatrix(3, 3, matrix);
        }
    
        public static LmsMatrix getMatrix(Deficiency d)
        {
            return (LmsMatrix) Attribute.GetCustomAttribute(deficiencyOf(d), typeof(LmsMatrix));
        }
    
        static MemberInfo deficiencyOf(Deficiency d)
        {
            return typeof(Deficiency).GetField(Enum.GetName(typeof(Deficiency), d));
        }
    }
    
    static double[,] toLinear(params byte[] rgb)
    {
        double[,] linear = new double[rgb.Length, 1];
        for (int i = 0; i < linear.Length; i++)
        {
            linear[i, 0] = Math.Clamp(rgb[i] <= 0.04045 * 255.0
                    ? (rgb[i] / 255.0) / 12.92
                    : Math.Pow((rgb[i] / 255.0 + 0.055) / 1.055, 2.4),
                0.0, 1.0);
        }
        return linear;
    }
    
    static byte[] fromLinear(double[,] linear)
    {
        byte[] normal = new byte[linear.GetLength(0)];
        for (int i = 0; i < normal.Length; i++)
        {
            double l = Math.Clamp(linear[i, 0], 0.0, 1.0);
            normal[i] = Math.Clamp((byte) (l <= 0.0031308
                    ? l * 255.0 * 12.92
                    : 255.0 * (1.055 * Math.Pow(l, 0.41666) - 0.055)),
                (byte) 0, (byte) 255);
        }
        return normal;
    }
    
    static double[,] multiplyMatrix(double[,] a, double[,] b)
    {
        int rA = a.GetLength(0);
        int cA = a.GetLength(1);
        int cB = b.GetLength(1);
        double[,] result = new double[rA, cB];
    
        for (int i = 0; i < rA; i++)
        {
            for (int j = 0; j < cB; j++)
            {
                double temp = 0;
                for (int k = 0; k < cA; k++)
                {
                    temp += a[i, k] * b[k, j];
                }
                result[i, j] = temp;
            }
        }
        return result;
    }
    
    static double[,] toMatrix(int rows, int columns, params double[] values)
    {
        double[,] result = new double[rows, columns];
        for (int i = 0; i < rows; i++)
        {
            for (int j = 0; j < columns; j++)
            {
                result[i, j] = values[j + i * columns];
            }
        }
        return result;
    }
    
    static double[,] getColorBlindnessMatrix(double[,] lmsMatrix)
    {
        return multiplyMatrix(
            multiplyMatrix(
                toLinearRgbMatrix,
                lmsMatrix),
            toLmsMatrix
        );
    }
    
    static ColorBgra applyColorBlindnessMatrix(double[,] matrix, ColorBgra pixel)
    {
        byte[] rgb = new byte[]{pixel.R, pixel.G, pixel.B};
        byte[] newRgb = fromLinear(
            multiplyMatrix(
                matrix,
                toLinear(rgb)
            )
        );
        return ColorBgra.FromBgra(newRgb[2], newRgb[1], newRgb[0], pixel.A);
    }
    
    void Render(Surface dst, Surface src, Rectangle rect)
    {
        double[,] matrix = getColorBlindnessMatrix(LmsMatrix.getMatrix(type).matrix);
    
        for (int y = rect.Top; y < rect.Bottom; y++)
        {
            if (IsCancelRequested) return;
            for (int x = rect.Left; x < rect.Right; x++)
            {
                dst[x,y] = applyColorBlindnessMatrix(matrix, src[x,y]);
            }
        }
    }

     

    • Like 2
    • Upvote 4
×
×
  • Create New...