Jump to content

Recommended Posts

Posted
2 hours ago, toe_head2001 said:

Obviously, writing outside of the selection is still a bad practice, and just wastes compute resources.

 

Would you expand of this. Do you just mean the write has no effect, so the effort is wasted, or does it waste resources in some other way? If it just wastes the effort to compute the unused pixels, is that behavior that's intended to remain that way, so that it can be relied on? There are probably lots of cases where it would be convenient to clip at most to the selection's bounding rectangle, and not worry that there will be some wasted computations if the user happens to have an elliptical selection.

 

Also, does  is writing outside the ROI in Render() allowed, in the sense that it will properly write into pixels if they're selected? To paraphrase Ghostbusters, are the ROI bounds more guidelines than rules?

  • Like 1
Posted
26 minutes ago, MJW said:

Do you just mean the write has no effect, so the effort is wasted

 

Yeah, pretty much.

 

28 minutes ago, MJW said:

is that behavior that's intended to remain that way, so that it can be relied on?

 

I believe so. If pixels outside of the selection are modified, that would be considered a bug.

 

30 minutes ago, MJW said:

Also, does writing outside the ROI in Render() allowed, in the sense that it will properly write into pixels if they're selected?

 

Yes, it will work. Using the ROI is, of course, the recommended route, and probably the most efficient.

  • Like 1
  • 1 month later...
Posted

Swirl can be found in Effects > Distort submenu.

Spoiler

// Name: Swirl
// Submenu: Distort
// Author: NSD
// Title: Swirl
// Version: 1.0
// Desc:
// Keywords:
// URL:

#region UICode
DoubleSliderControl intensity = 0.0; // [-1,1] Amount / Direction
DoubleSliderControl zoom = 0; // [0.0,0.999] Zoom
PanSliderControl pan = Pair.Create(0.0, 0.0); // Center
#endregion

void Render(Surface dst, Surface src, Rectangle rect)
{
    int x, y;
    double offx, offy, dx, dy, th, rd, ct, offset, xPan, yPan, zm;
    ColorBgra CurrentPixel;

    Rectangle sel = EnvironmentParameters.SelectionBounds;
    dst.CopySurface(src, rect.Location, rect);

    ct = intensity * 0.2;
    offset = Math.PI / 2.0;

    xPan = (pan.First + 1) / 2 * (sel.Right - sel.Left) + sel.Left;
    yPan = (pan.Second + 1) / 2 * (sel.Bottom - sel.Top) + sel.Top;

    zm  = 1 - zoom;

    for (y = rect.Top; y < rect.Bottom; y++)
    {
        if (IsCancelRequested) return;

        for (x = rect.Left; x < rect.Right; x++)
        {
            dx = x - xPan;
            dy = y - yPan;

            rd = Math.Sqrt((dx * dx + dy * dy) * zm);
            th = Math.Atan2(dx, -dy) - offset;

            offx = rd * Math.Cos(th + ct * rd);
            offy = rd * Math.Sin(th + ct * rd);

            offx += xPan;
            offy += yPan;

            CurrentPixel = src.GetBilinearSampleWrapped((float)offx, (float)offy);
            dst[x,y] = CurrentPixel;
        }
    }
}

 

 

 

Swirl.zip

  • Like 2
  • Upvote 1
  • 1 month later...
Posted (edited)

This plugin can be found in the Effects Menu.
You need to put OptionBasedLibrary v0.7.8 dlc and dll files in paint.net folder and
WarpTextOnPath dll and dlc files in Effects folder.

 

The UI:
gyPoYl0.png

 

Spoiler





// Name: WarpTextOnBezier
// Submenu:
// Author: NSD
// Title:
// Version: 1.0
// Desc:
// Keywords:
// URL:
// Help:
// Force Single Render Call

#region UICode
MultiLineTextboxControl text = "WARP TEXT ON A BEZIER CURVE"; // [32767]
FontFamily font = new FontFamily("Georgia");
DoubleSliderControl fontSize = 120; // [5,800] Font size
CheckboxControl bold = true; // Bold
CheckboxControl italic = false; // Italic
PanSliderControl p0 = Pair.Create(-0.500, 0.740); //
PanSliderControl p1 = Pair.Create(-1.000, -1.000); //
PanSliderControl p2 = Pair.Create(1.000, -1.000); //
PanSliderControl p3 = Pair.Create(0.500, 0.740); //
ListBoxControl<TextPathPositionEnum> textPathPosition = TextPathPositionEnum.OverPath; //|Over path|Center path|Under path
ListBoxControl<RenderModeEnum> renderMode = RenderModeEnum.Normal; //|Normal|Mask|Transparent
CheckboxControl viewPoints = true; // Show path
#endregion


Surface wrk = null;
float c1, r1, c2, r2, c3, r3, c4, r4, d, r;
PointF [] points;


protected override void OnDispose(bool disposing)
{
  if (disposing)
  {
    if (wrk != null) wrk.Dispose();
    wrk = null;
  }
  base.OnDispose(disposing);
}

void PreRender(Surface dst, Surface src)
{
  if (wrk == null)
  {
    wrk = new Surface(src.Size);
  }

  else
  {
    wrk.Clear(Color.Transparent);
  }

  Rectangle sel = EnvironmentParameters.SelectionBounds;
  c1 = ((float)p0.First + 1) / 2 * (sel.Right - sel.Left) + sel.Left;
  r1 = ((float)p0.Second + 1) / 2 * (sel.Bottom - sel.Top)+ sel.Top;

  c2 = ((float)p1.First + 1) / 2 * (sel.Right - sel.Left) + sel.Left;;
  r2 = ((float)p1.Second + 1) / 2 * (sel.Bottom - sel.Top)+ sel.Top;;

  c3 = ((float)p2.First + 1) / 2 * (sel.Right - sel.Left) + sel.Left;;
  r3 = ((float)p2.Second + 1) / 2 * (sel.Bottom - sel.Top)+ sel.Top;;

  c4 = ((float)p3.First + 1) / 2 * (sel.Right - sel.Left) + sel.Left;;
  r4 = ((float)p3.Second + 1) / 2 * (sel.Bottom - sel.Top)+ sel.Top;;

  Size selSize = EnvironmentParameters.SelectionBounds.Size;

  d = Math.Min(selSize.Width, selSize.Height) / 20;
  if (d <= 1) return;
  r = d / 2;
  points = new PointF[4];
  points[0] = new PointF(c1, r1);
  points[1] = new PointF(c2, r2);
  points[2] = new PointF(c3, r3);
  points[3] = new PointF(c4, r4);
}


void Render(Surface dst, Surface src, Rectangle rect)
{
  dst.CopySurface(src, rect.Location, rect);

  using (RenderArgs ra = renderMode == 0 ? new RenderArgs(dst) : new RenderArgs(wrk))
  using (GraphicsPath textPath = new GraphicsPath())
  using (SolidBrush sBrush = new SolidBrush(Color.Blue))
  using (Pen pen = new Pen(Color.FromArgb(255, Color.Red), 3))
  using (SolidBrush pointBr = new SolidBrush(Color.YellowGreen))
  {
    pen.LineJoin = LineJoin.Round;
    pen.DashStyle = DashStyle.Solid;
    Graphics g = ra.Graphics;
    g.Clip = new Region(rect);
    g.SmoothingMode = SmoothingMode.AntiAlias;
    g.TextRenderingHint = TextRenderingHint.AntiAlias;
    FontStyle myStyle = FontStyle.Regular;
    if (bold) myStyle |= FontStyle.Bold;
    if (italic) myStyle |= FontStyle.Italic;
    Font fnt = new Font(font.Name, (float)fontSize, myStyle);
    FontFamily ff = new FontFamily(font.Name);
    StringFormat format = new StringFormat();
    format.Alignment = StringAlignment.Near;
    format.LineAlignment = StringAlignment.Near;

    switch (textPathPosition)
    {
      case TextPathPositionEnum.CenterPath:
        format.Alignment = StringAlignment.Near;
        format.LineAlignment = StringAlignment.Center;
        break;
      case TextPathPositionEnum.OverPath:
        format.Alignment = StringAlignment.Near;
        format.LineAlignment = StringAlignment.Far;
        break;
      case TextPathPositionEnum.UnderPath:
        format.Alignment = StringAlignment.Near;
        format.LineAlignment = StringAlignment.Near;
        break;
    }

    if (viewPoints)
    {
      g.DrawBeziers(pen, points);
      pen.DashStyle = DashStyle.Dash;
      g.DrawLine(pen, c1, r1, c2, r2);
      g.DrawLine(pen, c3, r3, c4, r4);
      pen.DashStyle = DashStyle.Solid;

      g.FillEllipse(pointBr, new RectangleF(c1 - r, r1 - r, d, d));
      g.DrawEllipse(Pens.Black, new RectangleF(c1 - r, r1 - r, d, d));
      g.DrawString("1", new Font("Tahoma", r), Brushes.Black, new RectangleF(c1 - 0.7f * r, r1 - r, d, d));

      g.FillEllipse(pointBr, new RectangleF(c2 - r, r2 - r, d, d));
      g.DrawEllipse(Pens.Black, new RectangleF(c2 - r, r2 - r, d, d));
      g.DrawString("2", new Font("Tahoma", r), Brushes.Black, new RectangleF(c2 - 0.7f * r, r2 - r, d, d));

      g.FillEllipse(pointBr, new RectangleF(c3 - r, r3 - r, d, d));
      g.DrawEllipse(Pens.Black, new RectangleF(c3 - r, r3 - r, d, d));
      g.DrawString("3", new Font("Tahoma", r), Brushes.Black, new RectangleF(c3 - 0.7f * r, r3 - r, d, d));

      g.FillEllipse(pointBr, new RectangleF(c4 - r, r4 - r, d, d));
      g.DrawEllipse(Pens.Black, new RectangleF(c4 - r, r4 - r, d, d));
      g.DrawString("4", new Font("Tahoma", r), Brushes.Black, new RectangleF(c4 - 0.7f * r, r4 - r, d, d));
    }

    textPath.AddString(text, ff, (int)myStyle, (float)fontSize, new PointF(0, 0), format);
    if(text.Length > 0)
    {
      g.DrawPath(pen, BezierWarp(textPath, g));
      g.FillPath(sBrush, BezierWarp(textPath, g));
    }

    if (renderMode == RenderModeEnum.Mask)//creates mask
    {
      for (int y = rect.Top; y < rect.Bottom; y++)
      {
        if (IsCancelRequested) return;
        for (int x = rect.Left; x < rect.Right; x++)
        {
          ColorBgra CurrentPixel = src[x, y];
          CurrentPixel.A = Int32Util.ClampToByte(wrk[x, y].A);
          dst[x, y] = CurrentPixel;
        }
      }
    }

    if (renderMode == RenderModeEnum.Transparent)//Transparent checked
    {
      for (int y = rect.Top; y < rect.Bottom; y++)
      {
        if (IsCancelRequested) return;
        for (int x = rect.Left; x < rect.Right; x++)
        {
          ColorBgra CurrentPixel = src[x, y];
          CurrentPixel.A = Int32Util.ClampToByte(255 - wrk[x, y].A);
          dst[x, y] = CurrentPixel;
        }
      }
    }

  }
}

GraphicsPath BezierWarp(GraphicsPath textPath, Graphics g)
{
  // Calculate coefficients A thru H from the control points
  float A = c4 - 3 * c3 + 3 * c2 - c1;
  float B = 3 * c3 - 6 * c2 + 3 * c1;
  float C = 3 * c2 - 3 * c1;
  float D = c1;

  float E = r4 - 3 * r3 + 3 * r2 - r1;
  float F = 3 * r3 - 6 * r2 + 3 * r1;
  float G = 3 * r2 - 3 * r1;
  float H = r1;

  PointF[] pathPoints = textPath.PathPoints;
  RectangleF textBounds = textPath.GetBounds();

  for (int i = 0; i < pathPoints.Length; i++)
  {
    PointF pt = pathPoints[i];
    float textX = pt.X;
    float textY = pt.Y;

    // Normalize the x coordinate into the parameterized
    // value with a domain between 0 and 1.
    float t  =  textX / textBounds.Width;
    float t2 = (t * t);
    float t3 = (t * t * t);

    // Calculate spline point for parameter t
    float Sx = A * t3 + B * t2 + C * t + D;
    float Sy = E * t3 + F * t2 + G * t + H;

    // Calculate the tangent vector for the point
    float Tx = 3 * A * t2 + 2 * B * t + C;
    float Ty = 3 * E * t2 + 2 * F * t + G;

    // Rotate 90 or 270 degrees to make it a perpendicular
    float Px = - Ty;
    float Py = Tx;

    // Normalize the perpendicular into a unit vector
    float magnitude = (float)Math.Sqrt((Px * Px) + (Py * Py));
    Px /= magnitude;
    Py /= magnitude;

    // Assume that input text point y coord is the "height" or
    // distance from the spline.  Multiply the perpendicular
    // vector with y. it becomes the new magnitude of the vector
    Px *= textY;
    Py *= textY;

    // Translate the spline point using the resultant vector
    float finalX = Px + Sx;
    float finalY = Py + Sy;

    pathPoints[i] = new PointF(finalX, finalY);
  }

  return new GraphicsPath(pathPoints, textPath.PathTypes);
}

enum TextPathPositionEnum
{
  OverPath,
  CenterPath,
  UnderPath
}
enum RenderModeEnum
{
  Normal,
  Mask,
  Transparent
}

 

 

WarpTextOnPath.zip

 

http://www.mediafire.com/file/ignc6de43v3m90e/WarpTextOnPathOB.zip/file

Edited by NSD
Added the code.
  • Like 2
  • Upvote 3
  • 1 month later...
Posted
On 8/31/2020 at 11:42 AM, NSD said:

This plugin can be found in the Effects Menu.
You need to put OptionBasedLibrary v0.7.8 dlc and dll files in paint.net folder and
WarpTextOnPath dll and dlc files in Effects folder.

 

The UI:
gyPoYl0.png

 

 

WarpTextOnPath.zip 174.27 kB · 10 downloads

Is there a way to install this on the Windows Store version of Paint?

I feel kind of gypped that I purchased the app to support the developer after a good decade of free use, and it seems super difficultr to install plugins now :/

Posted

It is not difficult. It requires a once-only setup of the correct folder structure. See the instructions in the yellow panel on this page: https://www.getpaint.net/doc/latest/InstallPlugins.html#4

Posted (edited)

EDIT : Never mind, solved the speed issue.

 

Edited by Reptillian

G'MIC Filter Developer

 

I am away from this forum for undetermined amount of time: If you really need anything related to my PDN plugin or my G'MIC filter within G'MIC plugin, then you can contact me via Paint.NET discord, and mention me.

Posted

Now, made something else. I think this is likely my final plugin for PDN as I don't think it makes sense to convert some of my other gmic work given either they're too long, or has features that are way too difficult to implement.

 

Plugin to download below. I hope it's good enough since there are slowdown issues.

Rotate by Torus Map.zip

 

G'MIC Filter Developer

 

I am away from this forum for undetermined amount of time: If you really need anything related to my PDN plugin or my G'MIC filter within G'MIC plugin, then you can contact me via Paint.NET discord, and mention me.

Posted (edited)

You're right, but the advantage of using OptionBased is that the users can place the plugin where they want.
To do this edit the .dlc file of plugin as follows:
1. change the extension from .dlc to .txt

2. open it with Notepad
3. the following line needs to be changed:
WarpTextOnPathEffectPlugin.SubmenuName=Text Formations
3. save the changes, close Notepad and then change the extension back to .dlc 
That's all. Now start PDN.

 

Edited by NSD
typo
  • Upvote 1
Posted
1 hour ago, NSD said:

1. change the extension from .dlc to .txt

File .dlc in any text editor can be opened and saved without changing the extension.

  • Upvote 1
Posted

Thank you @NSD and @ReMake.

I copied and pasted the text above only for the plugin to disappear altogether. It was not in Effects, neither in Effects > Text Formations. I tried again without the spaces either side of "=" and it worked. It may have been a fluke, bit I thought I'd mention it anyway.

 

When (if?) the plugin is released in the main plugin forum, I think it would perhaps be easier for everyone if it was placed in the text sub-menu outright.

  • Upvote 1

Xkds4Lh.png

  • 1 month later...
Posted

I created this plugin for personal purposes.
Because there are already several such plugins
I will not post it in the dedicated tread.
If you like it use it. If you don't like it, I'm sorry.

 

fGnfaw0.png

 

AlignNSD.zip

  • Like 1
  • Upvote 2
Posted

I don't plan to download and use that, but going to compliment you on the GUI design. I like the design of it and the features there.

G'MIC Filter Developer

 

I am away from this forum for undetermined amount of time: If you really need anything related to my PDN plugin or my G'MIC filter within G'MIC plugin, then you can contact me via Paint.NET discord, and mention me.

  • 2 months later...
Posted (edited)

The effect of this plugin is similar to that obtained by Rotate / Zoom except that the zoom is centered on the created selection.
To see the center of the selection click on the Move Selection tool and notice where the small circle marked with + is.

If there is no selection it zooms the entire canvas.
The plugin is inspired by the discussion on this thread:

 

https://forums.getpaint.net/topic/117885-zoomin-plugin/

 

It is located in Effects -> Selection submenu.

zpJvhzZ.png

Zoom Selection.zip

 

LE:

@Djisves pointed out to me that there is already another plugin that I missed and that does the same thing much better and has more options:

 

 

Edited by NSD
Added more information.
  • Like 1
  • Upvote 2
  • 3 months later...
Posted (edited)

As soon as I have figured out how to work with HSV in content of PDN C# development, I was able to almost complete the plugin. For now, I am releasing as a test plugin, and there is only one more thing to complete functionality-wise (No, I won't bother getting the plugin to automatically disable colors on circumstances), and that is getting the seed to work. I don't know how to fix that. Here's the current build of the Random Gradient Bars plugin.

 

Let me know if there is any bugs outside of those two I mentioned.

 

Random Gradient Bars.zip

 

Source Code:

Spoiler
// Name: Random Gradient Bars
// Submenu: Render
// Author: Reptillian
// Title: Random Gradient Bars
// Version: .75
// Desc: Generates Random Gradient Bars onto the canvas
// Keywords: Render, Bars
// URL: https://forums.getpaint.net/profile/85868-reptillian/
// Help:
#region UICode
ReseedButtonControl seed = 0; // Reseed
IntSliderControl bar_size = 50; // [1,256] Bar Size
IntSliderControl space_size = 0; // [0,256] Space Size
AngleControl degree = 45; // [-180,180] Angle
DoubleSliderControl skew_degree = 0; // [-89,89] Skew Angle
PanSliderControl origin = Pair.Create(0.000, 0.000); // Origin
IntSliderControl sublevel = 0; // [0,3] Subsampling
DoubleSliderControl shift = 0; // [0,100] Shift
DoubleSliderControl mult_1 = 0.1; // [0.1,256] Multiplier A
DoubleSliderControl mult_2 = 100; // [0.1,256] Multiplier B
ListBoxControl repetition_mode = 0; // Repetition|Random|Cut|Periodic|Continuous
ListBoxControl<Random_Repetition_Mode> repetition_random_repetition_modes = 0; // {repetition_mode} Random Bar Repetition|All|Cut and Periodic|Cut and Continuous|Periodic and Continuous
ListBoxControl<CS_Mode> color_space = 0; // Color|Gray|Duotone|Random-RGB|Random-HSV
ListBoxControl<Space_Mode> space_mode = 0; // Space Mode|Alpha|Cut|Gradient
ListBoxControl<Sym_Mode> symmetry = 0; // Symmetry Mode|N/A|A|B
CheckboxControl inversion_mode = false; // Use Inversion
ColorWheelControl space_color_a = ColorBgra.FromBgr(0, 140, 255); // [DarkOrange] Space Color A
ColorWheelControl space_color_b = ColorBgra.FromBgr(0, 215, 255); // [Gold] Space Color B
#endregion
double[] v_base = null;
double[] v_shift = null;
double[] v_mult = null;
int[] v_modulo_out = null;
bool[] v_invert = null;
int[] v_hue = null;
int[] v_rgb_r = null;
int[] v_rgb_g = null;
int[] v_rgb_b = null;
double ang;
int number_of_bars;
int shift_bars;

double cut(double a,double b,double c){
    double min_val = Math.Min(b,c);
    double max_val = Math.Max(b,c);
    return (a < min_val) ? min_val : (a > max_val) ? max_val : a;
}

double fmod(double a, double b){
    return a - Math.Floor(a / b) ;
}

int imod(int a, int b){
    int r = a % b;
    return r < 0 ? r + b : r;
}

double fmod_cont(double a, double b){
    double ind = imod((int)(Math.Floor(a/b)),2) ;
    return ind == 1 ? b - fmod(a,b) : fmod(a,b) ;
}

double fcut(double a, double b){
    return (cut(a,-b,b)+b)/2 ;
}


double rot_x(double a, double b, double sin_ang, double cos_ang){
    return a * cos_ang - b * sin_ang ;
}


double rot_y(double a, double b, double sin_ang, double cos_ang){
    return a * sin_ang + b * cos_ang ;
}


double lerp(double a, double b, double t){
    return a * (1 - t) + b * t ;
}

ColorBgra lerp_HSV(HsvColor B,HsvColor A,double t){

    double A_H = (double)(A.Hue);
    double A_S = (double)(A.Saturation);
    double A_V = (double)(A.Value);
    double B_H = (double)(B.Hue);
    double B_S = (double)(B.Saturation);
    double B_V = (double)(B.Value);
    double d_NH = lerp(A_H,B_H,t);
    double d_NS = lerp(A_S,B_S,t);
    double d_NV = lerp(A_V,B_V,t);
    int NH = (int)(Math.Round(d_NH));
    int NS = (int)(Math.Round(d_NS));
    int NV = (int)(Math.Round(d_NV));
    HsvColor new_hsv = new HsvColor(NH,NS,NV);
    return ColorBgra.FromColor(new_hsv.ToColor());
}

ColorBgra fromHueandValue(int Hue,double t){
    HsvColor new_hsv = new HsvColor(Hue,100,(int)(Math.Round(t*100)));
    return ColorBgra.FromColor(new_hsv.ToColor());
}

void PreRender(Surface dst, Surface src)
{
    Random myRandom = new Random(int.MaxValue);
    Random myRandom_2 = new Random(int.MaxValue);
    Random myRandom_3 = new Random(int.MaxValue);
    int ww = src.Width - 1 ;
    int hh = src.Height - 1 ;
    double cx = (double)(ww) / 2 ;
    double cy = (double)(hh) / 2 ;
    double cut_ang = Math.Atan2(cy,cx) ;
    double cut_ang_2 = Math.PI - cut_ang ;
    ang = ( degree / 180 ) / Math.PI ;
    double trimmed_ang = ang % Math.PI ;
    bool use_shift = shift > 0 ;
    int total_width = bar_size + space_size;
    double d_total_width = (double)(total_width);
    double d_ww = (double)(ww);
    double d_hh = (double)(hh);

    if ((trimmed_ang>=cut_ang)&&(trimmed_ang<cut_ang)){
        number_of_bars =(int)(Math.Ceiling((Math.Abs(1/Math.Sin(ang))*d_ww)/d_total_width));
    }
    else
    {
        number_of_bars =(int)(Math.Ceiling((Math.Abs(1/Math.Cos(ang))*d_hh)/d_total_width));
    }

    shift_bars = number_of_bars / 2;

    v_base = new double[number_of_bars];
    v_modulo_out = new int[number_of_bars];
    v_invert = new bool[number_of_bars];
    v_shift = new double[number_of_bars];   

    for(int n = 0 ; n < number_of_bars ; n++){
        v_base[n] = 0;
        v_invert[n] = false ;
    }


    Array.Copy(v_base, v_shift, v_base.Length);

    double shift_dist;
    int precision = 100000;

    if (use_shift){
        for(int n = 0 ; n < number_of_bars ; n++){
            shift_dist = (double)(myRandom_3.Next(precision)) / (double)(precision) ;
            shift_dist*=shift;
            if (myRandom_3.Next(255) > 128){
                v_shift[n] = shift_dist;
            }
            else{
                v_shift[n] = -shift_dist;
            }
        }
    }

    if (repetition_mode > 0) {
        int rep_pos=repetition_mode - 1 ;
        for(int n = 0 ; n < number_of_bars ; n++){
            v_modulo_out[n]=rep_pos;
        }
    }
    else{
        switch(repetition_random_repetition_modes){
            case Random_Repetition_Mode.Cut_Periodic:
                for(int n = 0 ; n < number_of_bars ; n++){
                    v_modulo_out[n] = myRandom.Next(2);
                }
                break;
            case Random_Repetition_Mode.Cut_Continuous:
                for(int n = 0 ; n < number_of_bars ; n++){
                    v_modulo_out[n] = myRandom.Next(2)*2;
                }
                break;
            case Random_Repetition_Mode.Periodic_Continuous:
                for(int n = 0 ; n < number_of_bars ; n++){
                    v_modulo_out[n] = myRandom.Next(2)+1;
                }                
                break;
            default:
                for(int n = 0 ; n < number_of_bars ; n++){
                    v_modulo_out[n] = myRandom.Next(3);
                }  
                
                break;
        }
    }

    if (inversion_mode){
        for(int n = 0 ; n < number_of_bars ; n++){
            if (myRandom_2.Next(255) > 128){
                v_invert[n] = true;
            }
        }
    }

    v_hue = new int[number_of_bars];
    v_rgb_r = new int[number_of_bars];
    v_rgb_g = new int[number_of_bars];
    v_rgb_b = new int[number_of_bars];
    v_mult = new double[number_of_bars];

    for(int n = 0 ; n < number_of_bars ; n++){
        v_hue[n] = myRandom.Next(359);
        v_rgb_r[n] = myRandom.Next(255);
        v_rgb_g[n] = myRandom.Next(255);
        v_rgb_b[n] = myRandom.Next(255);
        v_mult[n] = lerp(mult_1,mult_2,(double)(myRandom.Next(precision))/(double)(precision));
    }

}

void Render(Surface dst, Surface src, Rectangle rect)
{
    // Delete any of these lines you don't need
    int ww = src.Width - 1 ;
    int hh = src.Height - 1 ;
    double d_ww = (double)(ww);
    double d_hh = (double)(hh);
    double sd = Math.Max(d_ww,d_hh)/Math.Min(d_ww,d_hh);
    double sx = d_ww>d_hh?sd:1;
    double sy = d_ww>d_hh?1:sd;
    double cx = (double)(ww) / 2 ;
    double cy = (double)(hh) / 2 ;
    double ox = cx - ((double)(cx)*-origin.First);
    double oy = cy - ((double)(cy)*-origin.Second);
    double ww_div_sx = (double)(ww)/sx;
    double hh_div_sy = (double)(hh)/sy;
    double pyth_img = Math.Sqrt(d_ww*d_ww+d_hh*d_hh);
    double ren_ang = ( degree / 180 ) * Math.PI ;
    double skew_ang = ( skew_degree / 180)*Math.PI;
    double cos_ang = Math.Cos(ren_ang);
    double sin_ang = Math.Sin(ren_ang);
    double mdist = Math.Tan(skew_ang)*pyth_img;
    int total_width = bar_size + space_size;
    bool width_test = total_width>1;
    bool bar_and_space_test = (bar_size==1)&&(space_size<2);
    bool space_test = space_size > 0;
    int half_total_width = width_test ? total_width / 2 : 0 ;
    double initial_x,initial_y,spacing,gradient,point_x,new_gradient,final_gradient;
    int bar,bar_id,use_modulo_out;
    bool spaces;
    double temp_result;
    double temp_result_2;
    bool gradient_test;

    int sc_a_B = Convert.ToInt32(space_color_a.B);
    int sc_a_G = Convert.ToInt32(space_color_a.G);
    int sc_a_R = Convert.ToInt32(space_color_a.R);
    int sc_b_B = Convert.ToInt32(space_color_b.B);
    int sc_b_G = Convert.ToInt32(space_color_b.G);
    int sc_b_R = Convert.ToInt32(space_color_b.R);

    
    Color rgb_1 = space_color_a.ToColor();
    Color rgb_2 = space_color_b.ToColor();
    HsvColor hsv_color_a = HsvColor.FromColor(rgb_1);
    HsvColor hsv_color_b = HsvColor.FromColor(rgb_2);

    if (bar_and_space_test){
        spacing = (space_size>0)?.5:0;
    }
    else{
        spacing = 1 - ((double)(space_size)/((double)(total_width) - 1));
    }

    for (int y = rect.Top; y < rect.Bottom; y++)
    {
        if (IsCancelRequested) return;
        for (int x = rect.Left; x < rect.Right; x++)
        {
             initial_x = ((double)(x) - ox) / d_ww * sx;
             initial_y = ((double)(y) - oy ) / d_hh * sy;
             gradient = -rot_y(initial_x,initial_y,sin_ang,cos_ang)*hh_div_sy/pyth_img;
             point_x = rot_x(initial_x,initial_y,sin_ang,cos_ang)*ww_div_sx+gradient*mdist+half_total_width;
             bar_id = (int)(Math.Floor(point_x/total_width));

             switch(symmetry){
                 case Sym_Mode.B:   bar = imod(-Math.Abs(bar_id)+shift_bars,number_of_bars);break;
                 case Sym_Mode.A:   bar = imod(Math.Abs(bar_id)+shift_bars,number_of_bars);break;
                 default:  bar = imod(bar_id+shift_bars,number_of_bars);break;
             }

             if(bar_and_space_test) {
                 if (space_test){
                     spaces = imod((int)(point_x),2) == 1 ;
                 }
                 else{
                     spaces = true;
                 }

             }
             else {
                 spaces = 2*Math.Abs(fmod(point_x/total_width,1)-.5)<=spacing;
             
             }

             new_gradient = gradient * v_mult[bar] + v_shift[bar];
             use_modulo_out = v_modulo_out[bar];

             switch(use_modulo_out){
                 case 2: final_gradient = v_invert[bar] ? 1 - fmod_cont(new_gradient,1) : fmod_cont(new_gradient,1); break;
                 case 1: final_gradient = v_invert[bar] ? 1 - fmod(new_gradient,1) : fmod(new_gradient,1); break;
                 default: final_gradient= v_invert[bar] ? 1 - fcut(new_gradient,1) : fcut(new_gradient,1); break;
             }

             switch(color_space){
                 case CS_Mode.HSV_Random: switch(space_mode){
                    case Space_Mode.Gradient:
                        temp_result = cut(gradient*2+.5,0,1);
                        if (spaces){
                            dst[x,y]=fromHueandValue(v_hue[bar],final_gradient);
                        }
                        else{
                            dst[x,y]=lerp_HSV(hsv_color_a,hsv_color_b,temp_result);
                        }
                        break;
                    case Space_Mode.Cut:
                        gradient_test = gradient >= 0;
                        if (spaces){
                            dst[x,y]=fromHueandValue(v_hue[bar],final_gradient);
                        }
                        else{
                            dst[x,y]=ColorBgra.FromBgr(
                             (byte)((int)(gradient_test?sc_a_B:sc_b_B)),
                             (byte)((int)(gradient_test?sc_a_G:sc_b_G)),
                             (byte)((int)(gradient_test?sc_a_R:sc_b_R))
                            );
                        }
                        break;
                    default:
                        if (spaces){
                            dst[x,y]=fromHueandValue(v_hue[bar],final_gradient);
                        }
                        else{
                            dst[x,y]=ColorBgra.FromBgra(0,0,0,0);
                        }
                        break;

                    }
                    break;
                 case CS_Mode.RGB_Random: switch(space_mode){
                    case Space_Mode.Gradient:
                        temp_result = cut(gradient*2+.5,0,1);
                        dst[x,y]=ColorBgra.FromBgr(
                         (byte)(spaces ? (int)(v_rgb_b[bar] * final_gradient) : (int)(lerp((double)(sc_b_B),(double)(sc_a_B),temp_result))),
                         (byte)(spaces ? (int)(v_rgb_g[bar] * final_gradient) : (int)(lerp((double)(sc_b_G),(double)(sc_a_G),temp_result))),
                         (byte)(spaces ? (int)(v_rgb_r[bar] * final_gradient) : (int)(lerp((double)(sc_b_R),(double)(sc_a_R),temp_result)))
                        );
                        break;
                    case Space_Mode.Cut:
                        gradient_test = gradient >= 0;
                        dst[x,y]=ColorBgra.FromBgr(
                         (byte)(spaces ? (int)(v_rgb_b[bar] * final_gradient) : (int)(gradient_test ? sc_a_B : sc_b_B)),
                         (byte)(spaces ? (int)(v_rgb_g[bar] * final_gradient) : (int)(gradient_test ? sc_a_G : sc_b_G)),
                         (byte)(spaces ? (int)(v_rgb_r[bar] * final_gradient) : (int)(gradient_test ? sc_a_R : sc_b_R))
                        );
                        break;
                    default: 
                        dst[x,y]=ColorBgra.FromBgra(
                         (byte)((int)(v_rgb_b[bar] * final_gradient)),
                         (byte)((int)(v_rgb_g[bar] * final_gradient)),
                         (byte)((int)(v_rgb_r[bar] * final_gradient)),
                         (byte)(spaces ? 255 : 0)
                            );
                        break;
                    }
                    break;
                 case CS_Mode.Duotone: switch(space_mode){
                    case Space_Mode.Gradient:
                        temp_result = cut(gradient*2+.5,0,1);
                        dst[x,y]=ColorBgra.FromBgr(
                         (byte)(spaces ? (int)(lerp((double)(sc_a_B),(double)(sc_b_B),final_gradient)) : (int)(lerp((double)(sc_b_B),(double)(sc_a_B),temp_result))),
                         (byte)(spaces ? (int)(lerp((double)(sc_a_G),(double)(sc_b_G),final_gradient)) : (int)(lerp((double)(sc_b_G),(double)(sc_a_G),temp_result))),
                         (byte)(spaces ? (int)(lerp((double)(sc_a_R),(double)(sc_b_R),final_gradient)) : (int)(lerp((double)(sc_b_R),(double)(sc_a_R),temp_result)))
                        );
                        break;
                    case Space_Mode.Cut:
                        gradient_test = gradient >= 0;
                        dst[x,y]=ColorBgra.FromBgr(
                         (byte)(spaces ? (int)(lerp((double)(sc_a_B),(double)(sc_b_B),final_gradient)) : (int)(gradient_test ? sc_a_B : sc_b_B)),
                         (byte)(spaces ? (int)(lerp((double)(sc_a_G),(double)(sc_b_G),final_gradient)) : (int)(gradient_test ? sc_a_G : sc_b_G)),
                         (byte)(spaces ? (int)(lerp((double)(sc_a_R),(double)(sc_b_R),final_gradient)) : (int)(gradient_test ? sc_a_R : sc_b_R))
                        );
                        break;
                    default: 
                        dst[x,y]=ColorBgra.FromBgra(
                         (byte)((int)(lerp((double)(sc_a_B),(double)(sc_b_B),final_gradient))),
                         (byte)((int)(lerp((double)(sc_a_G),(double)(sc_b_G),final_gradient))),
                         (byte)((int)(lerp((double)(sc_a_R),(double)(sc_b_R),final_gradient))),
                            (byte)(spaces ? 255 : 0)
                            );
                        break;
                    }
                    break;
                    default: switch(space_mode){
                    case Space_Mode.Gradient:
                        temp_result = Math.Round(255 * final_gradient);
                        temp_result_2 = cut(gradient*2+.5,0,1) * 255;
                        temp_result = spaces ? temp_result : temp_result_2;
                        dst[x,y]=ColorBgra.FromBgr((byte)(temp_result),(byte)(temp_result),(byte)(temp_result));
                        break;
                    case Space_Mode.Cut:
                        temp_result = spaces ? Math.Round(255 * final_gradient) : (gradient >= 0 ? 255 : 0);
                        dst[x,y]=ColorBgra.FromBgr((byte)(temp_result),(byte)(temp_result),(byte)(temp_result));
                        break;
                    default: 
                        temp_result = Math.Round(255 * final_gradient);
                        dst[x,y]=ColorBgra.FromBgra((byte)(temp_result),(byte)(temp_result),(byte)(temp_result),(byte)(spaces ? 255 : 0));
                        break;
                    }
                    break;
             }


        }
    }
}

enum Random_Repetition_Mode{
    All,
    Cut_Periodic,
    Cut_Continuous,
    Periodic_Continuous
}

enum CS_Mode{
    Grayscale,
    Duotone,
    RGB_Random,
    HSV_Random
}

enum Space_Mode{
    Alpha,
    Cut,
    Gradient
}

enum Sym_Mode{
    None,
    A,
    B,
}

 

 

Edited by Reptillian
Added enum into C# Source Code.
  • Like 1
  • Upvote 1

G'MIC Filter Developer

 

I am away from this forum for undetermined amount of time: If you really need anything related to my PDN plugin or my G'MIC filter within G'MIC plugin, then you can contact me via Paint.NET discord, and mention me.

Posted

That's pretty cool @Reptillian!  I could see me using this.  You're getting good at C# code.  Keep up the good work.  😊

 

randomgradientbars_01.png

  • 1 month later...
Posted

This is pretty neat @NSD!  Selecting the Polygon and playing with the 'Tens and 'Arc' gives you limitless shapes.

Maybe a little more information about these two selections would be  beneficial for everyone.  I simply played with them to see what they do.

Thank you for coding this.  ☺️

 

DrawingTool_01.png

 

  • Like 2
  • Upvote 1
Posted

Thanks, but I need to clarify the limitations of this plugin.
The implemented Undo function is extremely simple, so that each time the left mouse button is lifted, the entire canvas is saved in memory.
This means extremely high memory consumption depending on the complexity of the drawing and the size of the canvas.
It is advisable to save the drawing on the canvas from time to time with the OK button. At this point the memory is freed.
If you do not move the drawing on the canvas you will be able to continue it when the plugin is run again. The grid will fit perfectly.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...