BoltBait Posted December 1, 2014 Share Posted December 1, 2014 When building DLL, in source code, some strings are always "Untitled" such as AssemblyProduct(Untitled), namespace(UntitledEffect), class(UntitledEffectPlugin). As a result, paint.net gets an issue when loading more than one plugins created by CodeLab. To avoid this issue, ALWAYS save your source code (File > Save as) before building to DLL. The reason for this is that CodeLab uses the saved filename as the namespace string. EDIT: I think I'm going to put a warning in CodeLab if you build before saving the file. Look for this in the next update. Quote Download: BoltBait's Plugin Pack | CodeLab | and a Free Computer Dominos Game Link to comment Share on other sites More sharing options...
Ego Eram Reputo Posted December 1, 2014 Share Posted December 1, 2014 Not a warning - make it compulsory. If (BuildDll) and ChangedFlag == True then GoSaveYourWork 2 Quote ebook: Mastering Paint.NET | resources: Plugin Index | Stereogram Tut | proud supporter of Codelab plugins: EER's Plugin Pack | Planetoid | StickMan | WhichSymbol+ | Dr Scott's Markup Renderer | CSV Filetype | dwarf horde plugins: Plugin Browser | ShapeMaker Link to comment Share on other sites More sharing options...
TechnoRobbo Posted December 31, 2014 Share Posted December 31, 2014 Bug Report - Double Slider CodeLab 2.4 (PDN 4.0.5) if double slider had Min:0 Default:8 Max:15 the numericupdown cannot increase the value above 8.03 unless the slider is already set above 8.03 Repro: Create Double slider Min:0 Default:8 Max:15. Compile Plugin - run plugin press up arrow and the value will stop at 8.03 Quote Go out there and be amazing. Have Fun, TRSome Pretty Pictures Some Cool Plugins Link to comment Share on other sites More sharing options...
midora Posted December 31, 2014 Share Posted December 31, 2014 Bug Report - Double Slider CodeLab 2.4 (PDN 4.0.5) if double slider had Min:0 Default:8 Max:15 the numericupdown cannot increase the value above 8.03 unless the slider is already set above 8.03 Repro: Create Double slider Min:0 Default:8 Max:15. Compile Plugin - run plugin press up arrow and the value will stop at 8.03 I can hardly believe that this is a CodeLab bug. Should be tested against IndirectUI. Quote Link to comment Share on other sites More sharing options...
BoltBait Posted December 31, 2014 Share Posted December 31, 2014 This is a Paint.NET bug. I'll file it for Rick. EDIT: Issue filed under http://forums.getpaint.net/index.php?/topic/31387- Quote Download: BoltBait's Plugin Pack | CodeLab | and a Free Computer Dominos Game Link to comment Share on other sites More sharing options...
MJW Posted January 7, 2015 Share Posted January 7, 2015 (edited) I notice when building the DLL, there's a new Single Threaded build option. When I looked at the generated source code, I couldn't tell what was different between building with or without the option. What exactly (or even inexactly) does the option do? Edit: I looked back at the previous comments and found one I somehow missed which kind of explains the Single Threaded option; though it mostly just says it runs the plugin single-threaded. I'm still curious to know what it does differently. Normally, to produce a single-threaded plugin I'd put the code in (as I recall) OnSetRenderInfo instead of Render, but that doesn't seem to be what happens when the option is set. Is there a practical difference between using the OnSetRenderInfo approach (in Visual Studio, of course) and using the CodeLab option, and can and should the CodeLab approach (whatever it is) be used instead of OnSetRenderInfo for Visual Studio single-threaded plugins? Edited January 7, 2015 by MJW Quote Link to comment Share on other sites More sharing options...
BoltBait Posted January 7, 2015 Share Posted January 7, 2015 MJW, the key difference is in this code that CodeLab generates: public nothingEffectPlugin() : base(StaticName, StaticIcon, null, EffectFlags.Configurable | EffectFlags.SingleThreaded) { } As you can see the constructor is specified with the SingleThreaded effect flag. In this case, paint.net will not break up the selection into separate work units. But, instead will pass the entire selection to the render function in a single block and therefore only use one thread. The main benefit of this is that the render is computed in an orderly way (from top to bottom, from left to right).You can see a good example here: http://forums.getpaint.net/index.php?/topic/29428- CodeLab does not make any other changes than just specifying the effect flag. The single-threaded rendering is supported by paint.net itself. This option should not be used unless absolutely necessary as the built effect will run slower than an effect built the normal way. 1 Quote Download: BoltBait's Plugin Pack | CodeLab | and a Free Computer Dominos Game Link to comment Share on other sites More sharing options...
MJW Posted January 7, 2015 Share Posted January 7, 2015 Thank you very much, BoltBait. Quote Link to comment Share on other sites More sharing options...
MJW Posted January 15, 2015 Share Posted January 15, 2015 (edited) I had another question about the single-threaded switch. Perhaps I misunderstand it, or perhaps I'm using it wrong (or perhaps I just made a stupid mistake in my code). As an experiment (but also because I thought it might be useful), I wrote a plugin that uses the gradient of a cloud texture to displace the pixels in an image. It's supposed to work as follows: First I generate the (black and white) cloud texture into the dst buffer. I then use the red channel of dst to compute a simple linear gradient, yielding an (x, y) displacement vector, which I store as a scaled integer version in the blue and green channels of dst. Finally, I index into the src buffer with the (x, y) values offset by scaled versions of the displacement vectors. It has to be done in a single thread so that the red channel for the cloud texture isn't overwritten by the modified src data before it can be used to compute the gradient. When I compile the plugin with the single-thread flag set, I see problems at the fairly regularly spaced horizontal lines. I assume they are where the slices meet and where the cloud texture was overwritten by one thread before it could be used by another. Hidden Content: // Title: Cloud Displacement // Author: MJW // Name: Cloud Displacement // Submenu: Distort // Force Single Threaded // Keywords: Cloud|Displacement // Desc: Displace pixels based on cloud gradient. // URL: http://www.BoltBait.com/pdn #region UICode int Amount1 = 250; // [2,1000] Size Scale double Amount2 = 0.2; // [0,1] Roughness double Amount3 = 1; // [0,10] Height Scale bool Amount4 = false; // [0,1] Wrap byte Amount5 = 0; // [255] Reseed #endregion // Setup for calling the Render Clouds effect private CloudsEffect cloudsEffect = new CloudsEffect(); private PropertyCollection cloudsProps; // Here is the main render loop function Surface Dst; double gradPreScale = 2.5; float gradScale; bool wrap; void Render(Surface dst, Surface src, Rectangle rect) { Dst = dst; wrap = Amount4; gradScale = (float)(0.2 * Amount3); // Call the Render Clouds function cloudsProps = cloudsEffect.CreatePropertyCollection(); PropertyBasedEffectConfigToken CloudsParameters = new PropertyBasedEffectConfigToken(cloudsProps); CloudsParameters.SetPropertyValue(CloudsEffect.PropertyNames.Scale, Amount1); CloudsParameters.SetPropertyValue(CloudsEffect.PropertyNames.Power, Amount2); CloudsParameters.SetPropertyValue(CloudsEffect.PropertyNames.BlendMode, LayerBlendModeUtil.CreateCompositionOp(LayerBlendMode.Normal) ); CloudsParameters.SetPropertyValue(CloudsEffect.PropertyNames.Seed, (int)Amount5); cloudsEffect.SetRenderInfo(CloudsParameters, new RenderArgs(dst), new RenderArgs(src)); // Call the Clouds function using Black and White cloudsEffect.Render(new Rectangle[1] {rect}, 0, 1); int width = dst.Width, height = dst.Height; int top = rect.Top, right = rect.Right, bottom = rect.Bottom, left = rect.Left; int gradLeft = (left == 0) ? 1 : left; int gradRight = (right == width - 1) ? width - 2 : width - 1; // Now in the main render loop, the dst canvas has a render of clouds ColorBgra CurrentPixel = ColorBgra.Black; for (int y = top; y < bottom; y++) { if (IsCancelRequested) return; if ((y == 0) || (y == height - 1)) { for (int x = left; x < right; x++) { ClrDstGrad(x, y); } } else { if (left != gradLeft) { ClrDstGrad(0, y); } if (right != gradRight) { ClrDstGrad(right - 1, y); } for (int x = gradLeft; x < gradRight; x++) { int UM, UR, MR, LR, LM, LL, ML, UL; UM = dst[x, y - 1].R; UR = dst[x + 1, y - 1].R; MR = dst[x + 1, y].R; LR = dst[x + 1, y + 1].R; LM = dst[x, y + 1].R; LL = dst[x - 1, y + 1].R; ML = dst[x - 1, y].R; UL = dst[x - 1, y - 1].R; int dX = (UL - UR) + 2 * (ML - MR) + (LL - LR); int dY = (UL - LL) + 2 * (UM - LM) + (UR - LR); SetDstGrad(x, y, dX, dY); } } } for (int y = top; y < bottom; y++) { if (IsCancelRequested) return; for (int x = left; x < right; x++) { float dX = gradScale * (float)(dst[x, y].G - 127); float dY = gradScale * (float)(dst[x, y].B - 127); dst[x, y] = wrap ? src.GetBilinearSampleWrapped(x + dX, y + dY) : src.GetBilinearSample(x + dX, y + dY); } } } void SetDstGrad(int x, int y, int dX, int dY) { dX = 127 + (int)(gradPreScale * (double)dX + 0.5); if (dX < 0) dX = 0; else if (dX > 255) dX = 255; dY = 127 + (int)(gradPreScale * (double)dY + 0.5); if (dY < 0) dY = 0; else if (dY > 255) dY = 255; Dst[x, y] = ColorBgra.FromBgr((byte)dX, (byte)dY, Dst[x, y].R); } void ClrDstGrad(int x, int y) { Dst[x, y] = ColorBgra.FromBgr((byte)0, (byte)0, Dst[x, y].R); } (My handling of the gradient at the edges is totally inelegant -- Hey, it's just an experiment for now!) Edited January 15, 2015 by MJW Quote Link to comment Share on other sites More sharing options...
BoltBait Posted January 15, 2015 Share Posted January 15, 2015 You need to read this page in regards to working with the Clouds effect:http://boltbait.com/pdn/CodeLab/help/tutorial3.php And, remember, while in CodeLab itself, the effect is still multi-threaded. Single threading only works on effects that are compiled to a dll file. EDIT: I don't see any obvious errors. I tested clouds in a compiled dll with single-threading on and it worked fine. Perhaps the error is in your calculations. Quote Download: BoltBait's Plugin Pack | CodeLab | and a Free Computer Dominos Game Link to comment Share on other sites More sharing options...
MJW Posted January 15, 2015 Share Posted January 15, 2015 (edited) I think I realized what's happening. Paint.Net is still calling the render routine one slice at a time, it's just doing so in a single thread; therefore, the final image overwrites the cloud image before the next slice is processed. Since the gradient requires pixels from the line above the current pixel, the computation is wrong at the boundaries I thought when single-threaded was set, Paint.Net would call the render routine once with the rectangle set to the entire region. I wish it worked that way. EDIT: If it works the way I think it does, there's a fairly simple kludge to fix the problem for this particular plugin: I'll just compute the gradient from the current line and the next two lines. That will, in effect, shift the cloud texture a pixel up, which, of course, doesn't matter. It also means there will be a valid gradient for the top line, but none for the bottom two lines. Edited January 15, 2015 by MJW Quote Link to comment Share on other sites More sharing options...
Ego Eram Reputo Posted January 15, 2015 Share Posted January 15, 2015 Why not fire up Visual Studio and render your clouds to a scratch surface in one go? CodeLab even gives you the source to start the project. Quote ebook: Mastering Paint.NET | resources: Plugin Index | Stereogram Tut | proud supporter of Codelab plugins: EER's Plugin Pack | Planetoid | StickMan | WhichSymbol+ | Dr Scott's Markup Renderer | CSV Filetype | dwarf horde plugins: Plugin Browser | ShapeMaker Link to comment Share on other sites More sharing options...
MJW Posted January 15, 2015 Share Posted January 15, 2015 (edited) I'll probably do that. I was hoping that the single-thread switch would provide a quick way to write simple plugins that need to access the dst surface in random order, but it seems to be quite limited in what it can do. The biggest problem I have with developing Visual Studio plugins is the user interface. IndirectIU doesn't seem very easy to use outside of CodeLab, so I usually start by writing a stub CodeLab plugin, and save the compiled source. The problem comes after I've added a bunch of non-CodeLab code, then want to change the user interface controls. Of course, I could just use the Visual Studio controls, but then there's the look-and-feel problem -- especially the controls' reset-to-default button, which is a really nice feature. Maybe some day I'll get ambitious enough to write Visual Studio lookalike versions of the IndirectIU controls. Edited January 15, 2015 by MJW Quote Link to comment Share on other sites More sharing options...
Ego Eram Reputo Posted January 15, 2015 Share Posted January 15, 2015 The hard work has already been done for you. http://forums.getpaint.net/index.php?/topic/29798-more-indirectui-controls-optionbasedeffects/ http://forums.getpaint.net/index.php?/topic/28226-vs-template-with-custom-ui-controls/ http://forums.getpaint.net/index.php?/topic/26516-propertybasedeffect-template-using-indirectui/ Then there is the WinForm template buried in this thread http://forums.getpaint.net/index.php?/topic/25828-help-needed-using-visual-studio-instead-of-codelab-for-developing 2 Quote ebook: Mastering Paint.NET | resources: Plugin Index | Stereogram Tut | proud supporter of Codelab plugins: EER's Plugin Pack | Planetoid | StickMan | WhichSymbol+ | Dr Scott's Markup Renderer | CSV Filetype | dwarf horde plugins: Plugin Browser | ShapeMaker Link to comment Share on other sites More sharing options...
Red ochre Posted January 16, 2015 Share Posted January 16, 2015 Useful links, bookmarked, thanks! Quote Red ochre Plugin pack.............. Diabolical Drawings ................Real Paintings Link to comment Share on other sites More sharing options...
MJW Posted January 16, 2015 Share Posted January 16, 2015 (edited) Thank you, that looks very useful! I'm eager to give that a try. Edited January 16, 2015 by MJW Quote Link to comment Share on other sites More sharing options...
toe_head2001 Posted February 23, 2015 Share Posted February 23, 2015 I do believe I've found a minor bug. If there happens to be a .bat file already on the desktop, then CodeLab doesn't create one to move the generated .dll file. Quote (September 25th, 2023) Sorry about any broken images in my posts. I am aware of the issue. My Gallery | My Plugin Pack Layman's Guide to CodeLab Link to comment Share on other sites More sharing options...
BoltBait Posted February 23, 2015 Share Posted February 23, 2015 I do believe I've found a minor bug. If there happens to be a .bat file already on the desktop, then CodeLab doesn't create one to move the generated .dll file. You mean, if the install_xxx.bat file already exists, it won't write a new one? Or, are you saying that if ANY bat file exists on the desktop then the install_xxx.bat file won't be written? Quote Download: BoltBait's Plugin Pack | CodeLab | and a Free Computer Dominos Game Link to comment Share on other sites More sharing options...
toe_head2001 Posted February 23, 2015 Share Posted February 23, 2015 You mean, if the install_xxx.bat file already exists, it won't write a new one? Or, are you saying that if ANY bat file exists on the desktop then the install_xxx.bat file won't be written? The second... if ANY bat file exists on the desktop then the install_xxx.bat file won't be written. Quote (September 25th, 2023) Sorry about any broken images in my posts. I am aware of the issue. My Gallery | My Plugin Pack Layman's Guide to CodeLab Link to comment Share on other sites More sharing options...
toe_head2001 Posted February 25, 2015 Share Posted February 25, 2015 Today I was trying to use a built in effect in a script, but for some reason the code for the effect was getting ignored when I added the main loop code. After a while, I copy & pasted an example from Part 3 of the CodeLab tutorial that uses Gaussian Blur, and tried to see how that one worked. However, even in the example code, the Gaussian Blur was not being applied as it should. This is the specific code example that I got from the tutorial. Hidden Content: #region UICode int Amount1=10; //[1,20]Radius #endregion private UserBlendOp darkenOp = new UserBlendOps.DarkenBlendOp(); void Render(Surface dst, Surface src, Rectangle rect) { // Call the Gaussian Blur effect GaussianBlurEffect blurEffect = new GaussianBlurEffect(); PropertyCollection bProps = blurEffect.CreatePropertyCollection(); PropertyBasedEffectConfigToken bParameters = new PropertyBasedEffectConfigToken(bProps); bParameters.SetPropertyValue(GaussianBlurEffect.PropertyNames.Radius, Amount1); blurEffect.SetRenderInfo(bParameters, new RenderArgs(dst), new RenderArgs(src)); blurEffect.Render(new Rectangle[1] {rect},0,1); // Loop through all pixels and calculate final pixel values ColorBgra CurrentPixel; for (int y = rect.Top; y < rect.Bottom; y++) { for (int x = rect.Left; x < rect.Right; x++) { // Get the current pixel from source canvas CurrentPixel = src[x,y]; // Combine source pixel with blured dest pixel // using the darken blend operation. CurrentPixel = darkenOp.Apply(CurrentPixel, dst[x,y]); // Save the results for final display. dst[x,y] = CurrentPixel; } } } Is it borked, or I just a noob? Quote (September 25th, 2023) Sorry about any broken images in my posts. I am aware of the issue. My Gallery | My Plugin Pack Layman's Guide to CodeLab Link to comment Share on other sites More sharing options...
BoltBait Posted February 25, 2015 Share Posted February 25, 2015 Is it borked, or I just a noob? For something simple like this, just use the File > New templates to write the code for you. Quote Download: BoltBait's Plugin Pack | CodeLab | and a Free Computer Dominos Game Link to comment Share on other sites More sharing options...
BoltBait Posted February 25, 2015 Share Posted February 25, 2015 The second... if ANY bat file exists on the desktop then the install_xxx.bat file won't be written. I have tried and tried, but I just can't get this thing to fail. Quote Download: BoltBait's Plugin Pack | CodeLab | and a Free Computer Dominos Game Link to comment Share on other sites More sharing options...
toe_head2001 Posted February 25, 2015 Share Posted February 25, 2015 I have tried and tried, but I just can't get this thing to fail. My apologies, I had assumed that was what was causing it. I checked for sure this time. The only time it doesn't create the .bat file is when you are still using the "Untitled" instance of CodeLab. (without opening a .cs file or going to File>New) For something simple like this, just use the File > New templates to write the code for you. No worries, I had the effect call code right all along. It was the loop code that was overriding the surface. I had to switch to Visual Studio. Now rendering the Pixelation effect to a scratch surface, and then apply the loop to the scratch surface. Your source code to 'Inner Shadow' proved to be a great example of how to use a scratch surface. Thank You. Quote (September 25th, 2023) Sorry about any broken images in my posts. I am aware of the issue. My Gallery | My Plugin Pack Layman's Guide to CodeLab Link to comment Share on other sites More sharing options...
BoltBait Posted February 25, 2015 Share Posted February 25, 2015 My apologies, I had assumed that was what was causing it. I checked for sure this time. The only time it doesn't create the .bat file is when you are still using the "Untitled" instance of CodeLab. (without opening a .cs file or going to File>New) As mentioned before in this thread, this has already been fixed for the next release. Quote Download: BoltBait's Plugin Pack | CodeLab | and a Free Computer Dominos Game Link to comment Share on other sites More sharing options...
MJW Posted March 12, 2015 Share Posted March 12, 2015 (edited) I added a feature to CodeLab which I think is quite useful. I've always hated inserting new controls in the middle of some previously-defined controls, and having to renumber the Amount variables; so I added a "Renumber UI Variables" option to the Edit list. A new control can be created with any unused number and inserted, out of order, into the middle of the other UI variables. Running the renumber option renumbers the UI variables consecutively, and changes all the UI variable uses in the code to match. (Though I explained it in terms of adding a new variable, renumbering also allows UI variables to be rearranged in any order, and then renumbered.) I changed only two files: CodeLabConfigDialog.cs to add the option into the Edit menu along with the mouse-click event handler, and CodeTextBox.cs to add the renumbering code. I also added a little renumber icon PNG file. I have no intention of starting a separate ColeLab line (heaven forbid!). I was hoping that perhaps if the feature is popular, BoltBait might possibly add it (or some variation of it) to a future revision of CodeLab. The renumbering code is: Hidden Content: public bool CanRenumberUIVariables { get { // Might want enable only if there are UI variables. return !string.IsNullOrEmpty(this.Text); } } // Renumber the Amount vaiables so they are in order from 1 to n. // The variables can originally be numbered in almost any manner. // I try to catch most error conditions. I don't catch the condition where there's a gap in the UI // numbers, and that variable is created in the user (non-UICode) part of the code. private int[] varNum = null; // Must be accessable to MatchEvaluator. private int numVars = 0; public bool RenumberUIVars() { string text = this.Text; varNum = new int[100]; numVars = GetCurrentUINumbering(text, varNum); if (numVars == -1) { MessageBox.Show("Could not process the UICode region.", "Renumber Error"); return false; } // There are obviously more efficent appoaches that don't require searching through // the array. But this method is straight forward and given the number of variables, // should work just fine. // Check for duplicate entries and determine if the variables are already in order. bool needsRenumbering = false; for (int i = 0; i < numVars; i++) { int myNum = varNum[i]; if (myNum != i + 1) needsRenumbering = true; // Check for duplicates. for (int j = i + 1; j < numVars; j++) { if (myNum == varNum[j]) { MessageBox.Show("Amount" + myNum.ToString() + " occurs more than once.", "Renumber Error"); return false; } } } if (!needsRenumbering) { MessageBox.Show("No renumbering required.", "Renumber"); return true; } // Change the Amount variable names so renumbered and non-renumbered variables aren't confused. // The substituted string is random, but shouldn't occur in any source code. text = Regex.Replace(text, @"\bAmount(\d+)\b", "Amt%!%$1"); // Change the old names to the new names. this.Text = Regex.Replace(text, @"Amt%!%\d+", ReplaceWithRenumbered); MessageBox.Show("Renumbering complete.", "Renumber"); return true; } private string ReplaceWithRenumbered(Match m) { int n; if (int.TryParse(m.Value.Substring(6), out n)) { // If in range, substitute the renumbered value, else used original value. // Try to find the new number in the renumber array. int i; for (i = 0; (varNum[i] != n) && (i < numVars); i++) ; return "Amount" + ((i == numVars) ? n : i + 1).ToString(); } else { // This shouldn't happen, but just in case. return "Amount" + m.Value.Substring(6); } } private int GetCurrentUINumbering(string text, int[] results) { int varCnt = 0; int max = results.Length - 1; string findUIRegion = @"\#region UICode$(?s:(?<uicode>.*?))\n\#endregion"; Match m = Regex.Match(text, findUIRegion, RegexOptions.Multiline); if (!m.Success) return -1; string textUI = m.Groups["uicode"].Value; string pattern = @"\s*Amount(?<number>\d+)[ =;\t]"; foreach (Match mv in Regex.Matches(textUI, pattern)) { int n; if (int.TryParse(mv.Groups["number"].Value, out n)) { // (This should always find an integer.) results[varCnt] = n; if (varCnt++ == max) break; // Just ignore any unprocessed variables (this shouldn't happen!) } } return varCnt; } If anyone wants to try it, the DLL is here: <snip> The VS (2013) project is here: Edited March 14, 2015 by 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.