BoltBait Posted July 15, 2008 Share Posted July 15, 2008 Does anyone have sample code of an effect that needs to create a scratch surface during processing? I've been working on an effect for hours with no luck at all. Basically, I need to create a surface and render some stuff to it (based on the source canvas). Then, blur from that scratch surface to the destination surface. Finally, I need to blend the source surface back into the destination surface for presentation of the final effect. I can provide source if it would help you to understand what I'm trying to do. But, hopefully, someone will have some sample code that I can study. Thanks! EDIT: I think that my problem is that the blur starts before the scratch surface is completely finished being created. If I do all my steps manually, the effect is perfect. If I automate it, there are bands or sometimes no effect at all. The run is not consistant. Quote Download: BoltBait's Plugin Pack | CodeLab | and a Computer Dominos Game Link to comment Share on other sites More sharing options...
Simon Brown Posted July 15, 2008 Share Posted July 15, 2008 Is the problem that the effect you are running from your plugin creates a dirty result? If so, this may be a result of threading. Edit: And I apolagise for insulting your intelligence. Quote Link to comment Share on other sites More sharing options...
BoltBait Posted July 15, 2008 Author Share Posted July 15, 2008 Funny, I edited that into my original post as you were posting... OK, so how do I fix? I even tried putting some Application.DoEvents() calls in there. It made things better, but never quite consistant. BTW, Rick once told me that you could do this and said that it was possible to chain effects between the dst canvas and the scratch canvas and back again. But, I just get screwy results. Quote Download: BoltBait's Plugin Pack | CodeLab | and a Computer Dominos Game Link to comment Share on other sites More sharing options...
Simon Brown Posted July 15, 2008 Share Posted July 15, 2008 Is the custom surface the source or the destination? Quote Link to comment Share on other sites More sharing options...
BoltBait Posted July 15, 2008 Author Share Posted July 15, 2008 This should illustrate what I'm trying to do: Does that make sense? Quote Download: BoltBait's Plugin Pack | CodeLab | and a Computer Dominos Game Link to comment Share on other sites More sharing options...
Simon Brown Posted July 15, 2008 Share Posted July 15, 2008 I believe I see the cause of your problem. The plugin only renders the graphic for the current thread bounds and yet guassian blur relies on parts of the source surface outside of its rendering target? Quote Link to comment Share on other sites More sharing options...
BoltBait Posted July 15, 2008 Author Share Posted July 15, 2008 No, that shouldn't be a problem. Most of the scratch surface is transparent. Only a few (relatively speaking) pixels are being rendered. And, the Gaussian blur causes those rendered pixels to be fairly transparent. I'm counting on that and that's why I'm blending them back with the source canvas. Quote Download: BoltBait's Plugin Pack | CodeLab | and a Computer Dominos Game Link to comment Share on other sites More sharing options...
Simon Brown Posted July 15, 2008 Share Posted July 15, 2008 No, that shouldn't be a problem. An explanation would give me a better idea of what is. Quote Link to comment Share on other sites More sharing options...
BoltBait Posted July 15, 2008 Author Share Posted July 15, 2008 Here is my code: protected override unsafe void OnRender(Rectangle[] rois, int startIndex, int length) { for (int i = startIndex; i { Render2Scratch(DstArgs.Surface, SrcArgs.Surface, rois[i]); } this.blurEffect.Render(rois, startIndex, length); this.NormalOp.Apply(DstArgs.Surface, SrcArgs.Surface, scratch); } It appears that my blurEffect is starting before my Render2Scratch function is done. Quote Download: BoltBait's Plugin Pack | CodeLab | and a Computer Dominos Game Link to comment Share on other sites More sharing options...
Simon Brown Posted July 15, 2008 Share Posted July 15, 2008 This may seem trivial, but it may also help to see OnSetRenderInfo(). Quote Link to comment Share on other sites More sharing options...
BoltBait Posted July 15, 2008 Author Share Posted July 15, 2008 OK, here it is: protected override void OnSetRenderInfo(PropertyBasedEffectConfigToken newToken, RenderArgs dstArgs, RenderArgs srcArgs) { this.Amount1 = newToken.GetProperty(PropertyNames.Amount1).Value; this.Amount2 = newToken.GetProperty(PropertyNames.Amount2).Value; scratch = new Surface(DstArgs.Size); RenderArgs scratchArgs = new RenderArgs(scratch); PropertyBasedEffectConfigToken blurToken = new PropertyBasedEffectConfigToken(this.blurProps); blurToken.SetPropertyValue(GaussianBlurEffect.PropertyNames.Radius, Amount1); this.blurEffect.SetRenderInfo(blurToken, scratchArgs, dstArgs); base.OnSetRenderInfo(newToken, dstArgs, srcArgs); } Hmmm... I just realized that I'm creating the canvas in there... That can't be good. Quote Download: BoltBait's Plugin Pack | CodeLab | and a Computer Dominos Game Link to comment Share on other sites More sharing options...
Simon Brown Posted July 15, 2008 Share Posted July 15, 2008 This is probably a bad idea that will not work, but try using CopySurface() to populate scratch with the contents of srcArgs.Surface. Quote Link to comment Share on other sites More sharing options...
BoltBait Posted July 15, 2008 Author Share Posted July 15, 2008 Why? I want my surface to be completely transparent when I start rendering to it, not a copy of the source surface. Quote Download: BoltBait's Plugin Pack | CodeLab | and a Computer Dominos Game Link to comment Share on other sites More sharing options...
Rick Brewster Posted July 16, 2008 Share Posted July 16, 2008 I'm confused by all of this :shock: Definitely do NOT call Application.DoEvents() though. Ever. Paint.NET v4 will make this sooooo much easier, trust me. (Of course, you want something that works now ...) Quote The Paint.NET Blog: https://blog.getpaint.net/ Donations are always appreciated! https://www.getpaint.net/donate.html Link to comment Share on other sites More sharing options...
I Like Pi Posted July 16, 2008 Share Posted July 16, 2008 SetRenderInfo(blurToken, scratchArgs, dstArgs);You said you need to blur from the scratch to the destination. The pattern for SetRenderInfo is (EffectConfigToken parameters, RenderArgs dstArgs, RenderArgs srcArgs), so you're passing the destination as the source and the scratch as the destination. Thus, what you rendered to the scratch is overwritten. Quote Link to comment Share on other sites More sharing options...
Curtis Posted July 16, 2008 Share Posted July 16, 2008 I believe pyrochild's ScriptLab creates a scratch surface to render one effect on top of another, you could have a look at its source. Quote Plugins Link to comment Share on other sites More sharing options...
pyrochild Posted July 16, 2008 Share Posted July 16, 2008 ScriptLab, Film, and Borders N' Shapes all use scratch surfaces.... badly. Here's something better: using System; using System.Collections.Generic; using System.Drawing; using System.Windows.Forms; using PaintDotNet; using PaintDotNet.Effects; using PaintDotNet.PropertySystem; using PaintDotNet.IndirectUI; namespace pyrochild.effects.tests { public class ScratchSurfaceTest : PropertyBasedEffect { public static string StaticName { get { string s = "scratchsurfacetest"; #if DEBUG s += " BETA"; #endif return s; } } protected override PropertyCollection OnCreatePropertyCollection() { return PropertyCollection.CreateEmpty(); } public ScratchSurfaceTest() : base(StaticName, null, null, EffectFlags.None) { gbe = new GaussianBlurEffect(); nbo = new UserBlendOps.NormalBlendOp(); } GaussianBlurEffect gbe; PropertyBasedEffectConfigToken gbeToken; UserBlendOps.NormalBlendOp nbo; protected override void OnRender(Rectangle[] rois, int startIndex, int length) { PdnRegion selection = EnvironmentParameters.GetSelection(SrcArgs.Bounds); gbe.Render(rois, startIndex, length); //OVERLAY has already been rendered onto DST, so we need to copy SRC *under* it. For that, we need an overload with //params for dst, lhs, and rhs, otherwise it assumes we want to put src on top of dst. foreach (Rectangle rect in rois) { Point pt = rect.Location; Size sz = rect.Size; nbo.Apply(DstArgs.Surface, pt, SrcArgs.Surface, pt, DstArgs.Surface, pt, sz); } } protected override void OnSetRenderInfo(PropertyBasedEffectConfigToken newToken, RenderArgs dstArgs, RenderArgs srcArgs) { PdnRegion selection = EnvironmentParameters.GetSelection(srcArgs.Bounds); PropertyCollection gbeProps = gbe.CreatePropertyCollection(); gbeToken = new PropertyBasedEffectConfigToken(gbeProps); gbeToken.SetPropertyValue(GaussianBlurEffect.PropertyNames.Radius, 50); //there's room for mem-optimization here, if we want to make the overlay surface only as large //as the selection: overlay = new Surface(selection.GetBoundsInt().Size); //will take more logic elsewhere, though. Surface overlay = new Surface(srcArgs.Size); overlay.Clear(selection, ColorBgra.Red); RenderArgs oArgs = new RenderArgs(overlay); gbe.SetRenderInfo(gbeToken, dstArgs, oArgs);//we want to blur from OVERLAY to DST. base.OnSetRenderInfo(newToken, dstArgs, srcArgs); } } } Let me know if I need to clarify anything. Quote ambigram signature by Kemaru [i write plugins and stuff] If you like a post, upvote it! Link to comment Share on other sites More sharing options...
BoltBait Posted July 16, 2008 Author Share Posted July 16, 2008 Thanks, pyrochild. I changed my code to look mostly like yours but it still doesn't work quite right. I PM'd you more details. Can you take a look at the result and see what's wrong? Quote Download: BoltBait's Plugin Pack | CodeLab | and a Computer Dominos Game Link to comment Share on other sites More sharing options...
Tanel Posted July 17, 2008 Share Posted July 17, 2008 Pyrochild helped me out with exactly the same problem when I tried to implement feather control into my "Color to Alpha" plugin (link to original discussion). Feel free to copy below code (visual studio). It's not cleaned up but has some comments; those marked with "???" are by pyrochild. Note that I have moved blurring into separate if-block which is ignored until feather token is >0. This is for better performance - because with larger images UI of Color to Alpha becomes quite laggy as soon as feather is on. using System; using System.Collections; using System.Drawing; using PaintDotNet; using PaintDotNet.Effects; using PaintDotNet.PropertySystem; using System.Collections.Generic; namespace ColorToAlpha { [EffectCategory(EffectCategory.Adjustment)] public class EffectPlugin : PaintDotNet.Effects.Effect { public static string StaticName { get { return "Color to Alpha"; } } public static Bitmap StaticImage { get { return new Bitmap(typeof(EffectPlugin), "EffectPluginIcon.png"); } } public static string StaticSubMenuName { get { return null; // Use for no submenu // return "My SubMenu"; // Use for custom submenu } } public EffectPlugin() : base(StaticName, StaticImage, StaticSubMenuName, EffectFlags.Configurable) { blurEffect = new GaussianBlurEffect(); } public override EffectConfigDialog CreateConfigDialog() { return new ColorToAlpha(); } private GaussianBlurEffect blurEffect; PropertyBasedEffectConfigToken blurToken; Surface tempSurface; RenderArgs temp; bool changed; protected override void OnSetRenderInfo(EffectConfigToken parameters, RenderArgs dstArgs, RenderArgs srcArgs) { this.changed = true; EffectPluginConfigToken token = (EffectPluginConfigToken)parameters; PropertyCollection blurProps = blurEffect.CreatePropertyCollection(); blurToken = new PropertyBasedEffectConfigToken(blurProps); blurToken.SetPropertyValue(GaussianBlurEffect.PropertyNames.Radius, token.Feather); base.OnSetRenderInfo(parameters, dstArgs, srcArgs); } public override unsafe void Render(EffectConfigToken parameters, RenderArgs dstArgs, RenderArgs srcArgs, Rectangle[] rois, int startIndex, int length) { EffectPluginConfigToken token = (EffectPluginConfigToken)parameters; int feax = token.Feather; bool inv = token.Invert; int basea = token.BaseAlpha; if (feax > 0) // THIS IS FOR FASTER PERFORMANCE WHILE FEATHER IS NOT USED { PdnRegion selectionRegion = EnvironmentParameters.GetSelection(srcArgs.Bounds); if (changed && tempSurface != null) // ??? I set changed = true in OnSetRenderInfo(), to indicate that the user has changed settings and therefore, invalidated our tempSurface. But if it's null it doesn't matter. { tempSurface.Dispose(); // ??? Clear up our resource usage. We have to be nice to our user's RAM. tempSurface = null; // ??? Then set it to null so the next ifblock gets executed. I could combine this more elegantly, but the code here evolved organically from the old version, and I'm lazy. } if (tempSurface == null) // ??? If we don't have a tempSurface at this point (whether it's because we never made one, or just invalidated it above), we need to make one. { Rectangle[] gorois = selectionRegion.GetRegionScansInt(); // build new surface "tempSurface" tempSurface = new Surface(srcArgs.Size); temp = new RenderArgs(tempSurface); RenderAlpha(parameters, tempSurface, srcArgs, gorois, 0, gorois.Length); changed = false; // ??? Set changed to false since we've made our tempSurface and it's currently valid, until changed gets set to true again. This prevents us from creating a new overlay every time OnRender() is called blurEffect.SetRenderInfo(blurToken, dstArgs, temp); } this.blurEffect.Render(rois, startIndex, length); for (int i = startIndex; i < startIndex + length; ++i) { Rectangle roi = rois[i]; for (int y = roi.Top; y < roi.Bottom; ++y) { ColorBgra* dstPtr = dstArgs.Surface.GetPointAddress(roi.X, roi.Y); ColorBgra NewPixel; ColorBgra OrigPixel; byte a, ro, go, bo, ao, ry, by, gy, ay; // r, g, b, for (int x = roi.Left; x < roi.Right; ++x) { NewPixel = dstArgs.Surface[x, y]; //r = NewPixel.R; //g = NewPixel.G; //b = NewPixel.B; a = NewPixel.R; // WE MADE GRAYSCALE IMAGE FROM ALPHA VALUES BEFORE BLURRING (see bottom of RenderAlpha), NOW WE TURN IT BACK TO ALPHA OrigPixel = srcArgs.Surface[x, y]; ro = OrigPixel.R; go = OrigPixel.G; bo = OrigPixel.B; ao = OrigPixel.A; byte baseab = (byte)basea; if (baseab > 0 && a < baseab) a = baseab; // INVERT if (inv == true) a = (byte)(255 - a); if (selectionRegion.IsVisible(x, y)) { ry = Utility.ClampToByte(ro); gy = Utility.ClampToByte(go); by = Utility.ClampToByte(bo); ay = Utility.ClampToByte(a); NewPixel = ColorBgra.FromBgra(by, gy, ry, ay); *dstPtr = NewPixel; ++dstPtr; } } } } } else // feather token = 0; no need for 3rd surface rendering { int hue1 = token.huefrom; int hue2 = token.hueto; int sat1 = token.satfrom; int sat2 = token.satto; int b1 = token.bnessfrom; int b2 = token.bnessto; int tol = token.Tolerance; bool huebox = token.Huebox; bool satbox = token.Satbox; bool bnessbox = token.Bnessbox; bool ovrride = token.Ovrride; // NEW for (int i = startIndex; i < startIndex + length; ++i) { Rectangle roi = rois[i]; for (int y = roi.Top; y < roi.Bottom; ++y) { ColorBgra* srcPtr = srcArgs.Surface.GetPointAddress(roi.X, roi.Y); ColorBgra* dstPtr = dstArgs.Surface.GetPointAddress(roi.X, roi.Y); ColorBgra CurrentPixel; ColorBgra OrigPixel; byte ro, go, bo, ao, ry, by, gy, ay; // r, g, b, a, float amtx; double ax, huej, huel, satj, satl, brtj, brtl, huej1, huel1, huej0, huel0, satj1, satl1, brtj1, brtl1, fn, ft, fu, fv, ffn, fft, ffu, ffv, fxx; for (int x = roi.Left; x < roi.Right; ++x) { OrigPixel = srcArgs.Surface[x, y]; ro = OrigPixel.R; go = OrigPixel.G; bo = OrigPixel.B; ao = OrigPixel.A; amtx = 1 - basea / 255f; CurrentPixel = dstArgs.Surface[x, y]; // GET HUE: FROM UnaryPixelOps.cs: HsvColor hsvColor = HsvColor.FromColor(OrigPixel.ToColor()); int hue = hsvColor.Hue; int satur = hsvColor.Saturation; int brt = (int)OrigPixel.GetIntensityByte(); if (hue1 > 359) hue1 = 359; if (hue2 > 359) hue2 = 359; double huearea = (hue2 - hue1); if (hue2 < hue1) huearea += 360; double hfea = tol; if (tol > ((360 - huearea) / 2) * 255 / 360) hfea = ((360 - huearea) / 2) * 255 / 360; // adjust hue fading to avoid crossing over total 360 // virtually shift hue into "normal" min-max bounds in case hue_from > hue_to double nhue0 = -(hue2 - hue1); double nhue1 = (((nhue0 + Math.Abs(nhue0)) / 2) / 360); double nhuex = (Math.Ceiling(nhue1)); // return 1 if hue_from > hue_to; else 0 int nhue = (int)((360 - hue1) * nhuex); int huex = hue; huex += nhue; while (huex > 359) { huex -= 360; } double hue22 = 360 - hue1; double hue12 = 360 - hue2; double huez = 360 - hue; // hue limiter *while hue_from > hue_to* huej = (hue2 + nhue - huex + 1 - 0.1); // huej = (hue2 + nhue - huex + 1 - 0.1); huel = (((huej + Math.Abs(huej)) / 2) / huej); // hue_to limiter // hue limiters *while hue_from < hue_to* huej0 = ((hue2 - hue + 1 - 0.1) * (1 - nhuex)) + ((hue22 - huez + 1 - 0.1) * nhuex); huel0 = (((huej0 + Math.Abs(huej0)) / 2) / huej0); // hue_to limiter huej1 = ((hue - hue1 + 1 - 0.1) * (1 - nhuex)) + ((huez - hue12 + 1 - 0.1) * nhuex); huel1 = (((huej1 + Math.Abs(huej1)) / 2) / huej1);// hue_from limiter double huelx = (huel * nhuex + huel0 * huel1 * (1 - nhuex)); // use only one set of limiters from cases hue_from > hue_to OR hue_from < hue_to satj = (sat2 - satur + 1 - 0.1); satl = (((satj + Math.Abs(satj)) / 2) / satj); // saturation_to limiter satj1 = (satur - sat1 + 1 - 0.1); satl1 = (((satj1 + Math.Abs(satj1)) / 2) / satj1); // saturation_from limiter brtj = (b2 - brt + 1 - 0.1); brtl = (((brtj + Math.Abs(brtj)) / 2) / brtj); // brightness_to limiter brtj1 = (brt - b1 + 1 - 0.1); brtl1 = (((brtj1 + Math.Abs(brtj1)) / 2) / brtj1); // brightness_from limiter double ax0 = (huelx * satl * brtl * satl1 * brtl1); double ax1 = ((1 - ax0) * (1 - amtx) + ax0); // set alpha of non-picked pixels to inverse of amount double ax0h = huelx; // double ax0h = (satl * brtl * satl1 * brtl1); double ax1h = ((1 - ax0h) * (1 - amtx) + ax0h); // set alpha of non-picked pixels to inverse of amount double ax0s = (satl * satl1); // double ax0s = (huelx * brtl * brtl1); double ax1s = ((1 - ax0s) * (1 - amtx) + ax0s); // set alpha of non-picked pixels to inverse of amount double ax0b = (brtl * brtl1); // double ax0b = (huelx * satl * satl1); double ax1b = ((1 - ax0b) * (1 - amtx) + ax0b); // set alpha of non-picked pixels to inverse of amount // HUE FADING TO_LIMITER double huej0f = (huej0 * 255 / 360); if (huej0 - 1 + 0.1 + (hfea * 360 / 255) > 359) // XXXX TEST if (huej0 - 1 + 0.1 + (hfea * 360 / 255) > 360) huej0f = ((huej0 - 1 + 0.1 - 360) * 255 / 360); // XXX TEST huej0f = ((huej0 - 1 + 0.1 - 361) * 255 / 360); if (huej0 - 1 + 0.1 + (hfea * 360 / 255) < 0) // XXXX TEST if (huej0 - 1 + 0.1 + (hfea * 360 / 255) > 360) huej0f = ((huej0 - 1 + 0.1 + 360) * 255 / 360); // XXX TEST huej0f = ((huej0 - 1 + 0.1 - 361) * 255 / 360); fn = (((-huej0f + Math.Abs(-huej0f)) / 2) / -huej0f); // * ax1h; ft = (-huej0f / (hfea + 0.01)); // tol -> hfea fu = (1 - ft * amtx); fv = (fu * fn + ax0h * (1 - fn)); //(fu * fn * fo + ax1 * fm + ax1 * (1 - fn)); // // HUE FADING FROM_LIMITER double huej1f = (huej1 * 255 / 360); if (huej1 - 1 + 0.1 + (hfea * 360 / 255) > 359) //XXXX if (huej1 - 1 + 0.1 + (hfea * 360 / 255) > 360) huej1f = ((huej1 - 1 + 0.1 - 360) * 255 / 360); // XXX huej1f = ((huej1 - 1 + 0.1 - 361) * 255 / 360); if (huej1 - 1 + 0.1 + (hfea * 360 / 255) < 0) //XXXX if (huej1 - 1 + 0.1 + (hfea * 360 / 255) > 360) huej1f = ((huej1 - 1 + 0.1 + 360) * 255 / 360); // XXX huej1f = ((huej1 - 1 + 0.1 - 361) * 255 / 360); ffn = (((-huej1f + Math.Abs(-huej1f)) / 2) / -huej1f); // *ax1h; fft = (-huej1f / (hfea + 0.01)); // tol -> hfea ffu = (1 - fft * amtx); ffv = (ffu * ffn + ax0h * (1 - ffn)); //(ffu * ffn * ffo + ax1 * ffm + ax1 * (1 - ffn)); // fxx = (Math.Max(fv, ffv)); // HUE TO ALPHA MULTIPLIER if (huebox == false) fxx = 1; // fxx = ax1h; // // SATURATION FADING TO_LIMITER double satjf = (satj * 255 / 100); // * ax1 ei sobi siia double fns = (((-satjf + Math.Abs(-satjf)) / 2) / -satjf); // * ax1s; double fts = (-satjf / (tol + 0.01)); // tol -> hfea double fus = (1 - fts * amtx); double fvs = (fus * fns + ax0s * (1 - fns)); //double fvs = (fus * fns + ax1 * (1 - fns)); // SATURATION FADING FROM_LIMITER double satj1f = (satj1 * 255 / 100); // * ax1 ei sobi siia double ffns = (((-satj1f + Math.Abs(-satj1f)) / 2) / -satj1f); // * ax1s; double ffts = (-satj1f / (tol + 0.01)); // tol -> hfea double ffus = (1 - ffts * amtx); double ffvs = (ffus * ffns + ax0s * (1 - ffns)); //(ffu * ffn * ffo + ax1 * ffm + ax1 * (1 - ffn)); // double fxxs = (Math.Max(fvs, ffvs)) * fxx; // SATURATION+HUE TO ALPHA MULTIPLIER if (satbox == false) fxxs = fxx; // fxxs = ax1s * fxx; // // BRIGHTNESS FADING TO_LIMITER double fnb = (((-brtj + Math.Abs(-brtj)) / 2) / -brtj); // * ax1b; double ftb = (-brtj / (tol + 0.01)); // tol -> hfea double fub = (1 - ftb * amtx); double fvb = (fub * fnb + ax0b * (1 - fnb)); //(fu * fn * fo + ax1 * fm + ax1 * (1 - fn)); // // BRIGHTNESS FADING FROM_LIMITER double ffnb = (((-brtj1 + Math.Abs(-brtj1)) / 2) / -brtj1); // * ax1b; double fftb = (-brtj1 / (tol + 0.01)); // tol -> hfea double ffub = (1 - fftb * amtx); double ffvb = (ffub * ffnb + ax0b * (1 - ffnb)); //(ffu * ffn * ffo + ax1 * ffm + ax1 * (1 - ffn)); // double fxxb = (Math.Max(fvb, ffvb)) * fxxs; // BRIGHTNESS+HUE+SATURATION TO ALPHA MULTIPLIER if (bnessbox == false) fxxb = fxxs; // fxxb = ax1b * fxxs;// // even out alpha for non-selected areas double fxxx0 = Math.Ceiling(fxxb); double fxxx = fxxb + (1 - amtx) * (1 - fxxx0); if (fxxx < (1 - amtx)) fxxx = (1 - amtx); if (ovrride == true) // NEW ao = 255; ax = (ao * fxxx); // FINAL ALPHA byte baseab = (byte)basea; if (baseab > 0 && ax < baseab) // REVISED 21-01-08 ax = baseab; // invert if (inv == true) ax = (255 - ax); ry = Utility.ClampToByte(ro); gy = Utility.ClampToByte(go); by = Utility.ClampToByte(bo); ay = Utility.ClampToByte(ax); CurrentPixel = ColorBgra.FromBgra(by, gy, ry, ay); *dstPtr = CurrentPixel; ++dstPtr; } } } } } private unsafe void RenderAlpha(EffectConfigToken parameters, Surface surface, RenderArgs srcArgs, Rectangle[] rois, int startIndex, int length) { EffectPluginConfigToken token = (EffectPluginConfigToken)parameters; int hue1 = token.huefrom; int hue2 = token.hueto; int sat1 = token.satfrom; int sat2 = token.satto; int b1 = token.bnessfrom; int b2 = token.bnessto; int tol = token.Tolerance; int basea = token.BaseAlpha; basea += 1; // HEAL THE SHIFT IN RESULTS bool huebox = token.Huebox; bool satbox = token.Satbox; bool bnessbox = token.Bnessbox; bool ovrride = token.Ovrride; for (int i = startIndex; i < startIndex + length; ++i) { Rectangle roi = rois[i]; for (int y = roi.Top; y < roi.Bottom; ++y) { ColorBgra* ptr = surface.GetPointAddressUnchecked(roi.Left, y); ColorBgra OrigPixel; byte ro, go, bo, ao, ry, by, gy, ay; // r, g, b, a, float amtx; double ax, huej, huel, satj, satl, brtj, brtl, huej1, huel1, huej0, huel0, satj1, satl1, brtj1, brtl1, fn, ft, fu, fv, ffn, fft, ffu, ffv, fxx; for (int x = roi.Left; x < roi.Right; ++x) { OrigPixel = srcArgs.Surface[x, y]; ro = OrigPixel.R; go = OrigPixel.G; bo = OrigPixel.B; ao = OrigPixel.A; amtx = 1 - basea / 255f; // amtx = amt / 100f; // GET HUE: FROM UnaryPixelOps.cs: HsvColor hsvColor = HsvColor.FromColor(OrigPixel.ToColor()); int hue = hsvColor.Hue; int satur = hsvColor.Saturation; int brt = (int)OrigPixel.GetIntensityByte(); if (hue1 > 359) hue1 = 359; if (hue2 > 359) hue2 = 359; double huearea = (hue2 - hue1); if (hue2 < hue1) huearea += 360; double hfea = tol; if (tol > ((360 - huearea) / 2) * 255 / 360) hfea = ((360 - huearea) / 2) * 255 / 360; // adjust hue fading to avoid crossing over total 360 // virtually shift hue into "normal" min-max bounds in case hue_from > hue_to double nhue0 = -(hue2 - hue1); double nhue1 = (((nhue0 + Math.Abs(nhue0)) / 2) / 360); double nhuex = (Math.Ceiling(nhue1)); // return 1 if hue_from > hue_to; else 0 int nhue = (int)((360 - hue1) * nhuex); int huex = hue; huex += nhue; while (huex > 359) { huex -= 360; } double hue22 = 360 - hue1; double hue12 = 360 - hue2; double huez = 360 - hue; // hue limiter *while hue_from > hue_to* huej = (hue2 + nhue - huex + 1 - 0.1); // huej = (hue2 + nhue - huex + 1 - 0.1); huel = (((huej + Math.Abs(huej)) / 2) / huej); // hue_to limiter // hue limiters *while hue_from < hue_to* huej0 = ((hue2 - hue + 1 - 0.1) * (1 - nhuex)) + ((hue22 - huez + 1 - 0.1) * nhuex); huel0 = (((huej0 + Math.Abs(huej0)) / 2) / huej0); // hue_to limiter huej1 = ((hue - hue1 + 1 - 0.1) * (1 - nhuex)) + ((huez - hue12 + 1 - 0.1) * nhuex); huel1 = (((huej1 + Math.Abs(huej1)) / 2) / huej1);// hue_from limiter double huelx = (huel * nhuex + huel0 * huel1 * (1 - nhuex)); // use only one set of limiters from cases hue_from > hue_to OR hue_from < hue_to satj = (sat2 - satur + 1 - 0.1); satl = (((satj + Math.Abs(satj)) / 2) / satj); // saturation_to limiter satj1 = (satur - sat1 + 1 - 0.1); satl1 = (((satj1 + Math.Abs(satj1)) / 2) / satj1); // saturation_from limiter brtj = (b2 - brt + 1 - 0.1); brtl = (((brtj + Math.Abs(brtj)) / 2) / brtj); // brightness_to limiter brtj1 = (brt - b1 + 1 - 0.1); brtl1 = (((brtj1 + Math.Abs(brtj1)) / 2) / brtj1); // brightness_from limiter double ax0 = (huelx * satl * brtl * satl1 * brtl1); double ax1 = ((1 - ax0) * (1 - amtx) + ax0); // set alpha of non-picked pixels to inverse of amount double ax0h = huelx; // double ax0h = (satl * brtl * satl1 * brtl1); double ax1h = ((1 - ax0h) * (1 - amtx) + ax0h); // set alpha of non-picked pixels to inverse of amount double ax0s = (satl * satl1); // double ax0s = (huelx * brtl * brtl1); double ax1s = ((1 - ax0s) * (1 - amtx) + ax0s); // set alpha of non-picked pixels to inverse of amount double ax0b = (brtl * brtl1); // double ax0b = (huelx * satl * satl1); double ax1b = ((1 - ax0b) * (1 - amtx) + ax0b); // set alpha of non-picked pixels to inverse of amount // HUE FADING TO_LIMITER double huej0f = (huej0 * 255 / 360); if (huej0 - 1 + 0.1 + (hfea * 360 / 255) > 359) // XXXX TEST if (huej0 - 1 + 0.1 + (hfea * 360 / 255) > 360) huej0f = ((huej0 - 1 + 0.1 - 360) * 255 / 360); // XXX TEST huej0f = ((huej0 - 1 + 0.1 - 361) * 255 / 360); if (huej0 - 1 + 0.1 + (hfea * 360 / 255) < 0) // XXXX TEST if (huej0 - 1 + 0.1 + (hfea * 360 / 255) > 360) huej0f = ((huej0 - 1 + 0.1 + 360) * 255 / 360); // XXX TEST huej0f = ((huej0 - 1 + 0.1 - 361) * 255 / 360); fn = (((-huej0f + Math.Abs(-huej0f)) / 2) / -huej0f); // * ax1h; ft = (-huej0f / (hfea + 0.01)); // tol -> hfea fu = (1 - ft * amtx); fv = (fu * fn + ax0h * (1 - fn)); //(fu * fn * fo + ax1 * fm + ax1 * (1 - fn)); // // HUE FADING FROM_LIMITER double huej1f = (huej1 * 255 / 360); if (huej1 - 1 + 0.1 + (hfea * 360 / 255) > 359) //XXXX if (huej1 - 1 + 0.1 + (hfea * 360 / 255) > 360) huej1f = ((huej1 - 1 + 0.1 - 360) * 255 / 360); // XXX huej1f = ((huej1 - 1 + 0.1 - 361) * 255 / 360); if (huej1 - 1 + 0.1 + (hfea * 360 / 255) < 0) //XXXX if (huej1 - 1 + 0.1 + (hfea * 360 / 255) > 360) huej1f = ((huej1 - 1 + 0.1 + 360) * 255 / 360); // XXX huej1f = ((huej1 - 1 + 0.1 - 361) * 255 / 360); ffn = (((-huej1f + Math.Abs(-huej1f)) / 2) / -huej1f); // *ax1h; fft = (-huej1f / (hfea + 0.01)); // tol -> hfea ffu = (1 - fft * amtx); ffv = (ffu * ffn + ax0h * (1 - ffn)); //(ffu * ffn * ffo + ax1 * ffm + ax1 * (1 - ffn)); // fxx = (Math.Max(fv, ffv)); // HUE TO ALPHA MULTIPLIER if (huebox == false) fxx = 1; // fxx = ax1h; // // SATURATION FADING TO_LIMITER double satjf = (satj * 255 / 100); // * ax1 ei sobi siia double fns = (((-satjf + Math.Abs(-satjf)) / 2) / -satjf); // * ax1s; double fts = (-satjf / (tol + 0.01)); // tol -> hfea double fus = (1 - fts * amtx); double fvs = (fus * fns + ax0s * (1 - fns)); //double fvs = (fus * fns + ax1 * (1 - fns)); // SATURATION FADING FROM_LIMITER double satj1f = (satj1 * 255 / 100); // * ax1 ei sobi siia double ffns = (((-satj1f + Math.Abs(-satj1f)) / 2) / -satj1f); // * ax1s; double ffts = (-satj1f / (tol + 0.01)); // tol -> hfea double ffus = (1 - ffts * amtx); double ffvs = (ffus * ffns + ax0s * (1 - ffns)); //(ffu * ffn * ffo + ax1 * ffm + ax1 * (1 - ffn)); // double fxxs = (Math.Max(fvs, ffvs)) * fxx; // SATURATION+HUE TO ALPHA MULTIPLIER if (satbox == false) fxxs = fxx; // fxxs = ax1s * fxx; // // BRIGHTNESS FADING TO_LIMITER double fnb = (((-brtj + Math.Abs(-brtj)) / 2) / -brtj); // * ax1b; double ftb = (-brtj / (tol + 0.01)); // tol -> hfea double fub = (1 - ftb * amtx); double fvb = (fub * fnb + ax0b * (1 - fnb)); //(fu * fn * fo + ax1 * fm + ax1 * (1 - fn)); // // BRIGHTNESS FADING FROM_LIMITER double ffnb = (((-brtj1 + Math.Abs(-brtj1)) / 2) / -brtj1); // * ax1b; double fftb = (-brtj1 / (tol + 0.01)); // tol -> hfea double ffub = (1 - fftb * amtx); double ffvb = (ffub * ffnb + ax0b * (1 - ffnb)); //(ffu * ffn * ffo + ax1 * ffm + ax1 * (1 - ffn)); // double fxxb = (Math.Max(fvb, ffvb)) * fxxs; // BRIGHTNESS+HUE+SATURATION TO ALPHA MULTIPLIER if (bnessbox == false) fxxb = fxxs; // fxxb = ax1b * fxxs;// // even out alpha for non-selected areas double fxxx0 = Math.Ceiling(fxxb); double fxxx = fxxb + (1 - amtx) * (1 - fxxx0); if (fxxx < (1 - amtx)) fxxx = (1 - amtx); if (ovrride == true) // NEW ao = 255; ax = (ao * fxxx); // FINAL ALPHA // TRICK TO BYPASS GAUSSIAN BLUR MISBEHAVIOUR ON SEMITRANSPARENT PIXELS (BUG IN PDN 3.22) // TYPE OF BUG: ALPHA (and Value) OF SEMITRANSPARENT PIXELS IS REDUCED // WE MAKE GRAYSCALE IMAGE WITH NO TRANSPARENCY, BASED ON ALPHA VALUES // THEN WE BLUR THIS (CALLED FROM MAIN RENDER) WITHOUT MISTAKES AND TURN RESULT BACK TO ALPHA VALUES ry = Utility.ClampToByte(ax); gy = Utility.ClampToByte(ax); by = Utility.ClampToByte(ax); ay = Utility.ClampToByte(255); OrigPixel = ColorBgra.FromBgra(by, gy, ry, ay); *ptr = OrigPixel; ++ptr; } } } } } } Quote Link to comment Share on other sites More sharing options...
BoltBait Posted July 18, 2008 Author Share Posted July 18, 2008 Thanks everyone. I did get it working... and not the way Tanel's does. I'll publish my findings later when I publish the plugin. Quote Download: BoltBait's Plugin Pack | CodeLab | and a Computer Dominos Game 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.