summaryrefslogtreecommitdiffstats
path: root/Common/NativeApp/Apple/Source/Classes
diff options
context:
space:
mode:
authorEgor Yusov <egor.yusov@gmail.com>2019-03-30 18:52:35 +0000
committerEgor Yusov <egor.yusov@gmail.com>2019-03-30 18:52:35 +0000
commit2992642a3ca94bf52b066eed18bcc1df631ec67e (patch)
tree6bdc4fd27c0d83245a3b43d9086cc1d1d9bd7be2 /Common/NativeApp/Apple/Source/Classes
parentUpdated core & native app cmake (diff)
downloadDiligentEngine-2992642a3ca94bf52b066eed18bcc1df631ec67e.tar.gz
DiligentEngine-2992642a3ca94bf52b066eed18bcc1df631ec67e.zip
Enabled Vulkan mode on iOS (close https://github.com/DiligentGraphics/DiligentCore/issues/46)
Diffstat (limited to 'Common/NativeApp/Apple/Source/Classes')
-rw-r--r--Common/NativeApp/Apple/Source/Classes/iOS/AppDelegate.h3
-rw-r--r--Common/NativeApp/Apple/Source/Classes/iOS/AppDelegate.m27
-rw-r--r--Common/NativeApp/Apple/Source/Classes/iOS/AppViewBase.h16
-rw-r--r--Common/NativeApp/Apple/Source/Classes/iOS/AppViewBase.m166
-rw-r--r--Common/NativeApp/Apple/Source/Classes/iOS/BaseView.h12
-rw-r--r--Common/NativeApp/Apple/Source/Classes/iOS/BaseView.m21
-rw-r--r--Common/NativeApp/Apple/Source/Classes/iOS/EAGLView.h11
-rw-r--r--Common/NativeApp/Apple/Source/Classes/iOS/EAGLView.m157
-rw-r--r--Common/NativeApp/Apple/Source/Classes/iOS/MetalView.h7
-rw-r--r--Common/NativeApp/Apple/Source/Classes/iOS/MetalView.m39
-rw-r--r--Common/NativeApp/Apple/Source/Classes/iOS/ModeSelectionViewController.h29
-rw-r--r--Common/NativeApp/Apple/Source/Classes/iOS/ModeSelectionViewController.mm64
12 files changed, 383 insertions, 169 deletions
diff --git a/Common/NativeApp/Apple/Source/Classes/iOS/AppDelegate.h b/Common/NativeApp/Apple/Source/Classes/iOS/AppDelegate.h
index bbb1f04..3839faa 100644
--- a/Common/NativeApp/Apple/Source/Classes/iOS/AppDelegate.h
+++ b/Common/NativeApp/Apple/Source/Classes/iOS/AppDelegate.h
@@ -9,9 +9,6 @@
#import <UIKit/UIKit.h>
-@class EAGLView;
-@class MainViewController;
-
@interface AppDelegate : NSObject <UIApplicationDelegate> {
}
diff --git a/Common/NativeApp/Apple/Source/Classes/iOS/AppDelegate.m b/Common/NativeApp/Apple/Source/Classes/iOS/AppDelegate.m
index 6aa6648..5e1745c 100644
--- a/Common/NativeApp/Apple/Source/Classes/iOS/AppDelegate.m
+++ b/Common/NativeApp/Apple/Source/Classes/iOS/AppDelegate.m
@@ -7,7 +7,7 @@
*/
#import "AppDelegate.h"
-#import "EAGLView.h"
+#import "BaseView.h"
@implementation AppDelegate
@@ -15,19 +15,12 @@
#pragma mark Application lifecycle
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
-{
+{
// Override point for customization after application launch.
-
+
[self.window makeKeyAndVisible];
-
- NSString *error = [(EAGLView*)self.window.rootViewController.view getError];
- if(error != nil)
- {
- UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Failed to start the application" message:error delegate:self cancelButtonTitle:@"OK" otherButtonTitles:@"Whatever", nil];
- [alert show];
- }
- [(EAGLView*)self.window.rootViewController.view startAnimation];
+ [(BaseView*)self.window.rootViewController.view startAnimation];
return YES;
}
@@ -40,7 +33,7 @@
Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
*/
- [(EAGLView*)self.window.rootViewController.view stopAnimation];
+ [(BaseView*)self.window.rootViewController.view stopAnimation];
}
@@ -50,7 +43,7 @@
If your application supports background execution, called instead of applicationWillTerminate: when the user quits.
*/
- [(EAGLView*)self.window.rootViewController.view stopAnimation];
+ [(BaseView*)self.window.rootViewController.view stopAnimation];
}
@@ -59,7 +52,7 @@
Called as part of transition from the background to the inactive state: here you can undo many of the changes made on entering the background.
*/
- [(EAGLView*)self.window.rootViewController.view startAnimation];
+ [(BaseView*)self.window.rootViewController.view startAnimation];
}
@@ -69,7 +62,7 @@
Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
*/
- [(EAGLView*)self.window.rootViewController.view startAnimation];
+ [(BaseView*)self.window.rootViewController.view startAnimation];
}
@@ -79,8 +72,8 @@
See also applicationDidEnterBackground:.
*/
- [(EAGLView*)self.window.rootViewController.view stopAnimation];
- [(EAGLView*)self.window.rootViewController.view terminate];
+ [(BaseView*)self.window.rootViewController.view stopAnimation];
+ [(BaseView*)self.window.rootViewController.view terminate];
}
diff --git a/Common/NativeApp/Apple/Source/Classes/iOS/AppViewBase.h b/Common/NativeApp/Apple/Source/Classes/iOS/AppViewBase.h
new file mode 100644
index 0000000..e6273e9
--- /dev/null
+++ b/Common/NativeApp/Apple/Source/Classes/iOS/AppViewBase.h
@@ -0,0 +1,16 @@
+
+#import <UIKit/UIKit.h>
+#import "BaseView.h"
+
+@interface AppViewBase : BaseView
+
+@property (nonatomic) NSInteger animationFrameInterval;
+
+- (void) initApp:(int)deviceType;
+- (void) startAnimation;
+- (void) stopAnimation;
+- (void) terminate;
+- (void) render;
+- (NSString*)getError;
+
+@end
diff --git a/Common/NativeApp/Apple/Source/Classes/iOS/AppViewBase.m b/Common/NativeApp/Apple/Source/Classes/iOS/AppViewBase.m
new file mode 100644
index 0000000..e7d4c57
--- /dev/null
+++ b/Common/NativeApp/Apple/Source/Classes/iOS/AppViewBase.m
@@ -0,0 +1,166 @@
+
+#import "AppViewBase.h"
+
+#include "NativeAppBase.h"
+#include <memory>
+#include <string>
+
+@interface AppViewBase ()
+{
+ std::unique_ptr<Diligent::NativeAppBase> _theApp;
+ NSInteger _animationFrameInterval;
+ CADisplayLink* _displayLink;
+ std::string _error;
+}
+@end
+
+@implementation AppViewBase
+
+- (void) initApp:(int)deviceType;
+{
+ try
+ {
+ _theApp.reset(Diligent::CreateApplication());
+ // Init our renderer.
+ _theApp->Initialize(deviceType, (__bridge void*)self.layer);
+ }
+ catch(std::runtime_error &err)
+ {
+ _error = err.what();
+ _theApp.reset();
+ }
+
+ [super stopAnimation];
+ _animationFrameInterval = 1;
+ _displayLink = nil;
+}
+
+- (void) render
+{
+ if(_theApp)
+ {
+ _theApp->Update();
+ _theApp->Render();
+ _theApp->Present();
+ }
+}
+
+- (void) layoutSubviews
+{
+ auto bounds = [self.layer bounds];
+ auto scale = [self.layer contentsScale];
+
+ if(_theApp)
+ {
+ _theApp->WindowResize(bounds.size.width * scale, bounds.size.height * scale);
+ }
+}
+
+- (NSInteger) animationFrameInterval
+{
+ return _animationFrameInterval;
+}
+
+- (void) setAnimationFrameInterval:(NSInteger)frameInterval
+{
+ // Frame interval defines how many display frames must pass between each time the
+ // display link fires. The display link will only fire 30 times a second when the
+ // frame internal is two on a display that refreshes 60 times a second. The default
+ // frame interval setting of one will fire 60 times a second when the display refreshes
+ // at 60 times a second. A frame interval setting of less than one results in undefined
+ // behavior.
+ if (frameInterval >= 1)
+ {
+ _animationFrameInterval = frameInterval;
+
+ if (self.animating)
+ {
+ [self stopAnimation];
+ [self startAnimation];
+ }
+ }
+}
+
+- (void) startAnimation
+{
+ if (!self.animating)
+ {
+ // Create the display link and set the callback to our drawView method
+ _displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(drawView:)];
+
+ // Set it to our _animationFrameInterval
+ [_displayLink setFrameInterval:_animationFrameInterval];
+
+ // Have the display link run on the default runn loop (and the main thread)
+ [_displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
+
+ [super startAnimation];
+ }
+}
+
+- (void)stopAnimation
+{
+ if (self.animating)
+ {
+ [_displayLink invalidate];
+ _displayLink = nil;
+ [super stopAnimation];
+ }
+}
+
+- (void)terminate
+{
+ _theApp.reset();
+ [super terminate];
+}
+
+- (NSString*)getError
+{
+ return _error.empty() ? nil : [NSString stringWithFormat:@"%s", _error.c_str()];
+}
+
+- (void)touchesBegan:(NSSet<UITouch *> *)touches
+ withEvent:(UIEvent *)event;
+{
+ UITouch *firstTouch = touches.allObjects[0];
+ CGPoint location = [firstTouch locationInView:self];
+ if(_theApp)
+ {
+ _theApp->OnTouchBegan(location.x, location.y);
+ }
+}
+
+- (void)touchesMoved:(NSSet<UITouch *> *)touches
+ withEvent:(UIEvent *)event;
+{
+ UITouch *firstTouch = touches.allObjects[0];
+ CGPoint location = [firstTouch locationInView:self];
+ if(_theApp)
+ {
+ _theApp->OnTouchMoved(location.x, location.y);
+ }
+}
+
+- (void)touchesEnded:(NSSet<UITouch *> *)touches
+ withEvent:(UIEvent *)event;
+{
+ UITouch *firstTouch = touches.allObjects[0];
+ CGPoint location = [firstTouch locationInView:self];
+ if(_theApp)
+ {
+ _theApp->OnTouchEnded(location.x, location.y);
+ }
+}
+
+- (void)touchesCancelled:(NSSet<UITouch *> *)touches
+ withEvent:(UIEvent *)event;
+{
+ UITouch *firstTouch = touches.allObjects[0];
+ CGPoint location = [firstTouch locationInView:self];
+ if(_theApp)
+ {
+ _theApp->OnTouchEnded(location.x, location.y);
+ }
+}
+
+@end
diff --git a/Common/NativeApp/Apple/Source/Classes/iOS/BaseView.h b/Common/NativeApp/Apple/Source/Classes/iOS/BaseView.h
new file mode 100644
index 0000000..9e8b99e
--- /dev/null
+++ b/Common/NativeApp/Apple/Source/Classes/iOS/BaseView.h
@@ -0,0 +1,12 @@
+
+#import <UIKit/UIKit.h>
+
+@interface BaseView : UIView
+
+@property (readonly, nonatomic, getter=isAnimating) BOOL animating;
+
+- (void) startAnimation;
+- (void) stopAnimation;
+- (void) terminate;
+
+@end
diff --git a/Common/NativeApp/Apple/Source/Classes/iOS/BaseView.m b/Common/NativeApp/Apple/Source/Classes/iOS/BaseView.m
new file mode 100644
index 0000000..c87e5cd
--- /dev/null
+++ b/Common/NativeApp/Apple/Source/Classes/iOS/BaseView.m
@@ -0,0 +1,21 @@
+
+#import "BaseView.h"
+
+@implementation BaseView
+
+- (void) startAnimation
+{
+ _animating = TRUE;
+}
+
+- (void)stopAnimation
+{
+ _animating = FALSE;
+}
+
+- (void) terminate
+{
+
+}
+
+@end
diff --git a/Common/NativeApp/Apple/Source/Classes/iOS/EAGLView.h b/Common/NativeApp/Apple/Source/Classes/iOS/EAGLView.h
index fd6b9b9..e5ba68a 100644
--- a/Common/NativeApp/Apple/Source/Classes/iOS/EAGLView.h
+++ b/Common/NativeApp/Apple/Source/Classes/iOS/EAGLView.h
@@ -6,20 +6,13 @@
The EAGLView class is a UIView subclass that renders OpenGL scene.
*/
-#import <UIKit/UIKit.h>
+#import "AppViewBase.h"
// This class wraps the CAEAGLLayer from CoreAnimation into a convenient UIView subclass.
// The view content is basically an EAGL surface you render your OpenGL scene into.
// Note that setting the view non-opaque will only work if the EAGL surface has an alpha channel.
-@interface EAGLView : UIView
+@interface EAGLView : AppViewBase
-@property (readonly, nonatomic, getter=isAnimating) BOOL animating;
-@property (nonatomic) NSInteger animationFrameInterval;
-
-- (void) startAnimation;
-- (void) stopAnimation;
-- (void) terminate;
- (void) drawView:(id)sender;
-- (NSString*)getError;
@end
diff --git a/Common/NativeApp/Apple/Source/Classes/iOS/EAGLView.m b/Common/NativeApp/Apple/Source/Classes/iOS/EAGLView.m
index 9120e99..ff02820 100644
--- a/Common/NativeApp/Apple/Source/Classes/iOS/EAGLView.m
+++ b/Common/NativeApp/Apple/Source/Classes/iOS/EAGLView.m
@@ -8,17 +8,11 @@
#import "EAGLView.h"
-#include "NativeAppBase.h"
-#include <memory>
-#include <string>
+#include "DeviceCaps.h"
@interface EAGLView ()
{
- std::unique_ptr<Diligent::NativeAppBase> _theApp;
EAGLContext* _context;
- NSInteger _animationFrameInterval;
- CADisplayLink* _displayLink;
- std::string _error;
}
@end
@@ -32,166 +26,49 @@
// The GL view is stored in the storyboard file. When it's unarchived it's sent -initWithCoder:
- (instancetype) initWithCoder:(NSCoder*)coder
-{
+{
if ((self = [super initWithCoder:coder]))
{
// Get the layer
CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer;
-
+
eaglLayer.opaque = TRUE;
eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:FALSE], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil];
-
-
+
_context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
-
+
if (!_context || ![EAGLContext setCurrentContext:_context])
{
return nil;
}
-
- try
- {
- _theApp.reset(Diligent::CreateApplication());
- // Init our renderer.
- _theApp->OnGLContextCreated((__bridge void*)self.layer);
- }
- catch(std::runtime_error &err)
- {
- _error = err.what();
- _theApp.reset();
- }
-
- _animating = FALSE;
- _animationFrameInterval = 1;
- _displayLink = nil;
+
+ [self initApp:(int)Diligent::DeviceType::OpenGLES];
}
-
+
return self;
}
- (void) drawView:(id)sender
-{
- [EAGLContext setCurrentContext:_context];
- if(_theApp)
+{
+ [EAGLContext setCurrentContext:_context];
+
+ // There is no autorelease pool when this method is called
+ // because it will be called from a background thread.
+ // It's important to create one or app can leak objects.
+ @autoreleasepool
{
- _theApp->Update();
- _theApp->Render();
- _theApp->Present();
+ [self render];
}
}
-- (void) layoutSubviews
-{
- if(_theApp)
- _theApp->WindowResize(0, 0);
- [self drawView:nil];
-}
-
-- (NSInteger) animationFrameInterval
-{
- return _animationFrameInterval;
-}
-
-- (void) setAnimationFrameInterval:(NSInteger)frameInterval
-{
- // Frame interval defines how many display frames must pass between each time the
- // display link fires. The display link will only fire 30 times a second when the
- // frame internal is two on a display that refreshes 60 times a second. The default
- // frame interval setting of one will fire 60 times a second when the display refreshes
- // at 60 times a second. A frame interval setting of less than one results in undefined
- // behavior.
- if (frameInterval >= 1)
- {
- _animationFrameInterval = frameInterval;
-
- if (_animating)
- {
- [self stopAnimation];
- [self startAnimation];
- }
- }
-}
-
-- (void) startAnimation
-{
- if (!_animating)
- {
- // Create the display link and set the callback to our drawView method
- _displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(drawView:)];
-
- // Set it to our _animationFrameInterval
- [_displayLink setFrameInterval:_animationFrameInterval];
-
- // Have the display link run on the default runn loop (and the main thread)
- [_displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
-
- _animating = TRUE;
- }
-}
-
-- (void)stopAnimation
-{
- if (_animating)
- {
- [_displayLink invalidate];
- _displayLink = nil;
- _animating = FALSE;
- }
-}
-
-- (void)terminate
-{
- _theApp.reset();
-}
-
- (void) dealloc
{
[self terminate];
// tear down context
- if ([EAGLContext currentContext] == _context)
+ if ([EAGLContext currentContext] == _context)
[EAGLContext setCurrentContext:nil];
}
-- (NSString*)getError
-{
- return _error.empty() ? nil : [NSString stringWithFormat:@"%s", _error.c_str()];
-}
-
-- (void)touchesBegan:(NSSet<UITouch *> *)touches
- withEvent:(UIEvent *)event;
-{
- UITouch *firstTouch = touches.allObjects[0];
- CGPoint location = [firstTouch locationInView:self];
- if(_theApp)
- _theApp->OnTouchBegan(location.x, location.y);
-}
-
-- (void)touchesMoved:(NSSet<UITouch *> *)touches
- withEvent:(UIEvent *)event;
-{
- UITouch *firstTouch = touches.allObjects[0];
- CGPoint location = [firstTouch locationInView:self];
- if(_theApp)
- _theApp->OnTouchMoved(location.x, location.y);
-}
-
-- (void)touchesEnded:(NSSet<UITouch *> *)touches
- withEvent:(UIEvent *)event;
-{
- UITouch *firstTouch = touches.allObjects[0];
- CGPoint location = [firstTouch locationInView:self];
- if(_theApp)
- _theApp->OnTouchEnded(location.x, location.y);}
-
-- (void)touchesCancelled:(NSSet<UITouch *> *)touches
- withEvent:(UIEvent *)event;
-{
- UITouch *firstTouch = touches.allObjects[0];
- CGPoint location = [firstTouch locationInView:self];
- if(_theApp)
- _theApp->OnTouchEnded(location.x, location.y);
-}
-
@end
diff --git a/Common/NativeApp/Apple/Source/Classes/iOS/MetalView.h b/Common/NativeApp/Apple/Source/Classes/iOS/MetalView.h
new file mode 100644
index 0000000..a485b27
--- /dev/null
+++ b/Common/NativeApp/Apple/Source/Classes/iOS/MetalView.h
@@ -0,0 +1,7 @@
+#import "AppViewBase.h"
+
+@interface MetalView : AppViewBase
+
+- (void) drawView:(id)sender;
+
+@end
diff --git a/Common/NativeApp/Apple/Source/Classes/iOS/MetalView.m b/Common/NativeApp/Apple/Source/Classes/iOS/MetalView.m
new file mode 100644
index 0000000..3c8b198
--- /dev/null
+++ b/Common/NativeApp/Apple/Source/Classes/iOS/MetalView.m
@@ -0,0 +1,39 @@
+#import "MetalView.h"
+#import <QuartzCore/CAMetalLayer.h>
+
+#include "DeviceCaps.h"
+
+@implementation MetalView
+
++ (Class) layerClass
+{
+ return [CAMetalLayer class];
+}
+
+- (instancetype) initWithCoder:(NSCoder*)coder
+{
+ if ((self = [super initWithCoder:coder]))
+ {
+ [self initApp:(int)Diligent::DeviceType::Vulkan];
+ }
+
+ return self;
+}
+
+- (void) drawView:(id)sender
+{
+ // There is no autorelease pool when this method is called
+ // because it will be called from a background thread.
+ // It's important to create one or app can leak objects.
+ @autoreleasepool
+ {
+ [self render];
+ }
+}
+
+- (void) dealloc
+{
+ [self terminate];
+}
+
+@end
diff --git a/Common/NativeApp/Apple/Source/Classes/iOS/ModeSelectionViewController.h b/Common/NativeApp/Apple/Source/Classes/iOS/ModeSelectionViewController.h
new file mode 100644
index 0000000..4a08d7d
--- /dev/null
+++ b/Common/NativeApp/Apple/Source/Classes/iOS/ModeSelectionViewController.h
@@ -0,0 +1,29 @@
+/* Copyright 2015-2019 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#import <UIKit/UIKit.h>
+
+@interface ModeSelectionViewController : UIViewController
+{
+}
+@end
diff --git a/Common/NativeApp/Apple/Source/Classes/iOS/ModeSelectionViewController.mm b/Common/NativeApp/Apple/Source/Classes/iOS/ModeSelectionViewController.mm
new file mode 100644
index 0000000..8958c10
--- /dev/null
+++ b/Common/NativeApp/Apple/Source/Classes/iOS/ModeSelectionViewController.mm
@@ -0,0 +1,64 @@
+/* Copyright 2015-2019 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#import "ModeSelectionViewController.h"
+#import "BaseView.h"
+#import "AppViewBase.h"
+
+@implementation ModeSelectionViewController
+{
+}
+
+-(void)selectViewController:(NSString*)controllerID
+{
+ auto animating = ((BaseView*)self.view).animating;
+
+ UIViewController* viewController = [self.storyboard instantiateViewControllerWithIdentifier:controllerID];
+ self.view.window.rootViewController = viewController;
+
+ NSString *error = [(AppViewBase*)viewController.view getError];
+ if(error != nil)
+ {
+ UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Failed to start the application" message:error delegate:self cancelButtonTitle:@"OK" otherButtonTitles:@"Whatever", nil];
+ [alert show];
+ }
+
+ if(animating)
+ {
+ [(BaseView*)viewController.view startAnimation];
+ }
+}
+
+- (IBAction)goOpenGLES:(id)sender
+{
+ [self selectViewController:@"EAGLViewControllerID"];
+}
+
+- (IBAction)goVulkan:(id)sender
+{
+#if VULKAN_SUPPORTED
+ [self selectViewController:@"MetalViewControllerID"];
+#endif
+}
+
+@end