2010-08-07 4 views
4

J'ai été bloqué pendant des heures en essayant de rendre un arbre de couches Core Animation dans un contexte OpenGL en utilisant CARenderer. Le contexte OpenGL est actuellement fourni par une sous-classe NSOpenGLView configurée dans Interface Builder, avec des paramètres par défaut.CARenderer ne produit jamais de sortie

Voici comment je mis en place les CALayers dans mon exemple:

l1 = [[CALayer layer] retain];  // l1 is an instance variable 
l1.bounds = CGRectMake(0, 0, 100, 100); 
l1.backgroundColor = CGColorCreateGenericRGB(1, 1, 0, 1); 
CALayer* l2 = [CALayer layer]; 
l2.bounds = CGRectMake(0, 0, 20, 20); 
l2.backgroundColor = CGColorCreateGenericRGB(1, 0, 0, 1); 
l2.position = CGPointMake(50, 50); 
[l1 addSublayer:l2]; 

Si j'ajouter à un NSView régulier, ils apparaissent très bien.

Voici le code de dessin de ma sous-classe NSOpenGLView:

- (void) drawRect:(NSRect)dirtyRect 
{ 
    NSRect frame = [self frame]; 

    // set up context according to CARenderer.h instructions 
    glViewport(0, 0, frame.size.width, frame.size.height); 
    glMatrixMode(GL_PROJECTION); 
    glLoadIdentity(); 
    glOrtho(0, frame.size.width, 0, frame.size.height, -1, 1); 

    glClearColor(0, 0, 0, 0); 
    glClear(GL_COLOR_BUFFER_BIT); 

    if (l1) 
    { 
     CARenderer* renderer = [CARenderer rendererWithCGLContext:[[self openGLContext] CGLContextObj] options:nil]; 
     renderer.layer = l1; 
     renderer.bounds = NSRectToCGRect(frame); 
     [renderer beginFrameAtTime:0.0 timeStamp:NULL]; 
     [renderer addUpdateRect:renderer.bounds]; 
     [renderer render]; 
     [renderer endFrame]; 
    } 

    glFlush(); 
} 

J'ai vérifié que la vue est redessinée après que les couches ont été créées, et la vue elle-même semble fonctionner ok - commandes OpenGL j'émets afficher correctement . Le CARenderer prend vie (en fait, si l1 est déjà attaché à un autre contexte au moment où ce code s'exécute, il se plaindra consciencieusement). Il n'y a juste pas de sortie visible, jamais. D'autres choses que j'ai essayées: envelopper le code CARenderer dans un CATransaction, en jouant avec les options de configuration NSOpenGLView dans Interface Builder, rendant l'affaire entière dans un contexte OpenGL créé manuellement hors écran et en enregistrant cela dans un fichier image ... tous dans le même sens: les commandes natives OpenGL sont bonnes, CARenderer ne montre rien.

Je pense qu'il y a quelque chose qui ne va pas dans la façon dont mon contexte OpenGL est configuré, ou que je pourrais même être en train de rendre en dehors de ma fenêtre ... probablement des détails mineurs vraiment stupides. Malheureusement, la documentation et l'exemple de code pour CARenderer sur le web sont assez rares, et bien que je sois assez expérimenté avec Core Animation, mes connaissances OpenGL sont décidément limitées.

Donc maintenant, je suis sérieusement perplexe et complètement à court d'idées, donc les pointeurs sont grandement appréciés!

Salutations

Répondre

4

Oh wouah. Donc, au cas où quelqu'un serait intéressé, j'ai eu ce "travail pour la plupart" entre-temps. Voici le code correspondant:

- (void) drawRect:(NSRect)dirtyRect 
{ 
    NSRect viewBounds = [self bounds]; 

    // set up context according to CARenderer.h instructions 
    glViewport(0, 0, viewBounds.size.width, viewBounds.size.height); 
    glMatrixMode(GL_PROJECTION); 
    glLoadIdentity(); 
    glOrtho(0, viewBounds.size.width, 0, viewBounds.size.height, -1, 1); 

    glClearColor(0, 0, 0, 0); 
    glClear(GL_COLOR_BUFFER_BIT); 

    [renderer beginFrameAtTime:0.0 timeStamp:NULL]; 
    [renderer addUpdateRect:renderer.bounds]; 
    [renderer render]; 
    [renderer endFrame]; 

    glFlush(); 
} 

- (void) prepareOpenGL 
{ 
    renderer = [[CARenderer rendererWithCGLContext:[[self openGLContext] CGLContextObj] options:nil] retain]; 

    [CATransaction begin]; 
    CALayer* l = [CALayer layer]; 
    l.bounds = CGRectMake(0, 0, 100, 100); 
    l.backgroundColor = CGColorCreateGenericRGB(1, 1, 0, 1); 

    renderer.layer = l; 
    renderer.bounds = l.bounds; 
    [CATransaction commit]; 
} 

Notez le bloc CATransaction autour du code de création couche/renderer. Sans cela, la couche n'apparaîtrait pas du tout (comme c'était mon problème initial), ou ne serait restituée qu'après un léger retard, c'est-à-dire lorsque la vue serait redessinée après un certain temps. Pour pourquoi cela est nécessaire, je ne sais toujours pas, et je serais plus qu'heureux si quelqu'un pouvait m'éclairer sur ce point.

De toute évidence, cette solution pourrait encore être en quelque sorte défectueux, mais j'ai décidé de le laisser ici pour le moment compte tenu du manque d'échantillon de code pour CARenderer.

EDIT: Comme je l'ai découvert plus tard, une erreur plutôt évidente avec la solution ci-dessus est que 0.0 est passée à l'appel de méthode beginFrameAtTime; Au lieu de cela, cela devrait être la valeur de CACurrentMediaTime. Cela supprimera la nécessité pour les blocs CATransaction, ainsi que la correction de quelques autres bugs en cours de route. Juste comme un avertissement pour quiconque pourrait trébucher sur cette réponse.

+0

Merci de poster un commentaire. Suivre la méthode prepareOpenGL semble aider le CALayer à avoir une couche de présentation non nulle sans être affichée (quelque chose que j'essaie d'utiliser avec CAKeyFrameanimation pour calculer hackishly des points le long d'un CGPath) –

Questions connexes