#include #include #import #import #if OSG_GLES1_FEATURES #import #else #import #if defined(OSG_GLES3_FEATURES) #import #endif // in GLES2, the OES suffix if dropped from function names (from rti) #define glGenFramebuffersOES glGenFramebuffers #define glGenRenderbuffersOES glGenRenderbuffers #define glBindFramebufferOES glBindFramebuffer #define glBindRenderbufferOES glBindRenderbuffer #define glFramebufferRenderbufferOES glFramebufferRenderbuffer #define glGetRenderbufferParameterivOES glGetRenderbufferParameteriv #define glRenderbufferStorageOES glRenderbufferStorage #define glDeleteRenderbuffersOES glDeleteRenderbuffers #define glDeleteFramebuffersOES glDeleteFramebuffers #define glCheckFramebufferStatusOES glCheckFramebufferStatus #define GL_FRAMEBUFFER_OES GL_FRAMEBUFFER #define GL_RENDERBUFFER_OES GL_RENDERBUFFER #define GL_RENDERBUFFER_WIDTH_OES GL_RENDERBUFFER_WIDTH #define GL_RENDERBUFFER_HEIGHT_OES GL_RENDERBUFFER_HEIGHT #define GL_COLOR_ATTACHMENT0_OES GL_COLOR_ATTACHMENT0 #define GL_DEPTH_ATTACHMENT_OES GL_DEPTH_ATTACHMENT #define GL_DEPTH_COMPONENT16_OES GL_DEPTH_COMPONENT16 #define GL_STENCIL_INDEX8_OES GL_STENCIL_INDEX8 #define GL_FRAMEBUFFER_COMPLETE_OES GL_FRAMEBUFFER_COMPLETE #define GL_STENCIL_ATTACHMENT_OES GL_STENCIL_ATTACHMENT #define GL_RGB5_A1_OES GL_RGB5_A1 #endif #include "IOSUtils.h" #pragma mark GraphicsWindowIOSWindow // ---------------------------------------------------------------------------------------------------------- // GraphicsWindowIOSWindow, implements canBecomeKeyWindow + canBecomeMainWindow // ---------------------------------------------------------------------------------------------------------- @interface GraphicsWindowIOSWindow : UIWindow { } - (BOOL) canBecomeKeyWindow; - (BOOL) canBecomeMainWindow; @end @implementation GraphicsWindowIOSWindow // //Implement dealloc // - (void) dealloc { [super dealloc]; } - (BOOL) canBecomeKeyWindow { return YES; } - (BOOL) canBecomeMainWindow { return YES; } @end #pragma mark GraphicsWindowIOSGLView // ---------------------------------------------------------------------------------------------------------- // GraphicsWindowIOSGLView // custom UIView-class handling creation and display of frame/render buffers plus receives touch input // ---------------------------------------------------------------------------------------------------------- typedef std::map TouchPointsIdMapping; @interface GraphicsWindowIOSGLView : UIView { @private osgViewer::GraphicsWindowIOS* _win; EAGLContext* _context; /* The pixel dimensions of the backbuffer */ GLint _backingWidth; GLint _backingHeight; //the pixel buffers for the video /* OpenGL names for the renderbuffer and framebuffers used to render to this view */ GLuint _viewRenderbuffer, _viewFramebuffer; /* OpenGL name for the depth buffer that is attached to viewFramebuffer, if it exists (0 if it does not exist) */ GLuint _depthRenderbuffer; /* OpenGL name for the stencil buffer that is attached to viewFramebuffer, if it exists (0 if it does not exist) */ GLuint _stencilBuffer; // for multisampled antialiased rendering GLuint _msaaFramebuffer, _msaaRenderBuffer, _msaaDepthBuffer; TouchPointsIdMapping* _touchPointsIdMapping; unsigned int _lastTouchPointId; } - (void)setGraphicsWindow: (osgViewer::GraphicsWindowIOS*) win; - (osgViewer::GraphicsWindowIOS*) getGraphicsWindow; - (void)setOpenGLContext: (EAGLContext*) context; - (void)updateDimensions; - (BOOL)createFramebuffer; - (void)destroyFramebuffer; - (void)swapBuffers; - (void)bindFrameBuffer; - (BOOL)acceptsFirstResponder; - (BOOL)becomeFirstResponder; - (BOOL)resignFirstResponder; - (osgGA::GUIEventAdapter::TouchPhase) convertTouchPhase: (UITouchPhase) phase; - (osg::Vec2) convertPointToPixel: (osg::Vec2) point; - (void) dealloc; @end @implementation GraphicsWindowIOSGLView - (osgGA::GUIEventAdapter::TouchPhase) convertTouchPhase: (UITouchPhase) phase { switch(phase) { case UITouchPhaseBegan: return osgGA::GUIEventAdapter::TOUCH_BEGAN; break; case UITouchPhaseMoved: return osgGA::GUIEventAdapter::TOUCH_MOVED; break; case UITouchPhaseStationary: return osgGA::GUIEventAdapter::TOUCH_STATIONERY; break; case UITouchPhaseEnded: case UITouchPhaseCancelled: return osgGA::GUIEventAdapter::TOUCH_ENDED; break; } return osgGA::GUIEventAdapter::TOUCH_ENDED; } - (unsigned int)computeTouchId: (UITouch*) touch mayCleanup: (bool)may_cleanup { unsigned int result(0); if (!_touchPointsIdMapping) { _lastTouchPointId = 0; _touchPointsIdMapping = new TouchPointsIdMapping(); } switch([touch phase]) { case UITouchPhaseBegan: { TouchPointsIdMapping::iterator itr = _touchPointsIdMapping->find(touch); // std::cout << "new: " << touch << " num: " << _touchPointsIdMapping->size() << " found: " << (itr != _touchPointsIdMapping->end()) << std::endl; if (itr == _touchPointsIdMapping->end()) { (*_touchPointsIdMapping)[touch] = result = _lastTouchPointId; _lastTouchPointId++; break; } } // missing "break" by intention! case UITouchPhaseMoved: case UITouchPhaseStationary: { result = (*_touchPointsIdMapping)[touch]; } break; case UITouchPhaseEnded: case UITouchPhaseCancelled: { TouchPointsIdMapping::iterator itr = _touchPointsIdMapping->find(touch); // std::cout<< "remove: " << touch << " num: " << _touchPointsIdMapping->size() << " found: " << (itr != _touchPointsIdMapping->end()) << std::endl; if (itr != _touchPointsIdMapping->end()) { result = itr->second; if(may_cleanup) _touchPointsIdMapping->erase(itr); } if(_touchPointsIdMapping->size() == 0) { _lastTouchPointId = 0; } // std::cout<< "remove: " << touch << " num: " << _touchPointsIdMapping->size() << std::endl; } break; default: break; } return result; } - (osg::Vec2) convertPointToPixel: (osg::Vec2) point { //get the views contentscale factor and multiply the point by it float scale = 1.0f; #if defined(__IPHONE_4_0) && (__IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_4_0) scale = self.contentScaleFactor; #endif return osg::Vec2(point.x()*scale, point.y()*scale); } -(void) setGraphicsWindow: (osgViewer::GraphicsWindowIOS*) win { _win = win; _touchPointsIdMapping = new TouchPointsIdMapping(); _lastTouchPointId = 0; } - (osgViewer::GraphicsWindowIOS*) getGraphicsWindow { return _win; } -(void) setOpenGLContext: (EAGLContext*) context { _context = context; } // You must implement this method + (Class)layerClass { return [CAEAGLLayer class]; } // //Called when the view is created using a frame for dimensions // - (id)initWithFrame:(CGRect)frame : (osgViewer::GraphicsWindowIOS*)win{ _win = win; if ((self = [super initWithFrame:frame])) { // Get the layer CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer; osgViewer::GraphicsWindowIOS::WindowData* win_data(NULL); if (_win->getTraits()->inheritedWindowData.valid()) win_data = dynamic_cast(_win->getTraits()->inheritedWindowData.get()); eaglLayer.opaque = win_data ? !win_data->getCreateTransparentView() : YES; bool retained_backing = win_data ? win_data->getUseRetainedBacking() : NO; if(_win->getTraits()->alpha > 0) { //create layer with alpha channel RGBA8 eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithBool:retained_backing], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil]; }else{ //else no alpha, IOS uses RBG565 eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithBool:retained_backing], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGB565, kEAGLDrawablePropertyColorFormat, nil]; } } self.multipleTouchEnabled = YES; return self; } // //Implement dealloc to destory our frame buffer // - (void) dealloc { OSG_INFO << "GraphicsWindowIOSGLView::dealloc" << std::endl; if(_touchPointsIdMapping) delete _touchPointsIdMapping; _touchPointsIdMapping = NULL; [super dealloc]; } - (void)layoutSubviews { [super layoutSubviews]; [self updateDimensions]; } - (void) setFrame:(CGRect)frame { [super setFrame:frame]; [self updateDimensions]; } - (void) updateDimensions { if (_win) { CGRect frame = self.bounds; osg::Vec2 pointOrigin = osg::Vec2(frame.origin.x,frame.origin.y); osg::Vec2 pointSize = osg::Vec2(frame.size.width,frame.size.height); osg::Vec2 pixelOrigin = [(GraphicsWindowIOSGLView*)(self) convertPointToPixel:pointOrigin]; osg::Vec2 pixelSize = [(GraphicsWindowIOSGLView*)(self) convertPointToPixel:pointSize]; OSG_INFO << "updateDimensions, resize to " << pixelOrigin.x() << " " << pixelOrigin.y() << " " << pixelSize.x() << " " << pixelSize.y() << std::endl; _win->resized(pixelOrigin.x(), pixelOrigin.y(), pixelSize.x(), pixelSize.y()); } } - (BOOL)createFramebuffer { _msaaFramebuffer = _msaaRenderBuffer = 0; glGenFramebuffersOES(1, &_viewFramebuffer); glGenRenderbuffersOES(1, &_viewRenderbuffer); // set the default id for osg to switch back after using fbos. _win->setDefaultFboId(_viewFramebuffer); glBindFramebufferOES(GL_FRAMEBUFFER_OES, _viewFramebuffer); glBindRenderbufferOES(GL_RENDERBUFFER_OES, _viewRenderbuffer); [_context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer*)self.layer]; glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, _viewRenderbuffer); glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &_backingWidth); glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &_backingHeight); osg::notify(osg::DEBUG_INFO) << "GraphicsWindowIOS::createFramebuffer INFO: Created GL RenderBuffer of size " << _backingWidth << ", " << _backingHeight << " ." << std::endl; #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 50000 //on ios 5 we have to use a packed depth stencil buffer if we want stencil if(_win->getTraits()->depth > 0) { //add stencil if requested if(_win->getTraits()->stencil > 0) { // Create a packed depth stencil buffer. glGenRenderbuffersOES(1, &_depthRenderbuffer); glBindRenderbufferOES(GL_RENDERBUFFER_OES, _depthRenderbuffer); glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH24_STENCIL8_OES, _backingWidth, _backingHeight); glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, _depthRenderbuffer); glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_STENCIL_ATTACHMENT_OES, GL_RENDERBUFFER_OES, _depthRenderbuffer); }else{ //normal depth buffer glGenRenderbuffersOES(1, &_depthRenderbuffer); glBindRenderbufferOES(GL_RENDERBUFFER_OES, _depthRenderbuffer); if(_win->getTraits()->depth == 16) { glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, _backingWidth, _backingHeight); }else if(_win->getTraits()->depth == 24){ glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT24_OES, _backingWidth, _backingHeight); } glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, _depthRenderbuffer); } } #else //add depth if requested if(_win->getTraits()->depth > 0) { glGenRenderbuffersOES(1, &_depthRenderbuffer); glBindRenderbufferOES(GL_RENDERBUFFER_OES, _depthRenderbuffer); if(_win->getTraits()->depth == 16) { glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, _backingWidth, _backingHeight); }else if(_win->getTraits()->depth == 24){ glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT24_OES, _backingWidth, _backingHeight); } #if defined(GL_DEPTH_COMPONENT32_OES) else if(_win->getTraits()->depth == 32){ glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT32_OES, _backingWidth, _backingHeight); } #endif glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, _depthRenderbuffer); } //add stencil if requested if(_win->getTraits()->stencil > 0) { glGenRenderbuffersOES(1, &_stencilBuffer); glBindRenderbufferOES(GL_RENDERBUFFER_OES, _stencilBuffer); glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_STENCIL_INDEX8_OES, _backingWidth, _backingHeight); glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_STENCIL_ATTACHMENT_OES, GL_RENDERBUFFER_OES, _stencilBuffer); } #endif //MSAA only available for >= 4.0 sdk #if defined(__IPHONE_4_0) && (__IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_4_0) if(_win->getTraits()->sampleBuffers > 0) { glGenFramebuffersOES(1, &_msaaFramebuffer); glGenRenderbuffersOES(1, &_msaaRenderBuffer); _win->setDefaultFboId(_msaaFramebuffer); glBindFramebufferOES(GL_FRAMEBUFFER_OES, _msaaFramebuffer); glBindRenderbufferOES(GL_RENDERBUFFER_OES, _msaaRenderBuffer); // Samples is the amount of pixels the MSAA buffer uses to make one pixel on the render // buffer. Use a small number like 2 for the 3G and below and 4 or more for newer models glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER_OES, _win->getTraits()->samples, GL_RGB5_A1_OES, _backingWidth, _backingHeight); glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, _msaaRenderBuffer); glGenRenderbuffersOES(1, &_msaaDepthBuffer); glBindRenderbufferOES(GL_RENDERBUFFER_OES, _msaaDepthBuffer); GLuint attachmentType = (_win->getTraits()->stencil > 0) ? GL_DEPTH24_STENCIL8_OES : ((_win->getTraits()->depth == 16) ? GL_DEPTH_COMPONENT16_OES : GL_DEPTH_COMPONENT24_OES); glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER_OES, _win->getTraits()->samples, attachmentType, _backingWidth , _backingHeight); glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, _msaaDepthBuffer); if (_win->getTraits()->stencil > 0) { glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_STENCIL_ATTACHMENT_OES, GL_RENDERBUFFER_OES, _msaaDepthBuffer); } } #endif if(glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) { OSG_FATAL << "GraphicsWindowIOS::createFramebuffer ERROR: Failed to create a GL RenderBuffer, glCheckFramebufferStatusOES returned '" << glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) << "'." << std::endl; return NO; } return YES; } - (void)destroyFramebuffer { if(_viewFramebuffer) { glDeleteFramebuffersOES(1, &_viewFramebuffer); _viewFramebuffer = 0; } if(_viewRenderbuffer) { glDeleteRenderbuffersOES(1, &_viewRenderbuffer); _viewRenderbuffer = 0; } if(_depthRenderbuffer) { glDeleteRenderbuffersOES(1, &_depthRenderbuffer); _depthRenderbuffer = 0; } if(_stencilBuffer) { glDeleteRenderbuffersOES(1, &_stencilBuffer); _stencilBuffer = 0; } if(_msaaRenderBuffer) { glDeleteRenderbuffersOES(1, &_msaaRenderBuffer); _msaaRenderBuffer = 0; } if(_msaaDepthBuffer) { glDeleteRenderbuffersOES(1, &_msaaDepthBuffer); _msaaDepthBuffer = 0; } if(_msaaFramebuffer) { glDeleteFramebuffersOES(1, &_msaaFramebuffer); _msaaFramebuffer = 0; } } // //Swap the view and render buffers // - (void)swapBuffers { #if defined(__IPHONE_4_0) && (__IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_4_0) if(_msaaFramebuffer) { glBindFramebufferOES(GL_FRAMEBUFFER_OES, _msaaFramebuffer); glBindFramebufferOES(GL_READ_FRAMEBUFFER_APPLE, _msaaFramebuffer); glBindFramebufferOES(GL_DRAW_FRAMEBUFFER_APPLE, _viewFramebuffer); glResolveMultisampleFramebufferAPPLE(); GLenum attachments[] = {GL_DEPTH_ATTACHMENT_OES, GL_COLOR_ATTACHMENT0_OES}; #ifdef OSG_GLES3_FEATURES switch ([_context API]) { case kEAGLRenderingAPIOpenGLES3: glBlitFramebuffer(0, 0, _backingWidth, _backingHeight, 0, 0, _backingWidth, _backingHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR); glInvalidateFramebuffer(GL_READ_FRAMEBUFFER_APPLE, 2, attachments); break; default: glResolveMultisampleFramebufferAPPLE(); glDiscardFramebufferEXT(GL_READ_FRAMEBUFFER_APPLE, 2, attachments); break; } #else glDiscardFramebufferEXT(GL_READ_FRAMEBUFFER_APPLE, 2, attachments); #endif } #endif //swap buffers (sort of i think?) glBindRenderbufferOES(GL_RENDERBUFFER_OES, _viewRenderbuffer); //display render in context [_context presentRenderbuffer:GL_RENDERBUFFER_OES]; //re bind the frame buffer for next frames renders glBindFramebufferOES(GL_FRAMEBUFFER_OES, _viewFramebuffer); #if defined(__IPHONE_4_0) && (__IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_4_0) if (_msaaFramebuffer) glBindFramebufferOES(GL_FRAMEBUFFER_OES, _msaaFramebuffer);; #endif } // //bind view buffer as current for new render pass // - (void)bindFrameBuffer { //bind the frame buffer glBindFramebufferOES(GL_FRAMEBUFFER_OES, _viewFramebuffer); #if defined(__IPHONE_4_0) && (__IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_4_0) if (_msaaFramebuffer) glBindFramebufferOES(GL_READ_FRAMEBUFFER_APPLE, _msaaFramebuffer); #endif } - (BOOL)acceptsFirstResponder { return YES; } - (BOOL)becomeFirstResponder { return YES; } - (BOOL)resignFirstResponder { return YES; } // //Touch input callbacks // - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { NSSet *allTouches = [event allTouches]; osg::ref_ptr osg_event(NULL); for(int i=0; i<[allTouches count]; i++) { UITouch *touch = [[allTouches allObjects] objectAtIndex:i]; CGPoint pos = [touch locationInView:self]; osg::Vec2 pixelPos = [self convertPointToPixel: osg::Vec2(pos.x,pos.y)]; unsigned int touch_id = [self computeTouchId: touch mayCleanup: FALSE]; if (!osg_event) { osg_event = _win->getEventQueue()->touchBegan(touch_id, [self convertTouchPhase: [touch phase]], pixelPos.x(), pixelPos.y()); osg_event->setMouseYOrientation(osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS); } else { osg_event->addTouchPoint(touch_id, [self convertTouchPhase: [touch phase]], pixelPos.x(), pixelPos.y()); } } [super touchesBegan:touches withEvent:event]; } - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { NSSet *allTouches = [event allTouches]; osg::ref_ptr osg_event(NULL); for(int i=0; i<[allTouches count]; i++) { UITouch *touch = [[allTouches allObjects] objectAtIndex:i]; CGPoint pos = [touch locationInView:self]; osg::Vec2 pixelPos = [self convertPointToPixel: osg::Vec2(pos.x,pos.y)]; unsigned int touch_id = [self computeTouchId: touch mayCleanup: FALSE]; if (!osg_event) { osg_event = _win->getEventQueue()->touchMoved(touch_id, [self convertTouchPhase: [touch phase]], pixelPos.x(), pixelPos.y()); osg_event->setMouseYOrientation(osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS); } else { osg_event->addTouchPoint(touch_id, [self convertTouchPhase: [touch phase]], pixelPos.x(), pixelPos.y()); } } [super touchesMoved:touches withEvent:event]; } - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { NSSet *allTouches = [event allTouches]; osg::ref_ptr osg_event(NULL); for(int i=0; i<[allTouches count]; i++) { UITouch *touch = [[allTouches allObjects] objectAtIndex:i]; CGPoint pos = [touch locationInView:self]; osg::Vec2 pixelPos = [self convertPointToPixel: osg::Vec2(pos.x,pos.y)]; unsigned int touch_id = [self computeTouchId: touch mayCleanup: TRUE]; if (!osg_event) { osg_event = _win->getEventQueue()->touchEnded(touch_id, [self convertTouchPhase: [touch phase]], pixelPos.x(), pixelPos.y(), [touch tapCount]); osg_event->setMouseYOrientation(osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS); } else { osg_event->addTouchPoint(touch_id, [self convertTouchPhase: [touch phase]], pixelPos.x(), pixelPos.y(), [touch tapCount]); } } [super touchesEnded:touches withEvent:event]; } -(void) touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { [self touchesEnded: touches withEvent:event]; } @end @interface GraphicsWindowIOSGLViewController : UIViewController { } - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation; - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration; @end @implementation GraphicsWindowIOSGLViewController - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { osgViewer::GraphicsWindowIOS* win = [(GraphicsWindowIOSGLView*)(self.view) getGraphicsWindow]; if(!win){return NO;} osgViewer::GraphicsWindowIOS::WindowData::DeviceOrientationFlags flags = win->getDeviceOrientationFlags(); BOOL result(NO); switch (interfaceOrientation) { case UIDeviceOrientationPortrait: if(flags & osgViewer::GraphicsWindowIOS::WindowData::PORTRAIT_ORIENTATION){ result = YES; } break; case UIDeviceOrientationPortraitUpsideDown: if(flags & osgViewer::GraphicsWindowIOS::WindowData::PORTRAIT_UPSIDEDOWN_ORIENTATION){ result = YES; } break; case UIInterfaceOrientationLandscapeLeft: if(win->getTraits()->supportsResize && flags & osgViewer::GraphicsWindowIOS::WindowData::LANDSCAPE_LEFT_ORIENTATION){ result = YES; } break; case UIInterfaceOrientationLandscapeRight: if(win->getTraits()->supportsResize && flags & osgViewer::GraphicsWindowIOS::WindowData::LANDSCAPE_RIGHT_ORIENTATION){ result = YES; } break; default: break; } OSG_INFO << "shouldAutorotateToInterfaceOrientation for " << interfaceOrientation << ": " << ((result==YES) ? "YES" : "NO") << std::endl; return result; } - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration { [(GraphicsWindowIOSGLView*)(self.view) updateDimensions]; } @end using namespace osgIOS; namespace osgViewer { #pragma mark GraphicsWindowIOS // ---------------------------------------------------------------------------------------------------------- // init // ---------------------------------------------------------------------------------------------------------- void GraphicsWindowIOS::init() { if (_initialized) return; _ownsWindow = false; _context = NULL; _window = NULL; _view = NULL; _viewController = NULL; _updateContext = true; //if -1.0 we use the screens scale factor _viewContentScaleFactor = -1.0f; _valid = _initialized = true; // make sure the event queue has the correct window rectangle size and input range getEventQueue()->syncWindowRectangleWithGraphicsContext(); } // ---------------------------------------------------------------------------------------------------------- // realizeImplementation, creates the window + context // ---------------------------------------------------------------------------------------------------------- bool GraphicsWindowIOS::realizeImplementation() { if (_realized) return true; NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; BOOL bar_hidden = (_traits->windowDecoration) ? NO: YES; #ifdef __IPHONE_OS_VERSION_MIN_REQUIRED #if __IPHONE_OS_VERSION_MIN_REQUIRED > 30100 [[UIApplication sharedApplication] setStatusBarHidden: bar_hidden withAnimation:UIStatusBarAnimationNone]; #else [[UIApplication sharedApplication] setStatusBarHidden: bar_hidden animated:NO]; #endif #endif //Get info about the requested screen IOSWindowingSystemInterface* wsi = dynamic_cast(osg::GraphicsContext::getWindowingSystemInterface()); osg::Vec2 screenSizePoints; osg::Vec2 screenSizePixels; float screenScaleFactor = 1.0f; UIScreen* screen = nil; osg::GraphicsContext::ScreenSettings screenSettings; if (wsi) { wsi->getScreenContentScaleFactor((*_traits), screenScaleFactor); wsi->getScreenSizeInPoints((*_traits), screenSizePoints); screenSizePixels = osg::Vec2(screenSettings.width, screenSettings.height); wsi->getScreenSettings((*_traits), screenSettings); screen = wsi->getUIScreen((*_traits)); }else{ OSG_FATAL << "GraphicsWindowIOS::realizeImplementation: ERROR: Failed to create IOS windowing system, OSG will be unable to create a vaild gl context and will not be able to render." << std::endl; return false; } _ownsWindow = true; // see if an existing inherited window was passed in WindowData* windowData = _traits->inheritedWindowData ? dynamic_cast(_traits->inheritedWindowData.get()) : NULL; if (windowData) { if (windowData->getWindowOrParentView()) { _ownsWindow = false; _window = windowData->getWindowOrParentView(); } _deviceOrientationFlags = windowData->_deviceOrientationFlags; _viewContentScaleFactor = windowData->_viewContentScaleFactor; } //if the user hasn't specified a viewScaleFactor we will use the screens scale factor //so we get a full res buffer if(_viewContentScaleFactor < 0.0f) {_viewContentScaleFactor = screenScaleFactor;} OSG_DEBUG << "GraphicsWindowIOS::realizeImplementation / ownsWindow: " << _ownsWindow << std::endl; //Here's the confusing bit, the default traits use the screen res which is in pixels and the user will want to use pixels also //but we need to create our views and windows in points. By default we create a full res buffer across all devices. This //means that for backward compatibility you need to set the windowData _viewContentScaleFactor to 1.0f and set the screen res to the //res of the older gen device. CGRect window_bounds; osg::Vec2 pointsOrigin = this->pixelToPoint(osg::Vec2(_traits->x, _traits->y)); osg::Vec2 pointsSize = this->pixelToPoint(osg::Vec2(_traits->width, _traits->height)); window_bounds.origin.x = pointsOrigin.x(); window_bounds.origin.y = pointsOrigin.y(); window_bounds.size.width = pointsSize.x(); window_bounds.size.height = pointsSize.y(); //if we own the window we need to create one if (_ownsWindow) { //create the IOS window object using the viewbounds (in points) required for our context size _window = [[GraphicsWindowIOSWindow alloc] initWithFrame: window_bounds];// styleMask: style backing: NSBackingStoreBuffered defer: NO]; if (!_window) { OSG_WARN << "GraphicsWindowIOS::realizeImplementation: ERROR: Failed to create GraphicsWindowIOSWindow can not display gl view" << std::endl; return false; } OSG_DEBUG << "GraphicsWindowIOS::realizeImplementation: INFO: Created UIWindow with bounds '" << window_bounds.size.width << ", " << window_bounds.size.height << "' (points)." << std::endl; //if the user has requested a differnet screenNum from default 0 get the UIScreen object and //apply to our window (this is for IPad external screens, I don't have one, so I've no idea if it works) //I'm also not sure if we should apply this to external windows also? if(_traits->screenNum > 0 && screen != nil) { _window.screen = screen; } } //create the desired OpenGLES context type #if OSG_GLES1_FEATURES _context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1]; #elif OSG_GLES2_FEATURES #if OSG_GLES3_FEATURES _context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3]; #endif if (!_context) _context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; #endif if (!_context || ![EAGLContext setCurrentContext:_context]) { #if OSG_GLES1_FEATURES OSG_FATAL << "GraphicsWindowIOS::realizeImplementation: ERROR: Failed to create a valid OpenGLES1 context" << std::endl; #elif OSG_GLES2_FEATURES #if OSG_GLES3_FEATURES OSG_FATAL << "GraphicsWindowIOS::realizeImplementation: ERROR: Failed to create a valid OpenGLES3 or OpenGLES2 context" << std::endl; #else OSG_FATAL << "GraphicsWindowIOS::realizeImplementation: ERROR: Failed to create a valid OpenGLES2 context" << std::endl; #endif #endif return false; } //create the view to display our context in our window CGRect gl_view_bounds = (_ownsWindow) ? [_window frame] : window_bounds; GraphicsWindowIOSGLView* theView = [[ GraphicsWindowIOSGLView alloc ] initWithFrame: gl_view_bounds : this ]; if(!theView) { OSG_FATAL << "GraphicsWindowIOS::realizeImplementation: ERROR: Failed to create GraphicsWindowIOSGLView, can not create frame buffers." << std::endl; return false; } [theView setAutoresizingMask: ( UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight) ]; //Apply our content scale factor to our view, this is what converts the views points //size to our desired context size. #if defined(__IPHONE_4_0) && (__IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_4_0) theView.contentScaleFactor = _viewContentScaleFactor; #endif [theView setGraphicsWindow: this]; [theView setOpenGLContext:_context]; _view = theView; OSG_DEBUG << "GraphicsWindowIOS::realizeImplementation / view: " << theView << std::endl; if (getDeviceOrientationFlags() != WindowData::IGNORE_ORIENTATION) { _viewController = [[GraphicsWindowIOSGLViewController alloc] init]; _viewController.view = _view; } // Attach view to window [_window addSubview: _view]; if ([_window isKindOfClass:[UIWindow class]]) _window.rootViewController = _viewController; [theView release]; //if we own the window also make it visible if (_ownsWindow) { //show window [_window makeKeyAndVisible]; } [pool release]; // IOSs origin is top/left: getEventQueue()->getCurrentEventState()->setMouseYOrientation(osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS); // make sure the event queue has the correct window rectangle size and input range getEventQueue()->syncWindowRectangleWithGraphicsContext(); _valid = _initialized = _realized = true; return _valid; } // ---------------------------------------------------------------------------------------------------------- // closeImplementation // ---------------------------------------------------------------------------------------------------------- void GraphicsWindowIOS::closeImplementation() { OSG_INFO << "close IOS window" << std::endl; _valid = false; _realized = false; if (_view) { [_view setOpenGLContext: NULL]; [_context release]; [_view removeFromSuperview]; [_view setGraphicsWindow: NULL]; } if (_viewController) { [_viewController release]; _viewController = NULL; } if (_window && _ownsWindow) { [_window release]; //[glView release]; } _window = NULL; _view = NULL; _context = NULL; } // ---------------------------------------------------------------------------------------------------------- // makeCurrentImplementation // ---------------------------------------------------------------------------------------------------------- bool GraphicsWindowIOS:: makeCurrentImplementation() { //bind the context [EAGLContext setCurrentContext:_context]; if (_updateContext) { [_view destroyFramebuffer]; [_view createFramebuffer]; _updateContext = false; } //i think we also want to bind the frame buffer here //[_view bindFrameBuffer]; return true; } // ---------------------------------------------------------------------------------------------------------- // releaseContextImplementation // ---------------------------------------------------------------------------------------------------------- bool GraphicsWindowIOS::releaseContextImplementation() { if ([EAGLContext currentContext] == _context) { [EAGLContext setCurrentContext:nil]; } return true; } // ---------------------------------------------------------------------------------------------------------- // swapBuffersImplementation // ---------------------------------------------------------------------------------------------------------- void GraphicsWindowIOS::swapBuffersImplementation() { //[_context flushBuffer]; [_view swapBuffers]; } // ---------------------------------------------------------------------------------------------------------- // setWindowDecorationImplementation // // We will use this to toggle the status bar on IPhone, nearest thing to window decoration // ---------------------------------------------------------------------------------------------------------- bool GraphicsWindowIOS::setWindowDecorationImplementation(bool flag) { if (!_realized || !_ownsWindow) return false; BOOL bar_hidden = (flag) ? NO: YES; #ifdef __IPHONE_OS_VERSION_MIN_REQUIRED #if __IPHONE_OS_VERSION_MIN_REQUIRED > 30100 [[UIApplication sharedApplication] setStatusBarHidden: bar_hidden withAnimation:UIStatusBarAnimationNone]; #else [[UIApplication sharedApplication] setStatusBarHidden: bar_hidden animated:NO]; #endif #endif return true; } // ---------------------------------------------------------------------------------------------------------- // grabFocus // ---------------------------------------------------------------------------------------------------------- void GraphicsWindowIOS::grabFocus() { //i think make key is the equivalent of focus on iphone [_window makeKeyWindow]; } // ---------------------------------------------------------------------------------------------------------- // grabFocusIfPointerInWindow // ---------------------------------------------------------------------------------------------------------- void GraphicsWindowIOS::grabFocusIfPointerInWindow() { OSG_INFO << "GraphicsWindowIOS :: grabFocusIfPointerInWindow not implemented yet " << std::endl; } // ---------------------------------------------------------------------------------------------------------- // raiseWindow // Raise the window to the top. // ---------------------------------------------------------------------------------------------------------- void GraphicsWindowIOS::raiseWindow() { [_window bringSubviewToFront:_view]; } // ---------------------------------------------------------------------------------------------------------- // resizedImplementation // ---------------------------------------------------------------------------------------------------------- void GraphicsWindowIOS::resizedImplementation(int x, int y, int width, int height) { GraphicsContext::resizedImplementation(x, y, width, height); _updateContext = true; getEventQueue()->windowResize(x,y,width, height, getEventQueue()->getTime()); } // ---------------------------------------------------------------------------------------------------------- // setWindowRectangleImplementation // ---------------------------------------------------------------------------------------------------------- bool GraphicsWindowIOS::setWindowRectangleImplementation(int x, int y, int width, int height) { OSG_INFO << "GraphicsWindowIOS :: setWindowRectangleImplementation not implemented yet " << std::endl; if (!_ownsWindow) return false; return true; } bool GraphicsWindowIOS::checkEvents() { return !(getEventQueue()->empty()); } // ---------------------------------------------------------------------------------------------------------- // setWindowName // ---------------------------------------------------------------------------------------------------------- void GraphicsWindowIOS::setWindowName (const std::string & name) { OSG_INFO << "GraphicsWindowIOS :: setWindowName not implemented yet " << std::endl; } // ---------------------------------------------------------------------------------------------------------- // useCursor, no cursor on IOS // ---------------------------------------------------------------------------------------------------------- void GraphicsWindowIOS::useCursor(bool cursorOn) { OSG_INFO << "GraphicsWindowIOS :: useCursor not implemented yet " << std::endl; } // ---------------------------------------------------------------------------------------------------------- // setCursor, no cursor on IOS // ---------------------------------------------------------------------------------------------------------- void GraphicsWindowIOS::setCursor(MouseCursor mouseCursor) { OSG_INFO << "GraphicsWindowIOS :: setCursor not implemented yet " << std::endl; } // ---------------------------------------------------------------------------------------------------------- // setVSync, no vsync on IOS // ---------------------------------------------------------------------------------------------------------- void GraphicsWindowIOS::setVSync(bool f) { OSG_INFO << "GraphicsWindowIOS :: setVSync not implemented yet " << std::endl; } // ---------------------------------------------------------------------------------------------------------- // helper funcs for converting points to pixels taking into account the views contents scale factor // ---------------------------------------------------------------------------------------------------------- osg::Vec2 GraphicsWindowIOS::pointToPixel(const osg::Vec2& point) { return point * _viewContentScaleFactor; } osg::Vec2 GraphicsWindowIOS::pixelToPoint(const osg::Vec2& pixel) { float scaler = 1.0f / _viewContentScaleFactor; return pixel * scaler; } // ---------------------------------------------------------------------------------------------------------- // d'tor // ---------------------------------------------------------------------------------------------------------- GraphicsWindowIOS::~GraphicsWindowIOS() { close(); } class ConcreteIOSWindowingSystemInterface : public IOSWindowingSystemInterface { public: ConcreteIOSWindowingSystemInterface() : IOSWindowingSystemInterface() { } virtual osg::GraphicsContext* createGraphicsContext(osg::GraphicsContext::Traits* traits) { if (traits->pbuffer) { // pbuffers not supported on iOS return 0; } else { osg::ref_ptr window = new GraphicsWindowIOS(traits); if (window->valid()) return window.release(); else return 0; } } }; REGISTER_WINDOWINGSYSTEMINTERFACE(IOS, ConcreteIOSWindowingSystemInterface) }//end namspace