Jump to content

GPU Drawing Effect Questions


Go to solution Solved by Rick Brewster,

Recommended Posts

Thanks for clarifying.
With G.D.I.+ classic effects I would use Brushes etc. all within a using block, which seemed like a tidy way to do it.
For this one there are only two brushes - re-used on each iteration of the loop, just changing the colour... so will not worry.
Presumably the resources are released when the effect is closed anyway.

 

Red ochre Plugin pack.............. Diabolical Drawings ................Real Paintings

 

PdnForumSig2.jpg

Link to comment
Share on other sites

Is it possible to get H,S,V values from a ColorRgba128Float, for one pixel, in the OnDraw() method?

 

I cannot see any way of simply doing this?
There is a  'ColorHsv96Float.FromRgb(ColorRgb96Float)' conversion but no ColorRgb128Float to ColorRgb96Float cast or conversion?... that I can find.
I can access the ColorRgba128Float r,g,b,a values but cannot find an option to create a ColorRgb96Float from the r,g & b values?

Do I have to write my own conversion methods to calculate H,S,V from the r,g,b,a values and just ignore the ColorHsv96Float type?

 

Any example code or references appreciated ...
I have looked through @Rick Brewster Github effect samples. Very useful for getting radial gradient brushes working b.t.w. but I could only see shader conversions for HSV.

 

Red ochre Plugin pack.............. Diabolical Drawings ................Real Paintings

 

PdnForumSig2.jpg

Link to comment
Share on other sites

ColorRgba128Float has an Rgb property that gives you the RGB values in a ColorRgb96Float

 

https://paintdotnet.github.io/apidocs/api/PaintDotNet.Imaging.ColorRgba128Float.Rgb.html

  • Thanks 1

The Paint.NET Blog: https://blog.getpaint.net/

Donations are always appreciated! https://www.getpaint.net/donate.html

forumSig_bmwE60.jpg

Link to comment
Share on other sites

So you can "extract" the ColorRgb96Float, then convert to HSV, do what you need there, then convert back to ColorRgb96Float. Then cast back to ColorRgba128Float and pull in the original alpha value with { with A = ... } syntax

 

ColorRgba128Float rgba1 = ...;
ColorRgb96Float rgb1 = rgba1.Rgb;
ColorHsv96Float hsv = ColorHsv96Float.FromRgb(rgb1);
... do things to hsv ...
ColorRgb96Float rgb2 = hsv.ToRgb();
ColorRgba128Float rgba2 = (ColorRgba128Float)rgb2 with { A = rgba1.A };

 

 

  • Thanks 1

The Paint.NET Blog: https://blog.getpaint.net/

Donations are always appreciated! https://www.getpaint.net/donate.html

forumSig_bmwE60.jpg

Link to comment
Share on other sites

Thanks for that!
I didn't know about the ColorRgba128Float Rgb property, though I suspected there must be a way.

 

Your code example is exactly what I was intending...
To convert the Primary and Secondary Colors to h,s,v values and 'morph' from one to the other, each iteration by gradually changing h,s,v, then converting back to a value the Brush can use.
Very useful to see the correct way to do this.

  • Upvote 1

 

Red ochre Plugin pack.............. Diabolical Drawings ................Real Paintings

 

PdnForumSig2.jpg

Link to comment
Share on other sites

  • 2 weeks later...

Here is the latest versionSlinkyPlus.zip

It will only run on Pdn 5.1+ (currently beta).

Tip: set you Primary and Secondary colours before running to explore all the new colour choices!

Codelab code below... I'm sure there will be code that could be more efficient but I'm pleased with the speed it renders, especially as I don't have a dedicated G.P.U.

Spoiler
// Name:SlinkyPlus
// Submenu:Iterative lines
// Author:John Robbins (Red ochre)
// Title:SlinkyPlus       Oct 2024       Red ochre
// Version:3.41
// Desc:Draws varying shapes along a path.
// Keywords:Circle, Ellipse, Triangle, Rectangle, Square, Pentagon, Hexagon, Heptagon, Octagon, Nonagon, Decagon, Polygon, stars, shells, rainbows
// URL:
// Help:Always makes the background clear but can use the layer's colours, so often best to duplicate the layer first. Also useful to set Primary and Secondary colours before running the effect.


#region UICode
ListBoxControl Amount16 = 0; // Shape|Ellipse|Triangle|Rectangle|Pentagon|5 star|Hexagon|Heptagon|7 star|Octagon|Nonagon|9 star|Decagon|Hendecagon|11 star
IntSliderControl Amount1 = 11; // [2,2000] Number of shapes
PanSliderControl Amount2 = new Vector2Double(0.000, 0.000); // Start position
IntSliderControl Amount3 = 50; // [0,1000] Start size
DoubleSliderControl Amount4 = 0; // [-10,10] Wide....................Start shape......................Tall
DoubleSliderControl Amount13 = 0; // [-180,180] Start angle
PanSliderControl Amount5 = new Vector2Double(0.000, 0.000); // End position
IntSliderControl Amount6 = 50; // [0,1000] End size
DoubleSliderControl Amount7 = 0; // [-10,10] Wide....................End shape........................Tall
DoubleSliderControl Amount14 = 720; // [-1800,1800] End angle
ListBoxControl Amount8 = 1; // Curve type|half ellipse|half sine|2 bend|3 bend|4 bend|5 bend|6 bend|8 bend|16 bend
DoubleSliderControl Amount9 = 0; // [-100,100] Curvature
DoubleSliderControl Amount17 = 0; // [-100,500] Squeeze...........Middle............Bulge
DoubleSliderControl Amount10 = 10; // [0,100] Line width
ListBoxControl Amount11 = 0; // Line colour|0.YRMBCG Rainbow|1.CBMRYG Rainbow|2.MRYGCB Rainbow|3.Primary|4.Secondary|5.Primary to Secondary|6.Secondary to Primary|7.Alternate Primary & Secondary|8.Colours from source image|9.Alternate src colour and inverse|10.Black|11.White|12.Primary to Secondary via HSV short|13.Primary to Secondary via HSV long|14.Secondary to Primary via HSV short|15.Secondary to Primary via HSV long
ListBoxControl Amount15 = 1; // Fill colour|0.No fill|1.As line colour|2.YRMBCG Rainbow|3.CBMRYG Rainbow|4.MRYGCB Rainbow|5.Primary|6.Secondary|7.Primary to Secondary|8.Secondary to Primary|9.Alternate Primary & Secondary|10.Colours from source image|11.Alternate src colour and inverse|12.Black|13.White|14.Primary to Secondary via HSV Short|15.Primary to Secondary via HSV Long|16.Secondary to Primary HSV Short|17.Secondary to Primary HSV Long|18.Radial Primary to Secondary|19.Radial Primary to Secondary HSV short|20.Radial Primary to Secondary HSV long|21.Radial Secondary to Primary|22.Radial Secondary to Primary HSV short|23.Radial Secondary to Primary HSV long|24.Pastel Radial rainbow|25.Radial rainbow 1|26.Radial rainbow 2|27.Radial rainbow 3
#endregion

protected override unsafe void OnDraw(IDeviceContext deviceContext)
{
  //Compiled with codelab v6.12 against Pdn 5.100.9038.5741 portable, (05/10/2024)
  // To do: When in VS, rename 'Amount' U.I. variables, set Pan slider defaults and possibly add tabbed U.I. with colorwheels.
  RectInt32 sel = Environment.Selection.RenderBounds;//selection
  using IEffectInputBitmap<ColorBgra32> sourceBitmap = Environment.GetSourceBitmapBgra32(); //Safely getting the src image
  using IBitmapLock<ColorBgra32> sourceLock = sourceBitmap.Lock(new RectInt32(0, 0, Environment.Document.Size));
  RegionPtr<ColorBgra32> sourceRegion = sourceLock.AsRegionPtr();

  int LineNum = Amount1; //number of shapes drawn
  
  ManagedColor primaryColorM = Environment.PrimaryColor; 
  ColorRgba128Float PC = primaryColorM.Get(deviceContext);
  ManagedColor secondaryColorM = Environment.SecondaryColor; 
  ColorRgba128Float SC = secondaryColorM.Get(deviceContext);
  
 //for HSV gradients (Note: Hue, 0f to 360f.Saturation, 0f to 100f. Value, 0f to 100f...BUT alpha is 0f to 1f)
  ColorRgb96Float PCrgb = PC.Rgb;//Primary
  ColorHsv96Float PChsv = ColorHsv96Float.FromRgb(PCrgb);
  float PCh = PChsv.Hue;float PCs = PChsv.Saturation;float PCv = PChsv.Value;float PCa = PC.A;
  ColorRgb96Float SCrgb = SC.Rgb;//Secondary
  ColorHsv96Float SChsv = ColorHsv96Float.FromRgb(SCrgb);
  float SCh = SChsv.Hue;float SCs = SChsv.Saturation;float SCv = SChsv.Value;float SCa = SC.A;
// define brush and stroke style... StrokeStyle not needed here so use 'null' when drawing the ellipses
    ISolidColorBrush lineBrush = deviceContext.CreateSolidColorBrush(PC);
    ISolidColorBrush fillBrush = deviceContext.CreateSolidColorBrush(PC);
    deviceContext.AntialiasMode = AntialiasMode.PerPrimitive;  // or .Aliased
 // Create a variables used for Radial gradient brush in fill colour
    int GsN = 32;// Gradient stop Number, 32 stops seems smooth (0 to 31 within loop)
    GradientStop[] gradientStops = new GradientStop[GsN];
    gradientStops[0] = new GradientStop(0.0f, SC);
    gradientStops[GsN - 1] = new GradientStop(1.0f, PC);//just to declare
    IGradientStopCollection gradientStopCollection = deviceContext.CreateGradientStopCollection(gradientStops, GradientStopGamma.Srgb,ExtendMode.Mirror);//gamma type makes no difference? Srgb looks same as Linear?
    Point2Float radgradOffSet = new Point2Float(0,0);

 //HSV differences--------------------------------------
    float newH,newS,newV,newA;
    ColorHsv96Float tempHSV;
    ColorRgb96Float tempRGB;
    ColorRgba128Float tempCOL;
    float hdShort = 0f,hdLong = 0f;//just to declare a value

  
/*#if DEBUG
Debug.Write(" PChue = ");Debug.Write(PCh);Debug.Write(", PCsat = ");Debug.Write(PCs);Debug.Write(", PCval = ");Debug.Write(PCv);Debug.Write(", PCalpha = ");Debug.WriteLine(PCa);
Debug.Write(" SChue = ");Debug.Write(SCh);Debug.Write(", SCsat = ");Debug.Write(SCs);Debug.Write(", SCval = ");Debug.Write(PCv);Debug.Write(", SCalpha = ");Debug.WriteLine(SCa);
#endif*/
 float PSdiff = PCh - SCh;float SPdiff = SCh - PCh;
    if(PSdiff > 0){
      if(PSdiff > 180f){hdLong = PSdiff;hdShort = 360f - hdLong;}
      else{hdShort = -PSdiff;hdLong = 360f - hdShort;}
    }
    if(SPdiff > 0){
      if(SPdiff > 180f){hdLong = -SPdiff;hdShort = -(360f - SPdiff);}
      else{hdShort = SPdiff;hdLong = 360f - hdShort;}
    }
 //-------my HSVcolP2S METHOD...Primary to Secondary (used for both each shape colour AND to populate gradient brush stops)----------------------- 
ColorRgba128Float HSVcolP2S(int n, int N, bool shortdiff){
   float HuediffincS = hdShort /(float)N;//N will be Gsn for radial gradient OR LineNum - 1 within the loop
   float HuediffincL = hdLong /(float)N;//+ve or -ve = different directions around colour wheel

   float Satdiffinc = (PCs - SCs)/(float)N;//range -100f to 100f, probably much smaller
   float Valdiffinc = (PCv - SCv)/(float)N;//range -100f to 100f
   float Adiffinc = (PCa - SCa)/(float)N;//range 0f to 1f (IMPORTANT!)
   if(shortdiff){newH = (PCh + (n * HuediffincS));}//short
   else {newH = PCh - (n * HuediffincL);}//long

   if(newH < 0){newH += 360f;}//Keep hue above zero
   newH = Math.Abs(newH%360f);//SHOULD keep hue within 0f to 360f range
  
   newS = Math.Clamp(PCs - (n * Satdiffinc),0,100f);
   newV = Math.Clamp(PCv - (n * Valdiffinc),0,100f);
   newA = Math.Clamp(PCa - (n * Adiffinc),0,1f);
     
   tempHSV = new ColorHsv96Float(newH,newS,newV);
   tempRGB = tempHSV.ToRgb();
   tempCOL = (ColorRgba128Float)tempRGB with { A = newA };//new syntax for me, thanks Rick!
   return tempCOL;}
//-----my HSVcolS2P method... Secondary to Primary!
ColorRgba128Float HSVcolS2P(int n, int N, bool shortdiff){
  float HuediffincS = hdShort /(float)N;
  float HuediffincL = hdLong /(float)N;
  float Satdiffinc = (SCs - PCs)/(float)N;
  float Valdiffinc = (SCv - PCv)/(float)N;
  float Adiffinc = (SCa - PCa)/(float)N;
  if(shortdiff){newH = (SCh - (n * HuediffincS));}
  else {newH = SCh + (n * HuediffincL);}
  if(newH < 0){newH += 360f;}
  newH = Math.Abs(newH%360f);
  newS = Math.Clamp(SCs - (n * Satdiffinc),0,100f);
  newV = Math.Clamp(SCv - (n * Valdiffinc),0,100f);
  newA = Math.Clamp(SCa - (n * Adiffinc),0,1f);
  tempHSV = new ColorHsv96Float(newH,newS,newV);
  tempRGB = tempHSV.ToRgb();
  tempCOL = (ColorRgba128Float)tempRGB with { A = newA };
  return tempCOL;}

if(Amount15 >= 18 && Amount15 < 24)//unchanging Radial gradient brush
    { for(int Gs = 0;Gs < GsN;Gs++){
          double PSrat = (double)(Gs)/(double)(GsN - 1);double iPSrat = 1.0 - PSrat;
          float stopPos = (float)PSrat;
          switch (Amount15)//fill colour
                {
                    case 18://Radial Primary to Secondary
                        float PSR = (float)((iPSrat * PC.R) + (PSrat * SC.R));
                        float PSG = (float)((iPSrat * PC.G) + (PSrat * SC.G));
                        float PSB = (float)((iPSrat * PC.B) + (PSrat * SC.B)); 
                        float PSA = (float)((iPSrat * PC.A) + (PSrat * SC.A));
                        ColorRgba128Float PScol = new ColorRgba128Float(PSR, PSG, PSB, PSA);
                        gradientStops[Gs] = new GradientStop(stopPos,PScol);
                    break;
                    case 19://Radial  Primary 2 Secondary HSV short
                        ColorRgba128Float PShsvcolourshort =  HSVcolP2S(Gs,GsN - 1, true);//short
                        gradientStops[Gs] = new GradientStop(stopPos,PShsvcolourshort);
                    break;
                    case 20://Radial  Primary 2 Secondary HSV long
                        ColorRgba128Float PShsvcolourlong =  HSVcolP2S(Gs,GsN - 1, false);//long
                        gradientStops[Gs] = new GradientStop(stopPos,PShsvcolourlong);
                    break;
                    case 21://Radial Secondary to Primary
                        float SPR = (float)((iPSrat * SC.R) + (PSrat * PC.R));
                        float SPG = (float)((iPSrat * SC.G) + (PSrat * PC.G));
                        float SPB = (float)((iPSrat * SC.B) + (PSrat * PC.B)); 
                        float SPA = (float)((iPSrat * SC.A) + (PSrat * PC.A));
                        ColorRgba128Float SPcol = new ColorRgba128Float(SPR, SPG, SPB, SPA);
                        gradientStops[Gs] = new GradientStop(stopPos,SPcol);
                    break;
                    case 22://Radial Secondary to Primary HSV short
                        ColorRgba128Float SPhsvcolourshort =  HSVcolS2P(Gs,GsN - 1, true);//short
                        gradientStops[Gs] = new GradientStop(stopPos,SPhsvcolourshort);
                    break;
                    case 23://Radial Secondary to Primary HSV long
                        ColorRgba128Float SPhsvcolourlong =  HSVcolS2P(Gs,GsN - 1, false);//long
                        gradientStops[Gs] = new GradientStop(stopPos,SPhsvcolourlong);
                    break;
                }//end switch block
    }//end PS loop
 gradientStopCollection = deviceContext.CreateGradientStopCollection(gradientStops, GradientStopGamma.Linear,ExtendMode.Mirror);
  }//end unchanging Radial gradient brush

    int Vertices = 3;
    float lineW = (float)(Amount10);//now a float from U.I. double
    int H = sel.Height;
    int W = sel.Width;
    double dx = W / 2;
    double dy = H / 2;
    double Pi = Math.PI;
    double Pi2 = Pi * 2;
    
    float EstarAng = (float)Amount13;//D2D transform takes float angle in degrees
    float EendAng = (float)Amount14;
    float EdiffAng = EendAng - EstarAng;
    float EiterAng = EdiffAng/(LineNum - 1f);
 //start
    double A1x = Amount2.X; double A1y = Amount2.Y;//CP1 
    float staS = Amount3;//start size
    double starat = Amount4 / 10;//stErat = start Ellipse ratio
    float Swidth = staS; if (starat > 0) { Swidth = (float)(staS * (1 - starat)); }
    float Sheight = staS; if (starat < 0) { Sheight = (float)(staS * (1 + starat)); }
 //end
    double A2x = Amount5.X; double A2y = Amount5.Y;//CP2 - end
    float endS = Amount6;// end size
    double endrat = Amount7 / 10;// = end Ellipse ratio
    float Ewidth = endS; if (endrat > 0) { Ewidth = (float)(endS * (1 - endrat)); }
    float Eheight = endS; if (endrat < 0) { Eheight = (float)(endS * (1 + endrat)); }
 // NEW need half values of start and end widths and heights to offset positions
    float halfstaW = Swidth/2f;float halfstaH = Sheight/2f;
    float halfendW = Ewidth/2f;float halfendH = Eheight/2f;
 // differences
    float Wdiff = Ewidth - Swidth;
    float Hdiff = Eheight - Sheight;
 // curvature
    double curvrat = Amount9 / 100;
 /* Pan slider defaults and range cannot be edited in codelab 6.12.
    So here, if both pan sliders are at zero I set the start and end coords.
    When compiled in VS this can go and these defaults and a range of 2 to -2 set in OnCreatePropertyCollection()*/
    if (A1x == 0 && A1y == 0 && A2x == 0 && A2y == 0){ A1x = -0.75; A1y = -0.65; A2x = 0.75; A2y = 0.65; }

 // The shapes points are calculated from the centre coord BUT the major and minor radii must be factored in for position
    float Cp1x = (float)(sel.Left + halfstaW + ((A1x + 1) * dx));
    float Cp1y = (float)(sel.Top + halfstaH + ((A1y + 1) * dy));
    float Cp2x = (float)(sel.Left + halfendW + ((A2x + 1) * dx));
    float Cp2y = (float)(sel.Top + halfendH + ((A2y + 1) * dy));

 // Create points for curve, the path the ellipses take.
    Point2Float CP1 = new Point2Float(Cp1x, Cp1y);//start ellipse centre

    float Xdiff = Cp2x - Cp1x;
    float Ydiff = Cp2y - Cp1y;
    float LN = LineNum - 1;
    float xdiv = Xdiff / LN;
    float ydiv = Ydiff / LN;
    float Wdiv = Wdiff / LN;
    float Hdiv = Hdiff / LN;

    double dist = Math.Sqrt((Xdiff * Xdiff) + (Ydiff * Ydiff));
    double r = dist / 2;
    float Ddiv = (float)(dist / LN);// minimum number of ellipses now 2 

    double stangle = Math.Atan2(Ydiff, Xdiff);
    double tangangle = stangle + (Pi / 2);

 
    //variables declared outside loop 
    float angle = MathF.PI * (2f/Vertices);//for polygons
    Point2Float vert;
    double curve = 0;
    double Brat = Amount17/100;
    
 
// The loop
for (int N = 0; N < LineNum; N++)
            {
                double Drat = (double)(N ) / (double)(LineNum - 1);//Drat correctly goes from 0 to 1.0
                double iDrat = 1 - Drat;
                int M = N + 1; 
               switch (Amount8)//curvature
                {
                    case 0://semi-circular - not great as spacing looks odd!
                        curve = r * Math.Sqrt(Math.Sin(Drat * Pi)) * curvrat;break;
                    case 1://semi-sinusoidal - make this default
                        curve = r * Math.Sin(Drat * Pi) * curvrat;break;
                    case 2://sinusoidal
                        curve = r * Math.Sin(Drat * Pi * 2) * curvrat;break;
                    case 3://3 bend... new ones added here and below
                        curve = r * Math.Sin(Drat * Pi * 3) * curvrat;break;
                    case 4:// double sinusoidal 4 bend
                        curve = r * Math.Sin(Drat * Pi * 4) * curvrat;break;
                    case 5://5 bend
                        curve = r * Math.Sin(Drat * Pi * 5) * curvrat;break;
                    case 6://6 bend
                        curve = r * Math.Sin(Drat * Pi * 6) * curvrat;break;
                    case 7://8 bend
                        curve = r * Math.Sin(Drat * Pi * 8) * curvrat;break;
                    case 8://16 bend
                        curve = r * Math.Sin(Drat * Pi * 16) * curvrat;break;
                }

                float Xcurve = (float)(curve * Math.Cos(tangangle));
                float Ycurve = (float)(curve * Math.Sin(tangangle));
                
                //Introduce bulge/squeeze
                float wrad = (float)(Swidth + (N * Wdiv));
                float wbulge = (float)(Math.Sqrt(Math.Sin(Drat * Pi)) * Brat * wrad);
                float Wrad = wrad + wbulge;
                float hrad = (float)(Sheight + (N * Hdiv));
                float hbulge = (float)(Math.Sqrt(Math.Sin(Drat * Pi)) * Brat * hrad);
                float Hrad = hrad + hbulge;
                
                float mcx = (float)(Cp1x + (N * xdiv)) - (Wrad / 2) + Xcurve + (wbulge/2);
                float mcy = (float)(Cp1y + (N * ydiv)) - (Hrad / 2) + Ycurve + (hbulge/2);
                Point2Float centre = new Point2Float(mcx, mcy);//ellipse centres
                //ellipse centres can be off canvas BUT cannot sample src pixels that don't exist or out of bounds exception!
                int mcxi = (int)Math.Clamp(mcx, sel.Left, sel.Right - 1);//Thanks _koh_ & Rick!
                int mcyi = (int)Math.Clamp(mcy, sel.Top, sel.Bottom - 1);
               
                //for rainbows
                double C1d = (Math.Sin((Drat * Pi2) + (Pi2 * 0.000000)) * 128) + 128;//adding Pi2 * 0 to 
                double C2d = (Math.Sin((Drat * Pi2) + (Pi2 * 0.666667)) * 128) + 128;//make comparison
                double C3d = (Math.Sin((Drat * Pi2) + (Pi2 * 0.333333)) * 128) + 128;//easier
                byte C1 = (byte)(Math.Clamp(C1d,0,255));//Thanks _koh_
                byte C2 = (byte)(Math.Clamp(C2d,0,255));
                byte C3 = (byte)(Math.Clamp(C3d,0,255));
                double C1drat = Math.Clamp(C1d/255,0,1.0);//used for radial gradient rainbows
                double C2drat = Math.Clamp(C2d/255,0,1.0);
                double C3drat = Math.Clamp(C3d/255,0,1.0);
               
               switch (Amount11)//line colour
                {
                    case 0://rainbow YRMBCG
                        ColorRgb96Float RBG = (LinearColor)(SrgbColor)ColorBgr24.FromBgr(C2, C3, C1);// The casts convert from sRGB (companded) to linear colour space that D2D expects.
                        lineBrush.Color = RBG;break;
                    case 1://rainbow CBMRYG
                        ColorRgb96Float BRG = (LinearColor)(SrgbColor)ColorBgr24.FromBgr(C1, C3, C2);
                        lineBrush.Color = BRG;break;
                    case 2://rainbow MRYGCB
                        ColorRgb96Float RGB = (LinearColor)(SrgbColor)ColorBgr24.FromBgr(C3, C2, C1);
                        lineBrush.Color = RGB;break;
                    case 3:// Primary
                        lineBrush.Color = PC;break;
                    case 4:// Secondary
                        lineBrush.Color = SC;break;
                    case 5:// Primary to Secondary
                        float Cf1 = (float)((iDrat * PC.R) + (Drat * SC.R));
                        float Cf2 = (float)((iDrat * PC.G) + (Drat * SC.G));
                        float Cf3 = (float)((iDrat * PC.B) + (Drat * SC.B)); 
                        float Cf4 = (float)((iDrat * PC.A) + (Drat * SC.A));
                        lineBrush.Color = new ColorRgba128Float(Cf1, Cf2, Cf3, Cf4);break;
                    case 6:// Secondary to Primary
                        Cf1 = (float)((iDrat * SC.R) + (Drat * PC.R));
                        Cf2 = (float)((iDrat * SC.G) + (Drat * PC.G));
                        Cf3 = (float)((iDrat * SC.B) + (Drat * PC.B)); 
                        Cf4 = (float)((iDrat * SC.A) + (Drat * PC.A));
                        lineBrush.Color = new ColorRgba128Float(Cf1, Cf2, Cf3, Cf4);break;
                    case 7:// Alternate primary and secondary
                        if(N%2 == 0){ lineBrush.Color = PC ;} else  lineBrush.Color = SC;break;
                    case 8://use source colours
                        ColorBgra32 srcCol = sourceRegion[mcxi, mcyi];//Clamped to canvas, protected from out of bounds exeptions.
                        ColorRgba128Float sColA= (LinearColor)(SrgbColor)ColorBgr24.FromBgr(srcCol.B, srcCol.G, srcCol.R);
                        sColA.A = (float)(srcCol.A)/255f;//ColorRgba128Float values are 4 * 32 bit float values (0 to 1f)
                        lineBrush.Color = sColA;break;
                    case 9:// Alternate src colour with inverted src
                        ColorBgra32 srcC = sourceRegion[mcxi, mcyi];
                        byte iR = (byte)(255 - srcC.R);byte iG = (byte)(255 - srcC.G); byte iB = (byte)(255 - srcC.B);
                        ColorRgba128Float sCol = (LinearColor)(SrgbColor)ColorBgr24.FromBgr(srcC.B, srcC.G, srcC.R); sCol.A = (float)(srcC.A)/255f;
                        ColorRgba128Float invsCol = (LinearColor)(SrgbColor)ColorBgr24.FromBgr(iB, iG, iR);invsCol.A = sCol.A;
                        if(N%2 == 0){ lineBrush.Color = sCol ;} else  lineBrush.Color = invsCol;break;
                    case 10: lineBrush.Color = LinearColors.Black;break;
                    case 11: lineBrush.Color = LinearColors.White;break;
                    case 12://Primary to Secondary via HSV
                        lineBrush.Color = HSVcolP2S(N,LineNum - 1, true);break;//calling HSVcolP2S method
                    case 13://Primary to Secondary via HSV LONG (more bloody rainbows!)
                        lineBrush.Color = HSVcolP2S(N,LineNum - 1, false);break;
                    case 14://Secondary to Primary via HSV
                        lineBrush.Color = HSVcolS2P(N,LineNum - 1, true);break;//calling HSVcolS2P method
                    case 15://Secondary to Primary via HSV LONG 
                        lineBrush.Color = HSVcolS2P(N,LineNum - 1, false);break;

                   }// end line colour switch block ----------------------------------------------------------------

                  switch (Amount15)//fill colour
                        {
                    case 0://no fill
                        fillBrush.Color = new ColorRgba128Float(0,0,0,0);break;
                    case 1:// as line colour
                        fillBrush.Color = lineBrush.Color;break;
                    case 2://rainbow YRMBCG
                        ColorRgb96Float RBG = (LinearColor)(SrgbColor)ColorBgr24.FromBgr(C2, C3, C1);
                        fillBrush.Color = RBG;break;
                    case 3://rainbow CBMRYG
                        ColorRgb96Float BRG = (LinearColor)(SrgbColor)ColorBgr24.FromBgr(C1, C3, C2);
                        fillBrush.Color = BRG;break;
                    case 4://rainbow MRYGCB
                        ColorRgb96Float RGB = (LinearColor)(SrgbColor)ColorBgr24.FromBgr(C3, C2, C1);
                        fillBrush.Color = RGB;break;
                    case 5://Primary
                        fillBrush.Color = PC;break;
                    case 6://Secondary
                        fillBrush.Color = SC;break;
                    case 7:// Primary to Secondary
                        float Cf1 = (float)((iDrat * PC.R) + (Drat * SC.R));
                        float Cf2 = (float)((iDrat * PC.G) + (Drat * SC.G));
                        float Cf3 = (float)((iDrat * PC.B) + (Drat * SC.B)); 
                        float Cf4 = (float)((iDrat * PC.A) + (Drat * SC.A));
                        fillBrush.Color = new ColorRgba128Float(Cf1, Cf2, Cf3, Cf4);break;
                    case 8:// Secondary to Primary
                        Cf1 = (float)((iDrat * SC.R) + (Drat * PC.R));
                        Cf2 = (float)((iDrat * SC.G) + (Drat * PC.G));
                        Cf3 = (float)((iDrat * SC.B) + (Drat * PC.B)); 
                        Cf4 = (float)((iDrat * SC.A) + (Drat * PC.A));
                        fillBrush.Color = new ColorRgba128Float(Cf1, Cf2, Cf3, Cf4);break;
                    case 9:// Alternate primary and secondary
                        if(N%2 == 0){ fillBrush.Color = PC ;} else  fillBrush.Color = SC;break;
                    case 10://use source colours
                        ColorBgra32 srcCol = sourceRegion[mcxi, mcyi];
                        ColorRgba128Float sColA= (LinearColor)(SrgbColor)ColorBgr24.FromBgr(srcCol.B, srcCol.G, srcCol.R);
                        sColA.A = (float)(srcCol.A)/255f;
                        fillBrush.Color = sColA;break;
                    case 11:// Alternate src colour with inverted src
                        ColorBgra32 srcC = sourceRegion[mcxi, mcyi];
                        byte iR = (byte)(255 - srcC.R);byte iG = (byte)(255 - srcC.G); byte iB = (byte)(255 - srcC.B);
                        ColorRgba128Float sCol = (LinearColor)(SrgbColor)ColorBgr24.FromBgr(srcC.B, srcC.G, srcC.R); sCol.A = (float)(srcC.A)/255f;
                        ColorRgba128Float invsCol = (LinearColor)(SrgbColor)ColorBgr24.FromBgr(iB, iG, iR);invsCol.A = sCol.A;
                        if(N%2 == 0){ fillBrush.Color = sCol ;} else  fillBrush.Color = invsCol;break;
                    case 12: fillBrush.Color = LinearColors.Black;break;
                    case 13: fillBrush.Color = LinearColors.White;break;
                    case 14:  fillBrush.Color = HSVcolP2S(N,LineNum - 1, true);break;//HSV short 
                    case 15:  fillBrush.Color = HSVcolP2S(N,LineNum - 1, false);break;//HSV long
                    case 16:  fillBrush.Color = HSVcolS2P(N,LineNum - 1, true);break;//HSV short 
                    case 17:  fillBrush.Color = HSVcolS2P(N,LineNum - 1, false);break;//HSV long
                   // case 18 to case 23, radial gradient brush, created before loop. Radial rainbows change each shape and are below.  
                  }// end fill colour switch block -------------------------------------
                  
      
          if(Amount15 >= 24)//Radial Rainbows. These change slightly on each shape iteration
          {
              double toneOffSet = 0;if(Amount15 == 24){toneOffSet = 48;}// for light pastel option, could remove this option?
            for (int Gs = 0; Gs < GsN; Gs++){
              float rainRat = (float)Gs/(float)(GsN - 1.0f);
              double Gs1d = (Math.Sin(((Drat + rainRat + 0.000000) * Pi2)) * 128) + 128 + toneOffSet;//adding Pi2 * 0 to 
              double Gs2d = (Math.Sin(((Drat + rainRat + 0.666667) * Pi2)) * 128) + 128 + toneOffSet;//make comparison
              double Gs3d = (Math.Sin(((Drat + rainRat + 0.333333) * Pi2)) * 128) + 128 + toneOffSet;//easier
              byte Gs1 = (byte)(Math.Clamp(Gs1d,0,255));
              byte Gs2 = (byte)(Math.Clamp(Gs2d,0,255));
              byte Gs3 = (byte)(Math.Clamp(Gs3d,0,255));
              ColorRgb24 radCol = ColorRgb24.FromRgb(Gs2,Gs3,Gs1);//case 24 or 25
              if(Amount15 == 26){radCol = ColorRgb24.FromRgb(Gs1,Gs3,Gs2);}//case 26
              if(Amount15 == 27){radCol = ColorRgb24.FromRgb(Gs3,Gs2,Gs1);}//case 27
              gradientStops[Gs] = new GradientStop(rainRat,(LinearColor)(SrgbColor)radCol);
              }//end stop creation loop
            gradientStopCollection = deviceContext.CreateGradientStopCollection(gradientStops, GradientStopGamma.Linear,ExtendMode.Mirror);
          }//end if RAINBOW radial gradient

          float iterAng = EstarAng + (N * EiterAng);// used for rotation transform

    switch(Amount16){
                    case 0://ellipses
                          Ellipse E = new Ellipse(mcx,mcy,Wrad,Hrad);//not clamped coords
                          
                          using (deviceContext.UseRotateAtTransform(iterAng, centre)){
                          if(Amount10 > 0){deviceContext.DrawEllipse(E, lineBrush, lineW, null);} 
                          if(Amount15 < 18){deviceContext.FillEllipse(E, fillBrush);}
                          else{IRadialGradientBrush radgradBrush = deviceContext.CreateRadialGradientBrush(
                              centre,radgradOffSet,Wrad,Hrad,gradientStopCollection,1f,null);
                                deviceContext.FillEllipse(E,radgradBrush);}
                          }//end ellipse using block
                    break;
                    case 1://triangles
                          Vertices = 3; angle = MathF.PI * (2f/Vertices);break;
                    case 2://rectangles
                          Vertices = 4; angle = MathF.PI * (2f/Vertices);break;
                    case 3://pentagons
                          Vertices = 5; angle = MathF.PI * (2f/Vertices);break;
                    case 4://5 stars
                          Vertices = 5; angle = MathF.PI * (4f/Vertices);break;
                    case 5://hexagon
                          Vertices = 6; angle = MathF.PI * (2f/Vertices);break;
                    case 6://heptagon
                          Vertices = 7; angle = MathF.PI * (2f/Vertices);break;
                    case 7://7 star
                          Vertices = 7; angle = MathF.PI * (4f/Vertices);break;
                    case 8://octagon
                          Vertices = 8; angle = MathF.PI * (2f/Vertices);break;
                    case 9://nonagon
                          Vertices = 9; angle = MathF.PI * (2f/Vertices);break;
                    case 10://9 star
                          Vertices = 9; angle = MathF.PI * (4f/Vertices);break;
                    case 11://decagon
                          Vertices = 10; angle = MathF.PI * (2f/Vertices);break;
                    case 12://hendecagon
                          Vertices = 11; angle = MathF.PI * (2f/Vertices);break;
                    case 13://11 star
                          Vertices = 11; angle = MathF.PI * (4f/Vertices);break;
                }//end shape switch block
 
    //rotate/draw & fill shapes of polygons and stars only
    if(Amount16 > 0){ Point2Float[] verts = new Point2Float[Vertices];//3 is min & arrays start at 0
                             for (int V = 0; V < Vertices; V++)
                             {vert = new Point2Float(centre.X + (MathF.Sin((float)(V +1f) * angle) * Wrad), centre.Y + (MathF.Cos((float)(V + 1f) * angle)* Hrad)); 
                              verts[V] = vert;}
                              using (deviceContext.UseRotateAtTransform(iterAng, centre)){
                              if(Amount10 > 0){deviceContext.DrawPolygon(verts,lineBrush,lineW,null);}
                              if(Amount15 < 18){deviceContext.FillPolygon(verts,fillBrush);}
                              else{IRadialGradientBrush radgradBrush = deviceContext.CreateRadialGradientBrush(
                              centre,radgradOffSet,Wrad,Hrad,gradientStopCollection,1f,null);
                                deviceContext.FillPolygon(verts,radgradBrush);}
                              }//end of polygon using block
                     }//end polygon generation loop
      }// end loop
            //No need to Dispose Brushes. only 2 SolidColorBrushes and 1 RadialGradientBrush... re-used each loop
}// end OnDraw

 

Note: the int M inside the loop is not needed but I can't work out how to edit the code once posted... without starting again!

  • Upvote 1

 

Red ochre Plugin pack.............. Diabolical Drawings ................Real Paintings

 

PdnForumSig2.jpg

Link to comment
Share on other sites

@BoltBait @toe_head2001 how hard would it be to add support for the new ManagedColor and ManagedColorProperty to CodeLab? It will always show up as a color wheel, no need to set the property control type

The Paint.NET Blog: https://blog.getpaint.net/

Donations are always appreciated! https://www.getpaint.net/donate.html

forumSig_bmwE60.jpg

Link to comment
Share on other sites

5 hours ago, Red ochre said:

I can't work out how to edit the code once posted... without starting again!

I think you double click on it? Took me a long time before I figured that out too 😂

  • Haha 1
  • Upvote 1

The Paint.NET Blog: https://blog.getpaint.net/

Donations are always appreciated! https://www.getpaint.net/donate.html

forumSig_bmwE60.jpg

Link to comment
Share on other sites

9 minutes ago, Rick Brewster said:

@BoltBait @toe_head2001 how hard would it be to add support for the new ManagedColor and ManagedColorProperty to CodeLab? It will always show up as a color wheel, no need to set the property control type

 

My goal is to do this before you release 5.1

 

I have updated one of my plugins to utilize ManagedColor, so I know what needs to be generated. It's just a matter of adjusting the generator code.  Should be easy--I just need to find some motivation...

 

Quote

Peel me off this Velcro seat
And get me moving

I sure as hell can't do it by myself...

 

  • Upvote 2
Link to comment
Share on other sites

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...