diff --git a/addons/ofxiOS/src/app/ofAppiOSWindow.h b/addons/ofxiOS/src/app/ofAppiOSWindow.h index 15ffecb469f..31c53f27849 100644 --- a/addons/ofxiOS/src/app/ofAppiOSWindow.h +++ b/addons/ofxiOS/src/app/ofAppiOSWindow.h @@ -30,8 +30,6 @@ * ***********************************************************************/ #pragma once -#include "ofxiOSConstants.h" -#if defined(TARGET_OF_IOS) #include #include "ofAppBaseWindow.h" #include "ofxiOSConstants.h" @@ -39,130 +37,131 @@ class ofiOSWindowSettings: public ofGLESWindowSettings{ public: - ofiOSWindowSettings() - :enableRetina(true) - ,retinaScale(0) - ,enableDepth(false) - ,enableAntiAliasing(false) - ,numOfAntiAliasingSamples(0) - ,enableHardwareOrientation(false) - ,enableHardwareOrientationAnimation(false) - ,enableSetupScreen(true) - ,windowControllerType(ofxiOSWindowControllerType::CORE_ANIMATION) - ,colorType(ofxiOSRendererColorFormat::RGBA8888) - ,depthType(ofxiOSRendererDepthFormat::DEPTH_NONE) - ,stencilType(ofxiOSRendererStencilFormat::STENCIL_NONE) - ,enableMultiTouch(false) { - windowMode = OF_FULLSCREEN; - setupOrientation = OF_ORIENTATION_DEFAULT; - glesVersion = 2; - } - - ofiOSWindowSettings(const ofWindowSettings & settings) - :ofGLESWindowSettings(settings) - ,enableRetina(true) - ,retinaScale(0) - ,enableDepth(false) - ,enableAntiAliasing(false) - ,numOfAntiAliasingSamples(0) - ,enableHardwareOrientation(false) - ,enableHardwareOrientationAnimation(false) - ,enableSetupScreen(true) - ,windowControllerType(ofxiOSWindowControllerType::CORE_ANIMATION) - ,colorType(ofxiOSRendererColorFormat::RGBA8888) - ,depthType(ofxiOSRendererDepthFormat::DEPTH_NONE) - ,stencilType(ofxiOSRendererStencilFormat::STENCIL_NONE) - ,enableMultiTouch(false) { - const ofGLESWindowSettings * glesSettings = dynamic_cast(&settings); - if(glesSettings){ - glesVersion = glesSettings->glesVersion; - } else { - glesVersion = 2; - } - const ofiOSWindowSettings * iosSettings = dynamic_cast(&settings); - if(iosSettings){ - enableRetina = iosSettings->enableRetina; - retinaScale = iosSettings->retinaScale; - enableDepth = iosSettings->enableDepth; - enableAntiAliasing = iosSettings->enableAntiAliasing; - numOfAntiAliasingSamples = iosSettings->numOfAntiAliasingSamples; - enableHardwareOrientation = iosSettings->enableHardwareOrientation; - enableHardwareOrientationAnimation = iosSettings->enableHardwareOrientationAnimation; - enableSetupScreen = iosSettings->enableSetupScreen; - setupOrientation = iosSettings->setupOrientation; - windowControllerType = iosSettings->windowControllerType; - colorType = iosSettings->colorType; - depthType = iosSettings->depthType; - stencilType = iosSettings->stencilType; - enableMultiTouch = iosSettings->enableMultiTouch; - } else { - enableRetina = true; - retinaScale = 0; - enableDepth = false; - enableAntiAliasing = false; - numOfAntiAliasingSamples = 0; - enableHardwareOrientation = false; - enableHardwareOrientationAnimation = false; - enableSetupScreen = true; - setupOrientation = OF_ORIENTATION_DEFAULT; - colorType = ofxiOSRendererColorFormat::RGBA8888; - depthType = ofxiOSRendererDepthFormat::DEPTH_NONE; - stencilType = ofxiOSRendererStencilFormat::STENCIL_NONE; - enableMultiTouch = false; - } - } + ofiOSWindowSettings() + :enableRetina(true) + ,retinaScale(0) + ,enableDepth(false) + ,enableAntiAliasing(false) + ,numOfAntiAliasingSamples(0) + ,enableHardwareOrientation(false) + ,enableHardwareOrientationAnimation(false) + ,enableSetupScreen(true) + ,windowControllerType(ofxiOSWindowControllerType::CORE_ANIMATION) + ,colorType(ofxiOSRendererColorFormat::RGBA8888) + ,depthType(ofxiOSRendererDepthFormat::DEPTH_NONE) + ,stencilType(ofxiOSRendererStencilFormat::STENCIL_NONE) + ,enableMultiTouch(false) { + windowMode = OF_FULLSCREEN; + setupOrientation = OF_ORIENTATION_DEFAULT; + glesVersion = 2; + } + + ofiOSWindowSettings(const ofWindowSettings & settings) + :ofGLESWindowSettings(settings) + ,enableRetina(true) + ,retinaScale(0) + ,enableDepth(false) + ,enableAntiAliasing(false) + ,numOfAntiAliasingSamples(0) + ,enableHardwareOrientation(false) + ,enableHardwareOrientationAnimation(false) + ,enableSetupScreen(true) + ,windowControllerType(ofxiOSWindowControllerType::CORE_ANIMATION) + ,colorType(ofxiOSRendererColorFormat::RGBA8888) + ,depthType(ofxiOSRendererDepthFormat::DEPTH_NONE) + ,stencilType(ofxiOSRendererStencilFormat::STENCIL_NONE) + ,enableMultiTouch(false) { + const ofGLESWindowSettings * glesSettings = dynamic_cast(&settings); + if(glesSettings){ + glesVersion = glesSettings->glesVersion; + } else { + glesVersion = 2; + } + const ofiOSWindowSettings * iosSettings = dynamic_cast(&settings); + if(iosSettings){ + enableRetina = iosSettings->enableRetina; + retinaScale = iosSettings->retinaScale; + enableDepth = iosSettings->enableDepth; + enableAntiAliasing = iosSettings->enableAntiAliasing; + numOfAntiAliasingSamples = iosSettings->numOfAntiAliasingSamples; + enableHardwareOrientation = iosSettings->enableHardwareOrientation; + enableHardwareOrientationAnimation = iosSettings->enableHardwareOrientationAnimation; + enableSetupScreen = iosSettings->enableSetupScreen; + setupOrientation = iosSettings->setupOrientation; + windowControllerType = iosSettings->windowControllerType; + colorType = iosSettings->colorType; + depthType = iosSettings->depthType; + stencilType = iosSettings->stencilType; + enableMultiTouch = iosSettings->enableMultiTouch; + } else { + enableRetina = true; + retinaScale = 0; + enableDepth = false; + enableAntiAliasing = false; + numOfAntiAliasingSamples = 0; + enableHardwareOrientation = false; + enableHardwareOrientationAnimation = false; + enableSetupScreen = true; + setupOrientation = OF_ORIENTATION_DEFAULT; +// windowControllerType = windowControllerType; + colorType = ofxiOSRendererColorFormat::RGBA8888; + depthType = ofxiOSRendererDepthFormat::DEPTH_NONE; + stencilType = ofxiOSRendererStencilFormat::STENCIL_NONE; + enableMultiTouch = false; + } + } - ofiOSWindowSettings(const ofGLESWindowSettings & settings) - :ofGLESWindowSettings(settings) - ,enableRetina(true) - ,retinaScale(0) - ,enableDepth(false) - ,enableAntiAliasing(false) - ,numOfAntiAliasingSamples(0) - ,enableHardwareOrientation(false) - ,enableHardwareOrientationAnimation(false) - ,enableSetupScreen(true) - ,windowControllerType(ofxiOSWindowControllerType::CORE_ANIMATION) - ,colorType(ofxiOSRendererColorFormat::RGBA8888) - ,depthType(ofxiOSRendererDepthFormat::DEPTH_NONE) - ,stencilType(ofxiOSRendererStencilFormat::STENCIL_NONE) - ,enableMultiTouch(false){ - const ofiOSWindowSettings * iosSettings = dynamic_cast(&settings); - if(iosSettings){ - enableRetina = iosSettings->enableRetina; - retinaScale = iosSettings->retinaScale; - enableDepth = iosSettings->enableDepth; - enableAntiAliasing = iosSettings->enableAntiAliasing; - numOfAntiAliasingSamples = iosSettings->numOfAntiAliasingSamples; - enableHardwareOrientation = iosSettings->enableHardwareOrientation; - enableHardwareOrientationAnimation = iosSettings->enableHardwareOrientationAnimation; - enableSetupScreen = iosSettings->enableSetupScreen; - setupOrientation = iosSettings->setupOrientation; - windowControllerType = iosSettings->windowControllerType; - colorType = iosSettings->colorType; - depthType = iosSettings->depthType; - stencilType = iosSettings->stencilType; - enableMultiTouch = iosSettings->enableMultiTouch; - } - } + ofiOSWindowSettings(const ofGLESWindowSettings & settings) + :ofGLESWindowSettings(settings) + ,enableRetina(true) + ,retinaScale(0) + ,enableDepth(false) + ,enableAntiAliasing(false) + ,numOfAntiAliasingSamples(0) + ,enableHardwareOrientation(false) + ,enableHardwareOrientationAnimation(false) + ,enableSetupScreen(true) + ,windowControllerType(ofxiOSWindowControllerType::CORE_ANIMATION) + ,colorType(ofxiOSRendererColorFormat::RGBA8888) + ,depthType(ofxiOSRendererDepthFormat::DEPTH_NONE) + ,stencilType(ofxiOSRendererStencilFormat::STENCIL_NONE) + ,enableMultiTouch(false){ + const ofiOSWindowSettings * iosSettings = dynamic_cast(&settings); + if(iosSettings){ + enableRetina = iosSettings->enableRetina; + retinaScale = iosSettings->retinaScale; + enableDepth = iosSettings->enableDepth; + enableAntiAliasing = iosSettings->enableAntiAliasing; + numOfAntiAliasingSamples = iosSettings->numOfAntiAliasingSamples; + enableHardwareOrientation = iosSettings->enableHardwareOrientation; + enableHardwareOrientationAnimation = iosSettings->enableHardwareOrientationAnimation; + enableSetupScreen = iosSettings->enableSetupScreen; + setupOrientation = iosSettings->setupOrientation; + windowControllerType = iosSettings->windowControllerType; + colorType = iosSettings->colorType; + depthType = iosSettings->depthType; + stencilType = iosSettings->stencilType; + enableMultiTouch = iosSettings->enableMultiTouch; + } + } - virtual ~ofiOSWindowSettings(){}; - - bool enableRetina; - float retinaScale; - bool enableDepth; - bool enableAntiAliasing; - int numOfAntiAliasingSamples; - bool enableHardwareOrientation; - bool enableHardwareOrientationAnimation; - bool enableSetupScreen; - bool enableMultiTouch; - ofxiOSWindowControllerType windowControllerType; - ofxiOSRendererColorFormat colorType; - ofxiOSRendererDepthFormat depthType; - ofxiOSRendererStencilFormat stencilType; - ofOrientation setupOrientation; - + virtual ~ofiOSWindowSettings(){}; + + bool enableRetina; + float retinaScale; + bool enableDepth; + bool enableAntiAliasing; + int numOfAntiAliasingSamples; + bool enableHardwareOrientation; + bool enableHardwareOrientationAnimation; + bool enableSetupScreen; + bool enableMultiTouch; + ofxiOSWindowControllerType windowControllerType; + ofxiOSRendererColorFormat colorType; + ofxiOSRendererDepthFormat depthType; + ofxiOSRendererStencilFormat stencilType; + ofOrientation setupOrientation; + }; @@ -286,5 +285,5 @@ class ofAppiOSWindow : public ofAppBaseGLESWindow { [[deprecated("use ofAppiOSWindow")]] typedef ofAppiOSWindow ofAppiPhoneWindow; -#endif + diff --git a/addons/ofxiOS/src/app/ofAppiOSWindow.mm b/addons/ofxiOS/src/app/ofAppiOSWindow.mm index 53a3856e6d4..127c29e7d7e 100644 --- a/addons/ofxiOS/src/app/ofAppiOSWindow.mm +++ b/addons/ofxiOS/src/app/ofAppiOSWindow.mm @@ -44,6 +44,7 @@ const std::string appDelegateName = "ofxtvOSAppDelegate"; #endif #include "ofxiOSGLKView.h" +#include "MGLKView.h" #include "ofxiOSEAGLView.h" //----------------------------------------------------------------------------------- instance. @@ -137,7 +138,7 @@ bAppCreated = true; @autoreleasepool { - UIApplicationMain(0, nil, nil, [NSString stringWithUTF8String:appDelegateClassName.c_str()]); + UIApplicationMain(0, 0, nil, [NSString stringWithUTF8String:appDelegateClassName.c_str()]); } } @@ -168,21 +169,27 @@ } glm::vec2 ofAppiOSWindow::getWindowPosition() { - if(settings.windowControllerType == METAL_KIT || settings.windowControllerType == GL_KIT) + if(settings.windowControllerType == METAL_KIT) { + return *[[MGLKView getInstance] getWindowPosition]; + }else if(settings.windowControllerType == GL_KIT) return *[[ofxiOSGLKView getInstance] getWindowPosition]; else return *[[ofxiOSEAGLView getInstance] getWindowPosition]; } glm::vec2 ofAppiOSWindow::getWindowSize() { - if(settings.windowControllerType == METAL_KIT || settings.windowControllerType == GL_KIT) + if(settings.windowControllerType == METAL_KIT) { + return *[[MGLKView getInstance] getWindowSize]; + }else if(settings.windowControllerType == GL_KIT) return *[[ofxiOSGLKView getInstance] getWindowSize]; else return *[[ofxiOSEAGLView getInstance] getWindowSize]; } glm::vec2 ofAppiOSWindow::getScreenSize() { - if(settings.windowControllerType == METAL_KIT || settings.windowControllerType == GL_KIT) + if(settings.windowControllerType == METAL_KIT) { + return *[[MGLKView getInstance] getScreenSize]; + } else if(settings.windowControllerType == GL_KIT) return *[[ofxiOSGLKView getInstance] getScreenSize]; else return *[[ofxiOSEAGLView getInstance] getScreenSize]; @@ -432,7 +439,11 @@ void ofAppiOSWindow::enableMultiTouch(bool isOn) { settings.enableMultiTouch = isOn; #if TARGET_OS_IOS || (TARGET_OS_IPHONE && !TARGET_OS_TV) - if(settings.windowControllerType == METAL_KIT || settings.windowControllerType == GL_KIT) { + if(settings.windowControllerType == METAL_KIT) { + if([MGLKView getInstance]) { + [[MGLKView getInstance] setMultipleTouchEnabled:isOn]; + } + } else if(settings.windowControllerType == GL_KIT) { if([ofxiOSGLKView getInstance]) { [[ofxiOSGLKView getInstance] setMultipleTouchEnabled:isOn]; } diff --git a/addons/ofxiOS/src/core/ofxiOSAppDelegate.h b/addons/ofxiOS/src/core/ofxiOSAppDelegate.h index a43f7b242ab..875d454b607 100644 --- a/addons/ofxiOS/src/core/ofxiOSAppDelegate.h +++ b/addons/ofxiOS/src/core/ofxiOSAppDelegate.h @@ -39,7 +39,7 @@ @class ofxiOSViewController; @class ofxiOSGLKViewController; -//@class ofxiOSMTKViewController; +@class ofxiOSMTKViewController; @interface ofxiOSAppDelegate : NSObject { NSInteger currentScreenIndex; diff --git a/addons/ofxiOS/src/core/ofxiOSAppDelegate.mm b/addons/ofxiOS/src/core/ofxiOSAppDelegate.mm index c98916523f7..f958a1b04b4 100644 --- a/addons/ofxiOS/src/core/ofxiOSAppDelegate.mm +++ b/addons/ofxiOS/src/core/ofxiOSAppDelegate.mm @@ -34,6 +34,10 @@ #import "ofxiOSAppDelegate.h" #import "ofxiOSViewController.h" #import "ofxiOSGLKViewController.h" + +#import "ofxiOSViewController.h" +#import "ofxiOSGLKViewController.h" +#import "ofxiOSMLKViewController.h" #import "ofxiOSExternalDisplay.h" #include "ofxiOSExtras.h" #include "ofxiOSAlerts.h" @@ -138,7 +142,15 @@ - (void)applicationDidFinishLaunching:(UIApplication *)application { switch(ofxiOSGetOFWindow()->getWindowControllerType()) { case METAL_KIT: - NSLog(@"No MetalKit yet supported for openFrameworks: Falling back to GLKit"); + NSLog(@"Metal ANGLE openFrameworks"); +// self.uiViewController = (UIViewController *)[[ofxiOSMLKViewController alloc] initWithFrame:frame app:(ofxiOSApp *)ofGetAppPtr()]; + +// UIStoryboard * storyboard = [UIStoryboard storyboardWithName:@"Storyboard" bundle:nil]; +// ofxiOSAppDelegate *del = (ofxiOSAppDelegate *)[UIApplication sharedApplication].delegate; +// MGLKViewController * game = [storyboard instantiateViewControllerWithIdentifier:@"iOSAppMGLKViewController"]; +// [del.navigationController pushViewController:game animated:YES]; + + case GL_KIT: self.uiViewController = (UIViewController *)[[ofxiOSGLKViewController alloc] initWithFrame:frame app:(ofxiOSApp *)ofGetAppPtr() sharegroup:nil]; break; @@ -252,6 +264,13 @@ - (void)receivedRotate:(NSNotification*)notification { if([controller isReadyToRotate]) { ofxiOSAlerts.deviceOrientationChanged( deviceOrientation ); } +#if defined(OF_METAL) + } else if([self.uiViewController isKindOfClass:ofxiOSMLKViewController.class]) { + ofxiOSMLKViewController *controller = (ofxiOSMLKViewController *)self.uiViewController; + if([controller isReadyToRotate]) { + ofxiOSAlerts.deviceOrientationChanged( deviceOrientation ); + } +#endif /* OF_METAL_KIT */ } } }else { diff --git a/addons/ofxiOS/src/core/ofxiOSGLKViewController.h b/addons/ofxiOS/src/core/ofxiOSGLKViewController.h index f2939c9209b..043ce5ef11b 100644 --- a/addons/ofxiOS/src/core/ofxiOSGLKViewController.h +++ b/addons/ofxiOS/src/core/ofxiOSGLKViewController.h @@ -18,11 +18,16 @@ #import #import +#if defined(METALKIT) +#import +#endif + class ofxiOSApp; @class ofxiOSGLKView; @interface ofxiOSGLKViewController : GLKViewController + @property (nonatomic, strong) ofxiOSGLKView * glView; - (instancetype)initWithFrame:(CGRect)frame app:(ofxiOSApp *)app; diff --git a/addons/ofxiOS/src/core/ofxiOSMLKView.h b/addons/ofxiOS/src/core/ofxiOSMLKView.h new file mode 100644 index 00000000000..b4d11f65d21 --- /dev/null +++ b/addons/ofxiOS/src/core/ofxiOSMLKView.h @@ -0,0 +1,71 @@ +// +// ofxiOSGLKView.mm +// iPhone+OF Static Library +// +// Created by Dan Rosser on 7/3/18. +// + + +#pragma once +#include +#import +#if defined(OF_METAL) +#import "EAMLKView.h" +#import +#import +#include +#import +#import +#import +#import + +class ofxiOSApp; +class ofAppiOSWindow; + +@interface ofxiOSMLKView : UIView { + +@protected + NSMutableDictionary * activeTouches; + glm::vec2 * screenSize; // because glm::vec2 is forward declared, + glm::vec2 * windowSize; // these values have to be pointers. + glm::vec2 * windowPos; + MGLKView * theMetal; + CGFloat scaleFactor; + CGFloat scaleFactorPref; +} + +@property (readonly, nonatomic, getter=getScreenSize) glm::vec2 * screenSize; +@property (readonly, nonatomic, getter=getWindowSize) glm::vec2 * windowSize; +@property (readonly, nonatomic, getter=getWindowPosition) glm::vec2 * windowPos; + ++ (ofxiOSMLKView *) getInstance; + +- (instancetype)initWithFrame:(CGRect)frame + andApp:(ofxiOSApp *)app; + +- (void)setupApp:(ofxiOSApp *)app; + +- (void)mglkView:(MGLKView *)view drawInRect:(CGRect)rect; +- (void)setupMetal:(MGLKView *)metal; +- (void)setup; +- (void)update; +- (void)draw; +- (void)setMSAA:(bool)on; +- (void)updateDimensions; +- (void)destroy; +- (CGPoint)orientateTouchPoint:(CGPoint)touchPoint; +- (void)resetTouches; + +- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event; +- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event; +- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event; +- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event; +//- (void)touchesEstimatedPropertiesUpdated:(NSSet *)touches; +//- (void)notifyAnimationStarted; +//- (void)notifyAnimationStopped; +//- (void)notifyDraw; +//- (void)notifyResized; + + +@end +#endif diff --git a/addons/ofxiOS/src/core/ofxiOSMLKView.mm b/addons/ofxiOS/src/core/ofxiOSMLKView.mm new file mode 100644 index 00000000000..8178437cff1 --- /dev/null +++ b/addons/ofxiOS/src/core/ofxiOSMLKView.mm @@ -0,0 +1,618 @@ +// +// ofxiOSGLKView.mm +// iPhone+OF Static Library +// +// Created by Dan Rosser on 7/3/18. +// +#if defined(OF_METAL) + +#include "ofxiOSMLKView.h" +#include "ofxiOSApp.h" +#include "ofAppiOSWindow.h" +#include "ofGLRenderer.h" +#include "ofGLProgrammableRenderer.h" +#include +#import + +static ofxiOSMLKView * _instanceRef = nil; + +@interface ofxiOSMLKView() { + BOOL bInit; + shared_ptr window; + shared_ptr app; + BOOL bSetup; + + + // The pixel dimensions of the backbuffer + GLint backingWidth; + GLint backingHeight; + + MGLContext *context; + MGLLayer *glLayer; + + // Shader objects + GLuint vertexShader; + GLuint fragmentShader; + GLuint shaderProgram; + + Boolean firstTouch; + Boolean needsErase; + + // Buffer Objects + GLuint vboId; + + BOOL initialized; +} +- (void)updateDimensions; +@end + +@implementation ofxiOSMLKView + +@synthesize screenSize; +@synthesize windowSize; +@synthesize windowPos; + + ++ (ofxiOSMLKView *) getInstance { + return _instanceRef; +} + +// You must implement this method ++ (Class) layerClass { + return [MGLLayer class]; +} + ++(id)alloc{ + NSLog(@"Allocating..."); +// return self; + return [super alloc]; +} + + +- (id)initWithCoder:(NSCoder *)coder +{ + if ((self = [super initWithCoder:coder])) + { + glLayer = (MGLLayer *)self.layer; + + glLayer.opaque = YES; + // In this application, we want to retain the EAGLDrawable contents after a call to + // presentRenderbuffer. + glLayer.drawableColorFormat = MGLDrawableColorFormatRGBA8888; + glLayer.drawableDepthFormat = MGLDrawableDepthFormatNone; + glLayer.drawableStencilFormat = MGLDrawableStencilFormatNone; + glLayer.retainedBacking = YES; + + if(true) + glLayer.drawableMultisample = MGLDrawableMultisample4X; + else + glLayer.drawableMultisample = MGLDrawableMultisampleNone; + // +// #if TARGET_OS_IOS || (TARGET_OS_IPHONE && !TARGET_OS_TV) +//// glLayer.multipleTouchEnabled = true; +// #endif + // self.opaque = true; + // + // [self bindDrawable]; + // + bInit = YES; + + context = [[MGLContext alloc] initWithAPI:kMGLRenderingAPIOpenGLES2]; + + if (!context || ![MGLContext setCurrentContext:context]) + { + return nil; + } + + // Set the view's scale factor as you wish + self.contentScaleFactor = [[UIScreen mainScreen] scale]; + + + } + + return self; +} + + +// If our view is resized, we'll be asked to layout subviews. +// This is the perfect opportunity to also update the framebuffer so that it is +// the same size as our display area. +- (void)layoutSubviews +{ + [MGLContext setCurrentContext:context forLayer:glLayer]; + + if (!initialized) + { + initialized = [self initGL]; + } + else + { + [self resizeFromGLLayer]; + } + + // Clear the framebuffer the first time it is allocated + if (needsErase) + { + [self erase]; + needsErase = NO; + } + + window->events().notifyWindowResized(ofGetWidth(), ofGetHeight()); +} + +- (BOOL)resizeFromGLLayer +{ + backingWidth = (GLint)glLayer.drawableSize.width; + backingHeight = (GLint)glLayer.drawableSize.height; + + + // Update viewport + glViewport(0, 0, backingWidth, backingHeight); + + return YES; +} + +- (BOOL)initGL +{ + backingWidth = (GLint)glLayer.drawableSize.width; + backingHeight = (GLint)glLayer.drawableSize.height; + + // Setup the view port in Pixels + glViewport(0, 0, backingWidth, backingHeight); + +} + +// Releases resources when they are not longer needed. +- (void)dealloc +{ + [self destroy]; + // vbo + if (vboId) + { + glDeleteBuffers(1, &vboId); + vboId = 0; + } + + // tear down context + if ([MGLContext currentContext] == context) + [MGLContext setCurrentContext:nil]; +} + +- (void)erase +{ + [MGLContext setCurrentContext:context forLayer:glLayer]; + + // Clear the buffer + glClearColor(0.0, 0.0, 0.0, 0.0); + glClear(GL_COLOR_BUFFER_BIT); + + // Display the buffer + [glLayer present]; +} + + +- (instancetype)initWithFrame:(CGRect)frame andApp:(ofxiOSApp *)appPtr { +// theMetal = glView; + window = dynamic_pointer_cast(ofGetMainLoop()->getCurrentWindow()); + + if(window.get() == NULL) { + ofLog(OF_LOG_FATAL_ERROR, "ofxiOSEAMLView::initWithFrame - window is NULL"); + return nil; + } + + +// ESRendererVersion preferedRendererVersion = (ESRendererVersion)window->getSettings().glesVersion; +// + + +// self = [self initWithFrame:frame +// andPreferedRenderer:preferedRendererVersion +// andAA:window->isAntiAliasingEnabled() +// andRetina:window->isRetinaEnabled() +// andRetinaScale:window->getRetinaScale() +// colorFormat:(MGLDrawableColorFormat)window->getRendererColorType() +// depthFormat:(MGLDrawableDepthFormat)window->getRendererDepthType() +// stencilFormat:(MGLDrawableStencilFormat)window->getRendererStencilType()]; + + bSetup = NO; + //if(self) { + + _instanceRef = self; + + app = shared_ptr(appPtr); + activeTouches = [[NSMutableDictionary alloc] init]; + + screenSize = new glm::vec2(); + windowSize = new glm::vec2(); + windowPos = new glm::vec2(); + ofSetOrientation(window->getOrientation()); + [self updateDimensions]; + + CGRect bounds = [[UIScreen mainScreen] bounds]; + *windowSize = glm::vec2(bounds.size.width * scaleFactor, bounds.size.height * scaleFactor); + *screenSize = glm::vec2(bounds.size.width * scaleFactor, bounds.size.height * scaleFactor); + + bInit = YES; + //} + + return self; +} + +- (void)setup { + if(window.get() == NULL) { + ofLog(OF_LOG_FATAL_ERROR, "ofxiOSEAGLView setup. Failed setup. window is NULL"); + return; + } + + [self updateDimensions]; + + if(app.get() != ofGetAppPtr()) { // check if already running. + + ofSetMainLoop(shared_ptr(NULL)); // destroy old main loop. + auto mainLoop = std::make_shared(); // make new main loop. + ofSetMainLoop(mainLoop); + + ofiOSWindowSettings windowSettings = window->getSettings(); + window = NULL; + + window = dynamic_pointer_cast(ofCreateWindow(windowSettings)); + + ofRunApp(app); + } + + if(window->isProgrammableRenderer() == true) { + static_cast(window->renderer().get())->setup(window->getSettings().glesVersion, 0); + } else{ + static_cast(window->renderer().get())->setup(); + } + + ofxiOSAlerts.addListener(app.get()); + + ofDisableTextureEdgeHack(); + + window->events().notifySetup(); + bSetup = YES; + window->renderer()->clear(); +} + +- (void)destroy { + if(!bInit) { + return; + } + + window->events().notifyExit(); + + ofxiOSAlerts.removeListener(app.get()); + + ofGetMainLoop()->exit(); + + app = NULL; + window = NULL; + + activeTouches = nil; + delete screenSize; + screenSize = NULL; + delete windowSize; + windowSize = NULL; + delete windowPos; + windowPos = NULL; + + _instanceRef = nil; + + bInit = NO; + +// [super destroy]; +} + +- (void)setupApp:(ofxiOSApp *)appPtr { + bSetup = NO; + //if(self) { + + _instanceRef = self; + + app = shared_ptr(appPtr); + activeTouches = [[NSMutableDictionary alloc] init]; + + screenSize = new glm::vec2(); + windowSize = new glm::vec2(); + windowPos = new glm::vec2(); + ofSetOrientation(window->getOrientation()); + [self updateDimensions]; + + CGRect bounds = [[UIScreen mainScreen] bounds]; + *windowSize = glm::vec2(bounds.size.width * scaleFactor, bounds.size.height * scaleFactor); + *screenSize = glm::vec2(bounds.size.width * scaleFactor, bounds.size.height * scaleFactor); + + bInit = YES; + +// bSetup = YES; +} + +- (void)mglkView:(MGLKView *)view drawInRect:(CGRect)rect { +// [super mglkView:view drawInRect:rect]; +} + +//- (void)dealloc { +// [self destroy]; +//} +// +//- (void)layoutSubviews { +//// [super layoutSubviews]; +//// [self updateDimensions]; +//// +//// [super notifyResized]; +// window->events().notifyWindowResized(ofGetWidth(), ofGetHeight()); +//} + +- (void)updateDimensions { + if(glLayer) { + + *windowPos = glm::vec2(glLayer.frame.origin.x * scaleFactor, glLayer.frame.origin.y * scaleFactor); + *windowSize = glm::vec2(glLayer.bounds.size.width * scaleFactor, glLayer.bounds.size.height * scaleFactor); + + UIScreen * currentScreen = self.window.screen; // current screen is the screen that GLView is attached to. + if(!currentScreen) { // if GLView is not attached, assume to be main device screen. + currentScreen = [UIScreen mainScreen]; + } + *screenSize = glm::vec2(currentScreen.bounds.size.width * scaleFactor, currentScreen.bounds.size.height * scaleFactor); + } else { + ofLog(OF_LOG_FATAL_ERROR, "ofxiOSMLKView updateDimensions. No Metal is NULL"); + + CGRect bounds = [[UIScreen mainScreen] bounds]; + *windowSize = glm::vec2(bounds.size.width * scaleFactor, bounds.size.height * scaleFactor); + *screenSize = glm::vec2(bounds.size.width * scaleFactor, bounds.size.height * scaleFactor); + } +} + +- (void) setMSAA:(bool)on +{ + if(on) + glLayer.drawableMultisample = MGLDrawableMultisample4X; + else + glLayer.drawableMultisample = MGLDrawableMultisampleNone; +} + +- (void)notifyResized { + // blank this. + // we want to notifyResized at the end of layoutSubviews. +} + +- (void)update { + if(bSetup == NO) return; + + window->events().notifyUpdate(); +} + + +- (void)draw { + if(bSetup == NO) return; + + window->renderer()->startRender(); + + if(window->isSetupScreenEnabled()) { + window->renderer()->setupScreen(); + } + + //------------------------------------------ draw. + + window->events().notifyDraw(); + + //------------------------------------------ + + window->renderer()->finishRender(); + +// [super notifyDraw]; // alerts delegate that a new frame has been drawn. +} + + +- (void)notifyDraw { + // blank this. + // we want to notifyDraw at the end of drawView. +} + +//------------------------------------------------------ +- (CGPoint)orientateTouchPoint:(CGPoint)touchPoint { + + if(ofAppiOSWindow::getInstance()->doesHWOrientation()) { + return touchPoint; + } + + ofOrientation orientation = ofGetOrientation(); + CGPoint touchPointOriented = CGPointZero; + + switch(orientation) { + case OF_ORIENTATION_180: + touchPointOriented.x = ofGetWidth() - touchPoint.x; + touchPointOriented.y = ofGetHeight() - touchPoint.y; + break; + + case OF_ORIENTATION_90_RIGHT: + touchPointOriented.x = touchPoint.y; + touchPointOriented.y = ofGetHeight() - touchPoint.x; + break; + + case OF_ORIENTATION_90_LEFT: + touchPointOriented.x = ofGetWidth() - touchPoint.y; + touchPointOriented.y = touchPoint.x; + break; + + case OF_ORIENTATION_DEFAULT: + default: + touchPointOriented = touchPoint; + break; + } + return touchPointOriented; +} + +//------------------------------------------------------ + +-(void) resetTouches { + + [activeTouches removeAllObjects]; +} + +- (void)touchesBegan:(NSSet *)touches + withEvent:(UIEvent *)event{ + + if(!bInit || !bSetup) { + // if the glView is destroyed which also includes the OF app, + // we no longer need to pass on these touch events. + return; + } + + for(UITouch *touch in touches) { + int touchIndex = 0; + while([[activeTouches allValues] containsObject:[NSNumber numberWithInt:touchIndex]]){ + touchIndex++; + } + + [activeTouches setObject:@(touchIndex) forKey:[NSValue valueWithPointer:(__bridge void *)touch]]; + + CGPoint touchPoint = [touch locationInView:self]; + + touchPoint.x *= scaleFactor; // this has to be done because retina still returns points in 320x240 but with high percision + touchPoint.y *= scaleFactor; + touchPoint = [self orientateTouchPoint:touchPoint]; + + if( touchIndex==0 ){ + window->events().notifyMousePressed(touchPoint.x, touchPoint.y, 0); + } + + ofTouchEventArgs touchArgs; + touchArgs.numTouches = [[event touchesForView:self] count]; + touchArgs.x = touchPoint.x; + touchArgs.y = touchPoint.y; + touchArgs.id = touchIndex; + if([touch tapCount] == 2){ + touchArgs.type = ofTouchEventArgs::doubleTap; + ofNotifyEvent(window->events().touchDoubleTap,touchArgs); // send doubletap + } + touchArgs.type = ofTouchEventArgs::down; + ofNotifyEvent(window->events().touchDown,touchArgs); // but also send tap (upto app programmer to ignore this if doubletap came that frame) + } +} + +//- (void)setupMetal:(MGLKView *)metal { +// +// if(theMetal == nil) +// theMetal = metal; +// [self updateDimensions]; +//} + +//------------------------------------------------------ +- (void)touchesMoved:(NSSet *)touches + withEvent:(UIEvent *)event{ + + if(!bInit || !bSetup) { + // if the glView is destroyed which also includes the OF app, + // we no longer need to pass on these touch events. + return; + } + + for(UITouch *touch in touches){ + int touchIndex = [[activeTouches objectForKey:[NSValue valueWithPointer:(__bridge void *)touch]] intValue]; + + CGPoint touchPoint = [touch locationInView:self]; + + touchPoint.x *= scaleFactor; // this has to be done because retina still returns points in 320x240 but with high percision + touchPoint.y *= scaleFactor; + touchPoint = [self orientateTouchPoint:touchPoint]; + + if( touchIndex==0 ){ + window->events().notifyMouseDragged(touchPoint.x, touchPoint.y, 0); + } + ofTouchEventArgs touchArgs; + touchArgs.numTouches = [[event touchesForView:self] count]; + touchArgs.x = touchPoint.x; + touchArgs.y = touchPoint.y; + touchArgs.id = touchIndex; + touchArgs.type = ofTouchEventArgs::move; + ofNotifyEvent(window->events().touchMoved, touchArgs); + } +} + +//------------------------------------------------------ +- (void)touchesEnded:(NSSet *)touches + withEvent:(UIEvent *)event{ + + if(!bInit || !bSetup) { + // if the glView is destroyed which also includes the OF app, + // we no longer need to pass on these touch events. + return; + } + + for(UITouch *touch in touches){ + int touchIndex = [[activeTouches objectForKey:[NSValue valueWithPointer:(__bridge void *)touch]] intValue]; + + [activeTouches removeObjectForKey:[NSValue valueWithPointer:(__bridge void *)touch]]; + + CGPoint touchPoint = [touch locationInView:self]; + + touchPoint.x *= scaleFactor; // this has to be done because retina still returns points in 320x240 but with high percision + touchPoint.y *= scaleFactor; + touchPoint = [self orientateTouchPoint:touchPoint]; + + if( touchIndex==0 ){ + window->events().notifyMouseReleased(touchPoint.x, touchPoint.y, 0); + } + + ofTouchEventArgs touchArgs; + touchArgs.numTouches = [[event touchesForView:self] count] - [touches count]; + touchArgs.x = touchPoint.x; + touchArgs.y = touchPoint.y; + touchArgs.id = touchIndex; + touchArgs.type = ofTouchEventArgs::up; + ofNotifyEvent(window->events().touchUp, touchArgs); + } +} + +//------------------------------------------------------ +- (void)touchesCancelled:(NSSet *)touches + withEvent:(UIEvent *)event{ + + if(!bInit || !bSetup) { + // if the glView is destroyed which also includes the OF app, + // we no longer need to pass on these touch events. + return; + } + + for(UITouch *touch in touches){ + int touchIndex = [[activeTouches objectForKey:[NSValue valueWithPointer:(__bridge void *)touch]] intValue]; + + CGPoint touchPoint = [touch locationInView:self]; + + touchPoint.x *= scaleFactor; // this has to be done because retina still returns points in 320x240 but with high percision + touchPoint.y *= scaleFactor; + touchPoint = [self orientateTouchPoint:touchPoint]; + + ofTouchEventArgs touchArgs; + touchArgs.numTouches = [[event touchesForView:self] count]; + touchArgs.x = touchPoint.x; + touchArgs.y = touchPoint.y; + touchArgs.id = touchIndex; + touchArgs.type = ofTouchEventArgs::cancel; + ofNotifyEvent(window->events().touchCancelled, touchArgs); + } + + [self touchesEnded:touches withEvent:event]; +} + + +- (void)updateScaleFactor { + //GLKView *view = (GLKView *)self; + + scaleFactor = MIN(scaleFactorPref, [self contentScaleFactor]); + if(scaleFactor != self.contentScaleFactor) { + self.contentScaleFactor = scaleFactor; + } +} + + + + + + + +@end + +#endif diff --git a/addons/ofxiOS/src/core/ofxiOSMLKViewController.h b/addons/ofxiOS/src/core/ofxiOSMLKViewController.h new file mode 100644 index 00000000000..2a08fbeea13 --- /dev/null +++ b/addons/ofxiOS/src/core/ofxiOSMLKViewController.h @@ -0,0 +1,55 @@ +// +// ofxiOSMLKViewController.h +// iOS+OFLib +// +// Created by Dan Rosser on 11/5/22. +// + +#ifndef ofxiOSMLKViewController_h +#define ofxiOSMLKViewController_h + +#pragma once + +#include +#if TARGET_OS_IOS || (TARGET_OS_IPHONE && !TARGET_OS_TV) + +#import +#import + +#if defined(OF_METAL) + +#import +#import +#import "EAMLKView.h" +#import "ofxiOSMLKView.h" + +class ofxiOSApp; +//@class ofxiOSMLKView; + + +@interface ofxiOSMLKViewController : MGLKViewController + + +@property (nonatomic, strong) MGLKView * glView; // no subclass +@property (nonatomic, strong) ofxiOSMLKView * ofView; + +- (instancetype)initWithFrame:(CGRect)frame app:(ofxiOSApp *)app; +- (void)setupApp:(ofxiOSApp *)appPtr; + +- (void)mglkView:(MGLKView *)view drawInRect:(CGRect)rect; + +- (UIInterfaceOrientation)currentInterfaceOrientation; +- (void)setCurrentInterfaceOrientation:(UIInterfaceOrientation) orient; +- (void)rotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation + animated:(BOOL)animated; +- (BOOL)isReadyToRotate; +- (void)setPreferredFPS:(int)fps; +- (void)setMSAA:(bool)value; + +@end + +#endif + +#endif /* OF_METAL_KIT */ + +#endif /* ofxiOSMLKViewController_h */ diff --git a/addons/ofxiOS/src/core/ofxiOSMLKViewController.mm b/addons/ofxiOS/src/core/ofxiOSMLKViewController.mm new file mode 100644 index 00000000000..64f390a990d --- /dev/null +++ b/addons/ofxiOS/src/core/ofxiOSMLKViewController.mm @@ -0,0 +1,650 @@ +// +// ofxiOSGLKViewController.mm +// iPhone+OF Static Library +// +// Created by Dan Rosser on 7/3/18. +// + +#include +#if defined(OF_METAL) +#if TARGET_OS_IOS || (TARGET_OS_IPHONE && !TARGET_OS_TV) + +#import "ofxiOSMLKViewController.h" + +#include "ofxiOSMLKView.h" +#import "ofxiOSExtras.h" +#include "ofAppiOSWindow.h" + +@interface ofxiOSMLKViewController() { + UIInterfaceOrientation currentInterfaceOrientation; + UIInterfaceOrientation pendingInterfaceOrientation; + BOOL bReadyToRotate; + BOOL bFirstUpdate; + BOOL bAnimated; + + MGLContext *_asyncLoadContext; + +// EAMLKView *mlkview; + + ofxiOSMLKView *mlkview; +} +@end + +@implementation ofxiOSMLKViewController + +@synthesize glView; +@synthesize ofView; +//@synthesize mtlkView; + +- (id)initWithCoder:(NSCoder *)aDecoder { + + currentInterfaceOrientation = pendingInterfaceOrientation = UIInterfaceOrientationPortrait; + + currentInterfaceOrientation = pendingInterfaceOrientation = self.interfaceOrientation; + if( [[[UIDevice currentDevice] systemVersion] compare:@"8.0" options:NSNumericSearch] == NSOrderedAscending ) { + bReadyToRotate = NO; + }else{ + bReadyToRotate = YES; + } + bFirstUpdate = NO; + bAnimated = NO; + +// if ([self.view isKindOfClass:[ofxiOSMLKView class]]) { +// mlkview = (ofxiOSMLKView *)self.view; +// if(mlkview != nullptr) { +// [mlkview setupApp:app]; +// } +// } else if ([self.view isKindOfClass:[EAMLKView class]]) { +// // wtf +// +// +// } else { +// // no idea +// } + + return self; + +} + +- (instancetype)initWithFrame:(CGRect)frame app:(ofxiOSApp *)app { +// return [self initWithFrame:frame app:app]; + currentInterfaceOrientation = pendingInterfaceOrientation = UIInterfaceOrientationPortrait; + if((self = [super init])) { + currentInterfaceOrientation = pendingInterfaceOrientation = self.interfaceOrientation; + if( [[[UIDevice currentDevice] systemVersion] compare:@"8.0" options:NSNumericSearch] == NSOrderedAscending ) { + bReadyToRotate = NO; + }else{ + bReadyToRotate = YES; + } + bFirstUpdate = NO; + bAnimated = NO; + + //self.glView = [[MGLKView alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; +// self.view = customView; +// self.view = self.glView ; +// self.glView = customView; +// mlkview = (EAMLKView *)self.view; + + if ([self.view isKindOfClass:[ofxiOSMLKView class]]) { + mlkview = (ofxiOSMLKView *)self.view; + if(mlkview != nullptr) { + [mlkview initWithFrame:frame andApp:app]; + } + } else if ([self.view isKindOfClass:[EAMLKView class]]) { + // wtf + + + } else { + // no idea + } + + + +// ofxiOSMLKView *newObject = [[ofxiOSMLKView alloc] initWithFrame:frame andApp:app]; + +// self.ofView = newObject; + +// self.mlkview.delegate = self; + + +// self.ofView.delegate = self; + } + + return self; +} + + +-(void)setupApp:(ofxiOSApp *)app { +// return [self initWithFrame:frame app:app]; + currentInterfaceOrientation = pendingInterfaceOrientation = UIInterfaceOrientationPortrait; +// if((self = [super init])) { + currentInterfaceOrientation = pendingInterfaceOrientation = self.interfaceOrientation; + if( [[[UIDevice currentDevice] systemVersion] compare:@"8.0" options:NSNumericSearch] == NSOrderedAscending ) { + bReadyToRotate = NO; + }else{ + bReadyToRotate = YES; + } + bFirstUpdate = NO; + bAnimated = NO; + + //self.glView = [[MGLKView alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; +// self.view = customView; +// self.view = self.glView ; +// self.glView = customView; +// mlkview = (EAMLKView *)self.view; + + if ([self.view isKindOfClass:[ofxiOSMLKView class]]) { + mlkview = (ofxiOSMLKView *)self.view; + if(mlkview != nullptr) { + [mlkview setupApp:app]; + } + } else if ([self.view isKindOfClass:[EAMLKView class]]) { + // wtf + + + } else { + // no idea + } + + + +// ofxiOSMLKView *newObject = [[ofxiOSMLKView alloc] initWithFrame:frame andApp:app]; + + self.ofView = mlkview; + +// self.mlkview.delegate = self; +// +// +// self.ofView.delegate = self; +// } + +// return self; +} + +- (void) dealloc { + [self.glView removeFromSuperview]; + self.glView.delegate = nil; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + + +// self.glView = self.view; + + //self.glView = mtlkView; +// view.context = [self.ofView context]; +// [MGLContext setCurrentContext:view.context]; + + // Create OpenGL context + self.glView.drawableDepthFormat = MGLDrawableDepthFormat16; + + bool useGLES3 = getenv("MGL_OF_USE_GLES3"); + useGLES3 = NO; + + MGLRenderingAPI api; + + if (useGLES3) + { + api = kMGLRenderingAPIOpenGLES3; + } + else + { + api = kMGLRenderingAPIOpenGLES2; + } + + MGLContext *context = [[MGLContext alloc] initWithAPI:api]; + self.glView.context = context; + + [MGLContext setCurrentContext:context]; + + self.glView.context = context; + [self.ofView setupMetal:self.glView]; + + self.glView.delegate = self; +// + self.delegate = self; + self.preferredFramesPerSecond = 60; //default +// [self.glView setMultipleTouchEnabled:ofxiOSGetOFWindow()->isMultiTouch()]; + [self.glView bindDrawable]; + [self.ofView setup]; +} + + +-(void) checkError +{ + GLenum error = glGetError(); + + if (error == GL_NO_ERROR) + return; + + switch (error) + { + case GL_INVALID_ENUM: + NSLog(@"Invalid Enum"); + break; + } +} + +- (void)mglkView:(MGLKView *)view drawInRect:(CGRect)rect { + [view bindDrawable]; + +// @try { + [self.ofView draw]; +// } +// +// @catch ( NSException *e ) { +// NSLog(@"exception:%@", e.reason); +// } +// + +} + + + +- (void)viewDidUnload +{ + [super viewDidUnload]; +} + +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + [self.ofView resetTouches]; +} + +- (void)glkViewControllerUpdate:(GLKViewController *)controller { + [self.ofView update]; +} + +- (void)mglkViewControllerUpdate:(MGLKViewController *)controller { + [self.ofView update]; +} + +- (void)mglkViewControllerUpdate:(MGLKViewController *)controller willPause:(BOOL)pause { +// [self.ofView update]; +} + +- (void)glkViewController:(GLKViewController *)controller willPause:(BOOL)pause { + +} + +- (void) glkView:(GLKView *)view drawInRect:(CGRect)rect +{ + [view bindDrawable]; + [self.ofView draw]; +} + +- (void)viewDidAppear:(BOOL)animated { + [super viewDidAppear:animated]; + + // rotation of the glView only works properly after viewDidAppear. + // this is something to do with either the bounds, center or transform properties not being initialised earlier. + // so now that glView is ready, we rotate it to the pendingInterfaceOrientation. + if( [[[UIDevice currentDevice] systemVersion] compare:@"8.0" options:NSNumericSearch] == NSOrderedAscending ) { + bReadyToRotate = YES; + bFirstUpdate = YES; + [self rotateToInterfaceOrientation:pendingInterfaceOrientation animated:NO]; + } +} + +- (void)viewWillDisappear:(BOOL)animated { + [super viewWillDisappear:animated]; +} + +- (void)viewDidDisappear:(BOOL)animated { + [super viewDidDisappear:animated]; +} + +- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { + if(self.glView != nil) + [self.glView touchesBegan:touches withEvent:event]; + if(self.ofView != nil) + [self.ofView touchesBegan:touches withEvent:event]; +} + +- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { + if(self.glView != nil) + [self.ofView touchesMoved:touches withEvent:event]; + if(self.ofView != nil) + [self.ofView touchesMoved:touches withEvent:event]; +} +- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { + if(self.glView != nil) + [self.ofView touchesEnded:touches withEvent:event]; + if(self.ofView != nil) + [self.ofView touchesEnded:touches withEvent:event]; +} +- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { + if(self.glView != nil) + [self.ofView touchesCancelled:touches withEvent:event]; + if(self.ofView != nil) + [self.ofView touchesCancelled:touches withEvent:event]; +} + +- (void)touchesEstimatedPropertiesUpdated:(NSSet *)touches { +// if(self.glView != nil) +// [self.ofView touchesEstimatedPropertiesUpdated:touches]; +// if(self.ofView != nil) +// [self.ofView touchesEstimatedPropertiesUpdated:touches]; +} + + +//-------------------------------------------------------------- glView callbacks. +- (void)glViewAnimationStarted { + // +} + +- (void)glViewAnimationStopped { + // +} + +- (void)glViewDraw { + // +} + +- (void)glViewResized { + // +} + +//-------------------------------------------------------------- orientation. +- (UIInterfaceOrientation)currentInterfaceOrientation { + return currentInterfaceOrientation; +} + +//-------------------------------------------------------------- orientation. +- (void)setCurrentInterfaceOrientation:(UIInterfaceOrientation) orient { + currentInterfaceOrientation = pendingInterfaceOrientation = orient; +} + +- (float)rotationForOrientation:(UIInterfaceOrientation)interfaceOrientation { + if (interfaceOrientation == UIInterfaceOrientationPortrait) { + return 0; // 0 degrees. + } else if (interfaceOrientation == UIInterfaceOrientationLandscapeRight) { + return M_PI * 0.5; // 90 degrees. + } else if (interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown) { + return M_PI; // 180 degrees. + } else if (interfaceOrientation == UIInterfaceOrientationLandscapeLeft) { + return M_PI * 1.5; // 270 degrees. + } else { + return 0; + } +} + +- (void)rotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation + animated:(BOOL)animated { + bAnimated = animated; + + + if(bReadyToRotate == NO) { + pendingInterfaceOrientation = interfaceOrientation; + + // we need to update the dimensions here, so if ofSetOrientation is called in setup, + // then it will return the correct width and height + CGSize screenSize = [UIScreen mainScreen].bounds.size; + CGRect bounds = CGRectMake(0, 0, screenSize.width, screenSize.height); + if(UIInterfaceOrientationIsLandscape(interfaceOrientation)) { + bounds.size.width = screenSize.height; + bounds.size.height = screenSize.width; + } + self.glView.bounds = bounds; + [self.ofView updateDimensions]; + + return; + } + + + if(currentInterfaceOrientation == interfaceOrientation && !bFirstUpdate) { + return; + } + + if(pendingInterfaceOrientation != interfaceOrientation) { + CGSize screenSize = [UIScreen mainScreen].bounds.size; + CGRect bounds = CGRectMake(0, 0, screenSize.width, screenSize.height); + if(UIInterfaceOrientationIsLandscape(interfaceOrientation)) { + bounds.size.width = screenSize.height; + bounds.size.height = screenSize.width; + } + self.glView.bounds = bounds; + [self.ofView updateDimensions]; + } + + CGSize screenSize = [UIScreen mainScreen].bounds.size; + CGPoint center; + CGRect bounds = CGRectMake(0, 0, screenSize.width, screenSize.height); + + if(UIInterfaceOrientationIsLandscape(interfaceOrientation)) { + center.x = screenSize.height * 0.5; + center.y = screenSize.width * 0.5; + } else { + center.x = screenSize.width * 0.5; + center.y = screenSize.height * 0.5; + } + + // Is the iOS version less than 8? + if( [[[UIDevice currentDevice] systemVersion] compare:@"8.0" options:NSNumericSearch] == NSOrderedAscending ) { + if(UIInterfaceOrientationIsLandscape(interfaceOrientation)) { + bounds.size.width = screenSize.height; + bounds.size.height = screenSize.width; + } + } else { + // Fixes for iOS 8 Portrait to Landscape issues + if((UIInterfaceOrientationIsPortrait(interfaceOrientation) && screenSize.width >= screenSize.height) || + (UIInterfaceOrientationIsLandscape(interfaceOrientation) && screenSize.height >= screenSize.width)) { + bounds.size.width = screenSize.height; + bounds.size.height = screenSize.width; + } else { + bounds.size.width = screenSize.width; + bounds.size.height = screenSize.height; + } + //borg + //NSLog(@"w %f h %f",[UIScreen mainScreen].bounds.size.width,[UIScreen mainScreen].bounds.size.height); + //assumes Portrait orientation + if(screenSize.width>screenSize.height){ + center.x = screenSize.height * 0.5; + center.y = screenSize.width * 0.5; + }else{ + center.x = screenSize.width * 0.5; + center.y = screenSize.height * 0.5; + } + //NSLog(@"rotating to portrait %i, is portrait %i, currentInterfaceOrientation %i, bound: w %f h %f",UIInterfaceOrientationIsPortrait(interfaceOrientation),UIInterfaceOrientationIsPortrait(self.interfaceOrientation),UIInterfaceOrientationIsPortrait(currentInterfaceOrientation),bounds.size.width,bounds.size.height); + } + + float rot1 = [self rotationForOrientation:currentInterfaceOrientation]; + float rot2 = [self rotationForOrientation:interfaceOrientation]; + float rot3 = rot2 - rot1; + CGAffineTransform rotate = CGAffineTransformMakeRotation(rot3); + rotate = CGAffineTransformConcat(rotate, self.glView.transform); + + if(animated) { + NSTimeInterval duration = 0.3; + if((UIInterfaceOrientationIsLandscape(currentInterfaceOrientation) && UIInterfaceOrientationIsLandscape(interfaceOrientation)) || + (UIInterfaceOrientationIsPortrait(currentInterfaceOrientation) && UIInterfaceOrientationIsPortrait(interfaceOrientation))) { + duration = 0.6; + } + [self.glView.layer removeAllAnimations]; + [UIView animateWithDuration:duration animations:^{ + self.glView.center = center; + self.glView.transform = rotate; + self.glView.bounds = bounds; + }]; + } else { + self.glView.center = center; + self.glView.transform = rotate; + self.glView.bounds = bounds; + } + + currentInterfaceOrientation = interfaceOrientation; + bFirstUpdate = NO; + + [self.ofView updateDimensions]; +} + + +//-------------------------------------------------------------- orientation callbacks. +// http://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/RespondingtoDeviceOrientationChanges/RespondingtoDeviceOrientationChanges.html + +- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation + duration:(NSTimeInterval)duration { + + // CALLBACK 1. + // The window calls the root view controller’s willRotateToInterfaceOrientation:duration: method. + // Container view controllers forward this message on to the currently displayed content view controllers. + // You can override this method in your custom content view controllers to hide views or make other changes to your view layout before the interface is rotated. + // Deprecated in iOS 8. See viewWillTransitionToSize below. +} + +- (void)viewWillLayoutSubviews { + [super viewWillLayoutSubviews]; + + // CALLBACK 2. + // The window adjusts the bounds of the view controller’s view. + // This causes the view to layout its subviews, triggering the view controller’s viewWillLayoutSubviews method. + // When this method runs, you can query the app object’s statusBarOrientation property to determine the current user interface layout. +} + +- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation + duration:(NSTimeInterval)duration { + + // CALLBACK 3. + // This method is called from within an animation block so that any property changes you make + // are animated at the same time as other animations that comprise the rotation. + // Deprecated in iOS 8. See viewWillTransitionToSize below. + + CGSize screenSize = [UIScreen mainScreen].bounds.size; + + CGPoint center; + // Is the iOS version less than 8? + if( [[[UIDevice currentDevice] systemVersion] compare:@"8.0" options:NSNumericSearch] == NSOrderedAscending ) { + if(UIInterfaceOrientationIsLandscape(self.interfaceOrientation)) { + center.x = screenSize.height * 0.5; + center.y = screenSize.width * 0.5; + } else { + center.x = screenSize.width * 0.5; + center.y = screenSize.height * 0.5; + } + } else { + center.x = screenSize.width * 0.5; + center.y = screenSize.height * 0.5; + } + + if(bAnimated) { + NSTimeInterval duration = 0.3; + [self.glView.layer removeAllAnimations]; + [UIView animateWithDuration:duration animations:^{ + self.glView.center = center; + self.glView.transform = CGAffineTransformMakeRotation(0); + }]; + } else { + self.glView.center = center; + self.glView.transform = CGAffineTransformMakeRotation(0); + } +} + +// iOS8+ version of willAnimateRotationToInterfaceOrientation +//NOTE: Only called if actually resizing and not masked +//http://stackoverflow.com/questions/25935006/ios8-interface-rotation-methods-not-called + +//borg +#ifdef __IPHONE_8_0 +- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator { + + CGPoint center; + + center.x = size.width * 0.5; + center.y = size.height * 0.5; + + + if(bAnimated) { + NSTimeInterval duration = 0.3; + [self.glView.layer removeAllAnimations]; + [UIView animateWithDuration:duration animations:^{ + self.glView.center = center; + self.glView.transform = CGAffineTransformMakeRotation(0); + self.glView.frame = CGRectMake(0, 0, size.width,size.height); + }]; + } else { + self.glView.center = center; + self.glView.transform = CGAffineTransformMakeRotation(0); + self.glView.frame = CGRectMake(0, 0, size.width,size.height); + } +} +#endif + + +- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { + + // CALLBACK 4. + // This action marks the end of the rotation process. + // You can use this method to show views, change the layout of views, or make other changes to your app. +} + +//-------------------------------------------------------------- iOS5 and earlier. +- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation { + return (toInterfaceOrientation == currentInterfaceOrientation); +} + +- (NSUInteger)supportedInterfaceOrientations { + switch (currentInterfaceOrientation) { + case UIInterfaceOrientationPortrait: + return UIInterfaceOrientationMaskPortrait; + break; + case UIInterfaceOrientationPortraitUpsideDown: + return UIInterfaceOrientationMaskPortraitUpsideDown; + break; + case UIInterfaceOrientationLandscapeLeft: + return UIInterfaceOrientationMaskLandscapeLeft; + break; + case UIInterfaceOrientationLandscapeRight: + return UIInterfaceOrientationMaskLandscapeRight; + break; + default: + break; + } + // defaults to orientations selected in the .plist file ('Supported Interface Orientations' in the XCode Project) + return -1; +} +- (BOOL)shouldAutorotate { + return YES; +} + +- (BOOL)isReadyToRotate { + return bReadyToRotate; +} + +-(BOOL)prefersStatusBarHidden{ + return YES; +} + +- (void)setPreferredFPS:(int)fps { + if(self.glView != nil) { + self.preferredFramesPerSecond = fps; + } +} + +- (CGSize)size +{ + return self.glView.drawableSize; +} + +- (void)setMSAA:(bool)value { + if(self.glView != nil) { + if(value) + self.glView.drawableMultisample = MGLDrawableMultisample4X; + else + self.glView.drawableMultisample = MGLDrawableMultisampleNone; + +// [self.glView setMSAA:value]; + } +} + + +- (UIImage*)getSnapshot { + return glView.snapshot; +} + +@end + + + +#endif +#endif diff --git a/addons/ofxiOS/src/metal/EAMLKView.h b/addons/ofxiOS/src/metal/EAMLKView.h new file mode 100644 index 00000000000..819065fc668 --- /dev/null +++ b/addons/ofxiOS/src/metal/EAMLKView.h @@ -0,0 +1,82 @@ +//// +//// EAGLKView.h +//// iPhone+OF Static Library +//// +//// Created by Dan Rosser on 11/5/22. +//// +// +// +#pragma once +// +#if defined(OF_METAL) +#import +#import +#import +#endif +#import + +////#import +//#import +// +//#import +//#import +//#import "ESRenderer.h" +// +/// ???: inherit MGLKViewDelegate? +@protocol EAMGLKViewDelegate +@optional +- (void)glViewAnimationStarted; +- (void)glViewAnimationStopped; +- (void)glViewDraw; +- (void)glViewResized; +@end + +@interface EAMLKView : UIView +{ + +@protected + + CGFloat scaleFactor; + CGFloat scaleFactorPref; + + BOOL bUseDepth; + BOOL bUseMSAA; + BOOL bUseRetina; + NSInteger msaaSamples; + //ESRendererVersion rendererVersion; +} + +/// TODO: need to give protocol explicity. +/// ???: can we assume EAGLKViewDelegate is inherit GLKViewDelegate? +@property (nonatomic, weak) id delegate; + +//- (instancetype)initWithFrame:(CGRect)frame +// andAA:(bool)msaaEnabled +// andRetina:(bool)retinaEnabled +// andRetinaScale:(CGFloat)retinaScale +// colorFormat:(MGLDrawableColorFormat)colorFormat +// depthFormat:(MGLDrawableDepthFormat)depthFormat +// stencilFormat:(MGLDrawableStencilFormat)stencilFormat; +// + + +- (void)setup; +- (void)update; +- (void)draw; +- (void)destroy; + +- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event; +- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event; +- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event; +- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event; + +- (void)touchesEstimatedPropertiesUpdated:(NSSet *)toucheso; +- (void)setMSAA:(bool)on; +- (void)notifyAnimationStarted; +- (void)notifyAnimationStopped; +- (void)notifyDraw; +- (void)notifyResized; + +@end + +#endif diff --git a/addons/ofxiOS/src/metal/EAMLKView.mm b/addons/ofxiOS/src/metal/EAMLKView.mm new file mode 100644 index 00000000000..6790e815a18 --- /dev/null +++ b/addons/ofxiOS/src/metal/EAMLKView.mm @@ -0,0 +1,322 @@ +// +// EAMLKView.h +// iPhone+OF Static Library +// +// Created by Dan Rosser on 11/5/22. +// + +#include +#if defined(OF_METAL) +#import "EAMLKView.h" +#import + +#import "ES2Renderer.h" + +@interface EAMLKView() { + BOOL bInit; + + // The pixel dimensions of the backbuffer + GLint backingWidth; + GLint backingHeight; + + MGLContext *context; + __weak MGLLayer *glLayer; + + // Shader objects + GLuint vertexShader; + GLuint fragmentShader; + GLuint shaderProgram; + + Boolean firstTouch; + Boolean needsErase; + + // Buffer Objects + GLuint vboId; + + BOOL initialized; +} +@end + +@implementation EAMLKView + +@synthesize delegate; +// You must implement this method ++ (Class) layerClass { + return [MGLLayer class]; +} + +- (id)initWithCoder:(NSCoder *)coder +{ + if ((self = [super initWithCoder:coder])) + { + glLayer = (MGLLayer *)self.layer; + + glLayer.opaque = YES; + // In this application, we want to retain the EAGLDrawable contents after a call to + // presentRenderbuffer. + glLayer.drawableColorFormat = MGLDrawableColorFormatRGBA8888; + glLayer.drawableDepthFormat = MGLDrawableDepthFormatNone; + glLayer.drawableStencilFormat = MGLDrawableStencilFormatNone; + glLayer.retainedBacking = YES; + + if(true) + glLayer.drawableMultisample = MGLDrawableMultisample4X; + else + glLayer.drawableMultisample = MGLDrawableMultisampleNone; + // +// #if TARGET_OS_IOS || (TARGET_OS_IPHONE && !TARGET_OS_TV) +//// glLayer.multipleTouchEnabled = true; +// #endif + // self.opaque = true; + // + // [self bindDrawable]; + // + bInit = YES; + + context = [[MGLContext alloc] initWithAPI:kMGLRenderingAPIOpenGLES2]; + + if (!context || ![MGLContext setCurrentContext:context]) + { + return nil; + } + + // Set the view's scale factor as you wish + self.contentScaleFactor = [[UIScreen mainScreen] scale]; + + + } + + return self; +} + + +// If our view is resized, we'll be asked to layout subviews. +// This is the perfect opportunity to also update the framebuffer so that it is +// the same size as our display area. +- (void)layoutSubviews +{ + [MGLContext setCurrentContext:context forLayer:glLayer]; + + if (!initialized) + { + initialized = [self initGL]; + } + else + { + [self resizeFromGLLayer]; + } + + // Clear the framebuffer the first time it is allocated + if (needsErase) + { + [self erase]; + needsErase = NO; + } +} + +- (BOOL)resizeFromGLLayer +{ + backingWidth = (GLint)glLayer.drawableSize.width; + backingHeight = (GLint)glLayer.drawableSize.height; + + + // Update viewport + glViewport(0, 0, backingWidth, backingHeight); + + return YES; +} + +- (BOOL)initGL +{ + backingWidth = (GLint)glLayer.drawableSize.width; + backingHeight = (GLint)glLayer.drawableSize.height; + + // Setup the view port in Pixels + glViewport(0, 0, backingWidth, backingHeight); + return true; + +} + +// Releases resources when they are not longer needed. +- (void)dealloc +{ + [self destroy]; + // vbo + if (vboId) + { + glDeleteBuffers(1, &vboId); + vboId = 0; + } + + // tear down context + if ([MGLContext currentContext] == context) + [MGLContext setCurrentContext:nil]; +} + +- (void)erase +{ + [MGLContext setCurrentContext:context forLayer:glLayer]; + + // Clear the buffer + glClearColor(0.0, 0.0, 0.0, 0.0); + glClear(GL_COLOR_BUFFER_BIT); + + // Display the buffer + [glLayer present]; +} + +//- (instancetype)initWithFrame:(CGRect)frame +// andPreferedRenderer:(ESRendererVersion)version +// andAA:(bool)msaaEnabled +// andRetina:(bool)retinaEnabled +// andRetinaScale:(CGFloat)retinaScale +// colorFormat:(MGLDrawableColorFormat)colorFormat +// depthFormat:(MGLDrawableDepthFormat)depthFormat +// stencilFormat:(MGLDrawableStencilFormat)stencilFormat { +// +// if((self = [super initWithFrame:frame])) { +// +// rendererVersion = version; +// bUseMSAA = msaaEnabled; +// bUseRetina = retinaEnabled; +// //------------------------------------------------------ +// scaleFactorPref = retinaScale; +// +// if(bUseRetina == YES) { +// if(scaleFactorPref == 0.0) { +// scaleFactorPref = [[UIScreen mainScreen] nativeScale]; // no scale preference, default to max scale. +// } else { +// if(scaleFactorPref < 1.0) { +// scaleFactorPref = 1.0; // invalid negative value, default scale to 1. +// } else if(scaleFactorPref > [[UIScreen mainScreen] nativeScale]) { +// scaleFactorPref = [[UIScreen mainScreen] nativeScale]; +// } +// } +// } else { +// scaleFactorPref = 1.0; +// } +// +// [self updateScaleFactor]; +// +// //------------------------------------------------------ +// if(rendererVersion == ESRendererVersion_30) { +// NSLog(@"OpenGLES 3.0 Renderer not implemented for oF. Defaulting to OpenGLES 2.0"); +// rendererVersion = ESRendererVersion_20; +// } +// +// if(rendererVersion == ESRendererVersion_20) { +// self.context = [[MGLContext alloc] initWithAPI:kMGLRenderingAPIOpenGLES2]; +// NSLog(@"Creating OpenGL ES2 Renderer"); +// if(!self.context) { +// NSLog(@"OpenGL ES2 failed"); +// rendererVersion = ESRendererVersion_11; +// } +// } +// +// +// +// self.drawableColorFormat = colorFormat; +// self.drawableDepthFormat = depthFormat; +// self.drawableStencilFormat = stencilFormat; +// +// if(msaaEnabled) +// self.drawableMultisample = MGLDrawableMultisample4X; +// else +// self.drawableMultisample = MGLDrawableMultisampleNone; +// +//#if TARGET_OS_IOS || (TARGET_OS_IPHONE && !TARGET_OS_TV) +// self.multipleTouchEnabled = true; +//#endif +// self.opaque = true; +// +// [self bindDrawable]; +// +// bInit = YES; +// } +// +// return self; +//} + +- (void) destroy { + if(!bInit) { + return; + } + bInit = NO; +} + +//- (void) dealloc{ +// [self destroy]; +//} + +- (void) setup { + +} +- (void) update{ + +} + +- (void) draw{ + +} + +- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { } +- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { } +- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { } +- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { } +#ifdef __IPHONE_9_1 +- (void)touchesEstimatedPropertiesUpdated:(NSSet *)touches { } +#endif + + +//------------------------------------------------------------------- +- (void)updateScaleFactor { + MGLKView *view = (MGLKView *)self; + + scaleFactor = MIN(scaleFactorPref, [view contentScaleFactor]); + if(scaleFactor != self.contentScaleFactor) { + self.contentScaleFactor = scaleFactor; + } +} + +- (void) setMSAA:(bool)on +{ + if(on) + glLayer.drawableMultisample = MGLDrawableMultisample4X; + else + glLayer.drawableMultisample = MGLDrawableMultisampleNone; +} + +//------------------------------------------------------------------- notify. +- (void) notifyAnimationStarted { + if([self.delegate respondsToSelector:@selector(glViewAnimationStarted)]) { + [self.delegate glViewAnimationStarted]; + } +} + +- (void) notifyAnimationStopped { + if([self.delegate respondsToSelector:@selector(glViewAnimationStopped)]) { + [self.delegate glViewAnimationStopped]; + } +} + +- (void) notifyDraw { + if([self.delegate respondsToSelector:@selector(glViewDraw)]) { + [self.delegate glViewDraw]; + } +} + +- (void) notifyResized { + if([self.delegate respondsToSelector:@selector(glViewResized)]) { + [self.delegate glViewResized]; + } +} + +- (BOOL)canBecomeFirstResponder +{ + return YES; +} + + +@end + +#endif diff --git a/addons/ofxiOS/src/metal/MGLKit/MGLContext+Private.h b/addons/ofxiOS/src/metal/MGLKit/MGLContext+Private.h new file mode 100644 index 00000000000..30e0051a650 --- /dev/null +++ b/addons/ofxiOS/src/metal/MGLKit/MGLContext+Private.h @@ -0,0 +1,25 @@ +// +// Copyright 2019 Le Hoang Quyen. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +#if defined(OF_METAL) +#ifndef MGLContext_Private_h +#define MGLContext_Private_h + +#import "MGLContext.h" +#import "MGLDisplay.h" + +#include + +@interface MGLContext () { + MGLRenderingAPI _renderingApi; +} + +@property(nonatomic, readonly) MGLDisplay *display; +@property(nonatomic, readonly) EGLContext eglContext; + +@end + +#endif /* MGLContext_Private_h */ +#endif diff --git a/addons/ofxiOS/src/metal/MGLKit/MGLContext.h b/addons/ofxiOS/src/metal/MGLKit/MGLContext.h new file mode 100644 index 00000000000..7f484a6c821 --- /dev/null +++ b/addons/ofxiOS/src/metal/MGLKit/MGLContext.h @@ -0,0 +1,57 @@ +// +// Copyright 2019 Le Hoang Quyen. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#import "MGLLayer.h" + +#if defined(OF_METAL) + +#include "EGL/egl.h" + +NS_ASSUME_NONNULL_BEGIN + +typedef enum MGLRenderingAPI : int +{ + kMGLRenderingAPIOpenGLES1 = 1, + kMGLRenderingAPIOpenGLES2 = 2, + kMGLRenderingAPIOpenGLES3 = 3, +} MGLRenderingAPI; + +@interface MGLSharegroup : NSObject +@end + +@interface MGLContext : NSObject + +- (id)initWithAPI:(MGLRenderingAPI)api; + +// NOTE: If you use sharegroup to share resources between contexts, make sure to call glFlush() +// when you finish the works of one context on a thread to make the changes visible to other +// contexts. +- (id)initWithAPI:(MGLRenderingAPI)api sharegroup:(MGLSharegroup *_Nullable)sharegroup; + +@property(nonatomic, readonly) MGLRenderingAPI API; + +@property(readonly) MGLSharegroup *sharegroup; + +@property(nonatomic, readonly) EGLDisplay eglDisplay; + +// Present the content of layer on screen as soon as possible. +- (BOOL)present:(MGLLayer *)layer; + ++ (MGLContext *)currentContext; ++ (MGLLayer *)currentLayer; + +// Set current context without layer. NOTE: this function is only useful if you want to +// create OpenGL resources such as textures/buffers before creating the presentation layer. +// Before drawing to a layer, use [MGLContext setCurrentContext: forLayer:] function instead. ++ (BOOL)setCurrentContext:(MGLContext *_Nullable)context; + +// Set current context to render to the given layer. ++ (BOOL)setCurrentContext:(MGLContext *_Nullable)context forLayer:(MGLLayer *_Nullable)layer; + +@end +NS_ASSUME_NONNULL_END +#endif + diff --git a/addons/ofxiOS/src/metal/MGLKit/MGLContext.mm b/addons/ofxiOS/src/metal/MGLKit/MGLContext.mm new file mode 100644 index 00000000000..4022c835f81 --- /dev/null +++ b/addons/ofxiOS/src/metal/MGLKit/MGLContext.mm @@ -0,0 +1,320 @@ +// +// MGLContext.m +// OpenGLES +// +// Created by Le Quyen on 16/10/19. +// Copyright © 2019 Google. All rights reserved. +// + +#import "MGLContext.h" +#import "MGLContext+Private.h" + +#if defined(OF_METAL) + +#include +#include + +#include +#include +#include +#include +#include +#import "MGLLayer+Private.h" + +namespace +{ +struct ThreadLocalInfo +{ + __weak MGLContext *currentContext = nil; + __weak MGLLayer *currentLayer = nil; +}; + +#if TARGET_OS_SIMULATOR +pthread_key_t gThreadSpecificKey; +void ThreadTLSDestructor(void *data) +{ + auto tlsData = reinterpret_cast(data); + delete tlsData; +} + +#endif + +ThreadLocalInfo &CurrentTLS() +{ +#if TARGET_OS_SIMULATOR + // There are some issuess with C++11 TLS could not be compiled on iOS + // simulator, so we have to fallback to use pthread TLS. + static pthread_once_t sKeyOnce = PTHREAD_ONCE_INIT; + pthread_once(&sKeyOnce, [] { pthread_key_create(&gThreadSpecificKey, ThreadTLSDestructor); }); + + auto tlsData = reinterpret_cast(pthread_getspecific(gThreadSpecificKey)); + if (!tlsData) + { + tlsData = new ThreadLocalInfo(); + pthread_setspecific(gThreadSpecificKey, tlsData); + } + return *tlsData; +#else // TARGET_OS_SIMULATOR + static thread_local ThreadLocalInfo tls; + return tls; +#endif +} + +void Throw(NSString *msg) +{ + [NSException raise:@"MGLSurfaceException" format:@"%@", msg]; +} + +EGLContext CreateEGLContext(EGLDisplay display, MGLRenderingAPI api, EGLContext sharedContext) +{ + // Init config + std::vector surfaceAttribs = { + EGL_RED_SIZE, EGL_DONT_CARE, EGL_GREEN_SIZE, EGL_DONT_CARE, + EGL_BLUE_SIZE, EGL_DONT_CARE, EGL_ALPHA_SIZE, EGL_DONT_CARE, + EGL_DEPTH_SIZE, EGL_DONT_CARE, EGL_STENCIL_SIZE, EGL_DONT_CARE, + EGL_SAMPLE_BUFFERS, EGL_DONT_CARE, EGL_SAMPLES, EGL_DONT_CARE, + }; + surfaceAttribs.push_back(EGL_NONE); + EGLConfig config; + EGLint numConfigs; + if (!eglChooseConfig(display, surfaceAttribs.data(), &config, 1, &numConfigs) || numConfigs < 1) + { + Throw(@"Failed to call eglChooseConfig()"); + } + + // Init context + int ctxMajorVersion = 2; + int ctxMinorVersion = 0; + switch (api) + { + case kMGLRenderingAPIOpenGLES1: + ctxMajorVersion = 1; + ctxMinorVersion = 0; + break; + case kMGLRenderingAPIOpenGLES2: + ctxMajorVersion = 2; + ctxMinorVersion = 0; + break; + case kMGLRenderingAPIOpenGLES3: + ctxMajorVersion = 3; + ctxMinorVersion = 0; + break; + default: + UNREACHABLE(); + } + EGLint ctxAttribs[] = {EGL_CONTEXT_MAJOR_VERSION, ctxMajorVersion, EGL_CONTEXT_MINOR_VERSION, + ctxMinorVersion, EGL_NONE}; + + EGLContext eglContext = eglCreateContext(display, config, sharedContext, ctxAttribs); + if (eglContext == EGL_NO_CONTEXT) + { + Throw(@"Failed to call eglCreateContext()"); + } + + return eglContext; +} +} + +// MGLSharegroup implementation +@interface MGLSharegroup () { + __weak MGLContext *_firstContext; + EGLDisplay _sharedEGLDisplay; + EGLContext _sharedEGLContext; +} + +// This shared context is only created when the shared group has more +// than one context. +- (EGLContext)sharedEGLContext; +- (void)addContext:(MGLContext *)context; + +@end + +@implementation MGLSharegroup + +- (id)init +{ + if (self = [super init]) + { + _sharedEGLContext = EGL_NO_CONTEXT; + } + return self; +} + +- (void)dealloc +{ + if (_sharedEGLContext != EGL_NO_CONTEXT) + { + eglDestroyContext(_sharedEGLDisplay, _sharedEGLContext); + _sharedEGLContext = EGL_NO_CONTEXT; + } +} + +- (EGLContext)sharedEGLContext +{ + @synchronized(self) + { + return _sharedEGLContext; + } +} + +- (void)addContext:(MGLContext *)context +{ + @synchronized(self) + { + if (!_firstContext) + { + _firstContext = context; + } + else if (_sharedEGLContext == EGL_NO_CONTEXT) + { + // If we have more than one context in the shared group, create + // a "master" context to be shared by all contexts in the group. + _sharedEGLDisplay = _firstContext.display.eglDisplay; + _sharedEGLContext = + CreateEGLContext(_sharedEGLDisplay, _firstContext.API, _firstContext.eglContext); + } + } +} + +@end + +// MGLContext implementation + +@implementation MGLContext + +- (id)initWithAPI:(MGLRenderingAPI)api +{ + return [self initWithAPI:api sharegroup:nil]; +} + +- (id)initWithAPI:(MGLRenderingAPI)api sharegroup:(MGLSharegroup *)sharegroup +{ + if (self = [super init]) + { + _renderingApi = api; + _display = [MGLDisplay defaultDisplay]; + if (sharegroup) + { + _sharegroup = sharegroup; + } + else + { + _sharegroup = [MGLSharegroup new]; + } + + [_sharegroup addContext:self]; + + [self initContext]; + } + return self; +} + +- (MGLRenderingAPI)API +{ + return _renderingApi; +} + +- (EGLDisplay)eglDisplay +{ + return _display.eglDisplay; +} + +- (void)dealloc +{ + [self releaseContext]; + + _display = nil; +} + +- (void)releaseContext +{ + if (eglGetCurrentContext() == _eglContext) + { + eglMakeCurrent(_display.eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + } + + if (_eglContext != EGL_NO_CONTEXT) + { + eglDestroyContext(_display.eglDisplay, _eglContext); + _eglContext = EGL_NO_CONTEXT; + } +} + +- (void)initContext +{ + _eglContext = + CreateEGLContext(_display.eglDisplay, _renderingApi, _sharegroup.sharedEGLContext); +} + +- (BOOL)present:(MGLLayer *)layer +{ + return [layer present]; +} + ++ (MGLContext *)currentContext +{ + return CurrentTLS().currentContext; +} + ++ (MGLLayer *)currentLayer +{ + return CurrentTLS().currentLayer; +} + ++ (BOOL)setCurrentContext:(MGLContext *)context +{ + ThreadLocalInfo &tlsData = CurrentTLS(); + if (context) + { + return [context setCurrentContextForLayer:tlsData.currentLayer]; + } + + // No context + tlsData.currentContext = nil; + tlsData.currentLayer = nil; + + return eglMakeCurrent([MGLDisplay defaultDisplay].eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, + EGL_NO_CONTEXT); +} + ++ (BOOL)setCurrentContext:(MGLContext *)context forLayer:(MGLLayer *)layer +{ + if (context) + { + return [context setCurrentContextForLayer:layer]; + } + return [self setCurrentContext:nil]; +} + +- (BOOL)setCurrentContextForLayer:(MGLLayer *_Nullable)layer +{ + if (!layer) + { + if (eglGetCurrentContext() != _eglContext || + eglGetCurrentSurface(EGL_READ) != EGL_NO_SURFACE || + eglGetCurrentSurface(EGL_DRAW) != EGL_NO_SURFACE) + { + if (!eglMakeCurrent(_display.eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, _eglContext)) + { + return NO; + } + } + } + else + { + if (![layer setCurrentContext:self]) + { + return NO; + } + } + + ThreadLocalInfo &tlsData = CurrentTLS(); + tlsData.currentContext = self; + tlsData.currentLayer = layer; + + return YES; +} + +@end + +#endif diff --git a/addons/ofxiOS/src/metal/MGLKit/MGLDisplay.h b/addons/ofxiOS/src/metal/MGLKit/MGLDisplay.h new file mode 100644 index 00000000000..fa62af37733 --- /dev/null +++ b/addons/ofxiOS/src/metal/MGLKit/MGLDisplay.h @@ -0,0 +1,26 @@ +// +// Copyright 2019 Le Hoang Quyen. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +#if defined(OF_METAL) +#ifndef MGLKitCommon_h +#define MGLKitCommon_h + +#import + +#include +#include +#include +#include + +@interface MGLDisplay : NSObject + +@property(nonatomic, readonly) EGLDisplay eglDisplay; + ++ (MGLDisplay *)defaultDisplay; + +@end + +#endif /* MGLKitCommon_h */ +#endif diff --git a/addons/ofxiOS/src/metal/MGLKit/MGLDisplay.mm b/addons/ofxiOS/src/metal/MGLKit/MGLDisplay.mm new file mode 100644 index 00000000000..68517c38c23 --- /dev/null +++ b/addons/ofxiOS/src/metal/MGLKit/MGLDisplay.mm @@ -0,0 +1,92 @@ +// +// Copyright 2019 Le Hoang Quyen. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +#if defined(OF_METAL) +#import "MGLDisplay.h" + +namespace +{ +void Throw(NSString *msg) +{ + [NSException raise:@"MGLSurfaceException" format:@"%@", msg]; +} +} + +// EGLDisplayHolder +@interface EGLDisplayHolder : NSObject +@property(nonatomic) EGLDisplay eglDisplay; +@end + +@implementation EGLDisplayHolder + +- (id)init +{ + if (self = [super init]) + { + // Init display + EGLAttrib displayAttribs[] = {EGL_NONE}; + _eglDisplay = eglGetPlatformDisplay(EGL_PLATFORM_ANGLE_ANGLE, nullptr, displayAttribs); + if (_eglDisplay == EGL_NO_DISPLAY) + { + Throw(@"Failed To call eglGetPlatformDisplay()"); + } + if (!eglInitialize(_eglDisplay, NULL, NULL)) + { + Throw(@"Failed To call eglInitialize()"); + } + } + + return self; +} + +- (void)dealloc +{ + if (_eglDisplay != EGL_NO_DISPLAY) + { + eglTerminate(_eglDisplay); + _eglDisplay = EGL_NO_DISPLAY; + } +} + +@end + +static EGLDisplayHolder *gGlobalDisplayHolder; +static MGLDisplay *gDefaultDisplay; + +// MGLDisplay implementation +@interface MGLDisplay () { + EGLDisplayHolder *_eglDisplayHolder; +} + +@end + +@implementation MGLDisplay + ++ (MGLDisplay *)defaultDisplay +{ + if (!gDefaultDisplay) + { + gDefaultDisplay = [[MGLDisplay alloc] init]; + } + return gDefaultDisplay; +} + +- (id)init +{ + if (self = [super init]) + { + if (!gGlobalDisplayHolder) + { + gGlobalDisplayHolder = [[EGLDisplayHolder alloc] init]; + } + _eglDisplayHolder = gGlobalDisplayHolder; + _eglDisplay = _eglDisplayHolder.eglDisplay; + } + + return self; +} + +@end +#endif diff --git a/addons/ofxiOS/src/metal/MGLKit/MGLKView+Private.h b/addons/ofxiOS/src/metal/MGLKit/MGLKView+Private.h new file mode 100644 index 00000000000..dc5ed79d9b0 --- /dev/null +++ b/addons/ofxiOS/src/metal/MGLKit/MGLKView+Private.h @@ -0,0 +1,22 @@ +// +// Copyright 2019 Le Hoang Quyen. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +#if defined(OF_METAL) +#ifndef MGLKView_Private_h +#define MGLKView_Private_h + +#import "MGLKView.h" + +@class MGLKViewController; + +@interface MGLKView () + +@property(atomic) BOOL drawing; +@property(nonatomic, weak) MGLKViewController *controller; + +@end + +#endif /* MGLKView_Private_h */ +#endif diff --git a/addons/ofxiOS/src/metal/MGLKit/MGLKView.h b/addons/ofxiOS/src/metal/MGLKit/MGLKView.h new file mode 100644 index 00000000000..17f62e86814 --- /dev/null +++ b/addons/ofxiOS/src/metal/MGLKit/MGLKView.h @@ -0,0 +1,69 @@ +// +// Copyright 2019 Le Hoang Quyen. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +#if defined(OF_METAL) +#ifndef MGLKView_h +#define MGLKView_h + +#import "MGLContext.h" + +@class MGLKView; + +@protocol MGLKViewDelegate + +// Implement this method to draw to the view using current OpenGL +// context associated with the view. +- (void)mglkView:(MGLKView *)view drawInRect:(CGRect)rect; + +@end + +// NOTE: do not subclass this class, use delegate if needed to override +// the drawing method. +@interface MGLKView : MGLKNativeView + +@property(nonatomic) MGLContext *context; +@property(nonatomic, assign) IBOutlet id delegate; + +// Default value is NO. Setting to YES will keep the framebuffer data after presenting. +// Doing so will reduce performance and increase memory usage. +@property(nonatomic) BOOL retainedBacking; +@property(nonatomic) MGLDrawableColorFormat drawableColorFormat; // Default is RGBA8888 +@property(nonatomic) MGLDrawableDepthFormat drawableDepthFormat; // Default is DepthNone +@property(nonatomic) MGLDrawableStencilFormat drawableStencilFormat; // Default is StencilNone +@property(nonatomic) + MGLDrawableMultisample drawableMultisample; // Default is MGLDrawableMultisampleNone + +@property(nonatomic, weak, readonly) MGLLayer *glLayer; + +// Return the size of the OpenGL default framebuffer. +@property(readonly) CGSize drawableSize; +@property(nonatomic, readonly) NSInteger drawableWidth; +@property(nonatomic, readonly) NSInteger drawableHeight; + +// OpenGL id of the underlying default framebuffer object. +// Might not necessary be zero. +@property(readonly) uint32_t defaultOpenGLFrameBufferID; + +#if TARGET_OS_IOS || TARGET_OS_TV +// Enable setNeedsDisplay method. +@property(nonatomic) BOOL enableSetNeedsDisplay; +@property(readonly, strong) UIImage *snapshot; +#endif + +- (id)initWithFrame:(CGRect)frame context:(MGLContext *)context; + +// Redraw the view's contents immediately. +- (void)display; + +// Binds the underlying default framebuffer object to OpenGL ES. +// Use this after drawing to offscreen FBO. +- (void)bindDrawable; + +@end + +//#define MGLKView ofxiOSMGLKView + +#endif /* MLKView_h */ +#endif diff --git a/addons/ofxiOS/src/metal/MGLKit/MGLKView.mm b/addons/ofxiOS/src/metal/MGLKit/MGLKView.mm new file mode 100644 index 00000000000..873edead9ac --- /dev/null +++ b/addons/ofxiOS/src/metal/MGLKit/MGLKView.mm @@ -0,0 +1,301 @@ +// +// Copyright 2019 Le Hoang Quyen. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +#if defined(OF_METAL) +#import "MGLKView+Private.h" +#import "MGLKViewController+Private.h" + +#include + +namespace +{ +void Throw(NSString *msg) +{ + [NSException raise:@"MGLSurfaceException" format:@"%@", msg]; +} +} + +@implementation MGLKView + +- (id)initWithCoder:(NSCoder *)coder +{ + if (self = [super initWithCoder:coder]) + { +#if TARGET_OS_OSX + self.wantsLayer = YES; + self.autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable; +#else + self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; +#if TARGET_OS_IOS || TARGET_OS_TV + self.enableSetNeedsDisplay = YES; +#endif +#endif + } + return self; +} + +- (id)initWithFrame:(CGRect)frame +{ + if (self = [super initWithFrame:frame]) + { +#if TARGET_OS_OSX + self.wantsLayer = YES; + self.autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable; +#else + self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; +#if TARGET_OS_IOS || TARGET_OS_TV + self.enableSetNeedsDisplay = YES; +#endif +#endif + } + return self; +} + +- (id)initWithFrame:(CGRect)frame context:(MGLContext *)context +{ + if (self = [self initWithFrame:frame]) + { + [self setContext:context]; + } + return self; +} + +- (void)dealloc +{ + _context = nil; +} + +#if TARGET_OS_OSX +- (CALayer *)makeBackingLayer +{ + return [MGLLayer layer]; +} +#else ++ (Class)layerClass +{ + return MGLLayer.class; +} +#endif + +- (MGLLayer *)glLayer +{ + return static_cast(self.layer); +} + +- (void)setContext:(MGLContext *)context +{ + if (_drawing) + { + Throw(@"Changing GL context when drawing is not allowed"); + } + + _context = context; +} + +#if TARGET_OS_IOS || TARGET_OS_TV +- (void)setNeedsDisplay +{ + if (_enableSetNeedsDisplay) + { + [super setNeedsDisplay]; + } +} + +- (void)setNeedsDisplayInRect:(CGRect)invalidRect +{ + if (_enableSetNeedsDisplay) + { + [super setNeedsDisplayInRect:invalidRect]; + } +} +#endif // TARGET_OS_IOS || TARGET_OS_TV + +- (void)setRetainedBacking:(BOOL)retainedBacking +{ + self.glLayer.retainedBacking = _retainedBacking = retainedBacking; +} + +- (void)setDrawableColorFormat:(MGLDrawableColorFormat)drawableColorFormat +{ + self.glLayer.drawableColorFormat = _drawableColorFormat = drawableColorFormat; +} + +- (void)setDrawableDepthFormat:(MGLDrawableDepthFormat)drawableDepthFormat +{ + self.glLayer.drawableDepthFormat = _drawableDepthFormat = drawableDepthFormat; +} + +- (void)setDrawableStencilFormat:(MGLDrawableStencilFormat)drawableStencilFormat +{ + self.glLayer.drawableStencilFormat = _drawableStencilFormat = drawableStencilFormat; +} + +- (void)setDrawableMultisample:(MGLDrawableMultisample)drawableMultisample +{ + self.glLayer.drawableMultisample = _drawableMultisample = drawableMultisample; +} + +- (void)display +{ + [self displayAndCapture:nullptr]; +} + +- (void)bindDrawable +{ + [self.glLayer bindDefaultFrameBuffer]; +} + +- (CGSize)drawableSize +{ + if (!self.layer) + { + CGSize zero = {0}; + return zero; + } + return self.glLayer.drawableSize; +} + +- (NSInteger)drawableWidth +{ + return self.drawableSize.width; +} + +- (NSInteger)drawableHeight +{ + return self.drawableSize.height; +} + +- (uint32_t)defaultOpenGLFrameBufferID +{ + return self.glLayer.defaultOpenGLFrameBufferID; +} + +#if TARGET_OS_OSX +- (void)viewDidMoveToWindow +{ + [super viewDidMoveToWindow]; +#else + - (void)didMoveToWindow + { + [super didMoveToWindow]; +#endif + + // notify view controller + if (_controller) + { + [_controller viewDidMoveToWindow]; + } + } + + - (void)drawRect:(CGRect)rect + { + if (_delegate) + { + [_delegate mglkView:self drawInRect:rect]; + } + } + + - (void)displayAndCapture:(uint8_t **)pPixels + { + _drawing = YES; + if (_context) + { + if (![MGLContext setCurrentContext:_context forLayer:self.glLayer]) + { + Throw(@"Failed to setCurrentContext"); + } + } + + [self drawRect:self.bounds]; + + if (pPixels) + { + // Frame capture request + int width = static_cast(self.drawableSize.width); + int height = static_cast(self.drawableSize.height); + if (width && height) + { + // Capture framebuffer's content + *pPixels = new uint8_t[4 * width * height]; + GLint prevPackAlignment; + gl::GetIntegerv(GL_PACK_ALIGNMENT, &prevPackAlignment); + gl::PixelStorei(GL_PACK_ALIGNMENT, 1); + + // Clear errors + gl::GetError(); + + gl::ReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, *pPixels); + + gl::PixelStorei(GL_PACK_ALIGNMENT, prevPackAlignment); + + // Clear errors + gl::GetError(); + } + else + { + *pPixels = nullptr; + } + } // if (pPixels) + + if (![_context present:self.glLayer]) + { + Throw(@"Failed to present framebuffer"); + } + _drawing = NO; + } + +#if TARGET_OS_IOS || TARGET_OS_TV + static void freeImageData(void *info, const void *data, size_t size) + { + delete[] static_cast(info); + } + + - (UIImage *)snapshot + { + uint8_t *pixels = nullptr; + [self displayAndCapture:&pixels]; + + if (!pixels) + { + return nil; + } + + int width = static_cast(self.drawableSize.width); + int height = static_cast(self.drawableSize.height); + size_t dataLen = width * height * 4; + + uint8_t *flippedPixels = new uint8_t[dataLen]; + for (int y1 = 0; y1 < height; y1++) + { + for (int x1 = 0; x1 < width * 4; x1++) + { + flippedPixels[(height - 1 - y1) * width * 4 + x1] = pixels[y1 * 4 * width + x1]; + } + } + delete[] pixels; + + CGDataProviderRef provider = + CGDataProviderCreateWithData(flippedPixels, flippedPixels, dataLen, freeImageData); + int bitsPerComponent = 8; + int bitsPerPixel = 32; + int bytesPerRow = 4 * width; + CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB(); + CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault | kCGImageAlphaNoneSkipLast; + CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault; + CGImageRef imageRef = + CGImageCreate(width, height, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpaceRef, + bitmapInfo, provider, NULL, NO, renderingIntent); + CGColorSpaceRelease(colorSpaceRef); + CGDataProviderRelease(provider); + UIImage *image = [UIImage imageWithCGImage:imageRef scale:1 orientation:UIImageOrientationUp]; + + CGImageRelease(imageRef); + return image; + } +#endif // TARGET_OS_IOS || TARGET_OS_TV + + @end + +#endif diff --git a/addons/ofxiOS/src/metal/MGLKit/MGLKViewController+Mac.mm b/addons/ofxiOS/src/metal/MGLKit/MGLKViewController+Mac.mm new file mode 100644 index 00000000000..941c1a4675a --- /dev/null +++ b/addons/ofxiOS/src/metal/MGLKit/MGLKViewController+Mac.mm @@ -0,0 +1,203 @@ +// +// Copyright 2019 Le Hoang Quyen. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +#if defined(OF_METAL) +- (void)initImpl {} + +- (void)releaseTimer +{ + if (_displayLink) + { + CVDisplayLinkRelease(_displayLink); + _displayLink = nullptr; + } + if (_displaySource) + { + dispatch_source_cancel(_displaySource); + _displaySource = nullptr; + } + if (_displayTimer) + { + [_displayTimer invalidate]; + _displayTimer = nil; + } +} + +- (void)deallocImpl +{ + NSLog(@"MGLKViewController deallocImpl"); + [self releaseTimer]; +} + +- (void)viewDidMoveToWindow +{ + NSLog(@"MGLKViewController viewDidMoveToWindow"); + if (self.view.window) + { + // Obtain current window's screen refresh rate. + CGDirectDisplayID displayID = + (CGDirectDisplayID)[self.view.window.screen + .deviceDescription[@"NSScreenNumber"] unsignedIntegerValue]; + + CGDisplayModeRef displayModeRef = CGDisplayCopyDisplayMode(displayID); + if (displayModeRef) + { + _currentScreenRefreshRate = CGDisplayModeGetRefreshRate(displayModeRef); + } + CGDisplayModeRelease(displayModeRef); + + // Call resume to reset display link's window + [self pause]; + [self resume]; + + // Register callback to be called when this window is closed. + _observedWindow = self.view.window; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(windowWillClose:) + name:NSWindowWillCloseNotification + object:self.view.window]; + } + else + { + // View is removed from window + [self releaseTimer]; + + // Unregister window closed callback. + if (_observedWindow) + { + [[NSNotificationCenter defaultCenter] removeObserver:self + name:NSWindowWillCloseNotification + object:_observedWindow]; + _observedWindow = nil; + } + } +} + +- (void)windowWillClose:(NSNotification *)notification +{ + NSLog(@"MGLKViewController windowWillClose:"); + [self releaseTimer]; +} + +static CVReturn CVFrameDisplayCallback(CVDisplayLinkRef displayLink, + const CVTimeStamp *now, + const CVTimeStamp *outputTime, + CVOptionFlags flagsIn, + CVOptionFlags *flagsOut, + void *displayLinkContext) +{ + // 'CVFrameDisplayCallback' is always called on a secondary thread. Merge the dispatch source + // setup for the main queue so that rendering occurs on the main thread + __weak dispatch_source_t source = (__bridge dispatch_source_t)displayLinkContext; + dispatch_source_merge_data(source, 1); + + return kCVReturnSuccess; +} + +- (void)setPreferredFramesPerSecond:(NSInteger)preferredFramesPerSecond +{ + _preferredFramesPerSecond = preferredFramesPerSecond; + + [self pause]; + [self resume]; +} + +- (void)pause +{ + if (_paused) + { + return; + } + NSLog(@"MGLKViewController pause"); + + if (_displayLink) + { + CVDisplayLinkStop(_displayLink); + } + if (_displayTimer) + { + [_displayTimer invalidate]; + _displayTimer = nil; + } + + _paused = YES; +} + +- (void)resume +{ + if (!_paused) + { + return; + } + + [self pause]; + NSLog(@"MGLKViewController resume"); + + if (!_glView) + { + return; + } + + if (_preferredFramesPerSecond == 1 || + (_currentScreenRefreshRate && + fabs(_preferredFramesPerSecond - _currentScreenRefreshRate) < 0.00001)) + { + NSWindow *window = _glView.window; + if (!window) + { + return; + } + // The CVDisplayLink callback, CVFrameDisplayCallback, never executes + // on the main thread. To execute rendering on the main thread, create + // a dispatch source using the main queue (the main thread). + // CVFrameDisplayCallback merges this dispatch source in each call + // to execute rendering on the main thread. + if (!_displaySource) + { + _displaySource = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0, + dispatch_get_main_queue()); + __weak MGLKViewController *weakSelf = self; + dispatch_source_set_event_handler(_displaySource, ^() { + [weakSelf frameStep]; + }); + dispatch_resume(_displaySource); + } + + // Sync to display refresh rate using CVDisplayLink + _needEnableVsync = YES; + if (!_displayLink) + { + CVDisplayLinkCreateWithActiveCGDisplays(&_displayLink); + CVDisplayLinkSetOutputCallback(_displayLink, CVFrameDisplayCallback, + (__bridge void *)_displaySource); + } + CGDirectDisplayID displayID = + (CGDirectDisplayID)[window.screen + .deviceDescription[@"NSScreenNumber"] unsignedIntegerValue]; + CVDisplayLinkSetCurrentCGDisplay(_displayLink, displayID); + + CVDisplayLinkStart(_displayLink); + } + else + { + // Render the frames without in sync with refresh rate. + _needDisableVsync = YES; + + ASSERT(!_displayTimer); + NSTimeInterval frameInterval = + (_preferredFramesPerSecond <= 0) ? 0 : (1.0 / _preferredFramesPerSecond); + _displayTimer = [NSTimer timerWithTimeInterval:frameInterval + target:self + selector:@selector(frameStep) + userInfo:nil + repeats:YES]; + [[NSRunLoop currentRunLoop] addTimer:_displayTimer forMode:NSDefaultRunLoopMode]; + [[NSRunLoop currentRunLoop] addTimer:_displayTimer forMode:NSModalPanelRunLoopMode]; + } + + _paused = NO; +} + +#endif diff --git a/addons/ofxiOS/src/metal/MGLKit/MGLKViewController+Private.h b/addons/ofxiOS/src/metal/MGLKit/MGLKViewController+Private.h new file mode 100644 index 00000000000..7256422d9bb --- /dev/null +++ b/addons/ofxiOS/src/metal/MGLKit/MGLKViewController+Private.h @@ -0,0 +1,44 @@ +// +// Copyright 2019 Le Hoang Quyen. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +#if defined(OF_METAL) +#ifndef MGLKViewController_Private_h +#define MGLKViewController_Private_h + +#import "MGLKViewController.h" + +@interface MGLKViewController () { + __weak MGLKView *_glView; +#if TARGET_OS_OSX + NSTimer *_displayTimer; // Used to render with irregular framerate + CVDisplayLinkRef _displayLink; // Used to render in sync with display refresh rate + dispatch_source_t _displaySource; // Used together with displayLink + double _currentScreenRefreshRate; + NSWindow *_observedWindow; +#else + CADisplayLink *_displayLink; +#endif + CFTimeInterval _lastUpdateTime; + BOOL _needDisableVsync; + BOOL _needEnableVsync; + + BOOL _appWasInBackground; +} + +- (void)viewDidMoveToWindow; + +// Platform specific +- (void)initImpl; +- (void)deallocImpl; +- (void)pause; +- (void)resume; + +// Common +- (void)frameStep; + +@end + +#endif /* MGLKViewController_Private_h */ +#endif diff --git a/addons/ofxiOS/src/metal/MGLKit/MGLKViewController+iOS.mm b/addons/ofxiOS/src/metal/MGLKit/MGLKViewController+iOS.mm new file mode 100644 index 00000000000..9067195feb1 --- /dev/null +++ b/addons/ofxiOS/src/metal/MGLKit/MGLKViewController+iOS.mm @@ -0,0 +1,92 @@ +// +// Copyright 2019 Le Hoang Quyen. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +#if defined(OF_METAL) +- (void)initImpl {} +- (void)deallocImpl {} +- (void)viewDidMoveToWindow {} + +- (void)viewDidLoad +{ + NSLog(@"MGLKViewController viewDidLoad"); + [super viewDidLoad]; +} + +- (void)setPreferredFramesPerSecond:(NSInteger)preferredFramesPerSecond +{ + _preferredFramesPerSecond = preferredFramesPerSecond; + if (_displayLink) + { + if (ANGLE_APPLE_AVAILABLE_CI(13.0, 10.0)) + { + _displayLink.preferredFramesPerSecond = _preferredFramesPerSecond; + } + else + { + _displayLink.frameInterval = 60 / std::max(_preferredFramesPerSecond, 1); + } + } + [self pause]; + [self resume]; +} + +- (void)pause +{ + if (_paused) + { + return; + } + + NSLog(@"MGLKViewController pause"); + + if (_displayLink) + { + [_displayLink removeFromRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; + _displayLink = nil; + } + + _paused = YES; +} + +- (void)resume +{ + if (!_paused) + { + return; + } + + [self pause]; + NSLog(@"MGLKViewController resume"); + + if (!_glView) + { + return; + } + + if (!_displayLink) + { + _displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(frameStep)]; + if (ANGLE_APPLE_AVAILABLE_CI(13.0, 10.0)) + { + _displayLink.preferredFramesPerSecond = _preferredFramesPerSecond == 1 ? 0 : _preferredFramesPerSecond; + } + else + { + if (_preferredFramesPerSecond <= 1) + { + _displayLink.frameInterval = 1; + } + else { + _displayLink.frameInterval = 60 / _preferredFramesPerSecond; + } + } + } + + [_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; + + _paused = NO; +} + +#endif diff --git a/addons/ofxiOS/src/metal/MGLKit/MGLKViewController.h b/addons/ofxiOS/src/metal/MGLKit/MGLKViewController.h new file mode 100644 index 00000000000..a503c527706 --- /dev/null +++ b/addons/ofxiOS/src/metal/MGLKit/MGLKViewController.h @@ -0,0 +1,44 @@ +// +// Copyright 2019 Le Hoang Quyen. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#if defined(OF_METAL) +#import "MGLKView.h" + +NS_ASSUME_NONNULL_BEGIN + +@class MGLKViewController; + +@protocol MGLKViewControllerDelegate + +- (void)mglkViewControllerUpdate:(MGLKViewController *)controller; + +@end + +@interface MGLKViewController : MGLKNativeViewController + +@property(nonatomic, assign) IBOutlet id delegate; + +// The default value is 30. +// On iOS: +// - Setting to 0 or 1 will sync the framerate with display's refresh rate +// On macOS: +// - Setting to 1 will sync the framerate with display's refresh rate +// - Setting to 0 will display the frames as fast as possible. +@property(nonatomic) NSInteger preferredFramesPerSecond; + +@property(nonatomic, readonly) NSInteger framesDisplayed; +@property(nonatomic, readonly) NSTimeInterval timeSinceLastUpdate; + +@property(nonatomic, getter=isPaused) BOOL paused; +@property(nonatomic) BOOL pauseOnWillResignActive; +@property(nonatomic) BOOL resumeOnDidBecomeActive; + +@property(weak, nonatomic, readonly) MGLKView *glView; + +@end + +NS_ASSUME_NONNULL_END +#endif diff --git a/addons/ofxiOS/src/metal/MGLKit/MGLKViewController.mm b/addons/ofxiOS/src/metal/MGLKit/MGLKViewController.mm new file mode 100644 index 00000000000..f2143f033d9 --- /dev/null +++ b/addons/ofxiOS/src/metal/MGLKit/MGLKViewController.mm @@ -0,0 +1,242 @@ +// +// Copyright 2019 Le Hoang Quyen. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +#if defined(OF_METAL) +#import "MGLKViewController+Private.h" + +#include +#include +#include +#include +#include +#include + +#import "MGLDisplay.h" +#import "MGLKView+Private.h" + +@implementation MGLKViewController + +#if TARGET_OS_OSX +# include "MGLKViewController+Mac.mm" +#else +# include "MGLKViewController+iOS.mm" +#endif + +- (instancetype)init +{ + if (self = [super init]) + { + [self constructor]; + } + return self; +} + +- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil +{ + if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) + { + [self constructor]; + } + return self; +} + +- (instancetype)initWithCoder:(NSCoder *)coder +{ + if (self = [super initWithCoder:coder]) + { + [self constructor]; + } + return self; +} + +- (void)constructor +{ + _appWasInBackground = YES; + _preferredFramesPerSecond = 30; + _pauseOnWillResignActive = YES; + _resumeOnDidBecomeActive = YES; + // not-paused corresponds to having a DisplayLink or timer active and driving the frame loop + _paused = YES; +} + +- (void)dealloc +{ + [self deallocImpl]; +} + +- (void)setView:(MGLKNativeView *)view +{ + [super setView:view]; + if ([view isKindOfClass:MGLKView.class]) + { + _glView = (MGLKView *)view; +#if TARGET_OS_IOS || TARGET_OS_TV + _glView.enableSetNeedsDisplay = NO; +#endif + if (!_glView.delegate) + { + // If view has no delegate, set this controller as its delegate + _glView.delegate = self; + } + // Store this object inside the view itself so that the view can notify + // this controller about certain events such as moving to new window. + _glView.controller = self; + } + else + { + if (_glView.delegate == self) + { + // Detach from old view + _glView.delegate = nil; + } + if (_glView.controller == self) + { + _glView.controller = nil; + } + _glView = nil; + } +} + +- (void)setPaused:(BOOL)paused +{ + if (paused != _paused) { + if (paused) { + [self pause]; + } else { + [self resume]; + } + } +} + +- (void)mglkView:(MGLKView *)view drawInRect:(CGRect)rect +{ + // Default implementation do nothing. +} + +// viewDidAppear callback +#if TARGET_OS_OSX +- (void)viewDidAppear +{ + [super viewDidAppear]; +#else // TARGET_OS_OSX +- (void)viewDidAppear:(BOOL)animated +{ + [super viewDidAppear:animated]; +#endif // TARGET_OS_OSX + NSLog(@"MGLKViewController viewDidAppear"); + + // Implementation dependent + [self resume]; + + // Register callbacks to be called when app enters/exits background + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(appWillPause:) + name:MGLKApplicationWillResignActiveNotification + object:nil]; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(appDidBecomeActive:) + name:MGLKApplicationDidBecomeActiveNotification + object:nil]; +} + +// viewDidDisappear callback +#if TARGET_OS_OSX +- (void)viewDidDisappear + { + [super viewDidDisappear]; +#else // TARGET_OS_OSX + - (void)viewDidDisappear:(BOOL)animated + { + [super viewDidDisappear:animated]; +#endif // TARGET_OS_OSX + NSLog(@"MGLKViewController viewDidDisappear"); + _appWasInBackground = YES; + + // Implementation dependent + [self pause]; + + // Unregister callbacks that are called when app enters/exits background + [[NSNotificationCenter defaultCenter] removeObserver:self + name:MGLKApplicationWillResignActiveNotification + object:nil]; + + [[NSNotificationCenter defaultCenter] removeObserver:self + name:MGLKApplicationDidBecomeActiveNotification + object:nil]; + } + + - (void)appWillPause:(NSNotification *)note + { + NSLog(@"MGLKViewController appWillPause:"); + if (_pauseOnWillResignActive) { + _appWasInBackground = YES; + self.paused = YES; + } + } + + - (void)appDidBecomeActive:(NSNotification *)note + { + NSLog(@"MGLKViewController appDidBecomeActive:"); + if (_resumeOnDidBecomeActive) { + self.paused = NO; + } + } + + - (void)handleAppWasInBackground + { + if (!_appWasInBackground) + { + return; + } + // To avoid time jump when the app goes to background + // for a long period of time. + _lastUpdateTime = CACurrentMediaTime(); + + _appWasInBackground = NO; + } + + - (void)frameStep + { + [self handleAppWasInBackground]; + + CFTimeInterval now = CACurrentMediaTime(); + _timeSinceLastUpdate = now - _lastUpdateTime; + + [self update]; + [_glView display]; + + if (_needDisableVsync) + { + eglSwapInterval([MGLDisplay defaultDisplay].eglDisplay, 0); + _needDisableVsync = NO; + } + else if (_needEnableVsync) + { + eglSwapInterval([MGLDisplay defaultDisplay].eglDisplay, 1); + _needEnableVsync = NO; + } + + _framesDisplayed++; + _lastUpdateTime = now; + +#if 0 + if (_timeSinceLastUpdate > 2 * _displayLink.duration) + { + NSLog(@"frame was jump by %fs", _timeSinceLastUpdate); + } +#endif + } + + - (void)update + { + if (_delegate) + { + [_delegate mglkViewControllerUpdate:self]; + } + } + + @end +#endif diff --git a/addons/ofxiOS/src/metal/MGLKit/MGLKit.h b/addons/ofxiOS/src/metal/MGLKit/MGLKit.h new file mode 100644 index 00000000000..ae0134b6a96 --- /dev/null +++ b/addons/ofxiOS/src/metal/MGLKit/MGLKit.h @@ -0,0 +1,15 @@ +// +// Copyright 2019 Le Hoang Quyen. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +#if defined(OF_METAL) +#ifndef MGLKit_h +#define MGLKit_h + +#import "MGLContext.h" +#import "MGLKView.h" +#import "MGLKViewController.h" + +#endif /* MGLKit_h */ +#endif diff --git a/addons/ofxiOS/src/metal/MGLKit/MGLKitPlatform.h b/addons/ofxiOS/src/metal/MGLKit/MGLKitPlatform.h new file mode 100644 index 00000000000..440ce60b1e7 --- /dev/null +++ b/addons/ofxiOS/src/metal/MGLKit/MGLKitPlatform.h @@ -0,0 +1,34 @@ +// +// Copyright 2020 Le Hoang Quyen. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +#if defined(OF_METAL) +#ifndef MGLKitPlatform_h +#define MGLKitPlatform_h + +#include + +#if TARGET_OS_IOS || TARGET_OS_MACCATALYST || TARGET_OS_TV || TARGET_OS_VISION +# include + +@compatibility_alias MGLKNativeView UIView; +@compatibility_alias MGLKNativeViewController UIViewController; + +# define MGLKApplicationWillResignActiveNotification UIApplicationWillResignActiveNotification +# define MGLKApplicationDidBecomeActiveNotification UIApplicationDidBecomeActiveNotification + +#elif TARGET_OS_OSX +# include + +@compatibility_alias MGLKNativeView NSView; +@compatibility_alias MGLKNativeViewController NSViewController; + +# define MGLKApplicationWillResignActiveNotification NSApplicationWillResignActiveNotification +# define MGLKApplicationDidBecomeActiveNotification NSApplicationDidBecomeActiveNotification +#else +# error "Unsupported platform" +#endif + +#endif /* MGLKitPlatform_h */ +#endif diff --git a/addons/ofxiOS/src/metal/MGLKit/MGLLayer+Private.h b/addons/ofxiOS/src/metal/MGLKit/MGLLayer+Private.h new file mode 100644 index 00000000000..2e6c36e35d5 --- /dev/null +++ b/addons/ofxiOS/src/metal/MGLKit/MGLLayer+Private.h @@ -0,0 +1,51 @@ +// +// Copyright 2019 Le Hoang Quyen. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +#if defined(OF_METAL) +#ifndef MGLLayer_Private_h +#define MGLLayer_Private_h + +#import "MGLLayer.h" + +#import +#import + +#include +#include +#include +#import "MGLDisplay.h" + +@interface MGLLayer () { + MGLDisplay *_display; + // The context that owns the offscreen FBO + MGLContext *_offscreenFBOCreatorContext; + EGLSurface _eglSurface; + CAMetalLayer *_metalLayer; + CALayer *_legacyGLLayer; + + // Textures used to retain the content of framebuffer. + GLuint _offscreenColorUnsizedFormat; + GLuint _offscreenColorFormatDataType; + GLuint _offscreenTexture; // Use if glBlitFramebufferANGLE is not available + GLuint _offscreenRenderBuffer; // Use if glBlitFramebufferANGLE is available + GLuint _offscreenDepthStencilBuffer; + GLuint _offscreenBlitProgram; + GLuint _offscreenBlitVBO; + GLuint _offscreenBlitVAO; + CGSize _offscreenFBOSize; + BOOL _isGLES3Plus; + BOOL _blitFramebufferAvail; + BOOL _drawBuffersAvail; + BOOL _useOffscreenFBO; +} + +@property(nonatomic, readonly) EGLSurface eglSurface; + +- (BOOL)setCurrentContext:(MGLContext *)context; + +@end + +#endif /* MGLLayer_Private_h */ +#endif diff --git a/addons/ofxiOS/src/metal/MGLKit/MGLLayer.h b/addons/ofxiOS/src/metal/MGLKit/MGLLayer.h new file mode 100644 index 00000000000..18ee8047916 --- /dev/null +++ b/addons/ofxiOS/src/metal/MGLKit/MGLLayer.h @@ -0,0 +1,74 @@ +// +// Copyright 2019 Le Hoang Quyen. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +#if defined(OF_METAL) +// We don't use GLES from Apple framework. +// Instead we use GLES provided by MetalANGLE. +#define GLES_SILENCE_DEPRECATION +#define GL_SILENCE_DEPRECATION + +#import +#import + +#import "MGLKitPlatform.h" + +NS_ASSUME_NONNULL_BEGIN + +@class MGLContext; + +typedef enum MGLDrawableColorFormat : int +{ + MGLDrawableColorFormatRGBA8888 = 32, + MGLDrawableColorFormatSRGBA8888 = -32, + MGLDrawableColorFormatRGB565 = 16, +} MGLDrawableColorFormat; + +typedef enum MGLDrawableStencilFormat : int +{ + MGLDrawableStencilFormatNone = 0, + MGLDrawableStencilFormat8 = 8, +} MGLDrawableStencilFormat; + +typedef enum MGLDrawableDepthFormat : int +{ + MGLDrawableDepthFormatNone = 0, + MGLDrawableDepthFormat16 = 16, + MGLDrawableDepthFormat24 = 24, +} MGLDrawableDepthFormat; + +typedef enum MGLDrawableMultisample : int +{ + MGLDrawableMultisampleNone = 0, + MGLDrawableMultisample4X = 4, +} MGLDrawableMultisample; + +@interface MGLLayer : CALayer + +// Return the size of the OpenGL framebuffer. +@property(readonly) CGSize drawableSize; +// Default OpenGL id of the framebuffer storing content of this layer. +// Might not necessary be zero. +@property(readonly) uint32_t defaultOpenGLFrameBufferID; + +@property(nonatomic) MGLDrawableColorFormat drawableColorFormat; // Default is RGBA8888 +@property(nonatomic) MGLDrawableDepthFormat drawableDepthFormat; // Default is DepthNone +@property(nonatomic) MGLDrawableStencilFormat drawableStencilFormat; // Default is StencilNone +@property(nonatomic) + MGLDrawableMultisample drawableMultisample; // Default is MGLDrawableMultisampleNone + +// Default value is NO. Setting to YES will keep the framebuffer data after presenting. +// Doing so will reduce performance and increase memory usage. +@property(nonatomic) BOOL retainedBacking; + +// Present the content of OpenGL backed framebuffer on screen as soon as possible. +- (BOOL)present; + +// Bind default framebuffer. Use this after drawing to offscreen FBO. +- (void)bindDefaultFrameBuffer; + +@end +NS_ASSUME_NONNULL_END + +#endif diff --git a/addons/ofxiOS/src/metal/MGLKit/MGLLayer.mm b/addons/ofxiOS/src/metal/MGLKit/MGLLayer.mm new file mode 100644 index 00000000000..004ee86b103 --- /dev/null +++ b/addons/ofxiOS/src/metal/MGLKit/MGLLayer.mm @@ -0,0 +1,1135 @@ +// +// Copyright 2019 Le Hoang Quyen. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +#if defined(OF_METAL) +#import "MGLLayer+Private.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#import "MGLContext+Private.h" +#import "MGLDisplay.h" + +namespace +{ + +constexpr GLchar kBlitVS[] = R"( +attribute vec2 aPosition; + +varying mediump vec2 vTexcoords; + +void main() +{ + gl_Position = vec4(aPosition.x, aPosition.y, 0.0, 1.0); + vTexcoords = 0.5 * (aPosition + vec2(1.0, 1.0)); +} +)"; + +constexpr GLchar kBlitFS[] = R"( +uniform sampler2D uTexture; + +varying mediump vec2 vTexcoords; + +void main() +{ + gl_FragColor = texture2D(uTexture, vTexcoords); +} +)"; + +template +class ScopedGLEnable +{ + public: + ScopedGLEnable(bool enable) + { + gl::GetIntegerv(State, &mPrevState); + + if (enable) + { + gl::Enable(State); + } + else + { + gl::Disable(State); + } + } + ~ScopedGLEnable() + { + if (mPrevState) + { + gl::Enable(State); + } + else + { + gl::Disable(State); + } + } + + private: + GLint mPrevState; +}; + +template +class ScopedGLBinding +{ + public: + ScopedGLBinding(GLuint newObj) + { + gl::GetIntegerv(TargetBindingGet, &mPrevBoundObj); + BindFunc(Target, newObj); + } + ~ScopedGLBinding() { BindFunc(Target, mPrevBoundObj); } + + private: + GLint mPrevBoundObj; +}; + +using ScopedTextureBind = ScopedGLBinding; +using ScopedBufferBind = ScopedGLBinding; +using ScopedRenderbufferBind = + ScopedGLBinding; +using ScopedFBOBind = ScopedGLBinding; +using ScopedDrawFBOBind = + ScopedGLBinding; +using ScopedReadFBOBind = + ScopedGLBinding; + +class ScopedProgramBind +{ + public: + ScopedProgramBind(GLuint program) + { + gl::GetIntegerv(GL_CURRENT_PROGRAM, &mPrevProgram); + gl::UseProgram(program); + } + ~ScopedProgramBind() { gl::UseProgram(mPrevProgram); } + + private: + GLint mPrevProgram; +}; + +class ScopedActiveTexture +{ + public: + ScopedActiveTexture(GLenum unit) + { + gl::GetIntegerv(GL_ACTIVE_TEXTURE, &mPrevActiveTexture); + gl::ActiveTexture(unit); + } + ~ScopedActiveTexture() { gl::ActiveTexture(mPrevActiveTexture); } + + private: + GLint mPrevActiveTexture; +}; + +struct ScopedVAOBind +{ + public: + ScopedVAOBind(GLuint vao) + { + gl::GetIntegerv(GL_VERTEX_ARRAY_BINDING_OES, &mPrevVAO); + gl::BindVertexArrayOES(vao); + } + ~ScopedVAOBind() { gl::BindVertexArrayOES(mPrevVAO); } + + private: + GLint mPrevVAO; +}; + +template +class ScopedGLObject +{ + public: + ScopedGLObject() : mObject(0) {} + ScopedGLObject(GLuint object) : mObject(object) {} + ~ScopedGLObject() + { + if (mObject) + { + DeleteFunc(1, &mObject); + } + mObject = 0; + } + + ScopedGLObject &operator=(GLuint object) + { + mObject = object; + return *this; + } + + operator GLuint() const { return get(); } + + const GLuint &get() const { return mObject; } + GLuint &get() { return mObject; } + + private: + GLuint mObject; +}; + +using ScopedTexture = ScopedGLObject; +using ScopedRenderbuffer = ScopedGLObject; +using ScopedFramebuffer = ScopedGLObject; + +class ScopedViewport +{ + public: + ScopedViewport(GLint x, GLint y, GLint width, GLint height) + { + gl::GetIntegerv(GL_VIEWPORT, mPrevViewport); + gl::Viewport(x, y, width, height); + } + ~ScopedViewport() + { + gl::Viewport(mPrevViewport[0], mPrevViewport[1], mPrevViewport[2], mPrevViewport[3]); + } + + private: + GLint mPrevViewport[4]; +}; + +class ScopedReadBuffer +{ + public: + ScopedReadBuffer(GLint buffer, bool readBufferAvail) : mReadBufferAvail(readBufferAvail) + { + if (!mReadBufferAvail) + { + return; + } + gl::GetIntegerv(GL_READ_BUFFER, &mPrevReadBuffer); + gl::ReadBuffer(buffer); + } + ~ScopedReadBuffer() + { + if (mReadBufferAvail) + { + gl::ReadBuffer(mPrevReadBuffer); + } + } + + private: + const bool mReadBufferAvail; + GLint mPrevReadBuffer; +}; + +class ScopedDrawBuffer +{ + public: + ScopedDrawBuffer(GLenum drawbuffer, PFNGLDRAWBUFFERSEXTPROC drawBuffersFunc) + : mDrawBuffersFunc(drawBuffersFunc) + { + if (!mDrawBuffersFunc) + { + return; + } + GLint maxDrawBuffers; + gl::GetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers); + mPrevDrawBuffers.resize(maxDrawBuffers, GL_NONE); + for (int i = 0; i < maxDrawBuffers; ++i) + { + GLint buffer = GL_NONE; + gl::GetIntegerv(GL_DRAW_BUFFER0 + i, &buffer); + mPrevDrawBuffers[i] = buffer; + } + mDrawBuffersFunc(1, &drawbuffer); + } + ~ScopedDrawBuffer() + { + if (!mDrawBuffersFunc) + { + return; + } + GLint currentFBO; + gl::GetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, ¤tFBO); + if (currentFBO == 0) + { + mDrawBuffersFunc(1, mPrevDrawBuffers.data()); + } + else + { + mDrawBuffersFunc(mPrevDrawBuffers.size(), mPrevDrawBuffers.data()); + } + } + + private: + std::vector mPrevDrawBuffers; + const PFNGLDRAWBUFFERSEXTPROC mDrawBuffersFunc; +}; + +void Throw(NSString *msg) +{ + [NSException raise:@"MGLSurfaceException" format:@"%@", msg]; +} + +GLint CompileShader(GLenum target, const GLchar *source, GLuint *shader) +{ + GLint logLength, status; + + *shader = gl::CreateShader(target); + const GLchar *sources[] = {source}; + gl::ShaderSource(*shader, 1, sources, NULL); + gl::CompileShader(*shader); + gl::GetShaderiv(*shader, GL_INFO_LOG_LENGTH, &logLength); + if (logLength > 0) + { + GLchar *log = (GLchar *)malloc(logLength); + gl::GetShaderInfoLog(*shader, logLength, &logLength, log); + NSLog(@"Shader compile log:\n%s", log); + free(log); + } + + gl::GetShaderiv(*shader, GL_COMPILE_STATUS, &status); + if (status == GL_FALSE) + { + NSLog(@"Failed to compile shader:\n"); + NSLog(@"%s", source); + } + + return status && *shader; +} + +GLint LinkProgram(GLuint program) +{ + GLint logLength, status; + + gl::LinkProgram(program); + gl::GetProgramiv(program, GL_INFO_LOG_LENGTH, &logLength); + if (logLength > 0) + { + GLchar *log = (GLchar *)malloc(logLength); + gl::GetProgramInfoLog(program, logLength, &logLength, log); + NSLog(@"Program link log:\n%s", log); + free(log); + } + + gl::GetProgramiv(program, GL_LINK_STATUS, &status); + if (status == 0) + NSLog(@"Failed to link program %d", program); + + return status && program; +} +} + +// MGLLayer implementation +@implementation MGLLayer + +- (id)init +{ + if (self = [super init]) + { + [self constructor]; + } + return self; +} + +- (id)initWithCoder:(NSCoder *)coder +{ + if (self = [super initWithCoder:coder]) + { + [self constructor]; + } + return self; +} + +- (void)constructor +{ + _drawableColorFormat = MGLDrawableColorFormatRGBA8888; + _drawableDepthFormat = MGLDrawableDepthFormatNone; + _drawableStencilFormat = MGLDrawableStencilFormatNone; + _drawableMultisample = MGLDrawableMultisampleNone; + + _display = [MGLDisplay defaultDisplay]; + + _eglSurface = EGL_NO_SURFACE; + + if (rx::IsMetalDisplayAvailable()) + { + _metalLayer = [[CAMetalLayer alloc] init]; + _metalLayer.frame = self.bounds; + [self addSublayer:_metalLayer]; + } + else + { + _legacyGLLayer = [[CALayer alloc] init]; + _legacyGLLayer.frame = self.bounds; + [self addSublayer:_legacyGLLayer]; + } +} + +- (void)dealloc +{ + [self releaseSurface]; + + _display = nil; +} + +- (void)setContentsScale:(CGFloat)contentsScale +{ + [super setContentsScale:contentsScale]; + + if (rx::IsMetalDisplayAvailable()) + { + _metalLayer.contentsScale = contentsScale; + } + else + { + _legacyGLLayer.contentsScale = contentsScale; + } +} + +- (CGSize)drawableSize +{ + if (rx::IsMetalDisplayAvailable()) + { + if (_metalLayer.drawableSize.width == 0 && _metalLayer.drawableSize.height == 0) + { + [self checkLayerSize]; + } + return _metalLayer.drawableSize; + } + + return CGSizeMake(self.bounds.size.width * self.contentsScale, + self.bounds.size.height * self.contentsScale); +} + +- (BOOL)setCurrentContext:(MGLContext *)context +{ + if (eglGetCurrentContext() != context.eglContext || + eglGetCurrentSurface(EGL_READ) != self.eglSurface || + eglGetCurrentSurface(EGL_DRAW) != self.eglSurface) + { + if (!eglMakeCurrent(_display.eglDisplay, self.eglSurface, self.eglSurface, + context.eglContext)) + { + return NO; + } + } + + if (_useOffscreenFBO) + { + GLint currentFBO; + gl::GetIntegerv(GL_FRAMEBUFFER_BINDING, ¤tFBO); + BOOL offscreenFBOWasBound = currentFBO == _defaultOpenGLFrameBufferID; + + if (![self ensureOffscreenFBOCreated]) + { + return NO; + } + + if (offscreenFBOWasBound) + { + // Draw to offscreen texture instead of eglSurface + gl::BindFramebuffer(GL_FRAMEBUFFER, _defaultOpenGLFrameBufferID); + } + } + + return YES; +} + +- (void)bindDefaultFrameBuffer +{ + gl::BindFramebuffer(GL_FRAMEBUFFER, _defaultOpenGLFrameBufferID); +} + +- (BOOL)present +{ + if (_useOffscreenFBO) + { + if (_blitFramebufferAvail) + { + if (![self blitFBO:_defaultOpenGLFrameBufferID + sourceSize:_offscreenFBOSize + toFBO:0 + destinationSize:self.drawableSize + destinationMSAA:NO]) + { + return NO; + } + } + else if (![self blitOffscreenTexture:_offscreenTexture toFBO:0]) + { + return NO; + } + } + + if (!eglSwapBuffers(_display.eglDisplay, self.eglSurface)) + { + return NO; + } + + [self checkLayerSize]; + + return YES; +} + +- (BOOL)blitFBO:(GLuint)srcFbo + sourceSize:(CGSize)srcSize + toFBO:(GLuint)dstFbo + destinationSize:(CGSize)dstSize + destinationMSAA:(BOOL)destinationMSAA +{ + if (srcSize.width != dstSize.width || srcSize.height != dstSize.height || destinationMSAA) + { + // Blit to a temporary texture + ScopedTexture tempTexture; + gl::GenTextures(1, &tempTexture.get()); + ScopedTextureBind bindTexture(tempTexture); + gl::TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + gl::TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + gl::TexImage2D(GL_TEXTURE_2D, 0, _offscreenColorUnsizedFormat, + static_cast(srcSize.width), static_cast(srcSize.height), 0, + _offscreenColorUnsizedFormat, _offscreenColorFormatDataType, 0); + + ScopedFramebuffer tempFBO; + gl::GenFramebuffers(1, &tempFBO.get()); + ScopedFBOBind bindFBO(tempFBO); + gl::FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tempTexture, + 0); + + if (![self blitFBO:srcFbo + sourceSize:srcSize + toFBO:tempFBO + destinationSize:srcSize + destinationMSAA:NO]) + { + return NO; + } + + // Draw the temporary texture to destination framebuffer + return [self blitOffscreenTexture:tempTexture toFBO:dstFbo]; + } + + // Same size blitting + ASSERT(_blitFramebufferAvail); + auto currentCtx = [MGLContext currentContext]; + auto currentLayer = [MGLContext currentLayer]; + [MGLContext setCurrentContext:_offscreenFBOCreatorContext forLayer:self]; + + ScopedDrawFBOBind bindDrawFBO(dstFbo); + ScopedReadFBOBind bindReadFBO(srcFbo); + ScopedReadBuffer setReadBuffer(GL_COLOR_ATTACHMENT0, _isGLES3Plus); + ScopedDrawBuffer setDrawBuffer(dstFbo ? GL_COLOR_ATTACHMENT0 : GL_BACK, + _isGLES3Plus ? gl::DrawBuffers : gl::DrawBuffersEXT); + ScopedGLEnable disableScissorTest(false); + + auto blitFunc = _isGLES3Plus ? gl::BlitFramebuffer : gl::BlitFramebufferANGLE; + + blitFunc(0, 0, static_cast(srcSize.width), static_cast(srcSize.height), 0, 0, + static_cast(dstSize.width), static_cast(dstSize.height), + GL_COLOR_BUFFER_BIT, GL_NEAREST); + + BOOL re = gl::GetError() == GL_NO_ERROR; + + [MGLContext setCurrentContext:currentCtx forLayer:currentLayer]; + + return re; +} + +- (BOOL)blitOffscreenTexture:(GLuint)texture toFBO:(GLuint)fbo +{ + ASSERT(texture && _offscreenBlitProgram && _offscreenBlitVAO); + + auto currentCtx = [MGLContext currentContext]; + auto currentLayer = [MGLContext currentLayer]; + [MGLContext setCurrentContext:_offscreenFBOCreatorContext forLayer:self]; + + ScopedFBOBind bindFBO(fbo); + ScopedDrawBuffer setDrawBuffer(fbo ? GL_COLOR_ATTACHMENT0 : GL_BACK, + _isGLES3Plus ? gl::DrawBuffers : gl::DrawBuffersEXT); + ScopedProgramBind bindProgram(_offscreenBlitProgram); + ScopedActiveTexture activeTexture(GL_TEXTURE0); + ScopedTextureBind bindTexture(texture); + ScopedVAOBind bindVAO(_offscreenBlitVAO); + + ScopedGLEnable disableCull(false); + ScopedGLEnable disableDepthTest(false); + ScopedGLEnable disableStencilTest(false); + ScopedGLEnable disableBlend(false); + ScopedGLEnable disableScissorTest(false); + + ScopedViewport setViewport(0, 0, static_cast(_offscreenFBOSize.width), + static_cast(_offscreenFBOSize.height)); + + gl::DrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + BOOL re = gl::GetError() == GL_NO_ERROR; + + [MGLContext setCurrentContext:currentCtx forLayer:currentLayer]; + + return re; +} + +- (EGLSurface)eglSurface +{ + [self ensureSurfaceCreated]; + + return _eglSurface; +} + +- (void)setDrawableColorFormat:(MGLDrawableColorFormat)drawableColorFormat +{ + _drawableColorFormat = drawableColorFormat; + [self releaseSurface]; +} + +- (void)setDrawableDepthFormat:(MGLDrawableDepthFormat)drawableDepthFormat +{ + _drawableDepthFormat = drawableDepthFormat; + [self releaseSurface]; +} + +- (void)setDrawableStencilFormat:(MGLDrawableStencilFormat)drawableStencilFormat +{ + _drawableStencilFormat = drawableStencilFormat; + [self releaseSurface]; +} + +- (void)setDrawableMultisample:(MGLDrawableMultisample)drawableMultisample +{ + _drawableMultisample = drawableMultisample; + if (!rx::IsMetalDisplayAvailable() && _drawableMultisample > 0) + { + // Default backbuffer MSAA is not supported in native GL backend yet. + // Use offscreen MSAA buffer. + _useOffscreenFBO = YES; + } + [self releaseSurface]; +} + +- (void)setRetainedBacking:(BOOL)retainedBacking +{ + if (!rx::IsMetalDisplayAvailable()) + { + if (_drawableMultisample > 0) + { + // Default backbuffer MSAA is not supported in native GL backend yet. + // Always use offscreen MSAA buffer. + _useOffscreenFBO = YES; + } + else + { + _useOffscreenFBO = retainedBacking; + } + } + // else Metal back-end already supports preserve swap behavior. + _retainedBacking = retainedBacking; +} + +- (void)releaseSurface +{ + if (_eglSurface == eglGetCurrentSurface(EGL_READ) || + _eglSurface == eglGetCurrentSurface(EGL_DRAW)) + { + eglMakeCurrent(_display.eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + } + if (_eglSurface != EGL_NO_SURFACE) + { + eglDestroySurface(_display.eglDisplay, _eglSurface); + _eglSurface = EGL_NO_SURFACE; + } + [self releaseOffscreenRenderingResources]; +} + +- (void)releaseOffscreenRenderingResources +{ + if (_defaultOpenGLFrameBufferID) + { + auto oldUseOffscreenFBOFlag = _useOffscreenFBO; + // Avoid the buffer being created again inside setCurrentContext: + _useOffscreenFBO = NO; + auto currentCtx = [MGLContext currentContext]; + auto currentLayer = [MGLContext currentLayer]; + [MGLContext setCurrentContext:_offscreenFBOCreatorContext]; + + gl::DeleteFramebuffers(1, &_defaultOpenGLFrameBufferID); + _defaultOpenGLFrameBufferID = 0; + + gl::DeleteTextures(1, &_offscreenTexture); + _offscreenTexture = 0; + gl::DeleteRenderbuffers(1, &_offscreenRenderBuffer); + _offscreenRenderBuffer = 0; + gl::DeleteRenderbuffers(1, &_offscreenDepthStencilBuffer); + _offscreenDepthStencilBuffer = 0; + gl::DeleteVertexArraysOES(1, &_offscreenBlitVAO); + _offscreenBlitVAO = 0; + gl::DeleteBuffers(1, &_offscreenBlitVBO); + _offscreenBlitVBO = 0; + gl::DeleteBuffers(1, &_offscreenBlitProgram); + _offscreenBlitProgram = 0; + + [MGLContext setCurrentContext:currentCtx forLayer:currentLayer]; + + _useOffscreenFBO = oldUseOffscreenFBOFlag; + } + + _offscreenFBOSize.width = _offscreenFBOSize.height = 0; +} + +- (void)checkLayerSize +{ + if (rx::IsMetalDisplayAvailable()) + { + // Resize the metal layer + [CATransaction begin]; + [CATransaction setValue:(id)kCFBooleanTrue + forKey:kCATransactionDisableActions]; + _metalLayer.frame = self.bounds; + _metalLayer.drawableSize = + CGSizeMake(_metalLayer.bounds.size.width * _metalLayer.contentsScale, + _metalLayer.bounds.size.height * _metalLayer.contentsScale); + [CATransaction commit]; + } + else + { + _legacyGLLayer.frame = self.bounds; + } +} + +- (void)ensureSurfaceCreated +{ + if (_eglSurface != EGL_NO_SURFACE) + { + return; + } + + [self checkLayerSize]; + + int red = 8, green = 8, blue = 8, alpha = 8; + int colorSpace; + switch (_drawableColorFormat) + { + case MGLDrawableColorFormatRGBA8888: + // RGB565 default framebuffer is not supported by Metal atm. + // Fallback to RGBA8. + case MGLDrawableColorFormatRGB565: + red = green = blue = alpha = 8; + colorSpace = EGL_GL_COLORSPACE_LINEAR_KHR; + break; + case MGLDrawableColorFormatSRGBA8888: + red = green = blue = alpha = 8; + colorSpace = EGL_GL_COLORSPACE_SRGB_KHR; + break; + default: + UNREACHABLE(); + break; + } + + // Init surface + std::vector surfaceAttribs = { + EGL_RED_SIZE, red, + EGL_GREEN_SIZE, green, + EGL_BLUE_SIZE, blue, + EGL_ALPHA_SIZE, alpha, + EGL_DEPTH_SIZE, _useOffscreenFBO ? 0 : _drawableDepthFormat, + EGL_STENCIL_SIZE, _useOffscreenFBO ? 0 : _drawableStencilFormat, + EGL_SAMPLE_BUFFERS, 0, + EGL_SAMPLES, _useOffscreenFBO ? EGL_DONT_CARE : _drawableMultisample, + }; + surfaceAttribs.push_back(EGL_NONE); + EGLConfig config; + EGLint numConfigs; + if (!eglChooseConfig(_display.eglDisplay, surfaceAttribs.data(), &config, 1, &numConfigs) || + numConfigs < 1) + { + Throw(@"Failed to call eglChooseConfig()"); + } + + EGLint creationAttribs[] = {EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE, EGL_TRUE, + EGL_GL_COLORSPACE_KHR, colorSpace, EGL_NONE}; + + EGLNativeWindowType nativeWindowPtr; + + if (rx::IsMetalDisplayAvailable()) + { + // If metal layer is available, use it directly + nativeWindowPtr = (__bridge EGLNativeWindowType)_metalLayer; + } + else + { + nativeWindowPtr = (__bridge EGLNativeWindowType)_legacyGLLayer; + } + + _eglSurface = + eglCreateWindowSurface(_display.eglDisplay, config, nativeWindowPtr, creationAttribs); + if (_eglSurface == EGL_NO_SURFACE) + { + Throw(@"Failed to call eglCreateWindowSurface()"); + } + + if (_retainedBacking && !_useOffscreenFBO) + { + eglSurfaceAttrib(_display.eglDisplay, _eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED); + } +} + +- (BOOL)ensureOffscreenFBOCreated +{ + ASSERT(eglGetCurrentContext() != EGL_NO_CONTEXT); + + ScopedTexture oldOffscreenTexture = 0; + ScopedRenderbuffer oldOffscreenRenderbuffer = 0; + CGSize oldOffscreenSize = _offscreenFBOSize; + + if (_offscreenFBOCreatorContext != [MGLContext currentContext] || ! + [self verifyOffscreenFBOSize]) + { + // We need to copy the old texture to current texture, so backup the offscreen + // texture/buffer value and set those instance variables to zero to avoid the texture/buffer + // being released. + oldOffscreenTexture = _offscreenTexture; + oldOffscreenRenderbuffer = _offscreenRenderBuffer; + oldOffscreenSize = _offscreenFBOSize; + _offscreenTexture = 0; + _offscreenRenderBuffer = 0; + [self releaseOffscreenRenderingResources]; + } + + if (_defaultOpenGLFrameBufferID) + { + // Already created. + return YES; + } + + if (![self createOffscreenRenderingResources]) + { + [self releaseOffscreenRenderingResources]; + return NO; + } + + // Copy old content to new offscreen framebuffer + if (oldOffscreenTexture.get() || oldOffscreenRenderbuffer.get()) + { + if (_blitFramebufferAvail) + { + ScopedFramebuffer tempFBO; + gl::GenFramebuffers(1, &tempFBO.get()); + gl::BindFramebuffer(GL_READ_FRAMEBUFFER, tempFBO); + gl::FramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, + oldOffscreenRenderbuffer); + + return [self blitFBO:tempFBO + sourceSize:oldOffscreenSize + toFBO:_defaultOpenGLFrameBufferID + destinationSize:_offscreenFBOSize + destinationMSAA:_drawableMultisample]; + } + return [self blitOffscreenTexture:oldOffscreenTexture toFBO:_defaultOpenGLFrameBufferID]; + } + + return YES; +} + +- (BOOL)createOffscreenRenderingResources +{ + auto version = reinterpret_cast(gl::GetString(GL_VERSION)); + auto exts = reinterpret_cast(gl::GetString(GL_EXTENSIONS)); + _isGLES3Plus = strstr(version, "OpenGL ES 3") != nullptr; + _drawBuffersAvail = _isGLES3Plus || strstr(exts, "GL_EXT_draw_buffers") != nullptr; + _blitFramebufferAvail = _isGLES3Plus || strstr(exts, "GL_ANGLE_framebuffer_blit") != nullptr; + + if (![self createOffscreenBlitVBO]) + { + return NO; + } + + if (![self createOffscreenBlitProgram]) + { + return NO; + } + + return [self createOffscreenFBO]; +} + +- (BOOL)createOffscreenFBO +{ + // Clear pending errors + gl::GetError(); + + _offscreenFBOCreatorContext = [MGLContext currentContext]; + _offscreenFBOSize = self.drawableSize; + + gl::GenFramebuffers(1, &_defaultOpenGLFrameBufferID); + + ScopedFBOBind bindFBO(_defaultOpenGLFrameBufferID); + + if (_blitFramebufferAvail) + { + if (![self createOffscreenRenderBuffer]) + { + return NO; + } + } + else + { + if (![self createOffscreenTexture]) + { + return NO; + } + } + + if (![self createOffscreenDepthStencilbuffer]) + { + return NO; + } + + if (gl::CheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + { + // Fatal error + Throw(@"Offscreen texture is not complete"); + } + + return _defaultOpenGLFrameBufferID && gl::GetError() == GL_NO_ERROR; +} + +- (BOOL)createOffscreenDepthStencilbuffer +{ + // Clear pending errors + gl::GetError(); + + int depthBits = _drawableDepthFormat; + int stencilBits = _drawableStencilFormat; + + if (!depthBits && !stencilBits) + { + // No depth & stencil buffer + return YES; + } + + GLenum depthStencilFormat = 0; + if (depthBits && stencilBits) + { + depthStencilFormat = GL_DEPTH24_STENCIL8_OES; + } + else if (depthBits) + { + depthStencilFormat = GL_DEPTH_COMPONENT24_OES; + } + else if (stencilBits) + { + depthStencilFormat = GL_STENCIL_INDEX8; + } + + gl::GenRenderbuffers(1, &_offscreenDepthStencilBuffer); + ScopedRenderbufferBind bindRenderbuffer(_offscreenDepthStencilBuffer); + + if (_drawableMultisample) + { + gl::RenderbufferStorageMultisampleANGLE(GL_RENDERBUFFER, _drawableMultisample, + depthStencilFormat, + static_cast(_offscreenFBOSize.width), + static_cast(_offscreenFBOSize.height)); + } + else + { + gl::RenderbufferStorage(GL_RENDERBUFFER, depthStencilFormat, + static_cast(_offscreenFBOSize.width), + static_cast(_offscreenFBOSize.height)); + } + + if (depthBits) + { + gl::FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, + _offscreenDepthStencilBuffer); + } + if (stencilBits) + { + gl::FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, + _offscreenDepthStencilBuffer); + } + + return _offscreenDepthStencilBuffer && gl::GetError() == GL_NO_ERROR; +} + +// Offscreen renderbuffer is used when glBlitFramebuffer is available. +- (BOOL)createOffscreenRenderBuffer +{ + ASSERT(_blitFramebufferAvail); + + // Clear pending errors + gl::GetError(); + + GLenum sizedFormat; + switch (_drawableColorFormat) + { + case MGLDrawableColorFormatRGBA8888: + case MGLDrawableColorFormatRGB565: + sizedFormat = GL_RGBA8_OES; + _offscreenColorUnsizedFormat = GL_RGBA; + _offscreenColorFormatDataType = GL_UNSIGNED_BYTE; + break; + case MGLDrawableColorFormatSRGBA8888: + sizedFormat = GL_SRGB8_ALPHA8_EXT; + _offscreenColorUnsizedFormat = GL_SRGB_ALPHA_EXT; + _offscreenColorFormatDataType = GL_UNSIGNED_BYTE; + break; + default: + UNREACHABLE(); + break; + } + + gl::GenRenderbuffers(1, &_offscreenRenderBuffer); + ScopedRenderbufferBind bindRenderbuffer(_offscreenRenderBuffer); + + if (_drawableMultisample) + { + gl::RenderbufferStorageMultisampleANGLE(GL_RENDERBUFFER, _drawableMultisample, sizedFormat, + static_cast(_offscreenFBOSize.width), + static_cast(_offscreenFBOSize.height)); + } + else + { + gl::RenderbufferStorage(GL_RENDERBUFFER, sizedFormat, + static_cast(_offscreenFBOSize.width), + static_cast(_offscreenFBOSize.height)); + } + + gl::FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, + _offscreenRenderBuffer); + + return _offscreenRenderBuffer && gl::GetError() == GL_NO_ERROR; +} + +// Offscreen texture is used when glBlitFramebuffer is NOT available. +- (BOOL)createOffscreenTexture +{ + ASSERT(!_blitFramebufferAvail); + + // Clear pending errors + gl::GetError(); + + gl::GenTextures(1, &_offscreenTexture); + + ScopedTextureBind bindTexture(_offscreenTexture); + + GLenum textureSizedFormat; + GLenum textureFormat; + GLenum type; + switch (_drawableColorFormat) + { + case MGLDrawableColorFormatRGBA8888: + case MGLDrawableColorFormatRGB565: + textureSizedFormat = GL_RGBA8_OES; + textureFormat = GL_RGBA; + type = GL_UNSIGNED_BYTE; + case MGLDrawableColorFormatSRGBA8888: + textureSizedFormat = GL_SRGB8_ALPHA8_EXT; + textureFormat = GL_SRGB_ALPHA_EXT; + type = GL_UNSIGNED_BYTE; + break; + default: + UNREACHABLE(); + break; + } + + _offscreenColorUnsizedFormat = textureFormat; + _offscreenColorFormatDataType = type; + + if (rx::IsMetalDisplayAvailable()) + { + gl::TexStorage2DEXT(GL_TEXTURE_2D, 1, textureSizedFormat, + static_cast(_offscreenFBOSize.width), + static_cast(_offscreenFBOSize.height)); + } + else + { + gl::TexImage2D( + GL_TEXTURE_2D, 0, textureFormat, static_cast(_offscreenFBOSize.width), + static_cast(_offscreenFBOSize.height), 0, textureFormat, type, nullptr); + } + + gl::TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + gl::TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + gl::TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + gl::TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + if (_drawableMultisample) + { + gl::FramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + _offscreenTexture, 0, _drawableMultisample); + } + else + { + gl::FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + _offscreenTexture, 0); + } + + return _offscreenTexture && gl::GetError() == GL_NO_ERROR; +} + +- (BOOL)verifyOffscreenFBOSize +{ + if (!_defaultOpenGLFrameBufferID) + { + return YES; + } + + return static_cast(_offscreenFBOSize.width) == + static_cast(self.drawableSize.width) && + static_cast(_offscreenFBOSize.height) == + static_cast(self.drawableSize.height); +} + +- (BOOL)createOffscreenBlitProgram +{ + GLenum vshader, fshader; + if (!CompileShader(GL_VERTEX_SHADER, kBlitVS, &vshader)) + { + return NO; + } + + if (!CompileShader(GL_FRAGMENT_SHADER, kBlitFS, &fshader)) + { + return NO; + } + + _offscreenBlitProgram = gl::CreateProgram(); + gl::AttachShader(_offscreenBlitProgram, vshader); + gl::AttachShader(_offscreenBlitProgram, fshader); + gl::BindAttribLocation(_offscreenBlitProgram, 0, "aPosition"); + + if (!LinkProgram(_offscreenBlitProgram)) + { + return NO; + } + GLint textureLocation = -1; + textureLocation = gl::GetUniformLocation(_offscreenBlitProgram, "uTexture"); + ASSERT(textureLocation != -1); + + ScopedProgramBind bindProgram(_offscreenBlitProgram); + gl::Uniform1i(textureLocation, 0); + + return YES; +} + +- (BOOL)createOffscreenBlitVBO +{ + // Clear pending errors + gl::GetError(); + + constexpr float kBlitVertices[] = {-1, 1, -1, -1, 1, 1, 1, -1}; + + gl::GenVertexArraysOES(1, &_offscreenBlitVAO); + gl::GenBuffers(1, &_offscreenBlitVBO); + ScopedVAOBind bindVAO(_offscreenBlitVAO); + ScopedBufferBind bindVBO(_offscreenBlitVBO); + gl::BufferData(GL_ARRAY_BUFFER, sizeof(kBlitVertices), kBlitVertices, GL_STATIC_DRAW); + + gl::EnableVertexAttribArray(0); + gl::VertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0); + + return _offscreenBlitVAO && _offscreenBlitVBO && gl::GetError() == GL_NO_ERROR; +} + +@end + +#endif diff --git a/addons/ofxiOS/src/ofxiOS.h b/addons/ofxiOS/src/ofxiOS.h index 41f766faaf0..f89dd14aae0 100644 --- a/addons/ofxiOS/src/ofxiOS.h +++ b/addons/ofxiOS/src/ofxiOS.h @@ -47,6 +47,8 @@ #include "ofxiOSViewController.h" #include "ofxiOSGLKViewController.h" #include "ofxiOSGLKView.h" +#include "ofxiOSMLKViewController.h" +#include "ofxiOSMLKView.h" #include "ofxiOSEAGLView.h" #include "ofxiOSApp.h" #include "ofxiOSExtras.h" diff --git a/addons/ofxiOS/src/utils/ofxiOSExtras.h b/addons/ofxiOS/src/utils/ofxiOSExtras.h index 3bc292d2184..db630126ebf 100644 --- a/addons/ofxiOS/src/utils/ofxiOSExtras.h +++ b/addons/ofxiOS/src/utils/ofxiOSExtras.h @@ -104,6 +104,8 @@ ofxiOSEAGLView * ofxiOSGetGLView(); ofxiOSGLKView * ofxiOSGetGLKView(); +bool isUsingGLKView(); + // return opengl parent view UIView * ofxiOSGetGLParentView(); diff --git a/addons/ofxiOS/src/utils/ofxiOSExtras.mm b/addons/ofxiOS/src/utils/ofxiOSExtras.mm index c0033cd2c77..c7ab3c44cd9 100644 --- a/addons/ofxiOS/src/utils/ofxiOSExtras.mm +++ b/addons/ofxiOS/src/utils/ofxiOSExtras.mm @@ -35,6 +35,7 @@ #include "ofPixels.h" #include #if TARGET_OS_IOS || (TARGET_OS_IPHONE && !TARGET_OS_TV) + #import "ofxiOSAppDelegate.h" #import "ofxiOSViewController.h" #import "ofxiOSGLKViewController.h" @@ -156,6 +157,12 @@ ofxiOSDeviceInfo ofxiOSGetDeviceInfo(){ return [ofxiOSGLKView getInstance]; } +bool isUsingGLKView() { + if([[ofxiOSGetAppDelegate() uiViewController] isKindOfClass:[ofxiOSGLKViewController class]] == YES) return true; + else + return false; +} + //-------------------------------------------------------------- UIView * ofxiOSGetGLParentView() { return ofxiOSGetGLView().superview; diff --git a/addons/ofxiOS/src/video/AVFoundationVideoPlayer.m b/addons/ofxiOS/src/video/AVFoundationVideoPlayer.m index 02b458155cb..59d60139fc6 100644 --- a/addons/ofxiOS/src/video/AVFoundationVideoPlayer.m +++ b/addons/ofxiOS/src/video/AVFoundationVideoPlayer.m @@ -434,7 +434,7 @@ - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(N dispatch_async(dispatch_get_main_queue(), ^{ bReady = true; [self update]; // update as soon is ready so pixels are loaded. - [self setVolume:volume]; // set volume for current video. + [self setVolume:self->volume]; // set volume for current video. if([self.delegate respondsToSelector:@selector(playerReady)]) { [self.delegate playerReady]; } @@ -633,12 +633,13 @@ - (void)addTimeObserverToPlayer { double interval = 1.0 / (double)timeObserverFps; -// __block typeof(self) weak_self = self; -// timeObserver = [_player addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(interval, NSEC_PER_SEC) -// queue:dispatch_get_main_queue() usingBlock: -// ^(CMTime time) { -// [weak_self update]; -// }]; + __block typeof(self) weak_self = self; + timeObserver = [_player addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(interval, NSEC_PER_SEC) + queue:dispatch_get_main_queue() usingBlock: + ^(CMTime time) { + [weak_self update]; + }]; + } - (void)removeTimeObserverFromPlayer { @@ -717,7 +718,7 @@ - (void)seekToTime:(CMTime)time toleranceAfter:tolerance completionHandler:^(BOOL finished) { - bSeeking = NO; + self->bSeeking = NO; if([self.delegate respondsToSelector:@selector(playerDidFinishSeeking)]) { [self.delegate playerDidFinishSeeking]; diff --git a/addons/ofxiOS/src/video/ofxiOSVideoPlayer.mm b/addons/ofxiOS/src/video/ofxiOSVideoPlayer.mm index d4356ebd07a..7c840493bdd 100644 --- a/addons/ofxiOS/src/video/ofxiOSVideoPlayer.mm +++ b/addons/ofxiOS/src/video/ofxiOSVideoPlayer.mm @@ -3,11 +3,12 @@ #if defined(TARGET_OF_IOS) #include "ofxiOSExtras.h" #include "ofxiOSEAGLView.h" +#import "ofxiOSGLKView.h" #import "AVFoundationVideoPlayer.h" #include "ofGLUtils.h" #include "ofMath.h" -using std::string; +using namespace std; CVOpenGLESTextureCacheRef _videoTextureCache = NULL; @@ -22,7 +23,7 @@ bUpdatePixels = false; bUpdateTexture = false; bTextureCacheSupported = (&CVOpenGLESTextureCacheCreate != NULL); - bTextureCacheEnabled = true; + bTextureCacheEnabled = false; } //---------------------------------------- @@ -44,12 +45,12 @@ bool ofxiOSVideoPlayer::load(const of::filesystem::path & fileName) { if(!videoPlayer) { - videoPlayer = (__bridge_retained void *)[[AVFoundationVideoPlayer alloc] init]; - [(__bridge AVFoundationVideoPlayer *)videoPlayer setWillBeUpdatedExternally:YES]; + videoPlayer = [[AVFoundationVideoPlayer alloc] init]; + [(AVFoundationVideoPlayer *)videoPlayer setWillBeUpdatedExternally:YES]; } NSString * videoPath = [NSString stringWithUTF8String:ofToDataPath(fileName).c_str()]; - [(__bridge AVFoundationVideoPlayer*)videoPlayer loadWithPath:videoPath]; + [(AVFoundationVideoPlayer*)videoPlayer loadWithPath:videoPath]; bResetPixels = true; bUpdatePixels = true; @@ -59,7 +60,7 @@ if(_videoTextureCache == NULL) { CVReturn err = CVOpenGLESTextureCacheCreate(kCFAllocatorDefault, NULL, - ofxiOSGetGLView().context, + isUsingGLKView() ? [[ofxiOSGLKView getInstance] context] : ofxiOSGetGLView().context, NULL, &_videoTextureCache); if(err) { @@ -79,7 +80,8 @@ videoTexture.clear(); - ((__bridge AVFoundationVideoPlayer *)videoPlayer).delegate = nil; + ((AVFoundationVideoPlayer *)videoPlayer).delegate = nil; + [(AVFoundationVideoPlayer *)videoPlayer release]; __autoreleasing AVFoundationVideoPlayer *player = (__bridge_transfer AVFoundationVideoPlayer *)videoPlayer; if(bTextureCacheSupported == true) { @@ -130,8 +132,8 @@ return; } - [(__bridge AVFoundationVideoPlayer *)videoPlayer update]; - bFrameNew = [(__bridge AVFoundationVideoPlayer *)videoPlayer isNewFrame]; // check for new frame staright after the call to update. + [(AVFoundationVideoPlayer *)videoPlayer update]; + bFrameNew = [(AVFoundationVideoPlayer *)videoPlayer isNewFrame]; // check for new frame staright after the call to update. if(bFrameNew) { /** @@ -151,7 +153,7 @@ ofLogWarning("ofxiOSVideoPlayer::play()") << "video not loaded"; } - [(__bridge AVFoundationVideoPlayer *)videoPlayer play]; + [(AVFoundationVideoPlayer *)videoPlayer play]; } //---------------------------------------- @@ -160,8 +162,8 @@ return; } - [(__bridge AVFoundationVideoPlayer *)videoPlayer pause]; - [(__bridge AVFoundationVideoPlayer *)videoPlayer setPosition:0]; + [(AVFoundationVideoPlayer *)videoPlayer pause]; + [(AVFoundationVideoPlayer *)videoPlayer setPosition:0]; } //---------------------------------------- @@ -190,7 +192,7 @@ bResetPixels = false; } - CVImageBufferRef imageBuffer = [(__bridge AVFoundationVideoPlayer *)videoPlayer getCurrentFrame]; + CVImageBufferRef imageBuffer = [(AVFoundationVideoPlayer *)videoPlayer getCurrentFrame]; CVPixelBufferLockBaseAddress(imageBuffer, kCVPixelBufferLock_ReadOnly); @@ -283,10 +285,10 @@ int maxTextureSize = 0; glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize); - if([(__bridge AVFoundationVideoPlayer *)videoPlayer getWidth] > maxTextureSize || - [(__bridge AVFoundationVideoPlayer *)videoPlayer getHeight] > maxTextureSize) { + if([(AVFoundationVideoPlayer *)videoPlayer getWidth] > maxTextureSize || + [(AVFoundationVideoPlayer *)videoPlayer getHeight] > maxTextureSize) { ofLogWarning("ofxiOSVideoPlayer::getTexturePtr()") - << [(__bridge AVFoundationVideoPlayer *)videoPlayer getWidth] << "x" << [(__bridge AVFoundationVideoPlayer *)videoPlayer getHeight] + << [(AVFoundationVideoPlayer *)videoPlayer getWidth] << "x" << [(AVFoundationVideoPlayer *)videoPlayer getHeight] << " video image is bigger then max supported texture size " << maxTextureSize; return NULL; } @@ -302,7 +304,7 @@ //---------------------------------------- texture cache void ofxiOSVideoPlayer::initTextureCache() { - CVImageBufferRef imageBuffer = [(__bridge AVFoundationVideoPlayer *)videoPlayer getCurrentFrame]; + CVImageBufferRef imageBuffer = [(AVFoundationVideoPlayer *)videoPlayer getCurrentFrame]; if(imageBuffer == nil) { return; } @@ -324,8 +326,8 @@ * so... we can use ofTexture::setUseExternalTextureID() to get around this. */ - int videoTextureW = [(__bridge AVFoundationVideoPlayer *)videoPlayer getWidth]; - int videoTextureH = [(__bridge AVFoundationVideoPlayer *)videoPlayer getHeight]; + int videoTextureW = [(AVFoundationVideoPlayer *)videoPlayer getWidth]; + int videoTextureH = [(AVFoundationVideoPlayer *)videoPlayer getHeight]; videoTexture.allocate(videoTextureW, videoTextureH, GL_RGBA); ofTextureData & texData = videoTexture.getTextureData(); @@ -392,7 +394,7 @@ return 0; } - return [((__bridge AVFoundationVideoPlayer *)videoPlayer) getWidth]; + return [((AVFoundationVideoPlayer *)videoPlayer) getWidth]; } //---------------------------------------- @@ -401,7 +403,7 @@ return 0; } - return [((__bridge AVFoundationVideoPlayer *)videoPlayer) getHeight]; + return [((AVFoundationVideoPlayer *)videoPlayer) getHeight]; } //---------------------------------------- @@ -410,7 +412,7 @@ return false; } - return ![((__bridge AVFoundationVideoPlayer *)videoPlayer) isPlaying]; + return ![((AVFoundationVideoPlayer *)videoPlayer) isPlaying]; } //---------------------------------------- @@ -419,7 +421,7 @@ return false; } - return [((__bridge AVFoundationVideoPlayer *)videoPlayer) isReady]; + return [((AVFoundationVideoPlayer *)videoPlayer) isReady]; } //---------------------------------------- @@ -428,7 +430,7 @@ return false; } - return [((__bridge AVFoundationVideoPlayer *)videoPlayer) isPlaying]; + return [((AVFoundationVideoPlayer *)videoPlayer) isPlaying]; } //---------------------------------------- @@ -437,7 +439,7 @@ return 0; } - return [((__bridge AVFoundationVideoPlayer *)videoPlayer) getPosition]; + return [((AVFoundationVideoPlayer *)videoPlayer) getPosition]; } //---------------------------------------- @@ -446,7 +448,7 @@ return 0; } - return [((__bridge AVFoundationVideoPlayer *)videoPlayer) getSpeed]; + return [((AVFoundationVideoPlayer *)videoPlayer) getSpeed]; } //---------------------------------------- @@ -455,7 +457,7 @@ return 0; } - return [((__bridge AVFoundationVideoPlayer *)videoPlayer) getDurationInSec]; + return [((AVFoundationVideoPlayer *)videoPlayer) getDurationInSec]; } //---------------------------------------- @@ -464,7 +466,7 @@ return false; } - return [((__bridge AVFoundationVideoPlayer *)videoPlayer) isFinished]; + return [((AVFoundationVideoPlayer *)videoPlayer) isFinished]; } //---------------------------------------- @@ -474,9 +476,9 @@ } if(bPause) { - [((__bridge AVFoundationVideoPlayer *)videoPlayer) pause]; + [((AVFoundationVideoPlayer *)videoPlayer) pause]; } else { - [((__bridge AVFoundationVideoPlayer *)videoPlayer) play]; + [((AVFoundationVideoPlayer *)videoPlayer) play]; } } @@ -486,7 +488,7 @@ return; } - [((__bridge AVFoundationVideoPlayer *)videoPlayer) setPosition:pct]; + [((AVFoundationVideoPlayer *)videoPlayer) setPosition:pct]; } //---------------------------------------- @@ -498,7 +500,7 @@ ofLogWarning("ofxiOSVideoPlayer::setVolume()") << "expected range is 0-1, limiting requested volume " << volume << " to 1.0"; volume = 1.0f; } - [((__bridge AVFoundationVideoPlayer *)videoPlayer) setVolume:volume]; + [((AVFoundationVideoPlayer *)videoPlayer) setVolume:volume]; } //---------------------------------------- @@ -512,7 +514,7 @@ (state == OF_LOOP_PALINDROME)) { bLoop = true; } - [((__bridge AVFoundationVideoPlayer *)videoPlayer) setLoop:bLoop]; + [((AVFoundationVideoPlayer *)videoPlayer) setLoop:bLoop]; } //---------------------------------------- @@ -521,7 +523,7 @@ return; } - [((__bridge AVFoundationVideoPlayer *)videoPlayer) setSpeed:speed]; + [((AVFoundationVideoPlayer *)videoPlayer) setSpeed:speed]; } //---------------------------------------- @@ -530,7 +532,7 @@ return; } - [((__bridge AVFoundationVideoPlayer *)videoPlayer) setFrame:frame]; + [((AVFoundationVideoPlayer *)videoPlayer) setFrame:frame]; } //---------------------------------------- @@ -538,7 +540,7 @@ if(videoPlayer == NULL){ return 0; } - return [((__bridge AVFoundationVideoPlayer *)videoPlayer) getCurrentFrameNum]; + return [((AVFoundationVideoPlayer *)videoPlayer) getCurrentFrameNum]; } //---------------------------------------- @@ -546,7 +548,7 @@ if(videoPlayer == NULL){ return 0; } - return [((__bridge AVFoundationVideoPlayer *)videoPlayer) getDurationInFrames]; + return [((AVFoundationVideoPlayer *)videoPlayer) getDurationInFrames]; } //---------------------------------------- @@ -555,7 +557,7 @@ return OF_LOOP_NONE; } - bool bLoop = [((__bridge AVFoundationVideoPlayer *)videoPlayer) getLoop]; + bool bLoop = [((AVFoundationVideoPlayer *)videoPlayer) getLoop]; if(bLoop) { return OF_LOOP_NORMAL; } @@ -568,7 +570,7 @@ return; } - [((__bridge AVFoundationVideoPlayer *)videoPlayer) setPosition:0]; + [((AVFoundationVideoPlayer *)videoPlayer) setPosition:0]; } //---------------------------------------- diff --git a/libs/openFrameworks/app/ofAppGLFWWindow.cpp b/libs/openFrameworks/app/ofAppGLFWWindow.cpp index a44aacb0de2..a6e4cf27064 100644 --- a/libs/openFrameworks/app/ofAppGLFWWindow.cpp +++ b/libs/openFrameworks/app/ofAppGLFWWindow.cpp @@ -146,7 +146,7 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { setup(ofGLFWWindowSettings(settings)); } } - + void ofAppGLFWWindow::setup(const ofGLFWWindowSettings & _settings) { if (windowP) { ofLogError() << "window already setup, probably you are mixing old and new style setup"; @@ -155,14 +155,14 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { return; } settings = _settings; - + if (!glfwInit()) { ofLogError("ofAppGLFWWindow") << "couldn't init GLFW"; return; } - + // ofLogNotice("ofAppGLFWWindow") << "WINDOW MODE IS " << screenMode; - + glfwDefaultWindowHints(); glfwWindowHint(GLFW_RED_BITS, settings.redBits); glfwWindowHint(GLFW_GREEN_BITS, settings.greenBits); @@ -181,7 +181,7 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { glfwWindowHint(GLFW_SAMPLES, settings.numSamples); glfwWindowHint(GLFW_RESIZABLE, settings.resizable); glfwWindowHint(GLFW_DECORATED, settings.decorated); - + #ifdef TARGET_OPENGLES glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, settings.glesVersion); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); @@ -215,12 +215,12 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { currentRenderer = std::make_shared(this); } #endif - + GLFWwindow * sharedContext = nullptr; if (settings.shareContextWith) { sharedContext = (GLFWwindow *)settings.shareContextWith->getWindowContext(); } - + if (settings.windowMode == OF_GAME_MODE) { int count; GLFWmonitor ** monitors = glfwGetMonitors(&count); @@ -255,7 +255,7 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { ofLogError("ofAppGLFWWindow") << "requested fullscreen monitor is: " << settings.monitor << " monitor count is: " << count; } settings.monitor = ofClamp(settings.monitor, 0, count - 1); - + auto mode = glfwGetVideoMode(monitors[settings.monitor]); currentW = mode->width; currentH = mode->height; @@ -324,40 +324,40 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { iconify(true); } } - + //don't try and show a window if its been requsted to be hidden bWindowNeedsShowing = settings.visible; - + glfwSetWindowUserPointer(windowP, this); - + windowW = settings.getWidth(); windowH = settings.getHeight(); - + #ifdef TARGET_RASPBERRY_PI windowRect.width = windowW; windowRect.height = windowH; #endif - + glfwMakeContextCurrent(windowP); - + int framebufferW, framebufferH, tmpWindowW, tmpWindowH; glfwGetFramebufferSize(windowP, &framebufferW, &framebufferH); glfwGetWindowSize(windowP, &tmpWindowW, &tmpWindowH); - + //this lets us detect if the window is running in a retina mode if (framebufferW != tmpWindowW) { pixelScreenCoordScale = (float)framebufferW / (float)tmpWindowW; if (pixelScreenCoordScale < 1) { pixelScreenCoordScale = 1; } - + if (targetWindowMode == OF_WINDOW) { auto position = getWindowPosition(); setWindowShape(windowW, windowH); setWindowPosition(position.x, position.y); } } - + #ifndef TARGET_OPENGLES static bool inited = false; if (!inited) { @@ -371,9 +371,9 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { inited = true; } #endif - + ofLogVerbose() << "GL Version: " << glGetString(GL_VERSION); - + if (currentRenderer->getType() == ofGLProgrammableRenderer::TYPE) { #ifndef TARGET_OPENGLES static_cast(currentRenderer.get())->setup(settings.glVersionMajor, settings.glVersionMinor); @@ -383,7 +383,7 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { } else { static_cast(currentRenderer.get())->setup(); } - + setVerticalSync(true); glfwSetMouseButtonCallback(windowP, mouse_cb); glfwSetCursorPosCallback(windowP, motion_cb); @@ -397,7 +397,7 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { glfwSetScrollCallback(windowP, scroll_cb); glfwSetDropCallback(windowP, drop_cb); glfwSetWindowRefreshCallback(windowP, refresh_cb); - + #ifdef TARGET_LINUX XSetLocaleModifiers(""); xim = XOpenIM(getX11Display(), 0, 0, 0); @@ -413,7 +413,7 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { NULL); #endif } - + #ifdef TARGET_LINUX //------------------------------------------------------------ void ofAppGLFWWindow::setWindowIcon(const of::filesystem::path & path) { @@ -421,7 +421,7 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { ofLoadImage(iconPixels, path); setWindowIcon(iconPixels); } - + //------------------------------------------------------------ void ofAppGLFWWindow::setWindowIcon(const ofPixels & iconPixels) { iconSet = true; @@ -435,27 +435,27 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { buffer[i + 2] += iconPixels[i * 4 + 1] << 8; buffer[i + 2] += iconPixels[i * 4 + 2]; } - + XChangeProperty(getX11Display(), getX11Window(), XInternAtom(getX11Display(), "_NET_WM_ICON", False), XA_CARDINAL, 32, PropModeReplace, (const unsigned char *)buffer.data(), length); XFlush(getX11Display()); } #endif - + //-------------------------------------------- ofCoreEvents & ofAppGLFWWindow::events() { return *coreEvents; } - + //-------------------------------------------- shared_ptr & ofAppGLFWWindow::renderer() { return currentRenderer; } - + //-------------------------------------------- void ofAppGLFWWindow::update() { events().notifyUpdate(); - + //show the window right before the first draw call. if (bWindowNeedsShowing && windowP) { glfwShowWindow(windowP); @@ -464,13 +464,13 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { setFullscreen(true); } } - + #ifdef TARGET_RASPBERRY_PI //needed for rpi. as good values don't come into resize_cb when coming out of fullscreen if (needsResizeCheck && windowP) { int winW, winH; glfwGetWindowSize(windowP, &winW, &winH); - + //wait until the window size is the size it was before going fullscreen //then stop the resize check if (winW == windowRect.getWidth() && winH == windowRect.getHeight()) { @@ -480,19 +480,19 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { } #endif } - + //-------------------------------------------- void ofAppGLFWWindow::pollEvents() { glfwPollEvents(); } - + //-------------------------------------------- void ofAppGLFWWindow::draw() { currentRenderer->startRender(); if (bEnableSetupScreen) currentRenderer->setupScreen(); - + events().notifyDraw(); - + #ifdef TARGET_WIN32 if (currentRenderer->getBackgroundAuto() == false) { // on a PC resizing a window with this method of accumulation (essentially single buffering) @@ -526,48 +526,48 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { glFlush(); } #endif - + currentRenderer->finishRender(); - + nFramesSinceWindowResized++; } - + //-------------------------------------------- void ofAppGLFWWindow::swapBuffers() { glfwSwapBuffers(windowP); } - + //-------------------------------------------- void ofAppGLFWWindow::startRender() { renderer()->startRender(); } - + //-------------------------------------------- void ofAppGLFWWindow::finishRender() { renderer()->finishRender(); } - + //-------------------------------------------- bool ofAppGLFWWindow::getWindowShouldClose() { return glfwWindowShouldClose(windowP); } - + //-------------------------------------------- void ofAppGLFWWindow::setWindowShouldClose() { glfwSetWindowShouldClose(windowP, 1); } - + //------------------------------------------------------------ void ofAppGLFWWindow::setWindowTitle(std::string title) { settings.title = title; glfwSetWindowTitle(windowP, settings.title.c_str()); } - + //------------------------------------------------------------ int ofAppGLFWWindow::getPixelScreenCoordScale() { return pixelScreenCoordScale; } - + //------------------------------------------------------------ glm::vec2 ofAppGLFWWindow::getWindowSize() { if (settings.windowMode == OF_GAME_MODE) { @@ -581,31 +581,31 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { return { currentW * pixelScreenCoordScale, currentH * pixelScreenCoordScale }; } } - + //------------------------------------------------------------ glm::vec2 ofAppGLFWWindow::getWindowPosition() { int x, y; glfwGetWindowPos(windowP, &x, &y); - + x *= pixelScreenCoordScale; y *= pixelScreenCoordScale; - + if (orientation == OF_ORIENTATION_DEFAULT || orientation == OF_ORIENTATION_180) { return glm::vec2 { x, y }; } else { return glm::vec2(x, y); //NOTE: shouldn't this be (y,x) ?????? } } - + //------------------------------------------------------------ int ofAppGLFWWindow::getCurrentMonitor() { int numberOfMonitors; GLFWmonitor ** monitors = glfwGetMonitors(&numberOfMonitors); - + int xW; int yW; glfwGetWindowPos(windowP, &xW, &yW); - + for (int iC = 0; iC < numberOfMonitors; iC++) { int xM; int yM; @@ -621,7 +621,7 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { } return 0; } - + //------------------------------------------------------------ glm::vec2 ofAppGLFWWindow::getScreenSize() { int count; @@ -639,7 +639,7 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { } return glm::vec2(); } - + //------------------------------------------------------------ int ofAppGLFWWindow::getWidth() { if (orientation == OF_ORIENTATION_DEFAULT || orientation == OF_ORIENTATION_180) { @@ -648,7 +648,7 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { return currentH * pixelScreenCoordScale; } } - + //------------------------------------------------------------ int ofAppGLFWWindow::getHeight() { if (orientation == OF_ORIENTATION_DEFAULT || orientation == OF_ORIENTATION_180) { @@ -657,22 +657,22 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { return currentW * pixelScreenCoordScale; } } - + //------------------------------------------------------------ GLFWwindow * ofAppGLFWWindow::getGLFWWindow() { return windowP; } - + //------------------------------------------------------------ ofWindowMode ofAppGLFWWindow::getWindowMode() { return settings.windowMode; } - + //------------------------------------------------------------ void ofAppGLFWWindow::setWindowPosition(int x, int y) { glfwSetWindowPos(windowP, x / pixelScreenCoordScale, y / pixelScreenCoordScale); } - + //------------------------------------------------------------ void ofAppGLFWWindow::setWindowShape(int w, int h) { if (settings.windowMode == OF_WINDOW) { @@ -681,7 +681,7 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { } currentW = w / pixelScreenCoordScale; currentH = h / pixelScreenCoordScale; - + #ifdef TARGET_OSX auto pos = getWindowPosition(); glfwSetWindowSize(windowP, currentW, currentH); @@ -692,7 +692,7 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { glfwSetWindowSize(windowP, currentW, currentH); #endif } - + //------------------------------------------------------------ void ofAppGLFWWindow::hideCursor() { if (settings.windowMode == OF_FULLSCREEN || settings.windowMode == OF_GAME_MODE) { @@ -701,22 +701,22 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { glfwSetInputMode(windowP, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); } }; - + //------------------------------------------------------------ void ofAppGLFWWindow::showCursor() { glfwSetInputMode(windowP, GLFW_CURSOR, GLFW_CURSOR_NORMAL); }; - + //------------------------------------------------------------ void ofAppGLFWWindow::enableSetupScreen() { bEnableSetupScreen = true; }; - + //------------------------------------------------------------ void ofAppGLFWWindow::disableSetupScreen() { bEnableSetupScreen = false; }; - + //------------------------------------------------------------ void ofAppGLFWWindow::setFullscreen(bool fullscreen) { if (fullscreen) { @@ -724,7 +724,7 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { } else { targetWindowMode = OF_WINDOW; } - + #if defined(TARGET_OSX) NSWindow * cocoaWindow = glfwGetCocoaWindow(windowP); if (([cocoaWindow styleMask] & NSWindowStyleMaskFullScreen) == NSWindowStyleMaskFullScreen) { @@ -736,20 +736,20 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { [cocoaWindow setHasShadow:NO]; } #endif - + //we only want to change window mode if the requested window is different to the current one. bool bChanged = targetWindowMode != settings.windowMode; if (!bChanged) { return; } - + #ifdef TARGET_LINUX #include - + Window nativeWin = glfwGetX11Window(windowP); Display * display = glfwGetX11Display(); if (targetWindowMode == OF_FULLSCREEN) { - + #ifdef TARGET_RASPBERRY_PI // save window shape before going fullscreen if (windowP) { @@ -758,7 +758,7 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { windowRect.setSize(tmpW, tmpH); } #endif - + int monitorCount; GLFWmonitor ** monitors = glfwGetMonitors(&monitorCount); if (settings.multiMonitorFullScreen && monitorCount > 1) { @@ -791,19 +791,19 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { maxy = y + h; } } - + // send fullscreen_monitors event with the edges monitors Atom m_net_fullscreen_monitors = XInternAtom(display, "_NET_WM_FULLSCREEN_MONITORS", false); - + XEvent xev; - + xev.xclient.type = ClientMessage; xev.xclient.serial = 0; xev.xclient.send_event = True; xev.xclient.window = nativeWin; xev.xclient.message_type = m_net_fullscreen_monitors; xev.xclient.format = 32; - + xev.xclient.data.l[0] = monitorTop; xev.xclient.data.l[1] = monitorBottom; xev.xclient.data.l[2] = monitorLeft; @@ -824,69 +824,69 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { } } } - + // send fullscreen event Atom m_net_state = XInternAtom(display, "_NET_WM_STATE", false); Atom m_net_fullscreen = XInternAtom(display, "_NET_WM_STATE_FULLSCREEN", false); - + XEvent xev; - + xev.xclient.type = ClientMessage; xev.xclient.serial = 0; xev.xclient.send_event = True; xev.xclient.window = nativeWin; xev.xclient.message_type = m_net_state; xev.xclient.format = 32; - + if (fullscreen) xev.xclient.data.l[0] = 1; else xev.xclient.data.l[0] = 0; - + xev.xclient.data.l[1] = m_net_fullscreen; xev.xclient.data.l[2] = 0; xev.xclient.data.l[3] = 0; xev.xclient.data.l[4] = 0; XSendEvent(display, RootWindow(display, DefaultScreen(display)), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); - + // tell the window manager to bypass composition for this window in fullscreen for speed // it'll probably help solving vsync issues Atom m_bypass_compositor = XInternAtom(display, "_NET_WM_BYPASS_COMPOSITOR", False); unsigned long value = fullscreen ? 1 : 0; XChangeProperty(display, nativeWin, m_bypass_compositor, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&value, 1); - + XFlush(display); - + #ifdef TARGET_RASPBERRY_PI if (!fullscreen) { needsResizeCheck = true; } #endif - + // setWindowShape(windowW, windowH); - + #elif defined(TARGET_OSX) - + if (targetWindowMode == OF_FULLSCREEN) { //---------------------------------------------------- [NSApp setPresentationOptions:NSApplicationPresentationHideMenuBar | NSApplicationPresentationHideDock]; NSWindow * cocoaWindow = glfwGetCocoaWindow(windowP); - + [cocoaWindow setStyleMask:NSWindowStyleMaskBorderless]; - + int monitorCount; GLFWmonitor ** monitors = glfwGetMonitors(&monitorCount); - + int currentMonitor = getCurrentMonitor(); auto screenSize = getScreenSize(); - + if (orientation == OF_ORIENTATION_90_LEFT || orientation == OF_ORIENTATION_90_RIGHT) { std::swap(screenSize.x, screenSize.y); } - + ofRectangle allScreensSpace; - + // save window shape before going fullscreen auto pos = getWindowPosition(); auto size = getWindowSize(); @@ -894,9 +894,9 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { windowRect.y = pos.y; windowRect.width = size.x; windowRect.height = size.y; - + if (settings.multiMonitorFullScreen && monitorCount > 1) { - + //calc the sum Rect of all the monitors for (int i = 0; i < monitorCount; i++) { const GLFWvidmode * desktopMode = glfwGetVideoMode(monitors[i]); @@ -909,18 +909,18 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { //need to account for the pixel density factor when we're getting the values from glfw setWindowShape(allScreensSpace.width * pixelScreenCoordScale, allScreensSpace.height * pixelScreenCoordScale); setWindowPosition(allScreensSpace.x, allScreensSpace.y); - + } else if (monitorCount > 1 && currentMonitor < monitorCount) { int xpos; int ypos; glfwGetMonitorPos(monitors[currentMonitor], &xpos, &ypos); - + // Scale (if needed) to physical pixels size, since setWindowPosition // uses physical pixel dimensions. On HIDPI screens pixelScreenCoordScale // is likely to be 2, on "normal" screens pixelScreenCoordScale will be 1: xpos *= pixelScreenCoordScale; ypos *= pixelScreenCoordScale; - + //we do this as setWindowShape affects the position of the monitor //normally we would just call setWindowShape first, but on multi monitor you see the window bleed onto the second monitor as it first changes shape and is then repositioned. //this first moves it over in X, does the screen resize and then by calling it again its set correctly in y. @@ -932,18 +932,18 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { setWindowShape(screenSize.x, screenSize.y); setWindowPosition(0, 0); } - + // make sure to save current pos if not specified in settings if (settings.isPositionSet()) { auto pos = getWindowPosition(); settings.setPosition(ofVec2f(pos.x, pos.y)); } - + //make sure the window is getting the mouse/key events [cocoaWindow makeFirstResponder:cocoaWindow.contentView]; - + } else if (targetWindowMode == OF_WINDOW) { - + // set window shape if started in fullscreen if (windowRect.width == 0 && windowRect.height == 0) { windowRect.x = getWindowPosition().x; @@ -951,21 +951,21 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { windowRect.width = getWindowSize().x; windowRect.height = getWindowSize().y; } - + setWindowShape(windowRect.width, windowRect.height); setWindowTitle(settings.title); - + [NSApp setPresentationOptions:NSApplicationPresentationDefault]; NSWindow * cocoaWindow = glfwGetCocoaWindow(windowP); [cocoaWindow setStyleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable]; - + //---------------------------------------------------- // if we have recorded the screen position, put it there // if not, better to let the system do it (and put it where it wants) if (ofGetFrameNum() > 0) { setWindowPosition(windowRect.x, windowRect.y); } - + //---------------------------------------------------- //make sure the window is getting the mouse/key events [cocoaWindow makeFirstResponder:cocoaWindow.contentView]; @@ -979,26 +979,26 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { windowRect.y = pos.y; windowRect.width = size.x; windowRect.height = size.y; - + //---------------------------------------------------- HWND hwnd = glfwGetWin32Window(windowP); - + SetWindowLong(hwnd, GWL_EXSTYLE, 0); SetWindowLong(hwnd, GWL_STYLE, WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS); SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED | SWP_SHOWWINDOW); - + float fullscreenW = getScreenSize().x; float fullscreenH = getScreenSize().y; - + if (orientation == OF_ORIENTATION_90_LEFT || orientation == OF_ORIENTATION_90_RIGHT) { std::swap(fullscreenW, fullscreenH); } - + int xpos = 0; int ypos = 0; - + if (settings.multiMonitorFullScreen) { - + int minX = 0; int maxX = 0; int minY = 0; @@ -1016,25 +1016,25 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { minY = std::min(tempYPos, minY); maxX = std::max(maxX, tempXPos + desktopMode->width); maxY = std::max(maxY, tempYPos + desktopMode->height); - + xpos = std::min(xpos, tempXPos); ypos = std::min(ypos, tempYPos); } - + fullscreenW = maxX - minX; fullscreenH = maxY - minY; } else { - + int monitorCount; GLFWmonitor ** monitors = glfwGetMonitors(&monitorCount); int currentMonitor = getCurrentMonitor(); glfwGetMonitorPos(monitors[currentMonitor], &xpos, &ypos); } - + SetWindowPos(hwnd, HWND_TOPMOST, xpos, ypos, fullscreenW, fullscreenH, SWP_SHOWWINDOW); currentW = fullscreenW; currentH = fullscreenH; - + } else if (targetWindowMode == OF_WINDOW) { // set window shape if started in fullscreen if (windowRect.width == 0 && windowRect.height == 0) { @@ -1043,38 +1043,38 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { windowRect.width = getWindowSize().x; windowRect.height = getWindowSize().y; } - + HWND hwnd = glfwGetWin32Window(windowP); - + DWORD EX_STYLE = WS_EX_OVERLAPPEDWINDOW; DWORD STYLE = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_SIZEBOX; - + ChangeDisplaySettings(0, 0); SetWindowLong(hwnd, GWL_EXSTYLE, EX_STYLE); SetWindowLong(hwnd, GWL_STYLE, STYLE); SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED | SWP_SHOWWINDOW); - + //not sure why this is - but if we don't do this the window shrinks by 4 pixels in x and y //should look for a better fix. setWindowPosition(windowRect.x - 2, windowRect.y - 2); setWindowShape(windowRect.width + 4, windowRect.height + 4); } #endif - + settings.windowMode = targetWindowMode; } - + //------------------------------------------------------------ void ofAppGLFWWindow::toggleFullscreen() { if (settings.windowMode == OF_GAME_MODE) return; - + if (settings.windowMode == OF_WINDOW) { setFullscreen(true); } else { setFullscreen(false); } } - + //------------------------------------------------------------ void ofAppGLFWWindow::setWindowMousePassThrough(bool allowPassThrough) { if(settings.mousePassThrough == allowPassThrough) return; @@ -1083,17 +1083,17 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { glfwSetWindowAttrib(getGLFWWindow(), GLFW_MOUSE_PASSTHROUGH, settings.mousePassThrough); #endif } - + //------------------------------------------------------------ void ofAppGLFWWindow::setOrientation(ofOrientation orientation) { this->orientation = orientation; } - + //------------------------------------------------------------ ofOrientation ofAppGLFWWindow::getOrientation() { return orientation; } - + //------------------------------------------------------------ static void rotateMouseXY(ofOrientation orientation, int w, int h, double & x, double & y) { int savedY; @@ -1102,25 +1102,25 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { x = w - x; y = h - y; break; - + case OF_ORIENTATION_90_RIGHT: savedY = y; y = x; x = w - savedY; break; - + case OF_ORIENTATION_90_LEFT: savedY = y; y = h - x; x = savedY; break; - + case OF_ORIENTATION_DEFAULT: default: break; } } - + //------------------------------------------------------------ ofAppGLFWWindow * ofAppGLFWWindow::setCurrent(GLFWwindow * windowP) { ofAppGLFWWindow * instance = static_cast(glfwGetWindowUserPointer(windowP)); @@ -1131,7 +1131,7 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { instance->makeCurrent(); return instance; } - + namespace { int glfwtToOFModifiers(int mods) { int modifiers = 0; @@ -1149,7 +1149,7 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { } return modifiers; } - + unsigned long keycodeToUnicode(ofAppGLFWWindow * window, int scancode, int modifier) { #ifdef TARGET_LINUX XkbStateRec xkb_state = {}; @@ -1171,13 +1171,13 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { 0x00000000u, 0x00003080u, 0x000e2080u, 0x03c82080u, 0xfa082080u, 0x82082080u }; - + do { ch = (ch << 6) + (unsigned char)**c; (*c)++; count++; } while ((**c & 0xc0) == 0x80); - + if (count > 6) { return 0; } else { @@ -1191,7 +1191,7 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { static WCHAR buf[2]; static BYTE keyboardState[256]; GetKeyboardState(keyboardState); - + // Careful: keycode arrives translated into GLFW key codes, // but keycode needs to be a virtual key (VK_...) so we're // in deep troble, since this information has been removed @@ -1203,11 +1203,11 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { // https://msdn.microsoft.com/en-us/library/windows/desktop/ms646306(v=vs.85).aspx // // create a "fake" virtual key - + UINT fakeVirtualKey = MapVirtualKey(scancode, MAPVK_VSC_TO_VK_EX); - + int ret = ToUnicode(fakeVirtualKey, scancode, keyboardState, buf, 2, 0); - + if (ret == 1) { return buf[0]; } else { @@ -1218,14 +1218,14 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { static UInt32 deadKeyState = 0; static UniChar characters[8]; static UniCharCount characterCount = 0; - + typedef struct __TISInputSource * TISInputSourceRef; typedef TISInputSourceRef (*pFnGetInputSource)(void); // define function pointer that may return a input source ref, no arguments typedef void * (*pFnGetInputSourceProperty)(TISInputSourceRef, CFStringRef); typedef UInt8 (*pFnGetKeyboardType)(void); - + static const CFBundleRef tisBundle = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.HIToolbox")); - + // We need to call some system methods, following GLFW's example // in their OS X version of ```_glfwPlatformGetKeyName```. // @@ -1246,21 +1246,21 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { static pFnGetInputSource getInputSource = (pFnGetInputSource)CFBundleGetFunctionPointerForName(tisBundle, CFSTR("TISCopyCurrentKeyboardLayoutInputSource")); static pFnGetKeyboardType getKeyboardType = (pFnGetKeyboardType)CFBundleGetFunctionPointerForName(tisBundle, CFSTR("LMGetKbdType")); static pFnGetInputSourceProperty getInputSourceProperty = (pFnGetInputSourceProperty)CFBundleGetFunctionPointerForName(tisBundle, CFSTR("TISGetInputSourceProperty")); - + static const TISInputSourceRef sourceRef = getInputSource(); // note that for the first time, this creates a copy on the heap, then we're re-using it. - + static const CFStringRef * kPropertyUnicodeKeyLayoutData = (CFStringRef *)CFBundleGetDataPointerForName(tisBundle, CFSTR("kTISPropertyUnicodeKeyLayoutData")); static const CFStringRef kTISPropertyUnicodeKeyLayoutData = *kPropertyUnicodeKeyLayoutData; static const CFDataRef UnicodeKeyLayoutData = (CFDataRef)getInputSourceProperty(sourceRef, kTISPropertyUnicodeKeyLayoutData); - + static const UCKeyboardLayout * pKeyboardLayout = (UCKeyboardLayout *)CFDataGetBytePtr(UnicodeKeyLayoutData); - + UInt32 mod_OSX = 0; { // We have to translate the GLFW modifier bitflags back to OS X, // so that SHIFT, CONTROL, etc can be taken into account when // calculating the unicode codepoint. - + // UCKeyTranslate expects the Carbon-era modifier mask values, // so use these instead of the NSEventModifierFlag enums if (modifier & GLFW_MOD_SHIFT) @@ -1271,30 +1271,30 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { mod_OSX |= 2048; // Carbon optionKey value if (modifier & GLFW_MOD_SUPER) mod_OSX |= 256; // Carbon cmdKey - + // shift into 1 byte as per the Apple docs mod_OSX = (mod_OSX >> 8) & 0xFF; } - + // All this yak shaving was necessary to feed this diva of a function call: // https://developer.apple.com/library/mac/documentation/Carbon/Reference/Unicode_Utilities_Ref/index.html#//apple_ref/c/func/UCKeyTranslate - + if (noErr == UCKeyTranslate(pKeyboardLayout, scancode, kUCKeyActionDisplay, mod_OSX, getKeyboardType(), kUCKeyTranslateNoDeadKeysBit, &deadKeyState, sizeof(characters) / sizeof(characters[0]), &characterCount, characters)) { // if successful, first character contains codepoint return characters[0]; } else { return 0; } - + #endif return 0; } } - + //------------------------------------------------------------ void ofAppGLFWWindow::mouse_cb(GLFWwindow * windowP_, int button, int state, int mods) { ofAppGLFWWindow * instance = setCurrent(windowP_); - + #ifdef TARGET_OSX //we do this as unlike glut, glfw doesn't report right click for ctrl click or middle click for alt click if (instance->events().getKeyPressed(OF_KEY_CONTROL) && button == GLFW_MOUSE_BUTTON_LEFT) { @@ -1304,7 +1304,7 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { button = GLFW_MOUSE_BUTTON_MIDDLE; } #endif - + switch (button) { case GLFW_MOUSE_BUTTON_LEFT: button = OF_MOUSE_BUTTON_LEFT; @@ -1317,7 +1317,7 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { break; } instance->buttonInUse = button; - + ofMouseEventArgs::Type action; if (state == GLFW_PRESS) { action = ofMouseEventArgs::Pressed; @@ -1326,26 +1326,26 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { action = ofMouseEventArgs::Released; instance->buttonPressed = false; } - + int modifiers = glfwtToOFModifiers(mods); - + ofMouseEventArgs args(action, instance->events().getMouseX(), instance->events().getMouseY(), button, modifiers); - + instance->events().notifyMouseEvent(args); } - + //------------------------------------------------------------ void ofAppGLFWWindow::motion_cb(GLFWwindow * windowP_, double x, double y) { ofAppGLFWWindow * instance = setCurrent(windowP_); rotateMouseXY(instance->orientation, instance->getWidth(), instance->getHeight(), x, y); - + ofMouseEventArgs::Type action; if (!instance->buttonPressed) { action = ofMouseEventArgs::Moved; } else { action = ofMouseEventArgs::Dragged; } - + ofMouseEventArgs args(action, x * instance->pixelScreenCoordScale, y * instance->pixelScreenCoordScale, @@ -1353,7 +1353,7 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { instance->events().getModifiers()); instance->events().notifyMouseEvent(args); } - + //------------------------------------------------------------ void ofAppGLFWWindow::entry_cb(GLFWwindow * windowP_, int entered) { ofAppGLFWWindow * instance = setCurrent(windowP_); @@ -1363,7 +1363,7 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { } else { action = ofMouseEventArgs::Exited; } - + ofMouseEventArgs args(action, instance->events().getMouseX(), instance->events().getMouseY(), @@ -1371,12 +1371,12 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { instance->events().getModifiers()); instance->events().notifyMouseEvent(args); } - + //------------------------------------------------------------ void ofAppGLFWWindow::scroll_cb(GLFWwindow * windowP_, double x, double y) { ofAppGLFWWindow * instance = setCurrent(windowP_); rotateMouseXY(instance->orientation, instance->getWidth(), instance->getHeight(), x, y); - + ofMouseEventArgs args(ofMouseEventArgs::Scrolled, instance->events().getMouseX(), instance->events().getMouseY(), @@ -1386,7 +1386,7 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { args.scrollY = y; instance->events().notifyMouseEvent(args); } - + //------------------------------------------------------------ void ofAppGLFWWindow::drop_cb(GLFWwindow * windowP_, int numFiles, const char ** dropString) { ofAppGLFWWindow * instance = setCurrent(windowP_); @@ -1398,12 +1398,12 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { } instance->events().notifyDragEvent(drag); } - + //------------------------------------------------------------ void ofAppGLFWWindow::error_cb(int errorCode, const char * errorDescription) { ofLogError("ofAppGLFWWindow") << errorCode << ": " << errorDescription; } - + //------------------------------------------------------------ void ofAppGLFWWindow::keyboard_cb(GLFWwindow * windowP_, int keycode, int scancode, int action, int mods) { int key = 0; @@ -1574,9 +1574,9 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { key = codepoint; break; } - + int modifiers = glfwtToOFModifiers(mods); - + if (action == GLFW_PRESS) { ofKeyEventArgs keyE(ofKeyEventArgs::Pressed, key, keycode, scancode, codepoint, modifiers); instance->events().notifyKeyEvent(keyE); @@ -1589,54 +1589,54 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { instance->events().notifyKeyEvent(keyE); } } - + //------------------------------------------------------------ void ofAppGLFWWindow::char_cb(GLFWwindow * windowP_, uint32_t key) { ofAppGLFWWindow * instance = setCurrent(windowP_); instance->events().charEvent.notify(key); } - + //------------------------------------------------------------ void ofAppGLFWWindow::position_cb(GLFWwindow* windowP_, int x, int y){ ofAppGLFWWindow * instance = setCurrent(windowP_); - + x *= instance->pixelScreenCoordScale; y *= instance->pixelScreenCoordScale; instance->events().notifyWindowMoved(x,y); } - + //------------------------------------------------------------ void ofAppGLFWWindow::refresh_cb(GLFWwindow * windowP_) { ofAppGLFWWindow * instance = setCurrent(windowP_); instance->draw(); } - + //------------------------------------------------------------ void ofAppGLFWWindow::resize_cb(GLFWwindow * windowP_, int w, int h) { ofAppGLFWWindow * instance = setCurrent(windowP_); - + // Detect if the window is running in a retina mode - + int framebufferW, framebufferH; // <- physical pixel extents glfwGetFramebufferSize(windowP_, &framebufferW, &framebufferH); - + int windowW, windowH; // <- screen coordinates, which may be scaled glfwGetWindowSize(windowP_, &windowW, &windowH); - + // Find scale factor needed to transform from screen coordinates // to physical pixel coordinates instance->pixelScreenCoordScale = (float)framebufferW / (float)windowW; - + if (instance->settings.windowMode == OF_WINDOW) { instance->windowW = framebufferW; instance->windowH = framebufferH; } - + instance->currentW = windowW; instance->currentH = windowH; instance->events().notifyWindowResized(framebufferW, framebufferH); instance->nFramesSinceWindowResized = 0; - + #if defined(TARGET_OSX) NSWindow * cocoaWindow = glfwGetCocoaWindow(windowP_); if (([cocoaWindow styleMask] & NSWindowStyleMaskFullScreen) == NSWindowStyleMaskFullScreen) { @@ -1646,18 +1646,18 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { } #endif } - + //------------------------------------------------------------ void ofAppGLFWWindow::framebuffer_size_cb(GLFWwindow * windowP_, int w, int h) { resize_cb(windowP_, w, h); } - + //-------------------------------------------- void ofAppGLFWWindow::exit_cb(GLFWwindow * windowP_) { ofAppGLFWWindow * instance = setCurrent(windowP_); instance->events().notifyExit(); } - + //------------------------------------------------------------ void ofAppGLFWWindow::setVerticalSync(bool bVerticalSync) { if (bVerticalSync) { @@ -1666,23 +1666,23 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { glfwSwapInterval(0); } } - + //------------------------------------------------------------ void ofAppGLFWWindow::setClipboardString(const std::string & text) { glfwSetClipboardString(ofAppGLFWWindow::windowP, text.c_str()); } - + //------------------------------------------------------------ std::string ofAppGLFWWindow::getClipboardString() { const char * clipboard = glfwGetClipboardString(ofAppGLFWWindow::windowP); - + if (clipboard) { return clipboard; } else { return ""; } } - + //------------------------------------------------------------ void ofAppGLFWWindow::listVideoModes() { glfwInit(); @@ -1693,7 +1693,7 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { << vidModes[i].redBits + vidModes[i].greenBits + vidModes[i].blueBits << "bit"; } } - + //------------------------------------------------------------ void ofAppGLFWWindow::listMonitors() { glfwInit(); @@ -1707,23 +1707,23 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { ofLogNotice() << i << ": " << glfwGetMonitorName(monitor) << ", physical size: " << w << "x" << h << "mm at " << x << ", " << y; } } - + //------------------------------------------------------------ bool ofAppGLFWWindow::isWindowIconified() { return glfwGetWindowAttrib(windowP, GLFW_ICONIFIED); } - + //------------------------------------------------------------ bool ofAppGLFWWindow::isWindowActive() { // return glfwGetWindowParam(GLFW_ACTIVE); return true; } - + //------------------------------------------------------------ bool ofAppGLFWWindow::isWindowResizeable() { return !glfwGetWindowAttrib(windowP, GLFW_RESIZABLE); } - + //------------------------------------------------------------ void ofAppGLFWWindow::iconify(bool bIconify) { if (bIconify) @@ -1731,64 +1731,64 @@ void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings) { else glfwRestoreWindow(windowP); } - + void ofAppGLFWWindow::makeCurrent() { glfwMakeContextCurrent(windowP); } - + #if defined(TARGET_LINUX) Display * ofAppGLFWWindow::getX11Display() { return glfwGetX11Display(); } - + Window ofAppGLFWWindow::getX11Window() { return glfwGetX11Window(windowP); } - + XIC ofAppGLFWWindow::getX11XIC() { return xic; } #endif - + #if defined(TARGET_LINUX) && !defined(TARGET_OPENGLES) GLXContext ofAppGLFWWindow::getGLXContext() { return glfwGetGLXContext(windowP); } #endif - + #if defined(TARGET_LINUX) && defined(TARGET_OPENGLES) EGLDisplay ofAppGLFWWindow::getEGLDisplay() { return glfwGetEGLDisplay(); } - + EGLContext ofAppGLFWWindow::getEGLContext() { return glfwGetEGLContext(windowP); } - + EGLSurface ofAppGLFWWindow::getEGLSurface() { return glfwGetEGLSurface(windowP); } #endif - + #if defined(TARGET_OSX) void * ofAppGLFWWindow::getNSGLContext() { return (__bridge void *)glfwGetNSGLContext(windowP); } - + void * ofAppGLFWWindow::getCocoaWindow() { return (__bridge void *)glfwGetCocoaWindow(windowP); } #endif - + #if defined(TARGET_WIN32) HGLRC ofAppGLFWWindow::getWGLContext() { return glfwGetWGLContext(windowP); } - + HWND ofAppGLFWWindow::getWin32Window() { return glfwGetWin32Window(windowP); } - + #endif - + #endif diff --git a/libs/openFrameworks/gl/ofGLProgrammableRenderer.cpp b/libs/openFrameworks/gl/ofGLProgrammableRenderer.cpp index 9ee3712a725..ec9f12dbcfa 100644 --- a/libs/openFrameworks/gl/ofGLProgrammableRenderer.cpp +++ b/libs/openFrameworks/gl/ofGLProgrammableRenderer.cpp @@ -195,12 +195,12 @@ void ofGLProgrammableRenderer::draw(const ofMesh & vertexData, ofPolyRenderMode drawMode = GL_POINTS; } } - + bool bConfigureForLinesShader = areLinesShadersEnabled() && (drawMode == GL_LINES || drawMode == GL_LINE_STRIP || drawMode == GL_LINE_LOOP); if( usingCustomShader || usingCustomShader || currentMaterial) { bConfigureForLinesShader = false; } - + if( bConfigureForLinesShader ) { mDrawMode = drawMode; tGoingToRenderLines = true; @@ -234,12 +234,12 @@ void ofGLProgrammableRenderer::draw(const ofMesh & vertexData, ofPolyRenderMode drawMode = ofGetGLPrimitiveMode(vertexData.getMode()); break; } - + bool bConfigureForLinesShader = areLinesShadersEnabled() && (drawMode == GL_LINES || drawMode == GL_LINE_STRIP || drawMode == GL_LINE_LOOP); if( usingCustomShader || usingCustomShader || currentMaterial) { bConfigureForLinesShader = false; } - + if(bConfigureForLinesShader) { mDrawMode = drawMode; tGoingToRenderLines = true; @@ -257,7 +257,7 @@ void ofGLProgrammableRenderer::draw(const ofMesh & vertexData, ofPolyRenderMode } #endif - + if( vboToRender != nullptr ) { if( tGoingToRenderLines ) { // Setting a bool here so that the setAttributes function does not try to switch the shaders because @@ -268,13 +268,13 @@ void ofGLProgrammableRenderer::draw(const ofMesh & vertexData, ofPolyRenderMode drawMode = GL_TRIANGLES; } } - + if (vboToRender->getUsingIndices()) { drawElements(*vboToRender, drawMode, vboToRender->getNumIndices()); } else { draw(*vboToRender, drawMode, 0, vboToRender->getNumVertices()); } - + if( tGoingToRenderLines ) { mBRenderingLines = false; } @@ -344,7 +344,7 @@ void ofGLProgrammableRenderer::drawInstanced(const ofVboMesh & mesh, ofPolyRende #if defined(TARGET_EMSCRIPTEN) } // close the if for checking for wireframe #endif - + // tig: note further that we could glGet() and store the current polygon mode, but don't, since that would // infer a massive performance hit. instead, we revert the glPolygonMode to mirror the current ofFill state // after we're finished drawing, following the principle of least surprise. @@ -412,11 +412,11 @@ void ofGLProgrammableRenderer::draw(const ofPolyline & poly) const { glDrawArrays(drawMode, 0, poly.size()); #else - + // polylineMesh.clear(); // polylineMesh.addVertices(poly.getVertices()); - - + + polylineMesh.getVertices() = poly.getVertices(); // check if it is closed and the last point is the same as the first if( poly.isClosed() ) { @@ -424,7 +424,7 @@ void ofGLProgrammableRenderer::draw(const ofPolyline & poly) const { polylineMesh.getVertices().pop_back(); } } - + if( currentTextureTarget != OF_NO_TEXTURE ) { // TODO: Should we be able to set tex coords on polylines somehow?? polylineMesh.getTexCoords().resize( polylineMesh.getNumVertices(), glm::vec2(0.f, 0.f)); @@ -440,12 +440,12 @@ void ofGLProgrammableRenderer::draw(const ofPolyline & poly) const { } else { polylineMesh.disableTextures(); } - + polylineMesh.setMode( poly.isClosed() ? OF_PRIMITIVE_LINE_LOOP : OF_PRIMITIVE_LINE_STRIP ); // draw(const ofMesh & vertexData, ofPolyRenderMode renderType, bool useColors, bool useTextures, bool useNormals) const; draw(polylineMesh, OF_MESH_FILL, false, false, false); - - + + // meshVbo.setVertexData(&poly.getVertices()[0], poly.size(), GL_DYNAMIC_DRAW); // meshVbo.draw(poly.isClosed() ? GL_LINE_LOOP : GL_LINE_STRIP, 0, poly.size()); // meshPolylineVbo.setVertexData(&poly.getVertices()[0], poly.size(), GL_DYNAMIC_DRAW); @@ -555,7 +555,7 @@ void ofGLProgrammableRenderer::draw(const ofBaseVideoDraws & video, float x, flo //---------------------------------------------------------- void ofGLProgrammableRenderer::draw(const ofVbo & vbo, GLuint drawMode, int first, int total) const { - if (vbo.getUsingVerts()) { + if (vbo.getUsingVerts()) { vbo.bind(); const_cast(this)->setAttributes(vbo.getUsingVerts(), vbo.getUsingColors(), vbo.getUsingTexCoords(), vbo.getUsingNormals(), drawMode); glDrawArrays(drawMode, first, total); @@ -728,9 +728,17 @@ void ofGLProgrammableRenderer::setupScreenPerspective(float width, float height, viewW = currentViewport.width; viewH = currentViewport.height; - } else { + + }else{ + viewW = width; viewH = height; + + #if defined(TARGET_IOS) + viewW = 1920; // temp debbug + viewH = 1080; + fov = 60; + #endif } float eyeX = viewW / 2; @@ -799,7 +807,7 @@ void ofGLProgrammableRenderer::setCircleResolution(int res) { circlePolyline.arc(0, 0, 0, 1, 1, 0, 360, res); circleMesh.getVertices() = circlePolyline.getVertices(); path.setCircleResolution(res); - + // for the outline polyline, we need a closed loop // so we make another line that is closed, excluding the same start and end points circleOutlinePolyline.clear(); @@ -808,10 +816,10 @@ void ofGLProgrammableRenderer::setCircleResolution(int res) { circleOutlinePolyline.addVertex(glm::vec3(cosf(ta),sinf(ta), 0.0f)); } // circleOutlinePolyline.setClosed(true); - + circleOutlineMesh.getVertices() = circleOutlinePolyline.getVertices(); - - + + } currentStyle.circleResolution = res; } @@ -1365,7 +1373,7 @@ void ofGLProgrammableRenderer::setStyle(const ofStyle & style) { //line width - finally! setLineWidth(style.lineWidth); - + setPointSize(style.pointSize); //ofSetDepthTest(style.depthTest); removed since it'll break old projects setting depth test through glEnable @@ -1410,14 +1418,14 @@ void ofGLProgrammableRenderer::setAttributes(bool vertices, bool color, bool tex texCoordsEnabled = tex; colorsEnabled = color; normalsEnabled = normals; - + // nh: we set a variable (mBRenderingLines) before calling set attributes() to disable // the setting of the draw mode. When rendering lines, the requested mode may be GL_LINES // but we use a shader with GL_TRIANGLES to create a mesh to render the lines of varying widths. if( !mBRenderingLines ) { mDrawMode = drawMode; } - + if( mDrawMode == GL_LINE_LOOP ) { // this uses the same line resources as GL_LINE_STRIP mDrawMode = GL_LINE_STRIP; @@ -1427,7 +1435,7 @@ void ofGLProgrammableRenderer::setAttributes(bool vertices, bool color, bool tex if( !areLinesShadersEnabled() ) { mDrawMode = GL_TRIANGLES; } - + // prevent a shader switch if we don't need it. if( mDrawMode != GL_TRIANGLES && mDrawMode != GL_POINTS && mDrawMode != GL_LINES && mDrawMode != GL_LINE_STRIP ) { mDrawMode = GL_TRIANGLES; @@ -1445,7 +1453,7 @@ void ofGLProgrammableRenderer::setAttributes(bool vertices, bool color, bool tex if (currentShader) currentShader->setUniform1f(USE_COLORS_UNIFORM, color); } - // if we switch the draw mode, lets set the textures + // if we switch the draw mode, lets set the textures if( prevDrawMode != mDrawMode ) { if (currentTextureTarget != OF_NO_TEXTURE && currentShader ) { // set all of the texture uniforms @@ -1468,7 +1476,7 @@ void ofGLProgrammableRenderer::setAttributes(bool vertices, bool color, bool tex } } } - + if (!usingCustomShader && currentShader && !uniqueShader && !currentMaterial) { if (mDrawMode == GL_POINTS && pointSpritesEnabled) { currentShader->setUniform1f("pointSize", currentStyle.pointSize ); @@ -1882,7 +1890,7 @@ void ofGLProgrammableRenderer::beginDefaultShader() { } else if (colorsEnabled && bUseTexture) { auto &shaderCollection = getShaderCollectionForMode(mDrawMode); - + switch (currentTextureTarget) { #ifndef TARGET_OPENGLES @@ -2022,7 +2030,7 @@ void ofGLProgrammableRenderer::drawCircle(float x, float y, float z, float radiu ofGLProgrammableRenderer * mutThis = const_cast(this); // use smoothness, if requested: if (currentStyle.smoothing && !currentStyle.bFill) mutThis->startSmoothing(); - + if( !currentStyle.bFill ) { // nh: We use the circleOutlineMesh to render a closed polyline // since the lines mesh creation and shader depends on it. @@ -2060,7 +2068,7 @@ void ofGLProgrammableRenderer::drawEllipse(float x, float y, float z, float widt // use smoothness, if requested: if (currentStyle.smoothing && !currentStyle.bFill) mutThis->startSmoothing(); - + if( !currentStyle.bFill ) { // nh: We use the circleOutlineMesh to render a closed polyline // since the lines mesh creation and shader depends on it. @@ -2319,16 +2327,16 @@ STRINGIFY( uniform mat4 modelViewMatrix; uniform mat4 textureMatrix; uniform mat4 modelViewProjectionMatrix; - + uniform float pointSize; - + IN vec4 position; IN vec2 texcoord; IN vec4 color; IN vec3 normal; - + OUT vec4 colorVarying; - + void main() { gl_PointSize = pointSize; @@ -2344,29 +2352,29 @@ STRINGIFY( uniform mat4 modelViewMatrix;\n uniform mat4 textureMatrix;\n uniform mat4 modelViewProjectionMatrix;\n - + uniform vec4 viewRect;\n uniform float uLineWidth;\n uniform float uUsePerspective;\n - + IN vec4 position; IN vec2 texcoord; IN vec4 color; IN vec3 normal; IN vec4 nextVertex; - + OUT vec4 colorVarying; OUT vec2 texCoordVarying; - + void main() { colorVarying = color; float pushDir = nextVertex.w; texCoordVarying = (textureMatrix*vec4(texcoord.x,texcoord.y, 0.0,1.0)).xy; - + // clip space vec4 cClipPos = modelViewProjectionMatrix * vec4(position.xyz, 1.0); vec4 nClipPos = modelViewProjectionMatrix * vec4(nextVertex.xyz, 1.0); - + vec2 cNdcPos = (cClipPos.xy / cClipPos.w); vec2 nNdcPos = (nClipPos.xy / nClipPos.w); /* @@ -2375,26 +2383,26 @@ STRINGIFY( */ cNdcPos = (cNdcPos + 1.0) * (0.5 * viewRect.zw); nNdcPos = (nNdcPos + 1.0) * (0.5 * viewRect.zw); - + float thickness = uLineWidth * 0.5; - - + + vec2 dir = normalize(cNdcPos - nNdcPos); dir = vec2(-dir.y, dir.x); dir = dir * thickness * pushDir; - + vec4 posScreen = cClipPos; posScreen.xy = cNdcPos; posScreen.xy += dir; posScreen.xy = posScreen.xy / viewRect.zw * 2.0 - 1.0; posScreen.xy *= posScreen.w; - + // perspective float vaspect = viewRect.w / viewRect.z; dir.x *= vaspect; vec4 posPersp = cClipPos; posPersp.xy += dir; - + gl_Position = mix( posScreen, posPersp, uUsePerspective ); } ); @@ -2406,21 +2414,21 @@ STRINGIFY( uniform mat4 modelViewMatrix;\n uniform mat4 textureMatrix; uniform mat4 modelViewProjectionMatrix; - + uniform vec4 viewRect; uniform float uLineWidth; uniform float uUsePerspective; - + IN vec4 position; IN vec2 texcoord; IN vec4 color; IN vec3 normal; IN vec4 prevVertex; IN vec4 nextVertex; - + OUT vec4 colorVarying; OUT vec2 texCoordVarying; - + float mapClamp( float value, float inMin, float inMax, float outMin, float outMax ) { float outVal = ( (value - inMin ) / ( inMax - inMin ) * ( outMax - outMin ) ) + outMin; if(outMax < outMin){ @@ -2432,29 +2440,29 @@ STRINGIFY( } return outVal; } - + void main() { colorVarying = color; texCoordVarying = (textureMatrix*vec4(texcoord.x, texcoord.y, 0.0,1.0)).xy; - + float thickness = uLineWidth;// * 0.5; float pushDir = nextVertex.w; float pushDirY = -prevVertex.w; - + // // clip space vec4 pClipPos = modelViewProjectionMatrix * vec4(prevVertex.xyz, 1.0); vec4 cClipPos = modelViewProjectionMatrix * vec4(position.xyz, 1.0); vec4 nClipPos = modelViewProjectionMatrix * vec4(nextVertex.xyz, 1.0); - + vec2 pNdcPos = (pClipPos.xy / pClipPos.w); vec2 cNdcPos = (cClipPos.xy / cClipPos.w); vec2 nNdcPos = (nClipPos.xy / nClipPos.w); - + // // convert to screen space pNdcPos = (pNdcPos + 1.0) * (0.5 * viewRect.zw); cNdcPos = (cNdcPos + 1.0) * (0.5 * viewRect.zw); nNdcPos = (nNdcPos + 1.0) * (0.5 * viewRect.zw); - + vec2 dir = vec2(1.0, 0.0); if( position.xyz == nextVertex.xyz ) { // this is the last point ( on a non-closed line ) @@ -2470,44 +2478,44 @@ STRINGIFY( vec2 pdir = normalize( cNdcPos-pNdcPos ); vec2 ndir = normalize( nNdcPos-cNdcPos ); vec2 tangent = normalize(pdir+ndir); - + // Miter code based on // https://blog.scottlogic.com/2019/11/18/drawing-lines-with-webgl.html // by Matt Stobbs - + vec2 miter = vec2(-tangent.y, tangent.x); vec2 normalA = vec2(-pdir.y, pdir.x); dir = miter; float miterLength = 1.0 / clamp(abs(dot(miter, normalA)), 0.01, 2.0); thickness = miterLength * thickness; - + vec2 point = normalize(pdir-ndir); float dmp = dot(miter, point); - + // float miterTooLongMix = clamp(step( 2.0, miterLength) * sign(pushDir * dmp), 0.0, 1.0); float miterTooLongMix = clamp(step( 2.0, miterLength), 0.0, 1.0); float pstr = mapClamp( miterLength, 2.0, 3.0, 0.0, 1.0 ); float thicknessL = mix( miterLength * uLineWidth, uLineWidth, pstr ); - + dir = mix( dir * pushDir, (pushDir * pushDirY) * normalA, pstr * miterTooLongMix ); thickness = mix( clamp(miterLength, 0.0, 3.0) * uLineWidth, thicknessL, miterTooLongMix ); } - + dir = dir * (thickness * 0.5 ); - + // we calculate both the screen pos and perspective to avoid an if statement vec4 posScreen = cClipPos; posScreen.xy = cNdcPos; posScreen.xy += dir;// * 0.5; posScreen.xy = posScreen.xy / viewRect.zw * 2.0 - 1.0; posScreen.xy *= posScreen.w; - + // perspective vec4 posPersp = cClipPos; float vaspect = viewRect.w / viewRect.z; dir.x *= vaspect; posPersp.xy += (dir); - + gl_Position = mix( posScreen, posPersp, uUsePerspective ); } ); @@ -2534,7 +2542,7 @@ R"( uniform vec4 globalColor; uniform float usingTexture; uniform float usingColors; - + IN vec4 colorVarying; void main(){ @@ -2542,7 +2550,7 @@ R"( float dist_sq = dot( centerPt, centerPt ); vec2 st = gl_PointCoord; - + #if defined(OF_USING_TEXTURE_RECT) st.x = gl_PointCoord.x * src_tex_unit0_dims.x; st.y = gl_PointCoord.y * src_tex_unit0_dims.y; @@ -2721,16 +2729,16 @@ static const string defaultFragmentShaderTex2DNoColor = fragment_shader_header + // ---------------------------------------------------------------------- static const string defaultFragmentShaderOESTexNoColor = fragment_shader_header + STRINGIFY( - + uniform samplerExternalOES src_tex_unit0; uniform float usingTexture; uniform float usingColors; uniform vec4 globalColor; - + IN float depth; IN vec4 colorVarying; IN vec2 texCoordVarying; - + void main(){ FRAG_COLOR = TEXTURE(src_tex_unit0, texCoordVarying) * globalColor; } @@ -2835,7 +2843,7 @@ static const string bitmapStringFragmentShader = fragment_shader_header + STRING // in desktop openGL these are not used but we declare it to avoid more ifdefs static const string uniqueVertexShader = vertex_shader_header + STRINGIFY( - + uniform mat4 modelViewMatrix; uniform mat4 projectionMatrix; uniform mat4 textureMatrix; @@ -2862,7 +2870,7 @@ static const string uniqueVertexShader = vertex_shader_header + STRINGIFY( // ---------------------------------------------------------------------- static const string uniqueFragmentShader = fragment_shader_header + STRINGIFY( - + uniform sampler2D src_tex_unit0; uniform float usingTexture; uniform float bitmapText; @@ -3141,7 +3149,7 @@ void ofGLProgrammableRenderer::LinesBundle::setMeshDataToVbo() { if( mesh.getNumVertices() > 0 ) { // void setMesh(const ofMesh & mesh, int usage, bool useColors, bool useTextures, bool useNormals); vbo.setMesh( mesh, GL_DYNAMIC_DRAW, mesh.hasColors() && mesh.usingColors(), mesh.hasTexCoords() && mesh.usingTextures(), mesh.hasNormals() && mesh.usingNormals() ); - + if( lineMeshPrevVerts.size() > 0 ) { vbo.setAttributeData(vertAttribPrev, &lineMeshPrevVerts[0].x, 4, mesh.getNumVertices(), GL_DYNAMIC_DRAW); } @@ -3174,7 +3182,7 @@ void ofGLProgrammableRenderer::setup(int _major, int _minor) { uniqueShader = false; #endif mDefaultShadersMap.clear(); - + mLinesBundleMap.clear(); if( mLinesBundleMap.count(GL_LINES) < 1 ) { mLinesBundleMap[GL_LINES] = LinesBundle(); @@ -3196,15 +3204,15 @@ void ofGLProgrammableRenderer::setup(int _major, int _minor) { defaultUniqueShader.linkProgram(); beginDefaultShader(); } else { - + mDefaultShadersMap[GL_TRIANGLES] = std::make_shared(); mDefaultShadersMap[GL_POINTS] = std::make_shared(); mDefaultShadersMap[GL_LINES] = std::make_shared(); mDefaultShadersMap[GL_LINE_STRIP] = std::make_shared(); - - + + mDefaultShadersMap[GL_TRIANGLES]->setupAllVertexShaders(shaderSource(defaultVertexShader, major, minor)); - + #ifndef TARGET_OPENGLES // defaultTexRectColor.setupShaderFromSource(GL_VERTEX_SHADER, shaderSource(defaultVertexShader, major, minor)); // defaultTexRectNoColor.setupShaderFromSource(GL_VERTEX_SHADER, shaderSource(defaultVertexShader, major, minor)); @@ -3246,7 +3254,7 @@ void ofGLProgrammableRenderer::setup(int _major, int _minor) { // defaultTex2DNoColor.bindDefaults(); // defaultNoTexNoColor.bindDefaults(); alphaMask2DShader.bindDefaults(); - + mDefaultShadersMap[GL_TRIANGLES]->bindDefaults(); mDefaultShadersMap[GL_TRIANGLES]->linkPrograms(); @@ -3276,19 +3284,19 @@ void ofGLProgrammableRenderer::setup(int _major, int _minor) { defaultOESTexColor.linkProgram(); defaultOESTexNoColor.linkProgram(); #endif - - + + // now lets start setting up the points shaders mDefaultShadersMap[GL_POINTS]->setupAllVertexShaders(shaderSource(defaultPointsVertexShader, major, minor)); - + // ok, now lets setup the lines shaders // mDefaultShadersMap[GL_LINES]->setupAllVertexShaders(shaderSource(defaultLinesVertexShader, major, minor)); - + // ok, now lets setup the line strip shaders // mDefaultShadersMap[GL_LINE_STRIP]->setupAllVertexShaders(shaderSource(defaultLineStripVertexShader, major, minor)); - + // defaultFragmentShaderLines - + string alt_frag_header = fragment_shader_header; string defines = "#define OF_USING_TEXTURE_RECT 1\n#define OF_USING_VERTEX_COLORS 1\n"; std::string header_w_defines = alt_frag_header + defines; @@ -3299,7 +3307,7 @@ void ofGLProgrammableRenderer::setup(int _major, int _minor) { shaderSource(header_w_defines + defaultFragmentShaderLines, major, minor)); mDefaultShadersMap[GL_LINE_STRIP]->texRectColor.setupShaderFromSource(GL_FRAGMENT_SHADER, shaderSource(header_w_defines + defaultFragmentShaderLines, major, minor)); - + defines = "#define OF_USING_TEXTURE_RECT 1\n"; header_w_defines = alt_frag_header + defines; mDefaultShadersMap[GL_POINTS]->texRectNoColor.setupShaderFromSource(GL_FRAGMENT_SHADER, @@ -3309,7 +3317,7 @@ void ofGLProgrammableRenderer::setup(int _major, int _minor) { mDefaultShadersMap[GL_LINE_STRIP]->texRectNoColor.setupShaderFromSource(GL_FRAGMENT_SHADER, shaderSource(header_w_defines + defaultFragmentShaderLines, major, minor)); #endif - + defines = "#define OF_USING_TEXTURE_2D 1\n#define OF_USING_VERTEX_COLORS 1\n"; header_w_defines = alt_frag_header + defines; mDefaultShadersMap[GL_POINTS]->tex2DColor.setupShaderFromSource(GL_FRAGMENT_SHADER, @@ -3318,7 +3326,7 @@ void ofGLProgrammableRenderer::setup(int _major, int _minor) { shaderSource(header_w_defines + defaultFragmentShaderLines, major, minor)); mDefaultShadersMap[GL_LINE_STRIP]->tex2DColor.setupShaderFromSource(GL_FRAGMENT_SHADER, shaderSource(header_w_defines + defaultFragmentShaderLines, major, minor)); - + defines = "#define OF_USING_TEXTURE_2D 1\n"; header_w_defines = alt_frag_header + defines; mDefaultShadersMap[GL_POINTS]->tex2DNoColor.setupShaderFromSource(GL_FRAGMENT_SHADER, @@ -3345,28 +3353,28 @@ void ofGLProgrammableRenderer::setup(int _major, int _minor) { shaderSource(header_w_defines + defaultFragmentShaderLines, major, minor)); mDefaultShadersMap[GL_LINE_STRIP]->noTexNoColor.setupShaderFromSource(GL_FRAGMENT_SHADER, shaderSource(header_w_defines + defaultFragmentShaderLines, major, minor)); - + mDefaultShadersMap[GL_POINTS]->bindDefaults(); mDefaultShadersMap[GL_POINTS]->linkPrograms(); - - + + mDefaultShadersMap[GL_LINES]->bindDefaults(); // now lets bind the vertex attribute for the next vertex mDefaultShadersMap[GL_LINES]->bindAttribute( mLinesBundleMap[GL_LINES].vertAttribNext, "nextVertex" ); mDefaultShadersMap[GL_LINES]->linkPrograms(); - - + + mDefaultShadersMap[GL_LINE_STRIP]->bindDefaults(); // now lets bind the vertex attribute for the previous and next vertex mDefaultShadersMap[GL_LINE_STRIP]->bindAttribute( mLinesBundleMap[GL_LINE_STRIP].vertAttribPrev, "prevVertex" ); mDefaultShadersMap[GL_LINE_STRIP]->bindAttribute( mLinesBundleMap[GL_LINE_STRIP].vertAttribNext, "nextVertex" ); mDefaultShadersMap[GL_LINE_STRIP]->linkPrograms(); - + // defaultPointsTex2DColor.bindDefaults(); // defaultPointsTex2DNoColor.bindDefaults(); // defaultPointsNoTexColor.bindDefaults(); // defaultPointsNoTexNoColor.bindDefaults(); -// +// // defaultPointsTex2DColor.linkProgram(); // defaultPointsTex2DNoColor.linkProgram(); // defaultPointsNoTexColor.linkProgram(); @@ -3375,7 +3383,7 @@ void ofGLProgrammableRenderer::setup(int _major, int _minor) { setupGraphicDefaults(); viewport(); - setupScreenPerspective(); + setupScreenPerspective(1920, 1080); } const ofShader * ofGLProgrammableRenderer::getVideoShader(const ofBaseVideoDraws & video) const { @@ -3644,16 +3652,16 @@ void ofGLProgrammableRenderer::configureMeshToMatchWithNewVertsAndIndices(const bool bUseColors = aSrcMesh.hasColors() && aSrcMesh.usingColors() && (aSrcMesh.getNumColors() == aSrcMesh.getNumVertices()); bool bUseNormals = aSrcMesh.hasNormals() && aSrcMesh.usingNormals() && (aSrcMesh.getNumNormals() == aSrcMesh.getNumVertices()); bool bUseTexCoords = aSrcMesh.hasTexCoords() && aSrcMesh.usingTextures() && (aSrcMesh.getNumTexCoords() == aSrcMesh.getNumVertices()); - + if (aDstMesh.getNumVertices() != aTargetNumVertices) { aDstMesh.getVertices().assign(aTargetNumVertices, glm::vec3(0.f, 0.f, 0.f)); } - + if( aDstMesh.getNumIndices() != aTargetNumIndices ) { aDstMesh.getIndices().assign(aTargetNumIndices, 0); } aDstMesh.enableIndices(); - + if (bUseColors) { if (aDstMesh.getNumColors() != aTargetNumVertices) { aDstMesh.getColors().assign(aTargetNumVertices, ofFloatColor(1.f)); @@ -3685,26 +3693,26 @@ void ofGLProgrammableRenderer::configureLinesBundleFromMesh(LinesBundle& aLinesB auto& polyMesh = aLinesBundle.mesh; auto& nextVerts = aLinesBundle.lineMeshNextVerts; auto& prevVerts = aLinesBundle.lineMeshPrevVerts; - + bool bClosed = (drawMode == GL_LINE_LOOP) && amesh.getNumVertices() > 2; bool srcHasIndices = amesh.getNumIndices() > 0 && amesh.usingIndices(); std::size_t srcNumVs = srcHasIndices ? amesh.getNumIndices() : amesh.getNumVertices(); - + std::size_t targetNumPs = (bClosed ? srcNumVs + 1 : srcNumVs); std::size_t numIndicesA = (targetNumPs - 1) * 6 + (targetNumPs) * 6; - + std::size_t numVertsPer = 4; - + if( drawMode == GL_LINES ) { numVertsPer = 2; std::size_t targetNumLines = srcNumVs / 2; numIndicesA = targetNumLines * 6; } std::size_t targetNumVs = targetNumPs * numVertsPer; - - + + configureMeshToMatchWithNewVertsAndIndices(amesh, polyMesh, targetNumVs, numIndicesA ); - + if( drawMode != GL_LINES ) { if( prevVerts.size() != targetNumVs ) { prevVerts.assign(targetNumVs, glm::vec4(0.0f, 0.0f, 0.0f, 0.0f)); @@ -3713,61 +3721,61 @@ void ofGLProgrammableRenderer::configureLinesBundleFromMesh(LinesBundle& aLinesB if (nextVerts.size() != targetNumVs ) { nextVerts.assign(targetNumVs, glm::vec4(0.0f, 0.0f, 0.0f, 0.0f)); } - + bool bUseColors = amesh.hasColors() && amesh.usingColors() && (amesh.getNumColors() == amesh.getNumVertices()); bool bUseNormals = amesh.hasNormals() && amesh.usingNormals() && (amesh.getNumNormals() == amesh.getNumVertices()); bool bUseTexCoords = amesh.hasTexCoords() && amesh.usingTextures() && (amesh.getNumTexCoords() == amesh.getNumVertices()); - - + + const auto *srcVerts = amesh.getVerticesPointer(); const auto *srcIndices = amesh.getIndexPointer(); const auto *srcColors = amesh.getColorsPointer(); const auto *srcNormals = amesh.getNormalsPointer(); const auto *srcTexCoords = amesh.getTexCoordsPointer(); std::size_t numPs = srcHasIndices ? amesh.getNumIndices() : amesh.getNumVertices(); - + auto &pmVerts = polyMesh.getVertices(); auto &pmIndices = polyMesh.getIndices(); auto *pmColors = polyMesh.getColorsPointer(); auto *pmNormals = polyMesh.getNormalsPointer(); auto *pmTexCoords = polyMesh.getTexCoordsPointer(); - + float texU = 1.0; if( currentTextureTarget != OF_NO_TEXTURE ) { if( mUniformsTex.size() > 0 ) { texU = mUniformsTex[0].texData.tex_u; } } - - + + glm::vec3 EPSILON_VEC3 = glm::vec3(0.00005f); - - + + if( drawMode == GL_LINES ) { std::size_t cindex1 = 0; std::size_t cindex2 = 0; std::size_t lineIndex = 0; - + std::size_t pmIndex = 0; std::size_t kindex = 0; std::size_t newIndex = 0; - + std::size_t k = 0; - + for (size_t i = 0; i < targetNumPs; i += 2) { cindex1 = (i % numPs); cindex2 = (i + 1) % numPs; - + lineIndex = i / 2; - + if (srcHasIndices) { // get the verts from the indices cindex1 = srcIndices[cindex1]; cindex2 = srcIndices[cindex2]; } - + pmIndex = i * 2; - + // duplicate the vertices // for(k = 0; k < 4; k++ ) { kindex = cindex2; @@ -3775,7 +3783,7 @@ void ofGLProgrammableRenderer::configureLinesBundleFromMesh(LinesBundle& aLinesB kindex = cindex1; } pmVerts[pmIndex + k] = srcVerts[kindex]; - + if (bUseColors) { pmColors[pmIndex + k] = srcColors[kindex]; } @@ -3792,23 +3800,23 @@ void ofGLProgrammableRenderer::configureLinesBundleFromMesh(LinesBundle& aLinesB } } } - + nextVerts[pmIndex + 0] = glm::vec4(srcVerts[cindex2], -1.0f); nextVerts[pmIndex + 1] = glm::vec4(srcVerts[cindex2], 1.0f); - + nextVerts[pmIndex + 2] = glm::vec4(srcVerts[cindex1], 1.0f); nextVerts[pmIndex + 3] = glm::vec4(srcVerts[cindex1], -1.0f); - + newIndex = lineIndex * 6; pmIndices[newIndex + 0] = pmIndex + 0; pmIndices[newIndex + 1] = pmIndex + 2; pmIndices[newIndex + 2] = pmIndex + 1; - + pmIndices[newIndex + 3] = pmIndex + 1; pmIndices[newIndex + 4] = pmIndex + 2; pmIndices[newIndex + 5] = pmIndex + 3; } - + aLinesBundle.setMeshDataToVbo(); } else { std::size_t nindex, pindex, cindex; @@ -3819,18 +3827,18 @@ void ofGLProgrammableRenderer::configureLinesBundleFromMesh(LinesBundle& aLinesB std::size_t k = 0; std::size_t newIndex = 0; std::size_t nextIndex = 0; - + // if we have vertices lying on top of each other, // lets create some way to store valid ones // might not be the best approach, but easier / faster than removing the vertices from the src mesh glm::vec3 cachedPrevVert = {0.f, 0.f, 0.f}; glm::vec3 cachedNextVert = {0.f, 0.f, 0.f}; - + for (size_t i = 0; i < targetNumPs; i++) { cindex = (i % numPs); nindex = (i + 1) % numPs; pindex = (i - 1) % numPs; - + if (i == 0) { if (bClosed) { cindex = 0; @@ -3844,26 +3852,26 @@ void ofGLProgrammableRenderer::configureLinesBundleFromMesh(LinesBundle& aLinesB nindex = numPs - 1; } } - + if (srcHasIndices) { // get the verts from the indices cindex = srcIndices[cindex]; nindex = srcIndices[nindex]; pindex = srcIndices[pindex]; } - + if( i == 0 ) { // just in case, lets init the cached verts to use cachedPrevVert = srcVerts[cindex]; cachedNextVert = srcVerts[cindex]; } - + // duplicate the vertices // pmIndex = i * numVertsPer; - + pvert = glm::vec4(srcVerts[pindex], 1.0f); nvert = glm::vec4(srcVerts[nindex], 1.0f); - + if( glm::all(glm::lessThan(glm::abs(srcVerts[cindex]-srcVerts[pindex]), EPSILON_VEC3 ))) { if( i != 0 || (i == 0 && bClosed )) { // loop through and find a good next vert // @@ -3883,9 +3891,9 @@ void ofGLProgrammableRenderer::configureLinesBundleFromMesh(LinesBundle& aLinesB } else { cachedPrevVert = srcVerts[pindex]; } - - - + + + if(glm::all(glm::lessThan(glm::abs(srcVerts[cindex]-srcVerts[nindex]), EPSILON_VEC3 )) ) { // nvert = glm::vec4(cachedNextVert, 1.f); if( i != targetNumPs - 1 || (i == targetNumPs - 1 && bClosed) ) { @@ -3906,7 +3914,7 @@ void ofGLProgrammableRenderer::configureLinesBundleFromMesh(LinesBundle& aLinesB } else { cachedNextVert = srcVerts[nindex]; } - + for(k = 0; k < numVertsPer; k++) { pmVerts[pmIndex + k] = srcVerts[cindex]; nextVerts[pmIndex + k] = nvert; @@ -3921,7 +3929,7 @@ void ofGLProgrammableRenderer::configureLinesBundleFromMesh(LinesBundle& aLinesB if (k < 2) { prevVerts[pmIndex + k].w = -1.0; } - + if (bUseColors) { pmColors[pmIndex + k] = srcColors[kindex]; } @@ -3933,39 +3941,39 @@ void ofGLProgrammableRenderer::configureLinesBundleFromMesh(LinesBundle& aLinesB // should be in relation to the top of the image pmTexCoords[pmIndex + k] = srcTexCoords[kindex]; } else { - // lets go down to the bottom of the texture + // lets go down to the bottom of the texture pmTexCoords[pmIndex + k] = glm::vec2(srcTexCoords[kindex].x, texU); } // pmTexCoords[pmIndex + k] = srcTexCoords[kindex]; } } - + newIndex = i * 2 * 6; pmIndices[newIndex + 0] = pmIndex + 0; pmIndices[newIndex + 1] = pmIndex + 2; pmIndices[newIndex + 2] = pmIndex + 1; - + pmIndices[newIndex + 3] = pmIndex + 1; pmIndices[newIndex + 4] = pmIndex + 2; pmIndices[newIndex + 5] = pmIndex + 3; - + nextIndex = (i+1); if( bClosed && i > targetNumPs -1 ) { nextIndex = 0; } - + if( nextIndex < targetNumPs) { std::size_t nextPmIndex = (nextIndex) * numVertsPer; pmIndices[newIndex + 6] = pmIndex + 2; pmIndices[newIndex + 7] = nextPmIndex + 0; pmIndices[newIndex + 8] = pmIndex + 3; - + pmIndices[newIndex + 9] = pmIndex + 3; pmIndices[newIndex + 10] = nextPmIndex + 0; pmIndices[newIndex + 11] = nextPmIndex + 1; } } - + aLinesBundle.setMeshDataToVbo(); } } diff --git a/libs/openFrameworks/graphics/ofTrueTypeFont.cpp b/libs/openFrameworks/graphics/ofTrueTypeFont.cpp index 943c08fae5e..6d0b66db0b6 100644 --- a/libs/openFrameworks/graphics/ofTrueTypeFont.cpp +++ b/libs/openFrameworks/graphics/ofTrueTypeFont.cpp @@ -868,11 +868,12 @@ bool ofTrueTypeFont::load(const ofTrueTypeFontSettings & _settings){ } int maxSize; - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxSize); - if(w > maxSize || h > maxSize){ - ofLogError("ofTruetypeFont") << "Trying to allocate texture of " << w << "x" << h << " which is bigger than supported in current platform: " << maxSize; - return false; - }else{ +// glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxSize); +// if(w > maxSize || h > maxSize){ +// ofLogError("ofTruetypeFont") << "Trying to allocate texture of " << w << "x" << h << " which is bigger than supported in current platform: " << maxSize; +// return false; +// }else + { texAtlas.allocate(atlasPixelsLuminanceAlpha,false); texAtlas.setRGToRGBASwizzles(true); diff --git a/libs/openFrameworksCompiled/lib/ios/.gitkeep b/libs/openFrameworksCompiled/lib/ios/.gitkeep deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/libs/openFrameworksCompiled/project/ios/CoreOF.xcconfig b/libs/openFrameworksCompiled/project/ios/CoreOF.xcconfig index 2294da0c886..75fbe5857d1 100644 --- a/libs/openFrameworksCompiled/project/ios/CoreOF.xcconfig +++ b/libs/openFrameworksCompiled/project/ios/CoreOF.xcconfig @@ -22,8 +22,17 @@ HEADER_FMT = "$(OF_PATH)/libs/fmt/include" HEADER_CURL = "$(OF_PATH)/libs/curl/include" HEADER_URIPARSER = "$(OF_PATH)/libs/uriparser/include" HEADER_PUGIXML = "$(OF_PATH)/libs/pugixml/include" +HEADER_UNICODE = "$(OF_PATH)/libs/utf8/include" +HEADER_METAL = "$(OF_PATH)/libs/metalangle/include" +HEADER_METAL_THIRD = "$(OF_PATH)/libs/metalangle/include_thirdparty" +HEADER_METAL_SRC = "$(OF_PATH)/libs/metalangle/include/src" +HEADER_METAL_BASE_SRC = "$(OF_PATH)/libs/metalangle/include/src/common/third_party/base" + +HEADER_METAL_GLSLANG_SRC = "$(OF_PATH)/libs/metalangle/include/third_party/glslang/src" +HEADER_METAL_SPIRVCROSS_SRC = "$(OF_PATH)/libs/metalangle/include/third_party/spirv-cross/src" + //------- Libraries LIB_OF = "$(OF_PATH)/libs/openFrameworksCompiled/lib/ios/libofxiOS_${PLATFORM_NAME}_${CONFIGURATION}.a" //LIB_FREEIMAGE = "$(OF_PATH)/libs/FreeImage/lib/ios/freeimage.a" @@ -33,15 +42,16 @@ LIB_OF = "$(OF_PATH)/libs/openFrameworksCompiled/lib/ios/libofxiOS_${PLATFORM_NA //LIB_URIPARSER = "$(OF_PATH)/libs/uriparser/lib/ios/uriparser.a" //LIB_PUGIXML = "$(OF_PATH)/libs/pugixml/lib/ios/pugixml.a" - - MISC_FLAGS = "-ObjC" + OF_CORE_LIBS = $(MISC_FLAGS) $(LIB_OF) -OF_CORE_HEADERS = $(HEADER_OF) $(HEADER_OFXIOS) $(HEADER_UTF8) $(HEADER_FREETYPE) $(HEADER_FREETYPE2) $(HEADER_GLEW) $(HEADER_FREEIMAGE) $(HEADER_TESS2) $(HEADER_RTAUDIO) $(HEADER_JSON) $(HEADER_GLM) $(HEADER_FMT) $(HEADER_CURL) $(HEADER_URIPARSER) $(HEADER_PUGIXML) +OF_CORE_HEADERS = $(HEADER_OF) $(HEADER_OFXIOS) $(HEADER_UTF8) $(HEADER_FREETYPE) $(HEADER_FREETYPE2) $(HEADER_GLEW) $(HEADER_FREEIMAGE) $(HEADER_TESS2) $(HEADER_RTAUDIO) $(HEADER_JSON) $(HEADER_GLM) $(HEADER_FMT) $(HEADER_CURL) $(HEADER_URIPARSER) $(HEADER_PUGIXML) $(HEADER_UNICODE) $(HEADER_METAL) $(HEADER_METAL_THIRD) $(HEADER_METAL_SRC) $(HEADER_METAL_BASE_SRC) $(HEADER_METAL_GLSLANG_SRC) $(HEADER_METAL_SPIRVCROSS_SRC) + +OF_CORE_LIBS = $(MISC_FLAGS) $(LIB_FREEIMAGE) $(LIB_FREETYPE) $(LIB_OPENSSL) $(LIB_TESS) $(LIB_CURL) $(LIB_URIPARSER) $(LIB_PUGIXML) $(LIB_OF) -OF_CORE_FRAMEWORKS = -framework AudioToolbox -framework Accelerate -framework AVFoundation -framework CoreAudio -framework CoreGraphics -framework CoreLocation -framework CoreMotion -framework CoreMedia -framework CoreVideo -framework Foundation -framework GameController -framework GLKit -framework MapKit -framework OpenAL -framework OpenGLES -framework UIKit -framework Security -framework QuartzCore -framework CoreHaptics -framework Metal +OF_CORE_FRAMEWORKS = -framework AudioToolbox -framework Accelerate -framework AVFoundation -framework CoreAudio -framework CoreGraphics -framework CoreLocation -framework CoreMotion -framework CoreMedia -framework CoreVideo -framework Foundation -framework GameController -framework GLKit -framework MapKit -framework OpenAL -weak_framework OpenGLES -framework UIKit -framework Security -framework QuartzCore -framework CoreHaptics -weak_framework Metal -weak_framework IOSurface // BOOST can be enabled in OF Core by uncommenting this block @@ -102,3 +112,11 @@ CONFIGURATION_BUILD_DIR = $(SRCROOT)/bin/ CC = $(OF_PATH)/scripts/osx/cc.sh CXX = $(OF_PATH)/scripts/osx/cxx.sh + +// once all libraries are compiled for libc++ / all architectures +CLANG_CXX_LIBRARY = libc++ +CLANG_CXX_LANGUAGE_STANDARD = c++17 +IPHONEOS_DEPLOYMENT_TARGET = 13.0 +CLANG_ENABLE_OBJC_ARC = YES + +OF_METAL = YES diff --git a/libs/openFrameworksCompiled/project/ios/iOS+OFLib.xcodeproj/project.pbxproj b/libs/openFrameworksCompiled/project/ios/iOS+OFLib.xcodeproj/project.pbxproj index c347655e373..28ab4743efe 100644 --- a/libs/openFrameworksCompiled/project/ios/iOS+OFLib.xcodeproj/project.pbxproj +++ b/libs/openFrameworksCompiled/project/ios/iOS+OFLib.xcodeproj/project.pbxproj @@ -46,7 +46,7 @@ 15594FCB15C56D1E00727FF2 /* ofxiOSMapKitDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 15594FBC15C56D1E00727FF2 /* ofxiOSMapKitDelegate.h */; }; 15594FCC15C56D1E00727FF2 /* ofxiOSMapKitListener.h in Headers */ = {isa = PBXBuildFile; fileRef = 15594FBD15C56D1E00727FF2 /* ofxiOSMapKitListener.h */; }; 1594366415CF5F420087B684 /* ofxiOSVideoGrabber.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1594366015CF5F420087B684 /* ofxiOSVideoGrabber.mm */; }; - 1594366515CF5F420087B684 /* ofxiOSVideoPlayer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1594366115CF5F420087B684 /* ofxiOSVideoPlayer.mm */; }; + 1594366515CF5F420087B684 /* ofxiOSVideoPlayer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1594366115CF5F420087B684 /* ofxiOSVideoPlayer.mm */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 1594366615CF5F420087B684 /* ofxiOSVideoGrabber.h in Headers */ = {isa = PBXBuildFile; fileRef = 1594366215CF5F420087B684 /* ofxiOSVideoGrabber.h */; }; 1594366715CF5F420087B684 /* ofxiOSVideoPlayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 1594366315CF5F420087B684 /* ofxiOSVideoPlayer.h */; }; 2E49891A292C98000096EC56 /* ofCubeMapShaders.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E498917292C98000096EC56 /* ofCubeMapShaders.h */; }; @@ -125,6 +125,28 @@ BB24DED110DA7A3F00E9C588 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BB16EBD80F2B2AB500518274 /* QuartzCore.framework */; }; BF2B781A2C7E6CF000EAAD6E /* ES3Renderer.m in Sources */ = {isa = PBXBuildFile; fileRef = BF2B78182C7E6CF000EAAD6E /* ES3Renderer.m */; }; BF2B781B2C7E6CF000EAAD6E /* ES3Renderer.h in Headers */ = {isa = PBXBuildFile; fileRef = BF2B78192C7E6CF000EAAD6E /* ES3Renderer.h */; }; + BF3E028A2CE66D830022E17F /* EAMLKView.h in Headers */ = {isa = PBXBuildFile; fileRef = BF3E02872CE66D830022E17F /* EAMLKView.h */; }; + BF3E028B2CE66D830022E17F /* EAMLKView.mm in Sources */ = {isa = PBXBuildFile; fileRef = BF3E02882CE66D830022E17F /* EAMLKView.mm */; }; + BF443C922CE6F000005B6CCB /* metalangle.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF3E028C2CE66E670022E17F /* metalangle.xcframework */; }; + BF443C942CE6F01B005B6CCB /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF443C932CE6F01B005B6CCB /* Metal.framework */; }; + BF443CA82CE6F0DC005B6CCB /* MGLLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = BF443CA42CE6F0DC005B6CCB /* MGLLayer.h */; }; + BF443CA92CE6F0DC005B6CCB /* MGLContext.h in Headers */ = {isa = PBXBuildFile; fileRef = BF443C952CE6F0DC005B6CCB /* MGLContext.h */; }; + BF443CAA2CE6F0DC005B6CCB /* MGLDisplay.h in Headers */ = {isa = PBXBuildFile; fileRef = BF443C982CE6F0DC005B6CCB /* MGLDisplay.h */; }; + BF443CAB2CE6F0DC005B6CCB /* MGLKViewController+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = BF443CA32CE6F0DC005B6CCB /* MGLKViewController+Private.h */; }; + BF443CAC2CE6F0DC005B6CCB /* MGLKViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = BF443C9F2CE6F0DC005B6CCB /* MGLKViewController.h */; }; + BF443CAD2CE6F0DC005B6CCB /* MGLKit.h in Headers */ = {isa = PBXBuildFile; fileRef = BF443C9A2CE6F0DC005B6CCB /* MGLKit.h */; }; + BF443CAE2CE6F0DC005B6CCB /* MGLContext+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = BF443C972CE6F0DC005B6CCB /* MGLContext+Private.h */; }; + BF443CAF2CE6F0DC005B6CCB /* MGLKitPlatform.h in Headers */ = {isa = PBXBuildFile; fileRef = BF443C9B2CE6F0DC005B6CCB /* MGLKitPlatform.h */; }; + BF443CB02CE6F0DC005B6CCB /* MGLKView.h in Headers */ = {isa = PBXBuildFile; fileRef = BF443C9C2CE6F0DC005B6CCB /* MGLKView.h */; }; + BF443CB12CE6F0DC005B6CCB /* MGLLayer+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = BF443CA62CE6F0DC005B6CCB /* MGLLayer+Private.h */; }; + BF443CB22CE6F0DC005B6CCB /* MGLKView+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = BF443C9E2CE6F0DC005B6CCB /* MGLKView+Private.h */; }; + BF443CB32CE6F0DC005B6CCB /* MGLKViewController+iOS.mm in Sources */ = {isa = PBXBuildFile; fileRef = BF443CA12CE6F0DC005B6CCB /* MGLKViewController+iOS.mm */; }; + BF443CB42CE6F0DC005B6CCB /* MGLContext.mm in Sources */ = {isa = PBXBuildFile; fileRef = BF443C962CE6F0DC005B6CCB /* MGLContext.mm */; }; + BF443CB52CE6F0DC005B6CCB /* MGLLayer.mm in Sources */ = {isa = PBXBuildFile; fileRef = BF443CA52CE6F0DC005B6CCB /* MGLLayer.mm */; }; + BF443CB62CE6F0DC005B6CCB /* MGLKViewController+Mac.mm in Sources */ = {isa = PBXBuildFile; fileRef = BF443CA22CE6F0DC005B6CCB /* MGLKViewController+Mac.mm */; platformFilter = maccatalyst; settings = {COMPILER_FLAGS = "-fobjc-arc -fexceptions -fvisibility=default"; }; }; + BF443CB72CE6F0DC005B6CCB /* MGLKView.mm in Sources */ = {isa = PBXBuildFile; fileRef = BF443C9D2CE6F0DC005B6CCB /* MGLKView.mm */; }; + BF443CB82CE6F0DC005B6CCB /* MGLDisplay.mm in Sources */ = {isa = PBXBuildFile; fileRef = BF443C992CE6F0DC005B6CCB /* MGLDisplay.mm */; }; + BF443CB92CE6F0DC005B6CCB /* MGLKViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = BF443CA02CE6F0DC005B6CCB /* MGLKViewController.mm */; settings = {COMPILER_FLAGS = "-fobjc-arc -fexceptions -fvisibility=default"; }; }; BFB0B4042C50E019008FB5A3 /* brotli.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = BFEC5C022C4FFC5900728DEC /* brotli.xcframework */; }; BFB0B4052C50E019008FB5A3 /* openssl.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = BFEC5C002C4FFC3A00728DEC /* openssl.xcframework */; }; BFB0B4062C50E019008FB5A3 /* curl.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF4730B02BA4056B00E6E3C6 /* curl.xcframework */; }; @@ -136,6 +158,10 @@ BFB0B40C2C50E019008FB5A3 /* freetype.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF7E590D2BA204D300E5C52E /* freetype.xcframework */; }; BFB0B40D2C50E019008FB5A3 /* fmt.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF7E590B2BA204BC00E5C52E /* fmt.xcframework */; }; BFB0B40E2C50E019008FB5A3 /* FreeImage.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF7E59052BA203BC00E5C52E /* FreeImage.xcframework */; }; + BFBCA8462D2E2B2000816ADC /* ofxiOSMLKView.mm in Sources */ = {isa = PBXBuildFile; fileRef = BFBCA8432D2E2B2000816ADC /* ofxiOSMLKView.mm */; }; + BFBCA8472D2E2B2000816ADC /* ofxiOSMLKViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = BFBCA8452D2E2B2000816ADC /* ofxiOSMLKViewController.mm */; }; + BFBCA8482D2E2B2000816ADC /* ofxiOSMLKView.h in Headers */ = {isa = PBXBuildFile; fileRef = BFBCA8422D2E2B2000816ADC /* ofxiOSMLKView.h */; }; + BFBCA8492D2E2B2000816ADC /* ofxiOSMLKViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = BFBCA8442D2E2B2000816ADC /* ofxiOSMLKViewController.h */; }; E4F76E19176CB27200798745 /* of3dPrimitives.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4F76D6F176CB27200798745 /* of3dPrimitives.cpp */; }; E4F76E1A176CB27200798745 /* of3dPrimitives.h in Headers */ = {isa = PBXBuildFile; fileRef = E4F76D70176CB27200798745 /* of3dPrimitives.h */; }; E4F76E1B176CB27200798745 /* of3dUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4F76D71176CB27200798745 /* of3dUtils.cpp */; }; @@ -371,6 +397,28 @@ BBE5EAB70F49AD8400F28951 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; }; BF2B78182C7E6CF000EAAD6E /* ES3Renderer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ES3Renderer.m; sourceTree = ""; }; BF2B78192C7E6CF000EAAD6E /* ES3Renderer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ES3Renderer.h; sourceTree = ""; }; + BF3E02872CE66D830022E17F /* EAMLKView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EAMLKView.h; sourceTree = ""; }; + BF3E02882CE66D830022E17F /* EAMLKView.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = EAMLKView.mm; sourceTree = ""; }; + BF3E028C2CE66E670022E17F /* metalangle.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = metalangle.xcframework; path = ../../../metalangle/lib/macos/metalangle.xcframework; sourceTree = ""; }; + BF443C932CE6F01B005B6CCB /* Metal.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Metal.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.1.sdk/System/Library/Frameworks/Metal.framework; sourceTree = DEVELOPER_DIR; }; + BF443C952CE6F0DC005B6CCB /* MGLContext.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLContext.h; sourceTree = ""; }; + BF443C962CE6F0DC005B6CCB /* MGLContext.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLContext.mm; sourceTree = ""; }; + BF443C972CE6F0DC005B6CCB /* MGLContext+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MGLContext+Private.h"; sourceTree = ""; }; + BF443C982CE6F0DC005B6CCB /* MGLDisplay.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLDisplay.h; sourceTree = ""; }; + BF443C992CE6F0DC005B6CCB /* MGLDisplay.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLDisplay.mm; sourceTree = ""; }; + BF443C9A2CE6F0DC005B6CCB /* MGLKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLKit.h; sourceTree = ""; }; + BF443C9B2CE6F0DC005B6CCB /* MGLKitPlatform.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLKitPlatform.h; sourceTree = ""; }; + BF443C9C2CE6F0DC005B6CCB /* MGLKView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLKView.h; sourceTree = ""; }; + BF443C9D2CE6F0DC005B6CCB /* MGLKView.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLKView.mm; sourceTree = ""; }; + BF443C9E2CE6F0DC005B6CCB /* MGLKView+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MGLKView+Private.h"; sourceTree = ""; }; + BF443C9F2CE6F0DC005B6CCB /* MGLKViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLKViewController.h; sourceTree = ""; }; + BF443CA02CE6F0DC005B6CCB /* MGLKViewController.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLKViewController.mm; sourceTree = ""; }; + BF443CA12CE6F0DC005B6CCB /* MGLKViewController+iOS.mm */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; path = "MGLKViewController+iOS.mm"; sourceTree = ""; }; + BF443CA22CE6F0DC005B6CCB /* MGLKViewController+Mac.mm */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; path = "MGLKViewController+Mac.mm"; sourceTree = ""; }; + BF443CA32CE6F0DC005B6CCB /* MGLKViewController+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MGLKViewController+Private.h"; sourceTree = ""; }; + BF443CA42CE6F0DC005B6CCB /* MGLLayer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLLayer.h; sourceTree = ""; }; + BF443CA52CE6F0DC005B6CCB /* MGLLayer.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLLayer.mm; sourceTree = ""; }; + BF443CA62CE6F0DC005B6CCB /* MGLLayer+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MGLLayer+Private.h"; sourceTree = ""; }; BF4730B02BA4056B00E6E3C6 /* curl.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = curl.xcframework; path = ../../../curl/lib/macos/curl.xcframework; sourceTree = ""; }; BF7E59052BA203BC00E5C52E /* FreeImage.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = FreeImage.xcframework; path = ../../../FreeImage/lib/macos/FreeImage.xcframework; sourceTree = ""; }; BF7E590B2BA204BC00E5C52E /* fmt.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = fmt.xcframework; path = ../../../fmt/lib/macos/fmt.xcframework; sourceTree = ""; }; @@ -380,6 +428,10 @@ BF7E59192BA2054700E5C52E /* tess2.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = tess2.xcframework; path = ../../../tess2/lib/macos/tess2.xcframework; sourceTree = ""; }; BF7E591B2BA2056600E5C52E /* uriparser.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = uriparser.xcframework; path = ../../../uriparser/lib/macos/uriparser.xcframework; sourceTree = ""; }; BF7E591D2BA2057900E5C52E /* zlib.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = zlib.xcframework; path = ../../../zlib/lib/macos/zlib.xcframework; sourceTree = ""; }; + BFBCA8422D2E2B2000816ADC /* ofxiOSMLKView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ofxiOSMLKView.h; sourceTree = ""; }; + BFBCA8432D2E2B2000816ADC /* ofxiOSMLKView.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ofxiOSMLKView.mm; sourceTree = ""; }; + BFBCA8442D2E2B2000816ADC /* ofxiOSMLKViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ofxiOSMLKViewController.h; sourceTree = ""; }; + BFBCA8452D2E2B2000816ADC /* ofxiOSMLKViewController.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ofxiOSMLKViewController.mm; sourceTree = ""; }; BFEC5C002C4FFC3A00728DEC /* openssl.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = openssl.xcframework; path = ../../../openssl/lib/macos/openssl.xcframework; sourceTree = ""; }; BFEC5C022C4FFC5900728DEC /* brotli.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = brotli.xcframework; path = ../../../brotli/lib/macos/brotli.xcframework; sourceTree = ""; }; E41D3E9013B38BE900A75A5D /* CoreOF.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = CoreOF.xcconfig; sourceTree = SOURCE_ROOT; }; @@ -502,6 +554,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + BF443C942CE6F01B005B6CCB /* Metal.framework in Frameworks */, + BF443C922CE6F000005B6CCB /* metalangle.xcframework in Frameworks */, 99752D331BF21EEE0026316A /* GameController.framework in Frameworks */, 67D48ED01C10399900F719BC /* CoreMotion.framework in Frameworks */, BB24DECA10DA7A3F00E9C588 /* AudioToolbox.framework in Frameworks */, @@ -642,6 +696,10 @@ 15594F8A15C56A4E00727FF2 /* core */ = { isa = PBXGroup; children = ( + BFBCA8422D2E2B2000816ADC /* ofxiOSMLKView.h */, + BFBCA8432D2E2B2000816ADC /* ofxiOSMLKView.mm */, + BFBCA8442D2E2B2000816ADC /* ofxiOSMLKViewController.h */, + BFBCA8452D2E2B2000816ADC /* ofxiOSMLKViewController.mm */, 15594F8F15C56A8A00727FF2 /* ofxiOSAppDelegate.h */, 15594F8C15C56A8A00727FF2 /* ofxiOSAppDelegate.mm */, 15594F8E15C56A8A00727FF2 /* ofxiOSEAGLView.h */, @@ -725,6 +783,7 @@ BB24E02310DA7C6100E9C588 /* ofxiOS */ = { isa = PBXGroup; children = ( + BF3E02892CE66D830022E17F /* metal */, BB24E02810DA7C6100E9C588 /* src */, ); name = ofxiOS; @@ -756,6 +815,42 @@ name = core; sourceTree = ""; }; + BF3E02892CE66D830022E17F /* metal */ = { + isa = PBXGroup; + children = ( + BF443CA72CE6F0DC005B6CCB /* MGLKit */, + BF3E02872CE66D830022E17F /* EAMLKView.h */, + BF3E02882CE66D830022E17F /* EAMLKView.mm */, + ); + name = metal; + path = src/metal; + sourceTree = ""; + }; + BF443CA72CE6F0DC005B6CCB /* MGLKit */ = { + isa = PBXGroup; + children = ( + BF443C952CE6F0DC005B6CCB /* MGLContext.h */, + BF443C962CE6F0DC005B6CCB /* MGLContext.mm */, + BF443C972CE6F0DC005B6CCB /* MGLContext+Private.h */, + BF443C982CE6F0DC005B6CCB /* MGLDisplay.h */, + BF443C992CE6F0DC005B6CCB /* MGLDisplay.mm */, + BF443C9A2CE6F0DC005B6CCB /* MGLKit.h */, + BF443C9B2CE6F0DC005B6CCB /* MGLKitPlatform.h */, + BF443C9C2CE6F0DC005B6CCB /* MGLKView.h */, + BF443C9D2CE6F0DC005B6CCB /* MGLKView.mm */, + BF443C9E2CE6F0DC005B6CCB /* MGLKView+Private.h */, + BF443C9F2CE6F0DC005B6CCB /* MGLKViewController.h */, + BF443CA02CE6F0DC005B6CCB /* MGLKViewController.mm */, + BF443CA12CE6F0DC005B6CCB /* MGLKViewController+iOS.mm */, + BF443CA22CE6F0DC005B6CCB /* MGLKViewController+Mac.mm */, + BF443CA32CE6F0DC005B6CCB /* MGLKViewController+Private.h */, + BF443CA42CE6F0DC005B6CCB /* MGLLayer.h */, + BF443CA52CE6F0DC005B6CCB /* MGLLayer.mm */, + BF443CA62CE6F0DC005B6CCB /* MGLLayer+Private.h */, + ); + path = MGLKit; + sourceTree = ""; + }; E4F76D69176CB27200798745 /* openFrameworks */ = { isa = PBXGroup; children = ( @@ -995,6 +1090,8 @@ E9F39181299E892200280B58 /* Frameworks */ = { isa = PBXGroup; children = ( + BF443C932CE6F01B005B6CCB /* Metal.framework */, + BF3E028C2CE66E670022E17F /* metalangle.xcframework */, BFEC5C022C4FFC5900728DEC /* brotli.xcframework */, BFEC5C002C4FFC3A00728DEC /* openssl.xcframework */, BF4730B02BA4056B00E6E3C6 /* curl.xcframework */, @@ -1021,8 +1118,11 @@ E4F76E1A176CB27200798745 /* of3dPrimitives.h in Headers */, E4F76E1C176CB27200798745 /* of3dUtils.h in Headers */, E999E70E299D53FC00649F18 /* ofxiOSCoreHaptics.h in Headers */, + BFBCA8482D2E2B2000816ADC /* ofxiOSMLKView.h in Headers */, + BFBCA8492D2E2B2000816ADC /* ofxiOSMLKViewController.h in Headers */, E4F76E1E176CB27200798745 /* ofCamera.h in Headers */, E4F76E20176CB27200798745 /* ofEasyCam.h in Headers */, + BF3E028A2CE66D830022E17F /* EAMLKView.h in Headers */, E4F76E22176CB27200798745 /* ofMesh.h in Headers */, E4F76E24176CB27200798745 /* ofNode.h in Headers */, 67833F8419F8990D00DBE7AA /* ofFpsCounter.h in Headers */, @@ -1033,6 +1133,17 @@ E4F76E37176CB27200798745 /* ofEvents.h in Headers */, E4F76E38176CB27200798745 /* ofEventUtils.h in Headers */, 67D48ED31C103BAE00F719BC /* ofxiOSCoreMotion.h in Headers */, + BF443CA82CE6F0DC005B6CCB /* MGLLayer.h in Headers */, + BF443CA92CE6F0DC005B6CCB /* MGLContext.h in Headers */, + BF443CAA2CE6F0DC005B6CCB /* MGLDisplay.h in Headers */, + BF443CAB2CE6F0DC005B6CCB /* MGLKViewController+Private.h in Headers */, + BF443CAC2CE6F0DC005B6CCB /* MGLKViewController.h in Headers */, + BF443CAD2CE6F0DC005B6CCB /* MGLKit.h in Headers */, + BF443CAE2CE6F0DC005B6CCB /* MGLContext+Private.h in Headers */, + BF443CAF2CE6F0DC005B6CCB /* MGLKitPlatform.h in Headers */, + BF443CB02CE6F0DC005B6CCB /* MGLKView.h in Headers */, + BF443CB12CE6F0DC005B6CCB /* MGLLayer+Private.h in Headers */, + BF443CB22CE6F0DC005B6CCB /* MGLKView+Private.h in Headers */, E4F76E3A176CB27200798745 /* ofFbo.h in Headers */, E4F76E3C176CB27200798745 /* ofGLProgrammableRenderer.h in Headers */, E4F76E3E176CB27200798745 /* ofGLRenderer.h in Headers */, @@ -1246,6 +1357,8 @@ E4F76E41176CB27200798745 /* ofLight.cpp in Sources */, E4F76E43176CB27200798745 /* ofMaterial.cpp in Sources */, E4F76E45176CB27200798745 /* ofShader.cpp in Sources */, + BFBCA8462D2E2B2000816ADC /* ofxiOSMLKView.mm in Sources */, + BFBCA8472D2E2B2000816ADC /* ofxiOSMLKViewController.mm in Sources */, E4F76E49176CB27200798745 /* ofTexture.cpp in Sources */, E999E70F299D53FC00649F18 /* ofxiOSCoreHaptics.mm in Sources */, E4F76E4B176CB27200798745 /* ofVbo.cpp in Sources */, @@ -1258,6 +1371,13 @@ E4F76E59176CB27200798745 /* ofPath.cpp in Sources */, E4F76E5B176CB27200798745 /* ofPixels.cpp in Sources */, E4F76E5F176CB27200798745 /* ofRendererCollection.cpp in Sources */, + BF443CB32CE6F0DC005B6CCB /* MGLKViewController+iOS.mm in Sources */, + BF443CB42CE6F0DC005B6CCB /* MGLContext.mm in Sources */, + BF443CB52CE6F0DC005B6CCB /* MGLLayer.mm in Sources */, + BF443CB62CE6F0DC005B6CCB /* MGLKViewController+Mac.mm in Sources */, + BF443CB72CE6F0DC005B6CCB /* MGLKView.mm in Sources */, + BF443CB82CE6F0DC005B6CCB /* MGLDisplay.mm in Sources */, + BF443CB92CE6F0DC005B6CCB /* MGLKViewController.mm in Sources */, E4F76E61176CB27200798745 /* ofTessellator.cpp in Sources */, E4F76E63176CB27200798745 /* ofTrueTypeFont.cpp in Sources */, E4F76E65176CB27200798745 /* ofMath.cpp in Sources */, @@ -1311,6 +1431,7 @@ 67833F8A19F8996300DBE7AA /* ofBufferObject.cpp in Sources */, 1594366415CF5F420087B684 /* ofxiOSVideoGrabber.mm in Sources */, 1594366515CF5F420087B684 /* ofxiOSVideoPlayer.mm in Sources */, + BF3E028B2CE66D830022E17F /* EAMLKView.mm in Sources */, 678C3D24176F04F800D1CC68 /* ofxiOSSoundStream.mm in Sources */, 678C3D26176F04F800D1CC68 /* ofxiOSSoundStreamDelegate.mm in Sources */, 678C3D28176F04F800D1CC68 /* SoundInputStream.m in Sources */, diff --git a/libs/openFrameworksCompiled/project/ios/iOS+OFLib.xcodeproj/xcshareddata/xcschemes/iPhone+OF Static Library.xcscheme b/libs/openFrameworksCompiled/project/ios/iOS+OFLib.xcodeproj/xcshareddata/xcschemes/iPhone+OF Static Library.xcscheme new file mode 100644 index 00000000000..04abf825ae7 --- /dev/null +++ b/libs/openFrameworksCompiled/project/ios/iOS+OFLib.xcodeproj/xcshareddata/xcschemes/iPhone+OF Static Library.xcscheme @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/scripts/templates/ios/emptyExample.xcodeproj/project.pbxproj b/scripts/templates/ios/emptyExample.xcodeproj/project.pbxproj index 389205d11e4..b8dc1fa6519 100644 --- a/scripts/templates/ios/emptyExample.xcodeproj/project.pbxproj +++ b/scripts/templates/ios/emptyExample.xcodeproj/project.pbxproj @@ -1,645 +1,482 @@ +// !$*UTF8*$! { - "classes": {}, - "objectVersion": "46", - "archiveVersion": "1", - "objects": { - "5326AEA710A23A0500278DE6": { - "path": "System/Library/Frameworks/CoreLocation.framework", - "isa": "PBXFileReference", - "name": "CoreLocation.framework", - "lastKnownFileType": "wrapper.framework", - "sourceTree": "SDKROOT" - }, - "BBE5EAB80F49AD8400F28951": { - "isa": "PBXBuildFile", - "fileRef": "BBE5EAB70F49AD8400F28951" - }, - "BB16EBD90F2B2AB500518274": { - "isa": "PBXBuildFile", - "fileRef": "BB16EBD80F2B2AB500518274" - }, - "E41D3EE513B3906D00A75A5D": { - "path": "../../../libs/openFrameworksCompiled/project/ios/CoreOF.xcconfig", - "isa": "PBXFileReference", - "lastKnownFileType": "text.xcconfig", - "name": "CoreOF.xcconfig", - "sourceTree": "SOURCE_ROOT", - "fileEncoding": "4" - }, - "1D6058910D05DD3D006BFB54": { - "path": "emptyExample.app", - "isa": "PBXFileReference", - "includeInIndex": "0", - "explicitFileType": "wrapper.application", - "sourceTree": "BUILT_PRODUCTS_DIR" - }, - "19C28FACFE9D520D11CA2CBB": { - "isa": "PBXGroup", - "name": "Products", - "children": [ - "1D6058910D05DD3D006BFB54" - ], - "sourceTree": "" - }, - "1D60588E0D05DD3D006BFB54": { - "isa": "PBXSourcesBuildPhase", - "buildActionMask": "2147483647", - "files": [ - "E4D8936E11527B74007E1F53", - "E4D8936F11527B74007E1F53" - ], - "runOnlyForDeploymentPostprocessing": "0" - }, - "BB24DDC910DA781C00E9C588": { - "path": "ofxiOS-Info.plist", - "isa": "PBXFileReference", - "lastKnownFileType": "text.plist.xml", - "sourceTree": "", - "fileEncoding": "4" - }, - "1D6058940D05DD3E006BFB54": { - "isa": "XCBuildConfiguration", - "buildSettings": { - "GCC_PREFIX_HEADER": "ofxiOS_Prefix.pch", - "ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME": "", - "TARGETED_DEVICE_FAMILY": "1,2", - "INFOPLIST_FILE": "ofxiOS-Info.plist", - "GCC_WARN_64_TO_32_BIT_CONVERSION[arch=*64]": "NO", - "ALWAYS_SEARCH_USER_PATHS": "NO", - "HEADER_SEARCH_PATHS": [ - "$(OF_CORE_HEADERS)", - "src" - ], - "PRODUCT_NAME": "${TARGET_NAME}", - "VALID_ARCHS": "$(ARCHS_STANDARD)", - "GCC_PRECOMPILE_PREFIX_HEADER": "YES", - "FRAMEWORK_SEARCH_PATHS": [ - "$(inherited)", - "$(PROJECT_DIR)" - ], - "ASSETCATALOG_COMPILER_APPICON_NAME": "AppIcon", - "OTHER_LDFLAGS": [ - "$(OF_CORE_LIBS)", - "$(OF_CORE_FRAMEWORKS)" - ] - }, - "name": "Debug" - }, - "E41D410213B3A0D800A75A5D": { - "path": "libofxiOS_iphoneos_Debug.a", - "isa": "PBXReferenceProxy", - "fileType": "archive.ar", - "remoteRef": "E41D410113B3A0D800A75A5D", - "sourceTree": "BUILT_PRODUCTS_DIR" - }, - "9936F6121BFA65F100891288": { - "isa": "PBXBuildFile", - "fileRef": "9936F6111BFA65F100891288" - }, - "67DFA53619F92A69003B3434": { - "isa": "PBXBuildFile", - "fileRef": "67DFA53419F92A5E003B3434" - }, - "288765FD0DF74451002DB57D": { - "isa": "PBXBuildFile", - "fileRef": "288765FC0DF74451002DB57D" - }, - "E4D8936D11527B74007E1F53": { - "path": "src/ofApp.mm", - "isa": "PBXFileReference", - "lastKnownFileType": "sourcecode.cpp.objcpp", - "name": "ofApp.mm", - "sourceTree": "SOURCE_ROOT", - "fileEncoding": "4" - }, - "C01FCF4F08A954540054247B": { - "baseConfigurationReference": "E41D3ED613B38FB500A75A5D", - "isa": "XCBuildConfiguration", - "buildSettings": { - "VALID_ARCHS": "$(ARCHS_STANDARD)", - "GCC_WARN_ABOUT_RETURN_TYPE": "YES", - "ONLY_ACTIVE_ARCH": "YES", - "GCC_SYMBOLS_PRIVATE_EXTERN": "NO", - "GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO": "NO", - "COMPRESS_PNG_FILES": "NO", - "GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL": "NO", - "GCC_OPTIMIZATION_LEVEL": "0", - "GCC_C_LANGUAGE_STANDARD": "c17", - "TARGETED_DEVICE_FAMILY": "1", - "GCC_WARN_PROTOTYPE_CONVERSION": "NO", - "GCC_WARN_64_TO_32_BIT_CONVERSION[arch=*64]": "NO", - "ALWAYS_SEARCH_USER_PATHS": "YES", - "PROVISIONING_PROFILE[sdk=iphoneos*]": "", - "SDKROOT": "iphoneos", - "CODE_SIGN_IDENTITY[sdk=iphoneos*]": "iPhone Developer", - "CODE_SIGN_IDENTITY": "", - "WARNING_LDFLAGS": "-no_arch_warnings", - "GCC_WARN_ABOUT_POINTER_SIGNEDNESS": "NO", - "CLANG_CXX_LIBRARY": "libc++", - "CODE_SIGN_IDENTITY[sdk=iphonesimulator*]": "", - "GCC_WARN_UNUSED_VARIABLE": "YES" - }, - "name": "Debug" - }, - "901808BF2053636F004A7774": { - "path": "System/Library/Frameworks/GLKit.framework", - "isa": "PBXFileReference", - "name": "GLKit.framework", - "lastKnownFileType": "wrapper.framework", - "sourceTree": "SDKROOT" - }, - "E41D400D13B39D2100A75A5D": { - "isa": "PBXBuildFile", - "fileRef": "E41D400813B39D2100A75A5D" - }, - "53F323EB10A20EDB00E0DAE4": { - "isa": "PBXBuildFile", - "fileRef": "53F323EA10A20EDB00E0DAE4" - }, - "901808C02053638E004A7774": { - "isa": "PBXGroup", - "name": "Frameworks", - "children": [], - "sourceTree": "" - }, - "6948EE371B920CB800B5AC1A": { - "isa": "PBXGroup", - "name": "local_addons", - "children": [], - "sourceTree": "" - }, - "E4D8936A11527B74007E1F53": { - "path": "src", - "isa": "PBXGroup", - "children": [ - "E4D8936B11527B74007E1F53", - "E4D8936D11527B74007E1F53", - "E4D8936C11527B74007E1F53" - ], - "sourceTree": "SOURCE_ROOT" - }, - "29B97313FDCFA39411CA2CEA": { - "projectReferences": [ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXBuildFile section */ + 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; }; + 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */; }; + 288765FD0DF74451002DB57D /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 288765FC0DF74451002DB57D /* CoreGraphics.framework */; }; + 5326AEA810A23A0500278DE6 /* CoreLocation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5326AEA710A23A0500278DE6 /* CoreLocation.framework */; }; + 53F323EB10A20EDB00E0DAE4 /* OpenAL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 53F323EA10A20EDB00E0DAE4 /* OpenAL.framework */; }; + 67DFA53619F92A69003B3434 /* Accelerate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 67DFA53419F92A5E003B3434 /* Accelerate.framework */; }; + 901808C12053638E004A7774 /* GLKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 901808BF2053636F004A7774 /* GLKit.framework */; }; + 9936F6101BFA4DEE00891288 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9936F60F1BFA4DEE00891288 /* Images.xcassets */; }; + 9936F6121BFA65F100891288 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9936F6111BFA65F100891288 /* LaunchScreen.storyboard */; }; + 9969E7561C782C4500DEF0F6 /* CoreMotion.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9969E7551C782C4500DEF0F6 /* CoreMotion.framework */; }; + BB16EBD20F2B2A9500518274 /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BB16EBD10F2B2A9500518274 /* OpenGLES.framework */; }; + BB16EBD90F2B2AB500518274 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BB16EBD80F2B2AB500518274 /* QuartzCore.framework */; }; + BBE5EAB80F49AD8400F28951 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BBE5EAB70F49AD8400F28951 /* AudioToolbox.framework */; }; + BF3E02862CE64C2D0022E17F /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF3E02852CE64C2D0022E17F /* Metal.framework */; }; + BF3E02962CE66F9C0022E17F /* metalangle.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF3E02952CE66F9C0022E17F /* metalangle.xcframework */; settings = {ATTRIBUTES = (Required, ); }; }; + E41D400B13B39D2100A75A5D /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E41D400613B39D2100A75A5D /* AVFoundation.framework */; }; + E41D400C13B39D2100A75A5D /* CoreMedia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E41D400713B39D2100A75A5D /* CoreMedia.framework */; }; + E41D400D13B39D2100A75A5D /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E41D400813B39D2100A75A5D /* CoreVideo.framework */; }; + E41D400E13B39D2100A75A5D /* MapKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E41D400913B39D2100A75A5D /* MapKit.framework */; }; + E4D8936E11527B74007E1F53 /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = E4D8936B11527B74007E1F53 /* main.mm */; }; + E4D8936F11527B74007E1F53 /* ofApp.mm in Sources */ = {isa = PBXBuildFile; fileRef = E4D8936D11527B74007E1F53 /* ofApp.mm */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + E41D410113B3A0D800A75A5D /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = E41D40FD13B3A0D800A75A5D /* iOS+OFLib.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = BB24DED610DA7A3F00E9C588; + remoteInfo = "iPhone+OF Static Library"; + }; + E41D410313B3A11300A75A5D /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = E41D40FD13B3A0D800A75A5D /* iOS+OFLib.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = BB24DE5C10DA7A3F00E9C588; + remoteInfo = "iPhone+OF Static Library"; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 1D30AB110D05D00D00671497 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 1D6058910D05DD3D006BFB54 /* emptyExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = emptyExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; + 288765FC0DF74451002DB57D /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; + 32CA4F630368D1EE00C91783 /* ofxiOS_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ofxiOS_Prefix.pch; sourceTree = ""; }; + 5326AEA710A23A0500278DE6 /* CoreLocation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreLocation.framework; path = System/Library/Frameworks/CoreLocation.framework; sourceTree = SDKROOT; }; + 53F323EA10A20EDB00E0DAE4 /* OpenAL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenAL.framework; path = System/Library/Frameworks/OpenAL.framework; sourceTree = SDKROOT; }; + 67DFA53419F92A5E003B3434 /* Accelerate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = System/Library/Frameworks/Accelerate.framework; sourceTree = SDKROOT; }; + 901808BF2053636F004A7774 /* GLKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GLKit.framework; path = System/Library/Frameworks/GLKit.framework; sourceTree = SDKROOT; }; + 9936F60F1BFA4DEE00891288 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; + 9936F6111BFA65F100891288 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; + 9969E7551C782C4500DEF0F6 /* CoreMotion.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMotion.framework; path = System/Library/Frameworks/CoreMotion.framework; sourceTree = SDKROOT; }; + BB16EBD10F2B2A9500518274 /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = System/Library/Frameworks/OpenGLES.framework; sourceTree = SDKROOT; }; + BB16EBD80F2B2AB500518274 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; + BB24DDC910DA781C00E9C588 /* ofxiOS-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "ofxiOS-Info.plist"; sourceTree = ""; }; + BBE5EAB70F49AD8400F28951 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; }; + BF3E02852CE64C2D0022E17F /* Metal.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Metal.framework; path = System/Library/Frameworks/Metal.framework; sourceTree = SDKROOT; }; + BF3E02952CE66F9C0022E17F /* metalangle.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = metalangle.xcframework; path = ../../../libs/metalangle/lib/macos/metalangle.xcframework; sourceTree = ""; }; + E41D3ED613B38FB500A75A5D /* Project.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Project.xcconfig; sourceTree = ""; }; + E41D3EE513B3906D00A75A5D /* CoreOF.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = CoreOF.xcconfig; path = ../../../libs/openFrameworksCompiled/project/ios/CoreOF.xcconfig; sourceTree = SOURCE_ROOT; }; + E41D400613B39D2100A75A5D /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; }; + E41D400713B39D2100A75A5D /* CoreMedia.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMedia.framework; path = System/Library/Frameworks/CoreMedia.framework; sourceTree = SDKROOT; }; + E41D400813B39D2100A75A5D /* CoreVideo.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreVideo.framework; path = System/Library/Frameworks/CoreVideo.framework; sourceTree = SDKROOT; }; + E41D400913B39D2100A75A5D /* MapKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MapKit.framework; path = System/Library/Frameworks/MapKit.framework; sourceTree = SDKROOT; }; + E41D40FD13B3A0D800A75A5D /* iOS+OFLib.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = "iOS+OFLib.xcodeproj"; path = "../../../libs/openFrameworksCompiled/project/ios/iOS+OFLib.xcodeproj"; sourceTree = SOURCE_ROOT; }; + E4A823A312561BE3002F86A2 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; + E4D8936B11527B74007E1F53 /* main.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = main.mm; path = src/main.mm; sourceTree = SOURCE_ROOT; }; + E4D8936C11527B74007E1F53 /* ofApp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ofApp.h; path = src/ofApp.h; sourceTree = SOURCE_ROOT; }; + E4D8936D11527B74007E1F53 /* ofApp.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ofApp.mm; path = src/ofApp.mm; sourceTree = SOURCE_ROOT; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 1D60588F0D05DD3D006BFB54 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + BF3E02862CE64C2D0022E17F /* Metal.framework in Frameworks */, + 9969E7561C782C4500DEF0F6 /* CoreMotion.framework in Frameworks */, + 901808C12053638E004A7774 /* GLKit.framework in Frameworks */, + 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */, + 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */, + 288765FD0DF74451002DB57D /* CoreGraphics.framework in Frameworks */, + BB16EBD20F2B2A9500518274 /* OpenGLES.framework in Frameworks */, + BB16EBD90F2B2AB500518274 /* QuartzCore.framework in Frameworks */, + BF3E02962CE66F9C0022E17F /* metalangle.xcframework in Frameworks */, + BBE5EAB80F49AD8400F28951 /* AudioToolbox.framework in Frameworks */, + 53F323EB10A20EDB00E0DAE4 /* OpenAL.framework in Frameworks */, + 5326AEA810A23A0500278DE6 /* CoreLocation.framework in Frameworks */, + E41D400B13B39D2100A75A5D /* AVFoundation.framework in Frameworks */, + E41D400C13B39D2100A75A5D /* CoreMedia.framework in Frameworks */, + E41D400D13B39D2100A75A5D /* CoreVideo.framework in Frameworks */, + E41D400E13B39D2100A75A5D /* MapKit.framework in Frameworks */, + 67DFA53619F92A69003B3434 /* Accelerate.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 19C28FACFE9D520D11CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + 1D6058910D05DD3D006BFB54 /* emptyExample.app */, + ); + name = Products; + sourceTree = ""; + }; + 29B97314FDCFA39411CA2CEA /* CustomTemplate */ = { + isa = PBXGroup; + children = ( + 9936F60E1BFA4DEE00891288 /* mediaAssets */, + E4D8936A11527B74007E1F53 /* src */, + BB24E1F710DAA51900E9C588 /* openFrameworks */, + BB16F26B0F2B646B00518274 /* addons */, + BB16E9930F2B1E5900518274 /* libs */, + 19C28FACFE9D520D11CA2CBB /* Products */, + 901808C02053638E004A7774 /* Frameworks */, + ); + name = CustomTemplate; + sourceTree = ""; + }; + 29B97323FDCFA39411CA2CEA /* core frameworks */ = { + isa = PBXGroup; + children = ( + 67DFA53419F92A5E003B3434 /* Accelerate.framework */, + 901808BF2053636F004A7774 /* GLKit.framework */, + BBE5EAB70F49AD8400F28951 /* AudioToolbox.framework */, + E41D400613B39D2100A75A5D /* AVFoundation.framework */, + E4A823A312561BE3002F86A2 /* CoreGraphics.framework */, + 5326AEA710A23A0500278DE6 /* CoreLocation.framework */, + E41D400713B39D2100A75A5D /* CoreMedia.framework */, + 9969E7551C782C4500DEF0F6 /* CoreMotion.framework */, + E41D400813B39D2100A75A5D /* CoreVideo.framework */, + 1D30AB110D05D00D00671497 /* Foundation.framework */, + E41D400913B39D2100A75A5D /* MapKit.framework */, + 53F323EA10A20EDB00E0DAE4 /* OpenAL.framework */, + BB16EBD10F2B2A9500518274 /* OpenGLES.framework */, + BB16EBD80F2B2AB500518274 /* QuartzCore.framework */, + 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */, + 288765FC0DF74451002DB57D /* CoreGraphics.framework */, + ); + name = "core frameworks"; + sourceTree = ""; + }; + 6948EE371B920CB800B5AC1A /* local_addons */ = { + isa = PBXGroup; + children = ( + ); + name = local_addons; + sourceTree = ""; + }; + 901808C02053638E004A7774 /* Frameworks */ = { + isa = PBXGroup; + children = ( + BF3E02952CE66F9C0022E17F /* metalangle.xcframework */, + BF3E02852CE64C2D0022E17F /* Metal.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 9936F60E1BFA4DEE00891288 /* mediaAssets */ = { + isa = PBXGroup; + children = ( + 9936F6111BFA65F100891288 /* LaunchScreen.storyboard */, + 9936F60F1BFA4DEE00891288 /* Images.xcassets */, + ); + path = mediaAssets; + sourceTree = ""; + }; + BB16E9930F2B1E5900518274 /* libs */ = { + isa = PBXGroup; + children = ( + BBE5E94E0F497BD800F28951 /* core */, + ); + name = libs; + sourceTree = ""; + }; + BB16F26B0F2B646B00518274 /* addons */ = { + isa = PBXGroup; + children = ( + ); + name = addons; + path = ../../../addons; + sourceTree = SOURCE_ROOT; + }; + BB24E1F710DAA51900E9C588 /* openFrameworks */ = { + isa = PBXGroup; + children = ( + E41D40FD13B3A0D800A75A5D /* iOS+OFLib.xcodeproj */, + 32CA4F630368D1EE00C91783 /* ofxiOS_Prefix.pch */, + BB24DDC910DA781C00E9C588 /* ofxiOS-Info.plist */, + E41D3EE513B3906D00A75A5D /* CoreOF.xcconfig */, + 6948EE371B920CB800B5AC1A /* local_addons */, + E41D3ED613B38FB500A75A5D /* Project.xcconfig */, + ); + name = openFrameworks; + sourceTree = ""; + }; + BBE5E94E0F497BD800F28951 /* core */ = { + isa = PBXGroup; + children = ( + 29B97323FDCFA39411CA2CEA /* core frameworks */, + ); + name = core; + sourceTree = ""; + }; + E41D40FE13B3A0D800A75A5D /* Products */ = { + isa = PBXGroup; + children = ( + E41D410213B3A0D800A75A5D /* libofxiOS_iphoneos_Debug.a */, + ); + name = Products; + sourceTree = ""; + }; + E4D8936A11527B74007E1F53 /* src */ = { + isa = PBXGroup; + children = ( + E4D8936B11527B74007E1F53 /* main.mm */, + E4D8936D11527B74007E1F53 /* ofApp.mm */, + E4D8936C11527B74007E1F53 /* ofApp.h */, + ); + path = src; + sourceTree = SOURCE_ROOT; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 1D6058900D05DD3D006BFB54 /* emptyExample */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "emptyExample" */; + buildPhases = ( + 1D60588D0D05DD3D006BFB54 /* Resources */, + 1D60588E0D05DD3D006BFB54 /* Sources */, + 1D60588F0D05DD3D006BFB54 /* Frameworks */, + 9255DD331112741900D6945E /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + E41D410413B3A11300A75A5D /* PBXTargetDependency */, + ); + name = emptyExample; + productName = iPhone; + productReference = 1D6058910D05DD3D006BFB54 /* emptyExample.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 29B97313FDCFA39411CA2CEA /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0600; + }; + buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "emptyExample" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = en; + hasScannedForEncodings = 1; + knownRegions = ( + en, + Base, + ); + mainGroup = 29B97314FDCFA39411CA2CEA /* CustomTemplate */; + projectDirPath = ""; + projectReferences = ( { - "ProjectRef": "E41D40FD13B3A0D800A75A5D", - "ProductGroup": "E41D40FE13B3A0D800A75A5D" - } - ], - "buildConfigurationList": "C01FCF4E08A954540054247B", - "targets": [ - "1D6058900D05DD3D006BFB54" - ], - "developmentRegion": "en", - "knownRegions": [ - "en", - "Base" - ], - "isa": "PBXProject", - "compatibilityVersion": "Xcode 3.2", - "projectDirPath": "", - "attributes": { - "LastUpgradeCheck": "0600" - }, - "hasScannedForEncodings": "1", - "projectRoot": "", - "mainGroup": "29B97314FDCFA39411CA2CEA" - }, - "9969E7551C782C4500DEF0F6": { - "path": "System/Library/Frameworks/CoreMotion.framework", - "isa": "PBXFileReference", - "name": "CoreMotion.framework", - "lastKnownFileType": "wrapper.framework", - "sourceTree": "SDKROOT" - }, - "29B97323FDCFA39411CA2CEA": { - "isa": "PBXGroup", - "name": "core frameworks", - "children": [ - "67DFA53419F92A5E003B3434", - "901808BF2053636F004A7774", - "BBE5EAB70F49AD8400F28951", - "E41D400613B39D2100A75A5D", - "E4A823A312561BE3002F86A2", - "5326AEA710A23A0500278DE6", - "E41D400713B39D2100A75A5D", - "9969E7551C782C4500DEF0F6", - "E41D400813B39D2100A75A5D", - "1D30AB110D05D00D00671497", - "E41D400913B39D2100A75A5D", - "53F323EA10A20EDB00E0DAE4", - "BB16EBD10F2B2A9500518274", - "BB16EBD80F2B2AB500518274", - "1DF5F4DF0D08C38300B7A737", - "288765FC0DF74451002DB57D" - ], - "sourceTree": "" - }, - "E41D400713B39D2100A75A5D": { - "path": "System/Library/Frameworks/CoreMedia.framework", - "isa": "PBXFileReference", - "name": "CoreMedia.framework", - "lastKnownFileType": "wrapper.framework", - "sourceTree": "SDKROOT" - }, - "9936F6101BFA4DEE00891288": { - "isa": "PBXBuildFile", - "fileRef": "9936F60F1BFA4DEE00891288" - }, - "1DF5F4E00D08C38300B7A737": { - "isa": "PBXBuildFile", - "fileRef": "1DF5F4DF0D08C38300B7A737" - }, - "BB16EBD10F2B2A9500518274": { - "path": "System/Library/Frameworks/OpenGLES.framework", - "isa": "PBXFileReference", - "name": "OpenGLES.framework", - "lastKnownFileType": "wrapper.framework", - "sourceTree": "SDKROOT" - }, - "1D30AB110D05D00D00671497": { - "path": "System/Library/Frameworks/Foundation.framework", - "isa": "PBXFileReference", - "name": "Foundation.framework", - "lastKnownFileType": "wrapper.framework", - "sourceTree": "SDKROOT" - }, - "5326AEA810A23A0500278DE6": { - "isa": "PBXBuildFile", - "fileRef": "5326AEA710A23A0500278DE6" - }, - "1D60588F0D05DD3D006BFB54": { - "isa": "PBXFrameworksBuildPhase", - "buildActionMask": "2147483647", - "files": [ - "9969E7561C782C4500DEF0F6", - "901808C12053638E004A7774", - "1D60589F0D05DD5A006BFB54", - "1DF5F4E00D08C38300B7A737", - "288765FD0DF74451002DB57D", - "BB16EBD20F2B2A9500518274", - "BB16EBD90F2B2AB500518274", - "BBE5EAB80F49AD8400F28951", - "53F323EB10A20EDB00E0DAE4", - "5326AEA810A23A0500278DE6", - "E41D400B13B39D2100A75A5D", - "E41D400C13B39D2100A75A5D", - "E41D400D13B39D2100A75A5D", - "E41D400E13B39D2100A75A5D", - "67DFA53619F92A69003B3434" - ], - "runOnlyForDeploymentPostprocessing": "0" - }, - "1D6058950D05DD3E006BFB54": { - "isa": "XCBuildConfiguration", - "buildSettings": { - "OTHER_LDFLAGS": [ - "$(OF_CORE_LIBS)", - "$(OF_CORE_FRAMEWORKS)" - ], - "ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME": "", - "TARGETED_DEVICE_FAMILY": "1,2", - "INFOPLIST_FILE": "ofxiOS-Info.plist", - "GCC_WARN_64_TO_32_BIT_CONVERSION[arch=*64]": "NO", - "HEADER_SEARCH_PATHS": [ + ProductGroup = E41D40FE13B3A0D800A75A5D /* Products */; + ProjectRef = E41D40FD13B3A0D800A75A5D /* iOS+OFLib.xcodeproj */; + }, + ); + projectRoot = ""; + targets = ( + 1D6058900D05DD3D006BFB54 /* emptyExample */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXReferenceProxy section */ + E41D410213B3A0D800A75A5D /* libofxiOS_iphoneos_Debug.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libofxiOS_iphoneos_Debug.a; + remoteRef = E41D410113B3A0D800A75A5D /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; +/* End PBXReferenceProxy section */ + +/* Begin PBXResourcesBuildPhase section */ + 1D60588D0D05DD3D006BFB54 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 9936F6101BFA4DEE00891288 /* Images.xcassets in Resources */, + 9936F6121BFA65F100891288 /* LaunchScreen.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 9255DD331112741900D6945E /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "rsync -avz --exclude='.DS_Store' \"${SRCROOT}/bin/data/\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}\"\n"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 1D60588E0D05DD3D006BFB54 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + E4D8936E11527B74007E1F53 /* main.mm in Sources */, + E4D8936F11527B74007E1F53 /* ofApp.mm in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + E41D410413B3A11300A75A5D /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "iPhone+OF Static Library"; + targetProxy = E41D410313B3A11300A75A5D /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 1D6058940D05DD3E006BFB54 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = ""; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)", + ); + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = ofxiOS_Prefix.pch; + "GCC_WARN_64_TO_32_BIT_CONVERSION[arch=*64]" = NO; + HEADER_SEARCH_PATHS = ( "$(OF_CORE_HEADERS)", - "src" - ], - "PRODUCT_NAME": "${TARGET_NAME}", - "VALID_ARCHS": "$(ARCHS_STANDARD)", - "FRAMEWORK_SEARCH_PATHS": [ + src, + ); + INFOPLIST_FILE = "ofxiOS-Info.plist"; + OTHER_LDFLAGS = ( + "$(OF_CORE_LIBS)", + "$(OF_CORE_FRAMEWORKS)", + ); + PRODUCT_NAME = "${TARGET_NAME}"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALID_ARCHS = "$(ARCHS_STANDARD)"; + }; + name = Debug; + }; + 1D6058950D05DD3E006BFB54 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = ""; + FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)" - ], - "GCC_PRECOMPILE_PREFIX_HEADER": "YES", - "ASSETCATALOG_COMPILER_APPICON_NAME": "AppIcon", - "GCC_PREFIX_HEADER": "ofxiOS_Prefix.pch" - }, - "name": "Release" - }, - "E4D8936E11527B74007E1F53": { - "isa": "PBXBuildFile", - "fileRef": "E4D8936B11527B74007E1F53" - }, - "E41D3ED613B38FB500A75A5D": { - "path": "Project.xcconfig", - "isa": "PBXFileReference", - "lastKnownFileType": "text.xcconfig", - "sourceTree": "", - "fileEncoding": "4" - }, - "9255DD331112741900D6945E": { - "inputPaths": [], - "shellPath": "/bin/sh", - "buildActionMask": "2147483647", - "isa": "PBXShellScriptBuildPhase", - "outputPaths": [], - "runOnlyForDeploymentPostprocessing": "0", - "shellScript": "rsync -avz --exclude='.DS_Store' \"${SRCROOT}/bin/data/\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}\"\n", - "files": [] - }, - "32CA4F630368D1EE00C91783": { - "path": "ofxiOS_Prefix.pch", - "isa": "PBXFileReference", - "lastKnownFileType": "sourcecode.c.h", - "sourceTree": "", - "fileEncoding": "4" - }, - "E41D400E13B39D2100A75A5D": { - "isa": "PBXBuildFile", - "fileRef": "E41D400913B39D2100A75A5D" - }, - "901808C12053638E004A7774": { - "isa": "PBXBuildFile", - "fileRef": "901808BF2053636F004A7774" - }, - "E4D8936B11527B74007E1F53": { - "path": "src/main.mm", - "isa": "PBXFileReference", - "lastKnownFileType": "sourcecode.cpp.objcpp", - "name": "main.mm", - "sourceTree": "SOURCE_ROOT", - "fileEncoding": "4" - }, - "29B97314FDCFA39411CA2CEA": { - "isa": "PBXGroup", - "name": "CustomTemplate", - "children": [ - "9936F60E1BFA4DEE00891288", - "E4D8936A11527B74007E1F53", - "BB24E1F710DAA51900E9C588", - "BB16F26B0F2B646B00518274", - "BB16E9930F2B1E5900518274", - "19C28FACFE9D520D11CA2CBB", - "901808C02053638E004A7774" - ], - "sourceTree": "" - }, - "9969E7561C782C4500DEF0F6": { - "isa": "PBXBuildFile", - "fileRef": "9969E7551C782C4500DEF0F6" - }, - "E41D410313B3A11300A75A5D": { - "isa": "PBXContainerItemProxy", - "containerPortal": "E41D40FD13B3A0D800A75A5D", - "remoteGlobalIDString": "BB24DE5C10DA7A3F00E9C588", - "remoteInfo": "iPhone+OF Static Library", - "proxyType": "1" - }, - "E4A823A312561BE3002F86A2": { - "path": "System/Library/Frameworks/CoreGraphics.framework", - "isa": "PBXFileReference", - "name": "CoreGraphics.framework", - "lastKnownFileType": "wrapper.framework", - "sourceTree": "SDKROOT" - }, - "9936F60E1BFA4DEE00891288": { - "path": "mediaAssets", - "isa": "PBXGroup", - "children": [ - "9936F6111BFA65F100891288", - "9936F60F1BFA4DEE00891288" - ], - "sourceTree": "" - }, - "E41D400B13B39D2100A75A5D": { - "isa": "PBXBuildFile", - "fileRef": "E41D400613B39D2100A75A5D" - }, - "E41D400813B39D2100A75A5D": { - "path": "System/Library/Frameworks/CoreVideo.framework", - "isa": "PBXFileReference", - "name": "CoreVideo.framework", - "lastKnownFileType": "wrapper.framework", - "sourceTree": "SDKROOT" - }, - "BBE5E94E0F497BD800F28951": { - "isa": "PBXGroup", - "name": "core", - "children": [ - "29B97323FDCFA39411CA2CEA" - ], - "sourceTree": "" - }, - "C01FCF5008A954540054247B": { - "baseConfigurationReference": "E41D3ED613B38FB500A75A5D", - "isa": "XCBuildConfiguration", - "buildSettings": { - "VALID_ARCHS": "$(ARCHS_STANDARD)", - "GCC_GENERATE_DEBUGGING_SYMBOLS": "NO", - "GCC_WARN_ABOUT_RETURN_TYPE": "YES", - "ONLY_ACTIVE_ARCH": "NO", - "GCC_SYMBOLS_PRIVATE_EXTERN": "NO", - "COMPRESS_PNG_FILES": "NO", - "GCC_OPTIMIZATION_LEVEL": "s", - "GCC_THUMB_SUPPORT": "NO", - "GCC_C_LANGUAGE_STANDARD": "c11", - "TARGETED_DEVICE_FAMILY": "1", - "GCC_WARN_64_TO_32_BIT_CONVERSION[arch=*64]": "NO", - "ALWAYS_SEARCH_USER_PATHS": "YES", - "SDKROOT": "iphoneos", - "WARNING_LDFLAGS": "-no_arch_warnings", - "CODE_SIGN_IDENTITY": "", - "GCC_DYNAMIC_NO_PIC": "NO", - "CODE_SIGN_IDENTITY[sdk=iphoneos*]": "iPhone Developer", - "CLANG_CXX_LIBRARY": "libc++", - "CODE_SIGN_IDENTITY[sdk=iphonesimulator*]": "", - "GCC_WARN_UNUSED_VARIABLE": "YES" - }, - "name": "Release" - }, - "BB16EBD20F2B2A9500518274": { - "isa": "PBXBuildFile", - "fileRef": "BB16EBD10F2B2A9500518274" - }, - "1D60589F0D05DD5A006BFB54": { - "isa": "PBXBuildFile", - "fileRef": "1D30AB110D05D00D00671497" - }, - "1D6058960D05DD3E006BFB54": { - "isa": "XCConfigurationList", - "defaultConfigurationIsVisible": "0", - "defaultConfigurationName": "Release", - "buildConfigurations": [ - "1D6058940D05DD3E006BFB54", - "1D6058950D05DD3E006BFB54" - ] - }, - "E41D40FD13B3A0D800A75A5D": { - "path": "../../../libs/openFrameworksCompiled/project/ios/iOS+OFLib.xcodeproj", - "isa": "PBXFileReference", - "name": "iOS+OFLib.xcodeproj", - "lastKnownFileType": "wrapper.pb-project", - "sourceTree": "SOURCE_ROOT" - }, - "BB16F26B0F2B646B00518274": { - "path": "../../../addons", - "isa": "PBXGroup", - "name": "addons", - "children": [], - "sourceTree": "SOURCE_ROOT" - }, - "E4D8936F11527B74007E1F53": { - "isa": "PBXBuildFile", - "fileRef": "E4D8936D11527B74007E1F53" - }, - "1D60588D0D05DD3D006BFB54": { - "isa": "PBXResourcesBuildPhase", - "buildActionMask": "2147483647", - "files": [ - "9936F6101BFA4DEE00891288", - "9936F6121BFA65F100891288" - ], - "runOnlyForDeploymentPostprocessing": "0" - }, - "BBE5EAB70F49AD8400F28951": { - "path": "System/Library/Frameworks/AudioToolbox.framework", - "isa": "PBXFileReference", - "name": "AudioToolbox.framework", - "lastKnownFileType": "wrapper.framework", - "sourceTree": "SDKROOT" - }, - "BB16EBD80F2B2AB500518274": { - "path": "System/Library/Frameworks/QuartzCore.framework", - "isa": "PBXFileReference", - "name": "QuartzCore.framework", - "lastKnownFileType": "wrapper.framework", - "sourceTree": "SDKROOT" - }, - "1D6058900D05DD3D006BFB54": { - "buildConfigurationList": "1D6058960D05DD3E006BFB54", - "productReference": "1D6058910D05DD3D006BFB54", - "productType": "com.apple.product-type.application", - "productName": "iPhone", - "isa": "PBXNativeTarget", - "buildPhases": [ - "1D60588D0D05DD3D006BFB54", - "1D60588E0D05DD3D006BFB54", - "1D60588F0D05DD3D006BFB54", - "9255DD331112741900D6945E" - ], - "dependencies": [ - "E41D410413B3A11300A75A5D" - ], - "name": "emptyExample", - "buildRules": [] - }, - "BB24E1F710DAA51900E9C588": { - "isa": "PBXGroup", - "name": "openFrameworks", - "children": [ - "E41D40FD13B3A0D800A75A5D", - "32CA4F630368D1EE00C91783", - "BB24DDC910DA781C00E9C588", - "E41D3EE513B3906D00A75A5D", - "6948EE371B920CB800B5AC1A", - "E41D3ED613B38FB500A75A5D" - ], - "sourceTree": "" - }, - "E41D410113B3A0D800A75A5D": { - "isa": "PBXContainerItemProxy", - "containerPortal": "E41D40FD13B3A0D800A75A5D", - "remoteGlobalIDString": "BB24DED610DA7A3F00E9C588", - "remoteInfo": "iPhone+OF Static Library", - "proxyType": "2" - }, - "288765FC0DF74451002DB57D": { - "path": "System/Library/Frameworks/CoreGraphics.framework", - "isa": "PBXFileReference", - "name": "CoreGraphics.framework", - "lastKnownFileType": "wrapper.framework", - "sourceTree": "SDKROOT" - }, - "E4D8936C11527B74007E1F53": { - "path": "src/ofApp.h", - "isa": "PBXFileReference", - "lastKnownFileType": "sourcecode.c.h", - "name": "ofApp.h", - "sourceTree": "SOURCE_ROOT", - "fileEncoding": "4" - }, - "9936F6111BFA65F100891288": { - "path": "LaunchScreen.storyboard", - "isa": "PBXFileReference", - "lastKnownFileType": "file.storyboard", - "sourceTree": "", - "fileEncoding": "4" - }, - "C01FCF4E08A954540054247B": { - "isa": "XCConfigurationList", - "defaultConfigurationIsVisible": "0", - "defaultConfigurationName": "Release", - "buildConfigurations": [ - "C01FCF4F08A954540054247B", - "C01FCF5008A954540054247B" - ] - }, - "9936F60F1BFA4DEE00891288": { - "path": "Images.xcassets", - "isa": "PBXFileReference", - "lastKnownFileType": "folder.assetcatalog", - "sourceTree": "" - }, - "E41D400C13B39D2100A75A5D": { - "isa": "PBXBuildFile", - "fileRef": "E41D400713B39D2100A75A5D" - }, - "E41D400913B39D2100A75A5D": { - "path": "System/Library/Frameworks/MapKit.framework", - "isa": "PBXFileReference", - "name": "MapKit.framework", - "lastKnownFileType": "wrapper.framework", - "sourceTree": "SDKROOT" - }, - "1DF5F4DF0D08C38300B7A737": { - "path": "System/Library/Frameworks/UIKit.framework", - "isa": "PBXFileReference", - "name": "UIKit.framework", - "lastKnownFileType": "wrapper.framework", - "sourceTree": "SDKROOT" - }, - "53F323EA10A20EDB00E0DAE4": { - "path": "System/Library/Frameworks/OpenAL.framework", - "isa": "PBXFileReference", - "name": "OpenAL.framework", - "lastKnownFileType": "wrapper.framework", - "sourceTree": "SDKROOT" - }, - "67DFA53419F92A5E003B3434": { - "path": "System/Library/Frameworks/Accelerate.framework", - "isa": "PBXFileReference", - "name": "Accelerate.framework", - "lastKnownFileType": "wrapper.framework", - "sourceTree": "SDKROOT" - }, - "E41D410413B3A11300A75A5D": { - "isa": "PBXTargetDependency", - "name": "iPhone+OF Static Library", - "targetProxy": "E41D410313B3A11300A75A5D" - }, - "BB16E9930F2B1E5900518274": { - "isa": "PBXGroup", - "name": "libs", - "children": [ - "BBE5E94E0F497BD800F28951" - ], - "sourceTree": "" - }, - "E41D400613B39D2100A75A5D": { - "path": "System/Library/Frameworks/AVFoundation.framework", - "isa": "PBXFileReference", - "name": "AVFoundation.framework", - "lastKnownFileType": "wrapper.framework", - "sourceTree": "SDKROOT" - }, - "E41D40FE13B3A0D800A75A5D": { - "isa": "PBXGroup", - "name": "Products", - "children": [ - "E41D410213B3A0D800A75A5D" - ], - "sourceTree": "" - } - }, - "rootObject": "29B97313FDCFA39411CA2CEA" + "$(PROJECT_DIR)", + ); + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = ofxiOS_Prefix.pch; + "GCC_WARN_64_TO_32_BIT_CONVERSION[arch=*64]" = NO; + HEADER_SEARCH_PATHS = ( + "$(OF_CORE_HEADERS)", + src, + ); + INFOPLIST_FILE = "ofxiOS-Info.plist"; + OTHER_LDFLAGS = ( + "$(OF_CORE_LIBS)", + "$(OF_CORE_FRAMEWORKS)", + ); + PRODUCT_NAME = "${TARGET_NAME}"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALID_ARCHS = "$(ARCHS_STANDARD)"; + }; + name = Release; + }; + C01FCF4F08A954540054247B /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = E41D3ED613B38FB500A75A5D /* Project.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = YES; + CLANG_CXX_LIBRARY = "libc++"; + CODE_SIGN_IDENTITY = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphonesimulator*]" = ""; + COMPRESS_PNG_FILES = NO; + GCC_C_LANGUAGE_STANDARD = c17; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + "GCC_WARN_64_TO_32_BIT_CONVERSION[arch=*64]" = NO; + GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = NO; + GCC_WARN_ABOUT_POINTER_SIGNEDNESS = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL = NO; + GCC_WARN_PROTOTYPE_CONVERSION = NO; + GCC_WARN_UNUSED_VARIABLE = YES; + ONLY_ACTIVE_ARCH = YES; + "PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = 1; + VALID_ARCHS = "$(ARCHS_STANDARD)"; + WARNING_LDFLAGS = "-no_arch_warnings"; + }; + name = Debug; + }; + C01FCF5008A954540054247B /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = E41D3ED613B38FB500A75A5D /* Project.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = YES; + CLANG_CXX_LIBRARY = "libc++"; + CODE_SIGN_IDENTITY = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphonesimulator*]" = ""; + COMPRESS_PNG_FILES = NO; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; + GCC_OPTIMIZATION_LEVEL = s; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_THUMB_SUPPORT = NO; + "GCC_WARN_64_TO_32_BIT_CONVERSION[arch=*64]" = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + ONLY_ACTIVE_ARCH = NO; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = 1; + VALID_ARCHS = "$(ARCHS_STANDARD)"; + WARNING_LDFLAGS = "-no_arch_warnings"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "emptyExample" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1D6058940D05DD3E006BFB54 /* Debug */, + 1D6058950D05DD3E006BFB54 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + C01FCF4E08A954540054247B /* Build configuration list for PBXProject "emptyExample" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C01FCF4F08A954540054247B /* Debug */, + C01FCF5008A954540054247B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; }