Red ochre Posted September 18 Author Share Posted September 18 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. Quote Red ochre Plugin pack.............. Diabolical Drawings ................Real Paintings Link to comment Share on other sites More sharing options...
Red ochre Posted September 26 Author Share Posted September 26 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. Quote Red ochre Plugin pack.............. Diabolical Drawings ................Real Paintings Link to comment Share on other sites More sharing options...
Rick Brewster Posted September 26 Share Posted September 26 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 1 Quote The Paint.NET Blog: https://blog.getpaint.net/ Donations are always appreciated! https://www.getpaint.net/donate.html Link to comment Share on other sites More sharing options...
Rick Brewster Posted September 26 Share Posted September 26 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 }; 1 Quote The Paint.NET Blog: https://blog.getpaint.net/ Donations are always appreciated! https://www.getpaint.net/donate.html Link to comment Share on other sites More sharing options...
Red ochre Posted September 26 Author Share Posted September 26 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. 1 Quote Red ochre Plugin pack.............. Diabolical Drawings ................Real Paintings Link to comment Share on other sites More sharing options...
Red ochre Posted Sunday at 10:48 PM Author Share Posted Sunday at 10:48 PM 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! 1 Quote Red ochre Plugin pack.............. Diabolical Drawings ................Real Paintings Link to comment Share on other sites More sharing options...
Rick Brewster Posted yesterday at 03:48 AM Share Posted yesterday at 03:48 AM @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 Quote The Paint.NET Blog: https://blog.getpaint.net/ Donations are always appreciated! https://www.getpaint.net/donate.html Link to comment Share on other sites More sharing options...
Rick Brewster Posted yesterday at 03:48 AM Share Posted yesterday at 03:48 AM 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 😂 1 1 Quote The Paint.NET Blog: https://blog.getpaint.net/ Donations are always appreciated! https://www.getpaint.net/donate.html Link to comment Share on other sites More sharing options...
BoltBait Posted yesterday at 03:50 AM Share Posted yesterday at 03:50 AM 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... 2 Quote Download: BoltBait's Plugin Pack | CodeLab | and a Free Computer Dominos Game Link to comment Share on other sites More sharing options...
Tactilis Posted yesterday at 07:22 AM Share Posted yesterday at 07:22 AM 3 hours ago, BoltBait said: Peel me off this Velcro seat And get me moving I sure as hell can't do it by myself I'm sure the rest of the description in Longview doesn't apply to you @BoltBait! 😉 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.