2013-01-04 6 views
12

iOS에 CADisplayLink가 있으며, Mac OS X에는 CVDisplayLink가 있지만 사용 방법을 찾을 수 없으며 모든 예제는 OpenGL과 관련되어 있습니다.Mac OS X 용 CADisplayLink의 대안

내가이 사용자 정의에 UIView를 생성하고 난 NSView의

#import "StarView.h" 
#import <QuartzCore/QuartzCore.h> 

#define MAX_FPS (100.0) 
#define MIN_FPS (MAX_FPS/40.0) 
#define FRAME_TIME (1.0/MAX_FPS) 
#define MAX_CPF (MAX_FPS/MIN_FPS) 
#define aEPS (0.0001f) 

@implementation StarView 

@synthesize starImage = _starImage; 
@synthesize x, y; 

- (void)baseInit { 
    _starImage = nil; 
    CADisplayLink *displayLink = [CADisplayLink displayLinkWithTarget:self  selector:@selector(runLoop)]; 
[displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; 
} 

- (id)initWithFrame:(CGRect)frame 
{ 
self = [super initWithFrame:frame]; 
if (self) { 
    [self baseInit]; 
} 
return self; 
} 

- (id)initWithCoder:(NSCoder *)aDecoder { 
if ((self = [super initWithCoder:aDecoder])) { 
    [self baseInit]; 
} 
return self; 
} 

// Only override drawRect: if you perform custom drawing. 
// An empty implementation adversely affects performance during animation. 
- (void)drawRect:(CGRect)rect 
{ 
    [self.starImage drawAtPoint:CGPointMake(self.x, self.y)]; 
} 

-(void) cycle { 
    self.x += 5; 
    if (self.x > 230) { 
     self.x = 0; 
    } 
} 

- (void) runLoop { 
//NSLog(@"called"); 
static CFTimeInterval last_time = 0.0f; 
static float cycles_left_over = 0.0f; 
static float dt2 = 0.0f; 

float dropAnimRate = (2.1f/25.0f); 

CFTimeInterval current_time = CACurrentMediaTime(); 
float dt = current_time - last_time + cycles_left_over; 
dt2 += dt; 

[self setNeedsDisplay]; 

if (dt > (MAX_CPF * FRAME_TIME)) { 
    dt = (MAX_CPF * FRAME_TIME); 
} 
while (dt > FRAME_TIME) { 
    if (dt2 > (dropAnimRate - aEPS)){ 
     [self cycle]; 
     dt2 = 0.0f; 
    } 
    dt -= FRAME_TIME; 
} 

cycles_left_over = dt; 
last_time = current_time; 
} 

@end 
로 번역 할

내가 번역 할 수없는 부분은 내가이를 사용할 수 있다는 것을 알고이 일

- (void)baseInit { 
    _starImage = nil; 
    CADisplayLink *displayLink = [CADisplayLink displayLinkWithTarget:self  selector:@selector(runLoop)]; 
[displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; 
} 

입니다 NSTimer,하지만 정확도가 동일하지 않습니다.

답변

19

OpenGL과 독립적으로 작동하도록 CVDisplayLink를 구성 할 수 있습니다.

static CVReturn renderCallback(CVDisplayLinkRef displayLink, 
           const CVTimeStamp *inNow, 
           const CVTimeStamp *inOutputTime, 
           CVOptionFlags flagsIn, 
           CVOptionFlags *flagsOut, 
           void *displayLinkContext) 
{ 
    return [(__bridge SPVideoView *)displayLinkContext renderTime:inOutputTime]; 
} 

당신은거야 :

CGDirectDisplayID displayID = CGMainDisplayID(); 
CVReturn   error = kCVReturnSuccess; 
error = CVDisplayLinkCreateWithCGDisplay(displayID, &displayLink); 
if (error) 
{ 
    NSLog(@"DisplayLink created with error:%d", error); 
    displayLink = NULL; 
} 
CVDisplayLinkSetOutputCallback(displayLink, renderCallback, (__bridge void *)self); 

renderCallback 기능은 다음과 같은 : 다음은 내가 산업용 카메라에서 일반 캡처 및 렌더링을 트리거 할 CVDisplayLink을 설정하는 데 사용했습니다 코드 물론 위의 코드를 자신의 클래스 및 콜백 메소드로 대체해야합니다. 코드의 __bridge은 ARC 지원을 위해 제공되므로 참조 계산 된 수동 환경에서는 필요하지 않을 수 있습니다.

, 당신은

CVDisplayLinkStart(displayLink); 

사용하십시오하고 완료되면

CVDisplayLinkStop(displayLink); 

, 당신의 생성 CVDisplayLink이 CVDisplayLinkRelease() 사용 후 청소해야 중지 디스플레이 링크에서 이벤트를 캡처를 시작합니다.

마지막 주석을 달 수있는 경우, 일반적으로 CVDisplayLink가 OpenGL과 쌍을 이루는 이유는 일반적으로 Core Graphics를 사용하여 화면에서 빠른 새로 고침을하고 싶지 않기 때문입니다. 30-60 FPS 속도로 무언가를 애니메이트해야한다면 OpenGL을 사용하여 직접 드로잉하거나 Core Animation을 사용하여 애니메이션 타이밍을 처리하도록 할 것입니다. 코어 그래픽 드로잉은 유동적으로 사물을 움직이는 방법이 아닙니다.

+0

'return [(__bridge SPVideoView *) displayLinkContext renderTime : inOutputTime];'이 줄을 이해하지 못했습니다. SPVideoView 대신 MyView를 사용해야하지만 renderTime 대신 무엇을 사용해야하는지 이해하지 못합니다. . 이 함수의 목적 (renderCallback과 renderTime)을 나에게 설명해 주시겠습니까? – AR89

+0

@ AR89 - CVDisplayLink는 메서드가 아닌 콜백 함수를 사용하기 때문에 클래스의 적절한 메서드를 다시 호출해야합니다. 위의 클래스는 SPVideoView 클래스를 사용하고 있으며 inOutputTime 타임 스탬프를 사용하는 메서드가 있습니다. 타임 스탬프를 사용하여 디스플레이 업데이트를 실행할지 여부를 결정할 수 있습니다. 또한이 콜백은 백그라운드 스레드에서 발생하기 때문에 디스플레이 업데이트에주의해야한다는 점을 지적 할 수 있습니다. 따라서 Core Graphics를 사용하는 경우 메인 스레드에서 드로잉이 발생하는지 확인해야합니다. –

+0

이것은 좋은 대답이지만보기가 그려지는 다른 스레드에서 콜백이 트리거되도록하는 것이 중요합니까? 적어도 OpenGL 렌더링을위한 것 같아요. – jheriko

1

나는 NSTimer가 여기에 갈 길이라고 생각할 것입니다. 귀하의 진술 "그것은 동일한 정확성을 가지고 있지 않다"는 흥미 롭습니다. 아마도 정확도 문제를 오해하고있는 것은 실행 루프 모드 문제입니다. 메뉴를 열거 나 드래그하는 것과 같은 특정 작업을 수행 할 때 타이머가 작동하지 않는다면 타이머가 실행중인 실행 루프 모드 만 변경하면됩니다.

또 다른 옵션은 애니메이션 기반 최종 렌더링 패스 이후의 가정 된 차이가 아니라 렌더링 된 실제 시간에 따라 달라집니다. 후자를 실행하면 렌더링이 지연되는 것을 시각적으로 과장하여 눈에 띄지 않게됩니다.

NSTimer 이외에도 GCD에서 타이머를 수행 할 수도 있습니다. 이 예를 보자 : http://www.fieryrobot.com/blog/2010/07/10/a-watchdog-timer-in-gcd/

우리는 비디오 재생을 포함하는 OpenGL 렌더링을 위해 CVDisplayLink를 사용한다. 나는 당신이하려는 것을 과잉이라고 확신한다.