Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion app/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2019-2025, Arm Limited and Contributors
# Copyright (c) 2019-2026, Arm Limited and Contributors
#
# SPDX-License-Identifier: Apache-2.0
#
Expand Down Expand Up @@ -49,6 +49,8 @@ elseif(IOS)
${CMAKE_CURRENT_SOURCE_DIR}/ios/main.mm
${CMAKE_CURRENT_SOURCE_DIR}/ios/AppDelegate.h
${CMAKE_CURRENT_SOURCE_DIR}/ios/AppDelegate.m
${CMAKE_CURRENT_SOURCE_DIR}/ios/SceneDelegate.h
${CMAKE_CURRENT_SOURCE_DIR}/ios/SceneDelegate.m
${CMAKE_CURRENT_SOURCE_DIR}/ios/ViewController.h
${CMAKE_CURRENT_SOURCE_DIR}/ios/ViewController.mm
)
Expand Down
3 changes: 1 addition & 2 deletions app/ios/AppDelegate.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* Copyright (c) 2024, Holochip Inc.
/* Copyright (c) 2024-2026, Holochip Inc.
*
* SPDX-License-Identifier: Apache-2.0
*
Expand All @@ -25,7 +25,6 @@
#if TARGET_OS_IOS
@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;
#else
@interface AppDelegate : NSResponder <NSApplicationDelegate>

Expand Down
24 changes: 3 additions & 21 deletions app/ios/AppDelegate.m
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* Copyright (c) 2024, Holochip Inc.
/* Copyright (c) 2024-2026, Holochip Inc.
*
* SPDX-License-Identifier: Apache-2.0
*
Expand Down Expand Up @@ -29,27 +29,9 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(
return YES;
}


- (void)applicationWillResignActive:(UIApplication *)application {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}


- (void)applicationDidEnterBackground:(UIApplication *)application {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
- (void)applicationWillTerminate:(UIApplication *)application {
// Called when the application is about to terminate. Save data if appropriate.
}


- (void)applicationWillEnterForeground:(UIApplication *)application {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}


- (void)applicationDidBecomeActive:(UIApplication *)application {
// 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.
}


@end
#endif
21 changes: 20 additions & 1 deletion app/ios/Info.plist
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (c) 2024, Holochip Inc.
Copyright (c) 2024-2026, Holochip Inc.

SPDX-License-Identifier: Apache-2.0

Expand Down Expand Up @@ -47,6 +47,25 @@ limitations under the License.
<string>Storyboard</string>
<key>UILaunchStoryboardName</key>
<string>launch</string>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<false/>
<key>UISceneConfigurations</key>
<dict>
<key>UIWindowSceneSessionRoleApplication</key>
<array>
<dict>
<key>UISceneConfigurationName</key>
<string>Default Configuration</string>
<key>UISceneDelegateClassName</key>
<string>SceneDelegate</string>
<key>UISceneStoryboardFile</key>
<string>Storyboard</string>
</dict>
</array>
</dict>
</dict>
<key>CSResourcesFileMapped</key>
<true/>
<key>NSHumanReadableCopyright</key>
Expand Down
25 changes: 25 additions & 0 deletions app/ios/SceneDelegate.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/* Copyright (c) 2026, Stephen Saunders
*
* SPDX-License-Identifier: Apache-2.0
*
* 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
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#import <UIKit/UIKit.h>

@interface SceneDelegate : UIResponder <UIWindowSceneDelegate>

@property (strong, nonatomic) UIWindow *window;

@end

65 changes: 65 additions & 0 deletions app/ios/SceneDelegate.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/* Copyright (c) 2026, Stephen Saunders
*
* SPDX-License-Identifier: Apache-2.0
*
* 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
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#import "SceneDelegate.h"
#import "ViewController.h"

@interface SceneDelegate ()

@end

@implementation SceneDelegate


- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
UIWindowScene *windowScene = (UIWindowScene *)scene;

self.window = [[UIWindow alloc] initWithWindowScene:windowScene];
self.window.rootViewController = [[ViewController alloc] init];

[self.window makeKeyAndVisible];
}

- (void)sceneWillEnterForeground:(UIScene *)scene {
// Called as the scene transitions from the background to the foreground.
// Use this method to undo the changes made on entering the background.
}

- (void)sceneDidBecomeActive:(UIScene *)scene {
// Called when the scene has moved from an inactive state to an active state.
// Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
}

- (void)sceneWillResignActive:(UIScene *)scene {
// Called when the scene will move from an active state to an inactive state.
// This may occur due to temporary interruptions (ex. an incoming phone call).
}

- (void)sceneDidEnterBackground:(UIScene *)scene {
// Called as the scene transitions from the foreground to the background.
// Use this method to save data, release shared resources, and store enough scene-specific state information
// to restore the scene back to its current state.
}

- (void)sceneDidDisconnect:(UIScene *)scene {
// Called as the scene is being released by the system.
// This occurs shortly after the scene enters the background, or when its session is discarded.
// Release any resources associated with this scene that can be re-created the next time the scene connects.
// The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
}

@end
77 changes: 74 additions & 3 deletions app/ios/ViewController.mm
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* Copyright (c) 2024, Holochip Inc.
/* Copyright (c) 2024-2026, Holochip Inc.
*
* SPDX-License-Identifier: Apache-2.0
*
Expand All @@ -20,6 +20,7 @@
#include "core/platform/entrypoint.hpp"
#include "platform/ios/ios_platform.h"
#include "platform/ios/ios_window.h"
#include "platform/input_events.h"

int platform_main(const vkb::PlatformContext &);

Expand All @@ -28,16 +29,16 @@ @interface ViewController(){
std::unique_ptr<vkb::PlatformContext> context;
vkb::IosPlatformContext* _context;
vkb::ExitCode _code;
UITouch* _activeTouch;
}
@property (retain, nonatomic) IBOutlet VulkanView *vulkan_view;

@end

@implementation ViewController
- (void)viewDidLoad {
- (void) viewDidLoad {
[super viewDidLoad];


// Convert incoming args to "C" argc/argv strings
NSArray *args = [[NSProcessInfo processInfo] arguments];
const char** argv = (const char**) alloca(sizeof(char*) * args.count);
Expand All @@ -46,6 +47,10 @@ - (void)viewDidLoad {
argv[i] = s.UTF8String;
}

// Allocate and add a Metal-compatible sub-view for Vulkan to use
self.vulkan_view = [[VulkanView alloc] initWithFrame:self.view.bounds];
[self.view addSubview:self.vulkan_view];

self.vulkan_view.contentScaleFactor = UIScreen.mainScreen.nativeScale;

context = create_platform_context((int)args.count, const_cast<char**>(argv));
Expand All @@ -58,6 +63,13 @@ - (void)viewDidLoad {
[_displayLink addToRunLoop: NSRunLoop.currentRunLoop forMode: NSDefaultRunLoopMode];
}

- (void) viewDidLayoutSubviews {
[super viewDidLayoutSubviews];

// Update the Vulkan sub-view to match parent view dimensions following rotation events
self.vulkan_view.layer.frame = self.view.bounds;
}

-(void) renderLoop {
if(!_displayLink.isPaused && [UIApplication sharedApplication].applicationState == UIApplicationStateActive) {
if(_code == vkb::ExitCode::Success) {
Expand All @@ -73,4 +85,63 @@ -(void) renderLoop {
}
}
}

-(CGPoint) getTouchLocalPoint:(UITouch*) touch {
CGPoint point = [touch locationInView:self.vulkan_view];
point.x *= self.vulkan_view.contentScaleFactor;
point.y *= self.vulkan_view.contentScaleFactor;
return point;
}

// Handle touch events for selection and dragging within the display and GUI overlay
-(void) touchesBegan:(NSSet*) touches withEvent:(UIEvent*) theEvent {
if (_activeTouch == nil) {
_activeTouch = [touches anyObject];

auto point = [self getTouchLocalPoint:_activeTouch];
((vkb::IosPlatform*)_context->userPlatform)->input_event(vkb::TouchInputEvent{
0, 1,
vkb::TouchAction::Down,
static_cast<float>(point.x),
static_cast<float>(point.y)});
}
}

-(void) touchesMoved:(NSSet*) touches withEvent:(UIEvent*) theEvent {
if (_activeTouch && [touches containsObject:_activeTouch]) {
auto point = [self getTouchLocalPoint:_activeTouch];
((vkb::IosPlatform*)_context->userPlatform)->input_event(vkb::TouchInputEvent{
0, 1,
vkb::TouchAction::Move,
static_cast<float>(point.x),
static_cast<float>(point.y)});
}
}

-(void) touchesEnded:(NSSet*) touches withEvent:(UIEvent*) theEvent {
if (_activeTouch && [touches containsObject:_activeTouch]) {
auto point = [self getTouchLocalPoint:_activeTouch];
((vkb::IosPlatform*)_context->userPlatform)->input_event(vkb::TouchInputEvent{
0, 1,
vkb::TouchAction::Up,
static_cast<float>(point.x),
static_cast<float>(point.y)});

_activeTouch = nil;
}
}

-(void) touchesCancelled:(NSSet*) touches withEvent:(UIEvent*) theEvent {
if (_activeTouch && [touches containsObject:_activeTouch]) {
auto point = [self getTouchLocalPoint:_activeTouch];
((vkb::IosPlatform*)_context->userPlatform)->input_event(vkb::TouchInputEvent{
0, 1,
vkb::TouchAction::Cancel,
static_cast<float>(point.x),
static_cast<float>(point.y)});

_activeTouch = nil;
}
}

@end
Loading