Last modified 29 August 2003 by jdavis@math.wisc.edu
Inherits from NSObject
SMKDrawingManager provides two unrelated drawing services:
As of Mac OS 10.2, it is possible to mix 2D and 3D drawing, because you can draw into an NSOpenGLView as if it were a normal NSView. The following excerpt shows how the NSOpenGLView could configure itself for this behavior.
long negativeOne = -1;
[[self openGLContext] setValues:&negativeOne forParameter:NSOpenGLCPSurfaceOrder];
[[self window] setOpaque:NO];
[[self window] setAlphaValue:1.0];
All of the NSView drawing takes place above the OpenGL surface. In particular, you will not see OpenGL if all of the NSView's pixels are opaque.
Clients of an SMKDrawingManager typically do not retain it. Instead, the class maintains a current instance, and clients obtain this instance and use it. You create one SMKDrawingManager per view, and make it current in the view's drawRect: method.
+ (id)currentDrawingManager;Returns the current drawing manager (which is nil until makeCurrentDrawingManager is called).
+ (void)clearCurrentDrawingManager;
Releases the current drawing manager, setting it to nil.
- (id)makeCurrentDrawingManager;
Makes the receiver the current drawing manager, retaining it.
SMKDrawingManager formats text using the standard NSTextStorage, NSLayoutManager and NSTextContainer classes. In order for the text to appear with correct line movement direction, the relevant NSView's coordinate system must be flipped; override the isFlipped method to return YES. All of this is very much like NSTextView; one could probably achieve similar results by attaching an NSOpenGLContext to an NSTextView and adjusting the text view's text container.
There are only two text-related methods. The first one formats an attributed string into a rectangular NSTextContainer, storing the string and other information inside the drawing manager. The second method draws the string at a specified location.
- (NSSize)formatAttributedString:(NSAttributedString *)attributedString withMaxTextSize:(NSSize)maxTextSize;Formats the string into a rectangular region of the specified size. The size of the rectangle that was actually used is returned.
- (id)drawAttributedStringAtPoint:(NSPoint)point;
Draws the stored string at the specified location in the focused view.
Objects that want to use sorted drawing must conform to the SMKManagedDrawing protocol. As the scene draws, they add themselves to the SMKDrawingManager's object list instead of drawing immediately.
- (id)addManagedDrawer:(id <SMKManagedDrawing>)managedDrawer;Adds the drawer to the receiver's list of objects, if it is not already in the list.
Once all of the objects have been added, the following method causes the drawing manager to draw them, from the most distant to the nearest.
- (id)draw;Draws the registered objects from back to front, by sending each one a drawManagedDrawer message.
SMKDrawingManager does not have a select method, but the next method is something similar. It tests the drawing objects, from front to back, and stops when it finds one containing the indicated point. Typically only 2D objects will be returned by this method, as 3D selection is handled by other means.
- (id)findPoint:(NSPoint)point;Returns the frontmost drawing object that contains the indicated point, or nil if none does.
Drawing in NSView is independent of drawing in OpenGL. If you are mixing the two, then you must clear the NSView when drawing each frame. Instead of clearing the entire NSView, you would prefer to clear just those parts that were drawn in the previous frame. In order to track which parts are drawn, SMKDrawingManager maintains a rectangle. As the various 2D objects draw, they should add their rectangles to the drawing manager's. (3D objects should ignore this feature.) Then, before the next frame is drawn, you can query the drawing manager for its rectangle and erase it.
- (id)absorbRectangle:(NSRect)rectangle;Replaces the receiver's rectangle with its union with the indicated rectangle.
Returns the drawing manager's current rectangle.
The following method resets the drawing manager to its initial state. You will probably call this once per frame, after erasing the old rectangle and before new objects start registering themselves with the drawing manager.
- (id)reset;Empties the list of objects and the rectangle. That is, the rectangle becomes {{0.0, 0.0}, {0.0, 0.0}}.
In summary, a typical drawing loop involving sorted drawing goes like this: