- Timestamp:
- 06/21/08 13:34:01 (5 years ago)
- Files:
-
- 1 modified
Legend:
- Unmodified
- Added
- Removed
-
OpenSceneGraph/trunk/examples/osgviewerCocoa/ViewerCocoa.mm
r7655 r8483 137 137 static void Internal_SetAlpha(NSBitmapImageRep *imageRep, unsigned char alpha_value) 138 138 { 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 } 161 161 } 162 162 … … 167 167 + (NSOpenGLPixelFormat*) basicPixelFormat 168 168 { 169 NSOpenGLPixelFormatAttribute pixel_attributes[] =170 {171 NSOpenGLPFAWindow,172 NSOpenGLPFADoubleBuffer, // double buffered173 NSOpenGLPFADepthSize, (NSOpenGLPixelFormatAttribute)32, // depth buffer size in bits174 // NSOpenGLPFAColorSize, (NSOpenGLPixelFormatAttribute)24, // Not sure if this helps175 // NSOpenGLPFAAlphaSize, (NSOpenGLPixelFormatAttribute)8, // Not sure if this helps176 (NSOpenGLPixelFormatAttribute)nil169 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 177 177 }; 178 178 return [[[NSOpenGLPixelFormat alloc] initWithAttributes:pixel_attributes] autorelease]; … … 191 191 - (id) initWithFrame:(NSRect)frame_rect pixelFormat:(NSOpenGLPixelFormat*)pixel_format 192 192 { 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; 199 199 } 200 200 … … 209 209 - (id) initWithCoder:(NSCoder*)the_coder 210 210 { 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; 219 219 } 220 220 … … 224 224 - (id) initWithFrame:(NSRect)frame_rect 225 225 { 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; 232 232 } 233 233 … … 236 236 - (void) commonInit 237 237 { 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 Drop248 [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 250 250 // 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]; 252 252 253 253 } … … 260 260 #ifdef VIEWER_USE_SHARED_CONTEXTS 261 261 262 NSOpenGLContext* this_views_opengl_context = nil;263 264 // create a context the first time through265 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] 268 268 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] 274 274 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]; 278 278 #endif // VIEWER_USE_SHARED_CONTEXTS 279 279 } … … 285 285 286 286 287 // osg::setNotifyLevel( osg::DEBUG_FP );288 theViewer = new osgViewer::Viewer;289 graphicsWindow = theViewer->setUpViewerAsEmbeddedInWindow(0,0,740,650); // numbers from Nib290 // Builts in Stats handler291 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); 292 292 #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. 296 296 graphicsWindow->getState()->setContextID(0); 297 osg::DisplaySettings::instance()->setMaxNumberOfGraphicsContexts(1);297 osg::DisplaySettings::instance()->setMaxNumberOfGraphicsContexts(1); 298 298 #endif // VIEWER_USE_SHARED_CONTEXTS 299 299 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 305 305 } 306 306 307 307 - (void) initAnimationTimer 308 308 { 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 method315 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 = [NSTimer322 scheduledTimerWithTimeInterval:1.0/60.0 // fps323 invocation:an_invocation324 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 seen329 // 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 to332 // specify the modes to avoid the blockage.333 // NSDefaultRunLoopMode seems to be the default. I don't think I need to explicitly334 // 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]; 340 340 } 341 341 342 342 - (void) dealloc 343 343 { 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]; 349 349 } 350 350 351 351 - (void) finalize 352 352 { 353 delete theViewer;354 theViewer = NULL;355 [super finalize];353 delete theViewer; 354 theViewer = NULL; 355 [super finalize]; 356 356 } 357 357 … … 365 365 - (void) prepareOpenGL 366 366 { 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 ; 372 372 [[self openGLContext] setValues:&swap_interval forParameter:NSOpenGLCPSwapInterval]; 373 373 374 374 375 // Try new multithreaded OpenGL engine?376 // See Technical Note TN2085 Enabling multi-threaded execution of the OpenGL framework377 // http://developer.apple.com/technotes/tn2006/tn2085.html378 // 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 check384 // 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 engine391 // 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 else401 {402 // NSLog(@"Success! Multithreaded OpenGL Engine activated!");403 isUsingMultithreadedOpenGLEngine = YES;404 }405 }406 else407 {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); 417 417 418 418 /* 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]); 422 422 */ 423 423 424 // We need to tell the osgViewer what the viewport size is425 [self resizeViewport];426 427 428 // This is optional:429 // This is to setup some default text in the OpenGL view so the430 // 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; 432 432 433 433 default_text->setAlignment(osgText::Text::CENTER_CENTER); 434 434 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)); 438 438 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()); 450 450 } 451 451 … … 467 467 NSWindow* the_window = [self window]; 468 468 if([the_window respondsToSelector:@selector(disableScreenUpdatesUntilFlush)]) 469 {470 [the_window disableScreenUpdatesUntilFlush];469 { 470 [the_window disableScreenUpdatesUntilFlush]; 471 471 } 472 472 [super renewGState]; … … 482 482 - (void) prepareForMiniaturization:(NSNotification*)notification 483 483 { 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 } 492 492 } 493 493 … … 496 496 - (BOOL) isUsingMultithreadedOpenGLEngine 497 497 { 498 return isUsingMultithreadedOpenGLEngine;498 return isUsingMultithreadedOpenGLEngine; 499 499 } 500 500 … … 512 512 - (void) mouseDown:(NSEvent*)the_event 513 513 { 514 // Because many Mac users have only a 1-button mouse, we should provide ways515 // to access the button 2 and 3 actions of osgViewer.516 // I will use the Ctrl modifer to represent right-clicking517 // 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 else533 {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 } 536 536 } 537 537 538 538 - (void) mouseDragged:(NSEvent*)the_event 539 539 { 540 // We must convert the mouse event locations from the window coordinate system to the541 // 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]; 543 543 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]; 547 547 } 548 548 549 549 - (void) mouseUp:(NSEvent*)the_event 550 550 { 551 // Because many Mac users have only a 1-button mouse, we should provide ways552 // to access the button 2 and 3 actions of osgViewer.553 // I will use the Ctrl modifer to represent right-clicking554 // 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 else566 {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 } 569 569 } 570 570 571 571 - (void) rightMouseDown:(NSEvent*)the_event 572 572 { 573 [self doRightMouseButtonDown:the_event];573 [self doRightMouseButtonDown:the_event]; 574 574 } 575 575 576 576 - (void) rightMouseDragged:(NSEvent*)the_event 577 577 { 578 // We must convert the mouse event locations from the window coordinate system to the579 // 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]; 581 581 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]; 585 585 } 586 586 587 587 - (void) rightMouseUp:(NSEvent*)the_event 588 588 { 589 [self doRightMouseButtonUp:the_event];589 [self doRightMouseButtonUp:the_event]; 590 590 } 591 591 … … 593 593 - (void) otherMouseDown:(NSEvent*)the_event 594 594 { 595 // Button 0 is left596 // Button 1 is right597 // Button 2 is middle598 // Button 3 keeps going599 // osgViewer expects 1 for left, 3 for right, 2 for middle600 // osgViewer has a reversed number mapping for right and middle compared to Cocoa601 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 osgViewer606 {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 } 609 609 } 610 610 611 611 - (void) otherMouseDragged:(NSEvent*)the_event 612 612 { 613 // We must convert the mouse event locations from the window coordinate system to the614 // 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]; 616 616 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]; 620 620 } 621 621 … … 623 623 - (void) otherMouseUp:(NSEvent*)the_event 624 624 { 625 // Button 0 is left626 // Button 1 is right627 // Button 2 is middle628 // Button 3 keeps going629 // osgViewer expects 1 for left, 3 for right, 2 for middle630 // osgViewer has a reversed number mapping for right and middle compared to Cocoa631 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 osgViewer636 {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 might639 // 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]]; 641 641 } 642 642 643 643 - (void) setIsUsingCtrlClick:(BOOL)is_using_ctrl_click 644 644 { 645 isUsingCtrlClick = is_using_ctrl_click;645 isUsingCtrlClick = is_using_ctrl_click; 646 646 } 647 647 648 648 - (BOOL) isUsingCtrlClick 649 649 { 650 return isUsingCtrlClick;650 return isUsingCtrlClick; 651 651 } 652 652 653 653 - (void) setIsUsingOptionClick:(BOOL)is_using_option_click 654 654 { 655 isUsingOptionClick = is_using_option_click;655 isUsingOptionClick = is_using_option_click; 656 656 } 657 657 658 658 - (BOOL) isUsingOptionClick 659 659 { 660 return isUsingOptionClick;660 return isUsingOptionClick; 661 661 } 662 662 … … 664 664 - (void) doLeftMouseButtonDown:(NSEvent*)the_event 665 665 { 666 // We must convert the mouse event locations from the window coordinate system to the667 // 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]; 669 669 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 else675 {676 theViewer->getEventQueue()->mouseDoubleButtonPress(converted_point.x, converted_point.y, 1);677 678 679 // Let's toggle fullscreen for show680 [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]; 684 684 } 685 685 686 686 - (void) doLeftMouseButtonUp:(NSEvent*)the_event 687 687 { 688 // We must convert the mouse event locations from the window coordinate system to the689 // 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]; 691 691 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]; 695 695 } 696 696 697 697 - (void) doRightMouseButtonDown:(NSEvent*)the_event 698 698 { 699 // We must convert the mouse event locations from the window coordinate system to the700 // 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]; 702 702 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 else708 {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]; 712 712 } 713 713 … … 715 715 - (void) doRightMouseButtonUp:(NSEvent*)the_event 716 716 { 717 // We must convert the mouse event locations from the window coordinate system to the718 // 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]; 720 720 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]; 724 724 } 725 725 726 726 - (void) doMiddleMouseButtonDown:(NSEvent*)the_event 727 727 { 728 // We must convert the mouse event locations from the window coordinate system to the729 // 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]; 731 731 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 else738 {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]; 742 742 } 743 743 744 744 - (void) doExtraMouseButtonDown:(NSEvent*)the_event buttonNumber:(int)button_number 745 745 { 746 // We must convert the mouse event locations from the window coordinate system to the747 // 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]; 749 749 NSPoint converted_point = [self convertPoint:the_point fromView:nil]; 750 750 751 if([the_event clickCount] == 1)752 {753 theViewer->getEventQueue()->mouseButtonPress(converted_point.x, converted_point.y, button_number+1);754 }755 else756 {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]; 760 760 } 761 761 … … 763 763 - (void) doMiddleMouseButtonUp:(NSEvent*)the_event 764 764 { 765 // We must convert the mouse event locations from the window coordinate system to the766 // 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]; 771 771 } 772 772 773 773 - (void) doExtraMouseButtonUp:(NSEvent*)the_event buttonNumber:(int)button_number 774 774 { 775 // We must convert the mouse event locations from the window coordinate system to the776 // 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]; 782 782 } 783 783 … … 792 792 - (void) scrollWheel:(NSEvent*)the_event 793 793 { 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]; 807 807 } 808 808 … … 817 817 - (BOOL) acceptsFirstResponder 818 818 { 819 return YES;819 return YES; 820 820 } 821 821 822 822 - (void) keyDown:(NSEvent*)the_event 823 823 { 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]; 833 833 } 834 834 835 835 - (void) keyUp:(NSEvent*)the_event 836 836 { 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]; 843 843 } 844 844 … … 854 854 - (void) animationCallback 855 855 { 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]; 859 859 } 860 860 … … 863 863 - (BOOL) isOpaque 864 864 { 865 return YES;865 return YES; 866 866 } 867 867 … … 870 870 - (void) resizeViewport 871 871 { 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); 877 877 } 878 878 … … 880 880 - (void) reshape 881 881 { 882 [super reshape];883 [self resizeViewport];882 [super reshape]; 883 [self resizeViewport]; 884 884 } 885 885 … … 890 890 - (void) drawRect:(NSRect)the_rect 891 891 { 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 case899 {900 [[self openGLContext] makeCurrentContext];901 902 // FIXME: We should be computing a size that fits best to the paper target903 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: NSCompositeSourceOver915 operation: NSCompositeCopy916 fraction: 1.0]; 917 }918 else919 {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 } 923 923 } 924 924 … … 932 932 - (NSBitmapImageRep*) renderOpenGLSceneToFramebuffer 933 933 { 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]]; 939 939 } 940 940 … … 942 942 - (NSBitmapImageRep*) renderOpenGLSceneToFramebufferAsFormat:(int)gl_format viewWidth:(float)view_width viewHeight:(float)view_height 943 943 { 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]]; 947 947 } 948 948 … … 952 952 - (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 953 953 { 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 transparency964 if([NSBitmapImageRep instancesRespondToSelector:@selector(initWithBitmapDataPlanes:pixelsWide:pixelsHigh:bitsPerSample:samplesPerPixel:hasAlpha:isPlanar:colorSpaceName:bitmapFormat:bytesPerRow:bitsPerPixel:)])965 {966 ns_image_rep = [[[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL967 pixelsWide:viewport_width968 pixelsHigh:viewport_height969 bitsPerSample:8970 samplesPerPixel:4971 hasAlpha:YES972 isPlanar:NO973 colorSpaceName:NSCalibratedRGBColorSpace974 bitmapFormat:NSAlphaNonpremultipliedBitmapFormat // 10.4+, gives much better looking results if you utilize transparency975 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.3980 {981 ns_image_rep = [[[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL982 pixelsWide:viewport_width983 pixelsHigh:viewport_height984 bitsPerSample:8985 samplesPerPixel:4986 hasAlpha:YES987 isPlanar:NO988 colorSpaceName:NSCalibratedRGBColorSpace989 // bitmapFormat:NSAlphaNonpremultipliedBitmapFormat // 10.4+, gives much better looking results if you utilize transparency990 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 with997 // memory management in the cases where it must interact with other Cocoa mechanisms like Drag-and-drop998 // where the memory persistence is less obvious. Make sure that you don't expect to use the osg::Image999 // outside the scope of this function because there is no telling when the data will be removed out1000 // 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:NULL1006 pixelsWide:viewport_width1007 pixelsHigh:viewport_height1008 bitsPerSample:81009 samplesPerPixel:31010 hasAlpha:NO1011 isPlanar:NO1012 colorSpaceName:NSCalibratedRGBColorSpace1013 // 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 with1021 // memory management in the cases where it must interact with other Cocoa mechanisms like Drag-and-drop1022 // where the memory persistence is less obvious. Make sure that you don't expect to use the osg::Image1023 // outside the scope of this function because there is no telling when the data will be removed out1024 // 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 else1028 {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 useful1044 * 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 view1052 * 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_alpha1073 )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 attach1080 // 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 scene1103 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 finish1106 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 changed1117 // 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; 1131 1131 } 1132 1132 … … 1134 1134 - (NSImage*)imageFromBitmapImageRep:(NSBitmapImageRep*)bitmap_image_rep 1135 1135 { 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; 1146 1146 } 1147 1147 … … 1158 1158 - (unsigned int) draggingEntered:(id <NSDraggingInfo>)the_sender 1159 1159 { 1160 if([the_sender draggingSource] != self)1161 {1162 NSPasteboard* paste_board = [the_sender draggingPasteboard];1163 // I respond to filename types or URL types1164 NSArray* supported_types = [NSArray arrayWithObjects:NSFilenamesPboardType, NSURLPboardType, nil];1165 // If any of the supported types are being dragged in, activate the copy operation1166 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 type1173 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; 1174 1174 } 1175 1175 … … 1181 1181 - (BOOL) prepareForDragOperation:(id <NSDraggingInfo>)the_sender 1182 1182 { 1183 return YES;1183 return YES; 1184 1184 } 1185 1185 1186 1186 - (BOOL) performDragOperation:(id <NSDraggingInfo>)the_sender 1187 1187 { 1188 NSPasteboard* paste_board = [the_sender draggingPasteboard];1188 NSPasteboard* paste_board = [the_sender draggingPasteboard]; 1189 1189 1190 1190 1191 1191 if([[paste_board types] containsObject:NSFilenamesPboardType]) 1192 {1192 { 1193 1193 NSArray* file_names = [paste_board propertyListForType:NSFilenamesPboardType]; 1194 1194 // int number_of_files = [file_names count]; 1195 // Exercise for the reader: Try loading all files in the array1196 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 path1210 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 } 1225 1225 return NO; 1226 1226 } … … 1229 1229 - (void) concludeDragOperation:(id <NSDraggingInfo>)the_sender 1230 1230 { 1231 [self setNeedsDisplay:YES];1231 [self setNeedsDisplay:YES]; 1232 1232 } 1233 1233 … … 1246 1246 1247 1247 if(image_data) 1248 {1248 { 1249 1249 NSPasteboard* general_pboard = [NSPasteboard generalPasteboard]; 1250 1250 [general_pboard declareTypes:[NSArray arrayWithObjects:type, nil] owner: nil]; … … 1255 1255 - (NSData*) dataWithTIFFOfContentView 1256 1256 { 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; 1266 1266 } 1267 1267 … … 1269 1269 - (NSData*) contentsAsDataOfType:(NSString *)pboardType 1270 1270 { 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 } 1276 1276 return data; 1277 1277 } … … 1280 1280 - (void) startDragAndDropAsSource:(NSEvent*)the_event 1281 1281 { 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 dragged1291 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]; 1303 1303 1304 1304 //NSBitmapImageRep* bitmap_image_rep_transparent_copy = bitmap_image_rep; 1305 1305 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]; 1310 1310 1311 1311 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) 1316 1316 [drag_paste_board declareTypes: [NSArray arrayWithObjects: type, nil] owner: self]; 1317 1317 [drag_paste_board setData:image_data forType: type]; 1318 1319 // create an image from the data1320 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 image1326 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 drag1330 [self dragImage:the_image1331 at:the_point1332 offset:NSMakeSize(0,0)1333 event:the_event1334 pasteboard:drag_paste_board1335 source:self1336 slideBack:YES];1337 1338 [the_image release];1339 }1340 else1341 {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 1345 1345 } 1346 1346 … … 1361 1361 - (IBAction) resetPosition:(id)the_sender 1362 1362 { 1363 //osgGA::MatrixManipulator* camera_manipulator = theViewer->getCameraManipulator();1364 // This only resets the position1365 //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 position1373 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]; 1375 1375 } 1376 1376 … … 1381 1381 - (IBAction) takeBackgroundColorFrom:(id)the_sender 1382 1382 { 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]; 1394 1394 } 1395 1395 1396 1396 - (IBAction) toggleFullScreen:(id)the_sender 1397 1397 { 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 exist1403 // 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 else1411 {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 } 1415 1415 } 1416 1416
