diff --git a/base/keycodes.hpp b/base/keycodes.hpp index c91390e1..e3527b89 100644 --- a/base/keycodes.hpp +++ b/base/keycodes.hpp @@ -53,12 +53,38 @@ #define KEY_O 0xF #define KEY_T 0x10 -#elif (defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK)) -#define KEY_ESCAPE 0x35 -#define KEY_F1 0x7A -#define KEY_F2 0x78 -#define KEY_F3 0x63 -#define KEY_F4 0x76 +#elif defined(VK_USE_PLATFORM_IOS_MVK) +// Use numeric keys instead of function keys. +// Use Delete key instead of Escape key. +#define KEY_ESCAPE 0x33 +#define KEY_F1 '1' +#define KEY_F2 '2' +#define KEY_F3 '3' +#define KEY_F4 '4' +#define KEY_W 'w' +#define KEY_A 'a' +#define KEY_S 's' +#define KEY_D 'd' +#define KEY_P 'p' +#define KEY_SPACE ' ' +#define KEY_KPADD '+' +#define KEY_KPSUB '-' +#define KEY_B 'b' +#define KEY_F 'f' +#define KEY_L 'l' +#define KEY_N 'n' +#define KEY_O 'o' +#define KEY_T 't' + +#elif defined(VK_USE_PLATFORM_MACOS_MVK) +// For iOS UX compatibility: +// - Use numeric keys instead of function keys +// - Use Delete key instead of Escape key +#define KEY_ESCAPE 0x33 +#define KEY_F1 0x12 +#define KEY_F2 0x13 +#define KEY_F3 0x14 +#define KEY_F4 0x15 #define KEY_W 0x0D #define KEY_A 0x00 #define KEY_S 0x01 diff --git a/xcode/README_MoltenVK_Examples.md b/xcode/README_MoltenVK_Examples.md index a1bcc38c..6ce5d8dd 100755 --- a/xcode/README_MoltenVK_Examples.md +++ b/xcode/README_MoltenVK_Examples.md @@ -61,4 +61,11 @@ in this repository on either *iOS* or *macOS*. To do so, follow these instructio 3. Run either the `examples-iOS` or `examples-macOS` *Xcode Scheme* to run the example in *iOS* or *macOS*, repectively. + +4. Many of the examples include an option to press keys to control the display of features + and scene components: + + - On *iOS*, tap on the scene to display the keyboard. Tap again on the scene to hide the keyboard. + - On both *iOS* and *macOS*, use the numeric keys (*1, 2, 3...*) instead of function keys (*F1, F2, F3...*). + - On both *iOS* and *macOS*, use the *delete* key instead of the *escape* key. diff --git a/xcode/examples.h b/xcode/examples.h index e7fc8ff9..200c1bb1 100644 --- a/xcode/examples.h +++ b/xcode/examples.h @@ -19,7 +19,7 @@ * * For example, to run the pipelines example, you would add the MVK_pipelines define macro * to the Preprocessor Macros (aka GCC_PREPROCESSOR_DEFINITIONS) entry of the Xcode project, - * overwriting any other value there. + * overwriting any otheor value there. * * If you choose to add a #define statement to this file, be sure to clear the existing macro * from the Preprocessor Macros (aka GCC_PREPROCESSOR_DEFINITIONS) compiler setting in Xcode. @@ -36,7 +36,7 @@ # include "../pipelines/pipelines.cpp" #endif -#ifdef MVK_texture // inverse() function not available in MSL +#ifdef MVK_texture # include "../texture/texture.cpp" #endif @@ -64,19 +64,19 @@ # include "../specializationconstants/specializationconstants.cpp" #endif -#ifdef MVK_offscreen +#ifdef MVK_offscreen // Bad access on iOS # include "../offscreen/offscreen.cpp" #endif -#ifdef MVK_radialblur // Runs but textureSize() function not available in MSL +#ifdef MVK_radialblur # include "../radialblur/radialblur.cpp" #endif -#ifdef MVK_textoverlay // inverse() function not available in MSL +#ifdef MVK_textoverlay # include "../textoverlay/textoverlay.cpp" #endif -#ifdef MVK_particlefire // Runs but inversesqrt() function not available in MSL +#ifdef MVK_particlefire # include "../particlefire/particlefire.cpp" #endif @@ -87,11 +87,11 @@ # include "../multithreading/multithreading.cpp" #endif -#ifdef MVK_scenerendering +#ifdef MVK_scenerendering // Bad access on macOS # include "../scenerendering/scenerendering.cpp" #endif -#ifdef MVK_instancing // inverse() function not available in MSL +#ifdef MVK_instancing # include "../instancing/instancing.cpp" #endif @@ -107,31 +107,31 @@ # include "../occlusionquery/occlusionquery.cpp" #endif -#ifdef MVK_texturemipmapgen // inverse() function not available in MSL + SPIRV->MSL conversion error +#ifdef MVK_texturemipmapgen // SPIRV->GLSL conversion error # include "../texturemipmapgen/texturemipmapgen.cpp" #endif -#ifdef MVK_multisampling +#ifdef MVK_multisampling // Multisampling too low on iOS # include "../multisampling/multisampling.cpp" #endif -#ifdef MVK_shadowmapping // textureSize() function not available in MSL +#ifdef MVK_shadowmapping // Bad access on iOS # include "../shadowmapping/shadowmapping.cpp" #endif -#ifdef MVK_shadowmappingomni +#ifdef MVK_shadowmappingomni // Bad access on iOS # include "../shadowmappingomni/shadowmappingomni.cpp" #endif -#ifdef MVK_skeletalanimation // inverse() function not available in MSL +#ifdef MVK_skeletalanimation // Bad access on macOS # include "../skeletalanimation/skeletalanimation.cpp" #endif -#ifdef MVK_bloom // Runs but textureSize() function not available in MSL +#ifdef MVK_bloom // Bad access on iOS # include "../bloom/bloom.cpp" #endif -#ifdef MVK_deferred // inverse() function not available in MSL +#ifdef MVK_deferred // buffer overload # include "../deferred/deferred.cpp" #endif @@ -170,7 +170,7 @@ # include "../gears/gears.cpp" #endif -#ifdef MVK_distancefieldfonts +#ifdef MVK_distancefieldfonts // Endless loop during loading on macOS # include "../distancefieldfonts/distancefieldfonts.cpp" #endif diff --git a/xcode/examples.xcodeproj/project.pbxproj b/xcode/examples.xcodeproj/project.pbxproj index 3fe138d8..6b04cd40 100644 --- a/xcode/examples.xcodeproj/project.pbxproj +++ b/xcode/examples.xcodeproj/project.pbxproj @@ -348,6 +348,9 @@ attributes = { LastUpgradeCheck = 0820; TargetAttributes = { + 1D6058900D05DD3D006BFB54 = { + DevelopmentTeam = VU3TCKU48B; + }; A977BCBD1B66BB010067E5BF = { DevelopmentTeam = VU3TCKU48B; }; @@ -434,7 +437,7 @@ isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_IDENTITY = "iPhone Developer"; - DEVELOPMENT_TEAM = ""; + DEVELOPMENT_TEAM = VU3TCKU48B; FRAMEWORK_SEARCH_PATHS = "\"$(SRCROOT)/MoltenVK/iOS\""; GCC_PREFIX_HEADER = "$(SRCROOT)/iOS/Prefix.pch"; GCC_PREPROCESSOR_DEFINITIONS = ( @@ -457,7 +460,7 @@ isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_IDENTITY = "iPhone Developer"; - DEVELOPMENT_TEAM = ""; + DEVELOPMENT_TEAM = VU3TCKU48B; FRAMEWORK_SEARCH_PATHS = "\"$(SRCROOT)/MoltenVK/iOS\""; GCC_PREFIX_HEADER = "$(SRCROOT)/iOS/Prefix.pch"; GCC_PREPROCESSOR_DEFINITIONS = ( @@ -531,7 +534,7 @@ GCC_C_LANGUAGE_STANDARD = c99; GCC_OPTIMIZATION_LEVEL = 0; GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREPROCESSOR_DEFINITIONS = MVK_vulkanscene; + GCC_PREPROCESSOR_DEFINITIONS = MVK_skeletalanimation; GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; GCC_WARN_ABOUT_RETURN_TYPE = YES; @@ -555,7 +558,7 @@ ENABLE_BITCODE = NO; GCC_C_LANGUAGE_STANDARD = c99; GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREPROCESSOR_DEFINITIONS = MVK_vulkanscene; + GCC_PREPROCESSOR_DEFINITIONS = MVK_skeletalanimation; GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; GCC_WARN_ABOUT_RETURN_TYPE = YES; diff --git a/xcode/ios/DemoViewController.h b/xcode/ios/DemoViewController.h index 48e3d255..dbea6c5c 100644 --- a/xcode/ios/DemoViewController.h +++ b/xcode/ios/DemoViewController.h @@ -19,7 +19,7 @@ #pragma mark DemoViewController /** The main view controller for the demo storyboard. */ -@interface DemoViewController : UIViewController +@interface DemoViewController : UIViewController @end diff --git a/xcode/ios/DemoViewController.mm b/xcode/ios/DemoViewController.mm index 7f705561..386a6c75 100644 --- a/xcode/ios/DemoViewController.mm +++ b/xcode/ios/DemoViewController.mm @@ -21,12 +21,15 @@ const std::string VulkanExampleBase::getAssetPath() { @implementation DemoViewController { VulkanExample* _vulkanExample; CADisplayLink* _displayLink; + BOOL _viewHasAppeared; } /** Since this is a single-view app, init Vulkan when the view is loaded. */ -(void) viewDidLoad { [super viewDidLoad]; + self.view.contentScaleFactor = UIScreen.mainScreen.nativeScale; + _vulkanExample = new VulkanExample(); _vulkanExample->initVulkan(); _vulkanExample->setupWindow(self.view); @@ -37,8 +40,24 @@ const std::string VulkanExampleBase::getAssetPath() { _displayLink = [CADisplayLink displayLinkWithTarget: self selector: @selector(renderFrame)]; [_displayLink setFrameInterval: 60 / fps]; [_displayLink addToRunLoop: NSRunLoop.currentRunLoop forMode: NSDefaultRunLoopMode]; + + // Setup tap gesture to toggle virtual keyboard + UITapGestureRecognizer* tapSelector = [[UITapGestureRecognizer alloc] + initWithTarget: self action: @selector(handleTapGesture:)]; + tapSelector.numberOfTapsRequired = 1; + tapSelector.cancelsTouchesInView = YES; + [self.view addGestureRecognizer: tapSelector]; + + _viewHasAppeared = NO; } +-(void) viewDidAppear: (BOOL) animated { + [super viewDidAppear: animated]; + _viewHasAppeared = YES; +} + +-(BOOL) canBecomeFirstResponder { return _viewHasAppeared; } + -(void) renderFrame { _vulkanExample->renderFrame(); } @@ -48,6 +67,45 @@ const std::string VulkanExampleBase::getAssetPath() { [super dealloc]; } +// Toggle the display of the virtual keyboard +-(void) toggleKeyboard { + if (self.isFirstResponder) { + [self resignFirstResponder]; + } else { + [self becomeFirstResponder]; + } +} + +// Display and hide the keyboard by tapping on the view +-(void) handleTapGesture: (UITapGestureRecognizer*) gestureRecognizer { + if (gestureRecognizer.state == UIGestureRecognizerStateEnded) { + [self toggleKeyboard]; + } +} + +// Handle keyboard input +-(void) handleKeyboardInput: (unichar) keycode { + _vulkanExample->keyPressed(keycode); +} + + +#pragma mark UIKeyInput methods + +// Returns whether text is available +-(BOOL) hasText { return YES; } + +// A key on the keyboard has been pressed. +-(void) insertText: (NSString*) text { + unichar keycode = (text.length > 0) ? [text characterAtIndex: 0] : 0; + [self handleKeyboardInput: keycode]; +} + +// The delete backward key has been pressed. +-(void) deleteBackward { + [self handleKeyboardInput: 0x33]; +} + + @end diff --git a/xcode/macos/DemoViewController.mm b/xcode/macos/DemoViewController.mm index 4204848a..373a4979 100644 --- a/xcode/macos/DemoViewController.mm +++ b/xcode/macos/DemoViewController.mm @@ -52,24 +52,17 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, CVDisplayLinkStart(_displayLink); } -/** Resize the window to fit the size of the content as set by the sample code. */ --(void) viewWillAppear { - [super viewWillAppear]; - - CGSize vSz = self.view.bounds.size; - NSWindow *window = self.view.window; - NSRect wFrm = [window contentRectForFrameRect: window.frame]; - NSRect newWFrm = [window frameRectForContentRect: NSMakeRect(wFrm.origin.x, wFrm.origin.y, vSz.width, vSz.height)]; - [window setFrame: newWFrm display: YES animate: window.isVisible]; - [window center]; -} - -(void) dealloc { CVDisplayLinkRelease(_displayLink); delete(_vulkanExample); [super dealloc]; } +// Handle keyboard input +-(void) keyDown:(NSEvent*) theEvent { + _vulkanExample->keyPressed(theEvent.keyCode); +} + @end @@ -85,6 +78,13 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, +(Class) layerClass { return [CAMetalLayer class]; } /** If the wantsLayer property is set to YES, this method will be invoked to return a layer instance. */ --(CALayer*) makeBackingLayer { return [self.class.layerClass layer]; } +-(CALayer*) makeBackingLayer { + CALayer* layer = [self.class.layerClass layer]; + CGSize viewScale = [self convertSizeToBacking: CGSizeMake(1.0, 1.0)]; + layer.contentsScale = MIN(viewScale.width, viewScale.height); + return layer; +} + +-(BOOL) acceptsFirstResponder { return YES; } @end