2013-01-04 23 views
12

के लिए कैडिसप्ले लिंक का वैकल्पिक आईओएस है मैक ओएस एक्स में कैडिसप्ले लिंक है, सीवीडिस्प्ले लिंक है, लेकिन मुझे इसका उपयोग करने का कोई तरीका नहीं मिल रहा है, सभी उदाहरण 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]; 
} 

मुझे पता है कि मैं एक का उपयोग कर सकते है एनएसटीमर, लेकिन इसमें समान सटीकता नहीं है

उत्तर

19

आप ओपनजीएल से स्वतंत्र रूप से काम करने के लिए एक सीवीडिस्प्ले लिंक कॉन्फ़िगर कर सकते हैं।

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 एआरसी समर्थन के लिए है, इसलिए आपको मैन्युअल रूप से संदर्भित वातावरण में इसकी आवश्यकता नहीं हो सकती है।

प्रदर्शन लिंक से घटनाओं पर कब्जा करने के लिए, आप

CVDisplayLinkStart(displayLink); 

का उपयोग करेंगे और बंद करने के लिए

CVDisplayLinkStop(displayLink); 

पूर्ण होने पर, आपके द्वारा बनाए CVDisplayLink CVDisplayLinkRelease() उपयोग करने के बाद साफ करने के लिए सुनिश्चित करें।

यदि मैं एक आखिरी टिप्पणी कर सकता हूं, तो आप सीवीडिस्प्ले लिंक को आम तौर पर ओपनजीएल के साथ जोड़ा क्यों देखते हैं कि आप आमतौर पर कोर ग्राफिक्स का उपयोग कर स्क्रीन पर तेज़ रीफ्रेश नहीं करना चाहते हैं। यदि आपको 30-60 एफपीएस दर पर कुछ एनिमेट करने की आवश्यकता है, तो आप या तो ओपनजीएल का उपयोग करके सीधे आकर्षित करना चाहते हैं या कोर एनीमेशन का उपयोग करना चाहते हैं और इसे आपके लिए एनीमेशन समय को संभालने दें। कोर ग्राफिक्स ड्राइंग चीजों को द्रव रूप से एनिमेट करने का तरीका नहीं है।

+0

वेटर्न [(__bridge एसपीवीडियो व्यू *) डिस्प्ले लिंक कॉन्टेक्स्ट रेंडरटाइम: इनऑटपुटटाइम]; 'मुझे यह लाइन समझ में नहीं आया, मुझे लगता है कि एसपीवीडियो व्यू के बजाय मुझे माईव्यू का उपयोग करना चाहिए, लेकिन मुझे समझ में नहीं आता कि मुझे रेंडरटाइम के बजाय क्या उपयोग करना चाहिए । क्या आप मुझे इस कार्यों के उद्देश्य (दोनों रेंडर कॉलबैक और रेंडरटाइम) के बारे में बता सकते हैं? – AR89

+0

@ AR89 - क्योंकि CVDisplayLink एक कॉलबैक फ़ंक्शन लेता है, एक विधि नहीं, यह आपके ऊपर है कि आप अपनी कक्षा में उचित विधि पर कॉल करें। उपर्युक्त में, मैं जिस कक्षा का उपयोग कर रहा था वह एसपीवीडियो व्यू है, और मेरे पास एक तरीका है जो आउटपुटटाइम टाइमस्टैम्प में लेता है। आप उस टाइमस्टैम्प का उपयोग यह निर्धारित करने के लिए करेंगे कि क्या आप अभी तक अपना प्रदर्शन अपडेट आग लगाना चाहते हैं। एक तरफ, मैं यह भी बता सकता हूं कि आपको इसका उपयोग करके प्रदर्शन अपडेट से सावधान रहना चाहिए, क्योंकि यह कॉलबैक पृष्ठभूमि थ्रेड पर होता है, इसलिए आपको कोर ग्राफिक्स का उपयोग करते हुए यह सुनिश्चित करना होगा कि आपका चित्र मुख्य थ्रेड पर होता है। –

+0

यह एक अच्छा जवाब है, लेकिन क्या यह महत्वपूर्ण है कि आप कॉलबैक को एक अलग थ्रेड पर ट्रिगर किए जा रहे हैं जहां एक दृश्य खींचा जाएगा? मुझे लगता है कि यह कम से कम OpenGL प्रतिपादन के लिए हो सकता है। – jheriko

1

मुझे लगता है कि एक एनएसटीमर यहां जाने का तरीका होगा। आपका बयान "इसमें समान सटीकता नहीं है", दिलचस्प है। शायद आप एक सटीकता समस्या के लिए गलत क्या कर रहे हैं एक रन लूप मोड समस्या है। यदि आप मेन्यू खोलने या खींचने जैसी कुछ चीजें कर रहे हैं तो टाइमर को आग नहीं लग रही है, तो आपको टाइमर चलने वाले रन लूप मोड को बदलने की आवश्यकता हो सकती है।

एक और विकल्प आपकी एनीमेशन आधारित गणना करना है वास्तविक समय पर यह प्रस्तुत किया गया है, अंतिम रेंडर पास के बाद से अनुमानित अंतर पर नहीं। उत्तरार्द्ध करने से प्रतिपादन में किसी भी देरी को स्पष्ट रूप से अतिरंजित किया जाएगा जो अन्यथा अनजान हो सकता है।

एनएसटीमर से परे, आप जीसीडी में टाइमर भी कर सकते हैं। इस उदाहरण पर एक नज़र डालें: http://www.fieryrobot.com/blog/2010/07/10/a-watchdog-timer-in-gcd/

हम ओपनजीएल प्रतिपादन के लिए सीवीडिस्प्ले लिंक का उपयोग करते हैं जिसमें वीडियो प्लेबैक शामिल है। मुझे पूरा यकीन है कि आप जो करने की कोशिश कर रहे हैं उसके लिए यह अधिक है।