Show
Ignore:
Timestamp:
06/21/08 13:34:01 (6 years ago)
Author:
robert
Message:

Converted tabs to four spaces

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • OpenSceneGraph/trunk/examples/osgviewerCocoa/ViewerCocoa.mm

    r7655 r8483  
    137137static void Internal_SetAlpha(NSBitmapImageRep *imageRep, unsigned char alpha_value) 
    138138{ 
    139         register unsigned char * sp = [imageRep bitmapData]; 
    140         register int bytesPerRow = [imageRep bytesPerRow]; 
    141         register int height = [imageRep pixelsHigh]; 
    142         register int width = [imageRep pixelsWide]; 
    143  
    144         for(int i=0; i<height; i++) 
    145         { 
    146                 register unsigned int * the_pixel = (unsigned int *) sp; 
    147                 register int w = width; 
    148                 while (w-- > 0) 
    149                 { 
    150                         unsigned char* sp_char = (unsigned char *) the_pixel; 
    151 //                      register unsigned char * the_red = sp_char; 
    152 //                      register unsigned char * the_green = (sp_char+1); 
    153 //                      register unsigned char * the_blue = (sp_char+2); 
    154                         register unsigned char * the_alpha = (sp_char+3); 
    155          
    156                         *the_alpha = alpha_value; 
    157                         *the_pixel++; 
    158                 } 
    159                 sp += bytesPerRow; 
    160         } 
     139    register unsigned char * sp = [imageRep bitmapData]; 
     140    register int bytesPerRow = [imageRep bytesPerRow]; 
     141    register int height = [imageRep pixelsHigh]; 
     142    register int width = [imageRep pixelsWide]; 
     143 
     144    for(int i=0; i<height; i++) 
     145    { 
     146        register unsigned int * the_pixel = (unsigned int *) sp; 
     147        register int w = width; 
     148        while (w-- > 0) 
     149        { 
     150            unsigned char* sp_char = (unsigned char *) the_pixel; 
     151//            register unsigned char * the_red = sp_char; 
     152//            register unsigned char * the_green = (sp_char+1); 
     153//            register unsigned char * the_blue = (sp_char+2); 
     154            register unsigned char * the_alpha = (sp_char+3); 
     155     
     156            *the_alpha = alpha_value; 
     157            *the_pixel++; 
     158        } 
     159        sp += bytesPerRow; 
     160    } 
    161161} 
    162162 
     
    167167+ (NSOpenGLPixelFormat*) basicPixelFormat 
    168168{ 
    169         NSOpenGLPixelFormatAttribute pixel_attributes[] = 
    170         { 
    171                 NSOpenGLPFAWindow, 
    172                 NSOpenGLPFADoubleBuffer,  // double buffered 
    173                 NSOpenGLPFADepthSize, (NSOpenGLPixelFormatAttribute)32, // depth buffer size in bits 
    174 //              NSOpenGLPFAColorSize, (NSOpenGLPixelFormatAttribute)24, // Not sure if this helps 
    175 //              NSOpenGLPFAAlphaSize, (NSOpenGLPixelFormatAttribute)8, // Not sure if this helps 
    176                 (NSOpenGLPixelFormatAttribute)nil 
     169    NSOpenGLPixelFormatAttribute pixel_attributes[] = 
     170    { 
     171        NSOpenGLPFAWindow, 
     172        NSOpenGLPFADoubleBuffer,  // double buffered 
     173        NSOpenGLPFADepthSize, (NSOpenGLPixelFormatAttribute)32, // depth buffer size in bits 
     174//        NSOpenGLPFAColorSize, (NSOpenGLPixelFormatAttribute)24, // Not sure if this helps 
     175//        NSOpenGLPFAAlphaSize, (NSOpenGLPixelFormatAttribute)8, // Not sure if this helps 
     176        (NSOpenGLPixelFormatAttribute)nil 
    177177    }; 
    178178    return [[[NSOpenGLPixelFormat alloc] initWithAttributes:pixel_attributes] autorelease]; 
     
    191191- (id) initWithFrame:(NSRect)frame_rect pixelFormat:(NSOpenGLPixelFormat*)pixel_format 
    192192{ 
    193         self = [super initWithFrame:frame_rect pixelFormat:pixel_format]; 
    194         if(self) 
    195         { 
    196                 [self commonInit]; 
    197         } 
    198         return self; 
     193    self = [super initWithFrame:frame_rect pixelFormat:pixel_format]; 
     194    if(self) 
     195    { 
     196        [self commonInit]; 
     197    } 
     198    return self; 
    199199} 
    200200 
     
    209209- (id) initWithCoder:(NSCoder*)the_coder 
    210210{ 
    211         self = [super initWithCoder:the_coder]; 
    212         if(self) 
    213         { 
    214                 NSOpenGLPixelFormat* pixel_format = [ViewerCocoa basicPixelFormat]; 
    215                 [self setPixelFormat:pixel_format]; 
    216                 [self commonInit]; 
    217         } 
    218         return self; 
     211    self = [super initWithCoder:the_coder]; 
     212    if(self) 
     213    { 
     214        NSOpenGLPixelFormat* pixel_format = [ViewerCocoa basicPixelFormat]; 
     215        [self setPixelFormat:pixel_format]; 
     216        [self commonInit]; 
     217    } 
     218    return self; 
    219219} 
    220220 
     
    224224- (id) initWithFrame:(NSRect)frame_rect 
    225225{ 
    226         self = [super initWithFrame:frame_rect pixelFormat:[ViewerCocoa basicPixelFormat]]; 
    227         if(self) 
    228         { 
    229                 [self commonInit]; 
    230         } 
    231         return self; 
     226    self = [super initWithFrame:frame_rect pixelFormat:[ViewerCocoa basicPixelFormat]]; 
     227    if(self) 
     228    { 
     229        [self commonInit]; 
     230    } 
     231    return self; 
    232232} 
    233233 
     
    236236- (void) commonInit 
    237237{ 
    238         isUsingCtrlClick = NO; 
    239         isUsingOptionClick = NO; 
    240         isUsingMultithreadedOpenGLEngine = NO; 
    241  
    242         [self initSharedOpenGLContext]; 
    243  
    244         [self initOSGViewer]; 
    245         [self initAnimationTimer]; 
    246          
    247         // Register for Drag and Drop 
    248         [self registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, NSURLPboardType, nil]]; 
    249          
     238    isUsingCtrlClick = NO; 
     239    isUsingOptionClick = NO; 
     240    isUsingMultithreadedOpenGLEngine = NO; 
     241 
     242    [self initSharedOpenGLContext]; 
     243 
     244    [self initOSGViewer]; 
     245    [self initAnimationTimer]; 
     246     
     247    // Register for Drag and Drop 
     248    [self registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, NSURLPboardType, nil]]; 
     249     
    250250    // Add minification observer so we can set the Dock picture since OpenGL views don't do this automatically for us. 
    251         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(prepareForMiniaturization:) name:NSWindowWillMiniaturizeNotification object:nil]; 
     251    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(prepareForMiniaturization:) name:NSWindowWillMiniaturizeNotification object:nil]; 
    252252 
    253253} 
     
    260260#ifdef VIEWER_USE_SHARED_CONTEXTS 
    261261 
    262         NSOpenGLContext* this_views_opengl_context = nil; 
    263          
    264         // create a context the first time through 
    265         if(s_sharedOpenGLContext == NULL) 
    266         { 
    267                 s_sharedOpenGLContext = [[NSOpenGLContext alloc] 
     262    NSOpenGLContext* this_views_opengl_context = nil; 
     263     
     264    // create a context the first time through 
     265    if(s_sharedOpenGLContext == NULL) 
     266    { 
     267        s_sharedOpenGLContext = [[NSOpenGLContext alloc] 
    268268                      initWithFormat:[ViewerCocoa basicPixelFormat] 
    269                                                 shareContext:nil]; 
    270                  
    271         } 
    272          
    273         this_views_opengl_context = [[NSOpenGLContext alloc] 
     269                        shareContext:nil]; 
     270         
     271    } 
     272     
     273    this_views_opengl_context = [[NSOpenGLContext alloc] 
    274274                      initWithFormat:[ViewerCocoa basicPixelFormat] 
    275                                                 shareContext:s_sharedOpenGLContext]; 
    276         [self setOpenGLContext:this_views_opengl_context]; 
    277 //      [this_views_opengl_context makeCurrentContext]; 
     275                        shareContext:s_sharedOpenGLContext]; 
     276     [self setOpenGLContext:this_views_opengl_context]; 
     277//    [this_views_opengl_context makeCurrentContext]; 
    278278#endif // VIEWER_USE_SHARED_CONTEXTS 
    279279} 
     
    285285 
    286286 
    287 //      osg::setNotifyLevel( osg::DEBUG_FP ); 
    288         theViewer = new osgViewer::Viewer; 
    289         graphicsWindow = theViewer->setUpViewerAsEmbeddedInWindow(0,0,740,650); // numbers from Nib 
    290         // Builts in Stats handler 
    291         theViewer->addEventHandler(new osgViewer::StatsHandler); 
     287//    osg::setNotifyLevel( osg::DEBUG_FP ); 
     288    theViewer = new osgViewer::Viewer; 
     289    graphicsWindow = theViewer->setUpViewerAsEmbeddedInWindow(0,0,740,650); // numbers from Nib 
     290    // Builts in Stats handler 
     291    theViewer->addEventHandler(new osgViewer::StatsHandler); 
    292292#ifdef VIEWER_USE_SHARED_CONTEXTS 
    293         // Workaround: osgViewer::Viewer automatically increments its context ID values. 
    294         // Since we're using a shared context, we want all Viewer's to use the same context ID. 
    295         // There is no API to avoid this behavior, so we need to undo what Viewer's constructor did. 
     293    // Workaround: osgViewer::Viewer automatically increments its context ID values. 
     294    // Since we're using a shared context, we want all Viewer's to use the same context ID. 
     295    // There is no API to avoid this behavior, so we need to undo what Viewer's constructor did. 
    296296    graphicsWindow->getState()->setContextID(0); 
    297         osg::DisplaySettings::instance()->setMaxNumberOfGraphicsContexts(1); 
     297    osg::DisplaySettings::instance()->setMaxNumberOfGraphicsContexts(1); 
    298298#endif // VIEWER_USE_SHARED_CONTEXTS 
    299299 
    300         // Cocoa follows the same coordinate convention as OpenGL. osgViewer's default is inverted. 
    301         theViewer->getEventQueue()->getCurrentEventState()->setMouseYOrientation(osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS); 
    302         // Use a trackball manipulator...matches nicely with the Mighty Mouse Scrollball. 
    303         theViewer->setCameraManipulator(new osgGA::TrackballManipulator); 
    304          
     300    // Cocoa follows the same coordinate convention as OpenGL. osgViewer's default is inverted. 
     301    theViewer->getEventQueue()->getCurrentEventState()->setMouseYOrientation(osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS); 
     302    // Use a trackball manipulator...matches nicely with the Mighty Mouse Scrollball. 
     303    theViewer->setCameraManipulator(new osgGA::TrackballManipulator); 
     304     
    305305} 
    306306 
    307307- (void) initAnimationTimer 
    308308{ 
    309         // Cocoa is event driven, so by default, there is nothing to trigger redraws for animation. 
    310         // The easiest way to animate is to set a repeating NSTimer which triggers a redraw. 
    311         SEL the_selector; 
    312         NSMethodSignature* a_signature; 
    313         NSInvocation* an_invocation; 
    314         // animationCallback is my animation callback method 
    315         the_selector = @selector( animationCallback ); 
    316         a_signature = [ViewerCocoa instanceMethodSignatureForSelector:the_selector]; 
    317         an_invocation = [NSInvocation invocationWithMethodSignature:a_signature] ; 
    318         [an_invocation setSelector:the_selector]; 
    319         [an_invocation setTarget:self]; 
    320          
    321         animationTimer = [NSTimer 
    322                 scheduledTimerWithTimeInterval:1.0/60.0 // fps 
    323                 invocation:an_invocation 
    324                 repeats:YES]; 
    325         [animationTimer retain]; 
    326          
    327         // For single threaded apps like this one, 
    328         // Cocoa seems to block timers or events sometimes. This can be seen 
    329         // when I'm animating (via a timer) and you open an popup box or move a slider. 
    330         // Apparently, sheets and dialogs can also block (try printing). 
    331         // To work around this, Cocoa provides different run-loop modes. I need to  
    332         // specify the modes to avoid the blockage. 
    333         // NSDefaultRunLoopMode seems to be the default. I don't think I need to explicitly 
    334         // set this one, but just in case, I will set it anyway. 
    335         [[NSRunLoop currentRunLoop] addTimer:animationTimer forMode:NSDefaultRunLoopMode]; 
    336         // This seems to be the one for preventing blocking on other events (popup box, slider, etc) 
    337         [[NSRunLoop currentRunLoop] addTimer:animationTimer forMode:NSEventTrackingRunLoopMode]; 
    338         // This seems to be the one for dialogs. 
    339         [[NSRunLoop currentRunLoop] addTimer:animationTimer forMode:NSModalPanelRunLoopMode]; 
     309    // Cocoa is event driven, so by default, there is nothing to trigger redraws for animation. 
     310    // The easiest way to animate is to set a repeating NSTimer which triggers a redraw. 
     311    SEL the_selector; 
     312    NSMethodSignature* a_signature; 
     313    NSInvocation* an_invocation; 
     314    // animationCallback is my animation callback method 
     315    the_selector = @selector( animationCallback ); 
     316    a_signature = [ViewerCocoa instanceMethodSignatureForSelector:the_selector]; 
     317    an_invocation = [NSInvocation invocationWithMethodSignature:a_signature] ; 
     318    [an_invocation setSelector:the_selector]; 
     319    [an_invocation setTarget:self]; 
     320     
     321    animationTimer = [NSTimer 
     322        scheduledTimerWithTimeInterval:1.0/60.0 // fps 
     323        invocation:an_invocation 
     324        repeats:YES]; 
     325    [animationTimer retain]; 
     326     
     327    // For single threaded apps like this one, 
     328    // Cocoa seems to block timers or events sometimes. This can be seen 
     329    // when I'm animating (via a timer) and you open an popup box or move a slider. 
     330    // Apparently, sheets and dialogs can also block (try printing). 
     331    // To work around this, Cocoa provides different run-loop modes. I need to  
     332    // specify the modes to avoid the blockage. 
     333    // NSDefaultRunLoopMode seems to be the default. I don't think I need to explicitly 
     334    // set this one, but just in case, I will set it anyway. 
     335    [[NSRunLoop currentRunLoop] addTimer:animationTimer forMode:NSDefaultRunLoopMode]; 
     336    // This seems to be the one for preventing blocking on other events (popup box, slider, etc) 
     337    [[NSRunLoop currentRunLoop] addTimer:animationTimer forMode:NSEventTrackingRunLoopMode]; 
     338    // This seems to be the one for dialogs. 
     339    [[NSRunLoop currentRunLoop] addTimer:animationTimer forMode:NSModalPanelRunLoopMode]; 
    340340} 
    341341 
    342342- (void) dealloc 
    343343{ 
    344         [animationTimer invalidate]; 
    345         [animationTimer release]; 
    346         delete theViewer; 
    347         theViewer = NULL; 
    348         [super dealloc]; 
     344    [animationTimer invalidate]; 
     345    [animationTimer release]; 
     346    delete theViewer; 
     347    theViewer = NULL; 
     348    [super dealloc]; 
    349349} 
    350350 
    351351- (void) finalize 
    352352{ 
    353         delete theViewer; 
    354         theViewer = NULL; 
    355         [super finalize]; 
     353    delete theViewer; 
     354    theViewer = NULL; 
     355    [super finalize]; 
    356356} 
    357357 
     
    365365- (void) prepareOpenGL 
    366366{ 
    367         [super prepareOpenGL]; 
    368          
    369         // The NSOpenGLCPSwapInterval seems to be vsync. If 1, buffers are swapped with vertical refresh. 
    370         // If 0, flushBuffer will execute as soon as possible. 
    371         long swap_interval = 1 ; 
     367    [super prepareOpenGL]; 
     368     
     369    // The NSOpenGLCPSwapInterval seems to be vsync. If 1, buffers are swapped with vertical refresh. 
     370    // If 0, flushBuffer will execute as soon as possible. 
     371    long swap_interval = 1 ; 
    372372    [[self openGLContext] setValues:&swap_interval forParameter:NSOpenGLCPSwapInterval]; 
    373373 
    374374 
    375         // Try new multithreaded OpenGL engine? 
    376         // See Technical Note TN2085 Enabling multi-threaded execution of the OpenGL framework 
    377         // http://developer.apple.com/technotes/tn2006/tn2085.html 
    378         // For this simple viewer, you are probably not going to see a speed boost, but possibly a speed hit, 
    379         // since we probably don't have much data to dispatch, 
    380         // but it is enabled anyway for demonstration purposes. 
    381         uint64_t num_cpus = 0; 
    382         size_t num_cpus_length = sizeof(num_cpus); 
    383         // Multithreaded engine only benefits with muliple CPUs, so do CPU count check 
    384         // I've been told that Apple has started doing this check behind the scenes in some version of Tiger. 
    385         if(sysctlbyname("hw.activecpu", &num_cpus, &num_cpus_length, NULL, 0) == 0) 
    386         { 
    387 //              NSLog(@"Num CPUs=%d", num_cpus); 
    388                 if(num_cpus >= 2) 
    389                 { 
    390                         // Cleared to enable multi-threaded engine 
    391                         // kCGLCEMPEngine may not be defined before certain versions of Tiger/Xcode, 
    392                         // so use the numeric value 313 instead to keep things compiling. 
    393                         CGLError error_val = CGLEnable((CGLContextObj)[[self openGLContext] CGLContextObj], static_cast<CGLContextEnable>(313)); 
    394                         if(error_val != 0) 
    395                         { 
    396                                 // The likelihood of failure seems quite high on older hardware, at least for now. 
    397                                 // NSLog(@"Failed to enable Multithreaded OpenGL Engine: %s", CGLErrorString(error_val)); 
    398                                 isUsingMultithreadedOpenGLEngine = NO; 
    399                         } 
    400                         else 
    401                         { 
    402                                 // NSLog(@"Success! Multithreaded OpenGL Engine activated!"); 
    403                                 isUsingMultithreadedOpenGLEngine = YES; 
    404                         } 
    405                 } 
    406                 else 
    407                 { 
    408                         isUsingMultithreadedOpenGLEngine = NO; 
    409                 } 
    410         } 
    411  
    412         // This is also might be a good place to setup OpenGL state that OSG doesn't control. 
    413         glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST); 
    414         glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); 
    415         glHint(GL_POINT_SMOOTH_HINT, GL_NICEST); 
    416         glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); 
     375    // Try new multithreaded OpenGL engine? 
     376    // See Technical Note TN2085 Enabling multi-threaded execution of the OpenGL framework 
     377    // http://developer.apple.com/technotes/tn2006/tn2085.html 
     378    // For this simple viewer, you are probably not going to see a speed boost, but possibly a speed hit, 
     379    // since we probably don't have much data to dispatch, 
     380    // but it is enabled anyway for demonstration purposes. 
     381    uint64_t num_cpus = 0; 
     382    size_t num_cpus_length = sizeof(num_cpus); 
     383    // Multithreaded engine only benefits with muliple CPUs, so do CPU count check 
     384    // I've been told that Apple has started doing this check behind the scenes in some version of Tiger. 
     385    if(sysctlbyname("hw.activecpu", &num_cpus, &num_cpus_length, NULL, 0) == 0) 
     386    { 
     387//        NSLog(@"Num CPUs=%d", num_cpus); 
     388        if(num_cpus >= 2) 
     389        { 
     390            // Cleared to enable multi-threaded engine 
     391            // kCGLCEMPEngine may not be defined before certain versions of Tiger/Xcode, 
     392            // so use the numeric value 313 instead to keep things compiling. 
     393            CGLError error_val = CGLEnable((CGLContextObj)[[self openGLContext] CGLContextObj], static_cast<CGLContextEnable>(313)); 
     394            if(error_val != 0) 
     395            { 
     396                // The likelihood of failure seems quite high on older hardware, at least for now. 
     397                // NSLog(@"Failed to enable Multithreaded OpenGL Engine: %s", CGLErrorString(error_val)); 
     398                isUsingMultithreadedOpenGLEngine = NO; 
     399            } 
     400            else 
     401            { 
     402                // NSLog(@"Success! Multithreaded OpenGL Engine activated!"); 
     403                isUsingMultithreadedOpenGLEngine = YES; 
     404            } 
     405        } 
     406        else 
     407        { 
     408            isUsingMultithreadedOpenGLEngine = NO; 
     409        } 
     410    } 
     411 
     412    // This is also might be a good place to setup OpenGL state that OSG doesn't control. 
     413    glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST); 
     414    glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); 
     415    glHint(GL_POINT_SMOOTH_HINT, GL_NICEST); 
     416    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); 
    417417 
    418418/* 
    419         GLint maxbuffers[1]; 
    420         glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, maxbuffers); 
    421         NSLog(@"GL_MAX_COLOR_ATTACHMENTS=%d", maxbuffers[0]); 
     419    GLint maxbuffers[1]; 
     420    glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, maxbuffers); 
     421    NSLog(@"GL_MAX_COLOR_ATTACHMENTS=%d", maxbuffers[0]); 
    422422*/ 
    423423 
    424         // We need to tell the osgViewer what the viewport size is 
    425         [self resizeViewport]; 
    426  
    427  
    428         // This is optional: 
    429         // This is to setup some default text in the OpenGL view so the  
    430         // user knows that they should drag and drop a model into the view. 
    431         osg::ref_ptr<osgText::Text> default_text = new osgText::Text; 
     424    // We need to tell the osgViewer what the viewport size is 
     425    [self resizeViewport]; 
     426 
     427 
     428    // This is optional: 
     429    // This is to setup some default text in the OpenGL view so the  
     430    // user knows that they should drag and drop a model into the view. 
     431    osg::ref_ptr<osgText::Text> default_text = new osgText::Text; 
    432432 
    433433    default_text->setAlignment(osgText::Text::CENTER_CENTER); 
    434434    default_text->setBackdropType(osgText::Text::OUTLINE); 
    435 //      default_text->setBackdropImplementation(osgText::Text::POLYGON_OFFSET); 
    436         default_text->setColor(osg::Vec4(1.0, 1.0, 0.0, 1.0)); 
    437         default_text->setBackdropColor(osg::Vec4(0.0, 0.0, 0.0, 1.0)); 
     435//    default_text->setBackdropImplementation(osgText::Text::POLYGON_OFFSET); 
     436    default_text->setColor(osg::Vec4(1.0, 1.0, 0.0, 1.0)); 
     437    default_text->setBackdropColor(osg::Vec4(0.0, 0.0, 0.0, 1.0)); 
    438438    default_text->setAxisAlignment(osgText::Text::XZ_PLANE); 
    439          
    440         // We should use a (Cocoa) localizable string instead of a hard coded string. 
    441 //      default_text->setText("Drag-and-Drop\nyour .osg model here!"); 
    442         // The first string is the key name (you need a Localizable.strings file for your Nib). The second string is just a comment. 
    443         NSString* localized_string = NSLocalizedString(@"DragAndDropHere", @"Drag-and-Drop\nyour .osg model here!"); 
    444         default_text->setText([localized_string UTF8String]); 
    445          
    446         osg::ref_ptr<osg::Geode> the_geode = new osg::Geode; 
    447         the_geode->addDrawable(default_text.get()); 
    448  
    449         theViewer->setSceneData(the_geode.get()); 
     439     
     440    // We should use a (Cocoa) localizable string instead of a hard coded string. 
     441//    default_text->setText("Drag-and-Drop\nyour .osg model here!"); 
     442    // The first string is the key name (you need a Localizable.strings file for your Nib). The second string is just a comment. 
     443    NSString* localized_string = NSLocalizedString(@"DragAndDropHere", @"Drag-and-Drop\nyour .osg model here!"); 
     444    default_text->setText([localized_string UTF8String]); 
     445     
     446    osg::ref_ptr<osg::Geode> the_geode = new osg::Geode; 
     447    the_geode->addDrawable(default_text.get()); 
     448 
     449    theViewer->setSceneData(the_geode.get()); 
    450450} 
    451451 
     
    467467    NSWindow* the_window = [self window]; 
    468468    if([the_window respondsToSelector:@selector(disableScreenUpdatesUntilFlush)]) 
    469         { 
    470                 [the_window disableScreenUpdatesUntilFlush]; 
     469    { 
     470        [the_window disableScreenUpdatesUntilFlush]; 
    471471    } 
    472472    [super renewGState]; 
     
    482482- (void) prepareForMiniaturization:(NSNotification*)notification 
    483483{ 
    484         [[self openGLContext] makeCurrentContext]; 
    485         NSBitmapImageRep* ns_image_rep = [self renderOpenGLSceneToFramebuffer]; 
    486         if([self lockFocusIfCanDraw]) 
    487         { 
    488                 [ns_image_rep draw]; 
    489                 [self unlockFocus]; 
    490                 [[self window] flushWindow]; 
    491         } 
     484    [[self openGLContext] makeCurrentContext]; 
     485    NSBitmapImageRep* ns_image_rep = [self renderOpenGLSceneToFramebuffer]; 
     486    if([self lockFocusIfCanDraw]) 
     487    { 
     488        [ns_image_rep draw]; 
     489        [self unlockFocus]; 
     490        [[self window] flushWindow]; 
     491    } 
    492492} 
    493493 
     
    496496- (BOOL) isUsingMultithreadedOpenGLEngine 
    497497{ 
    498         return isUsingMultithreadedOpenGLEngine; 
     498    return isUsingMultithreadedOpenGLEngine; 
    499499} 
    500500 
     
    512512- (void) mouseDown:(NSEvent*)the_event 
    513513{ 
    514         // Because many Mac users have only a 1-button mouse, we should provide ways 
    515         // to access the button 2 and 3 actions of osgViewer. 
    516         // I will use the Ctrl modifer to represent right-clicking 
    517         // and Option modifier to represent middle clicking. 
    518         if([the_event modifierFlags] & NSControlKeyMask) 
    519         { 
    520                 [self setIsUsingCtrlClick:YES]; 
    521                 [self doRightMouseButtonDown:the_event]; 
    522         } 
    523         else if([the_event modifierFlags] & NSAlternateKeyMask) 
    524         { 
    525                 [self setIsUsingOptionClick:YES]; 
    526                 [self doMiddleMouseButtonDown:the_event]; 
    527         } 
    528         else if([the_event modifierFlags] & NSCommandKeyMask) 
    529         { 
    530                 [self startDragAndDropAsSource:the_event]; 
    531         } 
    532         else 
    533         { 
    534                 [self doLeftMouseButtonDown:the_event]; 
    535         } 
     514    // Because many Mac users have only a 1-button mouse, we should provide ways 
     515    // to access the button 2 and 3 actions of osgViewer. 
     516    // I will use the Ctrl modifer to represent right-clicking 
     517    // and Option modifier to represent middle clicking. 
     518    if([the_event modifierFlags] & NSControlKeyMask) 
     519    { 
     520        [self setIsUsingCtrlClick:YES]; 
     521        [self doRightMouseButtonDown:the_event]; 
     522    } 
     523    else if([the_event modifierFlags] & NSAlternateKeyMask) 
     524    { 
     525        [self setIsUsingOptionClick:YES]; 
     526        [self doMiddleMouseButtonDown:the_event]; 
     527    } 
     528    else if([the_event modifierFlags] & NSCommandKeyMask) 
     529    { 
     530        [self startDragAndDropAsSource:the_event]; 
     531    } 
     532    else 
     533    { 
     534        [self doLeftMouseButtonDown:the_event]; 
     535    } 
    536536} 
    537537 
    538538- (void) mouseDragged:(NSEvent*)the_event 
    539539{ 
    540         // We must convert the mouse event locations from the window coordinate system to the 
    541         // local view coordinate system. 
    542         NSPoint the_point = [the_event locationInWindow]; 
     540    // We must convert the mouse event locations from the window coordinate system to the 
     541    // local view coordinate system. 
     542    NSPoint the_point = [the_event locationInWindow]; 
    543543    NSPoint converted_point = [self convertPoint:the_point fromView:nil]; 
    544          
    545         theViewer->getEventQueue()->mouseMotion(converted_point.x, converted_point.y); 
    546         [self setNeedsDisplay:YES]; 
     544     
     545    theViewer->getEventQueue()->mouseMotion(converted_point.x, converted_point.y); 
     546    [self setNeedsDisplay:YES]; 
    547547} 
    548548 
    549549- (void) mouseUp:(NSEvent*)the_event 
    550550{ 
    551         // Because many Mac users have only a 1-button mouse, we should provide ways 
    552         // to access the button 2 and 3 actions of osgViewer. 
    553         // I will use the Ctrl modifer to represent right-clicking 
    554         // and Option modifier to represent middle clicking. 
    555         if([self isUsingCtrlClick] == YES) 
    556         { 
    557                 [self setIsUsingCtrlClick:NO]; 
    558                 [self doRightMouseButtonUp:the_event]; 
    559         } 
    560         else if([self isUsingOptionClick] == YES) 
    561         { 
    562                 [self setIsUsingOptionClick:NO]; 
    563                 [self doMiddleMouseButtonUp:the_event]; 
    564         } 
    565         else 
    566         { 
    567                 [self doLeftMouseButtonUp:the_event]; 
    568         } 
     551    // Because many Mac users have only a 1-button mouse, we should provide ways 
     552    // to access the button 2 and 3 actions of osgViewer. 
     553    // I will use the Ctrl modifer to represent right-clicking 
     554    // and Option modifier to represent middle clicking. 
     555    if([self isUsingCtrlClick] == YES) 
     556    { 
     557        [self setIsUsingCtrlClick:NO]; 
     558        [self doRightMouseButtonUp:the_event]; 
     559    } 
     560    else if([self isUsingOptionClick] == YES) 
     561    { 
     562        [self setIsUsingOptionClick:NO]; 
     563        [self doMiddleMouseButtonUp:the_event]; 
     564    } 
     565    else 
     566    { 
     567        [self doLeftMouseButtonUp:the_event]; 
     568    } 
    569569} 
    570570 
    571571- (void) rightMouseDown:(NSEvent*)the_event 
    572572{ 
    573         [self doRightMouseButtonDown:the_event]; 
     573    [self doRightMouseButtonDown:the_event]; 
    574574} 
    575575 
    576576- (void) rightMouseDragged:(NSEvent*)the_event 
    577577{ 
    578         // We must convert the mouse event locations from the window coordinate system to the 
    579         // local view coordinate system. 
    580         NSPoint the_point = [the_event locationInWindow]; 
     578    // We must convert the mouse event locations from the window coordinate system to the 
     579    // local view coordinate system. 
     580    NSPoint the_point = [the_event locationInWindow]; 
    581581    NSPoint converted_point = [self convertPoint:the_point fromView:nil]; 
    582          
    583         theViewer->getEventQueue()->mouseMotion(converted_point.x, converted_point.y); 
    584         [self setNeedsDisplay:YES]; 
     582     
     583    theViewer->getEventQueue()->mouseMotion(converted_point.x, converted_point.y); 
     584    [self setNeedsDisplay:YES]; 
    585585} 
    586586 
    587587- (void) rightMouseUp:(NSEvent*)the_event 
    588588{ 
    589         [self doRightMouseButtonUp:the_event]; 
     589    [self doRightMouseButtonUp:the_event]; 
    590590} 
    591591 
     
    593593- (void) otherMouseDown:(NSEvent*)the_event 
    594594{ 
    595         // Button 0 is left 
    596         // Button 1 is right 
    597         // Button 2 is middle 
    598         // Button 3 keeps going 
    599         // osgViewer expects 1 for left, 3 for right, 2 for middle 
    600         // osgViewer has a reversed number mapping for right and middle compared to Cocoa 
    601         if([the_event buttonNumber] == 2) 
    602         { 
    603                 [self doMiddleMouseButtonDown:the_event]; 
    604         } 
    605         else // buttonNumber should be 3,4,5,etc; must map to 4,5,6,etc in osgViewer 
    606         { 
    607                 [self doExtraMouseButtonDown:the_event buttonNumber:[the_event buttonNumber]]; 
    608         } 
     595    // Button 0 is left 
     596    // Button 1 is right 
     597    // Button 2 is middle 
     598    // Button 3 keeps going 
     599    // osgViewer expects 1 for left, 3 for right, 2 for middle 
     600    // osgViewer has a reversed number mapping for right and middle compared to Cocoa 
     601    if([the_event buttonNumber] == 2) 
     602    { 
     603        [self doMiddleMouseButtonDown:the_event]; 
     604    } 
     605    else // buttonNumber should be 3,4,5,etc; must map to 4,5,6,etc in osgViewer 
     606    { 
     607        [self doExtraMouseButtonDown:the_event buttonNumber:[the_event buttonNumber]]; 
     608    } 
    609609} 
    610610 
    611611- (void) otherMouseDragged:(NSEvent*)the_event 
    612612{ 
    613         // We must convert the mouse event locations from the window coordinate system to the 
    614         // local view coordinate system. 
    615         NSPoint the_point = [the_event locationInWindow]; 
     613    // We must convert the mouse event locations from the window coordinate system to the 
     614    // local view coordinate system. 
     615    NSPoint the_point = [the_event locationInWindow]; 
    616616    NSPoint converted_point = [self convertPoint:the_point fromView:nil]; 
    617          
    618         theViewer->getEventQueue()->mouseMotion(converted_point.x, converted_point.y); 
    619         [self setNeedsDisplay:YES]; 
     617     
     618    theViewer->getEventQueue()->mouseMotion(converted_point.x, converted_point.y); 
     619    [self setNeedsDisplay:YES]; 
    620620} 
    621621 
     
    623623- (void) otherMouseUp:(NSEvent*)the_event 
    624624{ 
    625         // Button 0 is left 
    626         // Button 1 is right 
    627         // Button 2 is middle 
    628         // Button 3 keeps going 
    629         // osgViewer expects 1 for left, 3 for right, 2 for middle 
    630         // osgViewer has a reversed number mapping for right and middle compared to Cocoa 
    631         if([the_event buttonNumber] == 2) 
    632         { 
    633                 [self doMiddleMouseButtonUp:the_event]; 
    634         } 
    635         else // buttonNumber should be 3,4,5,etc; must map to 4,5,6,etc in osgViewer 
    636         { 
    637                 // I don't think osgViewer does anything for these additional buttons, 
    638                 // but just in case, pass them along. But as a Cocoa programmer, you might  
    639                 // think about things you can do natively here instead of passing the buck. 
    640         }       [self doExtraMouseButtonUp:the_event buttonNumber:[the_event buttonNumber]]; 
     625    // Button 0 is left 
     626    // Button 1 is right 
     627    // Button 2 is middle 
     628    // Button 3 keeps going 
     629    // osgViewer expects 1 for left, 3 for right, 2 for middle 
     630    // osgViewer has a reversed number mapping for right and middle compared to Cocoa 
     631    if([the_event buttonNumber] == 2) 
     632    { 
     633        [self doMiddleMouseButtonUp:the_event]; 
     634    } 
     635    else // buttonNumber should be 3,4,5,etc; must map to 4,5,6,etc in osgViewer 
     636    { 
     637        // I don't think osgViewer does anything for these additional buttons, 
     638        // but just in case, pass them along. But as a Cocoa programmer, you might  
     639        // think about things you can do natively here instead of passing the buck. 
     640    }    [self doExtraMouseButtonUp:the_event buttonNumber:[the_event buttonNumber]]; 
    641641} 
    642642 
    643643- (void) setIsUsingCtrlClick:(BOOL)is_using_ctrl_click 
    644644{ 
    645         isUsingCtrlClick = is_using_ctrl_click; 
     645    isUsingCtrlClick = is_using_ctrl_click; 
    646646} 
    647647 
    648648- (BOOL) isUsingCtrlClick 
    649649{ 
    650         return isUsingCtrlClick; 
     650    return isUsingCtrlClick; 
    651651} 
    652652 
    653653- (void) setIsUsingOptionClick:(BOOL)is_using_option_click 
    654654{ 
    655         isUsingOptionClick = is_using_option_click; 
     655    isUsingOptionClick = is_using_option_click; 
    656656} 
    657657 
    658658- (BOOL) isUsingOptionClick 
    659659{ 
    660         return isUsingOptionClick; 
     660    return isUsingOptionClick; 
    661661} 
    662662 
     
    664664- (void) doLeftMouseButtonDown:(NSEvent*)the_event 
    665665{ 
    666         // We must convert the mouse event locations from the window coordinate system to the 
    667         // local view coordinate system. 
    668         NSPoint the_point = [the_event locationInWindow]; 
     666    // We must convert the mouse event locations from the window coordinate system to the 
     667    // local view coordinate system. 
     668    NSPoint the_point = [the_event locationInWindow]; 
    669669    NSPoint converted_point = [self convertPoint:the_point fromView:nil]; 
    670         if([the_event clickCount] == 1) 
    671         { 
    672                 theViewer->getEventQueue()->mouseButtonPress(converted_point.x, converted_point.y, 1); 
    673         } 
    674         else 
    675         { 
    676                 theViewer->getEventQueue()->mouseDoubleButtonPress(converted_point.x, converted_point.y, 1); 
    677                  
    678                  
    679                 // Let's toggle fullscreen for show 
    680                 [self toggleFullScreen:nil]; 
    681  
    682         } 
    683         [self setNeedsDisplay:YES]; 
     670    if([the_event clickCount] == 1) 
     671    { 
     672        theViewer->getEventQueue()->mouseButtonPress(converted_point.x, converted_point.y, 1); 
     673    } 
     674    else 
     675    { 
     676        theViewer->getEventQueue()->mouseDoubleButtonPress(converted_point.x, converted_point.y, 1); 
     677         
     678         
     679        // Let's toggle fullscreen for show 
     680        [self toggleFullScreen:nil]; 
     681 
     682    } 
     683    [self setNeedsDisplay:YES]; 
    684684} 
    685685 
    686686- (void) doLeftMouseButtonUp:(NSEvent*)the_event 
    687687{ 
    688         // We must convert the mouse event locations from the window coordinate system to the 
    689         // local view coordinate system. 
    690         NSPoint the_point = [the_event locationInWindow]; 
     688    // We must convert the mouse event locations from the window coordinate system to the 
     689    // local view coordinate system. 
     690    NSPoint the_point = [the_event locationInWindow]; 
    691691    NSPoint converted_point = [self convertPoint:the_point fromView:nil]; 
    692          
    693         theViewer->getEventQueue()->mouseButtonRelease(converted_point.x, converted_point.y, 1); 
    694         [self setNeedsDisplay:YES]; 
     692     
     693    theViewer->getEventQueue()->mouseButtonRelease(converted_point.x, converted_point.y, 1); 
     694    [self setNeedsDisplay:YES]; 
    695695} 
    696696 
    697697- (void) doRightMouseButtonDown:(NSEvent*)the_event 
    698698{ 
    699         // We must convert the mouse event locations from the window coordinate system to the 
    700         // local view coordinate system. 
    701         NSPoint the_point = [the_event locationInWindow]; 
     699    // We must convert the mouse event locations from the window coordinate system to the 
     700    // local view coordinate system. 
     701    NSPoint the_point = [the_event locationInWindow]; 
    702702    NSPoint converted_point = [self convertPoint:the_point fromView:nil]; 
    703         if([the_event clickCount] == 1) 
    704         { 
    705                 theViewer->getEventQueue()->mouseButtonPress(converted_point.x, converted_point.y, 3); 
    706         } 
    707         else 
    708         { 
    709                 theViewer->getEventQueue()->mouseDoubleButtonPress(converted_point.x, converted_point.y, 3); 
    710         } 
    711         [self setNeedsDisplay:YES]; 
     703    if([the_event clickCount] == 1) 
     704    { 
     705        theViewer->getEventQueue()->mouseButtonPress(converted_point.x, converted_point.y, 3); 
     706    } 
     707    else 
     708    { 
     709        theViewer->getEventQueue()->mouseDoubleButtonPress(converted_point.x, converted_point.y, 3); 
     710    } 
     711    [self setNeedsDisplay:YES]; 
    712712} 
    713713 
     
    715715- (void) doRightMouseButtonUp:(NSEvent*)the_event 
    716716{ 
    717         // We must convert the mouse event locations from the window coordinate system to the 
    718         // local view coordinate system. 
    719         NSPoint the_point = [the_event locationInWindow]; 
     717    // We must convert the mouse event locations from the window coordinate system to the 
     718    // local view coordinate system. 
     719    NSPoint the_point = [the_event locationInWindow]; 
    720720    NSPoint converted_point = [self convertPoint:the_point fromView:nil]; 
    721          
    722         theViewer->getEventQueue()->mouseButtonRelease(converted_point.x, converted_point.y, 3); 
    723         [self setNeedsDisplay:YES]; 
     721     
     722    theViewer->getEventQueue()->mouseButtonRelease(converted_point.x, converted_point.y, 3); 
     723    [self setNeedsDisplay:YES]; 
    724724} 
    725725 
    726726- (void) doMiddleMouseButtonDown:(NSEvent*)the_event 
    727727{ 
    728         // We must convert the mouse event locations from the window coordinate system to the 
    729         // local view coordinate system. 
    730         NSPoint the_point = [the_event locationInWindow]; 
     728    // We must convert the mouse event locations from the window coordinate system to the 
     729    // local view coordinate system. 
     730    NSPoint the_point = [the_event locationInWindow]; 
    731731    NSPoint converted_point = [self convertPoint:the_point fromView:nil]; 
    732          
    733         if([the_event clickCount] == 1) 
    734         { 
    735                 theViewer->getEventQueue()->mouseButtonPress(converted_point.x, converted_point.y, 2); 
    736         } 
    737         else 
    738         { 
    739                 theViewer->getEventQueue()->mouseDoubleButtonPress(converted_point.x, converted_point.y, 2); 
    740         } 
    741         [self setNeedsDisplay:YES]; 
     732     
     733    if([the_event clickCount] == 1) 
     734    { 
     735        theViewer->getEventQueue()->mouseButtonPress(converted_point.x, converted_point.y, 2); 
     736    } 
     737    else 
     738    { 
     739        theViewer->getEventQueue()->mouseDoubleButtonPress(converted_point.x, converted_point.y, 2); 
     740    } 
     741    [self setNeedsDisplay:YES]; 
    742742} 
    743743 
    744744- (void) doExtraMouseButtonDown:(NSEvent*)the_event buttonNumber:(int)button_number 
    745745{ 
    746         // We must convert the mouse event locations from the window coordinate system to the 
    747         // local view coordinate system. 
    748         NSPoint the_point = [the_event locationInWindow]; 
     746    // We must convert the mouse event locations from the window coordinate system to the 
     747    // local view coordinate system. 
     748    NSPoint the_point = [the_event locationInWindow]; 
    749749    NSPoint converted_point = [self convertPoint:the_point fromView:nil]; 
    750750 
    751         if([the_event clickCount] == 1) 
    752         { 
    753                 theViewer->getEventQueue()->mouseButtonPress(converted_point.x, converted_point.y, button_number+1); 
    754         } 
    755         else 
    756         { 
    757                 theViewer->getEventQueue()->mouseDoubleButtonPress(converted_point.x, converted_point.y, button_number+1); 
    758         } 
    759         [self setNeedsDisplay:YES]; 
     751    if([the_event clickCount] == 1) 
     752    { 
     753        theViewer->getEventQueue()->mouseButtonPress(converted_point.x, converted_point.y, button_number+1); 
     754    } 
     755    else 
     756    { 
     757        theViewer->getEventQueue()->mouseDoubleButtonPress(converted_point.x, converted_point.y, button_number+1); 
     758    } 
     759    [self setNeedsDisplay:YES]; 
    760760} 
    761761 
     
    763763- (void) doMiddleMouseButtonUp:(NSEvent*)the_event 
    764764{ 
    765         // We must convert the mouse event locations from the window coordinate system to the 
    766         // local view coordinate system.        NSPoint the_point = [the_event locationInWindow]; 
    767         NSPoint the_point = [the_event locationInWindow]; 
    768         NSPoint converted_point = [self convertPoint:the_point fromView:nil]; 
    769         theViewer->getEventQueue()->mouseButtonRelease(converted_point.x, converted_point.y, 2); 
    770         [self setNeedsDisplay:YES]; 
     765    // We must convert the mouse event locations from the window coordinate system to the 
     766    // local view coordinate system.    NSPoint the_point = [the_event locationInWindow]; 
     767     NSPoint the_point = [the_event locationInWindow]; 
     768    NSPoint converted_point = [self convertPoint:the_point fromView:nil]; 
     769    theViewer->getEventQueue()->mouseButtonRelease(converted_point.x, converted_point.y, 2); 
     770    [self setNeedsDisplay:YES]; 
    771771} 
    772772 
    773773- (void) doExtraMouseButtonUp:(NSEvent*)the_event buttonNumber:(int)button_number 
    774774{ 
    775         // We must convert the mouse event locations from the window coordinate system to the 
    776         // local view coordinate system.        NSPoint the_point = [the_event locationInWindow]; 
    777         NSPoint the_point = [the_event locationInWindow]; 
    778         NSPoint converted_point = [self convertPoint:the_point fromView:nil]; 
    779         theViewer->getEventQueue()->mouseButtonRelease(converted_point.x, converted_point.y, button_number+1); 
    780          
    781         [self setNeedsDisplay:YES]; 
     775    // We must convert the mouse event locations from the window coordinate system to the 
     776    // local view coordinate system.    NSPoint the_point = [the_event locationInWindow]; 
     777    NSPoint the_point = [the_event locationInWindow]; 
     778    NSPoint converted_point = [self convertPoint:the_point fromView:nil]; 
     779    theViewer->getEventQueue()->mouseButtonRelease(converted_point.x, converted_point.y, button_number+1); 
     780     
     781    [self setNeedsDisplay:YES]; 
    782782} 
    783783 
     
    792792- (void) scrollWheel:(NSEvent*)the_event 
    793793{ 
    794         // Unfortunately, it turns out mouseScroll2D doesn't actually do anything. 
    795         // The camera manipulators don't seem to implement any code that utilize the scroll values. 
    796         // This this call does nothing. 
    797 //      theViewer->getEventQueue()->mouseScroll2D([the_event deltaX], [the_event deltaY]); 
    798  
    799         // With the absense of a useful mouseScroll2D API, we can manually simulate the desired effect. 
    800         NSPoint the_point = [the_event locationInWindow]; 
    801         NSPoint converted_point = [self convertPoint:the_point fromView:nil]; 
    802         theViewer->getEventQueue()->mouseButtonPress(converted_point.x, converted_point.y, 1); 
    803         theViewer->getEventQueue()->mouseMotion(converted_point.x + -[the_event deltaX], converted_point.y + [the_event deltaY]); 
    804         theViewer->getEventQueue()->mouseButtonRelease(converted_point.x + -[the_event deltaX], converted_point.y + [the_event deltaY], 1); 
    805  
    806         [self setNeedsDisplay:YES]; 
     794    // Unfortunately, it turns out mouseScroll2D doesn't actually do anything. 
     795    // The camera manipulators don't seem to implement any code that utilize the scroll values. 
     796    // This this call does nothing. 
     797//    theViewer->getEventQueue()->mouseScroll2D([the_event deltaX], [the_event deltaY]); 
     798 
     799    // With the absense of a useful mouseScroll2D API, we can manually simulate the desired effect. 
     800    NSPoint the_point = [the_event locationInWindow]; 
     801    NSPoint converted_point = [self convertPoint:the_point fromView:nil]; 
     802    theViewer->getEventQueue()->mouseButtonPress(converted_point.x, converted_point.y, 1); 
     803    theViewer->getEventQueue()->mouseMotion(converted_point.x + -[the_event deltaX], converted_point.y + [the_event deltaY]); 
     804    theViewer->getEventQueue()->mouseButtonRelease(converted_point.x + -[the_event deltaX], converted_point.y + [the_event deltaY], 1); 
     805 
     806    [self setNeedsDisplay:YES]; 
    807807} 
    808808 
     
    817817- (BOOL) acceptsFirstResponder 
    818818{ 
    819         return YES; 
     819    return YES; 
    820820} 
    821821 
    822822- (void) keyDown:(NSEvent*)the_event 
    823823{ 
    824         // Do you want characters or charactersIgnoringModifiers? 
    825         NSString* event_characters = [the_event characters]; 
    826 //      NSString* event_characters = [the_event charactersIgnoringModifiers]; 
    827  
    828         unichar unicode_character = [event_characters characterAtIndex:0]; 
    829 //      NSLog(@"unicode_character: %d", unicode_character); 
    830         theViewer->getEventQueue()->keyPress(static_cast<osgGA::GUIEventAdapter::KeySymbol>(unicode_character)); 
    831  
    832         [self setNeedsDisplay:YES]; 
     824    // Do you want characters or charactersIgnoringModifiers? 
     825    NSString* event_characters = [the_event characters]; 
     826//    NSString* event_characters = [the_event charactersIgnoringModifiers]; 
     827 
     828    unichar unicode_character = [event_characters characterAtIndex:0]; 
     829//    NSLog(@"unicode_character: %d", unicode_character); 
     830    theViewer->getEventQueue()->keyPress(static_cast<osgGA::GUIEventAdapter::KeySymbol>(unicode_character)); 
     831 
     832    [self setNeedsDisplay:YES]; 
    833833} 
    834834 
    835835- (void) keyUp:(NSEvent*)the_event 
    836836{ 
    837         // Do you want characters or charactersIgnoringModifiers? 
    838         NSString* event_characters = [the_event characters]; 
    839 //      NSString* event_characters = [the_event charactersIgnoringModifiers]; 
    840         unichar unicode_character = [event_characters characterAtIndex:0]; 
    841         theViewer->getEventQueue()->keyRelease(static_cast<osgGA::GUIEventAdapter::KeySymbol>(unicode_character)); 
    842         [self setNeedsDisplay:YES]; 
     837    // Do you want characters or charactersIgnoringModifiers? 
     838    NSString* event_characters = [the_event characters]; 
     839//    NSString* event_characters = [the_event charactersIgnoringModifiers]; 
     840    unichar unicode_character = [event_characters characterAtIndex:0]; 
     841    theViewer->getEventQueue()->keyRelease(static_cast<osgGA::GUIEventAdapter::KeySymbol>(unicode_character)); 
     842    [self setNeedsDisplay:YES]; 
    843843} 
    844844 
     
    854854- (void) animationCallback 
    855855{ 
    856         // Simply notify Cocoa that a drawRect needs to take place. 
    857         // Potential optimization is to query the OSG stuff to find out if a redraw is actually necessary. 
    858         [self setNeedsDisplay:YES]; 
     856    // Simply notify Cocoa that a drawRect needs to take place. 
     857    // Potential optimization is to query the OSG stuff to find out if a redraw is actually necessary. 
     858    [self setNeedsDisplay:YES]; 
    859859} 
    860860 
     
    863863- (BOOL) isOpaque 
    864864{ 
    865         return YES; 
     865    return YES; 
    866866} 
    867867 
     
    870870- (void) resizeViewport 
    871871{ 
    872         NSSize size_in_points = [self bounds].size; 
    873         // This coordinate system conversion seems to make things work with Quartz Debug. 
    874         NSSize size_in_window_coordinates = [self convertSize:size_in_points toView:nil]; 
    875         theViewer->getEventQueue()->windowResize(0, 0, size_in_window_coordinates.width, size_in_window_coordinates.height); 
    876         graphicsWindow->resized(0, 0, size_in_window_coordinates.width, size_in_window_coordinates.height); 
     872    NSSize size_in_points = [self bounds].size; 
     873    // This coordinate system conversion seems to make things work with Quartz Debug. 
     874    NSSize size_in_window_coordinates = [self convertSize:size_in_points toView:nil]; 
     875    theViewer->getEventQueue()->windowResize(0, 0, size_in_window_coordinates.width, size_in_window_coordinates.height); 
     876    graphicsWindow->resized(0, 0, size_in_window_coordinates.width, size_in_window_coordinates.height); 
    877877} 
    878878 
     
    880880- (void) reshape 
    881881{ 
    882         [super reshape]; 
    883         [self resizeViewport]; 
     882    [super reshape]; 
     883    [self resizeViewport]; 
    884884} 
    885885 
     
    890890- (void) drawRect:(NSRect)the_rect 
    891891{ 
    892         if([[NSGraphicsContext currentContext] isDrawingToScreen]) 
    893         { 
    894                 [[self openGLContext] makeCurrentContext]; 
    895                 theViewer->frame(); 
    896                 [[self openGLContext] flushBuffer]; 
    897         } 
    898         else // This is usually the print case 
    899         { 
    900                 [[self openGLContext] makeCurrentContext]; 
    901  
    902                 // FIXME: We should be computing a size that fits best to the paper target 
    903                 NSSize size_in_points = [self bounds].size; 
    904                 NSSize size_in_window_coordinates = [self convertSize:size_in_points toView:nil]; 
    905                 NSBitmapImageRep * bitmap_image_rep = [self renderOpenGLSceneToFramebufferAsFormat:GL_RGB viewWidth:size_in_window_coordinates.width viewHeight:size_in_window_coordinates.height]; 
    906                  
    907                 NSImage* ns_image = [self imageFromBitmapImageRep:bitmap_image_rep]; 
    908  
    909                 if(ns_image) 
    910                 { 
    911                         NSSize image_size = [ns_image size]; 
    912                         [ns_image drawAtPoint:NSMakePoint(0.0, 0.0)  
    913                                         fromRect: NSMakeRect(0.0, 0.0, image_size.width, image_size.height) 
    914 //                                 operation: NSCompositeSourceOver 
    915                                    operation: NSCompositeCopy 
    916                                         fraction: 1.0];          
    917                 } 
    918                 else 
    919                 { 
    920                         NSLog(@"Image not valid"); 
    921                 } 
    922         } 
     892    if([[NSGraphicsContext currentContext] isDrawingToScreen]) 
     893    { 
     894        [[self openGLContext] makeCurrentContext]; 
     895        theViewer->frame(); 
     896        [[self openGLContext] flushBuffer]; 
     897    } 
     898    else // This is usually the print case 
     899    { 
     900        [[self openGLContext] makeCurrentContext]; 
     901 
     902        // FIXME: We should be computing a size that fits best to the paper target 
     903        NSSize size_in_points = [self bounds].size; 
     904        NSSize size_in_window_coordinates = [self convertSize:size_in_points toView:nil]; 
     905        NSBitmapImageRep * bitmap_image_rep = [self renderOpenGLSceneToFramebufferAsFormat:GL_RGB viewWidth:size_in_window_coordinates.width viewHeight:size_in_window_coordinates.height]; 
     906         
     907        NSImage* ns_image = [self imageFromBitmapImageRep:bitmap_image_rep]; 
     908 
     909        if(ns_image) 
     910        { 
     911            NSSize image_size = [ns_image size]; 
     912            [ns_image drawAtPoint:NSMakePoint(0.0, 0.0)  
     913                    fromRect: NSMakeRect(0.0, 0.0, image_size.width, image_size.height) 
     914//                   operation: NSCompositeSourceOver 
     915                   operation: NSCompositeCopy 
     916                    fraction: 1.0];      
     917        } 
     918        else 
     919        { 
     920            NSLog(@"Image not valid"); 
     921        } 
     922    } 
    923923} 
    924924 
     
    932932- (NSBitmapImageRep*) renderOpenGLSceneToFramebuffer 
    933933{ 
    934         NSSize size_in_points = [self bounds].size; 
    935         NSSize size_in_window_coordinates = [self convertSize:size_in_points toView:nil]; 
    936         const osg::Vec4& clear_color = theViewer->getCamera()->getClearColor(); 
    937  
    938         return [self renderOpenGLSceneToFramebufferAsFormat:GL_RGB viewWidth:size_in_window_coordinates.width viewHeight:size_in_window_coordinates.height clearColorRed:clear_color[0] clearColorGreen:clear_color[1] clearColorBlue:clear_color[2] clearColorAlpha:clear_color[3]]; 
     934    NSSize size_in_points = [self bounds].size; 
     935    NSSize size_in_window_coordinates = [self convertSize:size_in_points toView:nil]; 
     936    const osg::Vec4& clear_color = theViewer->getCamera()->getClearColor(); 
     937 
     938    return [self renderOpenGLSceneToFramebufferAsFormat:GL_RGB viewWidth:size_in_window_coordinates.width viewHeight:size_in_window_coordinates.height clearColorRed:clear_color[0] clearColorGreen:clear_color[1] clearColorBlue:clear_color[2] clearColorAlpha:clear_color[3]]; 
    939939} 
    940940 
     
    942942- (NSBitmapImageRep*) renderOpenGLSceneToFramebufferAsFormat:(int)gl_format viewWidth:(float)view_width viewHeight:(float)view_height 
    943943{ 
    944         const osg::Vec4& clear_color = theViewer->getCamera()->getClearColor(); 
    945  
    946         return [self renderOpenGLSceneToFramebufferAsFormat:gl_format viewWidth:view_width viewHeight:view_height clearColorRed:clear_color[0] clearColorGreen:clear_color[1] clearColorBlue:clear_color[2] clearColorAlpha:clear_color[3]]; 
     944    const osg::Vec4& clear_color = theViewer->getCamera()->getClearColor(); 
     945 
     946    return [self renderOpenGLSceneToFramebufferAsFormat:gl_format viewWidth:view_width viewHeight:view_height clearColorRed:clear_color[0] clearColorGreen:clear_color[1] clearColorBlue:clear_color[2] clearColorAlpha:clear_color[3]]; 
    947947} 
    948948 
     
    952952- (NSBitmapImageRep*) renderOpenGLSceneToFramebufferAsFormat:(int)gl_format viewWidth:(float)view_width viewHeight:(float)view_height clearColorRed:(float)clear_red clearColorGreen:(float)clear_green clearColorBlue:(float)clear_blue clearColorAlpha:(float)clear_alpha 
    953953{ 
    954         // Round values and bring to closest integer. 
    955         int viewport_width = (int)(view_width + 0.5f); 
    956         int viewport_height = (int)(view_height + 0.5f); 
    957          
    958         NSBitmapImageRep* ns_image_rep; 
    959         osg::ref_ptr<osg::Image> osg_image = new osg::Image; 
    960          
    961         if(GL_RGBA == gl_format) 
    962         { 
    963                 // Introduced in 10.4, but gives much better looking results if you utilize transparency 
    964                 if([NSBitmapImageRep instancesRespondToSelector:@selector(initWithBitmapDataPlanes:pixelsWide:pixelsHigh:bitsPerSample:samplesPerPixel:hasAlpha:isPlanar:colorSpaceName:bitmapFormat:bytesPerRow:bitsPerPixel:)]) 
    965                 { 
    966                         ns_image_rep = [[[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL 
    967                                                                                                   pixelsWide:viewport_width 
    968                                                                                                   pixelsHigh:viewport_height 
    969                                                                                            bitsPerSample:8 
    970                                                                                         samplesPerPixel:4 
    971                                                                                                         hasAlpha:YES 
    972                                                                                                         isPlanar:NO 
    973                                                                                           colorSpaceName:NSCalibratedRGBColorSpace 
    974                                                                                                 bitmapFormat:NSAlphaNonpremultipliedBitmapFormat // 10.4+, gives much better looking results if you utilize transparency 
    975                                                                                                 bytesPerRow:osg::Image::computeRowWidthInBytes(viewport_width, GL_RGBA, GL_UNSIGNED_BYTE, 1) 
    976                                                                                                 bitsPerPixel:32] 
    977                                         autorelease]; 
    978                 } 
    979                 else // fallback for 10.0 to 10.3 
    980                 { 
    981                         ns_image_rep = [[[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL 
    982                                                                                                   pixelsWide:viewport_width 
    983                                                                                                   pixelsHigh:viewport_height 
    984                                                                                            bitsPerSample:8 
    985                                                                                         samplesPerPixel:4 
    986                                                                                                         hasAlpha:YES 
    987                                                                                                         isPlanar:NO 
    988                                                                                           colorSpaceName:NSCalibratedRGBColorSpace 
    989                                                                                                 // bitmapFormat:NSAlphaNonpremultipliedBitmapFormat // 10.4+, gives much better looking results if you utilize transparency 
    990                                                                                                 bytesPerRow:osg::Image::computeRowWidthInBytes(viewport_width, GL_RGBA, GL_UNSIGNED_BYTE, 1) 
    991                                                                                                 bitsPerPixel:32] 
    992                                         autorelease]; 
    993                 } 
    994                 // This is an optimization. Instead of creating data in both an osg::Image and NSBitmapImageRep, 
    995                 // Allocate just the memory in the NSBitmapImageRep and give the osg::Image a reference to the data. 
    996                 // I let NSBitmapImageRep control the memory because I think it will be easier to deal with  
    997                 // memory management in the cases where it must interact with other Cocoa mechanisms like Drag-and-drop 
    998                 // where the memory persistence is less obvious. Make sure that you don't expect to use the osg::Image 
    999                 // outside the scope of this function because there is no telling when the data will be removed out 
    1000                 // from under it by Cocoa since osg::Image will not retain. 
    1001                 osg_image->setImage([ns_image_rep pixelsWide], [ns_image_rep pixelsHigh], 1,  GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, [ns_image_rep bitmapData], osg::Image::NO_DELETE, 1); 
    1002         } 
    1003         else if(GL_RGB == gl_format) 
    1004         { 
    1005                 ns_image_rep = [[[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL 
    1006                                                                                                   pixelsWide:viewport_width 
    1007                                                                                                   pixelsHigh:viewport_height 
    1008                                                                                            bitsPerSample:8 
    1009                                                                                         samplesPerPixel:3 
    1010                                                                                                         hasAlpha:NO 
    1011                                                                                                         isPlanar:NO 
    1012                                                                                           colorSpaceName:NSCalibratedRGBColorSpace 
    1013                                                                                                 // bitmapFormat:(NSBitmapFormat)0 // 10.4+ 
    1014                                                                                                 bytesPerRow:osg::Image::computeRowWidthInBytes(viewport_width, GL_RGB, GL_UNSIGNED_BYTE, 1) 
    1015                                                                                                 bitsPerPixel:24] 
    1016                                         autorelease]; 
    1017  
    1018                 // This is an optimization. Instead of creating data in both an osg::Image and NSBitmapImageRep, 
    1019                 // Allocate just the memory in the NSBitmapImageRep and give the osg::Image a reference to the data. 
    1020                 // I let NSBitmapImageRep control the memory because I think it will be easier to deal with  
    1021                 // memory management in the cases where it must interact with other Cocoa mechanisms like Drag-and-drop 
    1022                 // where the memory persistence is less obvious. Make sure that you don't expect to use the osg::Image 
    1023                 // outside the scope of this function because there is no telling when the data will be removed out 
    1024                 // from under it by Cocoa since osg::Image will not retain. 
    1025                 osg_image->setImage([ns_image_rep pixelsWide], [ns_image_rep pixelsHigh], 1,  GL_RGB, GL_RGB, GL_UNSIGNED_BYTE, [ns_image_rep bitmapData], osg::Image::NO_DELETE, 1); 
    1026         } 
    1027         else 
    1028         { 
    1029                 NSLog(@"Sorry, unsupported format in renderOpenGLSceneToFramebufferAsFormat"); 
    1030                 return nil; 
    1031         } 
    1032  
    1033         // Can't find a way to query Viewer for the current values, so recompute current view size. 
    1034         NSSize original_size_in_points = [self bounds].size; 
    1035         NSSize original_size_in_window_coordinates = [self convertSize:original_size_in_points toView:nil]; 
    1036 //      theViewer->getEventQueue()->windowResize(0, 0, original_size_in_window_coordinates.width, original_size_in_window_coordinates.height); 
    1037  
    1038         theViewer->getEventQueue()->windowResize(0, 0, viewport_width, viewport_height); 
    1039         graphicsWindow->resized(0, 0, viewport_width, viewport_height); 
    1040  
    1041         /* 
    1042         * I want to use a Framebuffer Object because it seems to be the OpenGL sanctioned way of rendering offscreen. 
    1043         * Also, I want to try to decouple the image capture from the onscreen rendering. This is potentially useful 
    1044         * for two reasons: 
    1045         * 1) You may want to customize the image dimensions to best fit the situation (consider printing to a page to fit) 
    1046         * 2) You may want to customize the scene for the target (consider special output for a printer, or removed data for a thumbnail) 
    1047         * Unfortunately, I have hit two problems. 
    1048         * 1) osg::Camera (which seems to be the way to access Framebuffer Objects in OSG) doesn't seem to capture if it is the root node. 
    1049         * The workaround is to copy the camera attributes into another camera, and then add a second camera node into the scene. 
    1050         * I'm hoping OSG will simplify this in the future. 
    1051         * 2) I may have encountered a bug. Under some circumstances, the offscreen renderbuffer seems to get drawn into the onscreen view 
    1052         * when using a DragImage for drag-and-drop. I reproduced a non-OSG example, but learned I missed two important FBO calls which trigger gl errors. 
    1053         * So I'm wondering if OSG made the same mistake. 
    1054         * But the problem doesn't seem critical. It just looks bad. 
    1055         */ 
    1056         //NSLog(@"Before camera glGetError: %s", gluErrorString(glGetError())); 
    1057         osg::Camera* root_camera = theViewer->getCamera(); 
    1058  
    1059         // I originally tried the clone() method and the copy construction, but it didn't work right, 
    1060         // so I manually copy the attributes. 
    1061         osg::Camera* the_camera = new osg::Camera; 
    1062  
    1063         the_camera->setClearMask(root_camera->getClearMask()); 
    1064         the_camera->setProjectionMatrix(root_camera->getProjectionMatrix()); 
    1065         the_camera->setViewMatrix(root_camera->getViewMatrix()); 
    1066         the_camera->setViewport(root_camera->getViewport()); 
    1067         the_camera->setClearColor( 
    1068                 osg::Vec4( 
    1069                         clear_red, 
    1070                         clear_green, 
    1071                         clear_blue, 
    1072                         clear_alpha 
    1073                 ) 
    1074         ); 
    1075  
    1076         // This must be ABSOLUTE_RF, and not a copy of the root camera because the transforms are additive. 
    1077         the_camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF); 
    1078  
    1079         // We need to insert the new (second) camera into the scene (below the root camera) and attach  
    1080         // the scene data to the new camera. 
    1081         osg::ref_ptr<osg::Node> root_node = theViewer->getSceneData(); 
    1082  
    1083         the_camera->addChild(root_node.get()); 
    1084         // Don't call (bypass) Viewer's setSceneData, but the underlying SceneView's setSceneData. 
    1085         // Otherwise, the camera position gets reset to the home position. 
    1086         theViewer->setSceneData(the_camera); 
    1087  
    1088         // set the camera to render before the main camera. 
    1089         the_camera->setRenderOrder(osg::Camera::PRE_RENDER); 
    1090  
    1091         // tell the camera to use OpenGL frame buffer object where supported. 
    1092         the_camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); 
    1093  
    1094  
    1095         // attach the image so its copied on each frame. 
    1096         the_camera->attach(osg::Camera::COLOR_BUFFER, osg_image.get()); 
    1097  
    1098  
    1099         //NSLog(@"Before frame(), glGetError: %s", gluErrorString(glGetError())); 
    1100  
    1101  
    1102         // Render the scene 
    1103         theViewer->frame(); 
    1104  
    1105         // Not sure if I really need this (seems to work without it), and if so, not sure if I need flush or finish 
    1106         glFlush(); 
    1107 //      glFinish(); 
    1108  
    1109         //NSLog(@"After flush(), glGetError: %s", gluErrorString(glGetError())); 
    1110  
    1111  
    1112  
    1113         // The image is upside-down to Cocoa, so invert it. 
    1114         osg_image.get()->flipVertical(); 
    1115  
    1116         // Clean up everything I changed 
    1117 //      the_camera->detach(osg::Camera::COLOR_BUFFER); 
    1118 //      the_camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER); 
    1119         // Don't call (bypass) Viewer's setSceneData, but the underlying SceneView's setSceneData. 
    1120         // Otherwise, the camera position gets reset to the home position. 
    1121         theViewer->setSceneData(root_node.get()); 
    1122         theViewer->getEventQueue()->windowResize(0, 0, original_size_in_window_coordinates.width, original_size_in_window_coordinates.height); 
    1123         graphicsWindow->resized(0, 0, original_size_in_window_coordinates.width, original_size_in_window_coordinates.height); 
    1124  
    1125  
    1126         // Ugh. Because of the bug I mentioned, I'm losing the picture in the display when I print. 
    1127         [self setNeedsDisplay:YES]; 
    1128         //NSLog(@"at return, glGetError: %s", gluErrorString(glGetError())); 
    1129  
    1130         return ns_image_rep; 
     954    // Round values and bring to closest integer. 
     955    int viewport_width = (int)(view_width + 0.5f); 
     956    int viewport_height = (int)(view_height + 0.5f); 
     957     
     958    NSBitmapImageRep* ns_image_rep; 
     959    osg::ref_ptr<osg::Image> osg_image = new osg::Image; 
     960     
     961    if(GL_RGBA == gl_format) 
     962    { 
     963        // Introduced in 10.4, but gives much better looking results if you utilize transparency 
     964        if([NSBitmapImageRep instancesRespondToSelector:@selector(initWithBitmapDataPlanes:pixelsWide:pixelsHigh:bitsPerSample:samplesPerPixel:hasAlpha:isPlanar:colorSpaceName:bitmapFormat:bytesPerRow:bitsPerPixel:)]) 
     965        { 
     966            ns_image_rep = [[[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL 
     967                                                  pixelsWide:viewport_width 
     968                                                  pixelsHigh:viewport_height 
     969                                               bitsPerSample:8 
     970                                            samplesPerPixel:4 
     971                                                    hasAlpha:YES 
     972                                                    isPlanar:NO 
     973                                              colorSpaceName:NSCalibratedRGBColorSpace 
     974                                                bitmapFormat:NSAlphaNonpremultipliedBitmapFormat // 10.4+, gives much better looking results if you utilize transparency 
     975                                                bytesPerRow:osg::Image::computeRowWidthInBytes(viewport_width, GL_RGBA, GL_UNSIGNED_BYTE, 1) 
     976                                                bitsPerPixel:32] 
     977                    autorelease]; 
     978        } 
     979        else // fallback for 10.0 to 10.3 
     980        { 
     981            ns_image_rep = [[[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL 
     982                                                  pixelsWide:viewport_width 
     983                                                  pixelsHigh:viewport_height 
     984                                               bitsPerSample:8 
     985                                            samplesPerPixel:4 
     986                                                    hasAlpha:YES 
     987                                                    isPlanar:NO 
     988                                              colorSpaceName:NSCalibratedRGBColorSpace 
     989                                                // bitmapFormat:NSAlphaNonpremultipliedBitmapFormat // 10.4+, gives much better looking results if you utilize transparency 
     990                                                bytesPerRow:osg::Image::computeRowWidthInBytes(viewport_width, GL_RGBA, GL_UNSIGNED_BYTE, 1) 
     991                                                bitsPerPixel:32] 
     992                    autorelease]; 
     993        } 
     994        // This is an optimization. Instead of creating data in both an osg::Image and NSBitmapImageRep, 
     995        // Allocate just the memory in the NSBitmapImageRep and give the osg::Image a reference to the data. 
     996        // I let NSBitmapImageRep control the memory because I think it will be easier to deal with  
     997        // memory management in the cases where it must interact with other Cocoa mechanisms like Drag-and-drop 
     998        // where the memory persistence is less obvious. Make sure that you don't expect to use the osg::Image 
     999        // outside the scope of this function because there is no telling when the data will be removed out 
     1000        // from under it by Cocoa since osg::Image will not retain. 
     1001        osg_image->setImage([ns_image_rep pixelsWide], [ns_image_rep pixelsHigh], 1,  GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, [ns_image_rep bitmapData], osg::Image::NO_DELETE, 1); 
     1002    } 
     1003    else if(GL_RGB == gl_format) 
     1004    { 
     1005        ns_image_rep = [[[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL 
     1006                                                  pixelsWide:viewport_width 
     1007                                                  pixelsHigh:viewport_height 
     1008                                               bitsPerSample:8 
     1009                                            samplesPerPixel:3 
     1010                                                    hasAlpha:NO 
     1011                                                    isPlanar:NO 
     1012                                              colorSpaceName:NSCalibratedRGBColorSpace 
     1013                                                // bitmapFormat:(NSBitmapFormat)0 // 10.4+ 
     1014                                                bytesPerRow:osg::Image::computeRowWidthInBytes(viewport_width, GL_RGB, GL_UNSIGNED_BYTE, 1) 
     1015                                                bitsPerPixel:24] 
     1016                    autorelease]; 
     1017 
     1018        // This is an optimization. Instead of creating data in both an osg::Image and NSBitmapImageRep, 
     1019        // Allocate just the memory in the NSBitmapImageRep and give the osg::Image a reference to the data. 
     1020        // I let NSBitmapImageRep control the memory because I think it will be easier to deal with  
     1021        // memory management in the cases where it must interact with other Cocoa mechanisms like Drag-and-drop 
     1022        // where the memory persistence is less obvious. Make sure that you don't expect to use the osg::Image 
     1023        // outside the scope of this function because there is no telling when the data will be removed out 
     1024        // from under it by Cocoa since osg::Image will not retain. 
     1025        osg_image->setImage([ns_image_rep pixelsWide], [ns_image_rep pixelsHigh], 1,  GL_RGB, GL_RGB, GL_UNSIGNED_BYTE, [ns_image_rep bitmapData], osg::Image::NO_DELETE, 1); 
     1026    } 
     1027    else 
     1028    { 
     1029        NSLog(@"Sorry, unsupported format in renderOpenGLSceneToFramebufferAsFormat"); 
     1030        return nil; 
     1031    } 
     1032 
     1033    // Can't find a way to query Viewer for the current values, so recompute current view size. 
     1034    NSSize original_size_in_points = [self bounds].size; 
     1035    NSSize original_size_in_window_coordinates = [self convertSize:original_size_in_points toView:nil]; 
     1036//    theViewer->getEventQueue()->windowResize(0, 0, original_size_in_window_coordinates.width, original_size_in_window_coordinates.height); 
     1037 
     1038    theViewer->getEventQueue()->windowResize(0, 0, viewport_width, viewport_height); 
     1039    graphicsWindow->resized(0, 0, viewport_width, viewport_height); 
     1040 
     1041    /* 
     1042    * I want to use a Framebuffer Object because it seems to be the OpenGL sanctioned way of rendering offscreen. 
     1043    * Also, I want to try to decouple the image capture from the onscreen rendering. This is potentially useful 
     1044    * for two reasons: 
     1045    * 1) You may want to customize the image dimensions to best fit the situation (consider printing to a page to fit) 
     1046    * 2) You may want to customize the scene for the target (consider special output for a printer, or removed data for a thumbnail) 
     1047    * Unfortunately, I have hit two problems. 
     1048    * 1) osg::Camera (which seems to be the way to access Framebuffer Objects in OSG) doesn't seem to capture if it is the root node. 
     1049    * The workaround is to copy the camera attributes into another camera, and then add a second camera node into the scene. 
     1050    * I'm hoping OSG will simplify this in the future. 
     1051    * 2) I may have encountered a bug. Under some circumstances, the offscreen renderbuffer seems to get drawn into the onscreen view 
     1052    * when using a DragImage for drag-and-drop. I reproduced a non-OSG example, but learned I missed two important FBO calls which trigger gl errors. 
     1053    * So I'm wondering if OSG made the same mistake. 
     1054    * But the problem doesn't seem critical. It just looks bad. 
     1055    */ 
     1056    //NSLog(@"Before camera glGetError: %s", gluErrorString(glGetError())); 
     1057    osg::Camera* root_camera = theViewer->getCamera(); 
     1058 
     1059    // I originally tried the clone() method and the copy construction, but it didn't work right, 
     1060    // so I manually copy the attributes. 
     1061    osg::Camera* the_camera = new osg::Camera; 
     1062 
     1063    the_camera->setClearMask(root_camera->getClearMask()); 
     1064    the_camera->setProjectionMatrix(root_camera->getProjectionMatrix()); 
     1065    the_camera->setViewMatrix(root_camera->getViewMatrix()); 
     1066    the_camera->setViewport(root_camera->getViewport()); 
     1067    the_camera->setClearColor( 
     1068        osg::Vec4( 
     1069            clear_red, 
     1070            clear_green, 
     1071            clear_blue, 
     1072            clear_alpha 
     1073        ) 
     1074    ); 
     1075 
     1076    // This must be ABSOLUTE_RF, and not a copy of the root camera because the transforms are additive. 
     1077    the_camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF); 
     1078 
     1079    // We need to insert the new (second) camera into the scene (below the root camera) and attach  
     1080    // the scene data to the new camera. 
     1081    osg::ref_ptr<osg::Node> root_node = theViewer->getSceneData(); 
     1082 
     1083    the_camera->addChild(root_node.get()); 
     1084    // Don't call (bypass) Viewer's setSceneData, but the underlying SceneView's setSceneData. 
     1085    // Otherwise, the camera position gets reset to the home position. 
     1086    theViewer->setSceneData(the_camera); 
     1087 
     1088    // set the camera to render before the main camera. 
     1089    the_camera->setRenderOrder(osg::Camera::PRE_RENDER); 
     1090 
     1091    // tell the camera to use OpenGL frame buffer object where supported. 
     1092    the_camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); 
     1093 
     1094 
     1095    // attach the image so its copied on each frame. 
     1096    the_camera->attach(osg::Camera::COLOR_BUFFER, osg_image.get()); 
     1097 
     1098 
     1099    //NSLog(@"Before frame(), glGetError: %s", gluErrorString(glGetError())); 
     1100 
     1101 
     1102    // Render the scene 
     1103    theViewer->frame(); 
     1104 
     1105    // Not sure if I really need this (seems to work without it), and if so, not sure if I need flush or finish 
     1106    glFlush(); 
     1107//    glFinish(); 
     1108 
     1109    //NSLog(@"After flush(), glGetError: %s", gluErrorString(glGetError())); 
     1110 
     1111 
     1112 
     1113    // The image is upside-down to Cocoa, so invert it. 
     1114    osg_image.get()->flipVertical(); 
     1115 
     1116    // Clean up everything I changed 
     1117//    the_camera->detach(osg::Camera::COLOR_BUFFER); 
     1118//    the_camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER); 
     1119    // Don't call (bypass) Viewer's setSceneData, but the underlying SceneView's setSceneData. 
     1120    // Otherwise, the camera position gets reset to the home position. 
     1121    theViewer->setSceneData(root_node.get()); 
     1122    theViewer->getEventQueue()->windowResize(0, 0, original_size_in_window_coordinates.width, original_size_in_window_coordinates.height); 
     1123    graphicsWindow->resized(0, 0, original_size_in_window_coordinates.width, original_size_in_window_coordinates.height); 
     1124 
     1125 
     1126    // Ugh. Because of the bug I mentioned, I'm losing the picture in the display when I print. 
     1127    [self setNeedsDisplay:YES]; 
     1128    //NSLog(@"at return, glGetError: %s", gluErrorString(glGetError())); 
     1129 
     1130    return ns_image_rep; 
    11311131} 
    11321132 
     
    11341134- (NSImage*)imageFromBitmapImageRep:(NSBitmapImageRep*)bitmap_image_rep 
    11351135{ 
    1136         if(nil == bitmap_image_rep) 
    1137         { 
    1138                 return nil; 
    1139         } 
    1140         NSImage* image = [[[NSImage alloc] initWithSize:[bitmap_image_rep size]] autorelease]; 
    1141         [image addRepresentation:bitmap_image_rep]; 
    1142         // This doesn't seem to work as I want it to. The image only gets flipped when rendered in a regular view. 
    1143         // It doesn't flip for the printer view. I must actually invert the pixels. 
    1144 //      [image setFlipped:YES]; 
    1145         return image; 
     1136    if(nil == bitmap_image_rep) 
     1137    { 
     1138        return nil; 
     1139    } 
     1140    NSImage* image = [[[NSImage alloc] initWithSize:[bitmap_image_rep size]] autorelease]; 
     1141    [image addRepresentation:bitmap_image_rep]; 
     1142    // This doesn't seem to work as I want it to. The image only gets flipped when rendered in a regular view. 
     1143    // It doesn't flip for the printer view. I must actually invert the pixels. 
     1144//    [image setFlipped:YES]; 
     1145    return image; 
    11461146} 
    11471147 
     
    11581158- (unsigned int) draggingEntered:(id <NSDraggingInfo>)the_sender 
    11591159{ 
    1160         if([the_sender draggingSource] != self) 
    1161         { 
    1162                 NSPasteboard* paste_board = [the_sender draggingPasteboard]; 
    1163                 // I respond to filename types or URL types 
    1164                 NSArray* supported_types = [NSArray arrayWithObjects:NSFilenamesPboardType, NSURLPboardType, nil]; 
    1165                 // If any of the supported types are being dragged in, activate the copy operation 
    1166                 NSString* first_type = [paste_board availableTypeFromArray:supported_types]; 
    1167                 if(first_type != nil) 
    1168                 { 
    1169                         return NSDragOperationCopy; 
    1170                 } 
    1171         } 
    1172         // Means we don't support this type 
    1173         return NSDragOperationNone; 
     1160    if([the_sender draggingSource] != self) 
     1161    { 
     1162        NSPasteboard* paste_board = [the_sender draggingPasteboard]; 
     1163        // I respond to filename types or URL types 
     1164        NSArray* supported_types = [NSArray arrayWithObjects:NSFilenamesPboardType, NSURLPboardType, nil]; 
     1165        // If any of the supported types are being dragged in, activate the copy operation 
     1166        NSString* first_type = [paste_board availableTypeFromArray:supported_types]; 
     1167        if(first_type != nil) 
     1168        { 
     1169            return NSDragOperationCopy; 
     1170        } 
     1171    } 
     1172    // Means we don't support this type 
     1173    return NSDragOperationNone; 
    11741174} 
    11751175 
     
    11811181- (BOOL) prepareForDragOperation:(id <NSDraggingInfo>)the_sender 
    11821182{ 
    1183         return YES; 
     1183    return YES; 
    11841184} 
    11851185 
    11861186- (BOOL) performDragOperation:(id <NSDraggingInfo>)the_sender 
    11871187{ 
    1188         NSPasteboard* paste_board = [the_sender draggingPasteboard]; 
     1188    NSPasteboard* paste_board = [the_sender draggingPasteboard]; 
    11891189 
    11901190  
    11911191    if([[paste_board types] containsObject:NSFilenamesPboardType]) 
    1192         { 
     1192    { 
    11931193        NSArray* file_names = [paste_board propertyListForType:NSFilenamesPboardType]; 
    11941194//        int number_of_files = [file_names count]; 
    1195                 // Exercise for the reader: Try loading all files in the array 
    1196                 NSString* single_file = [file_names objectAtIndex:0]; 
    1197             osg::ref_ptr<osg::Node> loaded_model = osgDB::readNodeFile([single_file fileSystemRepresentation]); 
    1198                 if(!loaded_model) 
    1199                 { 
    1200                         NSLog(@"File: %@ failed to load", single_file); 
    1201                         return NO; 
    1202                 } 
    1203                 theViewer->setSceneData(loaded_model.get()); 
    1204                 return YES; 
    1205     } 
    1206         else if([[paste_board types] containsObject:NSURLPboardType]) 
    1207         { 
    1208                 NSURL* file_url = [NSURL URLFromPasteboard:paste_board]; 
    1209                 // See if the URL is valid file path 
    1210                 if(![file_url isFileURL]) 
    1211                 { 
    1212                         NSLog(@"URL: %@ needs to be a file for readNodeFile()", file_url); 
    1213                         return NO; 
    1214                 } 
    1215                 NSString* file_path = [file_url path]; 
    1216             osg::ref_ptr<osg::Node> loaded_model = osgDB::readNodeFile([file_path fileSystemRepresentation]); 
    1217                 if(!loaded_model) 
    1218                 { 
    1219                         NSLog(@"URL: %@ failed to load, %@", file_url, file_path); 
    1220                         return NO; 
    1221                 } 
    1222                 theViewer->setSceneData(loaded_model.get()); 
    1223                 return YES; 
    1224         } 
     1195        // Exercise for the reader: Try loading all files in the array 
     1196        NSString* single_file = [file_names objectAtIndex:0]; 
     1197        osg::ref_ptr<osg::Node> loaded_model = osgDB::readNodeFile([single_file fileSystemRepresentation]); 
     1198        if(!loaded_model) 
     1199        { 
     1200            NSLog(@"File: %@ failed to load", single_file); 
     1201            return NO; 
     1202        } 
     1203        theViewer->setSceneData(loaded_model.get()); 
     1204        return YES; 
     1205    } 
     1206    else if([[paste_board types] containsObject:NSURLPboardType]) 
     1207    { 
     1208        NSURL* file_url = [NSURL URLFromPasteboard:paste_board]; 
     1209        // See if the URL is valid file path 
     1210        if(![file_url isFileURL]) 
     1211        { 
     1212            NSLog(@"URL: %@ needs to be a file for readNodeFile()", file_url); 
     1213            return NO; 
     1214        } 
     1215        NSString* file_path = [file_url path]; 
     1216        osg::ref_ptr<osg::Node> loaded_model = osgDB::readNodeFile([file_path fileSystemRepresentation]); 
     1217        if(!loaded_model) 
     1218        { 
     1219            NSLog(@"URL: %@ failed to load, %@", file_url, file_path); 
     1220            return NO; 
     1221        } 
     1222        theViewer->setSceneData(loaded_model.get()); 
     1223        return YES; 
     1224    } 
    12251225    return NO; 
    12261226} 
     
    12291229- (void) concludeDragOperation:(id <NSDraggingInfo>)the_sender 
    12301230{ 
    1231         [self setNeedsDisplay:YES]; 
     1231    [self setNeedsDisplay:YES]; 
    12321232} 
    12331233 
     
    12461246         
    12471247    if(image_data) 
    1248         { 
     1248    { 
    12491249        NSPasteboard* general_pboard = [NSPasteboard generalPasteboard]; 
    12501250        [general_pboard declareTypes:[NSArray arrayWithObjects:type, nil] owner: nil]; 
     
    12551255- (NSData*) dataWithTIFFOfContentView 
    12561256{ 
    1257         [[self openGLContext] makeCurrentContext]; 
    1258         NSBitmapImageRep * image = [self renderOpenGLSceneToFramebuffer]; 
    1259         NSData* data = nil; 
    1260  
    1261         if(image != nil) 
    1262         { 
    1263                 data = [image TIFFRepresentation]; 
    1264         } 
    1265         return data; 
     1257    [[self openGLContext] makeCurrentContext]; 
     1258    NSBitmapImageRep * image = [self renderOpenGLSceneToFramebuffer]; 
     1259    NSData* data = nil; 
     1260 
     1261    if(image != nil) 
     1262    { 
     1263        data = [image TIFFRepresentation]; 
     1264    } 
     1265    return data; 
    12661266} 
    12671267 
     
    12691269- (NSData*) contentsAsDataOfType:(NSString *)pboardType 
    12701270{ 
    1271         NSData * data = nil; 
    1272         if ([pboardType isEqualToString: NSTIFFPboardType] == YES) 
    1273         { 
    1274                 data = [self dataWithTIFFOfContentView]; 
    1275         } 
     1271    NSData * data = nil; 
     1272    if ([pboardType isEqualToString: NSTIFFPboardType] == YES) 
     1273    { 
     1274        data = [self dataWithTIFFOfContentView]; 
     1275    } 
    12761276    return data; 
    12771277} 
     
    12801280- (void) startDragAndDropAsSource:(NSEvent*)the_event 
    12811281{ 
    1282         NSPasteboard* drag_paste_board; 
    1283         NSImage* the_image; 
    1284         NSSize the_size; 
    1285         NSPoint the_point; 
    1286  
    1287         NSSize size_in_points = [self bounds].size; 
    1288         NSSize size_in_window_coordinates = [self convertSize:size_in_points toView:nil]; 
    1289  
    1290         // Create the image that will be dragged 
    1291         NSString * type = NSTIFFPboardType; 
    1292  
    1293         [[self openGLContext] makeCurrentContext]; 
    1294  
    1295         // I want two images. One to be rendered for the target, and one as the drag-image. 
    1296         // I want the drag-image to be translucent. 
    1297         // I think this is where render GL_COLOR_ATTACHMENTn (COLOR_BUFFERn?) would be handy. 
    1298         // But my hardware only returns 1 for glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, maxbuffers); 
    1299         // So I won't bother and will just render twice. 
    1300         NSBitmapImageRep* bitmap_image_rep = [self renderOpenGLSceneToFramebufferAsFormat:GL_RGB viewWidth:size_in_window_coordinates.width viewHeight:size_in_window_coordinates.height]; 
    1301         NSBitmapImageRep* bitmap_image_rep_transparent_copy = [self renderOpenGLSceneToFramebufferAsFormat:GL_RGBA viewWidth:size_in_window_coordinates.width viewHeight:size_in_window_coordinates.height]; 
    1302 //      NSBitmapImageRep* bitmap_image_rep = [self renderOpenGLSceneToFramebufferAsFormat:GL_RGBA viewWidth:size_in_window_coordinates.width viewHeight:size_in_window_coordinates.height clearColorRed:1.0f clearColorGreen:1.0f clearColorBlue:0.0f clearColorAlpha:0.4f]; 
     1282    NSPasteboard* drag_paste_board; 
     1283    NSImage* the_image; 
     1284    NSSize the_size; 
     1285    NSPoint the_point; 
     1286 
     1287    NSSize size_in_points = [self bounds].size; 
     1288    NSSize size_in_window_coordinates = [self convertSize:size_in_points toView:nil]; 
     1289 
     1290    // Create the image that will be dragged 
     1291    NSString * type = NSTIFFPboardType; 
     1292 
     1293    [[self openGLContext] makeCurrentContext]; 
     1294 
     1295    // I want two images. One to be rendered for the target, and one as the drag-image. 
     1296    // I want the drag-image to be translucent. 
     1297    // I think this is where render GL_COLOR_ATTACHMENTn (COLOR_BUFFERn?) would be handy. 
     1298    // But my hardware only returns 1 for glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, maxbuffers); 
     1299    // So I won't bother and will just render twice. 
     1300    NSBitmapImageRep* bitmap_image_rep = [self renderOpenGLSceneToFramebufferAsFormat:GL_RGB viewWidth:size_in_window_coordinates.width viewHeight:size_in_window_coordinates.height]; 
     1301    NSBitmapImageRep* bitmap_image_rep_transparent_copy = [self renderOpenGLSceneToFramebufferAsFormat:GL_RGBA viewWidth:size_in_window_coordinates.width viewHeight:size_in_window_coordinates.height]; 
     1302//    NSBitmapImageRep* bitmap_image_rep = [self renderOpenGLSceneToFramebufferAsFormat:GL_RGBA viewWidth:size_in_window_coordinates.width viewHeight:size_in_window_coordinates.height clearColorRed:1.0f clearColorGreen:1.0f clearColorBlue:0.0f clearColorAlpha:0.4f]; 
    13031303 
    13041304//NSBitmapImageRep* bitmap_image_rep_transparent_copy = bitmap_image_rep; 
    13051305 
    1306         // 0x32 is an arbitrary number. Basically, I want something between 0 and 0xFF. 
    1307         Internal_SetAlpha(bitmap_image_rep_transparent_copy, 0x32); 
    1308  
    1309         NSData* image_data = [bitmap_image_rep TIFFRepresentation]; 
     1306    // 0x32 is an arbitrary number. Basically, I want something between 0 and 0xFF. 
     1307    Internal_SetAlpha(bitmap_image_rep_transparent_copy, 0x32); 
     1308 
     1309    NSData* image_data = [bitmap_image_rep TIFFRepresentation]; 
    13101310 
    13111311    if(image_data) 
    1312         { 
    1313          
    1314                 drag_paste_board = [NSPasteboard pasteboardWithName:NSDragPboard]; 
    1315                 // is owner:self or nil? (Hillegass says self) 
     1312    { 
     1313     
     1314        drag_paste_board = [NSPasteboard pasteboardWithName:NSDragPboard]; 
     1315        // is owner:self or nil? (Hillegass says self) 
    13161316        [drag_paste_board declareTypes: [NSArray arrayWithObjects: type, nil] owner: self]; 
    13171317        [drag_paste_board setData:image_data forType: type]; 
    1318                  
    1319                 // create an image from the data 
    1320                 the_image = [[NSImage alloc] initWithData:[bitmap_image_rep_transparent_copy TIFFRepresentation]]; 
    1321                  
    1322                 the_point = [self convertPoint:[the_event locationInWindow] fromView:nil]; 
    1323                 the_size = [the_image size]; 
    1324                  
    1325                 // shift the point to the center of the image 
    1326                 the_point.x = the_point.x - the_size.width/2.0; 
    1327                 the_point.y = the_point.y - the_size.height/2.0; 
    1328  
    1329                 // start drag 
    1330                 [self dragImage:the_image 
    1331                                         at:the_point 
    1332                                 offset:NSMakeSize(0,0) 
    1333                                   event:the_event 
    1334                         pasteboard:drag_paste_board 
    1335                                 source:self 
    1336                           slideBack:YES]; 
    1337                            
    1338                 [the_image release]; 
    1339         } 
    1340         else 
    1341         { 
    1342                 NSLog(@"Error, failed to create image data"); 
    1343         } 
    1344          
     1318         
     1319        // create an image from the data 
     1320        the_image = [[NSImage alloc] initWithData:[bitmap_image_rep_transparent_copy TIFFRepresentation]]; 
     1321         
     1322        the_point = [self convertPoint:[the_event locationInWindow] fromView:nil]; 
     1323        the_size = [the_image size]; 
     1324         
     1325        // shift the point to the center of the image 
     1326        the_point.x = the_point.x - the_size.width/2.0; 
     1327        the_point.y = the_point.y - the_size.height/2.0; 
     1328 
     1329        // start drag 
     1330        [self dragImage:the_image 
     1331                    at:the_point 
     1332                offset:NSMakeSize(0,0) 
     1333                  event:the_event 
     1334            pasteboard:drag_paste_board 
     1335                source:self 
     1336              slideBack:YES]; 
     1337               
     1338        [the_image release]; 
     1339    } 
     1340    else 
     1341    { 
     1342        NSLog(@"Error, failed to create image data"); 
     1343    } 
     1344     
    13451345} 
    13461346 
     
    13611361- (IBAction) resetPosition:(id)the_sender 
    13621362{ 
    1363         //      osgGA::MatrixManipulator* camera_manipulator = theViewer->getCameraManipulator(); 
    1364         // This only resets the position 
    1365         //      camera_manipulator->home(0.0); 
    1366          
    1367         // There is no external API from SimpleViewer that I can see that will stop movement. 
    1368         // So fake the 'spacebar' to stop things and reset. 
    1369         // (Changed in Viewer?) 
    1370         //      printf("I'am here");  
    1371          
    1372         // Reset to start position 
    1373         theViewer->home(); 
    1374         [self setNeedsDisplay:YES]; 
     1363    //    osgGA::MatrixManipulator* camera_manipulator = theViewer->getCameraManipulator(); 
     1364    // This only resets the position 
     1365    //    camera_manipulator->home(0.0); 
     1366     
     1367    // There is no external API from SimpleViewer that I can see that will stop movement. 
     1368    // So fake the 'spacebar' to stop things and reset. 
     1369    // (Changed in Viewer?) 
     1370    //    printf("I'am here");  
     1371     
     1372    // Reset to start position 
     1373    theViewer->home(); 
     1374    [self setNeedsDisplay:YES]; 
    13751375} 
    13761376 
     
    13811381- (IBAction) takeBackgroundColorFrom:(id)the_sender 
    13821382{ 
    1383         NSColor* the_color = [the_sender color]; 
    1384  
    1385         theViewer->getCamera()->setClearColor( 
    1386                 osg::Vec4( 
    1387                         [the_color redComponent], 
    1388                         [the_color greenComponent], 
    1389                         [the_color blueComponent], 
    1390                         [the_color alphaComponent] 
    1391                 ) 
    1392         ); 
    1393         [self setNeedsDisplay:YES]; 
     1383    NSColor* the_color = [the_sender color]; 
     1384 
     1385    theViewer->getCamera()->setClearColor( 
     1386        osg::Vec4( 
     1387            [the_color redComponent], 
     1388            [the_color greenComponent], 
     1389            [the_color blueComponent], 
     1390            [the_color alphaComponent] 
     1391        ) 
     1392    ); 
     1393    [self setNeedsDisplay:YES]; 
    13941394} 
    13951395 
    13961396- (IBAction) toggleFullScreen:(id)the_sender 
    13971397{ 
    1398         // I'm lazy and rather use the new 10.5 Cocoa Fullscreen API. 
    1399         // For now, no legacy support for fullscreen. 
    1400         // One of the cool things about Obj-C is dynamic/late binding. 
    1401         // We can compile and run this code on versions prior to 10.5. 
    1402         // At run-time, we check to see if these methods actually exist 
    1403         // and if they do, we message them. If not, we avoid them. 
    1404         if([self respondsToSelector:@selector(isInFullScreenMode)]) 
    1405         { 
    1406                 if([self isInFullScreenMode]) 
    1407                 { 
    1408                         [self exitFullScreenModeWithOptions:nil]; 
    1409                 } 
    1410                 else 
    1411                 { 
    1412                         [self enterFullScreenMode:[NSScreen mainScreen] withOptions:nil]; 
    1413                 } 
    1414         } 
     1398    // I'm lazy and rather use the new 10.5 Cocoa Fullscreen API. 
     1399    // For now, no legacy support for fullscreen. 
     1400    // One of the cool things about Obj-C is dynamic/late binding. 
     1401    // We can compile and run this code on versions prior to 10.5. 
     1402    // At run-time, we check to see if these methods actually exist 
     1403    // and if they do, we message them. If not, we avoid them. 
     1404    if([self respondsToSelector:@selector(isInFullScreenMode)]) 
     1405    { 
     1406        if([self isInFullScreenMode]) 
     1407        { 
     1408            [self exitFullScreenModeWithOptions:nil]; 
     1409        } 
     1410        else 
     1411        { 
     1412            [self enterFullScreenMode:[NSScreen mainScreen] withOptions:nil]; 
     1413        } 
     1414    } 
    14151415} 
    14161416