diff --git a/include/vsg/platform/ios/iOS_ViewController.h b/include/vsg/platform/ios/iOS_ViewController.h new file mode 100644 index 0000000000..10f1b9805c --- /dev/null +++ b/include/vsg/platform/ios/iOS_ViewController.h @@ -0,0 +1,19 @@ +#include + + +#include +#include + +#pragma mark - +#pragma mark vsg_iOS_View +@interface vsg_iOS_View : UIView +@end + + +#pragma mark - +#pragma mark vsg_iOS_ViewController +@interface vsg_iOS_ViewController : UIViewController + @property vsg::ref_ptr vsgWindow; + - (instancetype)initWithTraits:(vsg::ref_ptr)traits andVsgViewer:(vsg::ref_ptr) vsgViewer; +@end + diff --git a/include/vsg/platform/ios/iOS_Window.h b/include/vsg/platform/ios/iOS_Window.h new file mode 100644 index 0000000000..0e0a16fa5b --- /dev/null +++ b/include/vsg/platform/ios/iOS_Window.h @@ -0,0 +1,98 @@ +// +// vsg_iOS_ApplicationDelegate.h +// IOS_vsg_native_example +// +// Created by jaume dominguez faus on 23/5/21. +// + +#ifndef vsg_iOS_Window_h +#define vsg_iOS_Window_h + + + +#include +#include +#include +#include + +@interface vsg_iOS_Window : UIWindow +- (vsg::ref_ptr) vsgWindow; +- (instancetype)initWithTraits:(vsg::ref_ptr)traits andVsgViewer:(vsg::ref_ptr) vsgViewer; +@end + + +@class vsg_iOS_View; + +namespace vsgiOS +{ + extern vsg::Names getInstanceExtensions(); + + class KeyboardMap : public vsg::Object + { + public: + KeyboardMap(); + + using kVKKeyCodeToKeySymbolMap = std::map; + + bool getKeySymbol(UIEvent* anEvent, vsg::KeySymbol& keySymbol, vsg::KeySymbol& modifiedKeySymbol, vsg::KeyModifier& keyModifier); + + protected: + kVKKeyCodeToKeySymbolMap _keycodeMap; + }; + + + class iOS_Window : public vsg::Inherit + { + public: + + iOS_Window(vsg::ref_ptr traits); + iOS_Window() = delete; + iOS_Window(const iOS_Window&) = delete; + iOS_Window operator = (const iOS_Window&) = delete; + + const char* instanceExtensionSurfaceName() const override { return VK_EXT_METAL_SURFACE_EXTENSION_NAME; } + + bool valid() const override { return _window; } + + bool pollEvents(vsg::UIEvents& events) override; + + // bool resized() const override; + + void resize() override; + + bool handleUIEvent(UIEvent* anEvent); + + // OS native objects + vsg_iOS_Window* window() { return _window; }; + // vsg_iOS_View* view() { return _view; }; + CAMetalLayer* layer() { return _metalLayer; }; + + vsg::clock::time_point getEventTime(double eventTime) + { + long elapsedmilli = long(double(eventTime - _first_macos_timestamp) * 1000.0f); + return _first_macos_time_point + std::chrono::milliseconds(elapsedmilli); + } + + void queueEvent(vsg::UIEvent* anEvent) { _bufferedEvents.emplace_back(anEvent); } + + protected: + virtual ~iOS_Window(); + + void _initSurface() override; + + vsg_iOS_Window* _window; + vsg_iOS_View* _view; + CAMetalLayer* _metalLayer; + + double _first_macos_timestamp = 0; + vsg::clock::time_point _first_macos_time_point; + + vsg::UIEvents _bufferedEvents; + vsg::ref_ptr _keyboard; + }; + +} // namespace vsgMacOS + +EVSG_type_name(vsgiOS::iOS_Window); + +#endif /* vsg_iOS_Window_h */ diff --git a/include/vsg/viewer/Trackball.h b/include/vsg/viewer/Trackball.h index 157cd62054..3b91982191 100644 --- a/include/vsg/viewer/Trackball.h +++ b/include/vsg/viewer/Trackball.h @@ -17,6 +17,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include #include #include +#include #include #include @@ -38,8 +39,11 @@ namespace vsg void apply(ButtonReleaseEvent& buttonRelease) override; void apply(MoveEvent& moveEvent) override; void apply(ScrollWheelEvent& scrollWheel) override; + void apply(TouchDownEvent& touchDown) override; + void apply(TouchUpEvent& touchUp) override; + void apply(TouchMoveEvent& touchMove) override; void apply(FrameEvent& frame) override; - + virtual void rotate(double angle, const dvec3& axis); virtual void zoom(double ratio); virtual void pan(const dvec2& delta); diff --git a/src/vsg/CMakeLists.txt b/src/vsg/CMakeLists.txt index 35855e3110..361faf8120 100644 --- a/src/vsg/CMakeLists.txt +++ b/src/vsg/CMakeLists.txt @@ -263,6 +263,16 @@ if (ANDROID) elseif (WIN32) set(SOURCES ${SOURCES} platform/win32/Win32_Window.cpp) +elseif (IOS) + set(HEADERS ${HEADERS} + ${CMAKE_SOURCE_DIR}/include/vsg/platform/ios/iOS_Window.h + ${CMAKE_SOURCE_DIR}/include/vsg/platform/ios/iOS_ViewController.h + ) + set(SOURCES ${SOURCES} + platform/ios/iOS_Window.mm + platform/ios/iOS_ViewController.mm + ) + set(LIBRARIES ${LIBRARIES} PRIVATE ${UIKIT_LIBRARY} PRIVATE ${QUARTZCORE_LIBRARY}) elseif (APPLE) set(SOURCES ${SOURCES} platform/macos/MacOS_Window.mm) set(LIBRARIES ${LIBRARIES} PRIVATE ${COCOA_LIBRARY} PRIVATE ${QUARTZCORE_LIBRARY}) diff --git a/src/vsg/platform/ios/iOS_ViewController.mm b/src/vsg/platform/ios/iOS_ViewController.mm new file mode 100644 index 0000000000..b55499ec45 --- /dev/null +++ b/src/vsg/platform/ios/iOS_ViewController.mm @@ -0,0 +1,84 @@ +#include +#include +#include + +#pragma mark - +#pragma mark vsg_iOS_ViewController + +@implementation vsg_iOS_ViewController { + CADisplayLink* _displayLink; + vsg::ref_ptr _traits; + vsg::ref_ptr _vsgViewer; +} + +- (instancetype)initWithTraits:(vsg::ref_ptr)traits andVsgViewer:(vsg::ref_ptr) vsgViewer +{ + self = [super init]; + _traits = traits; + _vsgViewer = vsgViewer; + return self; +} + +- (void)loadView +{ + // We need to create a vsgView because doing so we ensure it has a CAMetalLayer + // otherwise it will make a view with a CALayer which is not compatible with MoltenVK. + // Also, very important to give it a size or it won't let access to any CAMetalDrawable + // which will cause a massive hang in the device forcing it to be rebooted in order + // to regain control of it. + CGRect frame; + frame.origin.x = _traits->x; + frame.origin.y = _traits->y; + frame.size.width = _traits->width <= 0 ? 1 : _traits->width; + frame.size.height = _traits->height <= 0 ? 1 : _traits->height; + vsg_iOS_View* view = [[vsg_iOS_View alloc] initWithFrame:frame]; + self.view = view; + +} + +-(void) dealloc { + _traits = nullptr; + _vsgViewer = nullptr; + _vsgWindow = nullptr; +} + + +-(void) viewDidLoad { + [super viewDidLoad]; + + self.view.contentScaleFactor = UIScreen.mainScreen.nativeScale; + uint32_t fps = 60; + _displayLink = [CADisplayLink displayLinkWithTarget: self selector: @selector(renderLoop)]; + [_displayLink setPreferredFramesPerSecond: fps]; + [_displayLink addToRunLoop: NSRunLoop.currentRunLoop forMode: NSDefaultRunLoopMode]; +} + +-(void) renderLoop { + if (self->_vsgViewer->advanceToNextFrame()) + { + self->_vsgViewer->compile(); + self->_vsgViewer->handleEvents(); + self->_vsgViewer->update(); + self->_vsgViewer->recordAndSubmit(); + self->_vsgViewer->present(); + } +} + +// Allow device rotation to resize the swapchain +-(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator { + [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; + // TODO implement this +} + +@end + + +#pragma mark - +#pragma mark vsg_iOS_View + +@implementation vsg_iOS_View + +/** Returns a Metal-compatible layer (required by Vulkan/MoltenVK. */ ++(Class) layerClass { return [CAMetalLayer class]; } + +@end diff --git a/src/vsg/platform/ios/iOS_Window.mm b/src/vsg/platform/ios/iOS_Window.mm new file mode 100644 index 0000000000..233f45404d --- /dev/null +++ b/src/vsg/platform/ios/iOS_Window.mm @@ -0,0 +1,745 @@ +#include + +/* + +Copyright(c) 2018 Robert Osfield + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +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. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + */ + + + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + +namespace vsg +{ + // Provide the Window::create(...) implementation that automatically maps to a iOS_Window + vsg::ref_ptr Window::create(vsg::ref_ptr traits) + { + return vsgiOS::iOS_Window::create(traits); + } + +} // namespace vsg + + +#pragma mark - +#pragma mark vsg_iOS_Window + + +@implementation vsg_iOS_Window +{ + vsg::ref_ptr _traits; + vsg::ref_ptr _vsgViewer; + +} + +- (instancetype)initWithTraits:(vsg::ref_ptr)traits andVsgViewer:(vsg::ref_ptr) vsgViewer +{ + _traits = traits; + _vsgViewer = vsgViewer; + CGRect frame; + frame.origin.x = _traits->x; + frame.origin.y = _traits->y; + frame.size.width = _traits->width <= 0 ? 1 : _traits->width; + frame.size.height = _traits->height <= 0 ? 1 : _traits->height; + self = [super initWithFrame:frame]; + if (self != nil) + { + vsg_iOS_ViewController* vc = [[vsg_iOS_ViewController alloc] initWithTraits: traits andVsgViewer: vsgViewer]; + self.rootViewController = vc; + } + + return self; +} + +- (void)makeKeyAndVisible +{ + [super makeKeyAndVisible]; + + vsg_iOS_Window* nWindow = self; + _traits->nativeWindow = nWindow; + + vsg::ref_ptr w = vsg::Window::create(_traits); + ((vsg_iOS_ViewController*)self.rootViewController).vsgWindow = w; + _vsgViewer->addWindow(w); +} + +- (vsg::ref_ptr)vsgWindow +{ + return ((vsg_iOS_ViewController*)self.rootViewController).vsgWindow; +} + +- (BOOL)windowShouldClose:(id)sender +{ + vsgiOS::iOS_Window* w = static_cast(self.vsgWindow.get()); + vsg::clock::time_point event_time = vsg::clock::now(); // TODO call window getEventTime()?? + w->queueEvent(new vsg::CloseWindowEvent(w, event_time)); + return NO; +} + +@end + +#pragma mark - +#pragma mark vsg_iOS_View + +@implementation vsg_iOS_View +{ + @public vsgiOS::iOS_Window* vsgWindow; + vsg::ref_ptr _traits; +} + +/** Returns a Metal-compatible layer. */ ++(Class) layerClass { return [CAMetalLayer class]; } + +- (BOOL)isOpaque +{ + return true; +} + +- (BOOL)canBecomeKeyView +{ + return YES; +} + +- (BOOL)becomeFirstResponder +{ + return YES; +} + +- (void)updateLayer +{ + +} + +- (BOOL)isMultipleTouchEnabled +{ + return YES; +} + +template +vsg::ref_ptr createTouchEvt(vsgiOS::iOS_Window* window, UIEvent* event, uint32_t in_id, float devicePixelScale) +{ + vsg::clock::time_point event_time = window->getEventTime([event timestamp]); + for (auto touch in [event allTouches]) + { + // it seems like there is always only one (TODO CHECK THAT) + auto pos = [touch locationInView:nil]; + uint32_t x = pos.x; + uint32_t y = pos.y; + return vsg::ref_ptr(new T(window, event_time, x, y, in_id)); + } + return vsg::ref_ptr(nullptr); +} + +- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event +{ + auto devicePixelScale = _traits->hdpi ? UIScreen.mainScreen.nativeScale : 1.0f; + vsgWindow->queueEvent(createTouchEvt(vsgWindow, event, 0, devicePixelScale)); +} + +- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event +{ + auto devicePixelScale = _traits->hdpi ? UIScreen.mainScreen.nativeScale : 1.0f; + vsgWindow->queueEvent(createTouchEvt(vsgWindow, event, 0, devicePixelScale)); +} + +- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event +{ + auto devicePixelScale = _traits->hdpi ? UIScreen.mainScreen.nativeScale : 1.0f; + vsgWindow->queueEvent(createTouchEvt(vsgWindow, event, 0, devicePixelScale)); +} + +- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event +{ + std::cout << "touchesCancelled" << std::endl; + // vsg::touch + vsgWindow->handleUIEvent(event); +} + +- (void)pressesBegan:(NSSet *)presses withEvent:(UIPressesEvent *)event +{ + vsgWindow->handleUIEvent(event); +} + +- (void)pressesEnded:(NSSet *)presses withEvent:(UIPressesEvent *)event +{ + vsgWindow->handleUIEvent(event); +} + +- (void)pressesChanged:(NSSet *)presses withEvent:(UIPressesEvent *)event +{ + vsgWindow->handleUIEvent(event); +} + +- (void)pressesCancelled:(NSSet *)presses withEvent:(UIPressesEvent *)event +{ + vsgWindow->handleUIEvent(event); +} + +- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event +{ + vsgWindow->handleUIEvent(event); +} + +- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event +{ + vsgWindow->handleUIEvent(event); +} + +- (void)cursorUpdate:(UIEvent *)event +{ + vsgWindow->handleUIEvent(event); +} + +- (void)mouseDown:(UIEvent *)event +{ + vsgWindow->handleUIEvent(event); +} + +- (void)mouseDragged:(UIEvent *)event +{ + vsgWindow->handleUIEvent(event); +} + +- (void)mouseUp:(UIEvent *)event +{ + vsgWindow->handleUIEvent(event); +} + +- (void)mouseMoved:(UIEvent *)event +{ + vsgWindow->handleUIEvent(event); +} +@end + + +namespace vsgiOS +{ + class iOSSurface : public vsg::Surface + { + public: + iOSSurface(vsg::Instance* instance, CAMetalLayer* caMetalLayer) + : vsg::Surface(VK_NULL_HANDLE, instance) + { + VkMetalSurfaceCreateInfoEXT surfaceCreateInfo{}; + surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT; + surfaceCreateInfo.pNext = nullptr; + surfaceCreateInfo.flags = 0; + surfaceCreateInfo.pLayer = caMetalLayer; + + auto res = vkCreateMetalSurfaceEXT(*instance, &surfaceCreateInfo, _instance->getAllocationCallbacks(), &_surface); + if (res != VK_SUCCESS || _surface == VK_NULL_HANDLE) + std::cerr << "[ERROR] Failed creating VkSurface"; + } + }; +} + +vsgiOS::iOS_Window::iOS_Window(vsg::ref_ptr traits) + : Inherit(traits) +{ + auto devicePixelScale = _traits->hdpi ? UIScreen.mainScreen.nativeScale : 1.0f; + _window = std::any_cast(traits->nativeWindow); + _view = (vsg_iOS_View*)( _window.rootViewController.view ); + _view->vsgWindow = this; + _view->_traits = _traits; + _keyboard = new KeyboardMap; + _metalLayer = (CAMetalLayer*) _view.layer; + + uint32_t finalwidth = traits->width * devicePixelScale; + uint32_t finalheight = traits->height * devicePixelScale; + + _extent2D.width = finalwidth; + _extent2D.height = finalheight; + + // manually trigger configure here?? + vsg::clock::time_point event_time = vsg::clock::now(); + _bufferedEvents.emplace_back(new vsg::ConfigureWindowEvent(this, event_time, _traits->x, _traits->y, finalwidth, finalheight)); +} + +vsgiOS::iOS_Window::~iOS_Window() +{ + clear(); +} + +void vsgiOS::iOS_Window::_initSurface() +{ + if (!_instance) _initInstance(); + + _surface = new vsgiOS::iOSSurface(_instance, _metalLayer); +} + +bool vsgiOS::iOS_Window::pollEvents(vsg::UIEvents& events) +{ +// for (;;) +// { +// NSEvent* event = [NSApp nextEventMatchingMask:NSEventMaskAny +// untilDate:[NSDate distantPast] +// inMode:NSDefaultRunLoopMode +// dequeue:YES]; +// if (event == nil) +// break; +// +// [NSApp sendEvent:event]; +// } +// + if (_bufferedEvents.size() > 0) + { + events.splice(events.end(), _bufferedEvents); + _bufferedEvents.clear(); + return true; + } + + return false; +} + +//bool vsgiOS::iOS_Window::resized() const +//{ +// const CGRect contentRect = [_view frame]; +// +// auto devicePixelScale = _traits->hdpi ? UIScreen.mainScreen.nativeScale : 1.0f; +// +// uint32_t width = contentRect.size.width * devicePixelScale; +// uint32_t height = contentRect.size.height * devicePixelScale; +// +// return (width != _extent2D.width || height != _extent2D.height); +//} + +void vsgiOS::iOS_Window::resize() +{ + const CGRect contentRect = [_view frame]; + + auto devicePixelScale = _traits->hdpi ? UIScreen.mainScreen.nativeScale : 1.0f; + [_metalLayer setContentsScale:devicePixelScale]; + + _extent2D.width = contentRect.size.width * devicePixelScale; + _extent2D.height = contentRect.size.height * devicePixelScale; + + buildSwapchain(); +} + + +vsgiOS::KeyboardMap::KeyboardMap() +{ + _keycodeMap = + { + { 0xFF, vsg::KEY_Undefined }, + +// { kVK_Space, KEY_Space }, + +// { kVK_ANSI_0, KEY_0 }, +// { kVK_ANSI_1, KEY_1 }, +// { kVK_ANSI_2, KEY_2 }, +// { kVK_ANSI_3, KEY_3 }, +// { kVK_ANSI_4, KEY_4 }, +// { kVK_ANSI_5, KEY_5 }, +// { kVK_ANSI_6, KEY_6 }, +// { kVK_ANSI_7, KEY_7 }, +// { kVK_ANSI_8, KEY_8 }, +// { kVK_ANSI_9, KEY_9 }, + +// { kVK_ANSI_A, KEY_a }, +// { kVK_ANSI_B, KEY_b }, +// { kVK_ANSI_C, KEY_c }, +// { kVK_ANSI_D, KEY_d }, +// { kVK_ANSI_E, KEY_e }, +// { kVK_ANSI_F, KEY_f }, +// { kVK_ANSI_G, KEY_g }, +// { kVK_ANSI_H, KEY_h }, +// { kVK_ANSI_I, KEY_i }, +// { kVK_ANSI_J, KEY_j }, +// { kVK_ANSI_K, KEY_k }, +// { kVK_ANSI_L, KEY_l }, +// { kVK_ANSI_M, KEY_m }, +// { kVK_ANSI_N, KEY_n }, +// { kVK_ANSI_O, KEY_o }, +// { kVK_ANSI_P, KEY_p }, +// { kVK_ANSI_Q, KEY_q }, +// { kVK_ANSI_R, KEY_r }, +// { kVK_ANSI_S, KEY_s }, +// { kVK_ANSI_T, KEY_t }, +// { kVK_ANSI_U, KEY_u }, +// { kVK_ANSI_Z, KEY_v }, +// { kVK_ANSI_W, KEY_w }, +// { kVK_ANSI_X, KEY_x }, +// { kVK_ANSI_Y, KEY_y }, +// { kVK_ANSI_Z, KEY_z }, + + { 'A', vsg::KEY_A }, + { 'B', vsg::KEY_B }, + { 'C', vsg::KEY_C }, + { 'D', vsg::KEY_D }, + { 'E', vsg::KEY_E }, + { 'F', vsg::KEY_F }, + { 'G', vsg::KEY_G }, + { 'H', vsg::KEY_H }, + { 'I', vsg::KEY_I }, + { 'J', vsg::KEY_J }, + { 'K', vsg::KEY_K }, + { 'L', vsg::KEY_L }, + { 'M', vsg::KEY_M }, + { 'N', vsg::KEY_N }, + { 'O', vsg::KEY_O }, + { 'P', vsg::KEY_P }, + { 'Q', vsg::KEY_Q }, + { 'R', vsg::KEY_R }, + { 'S', vsg::KEY_S }, + { 'T', vsg::KEY_T }, + { 'U', vsg::KEY_U }, + { 'V', vsg::KEY_V }, + { 'W', vsg::KEY_W }, + { 'X', vsg::KEY_X }, + { 'Y', vsg::KEY_Y }, + { 'Z', vsg::KEY_Z }, + + { '!', vsg::KEY_Exclaim }, + { '"', vsg::KEY_Quotedbl }, + { '#', vsg::KEY_Hash }, + { '$', vsg::KEY_Dollar }, + { '&', vsg::KEY_Ampersand }, +// { kVK_ANSI_Quote, KEY_Quote }, + { '(', vsg::KEY_Leftparen }, + { ')', vsg::KEY_Rightparen }, + { '*', vsg::KEY_Asterisk }, + { '+', vsg::KEY_Plus }, +// { kVK_ANSI_Comma, KEY_Comma }, +// { kVK_ANSI_Minus, KEY_Minus }, +// { kVK_ANSI_Period, KEY_Period }, +// { kVK_ANSI_Slash, KEY_Slash }, + { ':', vsg::KEY_Colon }, +// { kVK_ANSI_Semicolon, KEY_Semicolon }, + { '<', vsg::KEY_Less }, +// { kVK_ANSI_Equal, KEY_Equals }, // + isnt an unmodded key, why does windows map is as a virtual?? + { '>', vsg::KEY_Greater }, + { '?', vsg::KEY_Question }, + { '@', vsg::KEY_At}, +// { kVK_ANSI_LeftBracket, KEY_Leftbracket }, +// { kVK_ANSI_Backslash, KEY_Backslash }, +// { kVK_ANSI_RightBracket, KEY_Rightbracket }, + {'|', vsg::KEY_Caret }, + {'_', vsg::KEY_Underscore }, + {'`', vsg::KEY_Backquote }, + +// { kVK_Delete, KEY_BackSpace }, /* back space, back char */ +// { kVK_Tab, KEY_Tab }, + // KEY_Linefeed = 0xFF0A, /* Linefeed, LF */ + //{ AKEYCODE_CLEAR, KEY_Clear }, +// { kVK_Return, KEY_Return }, /* Return, enter */ + //{ AKEYCODE_BREAK, KEY_Pause }, /* Pause, hold */ + //{ AKEYCODE_SCROLL_LOCK, KEY_Scroll_Lock }, + // KEY_Sys_Req = 0xFF15, +// { kVK_Escape, KEY_Escape }, +// { kVK_ForwardDelete, KEY_Delete }, /* Delete, rubout */ + + /* Cursor control & motion */ + +// { kVK_Home, KEY_Home }, +// { kVK_LeftArrow, KEY_Left }, /* Move left, left arrow */ +// { kVK_UpArrow, KEY_Up }, /* Move up, up arrow */ +// { kVK_RightArrow, KEY_Right }, /* Move right, right arrow */ +// { kVK_DownArrow, KEY_Down }, /* Move down, down arrow */ + //{ AKEYCODE_NAVIGATE_PREVIOUS, KEY_Prior }, /* Prior, previous */ +// { kVK_PageUp, KEY_Page_Up }, + //{ AKEYCODE_NAVIGATE_NEXT, KEY_Next }, /* Next */ +// { kVK_PageDown, KEY_Page_Down }, +// { kVK_End, KEY_End }, /* EOL */ + //{ KEY_Begin = 0xFF58, /* BOL */ + + /* Misc Functions */ + + //{ VK_SELECT, KEY_Select }, /* Select, mark */ + //{ VK_PRINT, KEY_Print }, + //{ VK_EXECUTE, KEY_Execute }, /* Execute, run, do */ + //{ AKEYCODE_INSERT, KEY_Insert }, /* Insert, insert here */ + //{ KEY_Undo = 0xFF65, /* Undo, oops */ + //KEY_Redo = 0xFF66, /* redo, again */ + //{ AKEYCODE_MENU, KEY_Menu }, /* On Windows, this is VK_APPS, the context-menu key */ + // KEY_Find = 0xFF68, /* Find, search */ + //{ VK_CANCEL, KEY_Cancel }, /* Cancel, stop, abort, exit */ +// { kVK_Help, KEY_Help }, /* Help */ + //{ KEY_Break = 0xFF6B, + //KEY_Mode_switch = 0xFF7E, /* Character set switch */ + //KEY_Script_switch = 0xFF7E, /* Alias for mode_switch */ + //{ AKEYCODE_NUM_LOCK, KEY_Num_Lock }, + + /* Keypad Functions, keypad numbers cleverly chosen to map to ascii */ + + //KEY_KP_Space = 0xFF80, /* space */ + //KEY_KP_Tab = 0xFF89, +// { kVK_ANSI_KeypadEnter, KEY_KP_Enter }, /* enter */ + //KEY_KP_F1 = 0xFF91, /* PF1, KP_A, ... */ + //KEY_KP_F2 = 0xFF92, + //KEY_KP_F3 = 0xFF93, + //KEY_KP_F4 = 0xFF94, + //KEY_KP_Home = 0xFF95, + //KEY_KP_Left = 0xFF96, + //KEY_KP_Up = 0xFF97, + //KEY_KP_Right = 0xFF98, + //KEY_KP_Down = 0xFF99, + //KEY_KP_Prior = 0xFF9A, + //KEY_KP_Page_Up = 0xFF9A, + //KEY_KP_Next = 0xFF9B, + //KEY_KP_Page_Down = 0xFF9B, + //KEY_KP_End = 0xFF9C, + //KEY_KP_Begin = 0xFF9D, + //KEY_KP_Insert = 0xFF9E, + //KEY_KP_Delete = 0xFF9F, +// { kVK_ANSI_KeypadEquals, KEY_KP_Equal }, /* equals */ +// { kVK_ANSI_KeypadMultiply, KEY_KP_Multiply }, +// { kVK_ANSI_KeypadPlus, KEY_KP_Add }, + //{ AKEYCODE_NUMPAD_COMMA, KEY_KP_Separator }, /* separator, often comma */ +// { kVK_ANSI_KeypadMinus, KEY_KP_Subtract }, +// { kVK_ANSI_KeypadDecimal, KEY_KP_Decimal }, +// { kVK_ANSI_KeypadDivide, KEY_KP_Divide }, + +// { kVK_ANSI_Keypad0, KEY_KP_0 }, +// { kVK_ANSI_Keypad1, KEY_KP_1 }, +// { kVK_ANSI_Keypad2, KEY_KP_2 }, +// { kVK_ANSI_Keypad3, KEY_KP_3 }, +// { kVK_ANSI_Keypad4, KEY_KP_4 }, +// { kVK_ANSI_Keypad5, KEY_KP_5 }, +// { kVK_ANSI_Keypad6, KEY_KP_6 }, +// { kVK_ANSI_Keypad7, KEY_KP_7 }, +// { kVK_ANSI_Keypad8, KEY_KP_8 }, +// { kVK_ANSI_Keypad9, KEY_KP_9 }, + + /* + * Auxiliary Functions; note the duplicate definitions for left and right + * function keys; Sun keyboards and a few other manufactures have such + * function key groups on the left and/or right sides of the keyboard. + * We've not found a keyboard with more than 35 function keys total. + */ + +// { kVK_F1, KEY_F1 }, +// { kVK_F2, KEY_F2 }, +// { kVK_F3, KEY_F3 }, +// { kVK_F4, KEY_F4 }, +// { kVK_F5, KEY_F5 }, +// { kVK_F6, KEY_F6 }, +// { kVK_F7, KEY_F7 }, +// { kVK_F8, KEY_F8 }, +// { kVK_F9, KEY_F9 }, +// { kVK_F10, KEY_F10 }, +// { kVK_F11, KEY_F11 }, +// { kVK_F12, KEY_F12 }, +// { kVK_F13, KEY_F13 }, +// { kVK_F14, KEY_F14 }, +// { kVK_F15, KEY_F15 }, +// { kVK_F16, KEY_F16 }, +// { kVK_F17, KEY_F17 }, +// { kVK_F18, KEY_F18 }, +// { kVK_F19, KEY_F19 }, +// { kVK_F20, KEY_F20 }, + //{ VK_F21, KEY_F21 }, + //{ VK_F22, KEY_F22 }, + //{ VK_F23, KEY_F23 }, + //{ VK_F24, KEY_F24 }, + + //KEY_F25 = 0xFFD6, + //KEY_F26 = 0xFFD7, + //KEY_F27 = 0xFFD8, + //KEY_F28 = 0xFFD9, + //KEY_F29 = 0xFFDA, + //KEY_F30 = 0xFFDB, + //KEY_F31 = 0xFFDC, + //KEY_F32 = 0xFFDD, + //KEY_F33 = 0xFFDE, + //KEY_F34 = 0xFFDF, + //KEY_F35 = 0xFFE0, + + /* Modifiers */ + +// { kVK_Shift, KEY_Shift_L }, /* Left shift */ +// { kVK_RightShift, KEY_Shift_R }, /* Right shift */ +// { kVK_Control, KEY_Control_L }, /* Left control */ + //{ AKEYCODE_CTRL_RIGHT, KEY_Control_R }, // no right control on mac +// { kVK_CapsLock, KEY_Caps_Lock }, /* Caps lock */ + //KEY_Shift_Lock = 0xFFE6, /* Shift lock */ + + //{ AKEYCODE_META_LEFT, KEY_Meta_L }, /* Left meta */ + //{ AKEYCODE_META_RIGHT, KEY_Meta_R }, /* Right meta */ +// { kVK_Option, KEY_Alt_L }, /* Left alt */ +// { kVK_RightOption, KEY_Alt_R }, /* Right alt */ +// { kVK_Command, KEY_Super_L }, /* Left super */ + //{ VK_RWIN, KEY_Super_R } /* Right super */ + //KEY_Hyper_L = 0xFFED, /* Left hyper */ + //KEY_Hyper_R = 0xFFEE /* Right hyper */ + }; +} + +//bool KeyboardMap::getKeySymbol(NSEvent* anEvent, vsg::KeySymbol& keySymbol, vsg::KeySymbol& modifiedKeySymbol, vsg::KeyModifier& keyModifier) +//{ +// unsigned short keycode = [anEvent keyCode]; +// NSEventModifierFlags modifierFlags = [anEvent modifierFlags]; +// //NSLog(@"keycode: %d", keycode); +// // try find the raw keycode +// auto itr = _keycodeMap.find(keycode); +// if (itr == _keycodeMap.end()) +// { +// // if we don't find it, try the unmodified characters +// NSString* unmodcharacters = [anEvent charactersIgnoringModifiers]; +// if ( [unmodcharacters length] == 0 ) return false; // dead key +// unsigned short unmodkeychar = [unmodcharacters characterAtIndex:0]; +// itr = _keycodeMap.find(unmodkeychar); +// if (itr == _keycodeMap.end()) return false; +// } + +// keySymbol = itr->second; +// modifiedKeySymbol = keySymbol; + +// uint16_t modifierMask = 0; + +// if (modifierFlags & NSEventModifierFlagOption) modifierMask |= vsg::KeyModifier::MODKEY_Alt; +// if (modifierFlags & NSEventModifierFlagControl) modifierMask |= vsg::KeyModifier::MODKEY_Control; +// if (modifierFlags & NSEventModifierFlagShift) modifierMask |= vsg::KeyModifier::MODKEY_Shift; +// if (modifierFlags & NSEventModifierFlagCapsLock) modifierMask |= vsg::KeyModifier::MODKEY_CapsLock; +// if (modifierFlags & NSEventModifierFlagNumericPad) modifierMask |= vsg::KeyModifier::MODKEY_NumLock; + +// keyModifier = (vsg::KeyModifier) modifierMask; + +// if(modifierMask == 0) return true; + +// // try find modified by using characters +// NSString* characters = [anEvent characters]; +// if ( [characters length] == 0 ) return true; // dead key + +// //NSLog(@"characters: %@", characters); + +// if ( [characters length] == 1 ) +// { +// unsigned short keychar = [characters characterAtIndex:0]; +// itr = _keycodeMap.find(keychar); +// if (itr == _keycodeMap.end()) return true; // still return true, we just don't have a specific modified character +// modifiedKeySymbol = itr->second; +// } + +// return true; +//} + + +bool vsgiOS::iOS_Window::handleUIEvent(UIEvent* anEvent) +{ + switch([anEvent type]) + { + +// // mouse events +// case UIEventTypeMouseMoved: +// case UIEventTypeLeftMouseDown: +// case UIEventTypeLeftMouseUp: +// case UIEventTypeLeftMouseDragged: +// case UIEventTypeRightMouseDown: +// case UIEventTypeRightMouseUp: +// case UIEventTypeRightMouseDragged: +// case UIEventTypeOtherMouseDown: +// case UIEventTypeOtherMouseUp: +// case UIEventTypeOtherMouseDragged: +// { +// CGRect contentRect = [_view frame]; +// CGPoint pos = [anEvent locationInWindow]; +// +// // dpi scale as needed +// auto devicePixelScale = _traits->hdpi ? [_window backingScaleFactor] : 1.0f; +// contentRect.size.width = contentRect.size.width * devicePixelScale; +// contentRect.size.height = contentRect.size.height * devicePixelScale; +// +// pos.x = pos.x * devicePixelScale; +// pos.y = pos.y * devicePixelScale; +// +// +// NSInteger buttonNumber = [anEvent buttonNumber]; +// NSUInteger pressedButtons = [NSEvent pressedMouseButtons]; +// +// //std::cout << "NSEventTypeMouseMoved(etc): " << pos.x << ", " << pos.y << std::endl; +// +// auto buttonMask = 0; +// if(pressedButtons & (1 << 0)) buttonMask |= vsg::BUTTON_MASK_1; +// if(pressedButtons & (1 << 1)) buttonMask |= vsg::BUTTON_MASK_2; +// if(pressedButtons & (1 << 2)) buttonMask |= vsg::BUTTON_MASK_3; +// +// switch([anEvent type]) +// { +// case NSEventTypeMouseMoved: +// case NSEventTypeLeftMouseDragged: +// case NSEventTypeRightMouseDragged: +// case NSEventTypeOtherMouseDragged: +// { +// _bufferedEvents.emplace_back(new vsg::MoveEvent(this, getEventTime([anEvent timestamp]), pos.x, contentRect.size.height - pos.y, vsg::ButtonMask(buttonMask))); +// break; +// } +// case NSEventTypeLeftMouseDown: +// case NSEventTypeRightMouseDown: +// case NSEventTypeOtherMouseDown: +// { +// _bufferedEvents.emplace_back(new vsg::ButtonPressEvent(this, getEventTime([anEvent timestamp]), pos.x, contentRect.size.height - pos.y, vsg::ButtonMask(buttonMask), buttonNumber)); +// break; +// } +// case NSEventTypeLeftMouseUp: +// case NSEventTypeRightMouseUp: +// case NSEventTypeOtherMouseUp: +// { +// _bufferedEvents.emplace_back(new vsg::ButtonReleaseEvent(this, getEventTime([anEvent timestamp]), pos.x, contentRect.size.height - pos.y, vsg::ButtonMask(buttonMask), buttonNumber)); +// break; +// } +// default: break; +// } +// return true; +// } + // keyboard events +// case NSEventTypeKeyDown: +// case NSEventTypeKeyUp: +// //case NSEventTypeFlagsChanged: +// { +// vsg::KeySymbol keySymbol, modifiedKeySymbol; +// vsg::KeyModifier keyModifier; +// if (!_keyboard->getKeySymbol(anEvent, keySymbol, modifiedKeySymbol, keyModifier)) +// return false; +// +// switch([anEvent type]) +// { +// case NSEventTypeKeyDown: +// { +// _bufferedEvents.emplace_back(new vsg::KeyPressEvent(this, getEventTime([anEvent timestamp]), keySymbol, modifiedKeySymbol, keyModifier)); +// break; +// } +// case NSEventTypeKeyUp: +// { +// _bufferedEvents.emplace_back(new vsg::KeyReleaseEvent(this, getEventTime([anEvent timestamp]), keySymbol, modifiedKeySymbol, keyModifier)); +// break; +// } +// default: break; +// } +// +// return true; +// } +// // scrollWheel events +// case NSEventTypeScrollWheel: +// { +// _bufferedEvents.emplace_back(new vsg::ScrollWheelEvent(this, getEventTime([anEvent timestamp]), vsg::vec3([anEvent deltaX], [anEvent deltaY], [anEvent deltaZ]))); +// return true; +// } + + default: break; + } + return false; +} + diff --git a/src/vsg/viewer/Trackball.cpp b/src/vsg/viewer/Trackball.cpp index 091155e86c..b9aa8f41f3 100644 --- a/src/vsg/viewer/Trackball.cpp +++ b/src/vsg/viewer/Trackball.cpp @@ -265,6 +265,46 @@ void Trackball::apply(ScrollWheelEvent& scrollWheel) zoom(scrollWheel.delta.y * 0.1); } +void Trackball::apply(TouchDownEvent& touchDown) +{ + vsg::ref_ptr w = touchDown.window; + vsg::ref_ptr evt = vsg::ButtonPressEvent::create( + w, + touchDown.time, + touchDown.x, + touchDown.y, + vsg::ButtonMask::BUTTON_MASK_1, + touchDown.id + ); + apply(*evt.get()); +} + +void Trackball::apply(TouchUpEvent& touchUp) +{ + vsg::ref_ptr w = touchUp.window; + vsg::ref_ptr evt = vsg::ButtonReleaseEvent::create( + w, + touchUp.time, + touchUp.x, + touchUp.y, + vsg::ButtonMask::BUTTON_MASK_1, + touchUp.id + ); + apply(*evt.get()); +} + +void Trackball::apply(TouchMoveEvent& touchMove) +{ + vsg::ref_ptr w = touchMove.window; + vsg::ref_ptr evt = vsg::MoveEvent::create( + w, + touchMove.time, + touchMove.x, + touchMove.y, + vsg::ButtonMask::BUTTON_MASK_1 + ); + apply(*evt.get()); +} void Trackball::apply(FrameEvent& frame) { if (_endLookAt) diff --git a/src/vsg/vk/RenderPass.cpp b/src/vsg/vk/RenderPass.cpp index 2b7e14688d..0b90836d32 100644 --- a/src/vsg/vk/RenderPass.cpp +++ b/src/vsg/vk/RenderPass.cpp @@ -157,7 +157,7 @@ RenderPass::RenderPass(Device* in_device, const Attachments& in_attachments, con renderPassInfo.correlatedViewMaskCount = static_cast(correlatedViewMasks.size()); renderPassInfo.pCorrelatedViewMasks = correlatedViewMasks.empty() ? nullptr : correlatedViewMasks.data(); - VkResult result = vkCreateRenderPass2(*device, &renderPassInfo, device->getAllocationCallbacks(), &_renderPass); + VkResult result = vkCreateRenderPass2KHR(*device, &renderPassInfo, device->getAllocationCallbacks(), &_renderPass); if (result != VK_SUCCESS) { throw Exception{"Error: vsg::RenderPass::create(...) Failed to create VkRenderPass.", result};