Hi again - you got me going now! ;-)

Occurs to me that there's no need to store more than one buffered image (actually really obvious once it dawned on me). Checking the OpenGL approach, this is what it does also - just one "history" buffered image, which is then drawn into the new image at each update, with a lower opacity such that over time it naturally fades away. This is much more efficient as there are only two bitblits per frame, and a maximum of two images in memory at once and then only briefly, no matter how much "persistence" you dial in or what the frame rate is, etc. It also looks a lot more realistic, so it's a winner all round. Here's my revised view which still uses NSImage, but even with this is working nice and smoothly. I also added a "target" to show how actual blips on the screen could be handled.


@interface GCRadarView : NSView
{
        NSTimer*        mTimer;
        NSTimeInterval  mLastUpdateTime;
        CGFloat         mAngle;
        NSImage*        mHistoryImage;
}


- (void)        drawHistoryBuffer;
- (void)        updateHistoryBuffer;
- (void)        drawContentIntoImage:(NSImage*) theImage;
- (void)        animateWithTimer:(NSTimer*) timer;

- (IBAction)    startSweep:(id) sender;
- (IBAction)    stopSweep:(id) sender;

@end


#define SWEEP_RATE                                      0.5             // 
radians per second


//------------------------------------------------------------------------------------



#import "GCRadarView.h"


@implementation GCRadarView

- (void)                drawHistoryBuffer
{
        // draw the current buffered image to the view

[mHistoryImage drawInRect:[self bounds] fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];
}


- (void)                updateHistoryBuffer
{
        NSImage* newImage = [[NSImage alloc] initWithSize:[self bounds].size];
        
// copy the current history into it at reduced opacity - dial in different opacity values to change the "persistence" // values closer to 1.0 give more persistence, closer to 0 give less. 1.0 gives infinite persistence, so the image never fades.
        
        [newImage lockFocus];
        
        if( mHistoryImage )
[mHistoryImage drawInRect:[self bounds] fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:0.92];
        
        // draw new content
        
        [self drawContentIntoImage:newImage];
        [newImage unlockFocus];
        
        // this is now the history buffer:
        
        [mHistoryImage release];
        mHistoryImage = newImage;
}


- (void)                drawContentIntoImage:(NSImage*) theImage
{
        // draw view content to the image. Image is already focused.
        
        NSTimeInterval  currentTime = [NSDate timeIntervalSinceReferenceDate];
        NSTimeInterval  elapsedTime = currentTime - mLastUpdateTime;
        mLastUpdateTime = currentTime;
        
// sweep rate is 0.5 rad/sec - so how many radians since we last updated?
        
        CGFloat angleIncrement = SWEEP_RATE * elapsedTime;
        mAngle += angleIncrement;
        mAngle = fmod( mAngle, 2 * pi );
        
        // set the transform to this angle rotated around the centre point
        
        NSPoint centre;
        
        centre.x = NSMidX([self bounds]);
        centre.y = NSMidY([self bounds]);
        
        [NSGraphicsContext saveGraphicsState];
        
        NSAffineTransform* transform = [NSAffineTransform transform];
        [transform translateXBy:centre.x yBy:centre.y];
        [transform rotateByRadians:mAngle];
        [transform translateXBy:-centre.x yBy:-centre.y];
        [transform concat];

        // set a shadow to simulate the backscatter glow
        
        NSShadow* shadow = [[NSShadow alloc] init];
[shadow setShadowColor:[NSColor colorWithCalibratedRed:0.4 green:1.0 blue:0.4 alpha:1.0]];
        [shadow setShadowOffset:NSZeroSize];
        [shadow setShadowBlurRadius:8.0];
        [shadow set];

// draw the sweep line from centre to edge. The transform is rotated so draw at a fixed angle.

        [[NSColor greenColor] set];
        [NSBezierPath setDefaultLineWidth:1.5];
[NSBezierPath strokeLineFromPoint:centre toPoint:NSMakePoint( NSMaxX ([self bounds]), NSMidY([self bounds]))];
        
// draw the "target" on the screen when the beam sweeps across it to simulate a blip - here just a square // restore first so that effect of rotation is removed - target stays at a fixed place.
        
        [NSGraphicsContext restoreGraphicsState];

        if( fabs(mAngle) < 0.1 )
        {
NSBezierPath* target = [NSBezierPath bezierPathWithRect:NSMakeRect (( centre.x + NSMaxX([self bounds])) / 2.0, NSMidY([self bounds]), 10, 10 )];
                [[NSColor greenColor] set];
                [target fill];
        }
        
        [shadow release];
}


- (void)                animateWithTimer:(NSTimer*) timer
{
// timer callback ends up here. It updates the history buffer and marks the display needed.

#pragma unused(timer)
        
        [self updateHistoryBuffer];
        [self setNeedsDisplay:YES];
}




- (IBAction)    startSweep:(id) sender
{
#pragma unused(sender)
        
        if( mTimer == nil )
        {
mTimer = [NSTimer scheduledTimerWithTimeInterval:1.0/60.0 target:self selector:@selector(animateWithTimer:) userInfo:nil repeats:YES];
                mLastUpdateTime = [NSDate timeIntervalSinceReferenceDate];
        }
}



- (IBAction)    stopSweep:(id) sender
{
#pragma unused(sender)
        
        if( mTimer )
        {
                [mTimer invalidate];
                mTimer = nil;
        }
}




#pragma mark -
#pragma mark - as a NSView


- (void)                drawRect:(NSRect) dirtyRect
{
        [[NSColor blackColor] set];
        NSRectFill( dirtyRect );

        [self drawHistoryBuffer];
}


- (void)                dealloc
{
        [self stopSweep:nil];
        [mHistoryImage release];
        [super dealloc];
}



@end



_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to