Jump to content

'FurBlur' - ROI & 'Random' problems.


Red ochre
 Share

Recommended Posts

I have successfully used Null54's method of using another surface to get around ROI banding in other plugins.
However, I am stumped with this one!

There are 2 main differences between this and the successful ones:
1. I am trying to copy the src to the dst, then randomly trail/blur lines across the ROIs.
2. I am trying to use random numbers in the same way they are generated by codelab.

I'm not sure which (or both) is causing the problems, or even if this way of doing things is possible. I would prefer to attack the canvas in a random way as if I used the normal y/x loops I think it would give a diagonal woven appearance.

I am attaching the .dll for the version still only using src and dst surfaces (only slightly adapted from the codelab version), to give an idea of what the plugin could potentially do (try it on an object). I am also attaching the corresponding VS code.
I think it could useful for watercolour/paper effects and  grass/fur textures as well as bearded ladies and bald patches! :)
 



Here is the code with my 'attempt' at using another surface called 'dest'. It builds without errors in VS2010 but when used in Pdn it crashes the program with null reference and threading errors?




Any help would be greatly appreciated. I will, of course, give credit for co-authorship if anyone can get this working. I will probably need to fine tune the controls a bit before publishing too.

Successful or not - many thanks.
 

  • Upvote 1

 

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

 

PdnForumSig2.jpg

Link to comment
Share on other sites

The fixed code is attached.

 

Strangely the single-threaded OnSetRenderInfo version performs 100x better than the multi-threaded version. :roll:

 

FurBlurdestSurface.zip

 

 

  • Upvote 2

PdnSig.png

Plugin Pack | PSFilterPdn | Content Aware Fill | G'MICPaint Shop Pro Filetype | RAW Filetype | WebP Filetype

The small increase in performance you get coding in C++ over C# is hardly enough to offset the headache of coding in the C++ language. ~BoltBait

 

Link to comment
Share on other sites

Hurray - it works!

Brilliant - many many thanks Null54 (to the rescue again!).

So far I have only compiled and a quick test - I can now work on fine tuning the effect and seeing where I went wrong. Really pleased the principle is possible as it could lead to many other effects. I'm thinking artistic sketch effects like the Jimi Hendrix 'Cry of love' album cover:
http://checkthisart.com/wp-content/uploads/2011/12/100_1695.jpg


I had all but given up on this one - so really appreciate this. Thank you.

 

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

 

PdnForumSig2.jpg

Link to comment
Share on other sites

Album cover reminds me of the PS plugin Fractalius. Good luck with this Red!

  • Upvote 1
Link to comment
Share on other sites

UtIk09i.png

Many thanks for the encouragement EER and Drew.
I had some problems getting the anti-aliasing right - well actually I think I was right but possibly exceeded the limits of one of the variables. Anyway fixed now and getting exciting results.
Am attaching the 'beta' .dll if you would like to preview/test (can be a little slow if reps set large on large objects/selections - but useful to have the choice for smaller areas).
Also attaching the code - if anything looks wrong please report back. I hope to publish properly soon.

 

Hidden Content:
 


Again thanks Null54 - this could be another addictive one.

I leave this image of my furry balls - don't have nightmares! :lol:

mc6AiNc.png

  • Upvote 3

 

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

 

PdnForumSig2.jpg

Link to comment
Share on other sites

Between your furry balls & Welshy's "Don't be Afraid of the Dark" image we will be having nightmares aplenty!!

 

Dare I say: I love your furry balls! I really do love the transition from metallic to furry. 

 

 

This is going to be so much fun...

THiGVp.png

Knowledge is no burden to carry.

 

April Jones, 2012

 
Link to comment
Share on other sites

Regarding the updated source code instead of casting the StartColor enum values you could change the type of the startColour variable.

StartColor startColour = StartColor.FromSrc;

this.startColour = (StartColor)newToken.GetProperty<StaticListChoiceProperty>(PropertyNames.StartC).Value;

 

  • Upvote 1

PdnSig.png

Plugin Pack | PSFilterPdn | Content Aware Fill | G'MICPaint Shop Pro Filetype | RAW Filetype | WebP Filetype

The small increase in performance you get coding in C++ over C# is hardly enough to offset the headache of coding in the C++ language. ~BoltBait

 

Link to comment
Share on other sites

^ Wow!  Great job 'noob. 

 

@Red:  This is AMAZING!  B)

Link to comment
Share on other sites

Hi Welshy,

 

Thanks for reporting that - It happened to me just now - I think I've fixed it (hopefully) - It uses a lot of random numbers between a maximum and minimum, and somewhere the minimum was larger than the max - computer says no!

 

Also working on varying the amount of curvature randomly and blending in the Primary Color in a more interesting way + some other ideas.

 

Nice pic!

 

Have got some good results just running it on a 20pix paintbrush line (on transparent layer) with 'Only keep fur' checked.

 

@ Null54 - thanks for that tip - I may be changing some of the controls - will bear this in mind.

 

@ EER - thanks!

 

@ Pdnnoob - monsters are great!

 

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

 

PdnForumSig2.jpg

Link to comment
Share on other sites

36RLiyX.png

I see you are all coming up with good uses for this! Thanks for the encouragement and enthusiasm.

Cool image Drew.

Love the ZZtop one Sasha - I think the drummer is called Frank Beard too!

TR - Grass effects are definitely one of the uses I had in mind for this one.

I'm still working on this one - the 'beta' above will crash occassionally (sorry) - so, if testing, always save everything before running it. Thanks Welshy and Doughty for testing.

Hopefully I will get a better (stable) version finished soon.

Cheers all

(just seen Doughty's American gothic - subtle but funny! - good work)

Sorry Mottoman - Only just seen yours too - good work - I think we should have a bearded lady comp once this plugin is finished!

A few of my tests:

http://i.imgur.com/CYZtKT3.png">http://i.imgur.com/CYZtKT3.png http://i.imgur.com/nMuAbk5.jpg">http://i.imgur.com/nMuAbk5.jpg

 

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

 

PdnForumSig2.jpg

Link to comment
Share on other sites

EchAv10.png

I am attaching the newest version of Furblur for testing. I've added quite a lot including the circular option for the curve, which gives much better results. However, I like the previous, slightly dotted (spiral) version as it can look like grass seeds, so am keeping that option.

Now doesn't mix the colour with the transparent white!

Added a slider to choose the transparency threshold of an 'object'. At around 250 will only put fur on 'objects', at 0 will work on whole selection (only seen if colour turned up).

Speeded up slightly too.

Changed radio buttons to checkboxes to save space.

I would be grateful if you can give it try and report any crashes. There shouldn't be any - but I thought that with the last one! - Many thanks

Also removing old versions of the .dll to avoid confusion.

The .dll

Some more examples:

RtaIJ3r.pngqMlYKJF.pngRAlFK3T.png

VS source code:

Hidden Content:
// Compiler options:  /unsafe /optimize /res:"C:\Users\john\Code experiments\PLUGIN pack stuff\pdn plugin graphics\plugin pack icons\FurBlurIcon.png","FurBlurEffect.FurBlurIcon.png"  /debug- /target:library /out:"C:\Program Files\Paint.NET\Effects\FurBlur2.dll"
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Reflection;
using System.Runtime.InteropServices;
using PaintDotNet;
using PaintDotNet.Effects;
using PaintDotNet.IndirectUI;
using PaintDotNet.PropertySystem;

[assembly: AssemblyTitle("FurBlurPlugin")]
[assembly: AssemblyDescription("FurBlur Plugin for Paint.NET")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Red ochre (John Robbins)")]
[assembly: AssemblyProduct("FurBlurPlugin")]
[assembly: AssemblyCopyright("Copyright © Red ochre (John Robbins)helped by Null54")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: AssemblyVersion("1.0.1")]

namespace FurBlurEffect
{
    public class PluginSupportInfo : IPluginSupportInfo
    {
        public string Author
        {
            get
            {
                return "Red ochre (John Robbins)helped by Null54";
            }
        }
        public string Copyright
        {
            get
            {
                return ((AssemblyCopyrightAttribute)base.GetType().Assembly.GetCustomAttributes(typeof(AssemblyCopyrightAttribute), false)[0]).Copyright;
            }
        }

        public string DisplayName
        {
            get
            {
                return ((AssemblyProductAttribute)base.GetType().Assembly.GetCustomAttributes(typeof(AssemblyProductAttribute), false)[0]).Product;
            }
        }

        public Version Version
        {
            get
            {
                return base.GetType().Assembly.GetName().Version;
            }
        }

        public Uri WebsiteUri
        {
            get
            {
                return new Uri("http://www.getpaint.net/redirect/plugins.html");
            }
        }
    }

    [PluginSupportInfo(typeof(PluginSupportInfo), DisplayName = "FurBlur")]
    public class FurBlurEffectPlugin : PropertyBasedEffect
    {// add another surface in "public class ....Plugin : PropertyBasedEffect"
        private Surface destSurface;

        protected override void OnDispose(bool disposing)//added
        {
            if (disposing)
            {
                if (destSurface != null)
                {
                    destSurface.Dispose();
                    destSurface = null;
                }
            }

            base.OnDispose(disposing);
        }
        public static string StaticName
        {
            get
            {
                return "Furblur";
            }
        }

        public static Image StaticIcon
        {
            get
            {
                return FurBlur.Properties.Resources.FurBlurIcon;
            }
        }

        public FurBlurEffectPlugin()
            : base(StaticName, StaticIcon, "Blurs", EffectFlags.Configurable)
        {
            instanceSeed = unchecked((int)DateTime.Now.Ticks);
        }

        public enum PropertyNames
        {
            StartC,
            Reps,
            MaxL,
            LenV,
            Mang,
            Bid,
            AngV,
            CurT,
            CurA,
            CurV,
            FriV,
            Sooo,
            BTrat,
            ColT,
            ColM,
            Qual,
            JustF,
            ReSeed

        }




        [ThreadStatic]
        private static Random RandomNumber;

        private int instanceSeed;



        protected override PropertyCollection OnCreatePropertyCollection()
        {
            List<Property> props = new List<Property>();
            props.Add(new BooleanProperty(PropertyNames.StartC, false));
            props.Add(new DoubleProperty(PropertyNames.Reps, 10, 0, 100));
            props.Add(new Int32Property(PropertyNames.MaxL, 30, 1, 300));
            props.Add(new DoubleProperty(PropertyNames.LenV, 0.10, 0, 1));
            props.Add(new DoubleProperty(PropertyNames.Mang, 90, -180, +180));
            props.Add(new BooleanProperty(PropertyNames.Bid, false));
            props.Add(new DoubleProperty(PropertyNames.AngV, 0.10, 0, 1));
            props.Add(new BooleanProperty(PropertyNames.CurT, true));
            props.Add(new DoubleProperty(PropertyNames.CurA, 0.10, 0, 1));
            props.Add(new DoubleProperty(PropertyNames.CurV, 0.10, 0, 1));
            props.Add(new DoubleProperty(PropertyNames.FriV, 0.10, 0, 1));
            props.Add(new Int32Property(PropertyNames.Sooo, 250, 0, 255));
            props.Add(new DoubleProperty(PropertyNames.BTrat, 0, 0, 1));
            props.Add(new BooleanProperty(PropertyNames.ColT, true));
            props.Add(new DoubleProperty(PropertyNames.ColM, 0, 0, 1));
            props.Add(new BooleanProperty(PropertyNames.Qual, true));
            props.Add(new BooleanProperty(PropertyNames.JustF, false));
            props.Add(new Int32Property(PropertyNames.ReSeed, 0, 0, 255));

            List<PropertyCollectionRule> propRules = new List<PropertyCollectionRule>();
            propRules.Add(new ReadOnlyBoundToBooleanRule("StartC", "JustF", false));

            return new PropertyCollection(props, propRules);
        }

        protected override ControlInfo OnCreateConfigUI(PropertyCollection props)
        {
            ControlInfo configUI = CreateDefaultConfigUI(props);

            configUI.SetPropertyControlValue(PropertyNames.StartC, ControlInfoPropertyNames.DisplayName, string.Empty);
            configUI.SetPropertyControlValue(PropertyNames.StartC, ControlInfoPropertyNames.Description, "0 = Src(original): tick = Dst(fur on fur)");
            configUI.SetPropertyControlValue(PropertyNames.Reps, ControlInfoPropertyNames.DisplayName, "Repetitions:      big reps & big length = slow!");
            configUI.SetPropertyControlValue(PropertyNames.MaxL, ControlInfoPropertyNames.DisplayName, "Main length");
            configUI.SetPropertyControlValue(PropertyNames.LenV, ControlInfoPropertyNames.DisplayName, "Length variations");
            configUI.SetPropertyControlValue(PropertyNames.LenV, ControlInfoPropertyNames.SliderLargeChange, 0.25);
            configUI.SetPropertyControlValue(PropertyNames.LenV, ControlInfoPropertyNames.SliderSmallChange, 0.05);
            configUI.SetPropertyControlValue(PropertyNames.LenV, ControlInfoPropertyNames.UpDownIncrement, 0.01);
            configUI.SetPropertyControlValue(PropertyNames.Mang, ControlInfoPropertyNames.DisplayName, "Main angle");
            configUI.SetPropertyControlType(PropertyNames.Mang, PropertyControlType.AngleChooser);
            configUI.SetPropertyControlValue(PropertyNames.Bid, ControlInfoPropertyNames.DisplayName, string.Empty);
            configUI.SetPropertyControlValue(PropertyNames.Bid, ControlInfoPropertyNames.Description, "Both directions");
            configUI.SetPropertyControlValue(PropertyNames.AngV, ControlInfoPropertyNames.DisplayName, "Angle variation");
            configUI.SetPropertyControlValue(PropertyNames.AngV, ControlInfoPropertyNames.SliderLargeChange, 0.25);
            configUI.SetPropertyControlValue(PropertyNames.AngV, ControlInfoPropertyNames.SliderSmallChange, 0.05);
            configUI.SetPropertyControlValue(PropertyNames.AngV, ControlInfoPropertyNames.UpDownIncrement, 0.01);
            configUI.SetPropertyControlValue(PropertyNames.CurT, ControlInfoPropertyNames.DisplayName, string.Empty);
            configUI.SetPropertyControlValue(PropertyNames.CurT, ControlInfoPropertyNames.Description, "0 = spiral(original - dotty): tick = circular(smooth!)");
            configUI.SetPropertyControlValue(PropertyNames.CurA, ControlInfoPropertyNames.DisplayName, "Curl curvature");
            configUI.SetPropertyControlValue(PropertyNames.CurA, ControlInfoPropertyNames.SliderLargeChange, 0.25);
            configUI.SetPropertyControlValue(PropertyNames.CurA, ControlInfoPropertyNames.SliderSmallChange, 0.05);
            configUI.SetPropertyControlValue(PropertyNames.CurA, ControlInfoPropertyNames.UpDownIncrement, 0.01);
            configUI.SetPropertyControlValue(PropertyNames.CurV, ControlInfoPropertyNames.DisplayName, "Curl variation");
            configUI.SetPropertyControlValue(PropertyNames.CurV, ControlInfoPropertyNames.SliderLargeChange, 0.25);
            configUI.SetPropertyControlValue(PropertyNames.CurV, ControlInfoPropertyNames.SliderSmallChange, 0.05);
            configUI.SetPropertyControlValue(PropertyNames.CurV, ControlInfoPropertyNames.UpDownIncrement, 0.01);
            configUI.SetPropertyControlValue(PropertyNames.FriV, ControlInfoPropertyNames.DisplayName, "Frizz curvature");
            configUI.SetPropertyControlValue(PropertyNames.FriV, ControlInfoPropertyNames.SliderLargeChange, 0.25);
            configUI.SetPropertyControlValue(PropertyNames.FriV, ControlInfoPropertyNames.SliderSmallChange, 0.05);
            configUI.SetPropertyControlValue(PropertyNames.FriV, ControlInfoPropertyNames.UpDownIncrement, 0.01);
            configUI.SetPropertyControlValue(PropertyNames.Sooo, ControlInfoPropertyNames.DisplayName, "Start object transparency");
            configUI.SetPropertyControlValue(PropertyNames.BTrat, ControlInfoPropertyNames.DisplayName, "Blur......................................................................Trail");
            configUI.SetPropertyControlValue(PropertyNames.BTrat, ControlInfoPropertyNames.SliderLargeChange, 0.25);
            configUI.SetPropertyControlValue(PropertyNames.BTrat, ControlInfoPropertyNames.SliderSmallChange, 0.05);
            configUI.SetPropertyControlValue(PropertyNames.BTrat, ControlInfoPropertyNames.UpDownIncrement, 0.01);
            configUI.SetPropertyControlValue(PropertyNames.ColT, ControlInfoPropertyNames.DisplayName, string.Empty);
            configUI.SetPropertyControlValue(PropertyNames.ColT, ControlInfoPropertyNames.Description, "0 = simple mix: tick = along fur");
            configUI.SetPropertyControlValue(PropertyNames.ColM, ControlInfoPropertyNames.DisplayName, "Src Color............................................... Primary Color");
            configUI.SetPropertyControlValue(PropertyNames.ColM, ControlInfoPropertyNames.SliderLargeChange, 0.25);
            configUI.SetPropertyControlValue(PropertyNames.ColM, ControlInfoPropertyNames.SliderSmallChange, 0.05);
            configUI.SetPropertyControlValue(PropertyNames.ColM, ControlInfoPropertyNames.UpDownIncrement, 0.01);
            configUI.SetPropertyControlValue(PropertyNames.Qual, ControlInfoPropertyNames.DisplayName, string.Empty);
            configUI.SetPropertyControlValue(PropertyNames.Qual, ControlInfoPropertyNames.Description, "0 = 1pix: tick = 4 pix anti-aliased");
            configUI.SetPropertyControlValue(PropertyNames.JustF, ControlInfoPropertyNames.DisplayName, string.Empty);
            configUI.SetPropertyControlValue(PropertyNames.JustF, ControlInfoPropertyNames.Description, "Only keep fur (src Start colour only)");
            configUI.SetPropertyControlValue(PropertyNames.ReSeed, ControlInfoPropertyNames.DisplayName, string.Empty);
            configUI.SetPropertyControlType(PropertyNames.ReSeed, PropertyControlType.IncrementButton);
            configUI.SetPropertyControlValue(PropertyNames.ReSeed, ControlInfoPropertyNames.ButtonText, "Reseed");

            return configUI;
        }
        protected override void OnSetRenderInfo(PropertyBasedEffectConfigToken newToken, RenderArgs dstArgs, RenderArgs srcArgs)
        {

            this.startColour = newToken.GetProperty<BooleanProperty>(PropertyNames.StartC).Value;
            this.repCount = newToken.GetProperty<DoubleProperty>(PropertyNames.Reps).Value;
            this.maxLength = newToken.GetProperty<Int32Property>(PropertyNames.MaxL).Value;
            this.lengthVariation = newToken.GetProperty<DoubleProperty>(PropertyNames.LenV).Value;
            this.mainAngle = newToken.GetProperty<DoubleProperty>(PropertyNames.Mang).Value;
            this.biDirectional = newToken.GetProperty<BooleanProperty>(PropertyNames.Bid).Value;
            this.angleVariation = newToken.GetProperty<DoubleProperty>(PropertyNames.AngV).Value;
            this.curtype = newToken.GetProperty<BooleanProperty>(PropertyNames.CurT).Value;
            this.curvature = newToken.GetProperty<DoubleProperty>(PropertyNames.CurA).Value;
            this.curvVari = newToken.GetProperty<DoubleProperty>(PropertyNames.CurV).Value;
            this.frizz = newToken.GetProperty<DoubleProperty>(PropertyNames.FriV).Value;
            this.startOnObject = newToken.GetProperty<Int32Property>(PropertyNames.Sooo).Value;
            this.blurAmount = newToken.GetProperty<DoubleProperty>(PropertyNames.BTrat).Value;
            this.coltype = newToken.GetProperty<BooleanProperty>(PropertyNames.ColT).Value;
            this.colmix = newToken.GetProperty<DoubleProperty>(PropertyNames.ColM).Value;
            this.quality = newToken.GetProperty<BooleanProperty>(PropertyNames.Qual).Value;
            this.justF = newToken.GetProperty<BooleanProperty>(PropertyNames.JustF).Value;
            this.randomSeed = (byte)newToken.GetProperty<Int32Property>(PropertyNames.ReSeed).Value;

            if (destSurface == null)
            {
                destSurface = new Surface(dstArgs.Surface.Width, dstArgs.Surface.Height);
            }

            Rectangle selection = this.EnvironmentParameters.GetSelection(srcArgs.Surface.Bounds).GetBoundsInt();

            this.Render(destSurface, srcArgs.Surface, selection); // clip the rendering to the selection.

            base.OnSetRenderInfo(newToken, dstArgs, srcArgs);
        }


        protected override void OnCustomizeConfigUIWindowProperties(PropertyCollection props)
        {
            // Change the effect's window title
            props[ControlInfoPropertyNames.WindowTitle].Value = "Fur Blur                           Aug 2013   Red Ochre/Null54";
            base.OnCustomizeConfigUIWindowProperties(props);
        }

        protected override unsafe void OnRender(Rectangle[] rois, int startIndex, int length)
        {
            if (length == 0) return;

            DstArgs.Surface.CopySurface(destSurface, rois, startIndex, length);
        }

        #region User Entered Code
        /* =================================================== */
        /* Furblur    */
        /* Name    */
        /* (c) 2013 Red Ochre     */
        /* comment   */
        /* Description:random trail/blur */
        /*     */
        /* ========================================== ======== */

        // Name: Furblur
        // Author: Red ochre (John Robbins)
        // Submenu: Blur
        // URL: http://www.getpaint.net/redirect/plugins.html
        // Title:Fur Blur                           Aug 2013 Red Ochre/Null54


        #region UICode
        bool startColour = false; // [1] Start colour|Src (original)| Dst ( fur on fur )
        double repCount = 10; // [0,100] Repetitions
        int maxLength = 20; // [1,200] Maximum length
        double lengthVariation = 0; // [0,1] Length variations
        double mainAngle = 45; // [-180,180] Main angle
        bool biDirectional = true; // [0,1] Both directions
        double angleVariation = 0; // [0,1] Angle variation
        bool curtype = true; // [0,1] Curve type
        double curvature = 0; // [0,1] Curl curvature
        double curvVari = 0; //[0,1] Curl variation
        double frizz = 0; // [0,1] Frizz curvature
        int startOnObject = 250; // [0,1] Start on object only
        double blurAmount = 0; // [0,1] Blur......................................................................Trail
        bool coltype = true; //[0,1] simple mix|along fur
        double colmix = 0; // [0,1] Src Color............................................... Primary Color
        bool quality = true; // [1] Quality|4 pixel Anti-alias (smoother)| 1 pixel (only slightly faster)
        bool justF = false; // [0,1] Only keep fur (src Start colour only)
        byte randomSeed = 0; // [255] Reseed
        #endregion
        void Render(Surface dest, Surface src, Rectangle rect)
        {
            dest.CopySurface(src, rect.Location, rect);// copy surface quicker than looping through
            if (justF) { ColorBgra klear = ColorBgra.Transparent; dest.Clear(klear); startColour = false; }//keep only blur/trail

            int H = rect.Bottom - rect.Top;
            int W = rect.Right - rect.Left;
            int N = (int)((repCount * W * H) / (100));
            int Lmain = maxLength;
            double Lvari = lengthVariation;
            double PI = Math.PI;
            double Amain = (mainAngle + 360) * 17.45329252;// add 360 so that angle can vary less than 0 (360) easier for random min & max
            // now in radians - note (PI * 1000)/180 = 17.453292519943295769236907684886
            bool Bidi = biDirectional;
            double Avar = angleVariation;
            bool Ctype = curtype;
            double Curve = curvature / 5;
            int CVari = (int)(curvVari * 1000);
            double Frizz = frizz / 50;
            int Athresh = startOnObject;
            double BlurV = 1 - blurAmount;
            double PriRat = colmix;
            double invPriRat = 1 - PriRat;
            bool Qual = quality;


            if (RandomNumber == null)
            {
                RandomNumber = new Random(instanceSeed ^ (randomSeed << 16) ^ (rect.X << 8) ^ rect.Y);
            }

            ColorBgra PrimC = base.EnvironmentParameters.PrimaryColor;


            ColorBgra LT, RT, LB, RB, stLT, stRT, stLB, stRB;
            int nB = 0; int nG = 0; int nR = 0; int nA = 255;// just to set a value
            int AngMax = (int)(Amain * (1 + Avar));
            int AngMin = (int)(Amain * (1 - Avar));// radians times 1000 for randoms
            double Angle = AngMax;//moved these out of loop
            int Lmax = Lmain + (int)(Lmain * Lvari);
            int Lmin = Lmain - (int)(Lmain * Lvari);
            int L = Lmax;//and these
            int CurMin = (int)(Curve * (1 - curvVari) * 1000);// times 1000 to use randoms
            int CurMax = (int)(Curve * (1 + curvVari) * 1000);

            for (int n = 0; n < N; n++)//number of 'stabs' at random locations
            {
                double Randx = RandomNumber.Next(rect.Left, rect.Right - 1); int Randxi = (int)(Randx);
                double Randy = RandomNumber.Next(rect.Top, rect.Bottom - 1); int Randyi = (int)(Randy);
                // note: start position to allow for 4 pixel square, so Randx < Right - 1 , Randy < Top -1

                if (Lmin < Lmax) { L = (int)RandomNumber.Next(Lmin, Lmax); }//Length of line

                //for RANDOMS - protection - Min MUST be less than Max or out of bounds exception

                if (AngMin < AngMax) { Angle = (double)(RandomNumber.Next(AngMin, AngMax)); }//Angle of line (rads * 1000 still)
                if (Avar == 0) { Angle = AngMax; }//bodge for odd unsolved bug when Avar = 0?????? - works!
                Angle = Angle / 1000;// back in radians

                int AngDir = RandomNumber.Next(0, 2);//Angle direction random 0 or 1
                if (Bidi && AngDir >= 1) { Angle += PI; }//randomly reverse angle 
                int CurDir = (int)RandomNumber.Next(0, 2);//Curve direction random 0 or 1
                if (CurMin < CurMax) { Curve = (double)(RandomNumber.Next(CurMin, CurMax) / 1000.0); }//divide by 1000 to get back to value range
                Curve = Curve - (Curve * CurDir * 2);//easier to read - randomly changes curve direction


                // need to know start alpha later
                stLT = src.GetPointUnchecked(Randxi, Randyi);
                stRT = src.GetPointUnchecked(Randxi + 1, Randyi);
                stLB = src.GetPointUnchecked(Randxi, Randyi + 1);
                stRB = src.GetPointUnchecked(Randxi + 1, Randyi + 1);
                int startA = (stLT.A + stRT.A + stLB.A + stRB.A) / 4;


                if (!startColour)
                {
                    nB = (int)((stLT.B + stRT.B + stLB.B + stRB. / 4);
                    nG = (int)((stLT.G + stRT.G + stLB.G + stRB.G) / 4);
                    nR = (int)((stLT.R + stRT.R + stLB.R + stRB.R) / 4);
                    nA = (int)((stLT.A + stRT.A + stLB.A + stRB.A) / 4);
                }

                else if (startColour)
                {
                    stLT = dest.GetPointUnchecked(Randxi, Randyi);
                    stRT = dest.GetPointUnchecked(Randxi + 1, Randyi);
                    stLB = dest.GetPointUnchecked(Randxi, Randyi + 1);
                    stRB = dest.GetPointUnchecked(Randxi + 1, Randyi + 1);
                    nB = (stLT.B + stRT.B + stLB.B + stRB. / 4;
                    nG = (stLT.G + stRT.G + stLB.G + stRB.G) / 4;
                    nR = (stLT.R + stRT.R + stLB.R + stRB.R) / 4;
                    nA = (stLT.A + stRT.A + stLB.A + stRB.A) / 4;
                }

                if (!coltype)// original Primary color blending see innner loop for along the fur
                {
                    nB = (int)((nB * invPriRat) + (PrimC.B * PriRat));//mix src or dest colour with Primary Color
                    nG = (int)((nG * invPriRat) + (PrimC.G * PriRat));
                    nR = (int)((nR * invPriRat) + (PrimC.R * PriRat));
                    nA = (int)((nA * invPriRat) + (PrimC.A * PriRat));//potentially transparent fur!
                }

                double oldx = Randx; double oldy = Randy;

                for (int l = 1; l < L; l++)// distance to loop out from that random location
                {
                    if (frizz != 0)// don't calculate if not needed - slow as within inner loop
                    {
                        double frangle = Angle;
                        int frizmin = (int)((Angle - (Angle * Frizz)) * 1000); int frizmax = (int)((Angle + (Angle * Frizz)) * 1000);
                        if (frizmin < frizmax) { frangle = (double)(RandomNumber.Next(frizmin, frizmax)) / 1000; }
                        int Lfra = (int)((1 - frizz) * L);
                        int frazz = RandomNumber.Next(0, Lfra);//added to increase frizz
                        if (frazz < l) { Angle = frangle; }
                    }

                    double Cang = Math.Cos(Angle); double Sang = -Math.Sin(Angle);

                    double Nx = Randx + (l * Cang); int Lxi = (int)(Nx); int Rxi = Lxi + 1;//this is angle from start
                    double Ny = Randy + (l * Sang); int Tyi = (int)(Ny); int Byi = Tyi + 1;
                    if (curtype)
                    {
                        Nx = oldx + (Cang); Lxi = (int)(Nx); Rxi = Lxi + 1;//this is angle from last point
                        Ny = oldy + (Sang); Tyi = (int)(Ny); Byi = Tyi + 1;
                    }// CIRCLES! - no gaps either

                    //start position is within bounds, however the loop may take it out of bounds!
                    // therefore protection required or use get sample clamped?

                    if (Lxi > rect.Left && Rxi < rect.Right && Tyi > rect.Top && Byi < rect.Bottom)
                    {

                        double blur = (double)(L - (l * BlurV)) / (double)(L);//BlurV is less than 1 so blur is too
                        double iblur = 1 - blur;
                        double colblur = (double)(L - l) / (double)(L); double icolblur = 1 - colblur;
                        if (coltype)//colour along the fur
                        {
                            nB = (int)((nB * colblur) + (((PrimC.B * PriRat) + (nB * invPriRat)) * icolblur));//add primary color along fur
                            nG = (int)((nG * colblur) + (((PrimC.G * PriRat) + (nG * invPriRat)) * icolblur));
                            nR = (int)((nR * colblur) + (((PrimC.R * PriRat) + (nR * invPriRat)) * icolblur));
                            nA = (int)((nA * colblur) + (((PrimC.A * PriRat) + (nA * invPriRat)) * icolblur));//potentially transparent fur!
                        }


                        //4 pixel AA
                        //if (Qual && (!Obtest || startA > Athresh))// assume objects have alpha greater than 250 or object-edge pixels trail transparency across object
                        if (Qual && startA >= Athresh)
                        {
                            LT = dest.GetPointUnchecked(Lxi, Tyi); int Blt = LT.B; int Glt = LT.G; int Rlt = LT.R; int Alt = LT.A;
                            if (LT.A <= Athresh) { Blt = nB; Glt = nG; Rlt = nR; }// to stop it blending colour with clear (white)
                            RT = dest.GetPointUnchecked(Rxi, Tyi); int Brt = RT.B; int Grt = RT.G; int Rrt = RT.R; int Art = RT.A;
                            if (RT.A <= Athresh) { Brt = nB; Grt = nG; Rrt = nR; }
                            LB = dest.GetPointUnchecked(Lxi, Byi); int Blb = LB.B; int Glb = LB.G; int Rlb = LB.R; int Alb = LB.A;
                            if (LB.A <= Athresh) { Blb = nB; Glb = nG; Rlb = nR; }
                            RB = dest.GetPointUnchecked(Rxi, Byi); int Brb = RB.B; int Grb = RB.G; int Rrb = RB.R; int Arb = RB.A;
                            if (RB.A <= Athresh) { Brb = nB; Grb = nG; Rrb = nR; }

                            double Nxd = Nx - Lxi; double iNxd = 1 - Nxd;
                            double Nyd = Ny - Tyi; double iNyd = 1 - Nyd;

                            // interesting - I think my previous calculations were correct but too complex?
                            // worked for 3 pixels then colours went strange with 4 pixels 
                            // hence the long winded version below

                            //left top 
                            double Blt1 = (nB * blur) + (Blt * iblur); double Blt2 = (Blt1 * iNxd) + (Blt * Nxd);
                            double Blt3 = (Blt2 * iNyd) + (Blt * Nyd); int nBlt = (int)(Blt3);
                            double Glt1 = (nG * blur) + (Glt * iblur); double Glt2 = (Glt1 * iNxd) + (Glt * Nxd);
                            double Glt3 = (Glt2 * iNyd) + (Glt * Nyd); int nGlt = (int)(Glt3);
                            double Rlt1 = (nR * blur) + (Rlt * iblur); double Rlt2 = (Rlt1 * iNxd) + (Rlt * Nxd);
                            double Rlt3 = (Rlt2 * iNyd) + (Rlt * Nyd); int nRlt = (int)(Rlt3);
                            double Alt1 = (nA * blur) + (Alt * iblur); double Alt2 = (Alt1 * iNxd) + (Alt * Nxd);
                            double Alt3 = (Alt2 * iNyd) + (Alt * Nyd); int nAlt = (int)(Alt3);
                            LT = ColorBgra.FromBgra(Int32Util.ClampToByte(nBlt), Int32Util.ClampToByte(nGlt), Int32Util.ClampToByte(nRlt), Int32Util.ClampToByte(nAlt));
                            dest[Lxi, Tyi] = LT;
                            //right top 
                            double Brt1 = (nB * blur) + (Brt * iblur); double Brt2 = (Brt1 * Nxd) + (Brt * iNxd);
                            double Brt3 = (Brt2 * iNyd) + (Brt * Nyd); int nBrt = (int)(Brt3);
                            double Grt1 = (nG * blur) + (Grt * iblur); double Grt2 = (Grt1 * Nxd) + (Grt * iNxd);
                            double Grt3 = (Grt2 * iNyd) + (Grt * Nyd); int nGrt = (int)(Grt3);
                            double Rrt1 = (nR * blur) + (Rrt * iblur); double Rrt2 = (Rrt1 * Nxd) + (Rrt * iNxd);
                            double Rrt3 = (Rrt2 * iNyd) + (Rrt * Nyd); int nRrt = (int)(Rrt3);
                            double Art1 = (nA * blur) + (Art * iblur); double Art2 = (Art1 * Nxd) + (Art * iNxd);
                            double Art3 = (Art2 * iNyd) + (Art * Nyd); int nArt = (int)(Art3);
                            RT = ColorBgra.FromBgra(Int32Util.ClampToByte(nBrt), Int32Util.ClampToByte(nGrt), Int32Util.ClampToByte(nRrt), Int32Util.ClampToByte(nArt));
                            dest[Rxi, Tyi] = RT;
                            //left bottom 
                            double Blb1 = (nB * blur) + (Blb * iblur); double Blb2 = (Blb1 * iNxd) + (Blb * Nxd);
                            double Blb3 = (Blb2 * Nyd) + (Blb * iNyd); int nBlb = (int)(Blb3);
                            double Glb1 = (nG * blur) + (Glb * iblur); double Glb2 = (Glb1 * iNxd) + (Glb * Nxd);
                            double Glb3 = (Glb2 * Nyd) + (Glb * iNyd); int nGlb = (int)(Glb3);
                            double Rlb1 = (nR * blur) + (Rlb * iblur); double Rlb2 = (Rlb1 * iNxd) + (Rlb * Nxd);
                            double Rlb3 = (Rlb2 * Nyd) + (Rlb * iNyd); int nRlb = (int)(Rlb3);
                            double Alb1 = (nA * blur) + (Alb * iblur); double Alb2 = (Alb1 * iNxd) + (Alb * Nxd);
                            double Alb3 = (Alb2 * Nyd) + (Alb * iNyd); int nAlb = (int)(Alb3);
                            LB = ColorBgra.FromBgra(Int32Util.ClampToByte(nBlb), Int32Util.ClampToByte(nGlb), Int32Util.ClampToByte(nRlb), Int32Util.ClampToByte(nAlb));
                            dest[Lxi, Byi] = LB;
                            //right bottom 
                            double Brb1 = (nB * blur) + (Brb * iblur); double Brb2 = (Brb1 * Nxd) + (Brb * iNxd);
                            double Brb3 = (Brb2 * Nyd) + (Brb * iNyd); int nBrb = (int)(Brb3);
                            double Grb1 = (nG * blur) + (Grb * iblur); double Grb2 = (Grb1 * Nxd) + (Grb * iNxd);
                            double Grb3 = (Grb2 * Nyd) + (Grb * iNyd); int nGrb = (int)(Grb3);
                            double Rrb1 = (nR * blur) + (Rrb * iblur); double Rrb2 = (Rrb1 * Nxd) + (Rrb * iNxd);
                            double Rrb3 = (Rrb2 * Nyd) + (Rrb * iNyd); int nRrb = (int)(Rrb3);
                            double Arb1 = (nA * blur) + (Arb * iblur); double Arb2 = (Arb1 * Nxd) + (Arb * iNxd);
                            double Arb3 = (Arb2 * Nyd) + (Arb * iNyd); int nArb = (int)(Arb3);
                            RB = ColorBgra.FromBgra(Int32Util.ClampToByte(nBrb), Int32Util.ClampToByte(nGrb), Int32Util.ClampToByte(nRrb), Int32Util.ClampToByte(nArb));
                            dest[Rxi, Byi] = RB;


                        }
                        //single pixel
                        //if (!Qual && (!Obtest || startA > Athresh))// assume objects have alpha greater than 250 or object-edge pixels trail transparency across object
                        if (!Qual && startA >= Athresh)
                        {
                            LT = dest.GetPointUnchecked(Lxi, Tyi); int Blt = LT.B; int Glt = LT.G; int Rlt = LT.R; int Alt = LT.A;
                            if (LT.A <= Athresh) { Blt = nB; Glt = nG; Rlt = nR; }// to stop it blending colour with clear (white)
                            int nBlt = (int)((nB * blur) + (Blt * iblur));
                            int nGlt = (int)((nG * blur) + (Glt * iblur));
                            int nRlt = (int)((nR * blur) + (Rlt * iblur));
                            int nAlt = (int)((nA * blur) + (Alt * iblur));
                            LT = ColorBgra.FromBgra(Int32Util.ClampToByte(nBlt), Int32Util.ClampToByte(nGlt), Int32Util.ClampToByte(nRlt), Int32Util.ClampToByte(nAlt));
                            dest[Lxi, Tyi] = LT;
                        }
                        oldx = Nx; oldy = Ny;// new point becomes old point for next l
                        Angle = Angle + Curve;
                    }
                }
            }
        }

        #endregion
    }
}
  • Upvote 1

 

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

 

PdnForumSig2.jpg

Link to comment
Share on other sites

Worked Great- This will definitely be one of the most significant Plugins for PDN.


The "Only Keep Fur" Checkbox is key in my book.


This stuff looks real.


 


FurMenagerie.png


 


Oh Yeah , one suggestion -- Presets!!!!


 


FurDemo.png


Edited by TechnoRobbo
  • Upvote 1

Go out there and be amazing. Have Fun, TR
TRsSig.png?raw=1
Some Pretty Pictures Some Cool Plugins

Link to comment
Share on other sites

No crashes yet then ? good! - thanks all for testing and positive feedback. I will publish it properly soon.

doughty - I really like that one. Interesting 'grunge' texture + the 'curve variation' slider way up = looks good! ;)

Drew - another good result! - that aeroplane needs a shave!   :lol:   - thanks for checking this one out.

TR - Thanks for the compliment - knowing your programming skills I am very flattered! :)

Regarding presets: I don't intend to add them - partly due to my laziness and also because I would rather users 'play' with all the controls to get an idea of what this can do. I generally like to give users as many options as practical but I know this can sometimes make the U.I. a bit intimidating. I will include some example settings and results in the publishing thread but hopefully users will experiment and come up with new uses.

That tiger has walked a long way! :D
 

  • Upvote 1

 

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

 

PdnForumSig2.jpg

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.

 Share

×
×
  • Create New...