簡體   English   中英

適用於Mac OS X的CADisplayLink替代方案

[英]Alternative of CADisplayLink for Mac OS X

iOS有CADisplayLink,在Mac OS X中有CVDisplayLink,但我找不到使用它的方法,所有的例子都與OpenGL有關。

我創建了這個自定義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,但它沒有相同的准確性

您可以將CVDisplayLink配置為獨立於OpenGL工作。 以下是我用來設置CVDisplayLink以觸發工業相機定期捕獲和渲染的代碼:

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函數看起來像這樣:

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

當然,您必須用自己的類和回調方法替換上面的內容。 代碼中的__bridge用於ARC支持,因此您可能不需要在手動引用計數環境中使用它。

要開始從顯示鏈接捕獲事件,您可以使用

CVDisplayLinkStart(displayLink);

並停下來

CVDisplayLinkStop(displayLink);

完成后,請務必使用CVDisplayLinkRelease()在創建的CVDisplayLink之后進行清理。

如果我可以做最后一次評論,你看到CVDisplayLink通常與OpenGL配對的原因是你通常不希望使用Core Graphics在屏幕上快速刷新。 如果您需要以30-60 FPS的速率制作動畫,那么您將要么直接使用OpenGL進行繪制,要么使用Core Animation讓它為您處理動畫時序。 核心圖形繪制不是流暢地制作動畫的方式。

我認為NSTimer將成為這里的方式。 你的陳述“它沒有相同的准確性”,很有意思。 也許你錯誤的准確性問題是運行循環模式問題。 如果您在執行某些操作(例如打開菜單或拖動)時看到計時器未激活,則可能只需更改運行計時器的運行循環模式。

另一種選擇是根據渲染的實際時間計算動畫,而不是根據上次渲染過程后的假設差異計算動畫。 執行后者會在視覺上誇大渲染中可能會被忽視的任何延遲。

除了NSTimer,您還可以在GCD中做計時器。 看一下這個例子: http//www.fieryrobot.com/blog/2010/07/10/a-watchdog-timer-in-gcd/

我們使用CVDisplayLink進行OpenGL渲染,包括視頻播放。 我很確定你想要做的事情有點過分。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM