18

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 を使用できることはわかっていますが、同じ精度ではありません

4

2 に答える 2

27

OpenGL とは独立して動作するように CVDisplayLink を構成できます。以下は、産業用カメラから定期的なキャプチャとレンダリングをトリガーするように 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()

最後に 1 つコメントするとしたら、通常、CVDisplayLink が OpenGL とペアになっているのは、通常、Core Graphics を使用して画面をすばやく更新したくないからです。何かを 30 ~ 60 FPS レートでアニメーション化する必要がある場合は、OpenGL を使用して直接描画するか、Core Animation を使用してアニメーションのタイミングを処理させます。Core Graphics の描画は、物事を流動的にアニメーション化する方法ではありません。

于 2013-01-04T22:12:54.030 に答える
1

NSTimer がここに行く方法だと思います。「同じ精度ではありません」というあなたの発言は興味深いものです。おそらく、精度の問題と誤解しているのは、実行ループ モードの問題です。メニューを開いたりドラッグしたりしているときにタイマーが起動しない場合は、タイマーが実行されている実行ループ モードを変更する必要があるかもしれません。

もう 1 つのオプションは、最後のレンダリング パス以降の想定される差ではなく、レンダリングされた実際の時間に基づいてアニメーションを計算することです。後者を行うと、他の方法では見過ごされる可能性のあるレンダリングの遅延が視覚的に誇張されます。

NSTimer とは別に、GCD でタイマーを実行することもできます。この例を見てみましょう: http://www.fieryrobot.com/blog/2010/07/10/a-watchdog-timer-in-gcd/

ビデオ再生を含む OpenGL レンダリングには CVDisplayLink を使用します。あなたがやろうとしていることはやり過ぎだと確信しています。

于 2013-01-04T20:35:40.913 に答える