Jump to content

CodeLab - First Steps (Lines/Grid)


ReMake

Recommended Posts

Each user who starts mastering CodeLab, asks a question - where to begin?
First of all, it's necessary to begin with studying the CodeLab Help by BoltBait.
If you have studied CodeLab Help and you have no ideas for creating effects, begin with updating of the old plugins developed by other authors.

Looking through the forum Plugins - Publishing ONLY!, I found a topic Simple Lines Plugin. This is a good example for a small tutorial.

The picture shows the user interface of the Lines effect by spongey437.

 

linesUI.png

This effect draws a line width of 1 pixel and has two controls: Width - an interval between lines and X - Y - the direction of lines (horizontal and vertical respectively).

So, let's get started.

Open the Simple Lines Plugin topic, select and copy (Ctl+C) the text of the script.
Open CodeLab: Effects -> Advanced -> CodeLab.
Select the CodeLab script text (Ctrl+A) and paste the previously copied script (Ctl+V).
Save the script with the Lines name for further working with it: File -> Save...

First of all, open the designer interface (File -> User Interface Designer) and just click OK. Your new script will look like this:

#region UICode
int Amount1 = 10; // [1,100] Width
int Amount2 = 2; // [1,2] X - Y
#endregion
// int Amount1=10; //[1,100]Width
// int Amount2=2; //[1,2]X - Y

void Render(Surface dst, Surface src, Rectangle rect)
{
    PdnRegion selectionRegion = EnvironmentParameters.GetSelection(src.Bounds);

    // Delete any of these lines you don't need
    Rectangle selection = this.EnvironmentParameters.GetSelection(src.Bounds).GetBoundsInt();

    long CenterX = (long)(((selection.Right - selection.Left) / 2)+selection.Left);
    long CenterY = (long)(((selection.Bottom - selection.Top) / 2)+selection.Top);
    ColorBgra PrimaryColor = (ColorBgra)EnvironmentParameters.PrimaryColor;
    ColorBgra SecondaryColor = (ColorBgra)EnvironmentParameters.SecondaryColor;
    int BrushWidth = (int)EnvironmentParameters.BrushWidth;

    ColorBgra CurrentPixel;
    for(int y = rect.Top; y < rect.Bottom; y++)
    {
        for (int x = rect.Left; x < rect.Right; x++)
        {
            if (selectionRegion.IsVisible(x, y))
            {
                CurrentPixel = src[x,y];
                // TODO: Add pixel processing code here
                if(Amount2 == 1)
                {
                    if (x % Amount1 == 0)
                    {
                        // Access RGBA values this way, for example:
                        CurrentPixel.R = (byte)PrimaryColor.R;
                        CurrentPixel.G = (byte)PrimaryColor.G;
                        CurrentPixel.B = (byte)PrimaryColor.B;
                        CurrentPixel.A = (byte)PrimaryColor.A;
                    }
                }

                if(Amount2 == 2)
                {
                    if (y % Amount1 == 0)
                    {
                        // Access RGBA values this way, for example:
                        CurrentPixel.R = (byte)PrimaryColor.R;
                        CurrentPixel.G = (byte)PrimaryColor.G;
                        CurrentPixel.B = (byte)PrimaryColor.B;
                        CurrentPixel.A = (byte)PrimaryColor.A;
                    }
                }

                dst[x,y] = CurrentPixel;
            }
        }
    }
}

Delete this two commented lines:

// int Amount1=10; //[1,100]Width
// int Amount2=2; //[1,2]X - Y

they aren't necessary any more.

The next lines (except ColorBgra PrimaryColor) will also not be necessary for us:

// Delete any of these lines you don't need
Rectangle selection = this.EnvironmentParameters.GetSelection(src.Bounds).GetBoundsInt();

long CenterX = (long)(((selection.Right - selection.Left) / 2)+selection.Left);
long CenterY = (long)(((selection.Bottom - selection.Top) / 2)+selection.Top);
ColorBgra SecondaryColor = (ColorBgra)EnvironmentParameters.SecondaryColor;
int BrushWidth = (int)EnvironmentParameters.BrushWidth;

so remove them, leaving a string

ColorBgra PrimaryColor = (ColorBgra)EnvironmentParameters.PrimaryColor;

and again save your script with the name Lines_1.

If you have carefully studied CodeLab Help, you probably noticed that in your new script there is no need to divide CurrentPixel into components (R, G, B and A). Therefore, the following lines

CurrentPixel.R = (byte)PrimaryColor.R;
CurrentPixel.G = (byte)PrimaryColor.G;
CurrentPixel.B = (byte)PrimaryColor.B;
CurrentPixel.A = (byte)PrimaryColor.A;

replace with

CurrentPixel = PrimaryColor;

If this effect draws a horizontal or vertical line separately, can it draw both lines at the same time? Yes, it can. To do this, you must perform the condition:

if ((x % Amount1 == 0) || (y % Amount1 == 0))

Add before dst[x,y] = CurrentPixel; the following lines:

if(Amount2 == 3)
{
    if ((x % Amount1 == 0) || (y % Amount1 == 0))
    {
        // Access RGBA values this way, for example:
        CurrentPixel = PrimaryColor;
    }
}

Now open the User Interface Designer and select the line X-Y (1..2..2).

In the Maximum box set the value to 3 and in the Control name box type X - Y - Grid. Click Update button, then click Ok. Your script will look like this:

#region UICode
int Amount1 = 10; // [1,100] Width
int Amount2 = 2; // [1,3] X - Y - Grid
#endregion

void Render(Surface dst, Surface src, Rectangle rect)
{
    PdnRegion selectionRegion = EnvironmentParameters.GetSelection(src.Bounds);

    ColorBgra PrimaryColor = (ColorBgra)EnvironmentParameters.PrimaryColor;

    ColorBgra CurrentPixel;
    for(int y = rect.Top; y < rect.Bottom; y++)
    {
        for (int x = rect.Left; x < rect.Right; x++)
        {
            if (selectionRegion.IsVisible(x, y))
            {
                CurrentPixel = src[x,y];
                // TODO: Add pixel processing code here
                if(Amount2 == 1)
                {
                    if (x % Amount1 == 0)
                    {
                        // Access RGBA values this way, for example:
                        CurrentPixel = PrimaryColor;
                    }
                }

                if(Amount2 == 2)
                {
                    if (y % Amount1 == 0)
                    {
                        // Access RGBA values this way, for example:
                        CurrentPixel = PrimaryColor;
                    }
                }

                if(Amount2 == 3)
                {
                    if ((x % Amount1 == 0) || (y % Amount1 == 0))
                    {
                        // Access RGBA values this way, for example:
                        CurrentPixel = PrimaryColor;
                    }
                }

                dst[x,y] = CurrentPixel;
            }
        }
    }
}

Save your script with Lines_Grid name now. Open File -> Save as DLL... and save your first update of the effect.
Close CodeLab and Paint.NET. Run the Install_Lines_Grid file on your desktop, which will place the Lines_Grid.dll file into the Effects folder (or drag the Lines_Grid.dll file to the Effects folder manually).
Start Paint.NET and you'll see your effect in the Effects menu, run it and check how it works. Probably, you don't want to switch a view of lines using the slider. You may have also noticed that the effect works is somewhat slow. Then let's go to the next step of the update.

Start CodeLab and open your Lines_Grid script. First of all delete the following line:

{
    if (selectionRegion.IsVisible(x, y))

and one of the closing braces ( } ) at the bottom of the script.

 

This line

PdnRegion selectionRegion = EnvironmentParameters.GetSelection(src.Bounds);

now we will not need and delete it too.

Open the User Interface Designer and select the line X-Y - Grid (1..2..3). In a drop-down list select the Radio Button List control. Enter View in the Control name box, and in the Parameters box enter the kinds of lines, separated by the pipe symbol (|): Vertical Lines|Horizontal Lines|Grid. Click Update button, and then click Ok. Now your script looks like this:

#region UICode
int Amount1 = 10; // [1,100] Width
byte Amount2 = 0; // [1] View|Vertical Lines|Horizontal Lines|Grid
#endregion

void Render(Surface dst, Surface src, Rectangle rect)
{

    ColorBgra PrimaryColor = (ColorBgra)EnvironmentParameters.PrimaryColor;

    ColorBgra CurrentPixel;
    for(int y = rect.Top; y < rect.Bottom; y++)
    {
        for (int x = rect.Left; x < rect.Right; x++)
        {
            CurrentPixel = src[x,y];
            // TODO: Add pixel processing code here
            if(Amount2 == 0)
            {
                if (x % Amount1 == 0)
                {
                    // Access RGBA values this way, for example:
                    CurrentPixel = PrimaryColor;
                }
            }

            if(Amount2 == 1)
            {
                if (y % Amount1 == 0)
                {
                    // Access RGBA values this way, for example:
                    CurrentPixel = PrimaryColor;
                }
            }

            if(Amount2 == 2)
            {
                if ((x % Amount1 == 0) || (y % Amount1 == 0))
                {
                    // Access RGBA values this way, for example:
                    CurrentPixel = PrimaryColor;
                }
            }

            dst[x,y] = CurrentPixel;
        }
    }
}

Pay attention for the line

byte Amount2 = 0; // [1] View|Vertical Lines|Horizontal Lines|Grid

Here, the initial value of Amount2 is 0, which corresponds to the Vertical Lines. Replace in this line 0 to 1 and you get a Horizontal lines.

Under the terms of programming our code is not very correct, so looking into CodeLab UI Elements, replace the lines

if(Amount2 == 0)
{
    if (x % Amount1 == 0)
    {
        // Access RGBA values this way, for example:
        CurrentPixel = PrimaryColor;
    }
}

if(Amount2 == 1)
{
    if (y % Amount1 == 0)
    {
        // Access RGBA values this way, for example:
        CurrentPixel = PrimaryColor;
    }
}

if(Amount2 == 2)
{
    if ((x % Amount1 == 0) || (y % Amount1 == 0))
    {
        // Access RGBA values this way, for example:
        CurrentPixel = PrimaryColor;
    }
}

with next lines

switch(Amount2)
{
    case 0: // Vertical Lines
        if (x % Amount1 == 0) {CurrentPixel = PrimaryColor;}
        break;
    case 1: // Horizontal Lines
        if (y % Amount1 == 0) {CurrentPixel = PrimaryColor;}
        break;
    case 2: // Horizontal Lines
        if ((x % Amount1 == 0) || (y % Amount1 == 0)) {CurrentPixel = PrimaryColor;}
        break;
}

Now our script would look like this:

#region UICode
int Amount1 = 10; // [1,100] Width
byte Amount2 = 0; // [1] View|Vertical Lines|Horizontal Lines|Grid
#endregion

void Render(Surface dst, Surface src, Rectangle rect)
{

    ColorBgra PrimaryColor = (ColorBgra)EnvironmentParameters.PrimaryColor;

    ColorBgra CurrentPixel;
    for(int y = rect.Top; y < rect.Bottom; y++)
    {
        for (int x = rect.Left; x < rect.Right; x++)
        {
            CurrentPixel = src[x,y];
            // TODO: Add pixel processing code here
            switch(Amount2)
            {
                case 0: // Vertical Lines
                    if (x % Amount1 == 0) {CurrentPixel = PrimaryColor;}
                    break;
                case 1: // Horizontal Lines
                    if (y % Amount1 == 0) {CurrentPixel = PrimaryColor;}
                    break;
                case 2: // Grid
                    if ((x % Amount1 == 0) || (y % Amount1 == 0)) {CurrentPixel = PrimaryColor;}
                    break;
            }

            dst[x,y] = CurrentPixel;
        }
    }
}

Save your script with Lines_Grid_1 name and create a DLL with the same name. Check how works your effect.

Lines color of our effect depends of the Primary Color, which was selected in the Colors window. If you want to draw a line or grid in other color, you will need to pre-set the color in the Colors window, and then run your effect. Is it possible to choose the color of the lines from effect directly, without addressing to the Colors window? Of course, it's possible. To do this, we will continue to update our effect.

Open with CodeLab your Lines_Grid_1 script. Open the User Interface Designer and in the drop-down list select the Color Wheel control. Write the Color in the Control name box, click the Add button and move up the control to one position with button MoveUp.png. Click Ok.

Now the code block of user interface (UI) will look like this:

#region UICode
int Amount1 = 10; // [1,100] Width
ColorBgra Amount2 = ColorBgra.FromBgr(0,0,0); // Color
byte Amount3 = 0; // [1] View|Vertical Lines|Horizontal Lines|Grid
#endregion

Note: View control is named now Amount3, therefore replace Amount2 to Amount3 in the line switch.
Now you have a possibility to select color immediately in the interface of effect and we don't depend on Primary color in the Colors window! It means that CurrentPixel = PrimaryColor; we can replace to CurrentPixel = Amount2; and we can delete the ColorBgra PrimaryColor = (ColorBgra)EnvironmentParameters.PrimaryColor; line.

Save your script with Lines_Grid_2 name and create a DLL with the same name. Check how works your effect. Probably, now you want to change width of lines and an interval between the lines. Let us continue.

Open with CodeLab your Lines_Grid_2 script. Open the User Interface Designer, select the Width (1..10..100) line, rename it to Line Width and click the Update button. Then from the drop-down list select the Integer Slider control and name it Interval Width. Write 1 in the Minimum box, in the Default box write 10. Click the Add button and move up the control to one position with button MoveUp.png. Click Ok.

Now the code block of user interface (UI) will look like this:

#region UICode
int Amount1 = 10; // [1,100] Line Width
ColorBgra Amount2 = ColorBgra.FromBgr(0,0,0); // Color
int Amount3 = 10; // [1,100] Interval Width
byte Amount4 = 0; // [1] View|Vertical Lines|Horizontal Lines|Grid
#endregion

View control is named now Amount4, therefore replace Amount3 to Amount4 in the line switch.

Now we enter variable Lines as a sum of Amount1 and Amount2 and place it before ColorBgra CurrentPixel; line

int Lines = Amount1 + Amount3;

and change the conditions

if (x % Amount1 == 0)
if (y % Amount1 == 0)

to

if (x % Lines < Amount1)
if (y % Lines < Amount1)

Our script has now the following view:

#region UICode
int Amount1 = 10; // [1,100] Line Width
ColorBgra Amount2 = ColorBgra.FromBgr(0,0,0); // Color
int Amount3 = 10; // [1,100] Interval Width
byte Amount4 = 0; // [1] View|Vertical Lines|Horizontal Lines|Grid
#endregion

void Render(Surface dst, Surface src, Rectangle rect)
{

    int Lines = Amount1 + Amount3;
    ColorBgra CurrentPixel;
    for(int y = rect.Top; y < rect.Bottom; y++)
    {
        for (int x = rect.Left; x < rect.Right; x++)
        {
            CurrentPixel = src[x,y];
            // TODO: Add pixel processing code here
            switch(Amount4)
            {
                case 0: // Vertical Lines
                    if (x % Lines < Amount1) {CurrentPixel = Amount2;}
                    break;
                case 1: // Horizontal Lines
                    if (y % Lines < Amount1) {CurrentPixel = Amount2;}
                    break;
                case 2: // Grid
                    if ((x % Lines < Amount1) || (y % Lines < Amount1)) {CurrentPixel = Amount2;}
                    break;
            }

            dst[x,y] = CurrentPixel;
        }
    }
}

Let's return to our last script. What if we add one more control item.
Open the User Interface Designer and in the drop-down list select the Check Box control. Write the Inverse in the Control name box, write 0 in the Default box and click the Add button. Click Ok.

Now the code block of user interface (UI) looks like this:

#region UICode
int Amount1 = 1; // [1,100] Line Width
ColorBgra Amount2 = ColorBgra.FromBgr(0,0,0); // Color
int Amount3 = 10; // [1,100] Interval Width
byte Amount4 = 0; // [1] View|Vertical Lines|Horizontal Lines|Grid
bool Amount5 = false; // [0,1] Inverse
#endregion

Let's set conditions for a checkbox. If the checkbox is unchecked, lines color accepts the color value, selected from a Color control. If the checkbox is checked, intervals color accepts the color value, selected from a Color control.

Final our code looks like this:

#region UICode
int Amount1 = 1; // [1,100] Line Width
ColorBgra Amount2 = ColorBgra.FromBgr(0,0,0); // Color
int Amount3 = 10; // [1,100] Interval Width
byte Amount4 = 0; // [1] View|Vertical Lines|Horizontal Lines|Grid
bool Amount5 = false; // [0,1] Inverse
#endregion

void Render(Surface dst, Surface src, Rectangle rect)
{
    int Lines = Amount1 + Amount3;
    ColorBgra CurrentPixel;
    for (int y = rect.Top; y < rect.Bottom; y++)
    {
        for (int x = rect.Left; x < rect.Right; x++)
        {
            CurrentPixel = src[x,y];
            // TODO: Add pixel processing code here

            if(!Amount5)
            {
                switch (Amount4)
                {
                    case 0: // Vertical Lines
                        if (x % Lines < Amount1) {CurrentPixel = Amount2;}
                        break;
                    case 1: // Horizontal Lines
                        if (y % Lines < Amount1) {CurrentPixel = Amount2;}
                        break;
                    case 2: // Grid from lines
                        if ((x % Lines < Amount1) || (y % Lines < Amount1)) {CurrentPixel = Amount2;}
                        break;
                }
            }
            else
            {
                switch(Amount4)
                {
                    case 0: // Vertical Intervals
                        if (x % Lines + 1 > Amount1) {CurrentPixel = Amount2;}
                        break;
                    case 1: // Horizontal Intervals
                        if (y % Lines + 1 > Amount1) {CurrentPixel = Amount2;}
                        break;
                    case 2: // Grid from intervals
                        if ((x % Lines + 1 > Amount1) && (y % Lines + 1 > Amount1)) {CurrentPixel = Amount2;}
                        break;
                }
            }
            dst[x,y] = CurrentPixel;
        }
    }
}

Save your script with name Lines_Grid_4 and create DLL with the same name.
Here would be possible to finish, but... Let's address to BoltBait's Using CodeLab to Build a DLL. We can find some usefull information in the Default section and we can create similar for our script:

// Submenu: Render - let's place our effect under a Render submenu of the Effects menu
// Name: Lines/Grid - name of effect in the menu (or submenu)
// Title: Lines/Grid - a title of the effect's interface
// Author: ReMake - name of the effect's author
// Desc: Drawing of direct lines or a grid - the effect description
// Keywords: effect|drawing|lines|grid - a keywords from which your effect can be found in the Internet
// URL: http://www.getpaint.net/redirect/plugins.html - your address in a network (or in the forum)

Let's place this information before the code block of the interface:

// Submenu: Render
// Name: Lines/Grid
// Title: Lines/Grid
// Author: ReMake
// Desc: Drawing of direct lines or a grid
// Keywords: effect|lines|grid
// URL: http://www.getpaint.net/redirect/plugins.html
#region UICode
int Amount1 = 1; // [1,100] Line Width
ColorBgra Amount2 = ColorBgra.FromBgr(0,0,0); // Color
int Amount3 = 10; // [1,100] Interval Width
byte Amount4 = 0; // [1] View|Vertical Lines|Horizontal Lines|Grid
bool Amount5 = false; // [0,1] Inverse
#endregion

Save this script with the name LinesGrid.

And last, it is necessary to create an icon for the interface of our effect from the PNG file, which have the size of 16x16 pixels. By means of our effect I have created such icon: Lines.png

Now let's save our effect as a DLL file: File-> Save as DLL... Almost all information is in the dialog box, which presented to you. Click the Select icon link and select the icon. Click the Build button - your new effect is ready!

Compare the interface of your effect with a picture shown above.

Line_UI_en.png

 

Our code, from the point of view of programming, maybe is not so elegant, but it only the tutorial. I also did not put the aim to explain algorithm of operation of this script - to understand it the task of the user.

I hope the first step in CodeLab was not so difficult.

 

 

Results of this effect works you can see in a Lines/Grid effect topic.

 

 

Thanks BoltBait for his CodeLab and CodeLab Help.

Thanks HELEN - my first reader - for her assessment of 'my' English.

 

Вариант этой темы на русском языке смотрите здесь.

 

Edited by toe_head2001
Formatting
  • Upvote 5
Link to comment
Share on other sites

Excellent tutorial.  How about showing how the effect affects the canvas (i.e. what it renders)?

 

Can I also suggest a PDF version be made available?

Link to comment
Share on other sites

Excellent tutorial.  How about showing how the effect affects the canvas (i.e. what it renders)?

I will try to attach pictures tomorrow. I barely coped with formatting codes (or helped someone from admins or moderators).

 

Can I also suggest a PDF version be made available?

I will try to do it with your help.

Link to comment
Share on other sites

Well done Remake! - 'your' English is very good, infinitely better than my Belarusian! ;)  - probably better than 'my' English too. :D

 

Nobody knows English better than an Englishman. Thank You Red ochre. I am very pleased to hear Your estimation.

Link to comment
Share on other sites

This is very interesting stuff @ReMake, thank you  :) .  I will study it at leasure and hope to understand at least some of it!  This subject has always intrigued, as well as mystified me.

 

P.S. My father spoke Russian (he was actually Polish) but, alas, the only words I remember learning from him were На здоровье & dziękuję.

30b8T8B.gif

How I made Jennifer & Halle in Paint.net

My Gallery | My Deviant Art

"Rescuing one animal may not change the world, but for that animal their world is changed forever!" anon.

 
Link to comment
Share on other sites

This is very interesting stuff @ReMake, thank you  :) .  I will study it at leasure and hope to understand at least some of it!  This subject has always intrigued, as well as mystified me.

 

P.S. My father spoke Russian (he was actually Polish) but, alas, the only words I remember learning from him were На здоровье & dziękuję.

 

Dziękuję bardzo, as would said Your father. I speak Polish, some a little.

 

Thank You Pixey for your assessment.

Link to comment
Share on other sites

See? Very understandable. :) You did a nice job.

 

Thank You HELEN. You brought me confidence when You have read my 'opus'.

 

 

I have updated the first post of this topic, because was detected error in the final program code and the result of the effect's work with checked Inverse control was not that was expected.

 

The effect works correctly now.

Edited by ReMake
Link to comment
Share on other sites

 

infinitely better than my Belarusian! ;)

 

@Red: You speak a different language?

Infinitely better meaning I do not speak any other languages, sadly, apart from jibberish sometimes :lol: . I greatly respect those who speak many - including C#!

 

Sorry for going off topic Remake.

  • Upvote 1

 

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

 

PdnForumSig2.jpg

Link to comment
Share on other sites

I renamed this topic because I have decided to continue the theme 'Codelab - First Steps'.

Edited by ReMake
Link to comment
Share on other sites

For the benefit of absolute beginners (people that haven't worked with paint.net resources or C#), perhaps it would be a good idea to identify which parts of the code are specific to paint.net and which are generic C#. Visual Studio (and Mono Develop) do a good job of telling you what comes from where, but people using CodeLab don't get that. From my own experience, I would say I was somewhat lost in some places until I switch to Visual Studio... but maybe that's just me.

(September 25th, 2023)  Sorry about any broken images in my posts. I am aware of the issue.

bp-sig.png
My Gallery  |  My Plugin Pack

Layman's Guide to CodeLab

Link to comment
Share on other sites

For the benefit of absolute beginners (people that haven't worked with paint.net resources or C#), perhaps it would be a good idea to identify which parts of the code are specific to paint.net and which are generic C#. ...

 

 

Each user who starts mastering CodeLab, asks a question - where to begin?

First of all, it's necessary to begin with studying the CodeLab Help by BoltBait.

 

"First, you must learn C# at least to a basic level. Now, if you have expirience with C, C++, or even Pascal, you'll probably do fine. If not, you must first learn C#" - said BoltBait in his CodeLab Tutorial Part 1 - Simple.

 

For absolute newbies will be difficult to understand of all without basic knowledge of C#. Before proceeding to VS, maybe they should experiment in CodeLab, even on the examples of other authors.

Link to comment
Share on other sites

On 3/15/2015 at 12:35 AM, toe_head2001 said:

Fair enough... I guess I took the unconventional route of learning both at the same time. :P

 

drinks.gif

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