So, I was messing around with a Cocoa app I created to test out some imaging code I had created. The point of this code was to deliver a really large image in smaller tiles and the Cocoa app would take those images and stitch them together into one large image. Now, the code I wrote delivered these small tiles quickly, and the point of the code was to handle the tiles, not to deliver one big image, so I used NSImage to put these tiles together.
Now… that didn’t work out too well. After many attempts, debugging and coding permutations, I realized that NSImage might not have been the best choice for drawing for one reason: it’s not that fast.
So, on to the web. After some digging around, and some patient reading, I found that CGImage would be the better way to go. Great! Now I have to admit, all of the projects I have done in the past were with whole images, not diced up ones. So, looking at the Cocoa API, I wondered, how do I draw just one Rect.
Now, before I go any further, I would like to point out something. I don’t write about anything unless I had a hard time finding information about something and I couldn’t find it on the web. And to my surprise, I really couldn’t find that much information about tiling images.
Okay, so, back to my problem. I implemented tiled drawing, and it wasn’t too hard to do, but then I started having some problems. My original code was expecting only one tile at a time to be drawn in. However, there were sections of the image that were not being drawn.
My - (void)drawRect:(NSRect)inrect
method was being called every time, or at least from what I could see, but, tiles were still missing.
So what gives?
Well, by accident I found out that you can get more than one tile at a time. Cocoa tries to make the drawing as efficient as possible if it detects that it can draw two or more tiles at the same time. So, I also had to use:
- (void)getRectsBeingDrawn:(const NSRect **)rects count:(NSInteger *)count
This method tells me how many tiles were given to me, so instead of only drawing one tile, I was now able to draw many tiles:
- (void)drawRect:(NSRect)inrect
{
/* Prevent anyone else from trying to update the view by locking our mutex*/
[self lockMyView];
/* Get the array of rects Cocoa wants us to draw */
const NSRect* arrayOfRects;
NSInteger countOfTiles;
[self getRectsBeingDrawn:&arrayOfRects tileCount:&countOfTiles];
if (countOfTiles==1)
{
/* We only have one tile to draw... easy! */
[self drawMyTile:(*arrayOfRects)];
}
else
{
/* We have more than one tile to draw. */
for (int i = 0; i <= countOfTiles; i++ )
{
NSRect currentRect;
currentRect.origin.x = arrayOfRects[i].origin.x;
currentRect.origin.y = arrayOfRects[i].origin.y;
currentRect.size.width = arrayOfRects[i].size.width;
currentRect.size.height = arrayOfRects[i].size.height;
[self drawMyTile:currentRect];
}
}
/* It is now safe to allow view updates */
[self unlockMyView];
}
Alright! Another problem solved!