Creating pattern on-the-fly? - cocoa

Is there a way to create a colored fill pattern dynamically in Cocoa?
In particular instead of using a fixed pattern from an image file via
NSColor *fillPattern = [NSColor colorWithPatternImage:patternImage];
I'd like to create a pattern by dynamically choosing the appropriate colors at runtime.
Background is highlighting a colored object by rendering stripes or squares in the ''opposite'' color on top of it - whatever opposite might mean in this context, but that's a different story..
Being applied to potentially hundreds of objects in a drawing app it needs to be a rather fast method so I suppose just swapping colors in patternImage won't be good enough.
(It did work just fine back in QuickDraw..!)

Why not just draw to an in-memory image and use that for your pattern?
NSImage* patternImage = [[NSImage alloc] initWithSize:someSize];
[patternImage lockFocus];
//draw your pattern
[patternImage unlockFocus];
NSColor* patternColor = [NSColor colorWithPatternImage:patternImage];
//do something with the pattern color
//remember to release patternImage if you're not using ARC
Performance-wise, you generally should be looking at optimising drawing by paying attention to the rect passed in to drawRect: and making sure you only draw what is necessary. If you do that then I can't see the pattern drawing performance being a major problem.

Background is highlighting a colored object by rendering stripes or squares in the ''opposite'' color on top of it - whatever opposite might mean in this context, but that's a different story..
You'll want to use one of Quartz's blend modes (most of them are present in Photoshop, Pixelmator, and Opacity, so you can experiment in one of those apps to determine which one you need).
You should then be able to fill with a static image—or a dynamic pattern, if it's really necessary—and Quartz will blend it in appropriately.
There's no way to do this in AppKit alone; you'll need to get a CGContext from the current NSGraphicsContext and do it in Quartz.

Related

Xcode GLKit printing Text on GLKView without using UIImages

I have an app, its a small game using opengles with GLKit.
No im wondering how it works when i want to draw text on
my screen (if it is possible).
How can i do it?
i draw all of my game objects using images (wrapped in some kind
of sprite). its possible to scale, to move, and to rotate.
everything works fine.
but finding out how it works to print text on that glkview
gets me deep inside of problems ^^
I dont want to use uiimages cause i also dont know how
to present uiimages on a glkview.
There are a number of ways to do what you want:
1) Have an image with all the text glyphs you need in it. For example, if your application is in English, you'd have the 26 uppercase and 26 lowercase letters in the image. Upload that texture to the GPU and use the proper texture coordinates or glSubTexImage2d() to pull out the glyphs you need. (It's not clear to me if this is what you meant by not wanting a UIImage. It doesn't have to be a UIImage, though that's probably easiest.)
2) Every time you need to display text, draw it on the CPU on the fly, and upload the entire word, phrase, or sentence as a texture. You could create a CGBitmapContext and use Core Graphics to draw text to it. Then upload it using glTexImage2D().
3) Get the individual glyphs out of the fonts and draw directly using the bezier curves that make up the glyphs. This allows for 3D extrusion, too. However, this option is the most time consuming to code and probably least performant. It also involves dealing with the many small problems that fonts have (like degenerate segments, and incorrect winding orders). IF you want to go down this path, I think maybe Core Text can help.
There are at least two clean ways to do this, depending on your requirements.
While documentation advises against compositing over a CAEAGLLayer (GLKView), it works quite well, at least in recent iOS versions, when transparent content is layered on top of the CAEAGLLayer. For example, try dropping a UITextView, with opaque set to false and a clear background color, on top of a GLKView in your Storyboard in Interface Builder in the Apple GLKit template or your app. In my test on an iPhone 5, frame rendering time remained around 1ms, even while scrolling in the text view. If your text needs are static, or you don't want the user to interact with the text, use CATextLayer as a child layer of your EAGLLayer instead of a view.
The second approach is to render the text into a texture. You can then composite the text onto your view by disabling the depth buffer and rendering the texture on a full screen rectangle. Look at UIGraphicsBeginImageContextWithOptions to see how to render to an offscreen image with Quartz. UIGraphicsGetImageFromCurrentImageContext allows you to retrieve the UIImage to use as a texture.

Convert NSGradient to NSColor

Is it possible to convert an NSGradient to an NSColor
- (void) viewWillDraw {
NSGradient *grad = [[NSGradient alloc] initWithStartingColor:[NSColor lightGrayColor] endingColor:[NSColor darkGrayColor]];
[super setBackgroundColor:*gradient*;
}
This is my method, I want to be able to pass the NSGradient in as an NSColor, which obviously i cant, is there any way to convert it to one?
On 10.8, you can create, in the following order:
A block that draws the gradient however you like.
An image that is backed by the block.
A color that repeats the image as a pattern.
In this way, you can create a color that looks like anything, including a gradient.
That said, this may not work correctly with window resizing if you try to have the gradient adapt to the size of the background (by using the rect passed to the block) and the background is of a text view in a scroll view. (When I tried it awhile back, the pattern didn't redraw the block; it simply tiled, which looked weird in at least one dimension.) If either your gradient or your window is fixed in size, then you will not have that problem.
NSGradient is not Convertible to NSColor.
The NSGradient class provides support for drawing gradient fill
colors, also known as shadings in Quartz. This class provides
convenience methods for drawing radial or linear (axial) gradients for
rectangles and NSBezierPath objects.
As you want to set the viewBackground to to an effect (Gradient effect) you need to do as:
[grad drawInRect:<the rect of your view> angle:270]; //angle is upto your requirement,

Cocoa Different text color in the same letter

What i need is a bit difficult to explain. Let's try...
I need to write a text in my app, and that text will gradually change color from left to right.
I think i could say it's a similar effect to what you see in a karaoke screen.
For instance. I draw a text line, in blue color, and gradually, using a timer, the color from left to right changes to red. But i don't want it to change letter by letter, but gradually. That would require that at some moment, the same letter can have a part in red and a part in blue.
I've been reading about core drawing, and maybe it's the solution, but i really don't know how to start. I was thinking about using a background layer and in top of it draw a transparent text (only with border), but i am not very sure how to do it.
any ideas would be appreciated.
You can probably do the job with a CGLayer.
Best of all you should be able to use your existing code to draw the characters (or anything else) in to the CGLayer.
Here's some rough code:
// first, make a CGLayer...
CGLayerRef yourDrawingPad =
CGLayerCreateWithContext(UIGraphicsGetCurrentContext(),etc..
CGContextRef yourRef = CGLayerGetContext(yourDrawingPad);
// now, draw to yourRef .. draw your various typography (or anything)
// use your current drawing code.
// all done drawing, now make an image mask...
UIGraphicsBeginImageContext(CGLayerGetSize(yourDrawingPad));
CGContextRef temp = UIGraphicsGetCurrentContext();
CGContextDrawLayerAtPoint(temp, CGPointZero, yourDrawingPad);
CGImageRef anAlphaMask = CGBitmapContextCreateImage(temp);
UIGraphicsEndImageContext();
You now have a nice mask you can use:
CGContextSaveGState(UIGraphicsGetCurrentContext()) ...
CGContextClipToMask(UIGraphicsGetCurrentContext(), self.frame, anAlphaMask);
So just mask it in to an image of a gradient, or whatever works.
(Conceivably: perhaps you will have to construct a bitmap image offscreen, and then use that as the mask?)
Footnote: Don't forget it is very likely you will have to paint upside down! Fortunately that is simple to deal with. Where it says "now, draw to yourRef" before drawing save your state and add the two lines of code:
CGContextTranslateCTM(refForMask, 0, self.frame.size.height);
CGContextScaleCTM(refForMask, 1.0, -1.0);
Hope it helps
I have an idea of how this could be done, but it is kind of complex. You could create an NSBezierPath and add the glyphs for each character. Then, set that as the clip and draw a NSGradient. Then you would just have to change the offset of the colors in the NSGradient to move the color along.

vs [CIContext drawImage:…]

What is the difference between the last two lines?
CIImage *outputImage = [compositingFilter valueForKey:#"outputImage"];
[[[NSGraphicsContext currentContext] CIContext] drawImage:outputImage atPoint:point fromRect:fromRect];
[outputImage drawAtPoint:point fromRect:fromRect operation:op fraction:delta];
The last one produces a distorted image with a rect that is smaller than [outputImage extent];
The drawImage: line crashes on some occasions.
From the docs on -drawAtPoint:…
The image content is drawn at its current resolution and is not scaled unless the CTM of the current coordinate system itself contains a scaling factor. The image is otherwise positioned and oriented using the current coordinate system.
fromRect should be the entire size of the image if you're wanting the whole thing drawn. Also in many cases flippedness is handled differently between different drawing methods.
Lastly, the docs on -drawImage:… somewhat cryptically only state:
You can call this method to force evaluation of the result after you apply a filter using one of the methods of the CIFilter class, such as apply:, apply:arguments:options:, and apply:k…
Hope this helps.

Cocoa focus ring color animation

I want to use a focus ring animation as an indicator of incorrect data in field. So I'm sending becomeFirstResponder: to field and want focus ring to fade from red to default color.
I'm wrestling with Core Animation but still have not found any way to do it. Is it possible?
I'm not sure if this strategy follows the HIG, its often more common to do something like display a persistent icon indicating a field doesn't validate next to the field, but it shouldn't be too hard to get the effect you're seeking.
It might be easier to use a simple NSAnimation here instead of using Core Animation.
The standard code for drawing a focus ring generally goes something like the following:
[NSGraphicsContext saveGraphicsState];
NSSetFocusRingStyle(NSFocusRingOnly);
[[NSColor clearColor] set];
[[NSBezierPath bezierPathWithRect:focusRect] fill];
[NSGraphicsContext restoreGraphicsState];
This code would be implemented in the drawRect: method in custom subclass of your control.
In order to draw a custom colored focus ring, you'll need to draw the rectangle yourself, and won't be able to benefit from the NSSetFocusRingStyle function. The color would be driven off of the NSAnimation, which would also set the control to repaint itself. Because you're not using Cocoa's facilities to draw the focus ring, you'll also probably need to inset the content of your view so you'll have space to draw the ring.
More information regarding NSAnimations is available in the Animation Programming Guide for Cocoa

Resources