fix: build
This commit is contained in:
+1
-1
@@ -1,6 +1,6 @@
|
||||
[submodule "moonlight-common/moonlight-common-c"]
|
||||
path = moonlight-common/moonlight-common-c
|
||||
url=https://github.com/TrueZhuangJia/voidlink-c.git
|
||||
url=https://github.com/Acaki/voidlink-c
|
||||
[submodule "X1Kit"]
|
||||
path = X1Kit
|
||||
url = https://github.com/cgutman/X1Kit.git
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
// dear imgui: Renderer Backend for Metal
|
||||
// This needs to be used along with a Platform Backend (e.g. OSX)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Renderer: User texture binding. Use 'MTLTexture' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
|
||||
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
|
||||
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// Learn about Dear ImGui:
|
||||
// - FAQ https://dearimgui.com/faq
|
||||
// - Getting Started https://dearimgui.com/getting-started
|
||||
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
|
||||
// - Introduction, links and more at the top of imgui.cpp
|
||||
|
||||
#pragma once
|
||||
#include "imgui.h" // IMGUI_IMPL_API
|
||||
#ifndef IMGUI_DISABLE
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ObjC API
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifdef __OBJC__
|
||||
|
||||
@class MTLRenderPassDescriptor;
|
||||
@protocol MTLDevice, MTLCommandBuffer, MTLRenderCommandEncoder;
|
||||
|
||||
// Follow "Getting Started" link and check examples/ folder to learn about using backends!
|
||||
IMGUI_IMPL_API bool ImGui_ImplMetal_Init(id<MTLDevice> device);
|
||||
IMGUI_IMPL_API void ImGui_ImplMetal_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplMetal_NewFrame(MTLRenderPassDescriptor* renderPassDescriptor);
|
||||
IMGUI_IMPL_API void ImGui_ImplMetal_RenderDrawData(ImDrawData* drawData,
|
||||
id<MTLCommandBuffer> commandBuffer,
|
||||
id<MTLRenderCommandEncoder> commandEncoder);
|
||||
|
||||
// Called by Init/NewFrame/Shutdown
|
||||
IMGUI_IMPL_API bool ImGui_ImplMetal_CreateDeviceObjects(id<MTLDevice> device);
|
||||
IMGUI_IMPL_API void ImGui_ImplMetal_DestroyDeviceObjects();
|
||||
|
||||
// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually.
|
||||
IMGUI_IMPL_API void ImGui_ImplMetal_UpdateTexture(ImTextureData* tex);
|
||||
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// C++ API
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Enable Metal C++ binding support with '#define IMGUI_IMPL_METAL_CPP' in your imconfig.h file
|
||||
// More info about using Metal from C++: https://developer.apple.com/metal/cpp/
|
||||
|
||||
#ifdef IMGUI_IMPL_METAL_CPP
|
||||
#include <Metal/Metal.hpp>
|
||||
#ifndef __OBJC__
|
||||
|
||||
// Follow "Getting Started" link and check examples/ folder to learn about using backends!
|
||||
IMGUI_IMPL_API bool ImGui_ImplMetal_Init(MTL::Device* device);
|
||||
IMGUI_IMPL_API void ImGui_ImplMetal_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplMetal_NewFrame(MTL::RenderPassDescriptor* renderPassDescriptor);
|
||||
IMGUI_IMPL_API void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data,
|
||||
MTL::CommandBuffer* commandBuffer,
|
||||
MTL::RenderCommandEncoder* commandEncoder);
|
||||
|
||||
// Called by Init/NewFrame/Shutdown
|
||||
IMGUI_IMPL_API bool ImGui_ImplMetal_CreateDeviceObjects(MTL::Device* device);
|
||||
IMGUI_IMPL_API void ImGui_ImplMetal_DestroyDeviceObjects();
|
||||
|
||||
// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually.
|
||||
IMGUI_IMPL_API void ImGui_ImplMetal_UpdateTexture(ImTextureData* tex);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#endif // #ifndef IMGUI_DISABLE
|
||||
@@ -1,40 +0,0 @@
|
||||
//
|
||||
// TemporarySettings.h
|
||||
// Moonlight
|
||||
//
|
||||
// Created by Cameron Gutman on 12/1/15.
|
||||
// Copyright © 2015 Moonlight Stream. All rights reserved.
|
||||
//
|
||||
|
||||
#import "Settings+CoreDataClass.h"
|
||||
|
||||
@interface TemporarySettings : NSObject
|
||||
|
||||
@property (nonatomic, retain) Settings * parent;
|
||||
|
||||
@property (nonatomic, retain) NSNumber * bitrate;
|
||||
@property (nonatomic, retain) NSNumber * framerate;
|
||||
@property (nonatomic, retain) NSNumber * height;
|
||||
@property (nonatomic, retain) NSNumber * width;
|
||||
@property (nonatomic, retain) NSNumber * audioConfig;
|
||||
@property (nonatomic, retain) NSNumber * onscreenControls;
|
||||
@property (nonatomic, retain) NSString * uniqueId;
|
||||
@property (nonatomic) enum {
|
||||
CODEC_PREF_AUTO,
|
||||
CODEC_PREF_H264,
|
||||
CODEC_PREF_HEVC,
|
||||
CODEC_PREF_AV1,
|
||||
} preferredCodec;
|
||||
@property (nonatomic) BOOL useFramePacing;
|
||||
@property (nonatomic) BOOL multiController;
|
||||
@property (nonatomic) BOOL swapABXYButtons;
|
||||
@property (nonatomic) BOOL playAudioOnPC;
|
||||
@property (nonatomic) BOOL optimizeGames;
|
||||
@property (nonatomic) BOOL enableHdr;
|
||||
@property (nonatomic) BOOL btMouseSupport;
|
||||
@property (nonatomic) BOOL absoluteTouchMode;
|
||||
@property (nonatomic) BOOL statsOverlay;
|
||||
|
||||
- (id) initFromSettings:(Settings*)settings;
|
||||
|
||||
@end
|
||||
@@ -1,37 +0,0 @@
|
||||
//
|
||||
// StreamView.h
|
||||
// Moonlight
|
||||
//
|
||||
// Created by Cameron Gutman on 10/19/14.
|
||||
// Copyright (c) 2014 Moonlight Stream. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ControllerSupport.h"
|
||||
#import "OnScreenControls.h"
|
||||
#import "Moonlight-Swift.h"
|
||||
#import "StreamConfiguration.h"
|
||||
|
||||
@protocol UserInteractionDelegate <NSObject>
|
||||
|
||||
- (void) userInteractionBegan;
|
||||
- (void) userInteractionEnded;
|
||||
|
||||
@end
|
||||
|
||||
#if TARGET_OS_TV
|
||||
@interface StreamView : UIView <X1KitMouseDelegate, UITextFieldDelegate>
|
||||
#else
|
||||
@interface StreamView : UIView <X1KitMouseDelegate, UITextFieldDelegate, UIPointerInteractionDelegate>
|
||||
#endif
|
||||
|
||||
- (void) setupStreamView:(ControllerSupport*)controllerSupport
|
||||
interactionDelegate:(id<UserInteractionDelegate>)interactionDelegate
|
||||
config:(StreamConfiguration*)streamConfig;
|
||||
- (void) showOnScreenControls;
|
||||
- (OnScreenControlsLevel) getCurrentOscState;
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
- (void) updateCursorLocation:(CGPoint)location isMouse:(BOOL)isMouse;
|
||||
#endif
|
||||
|
||||
@end
|
||||
@@ -1128,7 +1128,6 @@ BOOL isCustomResolution(CGSize res) {
|
||||
NSInteger touchMode = [self.touchModeSelector selectedSegmentIndex];
|
||||
NSInteger statsOverlayLevel = [self.statsOverlaySelector selectedSegmentIndex];
|
||||
BOOL statsOverlayEnabled = statsOverlayLevel != 0;
|
||||
BOOL statsOverlay = [self.statsOverlaySelector selectedSegmentIndex] == 1;
|
||||
BOOL enableGraphs = [self.enableGraphsSelector selectedSegmentIndex] == 1;
|
||||
BOOL enableHdr = [self.hdrSelector selectedSegmentIndex] == 1;
|
||||
BOOL unlockDisplayOrientation = [self.unlockDisplayOrientationSelector selectedSegmentIndex] == 1;
|
||||
@@ -1172,7 +1171,6 @@ BOOL isCustomResolution(CGSize res) {
|
||||
resolutionSelected:resolutionSelected
|
||||
externalDisplayMode:externalDisplayMode
|
||||
localMousePointerMode:localMousePointerMode];
|
||||
statsOverlay:statsOverlay
|
||||
enableGraphs:enableGraphs
|
||||
graphOpacity:_graphOpacity
|
||||
renderingBackend:renderingBackend];
|
||||
|
||||
@@ -1,714 +0,0 @@
|
||||
//
|
||||
// StreamFrameViewController.m
|
||||
// Moonlight
|
||||
//
|
||||
// Created by Diego Waxemberg on 1/18/14.
|
||||
// Copyright (c) 2015 Moonlight Stream. All rights reserved.
|
||||
//
|
||||
|
||||
#import "StreamFrameViewController.h"
|
||||
#import "MainFrameViewController.h"
|
||||
#import "VideoDecoderRenderer.h"
|
||||
#import "StreamManager.h"
|
||||
#import "ControllerSupport.h"
|
||||
#import "DataManager.h"
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <Limelight.h>
|
||||
|
||||
#if TARGET_OS_TV
|
||||
#import <AVFoundation/AVDisplayCriteria.h>
|
||||
#import <AVKit/AVDisplayManager.h>
|
||||
#import <AVKit/UIWindow.h>
|
||||
#endif
|
||||
|
||||
@interface AVDisplayCriteria()
|
||||
@property(readonly) int videoDynamicRange;
|
||||
@property(readonly, nonatomic) float refreshRate;
|
||||
- (id)initWithRefreshRate:(float)arg1 videoDynamicRange:(int)arg2;
|
||||
@end
|
||||
|
||||
@implementation StreamFrameViewController {
|
||||
ControllerSupport *_controllerSupport;
|
||||
StreamManager *_streamMan;
|
||||
TemporarySettings *_settings;
|
||||
NSTimer *_inactivityTimer;
|
||||
NSTimer *_statsUpdateTimer;
|
||||
UITapGestureRecognizer *_menuTapGestureRecognizer;
|
||||
UITapGestureRecognizer *_menuDoubleTapGestureRecognizer;
|
||||
UITapGestureRecognizer *_playPauseTapGestureRecognizer;
|
||||
UITextView *_overlayView;
|
||||
UILabel *_stageLabel;
|
||||
UILabel *_tipLabel;
|
||||
UIActivityIndicatorView *_spinner;
|
||||
StreamView *_streamView;
|
||||
UIScrollView *_scrollView;
|
||||
BOOL _userIsInteracting;
|
||||
CGSize _keyboardSize;
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
UIScreenEdgePanGestureRecognizer *_exitSwipeRecognizer;
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)viewDidAppear:(BOOL)animated
|
||||
{
|
||||
[super viewDidAppear:animated];
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
[[self revealViewController] setPrimaryViewController:self];
|
||||
#endif
|
||||
}
|
||||
|
||||
#if TARGET_OS_TV
|
||||
- (void)controllerPauseButtonPressed:(id)sender { }
|
||||
- (void)controllerPauseButtonDoublePressed:(id)sender {
|
||||
Log(LOG_I, @"Menu double-pressed -- backing out of stream");
|
||||
[self returnToMainFrame];
|
||||
}
|
||||
- (void)controllerPlayPauseButtonPressed:(id)sender {
|
||||
Log(LOG_I, @"Play/Pause button pressed -- backing out of stream");
|
||||
[self returnToMainFrame];
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
|
||||
[self.navigationController setNavigationBarHidden:YES animated:YES];
|
||||
|
||||
[UIApplication sharedApplication].idleTimerDisabled = YES;
|
||||
|
||||
_settings = [[[DataManager alloc] init] getSettings];
|
||||
|
||||
_stageLabel = [[UILabel alloc] init];
|
||||
[_stageLabel setUserInteractionEnabled:NO];
|
||||
[_stageLabel setText:[NSString stringWithFormat:@"Starting %@...", self.streamConfig.appName]];
|
||||
[_stageLabel sizeToFit];
|
||||
_stageLabel.textAlignment = NSTextAlignmentCenter;
|
||||
_stageLabel.textColor = [UIColor whiteColor];
|
||||
_stageLabel.center = CGPointMake(self.view.frame.size.width / 2, self.view.frame.size.height / 2);
|
||||
|
||||
_spinner = [[UIActivityIndicatorView alloc] init];
|
||||
[_spinner setUserInteractionEnabled:NO];
|
||||
#if TARGET_OS_TV
|
||||
[_spinner setActivityIndicatorViewStyle:UIActivityIndicatorViewStyleWhiteLarge];
|
||||
#else
|
||||
[_spinner setActivityIndicatorViewStyle:UIActivityIndicatorViewStyleWhite];
|
||||
#endif
|
||||
[_spinner sizeToFit];
|
||||
[_spinner startAnimating];
|
||||
_spinner.center = CGPointMake(self.view.frame.size.width / 2, self.view.frame.size.height / 2 - _stageLabel.frame.size.height - _spinner.frame.size.height);
|
||||
|
||||
_controllerSupport = [[ControllerSupport alloc] initWithConfig:self.streamConfig delegate:self];
|
||||
_inactivityTimer = nil;
|
||||
|
||||
_streamView = [[StreamView alloc] initWithFrame:self.view.frame];
|
||||
[_streamView setupStreamView:_controllerSupport interactionDelegate:self config:self.streamConfig];
|
||||
|
||||
#if TARGET_OS_TV
|
||||
if (!_menuTapGestureRecognizer || !_menuDoubleTapGestureRecognizer || !_playPauseTapGestureRecognizer) {
|
||||
_menuTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(controllerPauseButtonPressed:)];
|
||||
_menuTapGestureRecognizer.allowedPressTypes = @[@(UIPressTypeMenu)];
|
||||
|
||||
_playPauseTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(controllerPlayPauseButtonPressed:)];
|
||||
_playPauseTapGestureRecognizer.allowedPressTypes = @[@(UIPressTypePlayPause)];
|
||||
|
||||
_menuDoubleTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(controllerPauseButtonDoublePressed:)];
|
||||
_menuDoubleTapGestureRecognizer.numberOfTapsRequired = 2;
|
||||
[_menuTapGestureRecognizer requireGestureRecognizerToFail:_menuDoubleTapGestureRecognizer];
|
||||
_menuDoubleTapGestureRecognizer.allowedPressTypes = @[@(UIPressTypeMenu)];
|
||||
}
|
||||
|
||||
[self.view addGestureRecognizer:_menuTapGestureRecognizer];
|
||||
[self.view addGestureRecognizer:_menuDoubleTapGestureRecognizer];
|
||||
[self.view addGestureRecognizer:_playPauseTapGestureRecognizer];
|
||||
|
||||
#else
|
||||
_exitSwipeRecognizer = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:@selector(edgeSwiped)];
|
||||
_exitSwipeRecognizer.edges = UIRectEdgeLeft;
|
||||
_exitSwipeRecognizer.delaysTouchesBegan = NO;
|
||||
_exitSwipeRecognizer.delaysTouchesEnded = NO;
|
||||
|
||||
[self.view addGestureRecognizer:_exitSwipeRecognizer];
|
||||
#endif
|
||||
|
||||
_tipLabel = [[UILabel alloc] init];
|
||||
[_tipLabel setUserInteractionEnabled:NO];
|
||||
|
||||
#if TARGET_OS_TV
|
||||
[_tipLabel setText:@"Tip: Tap the Play/Pause button on the Apple TV Remote to disconnect from your PC"];
|
||||
#else
|
||||
[_tipLabel setText:@"Tip: Swipe from the left edge to disconnect from your PC"];
|
||||
#endif
|
||||
|
||||
[_tipLabel sizeToFit];
|
||||
_tipLabel.textColor = [UIColor whiteColor];
|
||||
_tipLabel.textAlignment = NSTextAlignmentCenter;
|
||||
_tipLabel.center = CGPointMake(self.view.frame.size.width / 2, self.view.frame.size.height * 0.9);
|
||||
|
||||
_streamMan = [[StreamManager alloc] initWithConfig:self.streamConfig
|
||||
renderView:_streamView
|
||||
connectionCallbacks:self];
|
||||
NSOperationQueue* opQueue = [[NSOperationQueue alloc] init];
|
||||
[opQueue addOperation:_streamMan];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(applicationWillResignActive:)
|
||||
name:UIApplicationWillResignActiveNotification
|
||||
object:nil];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver: self
|
||||
selector: @selector(applicationDidBecomeActive:)
|
||||
name: UIApplicationDidBecomeActiveNotification
|
||||
object: nil];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver: self
|
||||
selector: @selector(applicationDidEnterBackground:)
|
||||
name: UIApplicationDidEnterBackgroundNotification
|
||||
object: nil];
|
||||
|
||||
#if 0
|
||||
// FIXME: This doesn't work reliably on iPad for some reason. Showing and hiding the keyboard
|
||||
// several times in a row will not correctly restore the state of the UIScrollView.
|
||||
[[NSNotificationCenter defaultCenter] addObserver: self
|
||||
selector: @selector(keyboardWillShow:)
|
||||
name: UIKeyboardWillShowNotification
|
||||
object: nil];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver: self
|
||||
selector: @selector(keyboardWillHide:)
|
||||
name: UIKeyboardWillHideNotification
|
||||
object: nil];
|
||||
#endif
|
||||
|
||||
// Only enable scroll and zoom in absolute touch mode
|
||||
if (_settings.absoluteTouchMode) {
|
||||
_scrollView = [[UIScrollView alloc] initWithFrame:self.view.frame];
|
||||
#if !TARGET_OS_TV
|
||||
[_scrollView.panGestureRecognizer setMinimumNumberOfTouches:2];
|
||||
#endif
|
||||
[_scrollView setShowsHorizontalScrollIndicator:NO];
|
||||
[_scrollView setShowsVerticalScrollIndicator:NO];
|
||||
[_scrollView setDelegate:self];
|
||||
[_scrollView setMaximumZoomScale:10.0f];
|
||||
|
||||
// Add StreamView inside a UIScrollView for absolute mode
|
||||
[_scrollView addSubview:_streamView];
|
||||
[self.view addSubview:_scrollView];
|
||||
}
|
||||
else {
|
||||
// Add StreamView directly in relative mode
|
||||
[self.view addSubview:_streamView];
|
||||
}
|
||||
|
||||
[self.view addSubview:_stageLabel];
|
||||
[self.view addSubview:_spinner];
|
||||
[self.view addSubview:_tipLabel];
|
||||
}
|
||||
|
||||
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
|
||||
return _streamView;
|
||||
}
|
||||
|
||||
- (void)willMoveToParentViewController:(UIViewController *)parent {
|
||||
// Only cleanup when we're being destroyed
|
||||
if (parent == nil) {
|
||||
[_controllerSupport cleanup];
|
||||
[UIApplication sharedApplication].idleTimerDisabled = NO;
|
||||
[_streamMan stopStream];
|
||||
if (_inactivityTimer != nil) {
|
||||
[_inactivityTimer invalidate];
|
||||
_inactivityTimer = nil;
|
||||
}
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
- (void)keyboardWillShow:(NSNotification *)notification {
|
||||
_keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
|
||||
|
||||
[UIView animateWithDuration:0.3 animations:^{
|
||||
CGRect frame = self->_scrollView.frame;
|
||||
frame.size.height -= self->_keyboardSize.height;
|
||||
self->_scrollView.frame = frame;
|
||||
}];
|
||||
}
|
||||
|
||||
-(void)keyboardWillHide:(NSNotification *)notification {
|
||||
// NOTE: UIKeyboardFrameEndUserInfoKey returns a different keyboard size
|
||||
// than UIKeyboardFrameBeginUserInfoKey, so it's unsuitable for use here
|
||||
// to undo the changes made by keyboardWillShow.
|
||||
|
||||
[UIView animateWithDuration:0.3 animations:^{
|
||||
CGRect frame = self->_scrollView.frame;
|
||||
frame.size.height += self->_keyboardSize.height;
|
||||
self->_scrollView.frame = frame;
|
||||
}];
|
||||
}
|
||||
#endif
|
||||
|
||||
- (void)updateStatsOverlay {
|
||||
NSString* overlayText = [self->_streamMan getStatsOverlayText];
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self updateOverlayText:overlayText];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)updateOverlayText:(NSString*)text {
|
||||
if (_overlayView == nil) {
|
||||
_overlayView = [[UITextView alloc] init];
|
||||
#if !TARGET_OS_TV
|
||||
[_overlayView setEditable:NO];
|
||||
#endif
|
||||
[_overlayView setUserInteractionEnabled:NO];
|
||||
[_overlayView setSelectable:NO];
|
||||
[_overlayView setScrollEnabled:NO];
|
||||
|
||||
// HACK: If not using stats overlay, center the text
|
||||
if (_statsUpdateTimer == nil) {
|
||||
[_overlayView setTextAlignment:NSTextAlignmentCenter];
|
||||
}
|
||||
|
||||
[_overlayView setTextColor:[UIColor lightGrayColor]];
|
||||
[_overlayView setBackgroundColor:[UIColor blackColor]];
|
||||
#if TARGET_OS_TV
|
||||
[_overlayView setFont:[UIFont systemFontOfSize:24]];
|
||||
#else
|
||||
[_overlayView setFont:[UIFont systemFontOfSize:12]];
|
||||
#endif
|
||||
[_overlayView setAlpha:0.5];
|
||||
[self.view addSubview:_overlayView];
|
||||
}
|
||||
|
||||
if (text != nil) {
|
||||
// We set our bounds to the maximum width in order to work around a bug where
|
||||
// sizeToFit interacts badly with the UITextView's line breaks, causing the
|
||||
// width to get smaller and smaller each time as more line breaks are inserted.
|
||||
[_overlayView setBounds:CGRectMake(self.view.frame.origin.x,
|
||||
_overlayView.frame.origin.y,
|
||||
self.view.frame.size.width,
|
||||
_overlayView.frame.size.height)];
|
||||
[_overlayView setText:text];
|
||||
[_overlayView sizeToFit];
|
||||
[_overlayView setCenter:CGPointMake(self.view.frame.size.width / 2, _overlayView.frame.size.height / 2)];
|
||||
[_overlayView setHidden:NO];
|
||||
}
|
||||
else {
|
||||
[_overlayView setHidden:YES];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) returnToMainFrame {
|
||||
// Reset display mode back to default
|
||||
[self updatePreferredDisplayMode:NO];
|
||||
|
||||
[_statsUpdateTimer invalidate];
|
||||
_statsUpdateTimer = nil;
|
||||
|
||||
[self.navigationController popToRootViewControllerAnimated:YES];
|
||||
}
|
||||
|
||||
// This will fire if the user opens control center or gets a low battery message
|
||||
- (void)applicationWillResignActive:(NSNotification *)notification {
|
||||
if (_inactivityTimer != nil) {
|
||||
[_inactivityTimer invalidate];
|
||||
}
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
// Terminate the stream if the app is inactive for 60 seconds
|
||||
Log(LOG_I, @"Starting inactivity termination timer");
|
||||
_inactivityTimer = [NSTimer scheduledTimerWithTimeInterval:60
|
||||
target:self
|
||||
selector:@selector(inactiveTimerExpired:)
|
||||
userInfo:nil
|
||||
repeats:NO];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)inactiveTimerExpired:(NSTimer*)timer {
|
||||
Log(LOG_I, @"Terminating stream after inactivity");
|
||||
|
||||
[self returnToMainFrame];
|
||||
|
||||
_inactivityTimer = nil;
|
||||
}
|
||||
|
||||
- (void)applicationDidBecomeActive:(NSNotification *)notification {
|
||||
// Stop the background timer, since we're foregrounded again
|
||||
if (_inactivityTimer != nil) {
|
||||
Log(LOG_I, @"Stopping inactivity timer after becoming active again");
|
||||
[_inactivityTimer invalidate];
|
||||
_inactivityTimer = nil;
|
||||
}
|
||||
}
|
||||
|
||||
// This fires when the home button is pressed
|
||||
- (void)applicationDidEnterBackground:(UIApplication *)application {
|
||||
Log(LOG_I, @"Terminating stream immediately for backgrounding");
|
||||
|
||||
if (_inactivityTimer != nil) {
|
||||
[_inactivityTimer invalidate];
|
||||
_inactivityTimer = nil;
|
||||
}
|
||||
|
||||
[self returnToMainFrame];
|
||||
}
|
||||
|
||||
- (void)edgeSwiped {
|
||||
Log(LOG_I, @"User swiped to end stream");
|
||||
|
||||
[self returnToMainFrame];
|
||||
}
|
||||
|
||||
- (void) connectionStarted {
|
||||
Log(LOG_I, @"Connection started");
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
// Leave the spinner spinning until it's obscured by
|
||||
// the first frame of video.
|
||||
self->_stageLabel.hidden = YES;
|
||||
self->_tipLabel.hidden = YES;
|
||||
|
||||
[self->_streamView showOnScreenControls];
|
||||
|
||||
[self->_controllerSupport connectionEstablished];
|
||||
|
||||
if (self->_settings.statsOverlay) {
|
||||
self->_statsUpdateTimer = [NSTimer scheduledTimerWithTimeInterval:1.0f
|
||||
target:self
|
||||
selector:@selector(updateStatsOverlay)
|
||||
userInfo:nil
|
||||
repeats:YES];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (void)connectionTerminated:(int)errorCode {
|
||||
Log(LOG_I, @"Connection terminated: %d", errorCode);
|
||||
|
||||
unsigned int portFlags = LiGetPortFlagsFromTerminationErrorCode(errorCode);
|
||||
unsigned int portTestResults = LiTestClientConnectivity(CONN_TEST_SERVER, 443, portFlags);
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
// Allow the display to go to sleep now
|
||||
[UIApplication sharedApplication].idleTimerDisabled = NO;
|
||||
|
||||
NSString* title;
|
||||
NSString* message;
|
||||
|
||||
if (portTestResults != ML_TEST_RESULT_INCONCLUSIVE && portTestResults != 0) {
|
||||
title = @"Connection Error";
|
||||
message = @"Your device's network connection is blocking Moonlight. Streaming may not work while connected to this network.";
|
||||
}
|
||||
else {
|
||||
switch (errorCode) {
|
||||
case ML_ERROR_GRACEFUL_TERMINATION:
|
||||
[self returnToMainFrame];
|
||||
return;
|
||||
|
||||
case ML_ERROR_NO_VIDEO_TRAFFIC:
|
||||
title = @"Connection Error";
|
||||
message = @"No video received from host.";
|
||||
if (portFlags != 0) {
|
||||
char failingPorts[256];
|
||||
LiStringifyPortFlags(portFlags, "\n", failingPorts, sizeof(failingPorts));
|
||||
message = [message stringByAppendingString:[NSString stringWithFormat:@"\n\nCheck your firewall and port forwarding rules for port(s):\n%s", failingPorts]];
|
||||
}
|
||||
break;
|
||||
|
||||
case ML_ERROR_NO_VIDEO_FRAME:
|
||||
title = @"Connection Error";
|
||||
message = @"Your network connection isn't performing well. Reduce your video bitrate setting or try a faster connection.";
|
||||
break;
|
||||
|
||||
case ML_ERROR_UNEXPECTED_EARLY_TERMINATION:
|
||||
case ML_ERROR_PROTECTED_CONTENT:
|
||||
title = @"Connection Error";
|
||||
message = @"Something went wrong on your host PC when starting the stream.\n\nMake sure you don't have any DRM-protected content open on your host PC. You can also try restarting your host PC.\n\nIf the issue persists, try reinstalling your GPU drivers and GeForce Experience.";
|
||||
break;
|
||||
|
||||
case ML_ERROR_FRAME_CONVERSION:
|
||||
title = @"Connection Error";
|
||||
message = @"The host PC reported a fatal video encoding error.\n\nTry disabling HDR mode, changing the streaming resolution, or changing your host PC's display resolution.";
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
NSString* errorString;
|
||||
if (abs(errorCode) > 1000) {
|
||||
// We'll assume large errors are hex values
|
||||
errorString = [NSString stringWithFormat:@"%08X", (uint32_t)errorCode];
|
||||
}
|
||||
else {
|
||||
// Smaller values will just be printed as decimal (probably errno.h values)
|
||||
errorString = [NSString stringWithFormat:@"%d", errorCode];
|
||||
}
|
||||
|
||||
title = @"Connection Terminated";
|
||||
message = [NSString stringWithFormat: @"The connection was terminated\n\nError code: %@", errorString];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UIAlertController* conTermAlert = [UIAlertController alertControllerWithTitle:title
|
||||
message:message
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[Utils addHelpOptionToDialog:conTermAlert];
|
||||
[conTermAlert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action){
|
||||
[self returnToMainFrame];
|
||||
}]];
|
||||
[self presentViewController:conTermAlert animated:YES completion:nil];
|
||||
});
|
||||
|
||||
[_streamMan stopStream];
|
||||
}
|
||||
|
||||
- (void) stageStarting:(const char*)stageName {
|
||||
Log(LOG_I, @"Starting %s", stageName);
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
NSString* lowerCase = [NSString stringWithFormat:@"%s in progress...", stageName];
|
||||
NSString* titleCase = [[[lowerCase substringToIndex:1] uppercaseString] stringByAppendingString:[lowerCase substringFromIndex:1]];
|
||||
[self->_stageLabel setText:titleCase];
|
||||
[self->_stageLabel sizeToFit];
|
||||
self->_stageLabel.center = CGPointMake(self.view.frame.size.width / 2, self->_stageLabel.center.y);
|
||||
});
|
||||
}
|
||||
|
||||
- (void) stageComplete:(const char*)stageName {
|
||||
}
|
||||
|
||||
- (void) stageFailed:(const char*)stageName withError:(int)errorCode portTestFlags:(int)portTestFlags {
|
||||
Log(LOG_I, @"Stage %s failed: %d", stageName, errorCode);
|
||||
|
||||
unsigned int portTestResults = LiTestClientConnectivity(CONN_TEST_SERVER, 443, portTestFlags);
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
// Allow the display to go to sleep now
|
||||
[UIApplication sharedApplication].idleTimerDisabled = NO;
|
||||
|
||||
NSString* message = [NSString stringWithFormat:@"%s failed with error %d", stageName, errorCode];
|
||||
if (portTestFlags != 0) {
|
||||
char failingPorts[256];
|
||||
LiStringifyPortFlags(portTestFlags, "\n", failingPorts, sizeof(failingPorts));
|
||||
message = [message stringByAppendingString:[NSString stringWithFormat:@"\n\nCheck your firewall and port forwarding rules for port(s):\n%s", failingPorts]];
|
||||
}
|
||||
if (portTestResults != ML_TEST_RESULT_INCONCLUSIVE && portTestResults != 0) {
|
||||
message = [message stringByAppendingString:@"\n\nYour device's network connection is blocking Moonlight. Streaming may not work while connected to this network."];
|
||||
}
|
||||
|
||||
UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Connection Failed"
|
||||
message:message
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[Utils addHelpOptionToDialog:alert];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action){
|
||||
[self returnToMainFrame];
|
||||
}]];
|
||||
[self presentViewController:alert animated:YES completion:nil];
|
||||
});
|
||||
|
||||
[_streamMan stopStream];
|
||||
}
|
||||
|
||||
- (void) launchFailed:(NSString*)message {
|
||||
Log(LOG_I, @"Launch failed: %@", message);
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
// Allow the display to go to sleep now
|
||||
[UIApplication sharedApplication].idleTimerDisabled = NO;
|
||||
|
||||
UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Connection Error"
|
||||
message:message
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[Utils addHelpOptionToDialog:alert];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action){
|
||||
[self returnToMainFrame];
|
||||
}]];
|
||||
[self presentViewController:alert animated:YES completion:nil];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)rumble:(unsigned short)controllerNumber lowFreqMotor:(unsigned short)lowFreqMotor highFreqMotor:(unsigned short)highFreqMotor {
|
||||
Log(LOG_I, @"Rumble on gamepad %d: %04x %04x", controllerNumber, lowFreqMotor, highFreqMotor);
|
||||
|
||||
[_controllerSupport rumble:controllerNumber lowFreqMotor:lowFreqMotor highFreqMotor:highFreqMotor];
|
||||
}
|
||||
|
||||
- (void) rumbleTriggers:(uint16_t)controllerNumber leftTrigger:(uint16_t)leftTrigger rightTrigger:(uint16_t)rightTrigger {
|
||||
Log(LOG_I, @"Trigger rumble on gamepad %d: %04x %04x", controllerNumber, leftTrigger, rightTrigger);
|
||||
|
||||
[_controllerSupport rumbleTriggers:controllerNumber leftTrigger:leftTrigger rightTrigger:rightTrigger];
|
||||
}
|
||||
|
||||
- (void) setMotionEventState:(uint16_t)controllerNumber motionType:(uint8_t)motionType reportRateHz:(uint16_t)reportRateHz {
|
||||
Log(LOG_I, @"Set motion state on gamepad %d: %02x %u Hz", controllerNumber, motionType, reportRateHz);
|
||||
|
||||
[_controllerSupport setMotionEventState:controllerNumber motionType:motionType reportRateHz:reportRateHz];
|
||||
}
|
||||
|
||||
- (void) setControllerLed:(uint16_t)controllerNumber r:(uint8_t)r g:(uint8_t)g b:(uint8_t)b {
|
||||
Log(LOG_I, @"Set controller LED on gamepad %d: l%02x%02x%02x", controllerNumber, r, g, b);
|
||||
|
||||
[_controllerSupport setControllerLed:controllerNumber r:r g:g b:b];
|
||||
}
|
||||
|
||||
- (void)connectionStatusUpdate:(int)status {
|
||||
Log(LOG_W, @"Connection status update: %d", status);
|
||||
|
||||
// The stats overlay takes precedence over these warnings
|
||||
if (_statsUpdateTimer != nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
switch (status) {
|
||||
case CONN_STATUS_OKAY:
|
||||
[self updateOverlayText:nil];
|
||||
break;
|
||||
|
||||
case CONN_STATUS_POOR:
|
||||
if (self->_streamConfig.bitRate > 5000) {
|
||||
[self updateOverlayText:@"Slow connection to PC\nReduce your bitrate"];
|
||||
}
|
||||
else {
|
||||
[self updateOverlayText:@"Poor connection to PC"];
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (void) updatePreferredDisplayMode:(BOOL)streamActive {
|
||||
#if TARGET_OS_TV
|
||||
if (@available(tvOS 11.2, *)) {
|
||||
UIWindow* window = [[[UIApplication sharedApplication] delegate] window];
|
||||
AVDisplayManager* displayManager = [window avDisplayManager];
|
||||
|
||||
// This logic comes from Kodi and MrMC
|
||||
if (streamActive) {
|
||||
int dynamicRange;
|
||||
|
||||
if (LiGetCurrentHostDisplayHdrMode()) {
|
||||
dynamicRange = 2; // HDR10
|
||||
}
|
||||
else {
|
||||
dynamicRange = 0; // SDR
|
||||
}
|
||||
|
||||
AVDisplayCriteria* displayCriteria = [[AVDisplayCriteria alloc] initWithRefreshRate:[_settings.framerate floatValue]
|
||||
videoDynamicRange:dynamicRange];
|
||||
displayManager.preferredDisplayCriteria = displayCriteria;
|
||||
}
|
||||
else {
|
||||
// Switch back to the default display mode
|
||||
displayManager.preferredDisplayCriteria = nil;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void) setHdrMode:(bool)enabled {
|
||||
Log(LOG_I, @"HDR is now: %s", enabled ? "active" : "inactive");
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self updatePreferredDisplayMode:YES];
|
||||
});
|
||||
}
|
||||
|
||||
- (void) videoContentShown {
|
||||
[_spinner stopAnimating];
|
||||
[self.view setBackgroundColor:[UIColor blackColor]];
|
||||
}
|
||||
|
||||
- (void)didReceiveMemoryWarning
|
||||
{
|
||||
[super didReceiveMemoryWarning];
|
||||
// Dispose of any resources that can be recreated.
|
||||
}
|
||||
|
||||
- (void)gamepadPresenceChanged {
|
||||
#if !TARGET_OS_TV
|
||||
if (@available(iOS 11.0, *)) {
|
||||
[self setNeedsUpdateOfHomeIndicatorAutoHidden];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)mousePresenceChanged {
|
||||
#if !TARGET_OS_TV
|
||||
if (@available(iOS 14.0, *)) {
|
||||
[self setNeedsUpdateOfPrefersPointerLocked];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void) streamExitRequested {
|
||||
Log(LOG_I, @"Gamepad combo requested stream exit");
|
||||
|
||||
[self returnToMainFrame];
|
||||
}
|
||||
|
||||
- (void)userInteractionBegan {
|
||||
// Disable hiding home bar when user is interacting.
|
||||
// iOS will force it to be shown anyway, but it will
|
||||
// also discard our edges deferring system gestures unless
|
||||
// we willingly give up home bar hiding preference.
|
||||
_userIsInteracting = YES;
|
||||
#if !TARGET_OS_TV
|
||||
if (@available(iOS 11.0, *)) {
|
||||
[self setNeedsUpdateOfHomeIndicatorAutoHidden];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)userInteractionEnded {
|
||||
// Enable home bar hiding again if conditions allow
|
||||
_userIsInteracting = NO;
|
||||
#if !TARGET_OS_TV
|
||||
if (@available(iOS 11.0, *)) {
|
||||
[self setNeedsUpdateOfHomeIndicatorAutoHidden];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
// Require a confirmation when streaming to activate a system gesture
|
||||
- (UIRectEdge)preferredScreenEdgesDeferringSystemGestures {
|
||||
return UIRectEdgeAll;
|
||||
}
|
||||
|
||||
- (BOOL)prefersHomeIndicatorAutoHidden {
|
||||
if ([_controllerSupport getConnectedGamepadCount] > 0 &&
|
||||
[_streamView getCurrentOscState] == OnScreenControlsLevelOff &&
|
||||
_userIsInteracting == NO) {
|
||||
// Autohide the home bar when a gamepad is connected
|
||||
// and the on-screen controls are disabled. We can't
|
||||
// do this all the time because any touch on the display
|
||||
// will cause the home indicator to reappear, and our
|
||||
// preferredScreenEdgesDeferringSystemGestures will also
|
||||
// be suppressed (leading to possible errant exits of the
|
||||
// stream).
|
||||
return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)shouldAutorotate {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)prefersPointerLocked {
|
||||
// Pointer lock breaks the UIKit mouse APIs, which is a problem because
|
||||
// GCMouse is horribly broken on iOS 14.0 for certain mice. Only lock
|
||||
// the cursor if there is a GCMouse present.
|
||||
return [GCMouse mice].count > 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
@end
|
||||
@@ -37,6 +37,25 @@
|
||||
84E1CDFA2C4FE83400547904 /* SwiftLocalizationHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E1CDF92C4FE83400547904 /* SwiftLocalizationHelper.swift */; };
|
||||
84FD0B512C31338D006B5BE5 /* LocalizationHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 84FD0B502C31338D006B5BE5 /* LocalizationHelper.m */; };
|
||||
84FD0B542C3134A6006B5BE5 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 84FD0B532C3134A6006B5BE5 /* Localizable.xcstrings */; };
|
||||
97E20DBF2E21637B000D5DCA /* SceneDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 97E20DBE2E21637B000D5DCA /* SceneDelegate.m */; };
|
||||
97E20DCF2E21647A000D5DCA /* Shaders.metal in Sources */ = {isa = PBXBuildFile; fileRef = 97E20DCD2E21647A000D5DCA /* Shaders.metal */; };
|
||||
97E20DD02E21647A000D5DCA /* MetalViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 97E20DCC2E21647A000D5DCA /* MetalViewController.m */; };
|
||||
97E20DD12E21647A000D5DCA /* MetalView.m in Sources */ = {isa = PBXBuildFile; fileRef = 97E20DCA2E21647A000D5DCA /* MetalView.m */; };
|
||||
97E20DD22E21647A000D5DCA /* MetalVideoRenderer.m in Sources */ = {isa = PBXBuildFile; fileRef = 97E20DC82E21647A000D5DCA /* MetalVideoRenderer.m */; };
|
||||
97E20DDF2E2164A9000D5DCA /* Frame.m in Sources */ = {isa = PBXBuildFile; fileRef = 97E20DD92E2164A9000D5DCA /* Frame.m */; };
|
||||
97E20DE02E2164A9000D5DCA /* FrameQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = 97E20DDB2E2164A9000D5DCA /* FrameQueue.m */; };
|
||||
97E20DE12E2164A9000D5DCA /* FloatBuffer.m in Sources */ = {isa = PBXBuildFile; fileRef = 97E20DD72E2164A9000D5DCA /* FloatBuffer.m */; };
|
||||
97E20DE22E2164A9000D5DCA /* PaddedLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = 97E20DDD2E2164A9000D5DCA /* PaddedLabel.m */; };
|
||||
97E20DE32E2164A9000D5DCA /* BandwidthTracker.m in Sources */ = {isa = PBXBuildFile; fileRef = 97E20DD52E2164A9000D5DCA /* BandwidthTracker.m */; };
|
||||
97E20DE72E216510000D5DCA /* ImGuiRenderer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 97E20DE62E216510000D5DCA /* ImGuiRenderer.mm */; };
|
||||
97E20DEA2E216532000D5DCA /* SceneDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 97E20DE92E216532000D5DCA /* SceneDelegate.m */; };
|
||||
97E20DEE2E2165A5000D5DCA /* ImGuiPlots.mm in Sources */ = {isa = PBXBuildFile; fileRef = 97E20DED2E2165A5000D5DCA /* ImGuiPlots.mm */; };
|
||||
97E21BB52E2186A3000D5DCA /* imgui_impl_metal.mm in Sources */ = {isa = PBXBuildFile; fileRef = 97E21BB32E2186A3000D5DCA /* imgui_impl_metal.mm */; };
|
||||
97E21BBF2E21882D000D5DCA /* imgui_tables.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 97E21BBD2E21882D000D5DCA /* imgui_tables.cpp */; };
|
||||
97E21BC02E21882D000D5DCA /* imgui_demo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 97E21BBA2E21882D000D5DCA /* imgui_demo.cpp */; };
|
||||
97E21BC12E21882D000D5DCA /* imgui_widgets.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 97E21BBE2E21882D000D5DCA /* imgui_widgets.cpp */; };
|
||||
97E21BC22E21882D000D5DCA /* imgui.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 97E21BB92E21882D000D5DCA /* imgui.cpp */; };
|
||||
97E21BC32E21882D000D5DCA /* imgui_draw.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 97E21BBB2E21882D000D5DCA /* imgui_draw.cpp */; };
|
||||
98181BE92791277400E43572 /* libSDL2.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 98181BE82791275D00E43572 /* libSDL2.a */; };
|
||||
98181BED2791281100E43572 /* CoreMotion.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 98181BEC2791281100E43572 /* CoreMotion.framework */; };
|
||||
9819CC14254F107A008A7C8E /* RelativeTouchHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 9819CC13254F107A008A7C8E /* RelativeTouchHandler.m */; };
|
||||
@@ -185,6 +204,43 @@
|
||||
84FD0B4F2C313343006B5BE5 /* LocalizationHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LocalizationHelper.h; sourceTree = "<group>"; };
|
||||
84FD0B502C31338D006B5BE5 /* LocalizationHelper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LocalizationHelper.m; sourceTree = "<group>"; };
|
||||
84FD0B532C3134A6006B5BE5 /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = "<group>"; };
|
||||
97E20DBD2E21637B000D5DCA /* SceneDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SceneDelegate.h; sourceTree = "<group>"; };
|
||||
97E20DBE2E21637B000D5DCA /* SceneDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SceneDelegate.m; sourceTree = "<group>"; };
|
||||
97E20DC62E21647A000D5DCA /* MetalConfig.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MetalConfig.h; sourceTree = "<group>"; };
|
||||
97E20DC72E21647A000D5DCA /* MetalVideoRenderer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MetalVideoRenderer.h; sourceTree = "<group>"; };
|
||||
97E20DC82E21647A000D5DCA /* MetalVideoRenderer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MetalVideoRenderer.m; sourceTree = "<group>"; };
|
||||
97E20DC92E21647A000D5DCA /* MetalView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MetalView.h; sourceTree = "<group>"; };
|
||||
97E20DCA2E21647A000D5DCA /* MetalView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MetalView.m; sourceTree = "<group>"; };
|
||||
97E20DCB2E21647A000D5DCA /* MetalViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MetalViewController.h; sourceTree = "<group>"; };
|
||||
97E20DCC2E21647A000D5DCA /* MetalViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MetalViewController.m; sourceTree = "<group>"; };
|
||||
97E20DCD2E21647A000D5DCA /* Shaders.metal */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.metal; path = Shaders.metal; sourceTree = "<group>"; };
|
||||
97E20DD42E2164A9000D5DCA /* BandwidthTracker.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BandwidthTracker.h; sourceTree = "<group>"; };
|
||||
97E20DD52E2164A9000D5DCA /* BandwidthTracker.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BandwidthTracker.m; sourceTree = "<group>"; };
|
||||
97E20DD62E2164A9000D5DCA /* FloatBuffer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FloatBuffer.h; sourceTree = "<group>"; };
|
||||
97E20DD72E2164A9000D5DCA /* FloatBuffer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FloatBuffer.m; sourceTree = "<group>"; };
|
||||
97E20DD82E2164A9000D5DCA /* Frame.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Frame.h; sourceTree = "<group>"; };
|
||||
97E20DD92E2164A9000D5DCA /* Frame.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Frame.m; sourceTree = "<group>"; };
|
||||
97E20DDA2E2164A9000D5DCA /* FrameQueue.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FrameQueue.h; sourceTree = "<group>"; };
|
||||
97E20DDB2E2164A9000D5DCA /* FrameQueue.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FrameQueue.m; sourceTree = "<group>"; };
|
||||
97E20DDC2E2164A9000D5DCA /* PaddedLabel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PaddedLabel.h; sourceTree = "<group>"; };
|
||||
97E20DDD2E2164A9000D5DCA /* PaddedLabel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PaddedLabel.m; sourceTree = "<group>"; };
|
||||
97E20DDE2E2164A9000D5DCA /* Plot.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Plot.h; sourceTree = "<group>"; };
|
||||
97E20DE52E2164EE000D5DCA /* ImGuiRenderer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ImGuiRenderer.h; sourceTree = "<group>"; };
|
||||
97E20DE62E216510000D5DCA /* ImGuiRenderer.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ImGuiRenderer.mm; sourceTree = "<group>"; };
|
||||
97E20DE82E216532000D5DCA /* SceneDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SceneDelegate.h; sourceTree = "<group>"; };
|
||||
97E20DE92E216532000D5DCA /* SceneDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SceneDelegate.m; sourceTree = "<group>"; };
|
||||
97E20DEC2E2165A0000D5DCA /* ImGuiPlots.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ImGuiPlots.h; sourceTree = "<group>"; };
|
||||
97E20DED2E2165A5000D5DCA /* ImGuiPlots.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ImGuiPlots.mm; sourceTree = "<group>"; };
|
||||
97E21BB32E2186A3000D5DCA /* imgui_impl_metal.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = imgui_impl_metal.mm; sourceTree = "<group>"; };
|
||||
97E21BB72E21882D000D5DCA /* imconfig.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = imconfig.h; path = third_party/imgui/imconfig.h; sourceTree = SOURCE_ROOT; };
|
||||
97E21BB82E21882D000D5DCA /* imgui.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = imgui.h; path = third_party/imgui/imgui.h; sourceTree = SOURCE_ROOT; };
|
||||
97E21BB92E21882D000D5DCA /* imgui.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = imgui.cpp; path = third_party/imgui/imgui.cpp; sourceTree = SOURCE_ROOT; };
|
||||
97E21BBA2E21882D000D5DCA /* imgui_demo.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_demo.cpp; path = third_party/imgui/imgui_demo.cpp; sourceTree = SOURCE_ROOT; };
|
||||
97E21BBB2E21882D000D5DCA /* imgui_draw.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_draw.cpp; path = third_party/imgui/imgui_draw.cpp; sourceTree = SOURCE_ROOT; };
|
||||
97E21BBC2E21882D000D5DCA /* imgui_internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = imgui_internal.h; path = third_party/imgui/imgui_internal.h; sourceTree = SOURCE_ROOT; };
|
||||
97E21BBD2E21882D000D5DCA /* imgui_tables.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_tables.cpp; path = third_party/imgui/imgui_tables.cpp; sourceTree = SOURCE_ROOT; };
|
||||
97E21BBE2E21882D000D5DCA /* imgui_widgets.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_widgets.cpp; path = third_party/imgui/imgui_widgets.cpp; sourceTree = SOURCE_ROOT; };
|
||||
97E21BC42E21883A000D5DCA /* imgui_impl_metal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = imgui_impl_metal.h; sourceTree = "<group>"; };
|
||||
9803CCAB254F9EAF00EE185E /* ConnectionCallbacks.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ConnectionCallbacks.h; sourceTree = "<group>"; };
|
||||
98181BE82791275D00E43572 /* libSDL2.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libSDL2.a; path = libs/SDL2/lib/iOS/libSDL2.a; sourceTree = "<group>"; };
|
||||
98181BEA2791278300E43572 /* libSDL2.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libSDL2.a; path = libs/SDL2/lib/tvOS/libSDL2.a; sourceTree = "<group>"; };
|
||||
@@ -403,6 +459,47 @@
|
||||
path = Localization;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
97E20DCE2E21647A000D5DCA /* Metal */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
97E20DC62E21647A000D5DCA /* MetalConfig.h */,
|
||||
97E20DC72E21647A000D5DCA /* MetalVideoRenderer.h */,
|
||||
97E20DC82E21647A000D5DCA /* MetalVideoRenderer.m */,
|
||||
97E20DC92E21647A000D5DCA /* MetalView.h */,
|
||||
97E20DCA2E21647A000D5DCA /* MetalView.m */,
|
||||
97E20DCB2E21647A000D5DCA /* MetalViewController.h */,
|
||||
97E20DCC2E21647A000D5DCA /* MetalViewController.m */,
|
||||
97E20DCD2E21647A000D5DCA /* Shaders.metal */,
|
||||
);
|
||||
path = Metal;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
97E20DEB2E21654B000D5DCA /* Stats */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
97E20DED2E2165A5000D5DCA /* ImGuiPlots.mm */,
|
||||
97E20DEC2E2165A0000D5DCA /* ImGuiPlots.h */,
|
||||
);
|
||||
path = Stats;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
97E21BB42E2186A3000D5DCA /* ImGui */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
97E21BC42E21883A000D5DCA /* imgui_impl_metal.h */,
|
||||
97E21BB72E21882D000D5DCA /* imconfig.h */,
|
||||
97E21BB82E21882D000D5DCA /* imgui.h */,
|
||||
97E21BB92E21882D000D5DCA /* imgui.cpp */,
|
||||
97E21BBA2E21882D000D5DCA /* imgui_demo.cpp */,
|
||||
97E21BBB2E21882D000D5DCA /* imgui_draw.cpp */,
|
||||
97E21BBC2E21882D000D5DCA /* imgui_internal.h */,
|
||||
97E21BBD2E21882D000D5DCA /* imgui_tables.cpp */,
|
||||
97E21BBE2E21882D000D5DCA /* imgui_widgets.cpp */,
|
||||
97E21BB32E2186A3000D5DCA /* imgui_impl_metal.mm */,
|
||||
);
|
||||
path = ImGui;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9896219423D15C2900211983 /* X1Kit */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -435,6 +532,7 @@
|
||||
FB290CE519B2C406004C83CF = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
97E21BB42E2186A3000D5DCA /* ImGui */,
|
||||
9896219423D15C2900211983 /* X1Kit */,
|
||||
98AB2E7F1CAD46830089BB98 /* moonlight-common.xcodeproj */,
|
||||
FB290CF919B2C406004C83CF /* VoidLink */,
|
||||
@@ -482,6 +580,12 @@
|
||||
FB290CF919B2C406004C83CF /* VoidLink */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
97E20DEB2E21654B000D5DCA /* Stats */,
|
||||
97E20DE82E216532000D5DCA /* SceneDelegate.h */,
|
||||
97E20DE92E216532000D5DCA /* SceneDelegate.m */,
|
||||
97E20DCE2E21647A000D5DCA /* Metal */,
|
||||
97E20DBD2E21637B000D5DCA /* SceneDelegate.h */,
|
||||
97E20DBE2E21637B000D5DCA /* SceneDelegate.m */,
|
||||
84D8EB932C5146AD00FC10A9 /* VoidLink-Bridging-Header.h */,
|
||||
84FD0B492C312C0B006B5BE5 /* Localization */,
|
||||
8454AC682C31907F00F0A302 /* iPad.storyboard */,
|
||||
@@ -516,6 +620,8 @@
|
||||
FB1D59981BBCCD7E00F482CA /* AppCollectionView.h */,
|
||||
FB1D59991BBCCD7E00F482CA /* AppCollectionView.m */,
|
||||
843E93BD2C41528700B1651F /* OrientationHelper.swift */,
|
||||
97E20DE62E216510000D5DCA /* ImGuiRenderer.mm */,
|
||||
97E20DE52E2164EE000D5DCA /* ImGuiRenderer.h */,
|
||||
);
|
||||
path = VoidLink;
|
||||
sourceTree = "<group>";
|
||||
@@ -616,6 +722,17 @@
|
||||
FB89461E19F646E200339C8A /* Utility */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
97E20DD42E2164A9000D5DCA /* BandwidthTracker.h */,
|
||||
97E20DD52E2164A9000D5DCA /* BandwidthTracker.m */,
|
||||
97E20DD62E2164A9000D5DCA /* FloatBuffer.h */,
|
||||
97E20DD72E2164A9000D5DCA /* FloatBuffer.m */,
|
||||
97E20DD82E2164A9000D5DCA /* Frame.h */,
|
||||
97E20DD92E2164A9000D5DCA /* Frame.m */,
|
||||
97E20DDA2E2164A9000D5DCA /* FrameQueue.h */,
|
||||
97E20DDB2E2164A9000D5DCA /* FrameQueue.m */,
|
||||
97E20DDC2E2164A9000D5DCA /* PaddedLabel.h */,
|
||||
97E20DDD2E2164A9000D5DCA /* PaddedLabel.m */,
|
||||
97E20DDE2E2164A9000D5DCA /* Plot.h */,
|
||||
FB89462119F646E200339C8A /* Utils.h */,
|
||||
FB89462219F646E200339C8A /* Utils.m */,
|
||||
FBD1C8E01A8AD69E00C6703C /* Logger.h */,
|
||||
@@ -859,8 +976,14 @@
|
||||
9819CC22254F180F008A7C8E /* AbsoluteTouchHandler.m in Sources */,
|
||||
9819CC14254F107A008A7C8E /* RelativeTouchHandler.m in Sources */,
|
||||
FB1A674D2131E65900507771 /* KeyboardSupport.m in Sources */,
|
||||
97E20DDF2E2164A9000D5DCA /* Frame.m in Sources */,
|
||||
97E20DE02E2164A9000D5DCA /* FrameQueue.m in Sources */,
|
||||
97E20DE12E2164A9000D5DCA /* FloatBuffer.m in Sources */,
|
||||
97E20DE22E2164A9000D5DCA /* PaddedLabel.m in Sources */,
|
||||
97E20DE32E2164A9000D5DCA /* BandwidthTracker.m in Sources */,
|
||||
84591A512BE1625E006AAB10 /* CustomEdgeSlideGestureRecognizer.m in Sources */,
|
||||
843CC7F62C1E7A1700BBC475 /* NativeTouchHandler.m in Sources */,
|
||||
97E20DEE2E2165A5000D5DCA /* ImGuiPlots.mm in Sources */,
|
||||
FB89463219F646E200339C8A /* VideoDecoderRenderer.m in Sources */,
|
||||
FB290D0419B2C406004C83CF /* AppDelegate.m in Sources */,
|
||||
FB9AFD401A7E127D00872C98 /* AppListResponse.m in Sources */,
|
||||
@@ -870,6 +993,11 @@
|
||||
FB9AFD321A7D867C00872C98 /* AppAssetRetriever.m in Sources */,
|
||||
843E93BE2C41528700B1651F /* OrientationHelper.swift in Sources */,
|
||||
FB4678FF1A565DAC00377732 /* WakeOnLanManager.m in Sources */,
|
||||
97E21BBF2E21882D000D5DCA /* imgui_tables.cpp in Sources */,
|
||||
97E21BC02E21882D000D5DCA /* imgui_demo.cpp in Sources */,
|
||||
97E21BC12E21882D000D5DCA /* imgui_widgets.cpp in Sources */,
|
||||
97E21BC22E21882D000D5DCA /* imgui.cpp in Sources */,
|
||||
97E21BC32E21882D000D5DCA /* imgui_draw.cpp in Sources */,
|
||||
84E1CDEC2C4F67D300547904 /* CommandManager.swift in Sources */,
|
||||
847D2FDB2DDA015F00937A62 /* MenuSectionView.m in Sources */,
|
||||
FB53E1431BE5DC4400CD6ECE /* IdManager.m in Sources */,
|
||||
@@ -882,7 +1010,9 @@
|
||||
FB89463019F646E200339C8A /* StreamConfiguration.m in Sources */,
|
||||
FBD3495319FF36FB002D2A60 /* SWRevealViewController.m in Sources */,
|
||||
84203F232C5F24C00032EEED /* OnScreenWidgetView.swift in Sources */,
|
||||
97E21BB52E2186A3000D5DCA /* imgui_impl_metal.mm in Sources */,
|
||||
84FD0B512C31338D006B5BE5 /* LocalizationHelper.m in Sources */,
|
||||
97E20DEA2E216532000D5DCA /* SceneDelegate.m in Sources */,
|
||||
FB1D59971BBCCB6400F482CA /* ComputerScrollView.m in Sources */,
|
||||
FBD3495019FF2174002D2A60 /* SettingsViewController.m in Sources */,
|
||||
843CC7F02C1E757D00BBC475 /* NativeTouchPointer.m in Sources */,
|
||||
@@ -905,8 +1035,13 @@
|
||||
84E1CDEF2C4F688E00547904 /* ToolboxViewController.swift in Sources */,
|
||||
844CD0EB2C7F8500004861A7 /* PureNativeTouchHandler.m in Sources */,
|
||||
84351B102C29ACCB00A77989 /* OSCProfile.m in Sources */,
|
||||
97E20DCF2E21647A000D5DCA /* Shaders.metal in Sources */,
|
||||
97E20DD02E21647A000D5DCA /* MetalViewController.m in Sources */,
|
||||
97E20DD12E21647A000D5DCA /* MetalView.m in Sources */,
|
||||
97E20DD22E21647A000D5DCA /* MetalVideoRenderer.m in Sources */,
|
||||
84351B2C2C29AD6100A77989 /* OSCProfilesTableViewController.m in Sources */,
|
||||
98D585701C0ED0E800F6CC00 /* TemporarySettings.m in Sources */,
|
||||
97E20DBF2E21637B000D5DCA /* SceneDelegate.m in Sources */,
|
||||
FB89462819F646E200339C8A /* CryptoManager.m in Sources */,
|
||||
DC1F5A07206436B20037755F /* ConnectionHelper.m in Sources */,
|
||||
FB89462E19F646E200339C8A /* PairManager.m in Sources */,
|
||||
@@ -921,6 +1056,7 @@
|
||||
FB89462A19F646E200339C8A /* ControllerSupport.m in Sources */,
|
||||
FB9AFD3D1A7E111600872C98 /* AppAssetResponse.m in Sources */,
|
||||
FBD349621A0089F6002D2A60 /* DataManager.m in Sources */,
|
||||
97E20DE72E216510000D5DCA /* ImGuiRenderer.mm in Sources */,
|
||||
FB4A23B81A9D3637004D2EF2 /* LoadingFrameViewController.m in Sources */,
|
||||
FB9AFD3A1A7E05CE00872C98 /* ServerInfoResponse.m in Sources */,
|
||||
84351B2B2C29AD6100A77989 /* LayoutOnScreenControlsViewController.m in Sources */,
|
||||
@@ -1112,6 +1248,7 @@
|
||||
"$(PROJECT_DIR)/Limelight/ViewControllers/CustomOSCViewControl/Cells",
|
||||
"$(PROJECT_DIR)/Limelight/Input",
|
||||
"$(PROJECT_DIR)/Limelight/Localization",
|
||||
"$(PROJECT_DIR)/third_party/imgui",
|
||||
"$(PROJECT_DIR)/Limelight/Database",
|
||||
);
|
||||
INFOPLIST_FILE = "VoidLink/Limelight-Info.plist";
|
||||
@@ -1122,6 +1259,11 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/third_party/imgui/examples/libs/glfw/lib-vc2010-32",
|
||||
"$(PROJECT_DIR)/third_party/imgui/examples/libs/glfw/lib-vc2010-64",
|
||||
);
|
||||
"LIBRARY_SEARCH_PATHS[sdk=iphoneos*]" = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/libs/opus/lib/iOS",
|
||||
@@ -1171,6 +1313,7 @@
|
||||
"$(PROJECT_DIR)/Limelight/ViewControllers/CustomOSCViewControl/Cells",
|
||||
"$(PROJECT_DIR)/Limelight/Input",
|
||||
"$(PROJECT_DIR)/Limelight/Localization",
|
||||
"$(PROJECT_DIR)/third_party/imgui",
|
||||
"$(PROJECT_DIR)/Limelight/Database",
|
||||
);
|
||||
INFOPLIST_FILE = "VoidLink/Limelight-Info.plist";
|
||||
@@ -1181,6 +1324,11 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/third_party/imgui/examples/libs/glfw/lib-vc2010-32",
|
||||
"$(PROJECT_DIR)/third_party/imgui/examples/libs/glfw/lib-vc2010-64",
|
||||
);
|
||||
"LIBRARY_SEARCH_PATHS[sdk=iphoneos*]" = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/libs/opus/lib/iOS",
|
||||
|
||||
@@ -78,14 +78,17 @@ typedef NS_ENUM(NSInteger, SettingsMenuMode) {
|
||||
useFramePacing:(BOOL)useFramePacing
|
||||
enableHdr:(BOOL)enableHdr
|
||||
btMouseSupport:(BOOL)btMouseSupport
|
||||
// absoluteTouchMode:(BOOL)absoluteTouchMode
|
||||
touchMode:(NSInteger)touchMode
|
||||
statsOverlayLevel:(NSInteger)statsOverlayLevel
|
||||
statsOverlayEnabled:(BOOL)statsOverlayEnabled
|
||||
unlockDisplayOrientation:(BOOL)unlockDisplayOrientation
|
||||
resolutionSelected:(NSInteger)resolutionSelected
|
||||
externalDisplayMode:(NSInteger)externalDisplayMode
|
||||
localMousePointerMode:(NSInteger)localMousePointerMode;
|
||||
localMousePointerMode:(NSInteger)localMousePointerMode
|
||||
frameQueueSize:(NSInteger)frameQueueSize
|
||||
enableGraphs:(BOOL)enableGraphs
|
||||
graphOpacity:(NSInteger)graphOpacity
|
||||
renderingBackend:(NSInteger)renderingBackend;
|
||||
|
||||
- (NSArray*) getHosts;
|
||||
- (void) updateHost:(TemporaryHost*)host;
|
||||
|
||||
@@ -82,20 +82,16 @@
|
||||
preferredCodec:(uint32_t)preferredCodec
|
||||
enableYUV444:(BOOL)enableYUV444
|
||||
useFramePacing:(BOOL)useFramePacing
|
||||
frameQueueSize:(NSInteger)frameQueueSize
|
||||
enableHdr:(BOOL)enableHdr
|
||||
btMouseSupport:(BOOL)btMouseSupport
|
||||
// absoluteTouchMode:(BOOL)absoluteTouchMode
|
||||
touchMode:(NSInteger)touchMode
|
||||
statsOverlayLevel:(NSInteger)statsOverlayLevel
|
||||
statsOverlayEnabled:(BOOL)statsOverlayEnabled
|
||||
unlockDisplayOrientation:(BOOL)unlockDisplayOrientation
|
||||
resolutionSelected:(NSInteger)resolutionSelected
|
||||
externalDisplayMode:(NSInteger)externalDisplayMode
|
||||
localMousePointerMode:(NSInteger)localMousePointerMode{
|
||||
|
||||
absoluteTouchMode:(BOOL)absoluteTouchMode
|
||||
statsOverlay:(BOOL)statsOverlay
|
||||
localMousePointerMode:(NSInteger)localMousePointerMode
|
||||
frameQueueSize:(NSInteger)frameQueueSize
|
||||
enableGraphs:(BOOL)enableGraphs
|
||||
graphOpacity:(NSInteger)graphOpacity
|
||||
renderingBackend:(NSInteger)renderingBackend
|
||||
@@ -128,7 +124,6 @@
|
||||
settingsToSave.playAudioOnPC = audioOnPC;
|
||||
settingsToSave.preferredCodec = preferredCodec;
|
||||
settingsToSave.enableYUV444 = enableYUV444;
|
||||
settingsToSave.frameQueueSize = [NSNumber numberWithInteger:frameQueueSize];
|
||||
settingsToSave.enableHdr = enableHdr;
|
||||
settingsToSave.btMouseSupport = btMouseSupport;
|
||||
// settingsToSave.absoluteTouchMode = absoluteTouchMode;
|
||||
@@ -139,8 +134,8 @@
|
||||
settingsToSave.resolutionSelected = [NSNumber numberWithInteger:resolutionSelected];
|
||||
settingsToSave.externalDisplayMode = [NSNumber numberWithInteger:externalDisplayMode];
|
||||
settingsToSave.localMousePointerMode = [NSNumber numberWithInteger:localMousePointerMode];
|
||||
settingsToSave.absoluteTouchMode = absoluteTouchMode;
|
||||
settingsToSave.statsOverlay = statsOverlay;
|
||||
|
||||
settingsToSave.frameQueueSize = [NSNumber numberWithInteger:frameQueueSize];
|
||||
settingsToSave.enableGraphs = enableGraphs;
|
||||
settingsToSave.graphOpacity = [NSNumber numberWithInteger:graphOpacity];
|
||||
settingsToSave.renderingBackend = [NSNumber numberWithInteger:renderingBackend];
|
||||
|
||||
@@ -62,6 +62,10 @@
|
||||
@property (nonatomic) BOOL liftStreamViewForKeyboard;
|
||||
@property (nonatomic) BOOL showKeyboardToolbar;
|
||||
@property (nonatomic) BOOL unlockDisplayOrientation;
|
||||
@property (nonatomic) BOOL enableGraphs;
|
||||
@property (nonatomic, retain) NSNumber * frameQueueSize;
|
||||
@property (nonatomic, retain) NSNumber * graphOpacity;
|
||||
@property (nonatomic, retain) NSNumber * renderingBackend;
|
||||
|
||||
- (id) initFromSettings:(Settings*)settings;
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
//
|
||||
// ImGuiRenderer 2.h
|
||||
// VoidLink
|
||||
//
|
||||
// Created by Mason Chen on 2025/7/11.
|
||||
// Copyright © 2025 Moonlight Game Streaming Project. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <Metal/Metal.h>
|
||||
#import <MetalKit/MetalKit.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "FloatBuffer.h"
|
||||
#import "Plot.h"
|
||||
|
||||
typedef void (^MetricsHandler)(int plotId, CFTimeInterval value);
|
||||
|
||||
@interface ImGuiRenderer : UIViewController
|
||||
@end
|
||||
|
||||
@interface ImGuiRenderer () <MTKViewDelegate>
|
||||
@property (nonatomic) CGRect bounds;
|
||||
@property (nonatomic, readonly) MTKView * _Nonnull mtkView;
|
||||
@property (nonatomic, strong) id <MTLDevice> _Nonnull device;
|
||||
@property (nonatomic, strong) id <MTLCommandQueue> _Nonnull commandQueue;
|
||||
@property (nonatomic) struct PlotDef * _Nonnull plots;
|
||||
@property (nonatomic) FloatBuffer * _Nonnull frametimes;
|
||||
@property (nonatomic) BOOL enableGraphs;
|
||||
@property (nonatomic) float graphOpacity;
|
||||
@property (nonatomic) BOOL imguiRunning;
|
||||
@property (nonatomic) MetricsHandler _Nonnull metricsHandler;
|
||||
|
||||
-(nonnull instancetype) initWithFrame:(CGRect)bounds
|
||||
streamFps:(int)streamFps
|
||||
enableGraphs:(BOOL)enableGraphs
|
||||
graphOpacity:(int)graphOpacity;
|
||||
-(void) start;
|
||||
-(void) show;
|
||||
-(void) hide;
|
||||
-(void) stop;
|
||||
-(void) observeFloat:(int)plotId value:(CFTimeInterval)value;
|
||||
-(void) observeFloatReturnMetrics:(int)plotId value:(CFTimeInterval)value plotMetrics:(PlotMetrics * _Nullable)plotMetrics;
|
||||
@end
|
||||
@@ -1,3 +1,12 @@
|
||||
//
|
||||
// ImGuiRenderer.m
|
||||
// VoidLink
|
||||
//
|
||||
// Created by Mason Chen on 2025/7/11.
|
||||
// Copyright © 2025 Moonlight Game Streaming Project. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
#import <Metal/Metal.h>
|
||||
#import "ImGuiRenderer.h"
|
||||
@@ -54,8 +54,9 @@
|
||||
<attribute name="showKeyboardToolbar" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES" syncable="YES"/>
|
||||
<attribute name="slideToSettingsDistance" optional="YES" attributeType="Float" defaultValueString="0.25" usesScalarValueType="NO" syncable="YES"/>
|
||||
<attribute name="slideToSettingsScreenEdge" optional="YES" attributeType="Integer 32" defaultValueString="2" usesScalarValueType="NO" syncable="YES"/>
|
||||
<attribute name="statsOverlayEnabled" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES" syncable="YES"/>
|
||||
<attribute name="statsOverlayLevel" optional="YES" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="NO" syncable="YES"/>
|
||||
<attribute name="renderingBackend" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="NO" syncable="YES"/>
|
||||
<attribute name="statsOverlay" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES" syncable="YES"/>
|
||||
<attribute name="swapABXYButtons" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES" syncable="YES"/>
|
||||
<attribute name="touchMode" optional="YES" attributeType="Integer 16" defaultValueString="1" usesScalarValueType="NO" syncable="YES"/>
|
||||
<attribute name="touchMoveEventInterval" optional="YES" attributeType="Integer 16" defaultValueString="320" usesScalarValueType="NO" syncable="YES"/>
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
//
|
||||
// MetalConfig.h
|
||||
// VoidLink
|
||||
//
|
||||
// Created by Mason Chen on 2025/7/11.
|
||||
// Copyright © 2025 Moonlight Game Streaming Project. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
// When enabled, rendering occurs on the main application thread.
|
||||
// This can make responding to UI events during redraw simpler
|
||||
// to manage because UI calls usually need to occur on the main thread.
|
||||
@@ -1,3 +1,12 @@
|
||||
//
|
||||
// MetalVideoRenderer.h
|
||||
// VoidLink
|
||||
//
|
||||
// Created by Mason Chen on 2025/7/11.
|
||||
// Copyright © 2025 Moonlight Game Streaming Project. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
#import <QuartzCore/CAMetalLayer.h>
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
#import "ConnectionCallbacks.h"
|
||||
@@ -1,3 +1,12 @@
|
||||
//
|
||||
// MetalVideoRenderer.m
|
||||
// VoidLink
|
||||
//
|
||||
// Created by Mason Chen on 2025/7/11.
|
||||
// Copyright © 2025 Moonlight Game Streaming Project. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
#import "MetalVideoRenderer.h"
|
||||
#import <CoreVideo/CoreVideo.h>
|
||||
#import <Metal/Metal.h>
|
||||
@@ -1,3 +1,12 @@
|
||||
//
|
||||
// MetalView.h
|
||||
// VoidLink
|
||||
//
|
||||
// Created by Mason Chen on 2025/7/11.
|
||||
// Copyright © 2025 Moonlight Game Streaming Project. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
#import <Metal/Metal.h>
|
||||
#import <QuartzCore/CAMetalDisplayLink.h>
|
||||
#import <QuartzCore/CAMetalLayer.h>
|
||||
@@ -1,3 +1,12 @@
|
||||
//
|
||||
// MetalView.m
|
||||
// VoidLink
|
||||
//
|
||||
// Created by Mason Chen on 2025/7/11.
|
||||
// Copyright © 2025 Moonlight Game Streaming Project. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
// This is based on the following Apple example:
|
||||
// https://developer.apple.com/documentation/metal/achieving-smooth-frame-rates-with-a-metal-display-link?language=objc
|
||||
// https://developer.apple.com/wwdc23/10123/
|
||||
@@ -1,3 +1,12 @@
|
||||
//
|
||||
// MetalViewController.h
|
||||
// VoidLink
|
||||
//
|
||||
// Created by Mason Chen on 2025/7/11.
|
||||
// Copyright © 2025 Moonlight Game Streaming Project. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
#import <Metal/Metal.h>
|
||||
#import "FrameQueue.h"
|
||||
#import "ImGuiRenderer.h"
|
||||
@@ -1,3 +1,12 @@
|
||||
//
|
||||
// MetalViewController.m
|
||||
// VoidLink
|
||||
//
|
||||
// Created by Mason Chen on 2025/7/11.
|
||||
// Copyright © 2025 Moonlight Game Streaming Project. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
/*
|
||||
See the LICENSE.txt file for this sample’s licensing information.
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
//
|
||||
// Vertex.swift
|
||||
// VoidLink
|
||||
//
|
||||
// Created by Mason Chen on 2025/7/11.
|
||||
// Copyright © 2025 Moonlight Game Streaming Project. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
#include <metal_stdlib>
|
||||
#include <simd/simd.h>
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface SceneDelegate : UIResponder <UIWindowSceneDelegate>
|
||||
|
||||
@property (strong, nonatomic) UIWindow * window;
|
||||
|
||||
+ (void)setExternalDisplayRenderView:(UIView *)renderView;
|
||||
+ (void)clearExternalDisplayRenderView;
|
||||
- (void)updatePreferredDisplayMode:(BOOL)streamActive withRenderView:(UIView *)renderView;
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
#import "SceneDelegate.h"
|
||||
#import "StreamFrameViewController.h"
|
||||
|
||||
@implementation SceneDelegate
|
||||
|
||||
static UIView *_sharedStreamVideoRenderView = nil;
|
||||
static UIWindow *_externalSceneWindow = nil;
|
||||
|
||||
- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
|
||||
if (![scene isKindOfClass:[UIWindowScene class]]) {
|
||||
return;
|
||||
}
|
||||
UIWindowScene *windowScene = (UIWindowScene *)scene;
|
||||
if ([session.role isEqualToString:UIWindowSceneSessionRoleApplication]) {
|
||||
self.window = [[UIWindow alloc] initWithWindowScene:windowScene];
|
||||
NSString *storyboardName;
|
||||
if (UIDevice.currentDevice.userInterfaceIdiom == UIUserInterfaceIdiomPad) {
|
||||
storyboardName = @"iPad";
|
||||
} else {
|
||||
storyboardName = @"iPhone";
|
||||
}
|
||||
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:storyboardName bundle:nil];
|
||||
UIViewController *initialViewController = [storyboard instantiateInitialViewController];
|
||||
self.window.rootViewController = initialViewController;
|
||||
[self.window makeKeyAndVisible];
|
||||
Log(LOG_I, @"SceneDelegate: Main app scene connected.");
|
||||
|
||||
} else if ([session.role isEqualToString:UIWindowSceneSessionRoleExternalDisplay]) {
|
||||
Log(LOG_I, @"SceneDelegate: External display scene connecting for screen: %@", ((UIWindowScene *)scene).screen.description);
|
||||
UIWindowScene *windowScene = (UIWindowScene *)scene;
|
||||
_externalSceneWindow = [[UIWindow alloc] initWithWindowScene:windowScene];
|
||||
UIViewController *externalVC = [[UIViewController alloc] init];
|
||||
externalVC.view.backgroundColor = [UIColor blackColor]; // Set a default background
|
||||
_externalSceneWindow.rootViewController = externalVC;
|
||||
|
||||
if (_sharedStreamVideoRenderView) {
|
||||
_sharedStreamVideoRenderView.frame = _externalSceneWindow.bounds;
|
||||
[_externalSceneWindow.rootViewController.view addSubview:_sharedStreamVideoRenderView];
|
||||
Log(LOG_I, @"SceneDelegate: External display scene connected.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Method for StreamFrameViewController to provide its render view
|
||||
+ (void)setExternalDisplayRenderView:(UIView *)renderView {
|
||||
_sharedStreamVideoRenderView = renderView;
|
||||
if (_externalSceneWindow && _externalSceneWindow.rootViewController && _sharedStreamVideoRenderView) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
// Ensure it's removed from any previous parent (should have been done by StreamFrameVC)
|
||||
[_sharedStreamVideoRenderView removeFromSuperview];
|
||||
_sharedStreamVideoRenderView.frame = _externalSceneWindow.bounds; // Set frame for external window
|
||||
[_externalSceneWindow.rootViewController.view addSubview:_sharedStreamVideoRenderView];
|
||||
_externalSceneWindow.hidden = NO;
|
||||
Log(LOG_I, @"SceneDelegate: Added render view to external window's root view.");
|
||||
});
|
||||
} else {
|
||||
Log(LOG_E, @"SceneDelegate: External display window or root view controller not available.");
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)clearExternalDisplayRenderView {
|
||||
if (_sharedStreamVideoRenderView) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[_sharedStreamVideoRenderView removeFromSuperview];
|
||||
Log(LOG_I, @"SceneDelegate: Removed render view from external display.");
|
||||
});
|
||||
}
|
||||
_sharedStreamVideoRenderView = nil;
|
||||
}
|
||||
|
||||
- (void)sceneDidDisconnect:(UIScene *)scene {
|
||||
Log(LOG_I, @"SceneDelegate: Scene disconnected: %@, role: %@", scene.title, scene.session.role);
|
||||
|
||||
if ([scene.session.role isEqualToString:UIWindowSceneSessionRoleExternalDisplay]) {
|
||||
if ([scene isKindOfClass:[UIWindowScene class]]) {
|
||||
UIWindowScene *windowScene = (UIWindowScene *)scene;
|
||||
if (_externalSceneWindow == windowScene.windows.firstObject) { // Compare with the window from the disconnecting scene
|
||||
[SceneDelegate clearExternalDisplayRenderView]; // Clears the shared view
|
||||
_externalSceneWindow = nil;
|
||||
Log(LOG_I, @"SceneDelegate: External display scene fully disconnected and cleaned up.");
|
||||
} else {
|
||||
Log(LOG_W, @"SceneDelegate: Disconnecting scene is not the one holding our _externalSceneWindow.");
|
||||
}
|
||||
} else {
|
||||
Log(LOG_W, @"SceneDelegate: Disconnecting scene is not a UIWindowScene.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,3 +1,12 @@
|
||||
//
|
||||
// ImGuiPlots.h
|
||||
// VoidLink
|
||||
//
|
||||
// Created by Mason Chen on 2025/7/11.
|
||||
// Copyright © 2025 Moonlight Game Streaming Project. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <VideoToolbox/VideoToolbox.h>
|
||||
|
||||
@@ -18,6 +18,6 @@
|
||||
|
||||
- (void) stopStream;
|
||||
|
||||
- (NSString*) getStatsOverlayText: (uint16_t) overlayLevel;
|
||||
- (NSString*) getStatsOverlayText;
|
||||
|
||||
@end
|
||||
|
||||
@@ -152,11 +152,9 @@
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
- (NSString*) getStatsOverlayText: (uint16_t) overlayLevel {
|
||||
- (NSString*) getStatsOverlayText {
|
||||
video_stats_t stats;
|
||||
|
||||
// NSLog(@"overlayLevel: %d", overlayLevel);
|
||||
|
||||
if (!_connection) {
|
||||
return nil;
|
||||
}
|
||||
@@ -168,16 +166,15 @@
|
||||
uint32_t rtt, variance;
|
||||
NSString* latencyString;
|
||||
if (LiGetEstimatedRttInfo(&rtt, &variance)) {
|
||||
latencyString = [LocalizationHelper localizedStringForKey:@"%u ms (variance: %u ms)", rtt, variance];
|
||||
latencyString = [NSString stringWithFormat:@"%u ms (variance: %u ms)", rtt, variance];
|
||||
}
|
||||
else {
|
||||
latencyString = @"N/A";
|
||||
}
|
||||
|
||||
NSString* hostProcessingString;
|
||||
// overlayLevel 2: detailed
|
||||
if (stats.framesWithHostProcessingLatency != 0) {
|
||||
hostProcessingString = [LocalizationHelper localizedStringForKey:@"\nHost processing latency min/max/avg: %.1f/%.1f/%.1f ms",
|
||||
hostProcessingString = [NSString stringWithFormat:@"Host processing latency min/max/avg: %.1f/%.1f/%.1f ms\n",
|
||||
stats.minHostProcessingLatency / 10.f,
|
||||
stats.maxHostProcessingLatency / 10.f,
|
||||
(float)stats.totalHostProcessingLatency / stats.framesWithHostProcessingLatency / 10.f];
|
||||
@@ -188,13 +185,12 @@
|
||||
}
|
||||
|
||||
float interval = stats.endTime - stats.startTime;
|
||||
if(overlayLevel == 2) return [LocalizationHelper localizedStringForKey:@"Video stream: %dx%d %.2f FPS (Codec: %@)\nNetwork dropped frames: %.2f%%\nAverage network latency: %@%@",
|
||||
float scalePlotMetrics = stats.frameDropMetrics.nsamples > 0 ? ((float)stats.frameDropMetrics.nsamples / stats.totalFrames) : 1.0f;
|
||||
float fps = (stats.totalFrames - stats.networkDroppedFrames - (stats.frameDropMetrics.total / scalePlotMetrics)) / interval;
|
||||
|
||||
|
||||
double avgVideoMbps = [_connection getBwTracker].averageMbps;
|
||||
double peakVideoMbps = [_connection getBwTracker].peakMbps;
|
||||
|
||||
|
||||
return [NSString stringWithFormat:@"Video stream: %dx%d %.2f FPS (Codec: %@)\n"
|
||||
"Bitrate: %.1f Mbps, Peak: %.1f, Renderer: %@\n"
|
||||
"%@"
|
||||
@@ -212,11 +208,6 @@
|
||||
(stats.networkDroppedFrames / stats.totalFrames) * 100.0,
|
||||
stats.frameDropMetrics.nsamples > 0 ? (stats.frameDropMetrics.total / stats.frameDropMetrics.nsamples) * 100.0 : 0.0f,
|
||||
latencyString,
|
||||
hostProcessingString];
|
||||
else return [LocalizationHelper localizedStringForKey:@"FPS: %5.2f Network dropped frames: %.2f%% Network latency: %@",
|
||||
stats.totalFrames / interval,
|
||||
stats.networkDroppedFrames / interval,
|
||||
latencyString];
|
||||
stats.decodeMetrics.min, stats.decodeMetrics.max, stats.decodeMetrics.avg];
|
||||
}
|
||||
|
||||
|
||||
@@ -106,6 +106,14 @@
|
||||
@property (strong, nonatomic) IBOutlet UIStackView *audioConfigStack;
|
||||
@property (strong, nonatomic) IBOutlet UISegmentedControl *audioConfigSelector;
|
||||
|
||||
@property (strong, nonatomic) IBOutlet UILabel *frameQueueSizeLabel;
|
||||
@property (strong, nonatomic) IBOutlet UISlider *frameQueueSizeSlider;
|
||||
|
||||
@property (strong, nonatomic) IBOutlet UILabel *enableGraphsLabel;
|
||||
@property (strong, nonatomic) IBOutlet UISwitch *enableGraphsSwitch;
|
||||
@property (strong, nonatomic) IBOutlet UIStepper *graphOpacityStepper;
|
||||
@property (strong, nonatomic) IBOutlet UISegmentedControl *renderingBackendSelector;
|
||||
|
||||
|
||||
|
||||
#pragma clang diagnostic push
|
||||
|
||||
@@ -37,6 +37,8 @@
|
||||
CGFloat _currentRefreshRate;
|
||||
MenuSectionView *touchControlSection;
|
||||
NSMutableSet* hiddenStacks;
|
||||
NSInteger _frameQueueSize;
|
||||
NSInteger _graphOpacity;
|
||||
}
|
||||
|
||||
@dynamic overrideUserInterfaceStyle;
|
||||
@@ -147,7 +149,7 @@ static const int bitrateTable[] = {
|
||||
500000,
|
||||
};
|
||||
|
||||
const int RESOLUTION_TABLE_SIZE = 6;
|
||||
const int RESOLUTION_TABLE_SIZE = 7;
|
||||
const int RESOLUTION_TABLE_CUSTOM_INDEX = RESOLUTION_TABLE_SIZE - 1;
|
||||
CGSize resolutionTable[RESOLUTION_TABLE_SIZE];
|
||||
|
||||
@@ -1149,6 +1151,8 @@ BOOL isCustomResolution(CGSize res) {
|
||||
|
||||
// Ensure we pick a bitrate that falls exactly onto a slider notch
|
||||
_bitrate = bitrateTable[[self getSliderValueForBitrate:[currentSettings.bitrate intValue]]];
|
||||
_frameQueueSize = [currentSettings.frameQueueSize intValue];
|
||||
_graphOpacity = [currentSettings.graphOpacity intValue];
|
||||
|
||||
// Get the size of the screen with and without safe area insets
|
||||
UIWindow *window = UIApplication.sharedApplication.windows.firstObject;
|
||||
@@ -1162,10 +1166,11 @@ BOOL isCustomResolution(CGSize res) {
|
||||
|
||||
resolutionTable[0] = CGSizeMake(1280, 720);
|
||||
resolutionTable[1] = CGSizeMake(1920, 1080);
|
||||
resolutionTable[2] = CGSizeMake(3840, 2160);
|
||||
resolutionTable[3] = CGSizeMake(safeAreaWidth, fullScreenHeight);
|
||||
resolutionTable[4] = CGSizeMake(fullScreenWidth, fullScreenHeight);
|
||||
resolutionTable[5] = CGSizeMake([currentSettings.width integerValue], [currentSettings.height integerValue]); // custom initial value
|
||||
resolutionTable[2] = CGSizeMake(2560, 1440);
|
||||
resolutionTable[3] = CGSizeMake(3840, 2160);
|
||||
resolutionTable[4] = CGSizeMake(safeAreaWidth, fullScreenHeight);
|
||||
resolutionTable[5] = CGSizeMake(fullScreenWidth, fullScreenHeight);
|
||||
resolutionTable[6] = CGSizeMake([currentSettings.width integerValue], [currentSettings.height integerValue]); // custom initial value
|
||||
[self updateResolutionTable];
|
||||
|
||||
// Don't populate the custom entry unless we have a custom resolution
|
||||
@@ -1183,9 +1188,12 @@ BOOL isCustomResolution(CGSize res) {
|
||||
case 60:
|
||||
framerate = 1;
|
||||
break;
|
||||
case 120:
|
||||
case 90:
|
||||
framerate = 2;
|
||||
break;
|
||||
case 120:
|
||||
framerate = 3;
|
||||
break;
|
||||
}
|
||||
|
||||
NSInteger resolution = currentSettings.resolutionSelected.integerValue;
|
||||
@@ -1246,6 +1254,10 @@ BOOL isCustomResolution(CGSize res) {
|
||||
|
||||
[self.yuv444Switch setOn:currentSettings.enableYUV444];
|
||||
[self.statsOverlaySelector setSelectedSegmentIndex:currentSettings.statsOverlayLevel.intValue];
|
||||
|
||||
NSInteger renderingBackend = [currentSettings.renderingBackend integerValue];
|
||||
[self.renderingBackendSelector setSelectedSegmentIndex:renderingBackend];
|
||||
|
||||
[self.citrixX1MouseSwitch setOn:currentSettings.btMouseSupport];
|
||||
[self.optimizeGamesSwitch setOn: currentSettings.optimizeGames];
|
||||
[self.framePacingSelector setSelectedSegmentIndex:currentSettings.useFramePacing ? 1 : 0];
|
||||
@@ -1274,6 +1286,21 @@ BOOL isCustomResolution(CGSize res) {
|
||||
[self.bitrateSlider addTarget:self action:@selector(bitrateSliderMoved) forControlEvents:UIControlEventValueChanged];
|
||||
[self updateBitrateText];
|
||||
[self updateResolutionDisplayLabel];
|
||||
|
||||
[self.frameQueueSizeSlider setMinimumValue:1];
|
||||
[self.frameQueueSizeSlider setMaximumValue:5];
|
||||
[self.frameQueueSizeSlider setValue:_frameQueueSize];
|
||||
[self.frameQueueSizeSlider addTarget:self action:@selector(frameQueueSizeSliderMoved) forControlEvents:UIControlEventValueChanged];
|
||||
[self updateFrameQueueSizeText];
|
||||
|
||||
[self.enableGraphsSwitch addTarget:self action:@selector(enableGraphsChanged) forControlEvents:UIControlEventValueChanged];
|
||||
[self enableGraphsChanged];
|
||||
[self.graphOpacityStepper setMinimumValue:0];
|
||||
[self.graphOpacityStepper setMaximumValue:100];
|
||||
[self.graphOpacityStepper setValue:_graphOpacity];
|
||||
[self.graphOpacityStepper addTarget:self action:@selector(graphOpacityStepperMoved) forControlEvents:UIControlEventValueChanged];
|
||||
[self updateGraphOpacityText];
|
||||
|
||||
if (@available(iOS 18.0, tvOS 18.0, *)) {}else{
|
||||
[self.audioConfigSelector removeSegmentAtIndex:1 animated:false];
|
||||
[self.audioConfigSelector removeSegmentAtIndex:1 animated:false]; // segment 2 goes away when you remove index 2
|
||||
@@ -1808,6 +1835,8 @@ BOOL isCustomResolution(CGSize res) {
|
||||
case 1:
|
||||
return 60;
|
||||
case 2:
|
||||
return 90;
|
||||
case 3:
|
||||
return 120;
|
||||
default:
|
||||
abort();
|
||||
@@ -1926,25 +1955,50 @@ BOOL isCustomResolution(CGSize res) {
|
||||
}
|
||||
}
|
||||
|
||||
- (void) frameQueueSizeSliderMoved {
|
||||
assert(self.frameQueueSizeSlider.value >= 0 && self.frameQueueSizeSlider.value <= 5);
|
||||
_frameQueueSize = (int)self.frameQueueSizeSlider.value;
|
||||
[self updateFrameQueueSizeText];
|
||||
}
|
||||
|
||||
- (void) updateFrameQueueSizeText {
|
||||
[self.frameQueueSizeLabel setText:[NSString stringWithFormat:@"Frames to buffer: %ld", _frameQueueSize ]];
|
||||
}
|
||||
|
||||
- (void) enableGraphsChanged {
|
||||
[self.graphOpacityStepper setEnabled:[self.enableGraphsSwitch isOn]];
|
||||
}
|
||||
|
||||
- (void) graphOpacityStepperMoved {
|
||||
assert(self.graphOpacityStepper.value >= 0 && self.graphOpacityStepper.value <= 100);
|
||||
_graphOpacity = (int)self.graphOpacityStepper.value;
|
||||
[self updateGraphOpacityText];
|
||||
}
|
||||
|
||||
- (void) updateGraphOpacityText {
|
||||
[self.enableGraphsLabel setText:[NSString stringWithFormat:@"Performance Graphs - Opacity: %ld%%", _graphOpacity ]];
|
||||
}
|
||||
|
||||
- (void) saveSettings {
|
||||
DataManager* dataMan = [[DataManager alloc] init];
|
||||
NSInteger framerate = [self getChosenFrameRate];
|
||||
NSInteger height = [self getChosenStreamHeight];
|
||||
NSInteger width = [self getChosenStreamWidth];
|
||||
NSInteger audioConfig = [@[@2, @6, @8][[self.audioConfigSelector selectedSegmentIndex]] integerValue];
|
||||
NSInteger renderingBackend = [self.renderingBackendSelector selectedSegmentIndex];
|
||||
NSInteger onscreenControls = [self.onScreenWidgetSelector selectedSegmentIndex];
|
||||
NSInteger keyboardToggleFingers = self.softKeyboardGestureSelector.selectedSegmentIndex == 3 ? 20 : self.softKeyboardGestureSelector.selectedSegmentIndex+3;
|
||||
NSInteger oscLayoutToolFingers = (uint16_t)self->oswLayoutFingers;
|
||||
|
||||
|
||||
CGFloat slideToSettingsDistance = self.slideToMenuDistanceSlider.value;
|
||||
uint32_t slideToSettingsScreenEdge = [self getScreenEdgeFromSelector];
|
||||
CGFloat pointerVelocityModeDivider = (CGFloat)(uint8_t)self.pointerVelocityModeDividerSlider.value/100;
|
||||
CGFloat touchPointerVelocityFactor = (CGFloat)(uint16_t)[self map_velocFactorDisplay_fromSliderValue:self.touchPointerVelocityFactorSlider.value]/100;
|
||||
CGFloat mousePointerVelocityFactor = (CGFloat)(uint16_t)[self map_velocFactorDisplay_fromSliderValue:self.mousePointerVelocityFactorSlider.value]/100;
|
||||
CGFloat gyroSensitivity = (CGFloat)(uint16_t)self.gyroSensitivitySlider.value/100;
|
||||
|
||||
|
||||
uint16_t touchMoveEventInterval = (uint16_t)self.touchMoveEventIntervalSlider.value;
|
||||
|
||||
|
||||
BOOL reverseMouseWheelDirection = [self.reverseMouseWheelDirectionSelector selectedSegmentIndex] == 1;
|
||||
NSInteger asyncNativeTouchPriority = 1;
|
||||
//BOOL liftStreamViewForKeyboard = [self.liftStreamViewForKeyboardSelector selectedSegmentIndex] == 1;
|
||||
@@ -1964,6 +2018,7 @@ BOOL isCustomResolution(CGSize res) {
|
||||
BOOL statsOverlayEnabled = statsOverlayLevel != 0;
|
||||
BOOL enableHdr = self.hdrSwitch.isOn;
|
||||
BOOL unlockDisplayOrientation = [self.unlockDisplayOrientationSelector selectedSegmentIndex] == 1;
|
||||
BOOL enableGraphs = self.enableGraphsSwitch.isOn;
|
||||
NSInteger resolutionSelected = [self.resolutionSelector selectedSegmentIndex];
|
||||
NSInteger externalDisplayMode = [self.externalDisplayModeSelector selectedSegmentIndex];
|
||||
NSInteger localMousePointerMode = [self.localMousePointerModeSelector selectedSegmentIndex];
|
||||
@@ -2002,7 +2057,11 @@ BOOL isCustomResolution(CGSize res) {
|
||||
unlockDisplayOrientation:unlockDisplayOrientation
|
||||
resolutionSelected:resolutionSelected
|
||||
externalDisplayMode:externalDisplayMode
|
||||
localMousePointerMode:localMousePointerMode];
|
||||
localMousePointerMode:localMousePointerMode
|
||||
frameQueueSize:_frameQueueSize
|
||||
enableGraphs:enableGraphs
|
||||
graphOpacity:_graphOpacity
|
||||
renderingBackend:renderingBackend];
|
||||
}
|
||||
|
||||
- (void)didReceiveMemoryWarning {
|
||||
|
||||
@@ -50,7 +50,6 @@
|
||||
UITapGestureRecognizer *_menuDoubleTapGestureRecognizer;
|
||||
UITapGestureRecognizer *_playPauseTapGestureRecognizer;
|
||||
UITextView *_overlayView;
|
||||
uint16_t overlayLevel;
|
||||
UILabel *_stageLabel;
|
||||
UILabel *_tipLabel;
|
||||
UIActivityIndicatorView *_spinner;
|
||||
@@ -189,7 +188,6 @@
|
||||
}
|
||||
|
||||
_settings = [[[DataManager alloc] init] getSettings]; //StreamFrameViewController retrieve the settings here.
|
||||
overlayLevel = _settings.statsOverlayLevel.intValue;
|
||||
[self configOscLayoutTool];
|
||||
[self configSwipeGestures];
|
||||
[self configZoomGestureAndAddStreamView];
|
||||
@@ -583,7 +581,7 @@
|
||||
}
|
||||
else [self.view addSubview:_overlayView]; // don't know why but this is necessary for reactivating overlay.
|
||||
|
||||
NSString* overlayText = [self->_streamMan getStatsOverlayText:overlayLevel];
|
||||
NSString* overlayText = [self->_streamMan getStatsOverlayText];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self updateOverlayText:overlayText];
|
||||
});
|
||||
|
||||
Submodule moonlight-common/moonlight-common-c updated: 58902e342f...6fbc8ff7b0
Vendored
-1
Submodule third_party/implot deleted from 3da8bd3429
Reference in New Issue
Block a user