Photoshop Layer Effects for JUCE Controls!

ColourGradient class should have “Conical gradient”, but there is no …

I disagree… ColourGradient should ONLY specify the colours. The information about the type of blend (linear, radial, angle, reflected, diamond) and the blend parameters (start point, end point, angle, scale) should be separate. For example we could have ColourGradient for the colours, and a separate class GradientFill that describes the fill parameters, of which the ColourGradient could be a member.

Furthermore to make it easy to pass these colour ramps around they should be lightweight handles to reference counted implementation objects (much like Image).

This is how I have designed my code in LayerEffects. I also made the colour lookup table a handle to a reference counted implementation object, so it is easy to pass around especially to pixel functors used with generic programming techniques.

1 Like

Unfortunately I’ve rolled my own GradientColours class. The transparency stops are separate from the colour stops, and it adds the “midpoint” feature. It’s a reference counted handle so it is lightweight and can be passed around and copied freely (which is great for generic programming).

If and when I get down to the painful task of creating this control for specifying the colours I will do it in a way that is independent of the underlying object (i.e. ColourGradient or GradientColours) this way it could be used with either. Although for the case of ColourGradient it would be necessary to have additional controls for the style (linear versus radial) since my class only represents the colours and not the style of blend.

Hi Vinn, I completely agree with you that the gradient colours should be separated from the gradient type. I’ll definitely try to get round to creating that component but it might have to wait until next week now as I’m away until then. If I can I’ll try and make two versions, one for Jules which he can add to the library and one for your more advanced gradients as the colour specifier component part probably won’t be much different. As you mentioned ColourGradient could probably use a pimpl to specify the gradient without affecting user code.

Keep up the great work!

Let JUCE become QJuce? hehe…

in QT:

QGradient
    |----QLinearGradient
    |----QRadialGradient
    |----QConicalGradient

QConicalGradient cg (QPointF (300, 150), 50);
cg.setColorAt (0.2, Qt::black);
cg.setColorAt (0.9, Qt:cyan);
painter.setBrush (cg);
painter.draw... (...);
// ...

Ok, so I finally managed to find a bit of time to have a go at the GradientDesigner class. This was actually a bit trickier than expected due to the coupling of the colours and positions and the co-ordinates, I definitely think these two aspects could be split which would lead to a slightly cleaner design.

I basically ended up doing this from scratch using an array of child components for the stops. Its a slightly different approach to Jules’ example but behaves in pretty much the same way. Anyway the repo is on my GitHub if you want to check it out, this is just a first draft at the moment though. There’s also a screenshot in the announcement post here.

There are a couple of differences with the photoshop gradient designer, the main thing being that the alpha levels are combined with the colour stops. I don’t think its really worth re-writing the wheel to separate those as its not really how colours are used in JUCE. I will add the “Stops” number boxes below the preview area though if there is demand.

I know this uses the JUCE ColourGradient class but you could probably easily write a quick conversion wrapper between that and your GradientColours class. presumably you would just have to iterate through all the points copying the position and colour.

On a slight aside I have tried a few times to get the LayerEffects demo working but it just hits endless amounts of assertions on OSX (10.7.4, Xcode 4.4.1). I think the problem is that Image’s on the Mac always have an alpha channel so it was asserting on either the source or destination image which is created somewhere in the JUCE rendering code. (By the way I did make sure to have USE_CORE_GRAPHICS_RENDERING off.)

Anyway, let me know what you think.

Try the “develop” branch. I think the problem you are getting on the Mac is that the version in the master branch doesn’t have the LookAndFeel which forces the software renderer. There should be a comment above the assert in my code to the effect that the software renderer is required to use a LayerEffects context.

Yeh, its not failing there though, I get endless assertions in vf_BlendProc.cpp, line 137 which end up here and in similar functions:

void ColourOverlayStyle::operator () (Pixels destPixels) { jassert (destPixels.isRGB ());

I’m not sure exactly where but an ARGB image must being created instead of an RGB one somewhere. This is on the develop branch by the way, just grabbed today and hit build. The CustomLookAndFeel::createGraphicsContext is being called but the imageToRenderOn is always ARGB.

As far as I can see its because juce::NSViewComponentPeer::drawRect(_NSRect) is always creating an ARGB image because the Component is not opaque. I tried setting isOpaque to true on the CMainWindow but still no luck, there must be something somewhere, even an internal component that is not opaque so the destination image is always ending up as ARGB.

Has anybody else got this to work? I can’t be the only one trying on Mac.

I will give it another look on the Mac

Ok cheers, if I can be of any help let me know but as its a pretty big codebase that I’m not familiar debugging is tricky. For what its worth I did just try this on an XP VM and it runs but still hits a lot of assertions about bounds not being equal in Pixels::Iterate2 and steps being less than 0 in advance(). I know this is still a work in progress and you are probably aware of these but I just thought I’d let you know anyway.

This usually happens when the window is partially obscured. I haven’t finished the calculations for determining the smallest rectangle to process and that is causing the bugs. I won’t have a proper calculation for these rectangles until I have finished the algorithms.

I believe the problem with the Macintosh is that CoreGraphics drawing is enabled. Could you please try disabling it? When CoreGraphics is on, it never calls the LookAndFeel::createGraphicsContext() function.

Despite the “wonders” of Introjucer, I could see no obvious way to turn off CoreGraphics. I was working in Xcode, an IDE which I am crippled in. So I could not figure out how to shut it off via Introjucer. I could probably do it in the AppConfig.h file but that would only get overwritten the next time I modified the .jucer file.

Well, overriding the LookAndFeel does a brute force return of a software renderer. I added a breakpoint in LookAndFeel::createGraphicsContext() an its definitely getting called. I think the problem is before the renderer is even created, when the final image to paint onto is created (in juce::NSViewComponentPeer::drawRect(_NSRect)) this always has an alpha channel because the isOpaque flag is returning false but I’m not sure what this NSViewComponentPeer is or if we even have control over it’s opaqueness.

You can add a pre-processor macro in the Introjucer USE_COREGRAPHICS_RENDERING=0 to remove the Core Graphics rendering, the app will then use the software renderer. This definitely works as I’m using this in my current app and you can see the difference in the text rending (I’m going to try our your FreeType code when I get a chance). But as I said, even without that set the software render is still being used. And yes, the assertions still happen with the flag set.

I do agree however that USE_COREGRAPHICS_RENDERING should be a config option similar to JUCE_USE_CORE_IMAGE_LOADER.

Well Jules just turned me on to ComponentPeer::setCurrentRenderingEngine() so I’m going to give that a whirl!

Well that was a dead end. I set the renderer to 0 (meaning software renderer) and it still insists on using a core graphics context. I observed that “usingCoreGraphics” in the ComponentPeer was getting set to false but somehow it goes back to true. I checked in the code, if you want to have a look:

No changes to AppConfig.h are required, thanks to setCurrentRenderingEngine().

[quote=“dave96”]On a slight aside I have tried a few times to get the LayerEffects demo working but it just hits endless amounts of assertions on OSX (10.7.4, Xcode 4.4.1). I think the problem is that Image’s on the Mac always have an alpha channel so it was asserting on either the source or destination image which is created somewhere in the JUCE rendering code. (By the way I did make sure to have USE_CORE_GRAPHICS_RENDERING off.)

Anyway, let me know what you think.[/quote]

I’ve updated the repository to use the latest JUCE, including setCurrentRenderingEngine(). This solves the problem where the CoreGraphics context gets used instead of the software renderer, and doesn’t require any changes to the .jucer file or AppConfig.h. But now there’s a new problem, it seems there is no way to create a juce::Image of type Image::RGB on the Mac, which strikes me as utter nonsense.

[quote=“dave96”]On a slight aside I have tried a few times to get the LayerEffects demo working but it just hits endless amounts of assertions on OSX (10.7.4, Xcode 4.4.1). I think the problem is that Image’s on the Mac always have an alpha channel so it was asserting on either the source or destination image which is created somewhere in the JUCE rendering code. (By the way I did make sure to have USE_CORE_GRAPHICS_RENDERING off.)

Anyway, let me know what you think.[/quote]

I’ve updated the repository to use the latest JUCE, including setCurrentRenderingEngine(). This solves the problem where the CoreGraphics context gets used instead of the software renderer, and doesn’t require any changes to the .jucer file or AppConfig.h. But now there’s a new problem, it seems there is no way to create a juce::Image of type Image::RGB on the Mac, which strikes me as utter nonsense.

I added a case to handle Mac OS destination images with associated alpha channels. The app runs now! The colors are screwed up, RGB is BGR. But it runs.

good job !

First, thanks for the cool effects!

From the demo code, I found the code
//c->setItemEnabled (4, false);
//c->setItemEnabled (8, false);
//c->setItemEnabled (11, false);

//c->setItemEnabled (13, false);
//c->setItemEnabled (14, false);

when I uncomment the code, there’s no change, I can not reproduce that effect as follow image.

Then I wrote a demo self, and also can not reproduce the effect. The codes are as follows

[code]]
Rectangle const b (getLocalBounds ());

g.fillAll (Colours::white);
vf::LayerGraphics lc (g, getLocalBounds ());

LayerGraphics::Options & opt =  lc.getOptions ();


opt.general.groupInteriorEffects = true;
opt.general.opacity = 1;
opt.fill.opacity = 1;

opt.dropShadow.active   = true;
opt.dropShadow.mode     =  BlendMode::modeNormal;
opt.dropShadow.colour   = Colours::black;
opt.dropShadow.angle    = 2*3.14159 * 135 / 360;
opt.dropShadow.distance = 4;
opt.dropShadow.spread   = 0.5;
opt.dropShadow.size     = 8;
opt.dropShadow.knockout = true;

opt.innerShadow.active   = true;
opt.innerShadow.mode     = BlendMode::modeNormal;//vf::normal;
opt.innerShadow.colour   = Colours::yellow;
opt.innerShadow.angle    = 2*3.14159 * 135 / 360;
opt.innerShadow.distance = 4;
opt.innerShadow.choke    = 0.5;
opt.innerShadow.size     = 4;

lc.setGradientFill (ColourGradient (
	Colours::red, b.getX (), b.getY (),
	Colours::yellow, b.getRight (), b.getBottom (),
	false));
lc.setFont (b.getHeight () / 3.f);
lc.drawFittedText ("Layer\nEffects",
	b, Justification::centred, 2);

[/code]

Is the function of the innerShadow canceled?