CADisplayLink替代的Mac OS X(Alternative of CADisplayL

2019-07-17 20:15发布

是的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,但它不具有相同的精度

Answer 1:

您可以配置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);

完成后,确保您使用创建后CVDisplayLink清理CVDisplayLinkRelease()

如果我可以做最后的评论,为什么你看到CVDisplayLink通常与OpenGL的配对是,你通常不希望使用核芯显卡,在屏幕上做快速刷新的原因。 如果您需要在30-60 FPS率进行动画的东西,你会想要么直接使用OpenGL绘制或使用的Core Animation,让它处理动画计时为您服务。 核心图形绘制不是流体动画事物的方式。



Answer 2:

我认为,一个NSTimer将去这里的路。 你的声明“它不具有相同的精度”,是有趣的。 也许你正在为误精度问题是一个运行循环模式的问题。 如果你看到,当你在做某些事情,如打开菜单或拖动计时器不火,你可能只是需要改变定时器运行的运行循环模式。

另一种选择是基于其呈现的实际时间来计算你的动画,而不是自上次渲染过程的假设的差异。 否则后者将在视觉上夸大渲染任何延迟,这可能会被忽视。

除了的NSTimer,你也可以做定时器在GCD。 看看这个例子: http://www.fieryrobot.com/blog/2010/07/10/a-watchdog-timer-in-gcd/

我们使用CVDisplayLink对于OpenGL渲染,包括视频播放。 我敢肯定这是矫枉过正你正在尝试做的。



文章来源: Alternative of CADisplayLink for Mac OS X