mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-26 11:48:36 +01:00
Merge pull request #20926 from hrydgard/more-ios-fixes
iOS: Refactor the GL ViewController
This commit is contained in:
11 files changed
+162
-55
No files matched your search
@@ -1349,6 +1349,7 @@ elseif(IOS AND NOT LIBRETRO)
|
||||
ios/Controls.h
|
||||
ios/Controls.mm
|
||||
ios/ViewControllerCommon.h
|
||||
ios/ViewControllerCommon.mm
|
||||
ios/ViewController.mm
|
||||
ios/ViewController.h
|
||||
ios/ViewControllerMetal.mm
|
||||
|
||||
@@ -145,8 +145,6 @@ Bounds UIContext::GetLayoutBounds() const {
|
||||
float top = System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_TOP);
|
||||
float bottom = System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_BOTTOM);
|
||||
|
||||
// ILOG("Insets: %f %f %f %f", left, right, top, bottom);
|
||||
|
||||
// Adjust left edge to compensate for cutouts (notches) if any.
|
||||
bounds.x += left;
|
||||
bounds.w -= (left + right);
|
||||
|
||||
+1
-1
@@ -546,7 +546,7 @@ enum class MultiPartResult {
|
||||
static MultiPartResult HandleMultipartPart(const http::ServerRequest &request, std::string boundary, const Path &uploadPath, ProgressTracker &progress) {
|
||||
std::string firstBoundary = request.In()->ReadLine();
|
||||
if (firstBoundary != "--" + boundary) {
|
||||
WARN_LOG(Log::HTTP, "Bad boundary: Expected --%s but got %s", boundary.c_str());
|
||||
WARN_LOG(Log::HTTP, "Bad boundary: Expected --%s but got %s", boundary.c_str(), firstBoundary.c_str());
|
||||
return MultiPartResult::RequestError;
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -495,8 +495,8 @@ void DrawFPS(UIContext *ctx, const Bounds &bounds) {
|
||||
|
||||
ctx->BindFontTexture();
|
||||
ctx->Draw()->SetFontScale(0.7f, 0.7f);
|
||||
ctx->Draw()->DrawText(ubuntu24, w.as_view(), bounds.x2() - 8, 20, 0xc0000000, ALIGN_TOPRIGHT | FLAG_DYNAMIC_ASCII);
|
||||
ctx->Draw()->DrawText(ubuntu24, w.as_view(), bounds.x2() - 10, 19, 0xFF3fFF3f, ALIGN_TOPRIGHT | FLAG_DYNAMIC_ASCII);
|
||||
ctx->Draw()->DrawText(ubuntu24, w.as_view(), bounds.x2() - 8, bounds.y + 10, 0xc0000000, ALIGN_TOPRIGHT | FLAG_DYNAMIC_ASCII);
|
||||
ctx->Draw()->DrawText(ubuntu24, w.as_view(), bounds.x2() - 10, bounds.y + 8, 0xFF3fFF3f, ALIGN_TOPRIGHT | FLAG_DYNAMIC_ASCII);
|
||||
ctx->Draw()->SetFontScale(1.0f, 1.0f);
|
||||
ctx->Flush();
|
||||
ctx->RebindTexture();
|
||||
|
||||
+4
-4
@@ -1128,7 +1128,7 @@ GameBrowser *MainScreen::CreateBrowserTab(const Path &path, std::string_view tit
|
||||
return gameBrowser;
|
||||
}
|
||||
|
||||
UI::ViewGroup *MainScreen::CreateLogoView(UI::LayoutParams *layoutParams) {
|
||||
UI::ViewGroup *MainScreen::CreateLogoView(bool portrait, UI::LayoutParams *layoutParams) {
|
||||
using namespace UI;
|
||||
AnchorLayout *logos = new AnchorLayout(layoutParams);
|
||||
if (System_GetPropertyBool(SYSPROP_APP_GOLD)) {
|
||||
@@ -1156,7 +1156,7 @@ UI::ViewGroup *MainScreen::CreateLogoView(UI::LayoutParams *layoutParams) {
|
||||
ver->SetClip(false);
|
||||
|
||||
// Only allow copying the version if it looks like a git version string. 1.19 for example is not really necessary to be able to copy/paste.
|
||||
if (strchr(PPSSPP_GIT_VERSION, '-')) {
|
||||
if (!portrait && strchr(PPSSPP_GIT_VERSION, '-')) {
|
||||
ver->OnClick.Add([](UI::EventParams &e) {
|
||||
auto di = GetI18NCategory(I18NCat::DIALOG);
|
||||
System_CopyStringToClipboard(PPSSPP_GIT_VERSION);
|
||||
@@ -1298,7 +1298,7 @@ void MainScreen::CreateViews() {
|
||||
if (vertical) {
|
||||
LinearLayout *header = new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT));
|
||||
header->SetSpacing(5.0f);
|
||||
header->Add(CreateLogoView(new LinearLayoutParams(WRAP_CONTENT, 80.0f, false)));
|
||||
header->Add(CreateLogoView(true, new LinearLayoutParams(WRAP_CONTENT, 80.0f, false)));
|
||||
|
||||
LinearLayout *buttonGroup = new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(WRAP_CONTENT, WRAP_CONTENT, 1.0f, UI::Gravity::G_VCENTER, UI::Margins(0,0,8,0)));
|
||||
|
||||
@@ -1317,7 +1317,7 @@ void MainScreen::CreateViews() {
|
||||
ViewGroup *rightColumn = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(300, FILL_PARENT, actionMenuMargins));
|
||||
LinearLayout *rightColumnItems = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT));
|
||||
rightColumnItems->SetSpacing(0.0f);
|
||||
ViewGroup *logo = CreateLogoView(new LinearLayoutParams(FILL_PARENT, 80.0f, false));
|
||||
ViewGroup *logo = CreateLogoView(false, new LinearLayoutParams(FILL_PARENT, 80.0f));
|
||||
#if !defined(MOBILE_DEVICE)
|
||||
auto gr = GetI18NCategory(I18NCat::GRAPHICS);
|
||||
ImageID icon(g_Config.UseFullScreen() ? "I_RESTORE" : "I_FULLSCREEN");
|
||||
|
||||
+1
-1
@@ -136,7 +136,7 @@ protected:
|
||||
void CreateViews() override;
|
||||
void CreateRecentTab();
|
||||
GameBrowser *CreateBrowserTab(const Path &path, std::string_view title, std::string_view howToTitle, std::string_view howToUri, BrowseFlags browseFlags, bool *bGridView, float *scrollPos);
|
||||
UI::ViewGroup *CreateLogoView(UI::LayoutParams *layoutParams);
|
||||
UI::ViewGroup *CreateLogoView(bool portrait, UI::LayoutParams *layoutParams);
|
||||
void CreateMainButtons(UI::ViewGroup *parent, bool vertical);
|
||||
|
||||
void DrawBackground(UIContext &dc) override;
|
||||
|
||||
+6
-6
@@ -108,13 +108,13 @@ bool InitController(GCController *controller) {
|
||||
};
|
||||
}
|
||||
|
||||
#if defined(__IPHONE_14_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_14_0
|
||||
if ([extendedProfile respondsToSelector:@selector(buttonHome)] && extendedProfile.buttonHome != nil) {
|
||||
extendedProfile.buttonHome.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) {
|
||||
controllerButtonPressed(pressed, NKCODE_HOME);
|
||||
};
|
||||
if (@available(iOS 14.0, *)) {
|
||||
if ([extendedProfile respondsToSelector:@selector(buttonHome)] && extendedProfile.buttonHome != nil) {
|
||||
extendedProfile.buttonHome.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) {
|
||||
controllerButtonPressed(pressed, NKCODE_HOME);
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
extendedProfile.leftThumbstick.xAxis.valueChangedHandler = ^(GCControllerAxisInput *axis, float value) {
|
||||
AxisInput axisInput;
|
||||
|
||||
@@ -10,8 +10,13 @@
|
||||
|
||||
#include "ViewControllerCommon.h"
|
||||
|
||||
@interface PPSSPPViewControllerGL : GLKViewController <
|
||||
@interface PPSSPPViewControllerGL : UIViewController <GLKViewDelegate,
|
||||
iCadeEventDelegate, LocationHandlerDelegate, CameraFrameDelegate,
|
||||
UIGestureRecognizerDelegate, UIKeyInput, PPSSPPViewController,
|
||||
UIImagePickerControllerDelegate, UINavigationControllerDelegate>
|
||||
|
||||
|
||||
// Public-ish control similar to GLKViewController
|
||||
@property (nonatomic, assign) NSInteger preferredFramesPerSecond; // default 60
|
||||
|
||||
@end
|
||||
+124
-35
@@ -3,18 +3,20 @@
|
||||
//
|
||||
// Created by rock88
|
||||
// Modified by xSacha
|
||||
//
|
||||
// Reworked by hrydgard
|
||||
|
||||
#import "AppDelegate.h"
|
||||
#import "ViewController.h"
|
||||
#import "DisplayManager.h"
|
||||
#include "Controls.h"
|
||||
#import "iOSCoreAudio.h"
|
||||
#import "IAPManager.h"
|
||||
|
||||
#import <GLKit/GLKit.h>
|
||||
#include <cassert>
|
||||
#import "ViewController.h"
|
||||
#import "Controls.h"
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
|
||||
#include <cassert>
|
||||
#include "Common/Net/Resolve.h"
|
||||
#include "Common/UI/Screen.h"
|
||||
#include "Common/GPU/thin3d.h"
|
||||
@@ -109,9 +111,13 @@ id<PPSSPPViewController> sharedViewController;
|
||||
NSString *imageFilename;
|
||||
}
|
||||
|
||||
@property (nonatomic, strong) EAGLContext *glContext;
|
||||
@property (nonatomic, strong) GLKView *glView;
|
||||
@property (nonatomic, strong) CADisplayLink *displayLink;
|
||||
@property (nonatomic, assign) NSTimeInterval lastTimestamp;
|
||||
|
||||
@property (nonatomic, strong) EAGLContext* context;
|
||||
|
||||
//@property (nonatomic) iCadeReaderView* iCadeView;
|
||||
@property (nonatomic) GCController *gameController __attribute__((weak_import));
|
||||
@property (strong, nonatomic) CMMotionManager *motionManager;
|
||||
@property (strong, nonatomic) NSOperationQueue *accelerometerQueue;
|
||||
@@ -122,9 +128,11 @@ id<PPSSPPViewController> sharedViewController;
|
||||
UIScreenEdgePanGestureRecognizer *mBackGestureRecognizer;
|
||||
}
|
||||
|
||||
|
||||
-(id) init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_preferredFramesPerSecond = 60; // default
|
||||
sharedViewController = self;
|
||||
g_iCadeTracker.InitKeyMap();
|
||||
|
||||
@@ -251,23 +259,45 @@ void GLRenderLoop(IOSGLESContext *graphicsContext) {
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
// 1) Create GL context
|
||||
self.glContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
|
||||
if (!self.glContext) {
|
||||
self.glContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
|
||||
}
|
||||
NSAssert(self.glContext != nil, @"Failed to create EAGLContext");
|
||||
|
||||
// 2) Create GLKView
|
||||
self.glView = [[GLKView alloc] initWithFrame:self.view.bounds context:self.glContext];
|
||||
self.glView.delegate = self;
|
||||
self.glView.enableSetNeedsDisplay = NO; // We'll call display manually
|
||||
self.glView.drawableDepthFormat = GLKViewDrawableDepthFormat24;
|
||||
self.glView.drawableStencilFormat = GLKViewDrawableStencilFormat8;
|
||||
self.glView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
[self.view addSubview:self.glView];
|
||||
|
||||
// Put context current for initial GL setup
|
||||
[EAGLContext setCurrentContext:self.glContext];
|
||||
|
||||
// Here we can do one time GL init if we want.
|
||||
|
||||
// 3) Setup display link
|
||||
self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayLinkFired:)];
|
||||
if (@available(iOS 10.0, *)) {
|
||||
self.displayLink.preferredFramesPerSecond = (NSInteger)self.preferredFramesPerSecond;
|
||||
} else {
|
||||
// older iOS: approximate with frameInterval
|
||||
self.displayLink.frameInterval = MAX(1, (NSInteger)round(60.0 / self.preferredFramesPerSecond));
|
||||
}
|
||||
[self.displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
|
||||
|
||||
self.lastTimestamp = 0;
|
||||
|
||||
[[DisplayManager shared] setupDisplayListener];
|
||||
|
||||
UIScreen* screen = [(AppDelegate*)[UIApplication sharedApplication].delegate screen];
|
||||
self.view.frame = [screen bounds];
|
||||
self.view.multipleTouchEnabled = YES;
|
||||
self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
|
||||
|
||||
if (!self.context) {
|
||||
self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
|
||||
}
|
||||
|
||||
GLKView* view = (GLKView *)self.view;
|
||||
view.context = self.context;
|
||||
view.drawableDepthFormat = GLKViewDrawableDepthFormat24;
|
||||
view.drawableStencilFormat = GLKViewDrawableStencilFormat8;
|
||||
[EAGLContext setCurrentContext:self.context];
|
||||
self.preferredFramesPerSecond = 60; // NOTE: We don't yet take advantage of 120hz screens
|
||||
|
||||
graphicsContext = new IOSGLESContext();
|
||||
|
||||
@@ -299,8 +329,79 @@ void GLRenderLoop(IOSGLESContext *graphicsContext) {
|
||||
INFO_LOG(Log::G3D, "Done with viewDidLoad.");
|
||||
}
|
||||
|
||||
- (void)handleSwipeFrom:(UIScreenEdgePanGestureRecognizer *)recognizer
|
||||
{
|
||||
- (void)viewDidLayoutSubviews {
|
||||
[super viewDidLayoutSubviews];
|
||||
self.glView.frame = self.view.bounds;
|
||||
/*
|
||||
// if you need to update viewport:
|
||||
CGSize s = self.glView.bounds.size;
|
||||
[EAGLContext setCurrentContext:self.glContext];
|
||||
glViewport(0, 0, (GLsizei)round(s.width), (GLsizei)round(s.height));
|
||||
*/
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
[super viewWillAppear:animated];
|
||||
// Resume display link unless explicitly paused
|
||||
INFO_LOG(Log::G3D, "viewWillAppear - resuming display link");
|
||||
}
|
||||
|
||||
- (void)viewWillDisappear:(BOOL)animated {
|
||||
[super viewWillDisappear:animated];
|
||||
// stop rendering while not visible
|
||||
INFO_LOG(Log::G3D, "viewWillDisappear - pausing display link");
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[self.displayLink invalidate];
|
||||
self.displayLink = nil;
|
||||
|
||||
if ([EAGLContext currentContext] == self.glContext) {
|
||||
[EAGLContext setCurrentContext:nil];
|
||||
}
|
||||
self.glContext = nil;
|
||||
}
|
||||
|
||||
- (void)setPreferredFramesPerSecond:(NSInteger)preferredFramesPerSecond {
|
||||
_preferredFramesPerSecond = preferredFramesPerSecond;
|
||||
if (self.displayLink) {
|
||||
if (@available(iOS 10.0, *)) {
|
||||
self.displayLink.preferredFramesPerSecond = (NSInteger)preferredFramesPerSecond;
|
||||
} else {
|
||||
self.displayLink.frameInterval = MAX(1, (NSInteger)round(60.0 / preferredFramesPerSecond));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)displayLinkFired:(CADisplayLink *)dl {
|
||||
// compute delta time
|
||||
NSTimeInterval timestamp = dl.timestamp;
|
||||
NSTimeInterval delta = 0;
|
||||
if (self.lastTimestamp > 0) {
|
||||
delta = timestamp - self.lastTimestamp;
|
||||
} else {
|
||||
delta = dl.duration; // fallback
|
||||
}
|
||||
self.lastTimestamp = timestamp;
|
||||
|
||||
// Ensure context is current before drawing
|
||||
[EAGLContext setCurrentContext:self.glContext];
|
||||
|
||||
// Trigger GLKView draw
|
||||
[self.glView display];
|
||||
}
|
||||
|
||||
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
|
||||
if (!renderLoopRunning) {
|
||||
INFO_LOG(Log::G3D, "Ignoring drawInRect");
|
||||
return;
|
||||
}
|
||||
if (sharedViewController) {
|
||||
graphicsContext->ThreadFrame(true);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)handleSwipeFrom:(UIScreenEdgePanGestureRecognizer *)recognizer {
|
||||
if (recognizer.state == UIGestureRecognizerStateEnded) {
|
||||
KeyInput key;
|
||||
key.flags = KEY_DOWN | KEY_UP;
|
||||
@@ -337,6 +438,8 @@ void GLRenderLoop(IOSGLESContext *graphicsContext) {
|
||||
[[DisplayManager shared] updateResolution:[UIScreen mainScreen]];
|
||||
|
||||
INFO_LOG(Log::System, "didBecomeActive end");
|
||||
|
||||
self.displayLink.paused = NO;
|
||||
}
|
||||
|
||||
- (void)willResignActive {
|
||||
@@ -349,6 +452,8 @@ void GLRenderLoop(IOSGLESContext *graphicsContext) {
|
||||
[self.motionManager stopAccelerometerUpdates];
|
||||
}
|
||||
INFO_LOG(Log::System, "willResignActive end");
|
||||
|
||||
self.displayLink.paused = YES;
|
||||
}
|
||||
|
||||
- (void)shutdown
|
||||
@@ -385,27 +490,11 @@ void GLRenderLoop(IOSGLESContext *graphicsContext) {
|
||||
INFO_LOG(Log::System, "Done shutting down GL");
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
INFO_LOG(Log::System, "dealloc GL");
|
||||
}
|
||||
|
||||
- (UIInterfaceOrientationMask)supportedInterfaceOrientations
|
||||
{
|
||||
return UIInterfaceOrientationMaskAll;
|
||||
}
|
||||
|
||||
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
|
||||
{
|
||||
if (!renderLoopRunning) {
|
||||
INFO_LOG(Log::G3D, "Ignoring drawInRect");
|
||||
return;
|
||||
}
|
||||
if (sharedViewController) {
|
||||
graphicsContext->ThreadFrame(true);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
|
||||
{
|
||||
g_touchTracker.Began(touches, self.view);
|
||||
@@ -428,7 +517,7 @@ void GLRenderLoop(IOSGLESContext *graphicsContext) {
|
||||
|
||||
- (void)bindDefaultFBO
|
||||
{
|
||||
[(GLKView*)self.view bindDrawable];
|
||||
[(GLKView*)self.glView bindDrawable];
|
||||
}
|
||||
|
||||
- (void)buttonDown:(iCadeState)button
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
#import "ios/ViewControllerCommon.h"
|
||||
|
||||
@@ -491,13 +491,25 @@ extern float g_safeInsetRight;
|
||||
extern float g_safeInsetTop;
|
||||
extern float g_safeInsetBottom;
|
||||
|
||||
static float BoostInset(float inset) {
|
||||
if (inset > 0.0f) {
|
||||
// If there's some inset, add a few pixels extra. Really needed on iPhone 12, at least.
|
||||
inset += 4.0f;
|
||||
}
|
||||
return inset;
|
||||
}
|
||||
|
||||
- (void)viewSafeAreaInsetsDidChange {
|
||||
if (@available(iOS 11.0, *)) {
|
||||
[super viewSafeAreaInsetsDidChange];
|
||||
// we use 0.0f instead of safeAreaInsets.bottom because the bottom overlay isn't disturbing (for now)
|
||||
g_safeInsetLeft = self.view.safeAreaInsets.left;
|
||||
g_safeInsetRight = self.view.safeAreaInsets.right;
|
||||
g_safeInsetTop = self.view.safeAreaInsets.top;
|
||||
g_safeInsetLeft = BoostInset(self.view.safeAreaInsets.left);
|
||||
g_safeInsetRight = BoostInset(self.view.safeAreaInsets.right);
|
||||
g_safeInsetTop = BoostInset(self.view.safeAreaInsets.top);
|
||||
|
||||
// TODO: In portrait mode, should probably use safeAreaInsets.bottom.
|
||||
// However, in landscape mode, it's not really needed.
|
||||
// g_safeInsetBottom = BoostInset(self.view.safeAreaInsets.bottom);
|
||||
g_safeInsetBottom = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user