简体   繁体   English

适用于Mac OS X的CADisplayLink替代方案

[英]Alternative of CADisplayLink for Mac OS X

Is iOS there is CADisplayLink, in Mac OS X there is CVDisplayLink, but I can't find a way to use it, all the examples are related to OpenGL. iOS有CADisplayLink,在Mac OS X中有CVDisplayLink,但我找不到使用它的方法,所有的例子都与OpenGL有关。

I created this custom UIView and I want to translate it to a NSView 我创建了这个自定义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

The part that I can't translate is this one 我无法翻译的部分是这一部分

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

I know that I can use a NSTimer, but it doesn't have the same accuracy 我知道我可以使用NSTimer,但它没有相同的准确性

You can configure a CVDisplayLink to work independently of OpenGL. 您可以将CVDisplayLink配置为独立于OpenGL工作。 The following is code that I've used to set up a CVDisplayLink to trigger regular capture and rendering from an industrial camera: 以下是我用来设置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);

my renderCallback function looks something like this: 我的renderCallback函数看起来像这样:

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

You'll have to replace the above with your own class and callback method, of course. 当然,您必须用自己的类和回调方法替换上面的内容。 The __bridge in the code is there for ARC support, so you may not need that in a manually reference counted environment. 代码中的__bridge用于ARC支持,因此您可能不需要在手动引用计数环境中使用它。

To start capturing events from the display link, you'd use 要开始从显示链接捕获事件,您可以使用

CVDisplayLinkStart(displayLink);

and to stop 并停下来

CVDisplayLinkStop(displayLink);

When done, be sure to clean up after your created CVDisplayLink using CVDisplayLinkRelease() . 完成后,请务必使用CVDisplayLinkRelease()在创建的CVDisplayLink之后进行清理。

If I may make one last comment, the reason why you see CVDisplayLink normally paired with OpenGL is that you usually don't want to be doing rapid refreshes on the screen using Core Graphics. 如果我可以做最后一次评论,你看到CVDisplayLink通常与OpenGL配对的原因是你通常不希望使用Core Graphics在屏幕上快速刷新。 If you need to be animating something at a 30-60 FPS rate, you're going to either want to draw directly using OpenGL or use Core Animation and let it handle the animation timing for you. 如果您需要以30-60 FPS的速率制作动画,那么您将要么直接使用OpenGL进行绘制,要么使用Core Animation让它为您处理动画时序。 Core Graphics drawing is not the way to fluidly animate things. 核心图形绘制不是流畅地制作动画的方式。

I would think that an NSTimer would be the way to go here. 我认为NSTimer将成为这里的方式。 Your statement "it doesn't have the same accuracy", is interesting. 你的陈述“它没有相同的准确性”,很有意思。 Perhaps what you are mistaking for an accuracy problem is a run loop mode problem. 也许你错误的准确性问题是运行循环模式问题。 If you are seeing the timer not fire when you are doing certain things such as opening menus or dragging, you may need to just change the run loop modes that the timer is running in. 如果您在执行某些操作(例如打开菜单或拖动)时看到计时器未激活,则可能只需更改运行计时器的运行循环模式。

Another option is to calculate your animation based on the actual time that it's rendered, not on an assumed difference since the last render pass. 另一种选择是根据渲染的实际时间计算动画,而不是根据上次渲染过程后的假设差异计算动画。 Doing the latter will visually exaggerate any delays in rendering that might be otherwise go unnoticed. 执行后者会在视觉上夸大渲染中可能会被忽视的任何延迟。

Aside from NSTimer, you can also do timers in GCD. 除了NSTimer,您还可以在GCD中做计时器。 Take a look at this example: http://www.fieryrobot.com/blog/2010/07/10/a-watchdog-timer-in-gcd/ 看一下这个例子: http//www.fieryrobot.com/blog/2010/07/10/a-watchdog-timer-in-gcd/

We use CVDisplayLink for OpenGL rendering that includes video playback. 我们使用CVDisplayLink进行OpenGL渲染,包括视频播放。 I am pretty sure it's overkill for what you are trying to do. 我很确定你想要做的事情有点过分。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM