Jump to content

Tim!

Members
  • Posts

    37
  • Joined

  • Last visited

Everything posted by Tim!

  1. Thanks. I commented-out the 4 errors and compiled it, and then tried it out with Paint.NET v4.2.13. There don't seem to be any obvious (at least to me) issues so far.
  2. Great to see that the file types have been updated. I've just been trying to compile the code with VS2017 targetting .NET 4.8. I have a couple of issues with SvgFileType.cs. Firstly, the obsolete constructor. Have I fixed it correctly? public class SvgFileType : FileType { // // Obsolete. // //public SvgFileType() // : base( // "Scalable Vector Graphics", // name // FileTypeFlags.SupportsLoading, // flags // new[] {".svg", ".svgz"}) // extensions //{ //} // // New and improved. // public SvgFileType() : base ( "Scalable Vector Graphics", // name new FileTypeOptions // options { LoadExtensions = new string[] { ".svg", ".svgx" } } ) { //this.Options.LoadExtensions = new List<string> { ".svg", ".svgx" }; //this.Options.LoadExtensions = new string[] { ".svg", ".svgx" }; //FileTypeOptions fto = new FileTypeOptions //{ // LoadExtensions = new List<string> { ".svg", ".svgx" } //}; } Secondly, I get 4 compile errors with SvgVisualElement.Visible being read only, e.g.: Would it be OK to comment these out. or is there a new equivalent?
  3. Hi verdy_p, You can reset the flag in OnSetRenderInfo()
  4. >the dotNet compiler already optimizes integer divisions or multiplications by constant powers of 2 using binary shifts. @verdy_p Thanks for enlightening me. I didn't know that. (The principle is still sound though.) What we need is higher resolutions VDUs, say 600dpi, then we wouldn't need antialiasing at all.
  5. @verdy_p: When multiplying or dividing by 2^n you can use shift left or shift right. The following code snippet: for (y2 *= 2, x2 = (n = e = x2) * 2; n > 0; --n) { becomes: for (y2 <<= 1, x2 = (n = e = x2) << 1; n > 0; --n) { It shaves off more than a few CPU cycles and doesn't use the FPU.
  6. I've tried the following plug-in experiment. It gives inconsistent results, but Loop 2 is usually a bit faster than Loop 1 (the JIT compiler has done its job well). The Windows Forms experiment gave a consistent and marked speed difference. So why the difference? Hidden Content: using System.Diagnostics; using System.Drawing; using System.Windows.Forms; using PaintDotNet; using PaintDotNet.Effects; namespace EffectsPluginTemplate1 { public class EffectPlugin : PaintDotNet.Effects.Effect { public static string StaticName { get { return "Effect Plugin"; } } public static Bitmap StaticIcon { get { return new Bitmap(typeof(EffectPlugin), "EffectPluginIcon.png"); } } public static string StaticSubMenuName { get { //return null; // Use for no submenu #if DEBUG return "_test"; // Use for custom submenu #else return SubmenuNames.Render; #endif } } public EffectPlugin() : base(EffectPlugin.StaticName, EffectPlugin.StaticIcon, EffectPlugin.StaticSubMenuName, EffectFlags.Configurable | EffectFlags.SingleThreaded) { show_msgbox = false; } ~EffectPlugin() { if (show_msgbox) { string str = ""; str += "Loop 1: " + loop1_ticks + "\r\n"; str += "Loop 2: " + loop2_ticks + "\r\n"; str += "Loop 1 / Loop 2: " + loop1_ticks / loop2_ticks + "\r\n"; str += "Ticks per second: " + Stopwatch.Frequency; MessageBox.Show(str); } } public override EffectConfigDialog CreateConfigDialog() { return new EffectPluginConfigDialog(); } protected override void OnSetRenderInfo(EffectConfigToken parameters, RenderArgs dstArgs, RenderArgs srcArgs) { loop1_ticks = 0; loop2_ticks = 0; show_msgbox = true; base.OnSetRenderInfo(parameters, dstArgs, srcArgs); } private Stopwatch sw = new Stopwatch(); private float loop1_ticks; private float loop2_ticks; private bool show_msgbox; public override void Render(EffectConfigToken parameters, RenderArgs dstArgs, RenderArgs srcArgs, Rectangle[] rois, int startIndex, int length) { PdnRegion selectionRegion = EnvironmentParameters.GetSelection(srcArgs.Bounds); sw.Reset(); sw.Start(); // // Loop 1 // for (int i = startIndex; i < startIndex + length; ++i) { Rectangle rect = rois[i]; for (int y = rect.Top; y < rect.Bottom; ++y) { for (int x = rect.Left; x < rect.Right; ++x) { // Render Code Here dstArgs.Surface[x, y] = srcArgs.Surface[rect.Right - x - 1, y]; } } } sw.Stop(); loop1_ticks += sw.ElapsedTicks; sw.Reset(); sw.Start(); // // Loop 2 // int r = startIndex + length; for (int i = startIndex; i < r; i++) { Rectangle rect = rois[i]; int left = rect.Left; int right = rect.Right; int top = rect.Top; int bottom = rect.Bottom; for (int y = top; y < bottom; y++) { for (int x = left; x < right; x++) { dstArgs.Surface[x, y] = srcArgs.Surface[right - x - 1, y]; } } } sw.Stop(); loop2_ticks += sw.ElapsedTicks; } } }
  7. I'm running it by double-clicking on the exe in Windows Explorer.
  8. And when I switch off overflow/underflow checks, Loop 2 runs about six times faster than Loop 1.
  9. I checked optimise code in project properties (Release). Loop 2 runs 3.64 times faster than Loop 1. Here's my ILDASM where Loop 1 uses call instance and Loop 2 uses ldloc.s: Hidden Content: .method private hidebysig instance void buttonLoops_Click(object sender, class [mscorlib]System.EventArgs e) cil managed { .maxstack 5 .locals init ( [0] class [system]System.Diagnostics.Stopwatch sw, [1] valuetype [system.Drawing]System.Drawing.Rectangle rect, [2] string str, [3] int32 y, [4] int32 x, [5] int32 left, [6] int32 right, [7] int32 top, [8] int32 bottom, [9] int32 V_9, [10] int32 V_10, [11] object CS$0$0000, [12] object[] CS$0$0001, [13] object CS$0$0002, [14] object[] CS$0$0003) L_0000: call class [system.Windows.Forms]System.Windows.Forms.Cursor [system.Windows.Forms]System.Windows.Forms.Cursors::get_WaitCursor() L_0005: call void [system.Windows.Forms]System.Windows.Forms.Cursor::set_Current(class [system.Windows.Forms]System.Windows.Forms.Cursor) L_000a: newobj instance void [system]System.Diagnostics.Stopwatch::.ctor() L_000f: stloc.0 L_0010: ldloca.s rect L_0012: ldc.i4.0 L_0013: ldc.i4.0 L_0014: ldc.i4 0x2710 L_0019: ldc.i4 0x2710 L_001e: call instance void [system.Drawing]System.Drawing.Rectangle::.ctor(int32, int32, int32, int32) L_0023: ldstr "" L_0028: stloc.2 L_0029: ldloc.0 L_002a: callvirt instance void [system]System.Diagnostics.Stopwatch::Start() L_002f: ldloca.s rect L_0031: call instance int32 [system.Drawing]System.Drawing.Rectangle::get_Top() L_0036: stloc.3 L_0037: br.s L_0059 L_0039: ldloca.s rect L_003b: call instance int32 [system.Drawing]System.Drawing.Rectangle::get_Left() L_0040: stloc.s x L_0042: br.s L_004a L_0044: ldloc.s x L_0046: ldc.i4.1 L_0047: add.ovf L_0048: stloc.s x L_004a: ldloc.s x L_004c: ldloca.s rect L_004e: call instance int32 [system.Drawing]System.Drawing.Rectangle::get_Right() L_0053: blt.s L_0044 L_0055: ldloc.3 L_0056: ldc.i4.1 L_0057: add.ovf L_0058: stloc.3 L_0059: ldloc.3 L_005a: ldloca.s rect L_005c: call instance int32 [system.Drawing]System.Drawing.Rectangle::get_Bottom() L_0061: blt.s L_0039 L_0063: ldloc.0 L_0064: callvirt instance void [system]System.Diagnostics.Stopwatch::Stop() L_0069: ldloc.2 L_006a: stloc.s CS$0$0000 L_006c: ldc.i4.4 L_006d: newarr object L_0072: stloc.s CS$0$0001 L_0074: ldloc.s CS$0$0001 L_0076: ldc.i4.0 L_0077: ldloc.s CS$0$0000 L_0079: stelem.ref L_007a: ldloc.s CS$0$0001 L_007c: ldc.i4.1 L_007d: ldstr "Loop 1: " L_0082: stelem.ref L_0083: ldloc.s CS$0$0001 L_0085: ldc.i4.2 L_0086: ldloc.0 L_0087: callvirt instance int64 [system]System.Diagnostics.Stopwatch::get_ElapsedTicks() L_008c: box int64 L_0091: stelem.ref L_0092: ldloc.s CS$0$0001 L_0094: ldc.i4.3 L_0095: ldstr "\r\n" L_009a: stelem.ref L_009b: ldloc.s CS$0$0001 L_009d: call string [mscorlib]System.String::Concat(object[]) L_00a2: stloc.2 L_00a3: ldloc.0 L_00a4: callvirt instance void [system]System.Diagnostics.Stopwatch::Reset() L_00a9: ldloc.0 L_00aa: callvirt instance void [system]System.Diagnostics.Stopwatch::Start() L_00af: ldloca.s rect L_00b1: call instance int32 [system.Drawing]System.Drawing.Rectangle::get_Left() L_00b6: stloc.s left L_00b8: ldloca.s rect L_00ba: call instance int32 [system.Drawing]System.Drawing.Rectangle::get_Right() L_00bf: stloc.s right L_00c1: ldloca.s rect L_00c3: call instance int32 [system.Drawing]System.Drawing.Rectangle::get_Top() L_00c8: stloc.s top L_00ca: ldloca.s rect L_00cc: call instance int32 [system.Drawing]System.Drawing.Rectangle::get_Bottom() L_00d1: stloc.s bottom L_00d3: ldloc.s top L_00d5: stloc.s V_9 L_00d7: br.s L_00f1 L_00d9: ldloc.s left L_00db: stloc.s V_10 L_00dd: br.s L_00e5 L_00df: ldloc.s V_10 L_00e1: ldc.i4.1 L_00e2: add.ovf L_00e3: stloc.s V_10 L_00e5: ldloc.s V_10 L_00e7: ldloc.s right L_00e9: blt.s L_00df L_00eb: ldloc.s V_9 L_00ed: ldc.i4.1 L_00ee: add.ovf L_00ef: stloc.s V_9 L_00f1: ldloc.s V_9 L_00f3: ldloc.s bottom L_00f5: blt.s L_00d9 L_00f7: ldloc.0 L_00f8: callvirt instance void [system]System.Diagnostics.Stopwatch::Stop() L_00fd: ldloc.2 L_00fe: stloc.s CS$0$0002 L_0100: ldc.i4.4 L_0101: newarr object L_0106: stloc.s CS$0$0003 L_0108: ldloc.s CS$0$0003 L_010a: ldc.i4.0 L_010b: ldloc.s CS$0$0002 L_010d: stelem.ref L_010e: ldloc.s CS$0$0003 L_0110: ldc.i4.1 L_0111: ldstr "Loop 2: " L_0116: stelem.ref L_0117: ldloc.s CS$0$0003 L_0119: ldc.i4.2 L_011a: ldloc.0 L_011b: callvirt instance int64 [system]System.Diagnostics.Stopwatch::get_ElapsedTicks() L_0120: box int64 L_0125: stelem.ref L_0126: ldloc.s CS$0$0003 L_0128: ldc.i4.3 L_0129: ldstr "\r\n" L_012e: stelem.ref L_012f: ldloc.s CS$0$0003 L_0131: call string [mscorlib]System.String::Concat(object[]) L_0136: stloc.2 L_0137: ldloc.2 L_0138: ldstr "Ticks per second: " L_013d: ldsfld int64 [system]System.Diagnostics.Stopwatch::Frequency L_0142: box int64 L_0147: call string [mscorlib]System.String::Concat(object, object, object) L_014c: stloc.2 L_014d: ldloc.2 L_014e: call valuetype [system.Windows.Forms]System.Windows.Forms.DialogResult [system.Windows.Forms]System.Windows.Forms.MessageBox::Show(string) L_0153: pop L_0154: call class [system.Windows.Forms]System.Windows.Forms.Cursor [system.Windows.Forms]System.Windows.Forms.Cursors::get_Default() L_0159: call void [system.Windows.Forms]System.Windows.Forms.Cursor::set_Current(class [system.Windows.Forms]System.Windows.Forms.Cursor) L_015e: ret }
  10. A common rendering inefficiency amongst many code samples is caused by the repetitive accessing of properties of the Rectangle class in for-loops in the Render method. Consider the following code sample. The second style is faster because it uses local variables to access the rectangle data. The first style makes repeated subroutine calls to access the rectangle data: Hidden Content: using System.Diagnostics; using System.Drawing; using System.Windows.Forms; namespace WindowsFormsApplication1 { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void buttonLoops_Click(object sender, System.EventArgs e) { Cursor.Current = Cursors.WaitCursor; Stopwatch sw = new Stopwatch(); Rectangle rect = new Rectangle(0, 0, 10000, 10000); string str = ""; sw.Start(); for (int y = rect.Top; y < rect.Bottom; y++) { for (int x = rect.Left; x < rect.Right; x++) { int result = 0; } } sw.Stop(); str += "Loop 1: " + sw.ElapsedTicks + "\r\n"; sw.Reset(); sw.Start(); int right = rect.Right; int left = rect.Left; int top = rect.Top; int bottom = rect.Bottom; for (int y = top; y < bottom; y++) { for (int x = left; x < right; x++) { int result = 0; } } sw.Stop(); str += "Loop 2: " + sw.ElapsedTicks + "\r\n"; str += "Ticks per second: " + Stopwatch.Frequency; MessageBox.Show(str); Cursor.Current = Cursors.Default; } } } Another common problem is unecessary recalculation of for-loop limits every time the loop is executed. Limits should be calculated before the for-loops. In Example 2 below, for an image of 800x600px, it saves 480598 computations (600 + 800 x 600 - 2) in comparison to Example 1: Hidden Content: // // Example 1 // int a = ComputeA(); int b = ComputeB(); int left = rect.Left; int right = rect.Right; int top = rect.Top; int bottom = rect.Bottom; for (int y = top; y < bottom - a; y++) { for (int x = left; x < right - b; x++) { int result = 0; } } // // Example 2 // int a = ComputeA(); int b = ComputeB(); int left = rect.Left; int right = rect.Right - b; int top = rect.Top; int bottom = rect.Bottom - a; for (int y = top; y < bottom; y++) { for (int x = left; x < right; x++) { int result = 0; } }
  11. I've just had another look at that problem. I should have put a lock statement in OnSetRenderInfo(). Thanks for highlighting it.
  12. Yes. Tile height and width of the tessarae can be changed independently using sliders ranging from 2px to 100px. I'll update my original post with a better description. No, but I could add this capability to a future release. Currently the tesserae are drawn on opaque background (it's the Secondary colour with Alpha set to fully opaque 255).
  13. Thanks for your suggestions. I've now published it here (and here) Rounded Corners: Hmmm. That involves calculating eight tangents and four x-y offsets and drawing an arc about each of the four x-y offsets between pairs of tangents. Easy enough to say, but tricky to implement. I'll have a think... EDIT 1: Updated links for new forum.
  14. Hi All, Here's my Rounded Rectangle effect. (A full list of my effects is here.) Rounded Rectangle - Version 1.5.0.0 - 27 February 2017 ©Copyright Tim Mathias 2017. All rights reserved. USE AT YOUR OWN RISK. Menu: Effects -> Render -> Rounded Rectangle... LavEnt.Effects.RoundedRectangle.1.5.0.0.zip Example 1 Example 2 The Rounded Rectanlge effect uses the Primary and Secondary colours and the current brush width to draw a rectangle with rounded corners into the current selection. The roundness of the corners, the border outline and fill type are user-selectable. You can have multiple selections (Ctrl key). If there's no selection, it uses the entire canvas. The selection can be any shape (rectangle, lasso, ellipse or magic wand). After drawing the first shape, you can change the colours and brush width for subsequent shapes without having to re-open the config dialog. Just change them in Paint.NET's toolbars and then press Ctrl+F to paint into the selection with the new colours and brush width. Note: If you choose corner radii whose sum is greater than the side length, the radii will be scaled to fit the side length. The scaling is indicated by a green bar. Version 1.5.0.0 - 27 February 2017: Recompiled for .NET 4.6.1. Version 1.3.0.0 - 14 May 2009: Added a lock statement to prevent multiple simultaneous renders. Removed cross-threaded calls. Removed UI bug where independent radii were overwritten when typing a new top-left x radius. Version 1.2.0.0 - 30 Mar 2009 (789 downloads): Added a supplementary brush width slider to the config dialog. Note: It reverts to the brush width set in the Paint.NET toolbar every time the dialog opens and when re-applying the effect using Ctrl+F. Added a fill overlap slider. It controls by how much the fill colour overlaps the outline colour. It's useful for removing gaps that sometimes appear due to antialiasing. The overlap ranges from zero to half the brush width. To see it in action use semi-transparent colours for the outline and fill, then move the Fill Overlap slider. Added a Reset Radii button. Added a Show Original checkbox. Improved slider performance. Improved radii UI logic. Version 1.1.0.0 - 16 Mar 2009 (266 downloads): Added support for the number keypad. Improved outline-fill algorithm so that semi-transparent colours don't overlap. Removed UI glitch when moving radii sliders. Version 1.0.0.0 (168 downloads): Original.
  15. Hi All, Here's my Mosaic effect. (A full list of my effects is here.) Mosaic - Version 1.3.0.0 - 27 February 2017 ©Copyright Tim Mathias 2017. All rights reserved. USE AT YOUR OWN RISK. Menu: Effects -> Artistic -> Mosaic... LavEnt.Effects.Mosaic.1.3.0.0.zip Before After The Mosaic effect converts a drawing into a mosaic pattern and uses the Secondary colour as the adhesive or grout between the tesserae. Tessera Width: 2px to 100px Tessera Height: 2px to 100px Tessera Colour: Centre spot sample or average. Tessera Shape Irregularity: 0% (square) to 50% of tessera side length. Adhesive Thickness: 0px to 50px. Antialias: On or off. Possible enhancements I might add in future: Mathematical formulae to generate the mosaic pattern; at the moment it just uses a random irregularity based on a square shape. Fully transparent Secondary colour so that the underlying image shows through the gaps between tessarae. Tip: Try using a dark semi-transparent Secondary colour for the adhesive. Version 1.3.0.0 - 27 February 2017: Recompiled for .NET 4.6.1. Version 1.1.0.0 - 14 May 2009: Added a lock statement to prevent multiple simultaneous renders. Version 1.0.0.0 - 30 March 2009 (813 downloads): Original.
  16. I value your comments but I don't know mean by that one. Mosaics are made of (usually) square tiles. One of the intrinsic properties of a mosaic is that it comprises versatile tesselating tesserae. ;-) Before After EDIT 1: Updated links for new forum.
  17. I've re-done the UI logic. All those multiple inter-dependencies is quite tricky. I've also added a few other things (see my original post).
  18. There are issues with using System.Windows.Forms.Timer with TrackBar. I use System.Threading.Timer instead. Add this example code to your ConfigDialog and replace all your calls to FinishTokenUpdate() with calls to FinishTokenUpdateDelayed(). Hidden Content: #region FinishTokenUpdateDelayed private System.Threading.Timer timer1 = null; private System.Threading.TimerCallback timer1_callback = null; private const int timer1_due_time = 100; // ms private void CreateTimer1() { timer1_callback = new System.Threading.TimerCallback(timer1_Callback); timer1 = new System.Threading.Timer(timer1_callback, null, timer1_due_time, System.Threading.Timeout.Infinite); } /// /// Remember to call DisposeTimer1() when dialog closes, e.g. in Form1_FormClosing() /// private void DisposeTimer1() { if (timer1 != null) { timer1.Dispose(); timer1 = null; } } private void ChangeTimer1() { if (timer1 == null) { CreateTimer1(); } else { timer1.Change(timer1_due_time, System.Threading.Timeout.Infinite); } } /// /// Call FinishTokenUpdateDelayed() instead of FinishTokenUpdate() /// private void FinishTokenUpdateDelayed() { ChangeTimer1(); } private void timer1_Callback(Object obj) { DisposeTimer1(); FinishTokenUpdate(); } #endregion
  19. Hi All, I've just written another plugin called Mosaic. It converts a drawing into mosaic pattern and uses the Secondary colour as the adhesive or grout between the tesserae. I was wondering what would be the best submenu for it: Distort, Render or Stylize? (This BETA version is in the _test submenu for now.) A possible enhancement I might add in future would be mathematical formulae to generate the mosaic pattern; at the moment it just uses a random irregularity based on a square shape. EDIT 1: Updated the effect by adding a tesserae colour computation option and removed the annoying message box. EDIT 2: Removed beta effect zip file because I've published it here (and here). Thanks for your suggestions. EDIT 3: Updated hyperlinks for new forum.
  20. Hi Michael, This could be worth a read: Buffered Graphics
  21. I decided to write this topic after reading this about a multi-pass IIR filter. I hope this bit of sample code helps. Option 1 is preferrable to Option 2 if possible. I've also shown how to implement "Show Original Image". Hidden Content: #define BUFFER public class MyEffect : PaintDotNet.Effects.Effect { private MyEffectConfigToken parameters = new MyEffectConfigToken(); private RenderArgs buffer_render_args; #if BUFFER ~MyEffect() { DisposeAll(); } private void DisposeAll() { try { if (buffer_render_args != null) { buffer_render_args.Dispose(); } } catch { } } #endif protected override void OnSetRenderInfo(EffectConfigToken parameters, RenderArgs dstArgs, RenderArgs srcArgs) { //MessageBox.Show("OnSetRenderInfo"); if (parameters is MyEffectConfigToken) { GenerateSurface((MyEffectConfigToken)parameters, dstArgs, srcArgs); } base.OnSetRenderInfo(parameters, dstArgs, srcArgs); } public override void Render(EffectConfigToken parameters, RenderArgs dstArgs, RenderArgs srcArgs, Rectangle[] rois, int startIndex, int length) { if (this.parameters.view_original) // Set via a control in ConfigDialog. Set it to false when closing ConfigDialog so that Ctrl+F doesn't do nothing. { dstArgs.Surface.CopySurface(srcArgs.Surface, rois, startIndex, length); } else { //ComputeIIROnRois(buffer_render_args.Surface, rois, startIndex, length); // Option 1 #if BUFFER dstArgs.Surface.CopySurface(buffer_render_args.Surface, rois, startIndex, length); #endif } } private void GenerateSurface(MyEffectConfigToken parameters, RenderArgs dstArgs, RenderArgs srcArgs) { #if BUFFER this.parameters.view_original = parameters.view_original; // Ignore view state #endif if (buffer_render_args != null && this.parameters == parameters) // Override == operator of MyEffectConfigToken (and associated operators) { return; } this.parameters = parameters; try { #if BUFFER DisposeAll(); buffer_render_args = new RenderArgs(new Surface(srcArgs.Size)); #else buffer_render_args = dstArgs; #endif buffer_render_args.Surface.CopySurface(srcArgs.Surface); //ComputeIIROnEntireBuffer(buffer_render_args); // Option 2. (You can also access the GDI+ Graphics and Bitmap as required.) } catch (Exception ex) { MessageBox.Show("An error occurred while generating surface:nn" + ex.Message, "My Effect"); } } } EDIT 1: Option 2 could be made more efficient by doing something like: //ComputeIIROnRoi(buffer_render_args, EnvironmentParameters.GetSelection(srcArgs.Bounds)); I put the code block in a hidden block. EDIT 2: OnSetRenderInfo() should have lock statement something like this: Hidden Content: private Object the_lock = new Object(); protected override void OnSetRenderInfo(EffectConfigToken parameters, RenderArgs dstArgs, RenderArgs srcArgs) { if (parameters is MyEffectConfigToken) { lock (the_lock) { GenerateSurface((MyEffectConfigToken)parameters, dstArgs, srcArgs); } } base.OnSetRenderInfo(parameters, dstArgs, srcArgs); } EDIT 3: Updated hyperlink for new forum.
  22. I'm new to Paint.NET, so correct me if I'm wrong. Does a canvas plugin mean an Effect plugin without a config dialog. For effect plugins without a config dialog, the EnvironmentParametersEx would only need to be read-only; for effect plugins with config dialogs, the EvironmentParametersEx could both readable and writeable. As an example, my Rounded Rectangle config dialog could have a brush width selector initialised to the value in EnvironmentParametersEx.BrushWidth when the dialog opens, the user then changes it and then the new value is written to EnvironmentParametersEx.BrushWidth when the dialog closes. What do you think?
  23. > Not sure if this is just me but I can not use the Numberpad on the side of my keyboard when I try in input numbers. I had tried both with the Numlock on and off. Thanks for spotting that. That was an oversight. I've fixed it for version 1.1. > This could be an OCD thing but I think that if you have the Independent Radii checkbox checked, make changes to the corners and sliders and then uncheck the Independent Radii, then the values should be set to the top left enabled textfield and should also reset the sliders back to the defaults. I've thought about various implementations in an OCD way but I was too lazy actually implement any of them ;-) . One of my ideas was to have two sets of radii values; one for independent radii and another for non-independent radii. And perhaps a separate Reset button and an Apply Same or Apply to All button for the radii. I haven't received any complaints on my effects thread yet, so I'll leave it be for now.
  24. Hi All, Here are my effects: Mosaic - v1.3.0.0 - 27 February 2017 Rounded Rectangle - v1.3.0.0 - 14 May 2009 Mosaic - Version 1.3.0.0 - 27 February 2017 Example Menu: Effects -> Artistic -> Mosaic... The Mosaic effect converts a drawing into a mosaic pattern and uses the Secondary colour as the adhesive or grout between the tesserae. Rounded Rectangle - Version 1.3.0.0 - 14 May 2009 Example Menu: Effects -> Render -> Rounded Rectangle... The Rounded Rectanlge effect uses the Primary and Secondary colours and the current brush width to draw a rectangle with rounded corners into the current selection. The roundness of the corners, the border outline and fill type are user-selectable.
  25. "_test": I'll change it when I finally publish it. Disabled sliders until Independent Radii checked: That's by design, but I was wondering whether it would be best to keep the sliders enabled and then automatically uncheck check (EDIT 1) Independent Radii when the sliders are scrolled, or hide the sliders when Independent Radii is not checked.
×
×
  • Create New...