Quickest Drawing Method
-
I'm writing an app which will constantly write an image to the
screen. I would like to know the quickest way to draw an image to the
screen (the image needs to be composed first).
Currently I have a borderless window the size of the screen with
clear background, and I set the window background to an image.
I would like it to be an animation, like the Dock resizing; how is
the Dock drawn without a window, and how can I accomplish this?
Cheers
Matt -
This is not a real answer, as the topic doesn't have an easy one (out
of the usual 'it depends'), just a couple of details that can help you
frame the issue.> I'm writing an app which will constantly write an image to the screen.If that's an option for you (i.e. you feel comfortable with it), I'd
> I would like to know the quickest way to draw an image to the screen
> (the image needs to be composed first).
definitely use OpenGL calls: it's quite well integrated with Cocoa
(that I assume it's a requirement, as you're posting to this list),
you have a lot of options for compositing, and a lot of control on
getting things on the screen as fast as possible.> I would like it to be an animation, like the Dock resizing; how is the Dock drawn withoutThere are far more windows on the screen than a user can perceive: try
> a window, and how can I accomplish this?
the Quartz Debug's 'Show Window List' command to see what I mean. And,
yes, the Dock has its windows (and quite a lot of them) too.
HTH
Paolo -
> If that's an option for you (i.e. you feel comfortable with it), I'd
> definitely use OpenGL calls: it's quite well integrated with Cocoa
> (that I assume it's a requirement, as you're posting to this list),
> you have a lot of options for compositing, and a lot of control on
> getting things on the screen as fast as possible.
My current situation is that I have a custom NSWindow with a single
custom view in it. I do my drawing in the view's drawRect function.
The drawing consists of:
- stretching a couple of images to size and drawing them
- applying a mask image (I think using a NSBezierPath to make the
mask image would be quicker than using a black and transparent PNG
file).
This all happens when I call setFrame for the custom window. Is
OpenGL still viable for an odd-shaped image (not rectangular; with
transparencies)? Or by using Quartz and CG* functions is that the
same as OpenGL?> There are far more windows on the screen than a user can perceive: try
> the Quartz Debug's 'Show Window List' command to see what I mean. And,
> yes, the Dock has its windows (and quite a lot of them) too.
Yeah I checked it out. There's a window for each icon plus more! Crazy.
Right now I have a "scheduledTimerWithTimeInterval:0.1" that calls a
function that just updates the custom window's size; this is quite
draining on the resources as well as jumpy. What can I do to get this
resize function called a lot, but without killing the system? Maybe a
run loop callback?
Cheers -
On 22.07.2007, at 14:18, spiderlama wrote:> - stretching a couple of images to size and drawing them
Can you do this beforehand, perhaps? Or composite the images into
each other, and thus only scale the final image once? There are
numerous ways to optimize stuff like that in general. Are you
cacheing your images, or recreating each time? And what are you
actually using this for? Animations? A status display? Graphing? What?> - applying a mask image (I think using a NSBezierPath to make the
> mask image would be quicker than using a black and transparent PNG
> file).
You'd have to profile that. Are you using CoreGraphics for the mask
image? CG has built-in masking, but last I checked this wasn't
exposed through NSImage or NSGraphicsContext. Also, it helps if you
only copy and redraw those rects that actually need to be drawn. E.g.
not drawing something is always faster than clipping it out.
And again, depending on what gets masked and what's doesn't you
could probably improve performance a lot by only applying the mask on
those parts that actually need it. It also depends on what commands
you actually use to apply the mask. Can you maybe just draw using an
alpha channel from the start instead of masking?> This all happens when I call setFrame for the custom window. Is
> OpenGL still viable for an odd-shaped image (not rectangular; with
> transparencies)? Or by using Quartz and CG* functions is that the
> same as OpenGL?
I think you'd have to do a lot of the initial drawing and masking
in Quartz, (CG or NSImage), but yes, OpenGL supports transparency and
compositing, so it'd be easy to do the scaling and drawing on top of
each other in OpenGL.> Yeah I checked it out. There's a window for each icon plus more!
> Crazy.
AFAIK each window is essentially backed by an OpenGL quad, at least
when running Quartz Etreme. That's why you can drag them so quickly,
and why drawing into one window behind another (and even into
transparent windows) is fairly fast.> Right now I have a "scheduledTimerWithTimeInterval:0.1" that calls
> a function that just updates the custom window's size;
What?! Why? What for? Unless you're doing animation, you shouldn't
need to use a timer to react to resizing. There are messages and
notifications sent whenever a window moves or resizes, or you can
make one window a subwindow of another to have them move together.
Those will generally cause your view's drawRect: method to be called
the next time it's needed (and whether it's needed is determined by
calls to setNeedsDisplay:, or even better setNeedsDisplayInRect:.> this is quite draining on the resources as well as jumpy. What can
> I do to get this resize function called a lot, but without killing
> the system? Maybe a run loop callback?
What are you actually trying to do? So far, this sounds like you're
going about things all wrong, and that's why you're getting bad
performance.
Cheers,
-- M. Uli Kusterer
http://www.zathras.de -
What I am attempting is to make the Leopard Dock (in Tiger) by first
hiding the Dock's background and drawing the new image behind it. I
am using the Accessibility framework to get the Dock's position, size
and orientation so this is why I need it to constantly update (as I
don't know when the Dock will change).
On 22/07/2007, at 11:50 PM, Uli Kusterer wrote:> On 22.07.2007, at 14:18, spiderlama wrote:
>> - stretching a couple of images to size and drawing them
>
> Can you do this beforehand, perhaps? Or composite the images into
> each other, and thus only scale the final image once? There are
> numerous ways to optimize stuff like that in general. Are you
> cacheing your images, or recreating each time? And what are you
> actually using this for? Animations? A status display? Graphing? What?
Two images are dynamically taken from the system, another is an image
with alpha channel, and another made using a multiple of a smaller
image. All of these depend on the size of the Dock, so no pre-composing.>> - applying a mask image (I think using a NSBezierPath to make the
>> mask image would be quicker than using a black and transparent PNG
>> file).
>
> You'd have to profile that. Are you using CoreGraphics for the
> mask image? CG has built-in masking, but last I checked this wasn't
> exposed through NSImage or NSGraphicsContext. Also, it helps if you
> only copy and redraw those rects that actually need to be drawn.
> E.g. not drawing something is always faster than clipping it out.
Not much masking is happening, the bare minimum is used. I use
[NSImage drawInRect...] with operation NSCompositeDestinationIn to
draw the mask (alpha image). I don't know if this is CG or what (as I
am new to this).> And again, depending on what gets masked and what's doesn't you
> could probably improve performance a lot by only applying the mask
> on those parts that actually need it. It also depends on what
> commands you actually use to apply the mask. Can you maybe just
> draw using an alpha channel from the start instead of masking?
>
>> This all happens when I call setFrame for the custom window. Is
>> OpenGL still viable for an odd-shaped image (not rectangular; with
>> transparencies)? Or by using Quartz and CG* functions is that the
>> same as OpenGL?
>
> I think you'd have to do a lot of the initial drawing and masking
> in Quartz, (CG or NSImage), but yes, OpenGL supports transparency
> and compositing, so it'd be easy to do the scaling and drawing on
> top of each other in OpenGL.
>
>> Yeah I checked it out. There's a window for each icon plus more!
>> Crazy.
>
> AFAIK each window is essentially backed by an OpenGL quad, at
> least when running Quartz Etreme. That's why you can drag them so
> quickly, and why drawing into one window behind another (and even
> into transparent windows) is fairly fast.
So is it feasible to copy this methodology? I want (need) lightning
fast resizing of the window (and therefore drawing of the image).>> Right now I have a "scheduledTimerWithTimeInterval:0.1" that calls
>> a function that just updates the custom window's size;
>
> What?! Why? What for? Unless you're doing animation, you shouldn't
> need to use a timer to react to resizing. There are messages and
> notifications sent whenever a window moves or resizes, or you can
> make one window a subwindow of another to have them move together.
> Those will generally cause your view's drawRect: method to be
> called the next time it's needed (and whether it's needed is
> determined by calls to setNeedsDisplay:, or even better
> setNeedsDisplayInRect:.
I know this sucks, but as the nature of the program is to follow Dock
size and I don't know of any callbacks that I can use.>> this is quite draining on the resources as well as jumpy. What can
>> I do to get this resize function called a lot, but without killing
>> the system? Maybe a run loop callback?
>
> What are you actually trying to do? So far, this sounds like
> you're going about things all wrong, and that's why you're getting
> bad performance.
Sorry, but I am trying to keep my project pretty need-to-know, to
deter the real programmers from stealing my idea!
Cheers -
Spider,
Instead of using images which you composite together and draw every
time I would suggest using a NSBezierPath as a clipping path and
filling it with a semi-transparent color for the dock background or,
whatever you want. That should be faster than compositing images and
drawing them, it will certainly be more memory efficient. Not to
mention being much more simple.
Good luck!
Peace, Alan
--
// Quotes from Alan Smith -------------------------
"You don't forget, you just don't remember."
"Maturity resides in the mind."
"Silence is the Universe's greatest gift."
"When the World realizes that personal beliefs are not something to
argue or fight over, it shall evolve." -
On 22.07.2007, at 16:08, spiderlama wrote:> What I am attempting is to make the Leopard Dock (in Tiger) by
> first hiding the Dock's background and drawing the new image behind
> it. I am using the Accessibility framework to get the Dock's
> position, size and orientation so this is why I need it to
> constantly update (as I don't know when the Dock will change).
Well, you don't need to constantly redraw, however. Just keep
around the old rect and size, and only when it changes, redraw. I
think that's your main issue. Only draw when something actually
changes. The OS caches each window in a buffer, so you don't
generally have to redraw when the dock changes, unless it actually
changes in a way that makes you need to change your drawings.>> Can you do this beforehand, perhaps? Or composite the images into
>> each other, and thus only scale the final image once? There are
>> numerous ways to optimize stuff like that in general. Are you
>> cacheing your images, or recreating each time? And what are you
>> actually using this for? Animations? A status display? Graphing?
>> What?
>
> Two images are dynamically taken from the system, another is an
> image with alpha channel, and another made using a multiple of a
> smaller image. All of these depend on the size of the Dock, so no
> pre-composing.
None of these should take very long to draw, if you do it
correctly. You *can* pre-scale all of them, though, and only recreate
the scaled versions from the larger versions when the size actually
changes. The less pixels in need of being scaled, the faster your
drawing will be. But as I said above, I doubt that's your problem.> Not much masking is happening, the bare minimum is used. I use
> [NSImage drawInRect...] with operation NSCompositeDestinationIn to
> draw the mask (alpha image). I don't know if this is CG or what (as
> I am new to this).
I think another compositing operation might be a little faster. I
think using a mask on the actual images while drawing should be
faster that using a compositing mode here. But even without that I
can't see why you would need it to draw faster.> So is it feasible to copy this methodology? I want (need) lightning
> fast resizing of the window (and therefore drawing of the image).
You must be doing something else wrong. Have you timed your code in
Shark? I would be very surprised if the window resized too slowly.
Keep in mind that each scrollbar is made up of several images, some
of them drawn repeating, and they resize fast enough while dragging
and resizing movies.> I know this sucks, but as the nature of the program is to follow
> Dock size and I don't know of any callbacks that I can use.
As I said, resize only when needed.> Sorry, but I am trying to keep my project pretty need-to-know, to
> deter the real programmers from stealing my idea!
Thanks for believing in our honesty this much, I guess ...? You
think nobody before you had the idea of copying the Leopard Dock?
Gee, we must not only be dishonest, but stupid, too.
Cheers,
-- M. Uli Kusterer
http://www.zathras.de -
Ok here's my updated drawing code. I'm not able to test it in shark
right now because I'm having trouble loading the CGImageRef's. After
pouring over Apple's Quartz drawing guide, I think it can't get any
faster...
- (void)drawRect:(NSRect)rect {
float takeIn = rect.size.height * 3/4; // amount to go in at edges
CGContextRef myContext = [[NSGraphicsContext currentContext]
graphicsPort]; // obtain graphics context for this view
CGContextClearRect(myContext, *(CGRect*)&rect); // clear
// create clipping path
CGContextBeginPath(myContext); // begin path
CGContextMoveToPoint(myContext, 0, 0); // move to start
CGContextAddLineToPoint(myContext, takeIn, rect.size.height); //
left edge
CGContextAddLineToPoint(myContext, rect.size.width - takeIn,
rect.size.height); // right edge
CGContextAddLineToPoint(myContext, rect.size.width, 0); // bottom
right corner
CGContextClosePath(myContext); // close shape
CGContextClip(myContext); // clip to path
CGContextDrawImage(myContext, *(CGRect*)&rect, scurve); // scurve
NSRect frontlineRect;
frontlineRect = NSMakeRect(0, 0, rect.size.width, 2); // we know the
height is 2
CGContextDrawImage(myContext, *(CGRect*)&frontlineRect,
frontline); // frontline
}
And it gets called like this:
- (void)applicationDidFinishLaunching:(NSNotification*)theNotification {
...
[NSTimer scheduledTimerWithTimeInterval:0.1 target:self
selector:@selector(resize) userInfo:nil repeats:YES];
}
- (void)resize {
[window setFrame:rect display:YES animate:NO]; // window contains
our view subclass
}
I wish there was a better way than using NSTimer.
Cheers
Matt -
On 25.07.2007, at 02:33, spiderlama wrote:> - (void)applicationDidFinishLaunching:(NSNotification*)
> theNotification {
> ...
> [NSTimer scheduledTimerWithTimeInterval:0.1 target:self
> selector:@selector(resize) userInfo:nil repeats:YES];
> }
>
> - (void)resize {
> [window setFrame:rect display:YES animate:NO]; // window contains
> our view subclass
> }
I hope you're doing this conditionally? There's no reason to change
the window's frame rect repeatedly, not to mention to a value that is
probably the same rect each time.
What you should do at the least is
-(void) resize: (NSTimer*)myTimer
{
NSRect currWinRect = [window frame];
if( currWinRect.origin.x != rect.origin.x || currWinRect.origin.y !=
rect.origin.y
|| currWinRect.size.width != rect.size.width ||
currWinRect.size.height != rect.size.height )
{
[window setFrame:rect display:YES animate:NO];
}
}
Also, I don't see why you would want to do this in a timer. You
must have some place where you fill out the "rect" instance variable
with the dock's current rect. So, what you should do is resize the
window from there, and *only* when its size has changed.
What your code is doing right now is needlessly burning cycles by
telling the window to constantly recreate and re-render its whole
back buffer, even when nothing is happening. Why?
Cheers,
-- M. Uli Kusterer
http://www.zathras.de -
On 25/07/2007, at 6:53 PM, Uli Kusterer wrote:> I hope you're doing this conditionally? There's no reason to change
> the window's frame rect repeatedly, not to mention to a value that
> is probably the same rect each time.
I've checked this out. It looks like if I call setFrame on a window,
and the frame is the same as the current frame, nothing happens.
Therefore I am only redrawing when the Dock moves. The activity
monitor shows the process at 0% when the Dock doesn't move. I know
this is similar to a spin lock, but I can't think of any other method.> Also, I don't see why you would want to do this in a timer. You
> must have some place where you fill out the "rect" instance
> variable with the dock's current rect. So, what you should do is
> resize the window from there, and *only* when its size has changed.
For sake of modularity, I have a function that returns the size of
the dock: (NSRect)getDockRect. And remembering resize:
- (void)resize {
static NSRect rect;
rect = [self getDockRect];
[window setFrame:rect
display:YES
animate:NO];
if (rect.size.width == 0) // NSZeroRect
dock = connectToDock();
}> What your code is doing right now is needlessly burning cycles by
> telling the window to constantly recreate and re-render its whole
> back buffer, even when nothing is happening. Why?
I'm pretty sure it doesn't re-render. I checked this with Quartz Debug.
Is there a callback I can place into the run loop?
AND... how can I find out when the application closed, so I can
release some CGImageRef's?
Cheers,
Matt -
On Jul 25, 2007, at 2:33 AM, spiderlama wrote:> ...I think it can't get any faster...
it can!
i was struggling with a similair performance issue,
but after some experiments i've come to very promising results;
my approach at this point is;
- create a tiny bitmap (CGBitmapContext) that containst all elements
needed to draw the 'big image'
- from that image, create tiles (corners, borders body etc..) and
cache those as CGLayers
the docs teach us that those are actually cached on the graphics-card
where approreate/needed/possible..
- in the drawrect:-routine, check what needs to be drawn, and draw
only that.
right now i'm just using NSViews' needsToDrawRect: to check for only
9 areas;
the corners (4), borders (4) and the body/fill.
and then i simply draw (if/as needed)
the corner-tiles on a 1:1 scale,
the border-tiles streched to fill whatever area needs to be filled,
and same for the body.
i guess this could be further improved using NSViews'
getRectsBeingDrawn:count:
but this is already blazing fast. i'm happy :)
i suspect that these CGLayers actually did the trick..
i didn't profile with shark, but my home-made fps-counter showed an
improvement of around 300%,
and memory consumption is not even worth mentioning anymore...
On Jul 22, 2007, at 4:52 PM, Alan Smith wrote:> Spider,
>
> Instead of using images which you composite together and draw every
> time I would suggest using a NSBezierPath as a clipping path and
> filling it with a semi-transparent color for the dock background or,
> whatever you want. That should be faster than compositing images and
> drawing them, it will certainly be more memory efficient. Not to
> mention being much more simple.
i might be wrong, please tell me if i am (i'm not exactly an expert..),
but i find it a very strange idea that 'rendering' vectors (into
bitmaps),
and then using those for compositing,
would be faster than just copying exisiting bitmap-data around.
especially when that bitmap data can be cached in hardware,
and even more when this compositing, and btw. also scaling can all be
done on the GPU.
i don't believe NSBezierpaths can benefit from hardware acceleration..
â¬.02
.a -
sorry, forgot the secret (no, it's not a leapard Dock..)
below;
.a
On Jul 27, 2007, at 3:38 AM, arri wrote:> On Jul 25, 2007, at 2:33 AM, spiderlama wrote:
>> ...I think it can't get any faster...
>
> it can!
>
> i was struggling with a similair performance issue,
> but after some experiments i've come to very promising results;
>
> my approach at this point is;
>
> - create a tiny bitmap (CGBitmapContext) that containst all
> elements needed to draw the 'big image'
>
> - from that image, create tiles (corners, borders body etc..) and
> cache those as CGLayers
> the docs teach us that those are actually cached on the graphics-
> card where approreate/needed/possible..
>
> - in the drawrect:-routine, check what needs to be drawn, and draw
> only that.
>
> right now i'm just using NSViews' needsToDrawRect: to check for
> only 9 areas;
> the corners (4), borders (4) and the body/fill.
>
> and then i simply draw (if/as needed)
> the corner-tiles on a 1:1 scale,
> the border-tiles streched to fill whatever area needs to be filled,
> and same for the body.
>
> i guess this could be further improved using NSViews'
> getRectsBeingDrawn:count:
> but this is already blazing fast. i'm happy :)
> i suspect that these CGLayers actually did the trick..
>
> i didn't profile with shark, but my home-made fps-counter showed an
> improvement of around 300%,
> and memory consumption is not even worth mentioning anymore...
>
>
>
> On Jul 22, 2007, at 4:52 PM, Alan Smith wrote:
>> Spider,
>>
>> Instead of using images which you composite together and draw every
>> time I would suggest using a NSBezierPath as a clipping path and
>> filling it with a semi-transparent color for the dock background or,
>> whatever you want. That should be faster than compositing images and
>> drawing them, it will certainly be more memory efficient. Not to
>> mention being much more simple.
>
>
> i might be wrong, please tell me if i am (i'm not exactly an
> expert..),
> but i find it a very strange idea that 'rendering' vectors (into
> bitmaps),
> and then using those for compositing,
> would be faster than just copying exisiting bitmap-data around.
> especially when that bitmap data can be cached in hardware,
> and even more when this compositing, and btw. also scaling can all
> be done on the GPU.
>
> i don't believe NSBezierpaths can benefit from hardware acceleration..
>
>
> â¬.02
> .a_______________________________________________
- (void)drawRect:(NSRect)rect {
if(!didInit) [self createBackgroundImage];
NSRect srect = [self bounds];
CGRect trect; // target rectangle
float vwidth = srect.size.width; // view width
float vheight = srect.size.height; // view hight
CGContextRef context = (CGContextRef)[[NSGraphicsContext
currentContext] graphicsPort];
CGContextSetInterpolationQuality(context,kCGInterpolationNone);
trect = CGRectMake(kTileSize,kTileSize,vwidth-(2*kTileSize),vheight-
(2*kTileSize));
if([self needsToDrawRect: *(NSRect *)&trect ])
CGContextDrawLayerInRect(context,trect,players[4]);
else NSLog(@"%d", 4);
// right edge
trect = CGRectMake(vwidth-kTileSize,kTileSize,kTileSize,vheight-
(2*kTileSize));
if([self needsToDrawRect: *(NSRect *)&trect ])
CGContextDrawLayerInRect(context,trect,players[5]);
else NSLog(@"%d", 5);
// bottom edge
trect = CGRectMake(kTileSize,0,vwidth-(2*kTileSize),kTileSize);
if([self needsToDrawRect: *(NSRect *)&trect ])
CGContextDrawLayerInRect(context,trect,players[7]);
else NSLog(@"%d", 7);
// TOP edge
trect = CGRectMake(kTileSize,vheight-kTileSize,vwidth-
(kTileSize*2),kTileSize);
if([self needsToDrawRect: *(NSRect *)&trect ])
CGContextDrawLayerInRect(context,trect,players[1]);
else NSLog(@"%d", 1);
// left edge
trect = CGRectMake(0,kTileSize,kTileSize,vheight-(2*kTileSize));
if([self needsToDrawRect: *(NSRect *)&trect ])
CGContextDrawLayerInRect(context,trect,players[3]);
else NSLog(@"%d", 3);
// top-right corner
trect = CGRectMake(vwidth-kTileSize,vheight-
kTileSize,kTileSize,kTileSize);
if([self needsToDrawRect: *(NSRect *)&trect ])
CGContextDrawLayerInRect(context,trect,players[2]);
else NSLog(@"%d", 2);
// bottom-right coner
trect = CGRectMake(vwidth-kTileSize,0,kTileSize,kTileSize);
if([self needsToDrawRect: *(NSRect *)&trect ])
CGContextDrawLayerInRect(context,trect,players[8]);
else NSLog(@"%d", 8);
// bottom left
trect = CGRectMake(0,0,kTileSize,kTileSize);
if([self needsToDrawRect: *(NSRect *)&trect ] && first)
CGContextDrawLayerInRect(context,trect,players[6]);
else NSLog(@"%d", 6);
// top right
trect = CGRectMake(0,vheight-kTileSize,kTileSize,kTileSize);
if([self needsToDrawRect: *(NSRect *)&trect ]&&first)
CGContextDrawLayerInRect(context,trect,players[0]);
else NSLog(@"%d", 0);
frc++;
}
- (void)createBackgroundImage {
didInit = YES;
int i = 0;
float radius = 7;
NSRect rect = NSMakeRect( 0, 0, (3*kTileSize), (3*kTileSize) );
NSRect irect = NSMakeRect( 5, 6, (3*kTileSize)-10,
(3*kTileSize)-7 );
float rx = irect.origin.x;
float ry = irect.origin.y;
float rw = irect.size.width;
float rh = irect.size.height;
float cwidth = rect.size.width;
float cheight = rect.size.height;
const int bytesPerPixel = 4;
const int rowBytes = cwidth * bytesPerPixel;
void* imageData = malloc( (rowBytes * cheight) );
CGColorSpaceRef cspace = CGColorSpaceCreateDeviceRGB();
CGBitmapInfo bmInfo = kCGBitmapByteOrder32Host |
kCGImageAlphaPremultipliedFirst;
CGContextRef context = CGBitmapContextCreate(imageData,
cwidth,
cheight,
8, // bits per component
rowBytes,
cspace,
bmInfo );
CGContextClearRect( context, CGRectMake
(0,0,rect.size.width,rect.size.height) );
assert( CGContextIsPathEmpty(context) );
CGContextSetShouldAntialias( context,1);
// path
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddArc(path, NULL, rx+radius, ry+radius, radius, radians(180),
radians(270),0);
CGPathAddArc(path, NULL, rw+rx-radius, ry+radius, radius, radians
(270), radians(360),0);
CGPathAddLineToPoint(path,NULL,rw+rx,rh+ry);
CGPathAddLineToPoint(path,NULL,rx,rh+ry);
CGPathCloseSubpath(path);
// fill with dropshadow
float clr[4] = {0.0,0.0,0.0,0.5};
CGColorRef shadowColor = CGColorCreate(cspace,clr);
CGContextSetShadowWithColor(context,CGSizeMake(0.0,-2.0),
5.0,shadowColor);
CGContextAddPath(context,path);
CGContextSetRGBFillColor(context,kJAWhite,kJAWhite,kJAWhite,kJAAlpha);
CGContextFillPath(context);
// clear fill area
CGContextAddPath(context,path);
CGContextClip(context);
CGContextClearRect(context,CGRectMake
(0,0,rect.size.width,rect.size.height));
// fill again without shadow
CGContextSetShadowWithColor(context,CGSizeZero,0,NULL);
CGContextAddPath(context,path);
CGContextSetRGBFillColor
(context,kJAWhite,kJAWhite,kJAWhite,kJAAlpha-.1);
CGContextFillPath(context);
// thin outline
CGContextSetLineWidth(context, 6.0);
CGContextSetShadowWithColor(context,CGSizeMake(0,0),1,shadowColor);
CGContextAddPath(context,path);
CGContextSetRGBStrokeColor(context,1,1,1,1);
CGContextStrokePath(context);
// resize corner
float stx, enx, len;
len = (rw/5);
if (len>30.) len=30.;
stx = rx + (rw/2.) - (len/2.);
enx = rx + (rw/2.) + (len/2.);
CGContextSetShadowWithColor(context,CGSizeMake(0,0),2,shadowColor);
CGContextSetRGBStrokeColor(context,1.,1.,1.,.99);
CGContextSetLineWidth(context, 6.);
CGContextMoveToPoint(context,rx+0,ry+radius+5);
CGContextAddArc(context, rx+radius+1,ry+radius+1,radius+1,radians
(180),radians(270),0);
CGContextAddLineToPoint(context,rx+radius+5,ry+0);
CGContextStrokePath(context);
CGColorRelease(shadowColor);
CGContextFlush(context);
CGImageRef smallImage = CGBitmapContextCreateImage(context);
CGContextRelease(context);
free(imageData);
// create CGLayers
CGRect srcR;
CGImageRef tile;
CGRect tileR = CGRectMake(0,0,kTileSize,kTileSize);
CGContextRef lcontext;
for (i=0; i<9; i++) {
int ox = (i%3) * kTileSize;
int oy = (i/3) * kTileSize;
srcR = CGRectMake(ox,oy,kTileSize,kTileSize);
tile = CGImageCreateWithImageInRect(smallImage,srcR);
players[i] = CGLayerCreateWithContext(context,CGSizeMake
(kTileSize,kTileSize),NULL);
lcontext = CGLayerGetContext(players[i]);
CGContextDrawImage(lcontext,tileR,tile);
CGContextFlush(lcontext);
}
CGImageRelease(smallImage);
} -
On 27/07/2007, at 11:38 AM, arri wrote:> my approach at this point is;
>
> - create a tiny bitmap (CGBitmapContext) that containst all
> elements needed to draw the 'big image'
>
> - from that image, create tiles (corners, borders body etc..) and
> cache those as CGLayers
> the docs teach us that those are actually cached on the graphics-
> card where approreate/needed/possible..
>
> - in the drawrect:-routine, check what needs to be drawn, and draw
> only that.
So if I was to apply this methodology to my app, I should:
- create a CGBitmapContext (how do I make it small/contain all the
images I want to draw)
- create a CGLayer for each of the images I need to draw
- in drawRect make the path and then draw the images as needed.
I don't know if this method would increase the drawing speed. If a
small part of my window needs drawing, then every image has to be
applied again (as every image is applied to the full size of the
window). Meaning that no steps can be skipped for different drawing
rectangles. Right now I:
- create CGImages of the images
- in drawRect make the path and then draw the images.
I think the "lagginess" comes from the fact that I am continually
changing the window's size.
Cheers
Matt -
hoi matt,
maybe i don't understand what exactly you are drawing..
in my case, the 'tiny bitmap that containst all elements' looks
something like this;(with dividing lines to illustrate the 'tiles')> If a small part of my window needs drawing, then every image has to
> be applied again
maybe you are compositing several layers with large images.
in that case using CGLayers can still speed-up drawing, as long as
you re-use them (see docs).
so as long as the images (and paths and masks..) you use to composit
are the same, use CGLayers.
.a
On Jul 28, 2007, at 9:52 AM, spiderlama wrote:>
> On 27/07/2007, at 11:38 AM, arri wrote:
>> my approach at this point is;
>>
>> - create a tiny bitmap (CGBitmapContext) that containst all
>> elements needed to draw the 'big image'
>>
>> - from that image, create tiles (corners, borders body etc..) and
>> cache those as CGLayers
>> the docs teach us that those are actually cached on the graphics-
>> card where approreate/needed/possible..
>>
>> - in the drawrect:-routine, check what needs to be drawn, and draw
>> only that.
>
> So if I was to apply this methodology to my app, I should:
>
> - create a CGBitmapContext (how do I make it small/contain all the
> images I want to draw)
> - create a CGLayer for each of the images I need to draw
> - in drawRect make the path and then draw the images as needed.
>
> I don't know if this method would increase the drawing speed. If a
> small part of my window needs drawing, then every image has to be
> applied again (as every image is applied to the full size of the
> window). Meaning that no steps can be skipped for different drawing
> rectangles. Right now I:
>
> - create CGImages of the images
> - in drawRect make the path and then draw the images.
>
> I think the "lagginess" comes from the fact that I am continually
> changing the window's size.
>
> Cheers
> Matt


