Where can I use drawInRect for strings? - objective-c

I'm having some trouble tracking down the exact usage of drawInRect; I know the syntax, but is it only available inside a UIView or its subclass? What exactly is the "context" required, and how to I create or get it?

The context is like the canvas for core graphics drawing. You can get the context from any UIView by calling UIGraphicsGetCurrentContext() within drawRect:. You can also create your own context anywhere, from which you can create a UIImage or save to a file, etc.
Hope this helps!

Related

Share Textures Between 2 OpenGL Contexts

I have an existing openGL context, using an OpenGL 2.1 core profile. I am able to draw objects/textures/etc no problem. However, now I want to be able to have my application to launch a separate NSWindow, with an NSOpenGLView, that displays part of a texture I drew in the original renderer's view. After some reading, I eventually bumped into the topic of context sharing, which I think may be the route I have to take if I want to pull this off.
My shared openGL context is of type - CGLContextObj, but I don't know what to do with it as my window resides in a different process. I've read the Apple documentation on rendering contexts, but I am unable to apply the concepts they laid out if there's barely any examples for me to go through. Any advice will be really appreciated, thank you in advance.
EDIT:
Perhaps I did not give enough description, my apologies. I subclass my NSOpenGLView, and it's init I do the following:
// *** irrelevant initialization stuff above inside init *** //
// Get pixel format from first context to be used for NSOpenGLView when it's finally initialized later
_pixFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:(void*)_attribs];
// We will create CGPixelFormatObj from our C array of pixel format ttributes
GLint nPix;
CGPixelFormatObj myCgPixObj;
CGLChoosePixelFormat(_attribs, &myCgPixOPbj, &nPix);
// Now that we have the pixel format in CGPixelFormatObj form, create CGLContextObj to be passed in later when we init NSOpenGLView
CGLContextObj newContext;
CGLCreateContext(myCgPixObj, mainRenderingContext, &newContext);
// Create an NSOpenGLContext object here to feed into NSOpenGLView
NSOpenGLContext* _contextForGLView = [[NSOpenGLContext alloc] initWithCGLContextObj:newContext];
[newContext setView:self];
[self setOpenGLContext:newContext];
// We don't need this anymore
CGLDestroyPixelFormat(myCgPixObj);
return self;
I am able to draw objects in this view just fine. But I get a blank white rectangle whenever I try to use the textures created in the main rendering context. I'm a little lost on how to proceed from here, I have never dealt with shared contexts before.
Seems like I got it working, partially at least since I had to force the view to redraw by moving my Window around to actually render the texture from the main context (another problem for another time!). Anyways, here's how I did it:
My main rendering context is supplied by a host application (yes, I'm working on a plugin), and is of type CGLContextObj. I wrap that context in an NSOpenGLContext object via calling initWithCGLContextObj
Next step was to create an NSOpenGLPixelFormat object, initializing it with the pixel format attributes used by the host application's renderer. This step is important as it ensures that the rendering context that will be used in my view will have the same OpenGL core profile, along with other attributes used by the host application.
Then in my subclassed NSOpenGLView, I create a new NSOpenGLContext object, preferably in the prepareOpenGL method, by using initWithFormat:shareContext: for allocation. I used the NSOpenGLPixelFormat and NSOpenGLContext objects created previously to pass as parameters.
Upon assigning the newly created context to my view, I was able to render the textures from the main rendering context.

Xcode (Obj-C) Updating a UIView (NSRect) after the window is already visible to the user

I am fairly new to creating Xcode projects using Objective-C and i'm trying to make a simple 2d graphics program to show me how well my graphing code works before I implement it elsewhere.
I have gotten the drawing of everything right but the problem comes when I want to clear the strokes and stroke new lines. From what I see from when I run the program the view will only display what I have executed once it hits that #end at the end of the implementation. The issue with this is that by the time it hits the #end the code has already been run. and I can't figure out if I need to recall the class in a loop to update the view each time (or where or how to do this, perhaps something in main.m?) or if I need to call a function to update the view before it exits the implementation because right now all the lines are just overwriting each other before the user can see anything.
Here is the interface in my header file (connected to a UIView):
#interface GraphView : NSView
- (void)drawRect:(NSRect)dirtyRect;
#end
Implementation file:
Here is how I am creating my rectangle:
- (void)drawRect:(NSRect)dirtyRect {
[self clearGrid:dirtyRect];
[self drawLines];
}
- (void)clearGrid:(NSRect)theRect {
//Wiping the slate clean
[super drawRect:theRect];
[self.window setBackgroundColor:[NSColor whiteColor]];
...
Here is what I am using to draw my lines:
NSBezierPath* eqLine = [NSBezierPath bezierPath];
[[NSColor greenColor] setStroke];
[eqLine setLineWidth:5.0];
[eqLine moveToPoint:NSMakePoint([self convertToPixels:previousX], [self convertToPixels:previousY])];
[eqLine lineToPoint:NSMakePoint([self convertToPixels:finalX], [self convertToPixels:finalY])];
[eqLine stroke];
I have been searching for the past few days now on how I could solve this but so far it hasn't turned up anything, perhaps i'm just not searching for the right thing. Any information is helpful even if it's just a point to a resource that I can look at. Let me know if any additional information is needed. Thanks!
It's clear that you're a noobie to this, which is not a crime. So there's a lot to address here. Let's take things one at a time.
To answer your basic question, the -drawRect: method is called whenever a view needs to draw its graphic representation, whatever that is. As long as nothing changes that would alter its graphical representation, the -drawRect: method will only be received once.
To inform Cocoa (or CocoaTouch) that the graphic representation has changed, you invalidate all, or a portion of, your view. This can be accomplished in many ways, but the simplest is by setting the needsDisplay property to YES. Once you do that, Cocoa will (at some point in the future) call the -drawRect: method again to modify the graphic representation of your view. Wash, rinse, repeat.
So here's the basic flow:
You create your class and add it to a view. Cocoa draws your view the first time when it appears by sending your class a -drawRect: message.
If you want your view to change, you invalidate a portion of the view (i.e. view.needsDisplay = YES). Then you just sit back and wait. Very soon, Cocoa will send -drawRect: again, your class draws the new and improved image, and it appears on the screen.
Many changes will cause your view to be invalidated, and subsequently redrawn, automatically—say, if it's resized. But unless you make a change that Cocoa knows will require your view to redraw itself, you'll have to invalidate the view yourself.
Now for the nit-picking, which I hope you understand is all an effort to help you understand what's going on and improve your code...
Your subject line says UIView but your code example subclasses NSView so I'm actually not sure if you're writing a macOS or an iOS app. It doesn't matter too much, because at this level the differences are minimal.
Your -drawRect: calls [self clearGrid:..., when then calls [super drawRect:... Don't do this. As a rule, never use super except from within the overloaded method of the same name. In other words, -drawRect: can use [super drawRect:, but no other methods should. It's not "illegal", but it will save you grief in the long run.
Your -clearGrid: method sets the backgroundColor of the window. Don't do this. The window's background color is a property, and your -drawRect: method should only be drawing the graphical representation of your view—nothing more, nothing less.
You're calling [super drawRect: from within a direct subclass of NSView (or UIView). While that's OK, it's unnecessary. Both of these base classes clearly document that their -drawRect: method does nothing, so there's nothing to be gained by calling it. Again, it won't cause any harm, it's just pointless. When your -drawRect: method begins execution, a graphics context has already been set up, cleared, and is ready to draw into. Just start drawing.
#end is not a statement. It does not get "executed". It's just a word that tell the compiler that the source code for your class has come to an end. The stuff that gets executed are the methods, like -drawRect:.
In your #interface section you declared a -drawRect: method. This is superfluous, because the -drawRect: method is already declared in the superclass.

UINavigationBar drawRect Alternative (aka, Need CoreGraphics calls in a category)

I recently discovered that in > iOS5 UINavigationBar does not get its drawRect called. I want to figure out how to draw with Core Graphics in a category.
The end goal I am trying to achieve is eliminating images from my app and have everything drawn at runtime. I am also trying to make this library automatic, so that users don't have to think about using my custom classes.
Is there a way to replace a class with one of your own at runtime? like: replaceClass([UINavigationBar class], [MyCustomBar class]);
Thanks in advance.
Is there a way to replace a class with one of your own at runtime?
In Objective-C this is know as class posing.
Class posing is based on the use of NSObject's poseClass method, which is now deprecated (on 64 bit platforms, including the iPhone).
Alternative approaches have been investigated; you can read about one here, but they do not seem quite to fit the bill.
I found the solution, Instead of messing with draw rect, I just made some methods that draw to a UIImage then set the image as the background view for the elements i am customizing. It makes my custom UI magic again.

Apples ZoomingPDFViewer Example - Object creation

I'm currently working on an App which should display and allow users to zoom a PDF page.
Therefore I was looking on the Apple example ZoomingPDFViewer.
Basically I understand the sample code.
But a few lines are not obvious to me.
Link to the sample code:
http://developer.apple.com/library/ios/#samplecode/ZoomingPDFViewer/Introduction/Intro.html
in PDFView.m:
//Set the layer's class to be CATiledLayer.
+ (Class)layerClass {
return [CATiledLayer class];
}
What does the code above do?
And the second code snippet I don't understand in PDFView.m again:
self = [super initWithFrame:frame];
if (self) {
CATiledLayer *tiledLayer = (CATiledLayer *)[self layer];
...
I know it creates a CATiledLayer object. But how it will be created is not clear to me.
I hope someone could give me a short answer to my question because I don't want to use code which I don't understand.
Thank you!
The TiledPDFView.h class is a subclass of UIView, so you can see what documentation UIView has on that method. According to the docs I see, it looks like:
layerClass - Implement this method only if you want your view to use a different Core Animation layer for its backing store. For example, if you are using OpenGL ES to do your drawing, you would want to override this method and return the CAEAGLLayer class.
So it seems that it is asking the Core Animation system to use a tiled-layer. Further docs from CATiledLayer:
CATiledLayer is a subclass of CALayer providing a way to
asynchronously provide tiles of the layer's content, potentially
cached at multiple levels of detail.
As more data is required by the renderer, the layer's drawLayer:inContext: method is called on one or more background
threads to supply the drawing operations to fill in one tile of data.
The clip bounds and CTM of the drawing context can be used to
determine the bounds and resolution of the tile being requested.
Regions of the layer may be invalidated using the setNeedsDisplayInRect: method however the update will be asynchronous.
While the next display update will most likely not contain the updated
content, a future update will.

Cocoa app gives EXC_BAD_ACCESS on any GL function

It seems that no matter what GL function I call, I get EXC_BAD_ACCESS. However, I'm calling these functions in readFromURL:ofType:error: of an NSDocument subclass, for some offscreen drawing. If I remove that code, and try to use GL later, once everything's loaded, everything works fine. Is this a GL context issue?
I read Apple's GL guide, but in the section about offscreen drawing, it just told me how to use framebuffers. Which I do, but since glGenFramebuffersEXT crashes just like everything else, it's not very helpful.
Is there some sort of context creation I need to perform, and if so, what's the best way to do it?
Yes, OpenGL calls need a context. If you have NSOpenGLView, you need to get its context and make it current:
[[openGLView openGLContext] makeCurrentContext];
// glCalls()
If you're not using NSOpenGLView, you can create NSOpenGLContext youself.