ppsspp/ios/ViewController.mm
Henrik Rydgård 80a99a67d9 Control: Change internal interfaces to batch-process input axis updates
These naturally come in bunches on many platforms like Android, so lay
some groundwork to also handle them in bunches to minimize locking in
the future.

Linux buildfix
2023-08-31 11:55:53 +02:00

769 lines
21 KiB
Plaintext

//
// ViewController.m
//
// Created by rock88
// Modified by xSacha
//
#import "AppDelegate.h"
#import "ViewController.h"
#import "DisplayManager.h"
#import "iOSCoreAudio.h"
#import <GLKit/GLKit.h>
#include <cassert>
#include "Common/Net/Resolve.h"
#include "Common/UI/Screen.h"
#include "Common/GPU/thin3d.h"
#include "Common/GPU/thin3d_create.h"
#include "Common/GPU/OpenGL/GLRenderManager.h"
#include "Common/GPU/OpenGL/GLFeatures.h"
#include "Common/System/Display.h"
#include "Common/System/System.h"
#include "Common/System/OSD.h"
#include "Common/System/NativeApp.h"
#include "Common/File/VFS/VFS.h"
#include "Common/Log.h"
#include "Common/TimeUtil.h"
#include "Common/Input/InputState.h"
#include "Common/Input/KeyCodes.h"
#include "Common/GraphicsContext.h"
#include "Core/Config.h"
#include "Core/ConfigValues.h"
#include "Core/KeyMap.h"
#include "Core/System.h"
#include "Core/HLE/sceUsbCam.h"
#include "Core/HLE/sceUsbGps.h"
#include <sys/types.h>
#include <sys/sysctl.h>
#include <mach/machine.h>
#define IS_IPAD() ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad)
#define IS_IPHONE() ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone)
class IOSGraphicsContext : public GraphicsContext {
public:
IOSGraphicsContext() {
CheckGLExtensions();
draw_ = Draw::T3DCreateGLContext(false);
renderManager_ = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
renderManager_->SetInflightFrames(g_Config.iInflightFrames);
SetGPUBackend(GPUBackend::OPENGL);
bool success = draw_->CreatePresets();
_assert_msg_(success, "Failed to compile preset shaders");
}
~IOSGraphicsContext() {
delete draw_;
}
Draw::DrawContext *GetDrawContext() override {
return draw_;
}
void Resize() override {}
void Shutdown() override {}
void ThreadStart() override {
renderManager_->ThreadStart(draw_);
}
bool ThreadFrame() override {
return renderManager_->ThreadFrame();
}
void ThreadEnd() override {
renderManager_->ThreadEnd();
}
void StopThread() override {
renderManager_->StopThread();
}
private:
Draw::DrawContext *draw_;
GLRenderManager *renderManager_;
};
static float dp_xscale = 1.0f;
static float dp_yscale = 1.0f;
static double lastSelectPress = 0.0f;
static double lastStartPress = 0.0f;
static bool simulateAnalog = false;
static bool iCadeConnectNotified = false;
static bool threadEnabled = true;
static bool threadStopped = false;
static UITouch *g_touches[10];
__unsafe_unretained ViewController* sharedViewController;
static GraphicsContext *graphicsContext;
static CameraHelper *cameraHelper;
static LocationHelper *locationHelper;
@interface ViewController () {
std::map<uint16_t, InputKeyCode> iCadeToKeyMap;
}
@property (nonatomic, strong) EAGLContext* context;
//@property (nonatomic) iCadeReaderView* iCadeView;
#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_6_1
@property (nonatomic) GCController *gameController __attribute__((weak_import));
#endif
@end
@implementation ViewController
-(id) init {
self = [super init];
if (self) {
sharedViewController = self;
memset(g_touches, 0, sizeof(g_touches));
iCadeToKeyMap[iCadeJoystickUp] = NKCODE_DPAD_UP;
iCadeToKeyMap[iCadeJoystickRight] = NKCODE_DPAD_RIGHT;
iCadeToKeyMap[iCadeJoystickDown] = NKCODE_DPAD_DOWN;
iCadeToKeyMap[iCadeJoystickLeft] = NKCODE_DPAD_LEFT;
iCadeToKeyMap[iCadeButtonA] = NKCODE_BUTTON_9; // Select
iCadeToKeyMap[iCadeButtonB] = NKCODE_BUTTON_7; // LTrigger
iCadeToKeyMap[iCadeButtonC] = NKCODE_BUTTON_10; // Start
iCadeToKeyMap[iCadeButtonD] = NKCODE_BUTTON_8; // RTrigger
iCadeToKeyMap[iCadeButtonE] = NKCODE_BUTTON_4; // Square
iCadeToKeyMap[iCadeButtonF] = NKCODE_BUTTON_2; // Cross
iCadeToKeyMap[iCadeButtonG] = NKCODE_BUTTON_1; // Triangle
iCadeToKeyMap[iCadeButtonH] = NKCODE_BUTTON_3; // Circle
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appWillTerminate:) name:UIApplicationWillTerminateNotification object:nil];
#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_6_1
if ([GCController class]) // Checking the availability of a GameController framework
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(controllerDidConnect:) name:GCControllerDidConnectNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(controllerDidDisconnect:) name:GCControllerDidDisconnectNotification object:nil];
}
#endif
}
return self;
}
- (BOOL)prefersHomeIndicatorAutoHidden {
return YES;
}
- (void)shareText:(NSString *)text {
NSArray *items = @[text];
UIActivityViewController * viewController = [[UIActivityViewController alloc] initWithActivityItems:items applicationActivities:nil];
dispatch_async(dispatch_get_main_queue(), ^{
[self presentViewController:viewController animated:YES completion:nil];
});
}
extern float g_safeInsetLeft;
extern float g_safeInsetRight;
extern float g_safeInsetTop;
extern float g_safeInsetBottom;
- (void)viewSafeAreaInsetsDidChange {
if (@available(iOS 11.0, *)) {
[super viewSafeAreaInsetsDidChange];
char safeArea[100];
// 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_safeInsetBottom = 0.0f;
}
}
- (void)viewDidLoad {
[super viewDidLoad];
[[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;
[[DisplayManager shared] updateResolution:[UIScreen mainScreen]];
graphicsContext = new IOSGraphicsContext();
graphicsContext->GetDrawContext()->SetErrorCallback([](const char *shortDesc, const char *details, void *userdata) {
g_OSD.Show(OSDType::MESSAGE_ERROR, details, 0.0f, "error_callback");
}, nullptr);
graphicsContext->ThreadStart();
dp_xscale = (float)g_display.dp_xres / (float)g_display.pixel_xres;
dp_yscale = (float)g_display.dp_yres / (float)g_display.pixel_yres;
/*self.iCadeView = [[iCadeReaderView alloc] init];
[self.view addSubview:self.iCadeView];
self.iCadeView.delegate = self;
self.iCadeView.active = YES;*/
#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_6_1
if ([GCController class]) {
if ([[GCController controllers] count] > 0) {
[self setupController:[[GCController controllers] firstObject]];
}
}
#endif
cameraHelper = [[CameraHelper alloc] init];
[cameraHelper setDelegate:self];
locationHelper = [[LocationHelper alloc] init];
[locationHelper setDelegate:self];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
NativeInitGraphics(graphicsContext);
INFO_LOG(SYSTEM, "Emulation thread starting\n");
while (threadEnabled) {
NativeFrame(graphicsContext);
}
INFO_LOG(SYSTEM, "Emulation thread shutting down\n");
NativeShutdownGraphics();
// Also ask the main thread to stop, so it doesn't hang waiting for a new frame.
INFO_LOG(SYSTEM, "Emulation thread stopping\n");
graphicsContext->StopThread();
threadStopped = true;
});
}
- (void)appWillTerminate:(NSNotification *)notification
{
[self shutdown];
}
- (void)shutdown
{
if (sharedViewController == nil) {
return;
}
iOSCoreAudioShutdown();
if (threadEnabled) {
threadEnabled = false;
while (graphicsContext->ThreadFrame()) {
continue;
}
while (!threadStopped) {}
graphicsContext->ThreadEnd();
}
sharedViewController = nil;
if (self.context) {
if ([EAGLContext currentContext] == self.context) {
[EAGLContext setCurrentContext:nil];
}
self.context = nil;
}
[[NSNotificationCenter defaultCenter] removeObserver:self];
#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_6_1
if ([GCController class]) {
self.gameController = nil;
}
#endif
if (graphicsContext) {
graphicsContext->Shutdown();
delete graphicsContext;
graphicsContext = NULL;
}
NativeShutdown();
}
- (void)dealloc
{
[self shutdown];
}
// For iOS before 6.0
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
return UIInterfaceOrientationIsLandscape(toInterfaceOrientation);
}
// For iOS 6.0 and up
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscape;
}
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
if (sharedViewController)
graphicsContext->ThreadFrame();
}
- (void)touchX:(float)x y:(float)y code:(int)code pointerId:(int)pointerId
{
float scale = [UIScreen mainScreen].scale;
if ([[UIScreen mainScreen] respondsToSelector:@selector(nativeScale)]) {
scale = [UIScreen mainScreen].nativeScale;
}
float scaledX = (int)(x * dp_xscale) * scale;
float scaledY = (int)(y * dp_yscale) * scale;
TouchInput input;
input.x = scaledX;
input.y = scaledY;
switch (code) {
case 1 :
input.flags = TOUCH_DOWN;
break;
case 2 :
input.flags = TOUCH_UP;
break;
default :
input.flags = TOUCH_MOVE;
break;
}
input.id = pointerId;
NativeTouch(input);
}
int ToTouchID(UITouch *uiTouch, bool allowAllocate) {
// Find the id for the touch.
for (int localId = 0; localId < (int)ARRAY_SIZE(g_touches); ++localId) {
if (g_touches[localId] == uiTouch) {
return localId;
}
}
// Allocate a new one, perhaps?
if (allowAllocate) {
for (int localId = 0; localId < (int)ARRAY_SIZE(g_touches); ++localId) {
if (g_touches[localId] == 0) {
g_touches[localId] = uiTouch;
return localId;
}
}
// None were free. Ignore?
return 0;
}
return -1;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
for(UITouch* touch in touches)
{
CGPoint point = [touch locationInView:self.view];
int touchId = ToTouchID(touch, true);
[self touchX:point.x y:point.y code:1 pointerId:touchId];
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
for(UITouch* touch in touches)
{
CGPoint point = [touch locationInView:self.view];
int touchId = ToTouchID(touch, true);
[self touchX:point.x y:point.y code:0 pointerId: touchId];
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
for(UITouch* touch in touches)
{
CGPoint point = [touch locationInView:self.view];
int touchId = ToTouchID(touch, false);
if (touchId >= 0) {
[self touchX:point.x y:point.y code:2 pointerId: touchId];
g_touches[touchId] = nullptr;
}
}
}
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
for(UITouch* touch in touches)
{
CGPoint point = [touch locationInView:self.view];
int touchId = ToTouchID(touch, false);
if (touchId >= 0) {
[self touchX:point.x y:point.y code:2 pointerId: touchId];
g_touches[touchId] = nullptr;
}
}
}
- (void)bindDefaultFBO
{
[(GLKView*)self.view bindDrawable];
}
- (void)buttonDown:(iCadeState)button
{
if (simulateAnalog &&
((button == iCadeJoystickUp) ||
(button == iCadeJoystickDown) ||
(button == iCadeJoystickLeft) ||
(button == iCadeJoystickRight))) {
AxisInput axis;
switch (button) {
case iCadeJoystickUp :
axis.axisId = JOYSTICK_AXIS_Y;
axis.value = -1.0f;
break;
case iCadeJoystickDown :
axis.axisId = JOYSTICK_AXIS_Y;
axis.value = 1.0f;
break;
case iCadeJoystickLeft :
axis.axisId = JOYSTICK_AXIS_X;
axis.value = -1.0f;
break;
case iCadeJoystickRight :
axis.axisId = JOYSTICK_AXIS_X;
axis.value = 1.0f;
break;
default:
break;
}
axis.deviceId = DEVICE_ID_PAD_0;
NativeAxis(&axis, 1);
} else {
KeyInput key;
key.flags = KEY_DOWN;
key.keyCode = iCadeToKeyMap[button];
key.deviceId = DEVICE_ID_PAD_0;
NativeKey(key);
}
}
- (void)buttonUp:(iCadeState)button
{
if (!iCadeConnectNotified) {
iCadeConnectNotified = true;
KeyMap::NotifyPadConnected(DEVICE_ID_PAD_0, "iCade");
}
if (button == iCadeButtonA) {
// Pressing Select twice within 1 second toggles the DPad between
// normal operation and simulating the Analog stick.
if ((lastSelectPress + 1.0f) > time_now_d())
simulateAnalog = !simulateAnalog;
lastSelectPress = time_now_d();
}
if (button == iCadeButtonC) {
// Pressing Start twice within 1 second will take to the Emu menu
if ((lastStartPress + 1.0f) > time_now_d()) {
KeyInput key;
key.flags = KEY_DOWN;
key.keyCode = NKCODE_ESCAPE;
key.deviceId = DEVICE_ID_KEYBOARD;
NativeKey(key);
return;
}
lastStartPress = time_now_d();
}
if (simulateAnalog &&
((button == iCadeJoystickUp) ||
(button == iCadeJoystickDown) ||
(button == iCadeJoystickLeft) ||
(button == iCadeJoystickRight))) {
AxisInput axis;
switch (button) {
case iCadeJoystickUp :
axis.axisId = JOYSTICK_AXIS_Y;
axis.value = 0.0f;
break;
case iCadeJoystickDown :
axis.axisId = JOYSTICK_AXIS_Y;
axis.value = 0.0f;
break;
case iCadeJoystickLeft :
axis.axisId = JOYSTICK_AXIS_X;
axis.value = 0.0f;
break;
case iCadeJoystickRight :
axis.axisId = JOYSTICK_AXIS_X;
axis.value = 0.0f;
break;
default:
break;
}
axis.deviceId = DEVICE_ID_PAD_0;
NativeAxis(&axis, 1);
} else {
KeyInput key;
key.flags = KEY_UP;
key.keyCode = iCadeToKeyMap[button];
key.deviceId = DEVICE_ID_PAD_0;
NativeKey(key);
}
}
#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_6_1
- (void)controllerDidConnect:(NSNotification *)note
{
if (![[GCController controllers] containsObject:self.gameController]) self.gameController = nil;
if (self.gameController != nil) return; // already have a connected controller
[self setupController:(GCController *)note.object];
}
- (void)controllerDidDisconnect:(NSNotification *)note
{
if (self.gameController == note.object) {
self.gameController = nil;
if ([[GCController controllers] count] > 0) {
[self setupController:[[GCController controllers] firstObject]];
} else {
[[UIApplication sharedApplication] setIdleTimerDisabled:NO];
}
}
}
- (void)controllerButtonPressed:(BOOL)pressed keyCode:(InputKeyCode)keyCode
{
KeyInput key;
key.deviceId = DEVICE_ID_PAD_0;
key.flags = pressed ? KEY_DOWN : KEY_UP;
key.keyCode = keyCode;
NativeKey(key);
}
// Enables tapping for edge area.
-(UIRectEdge)preferredScreenEdgesDeferringSystemGestures
{
return UIRectEdgeAll;
}
- (void)setupController:(GCController *)controller
{
self.gameController = controller;
GCGamepad *baseProfile = self.gameController.gamepad;
if (baseProfile == nil) {
self.gameController = nil;
return;
}
[[UIApplication sharedApplication] setIdleTimerDisabled:YES]; // prevent auto-lock
self.gameController.controllerPausedHandler = ^(GCController *controller) {
KeyInput key;
key.flags = KEY_DOWN;
key.keyCode = NKCODE_ESCAPE;
key.deviceId = DEVICE_ID_KEYBOARD;
NativeKey(key);
};
baseProfile.buttonA.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) {
[self controllerButtonPressed:pressed keyCode:NKCODE_BUTTON_2]; // Cross
};
baseProfile.buttonB.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) {
[self controllerButtonPressed:pressed keyCode:NKCODE_BUTTON_3]; // Circle
};
baseProfile.buttonX.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) {
[self controllerButtonPressed:pressed keyCode:NKCODE_BUTTON_4]; // Square
};
baseProfile.buttonY.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) {
[self controllerButtonPressed:pressed keyCode:NKCODE_BUTTON_1]; // Triangle
};
baseProfile.leftShoulder.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) {
[self controllerButtonPressed:pressed keyCode:NKCODE_BUTTON_7]; // LTrigger
};
baseProfile.rightShoulder.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) {
[self controllerButtonPressed:pressed keyCode:NKCODE_BUTTON_8]; // RTrigger
};
baseProfile.dpad.up.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) {
[self controllerButtonPressed:pressed keyCode:NKCODE_DPAD_UP];
};
baseProfile.dpad.down.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) {
[self controllerButtonPressed:pressed keyCode:NKCODE_DPAD_DOWN];
};
baseProfile.dpad.left.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) {
[self controllerButtonPressed:pressed keyCode:NKCODE_DPAD_LEFT];
};
baseProfile.dpad.right.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) {
[self controllerButtonPressed:pressed keyCode:NKCODE_DPAD_RIGHT];
};
GCExtendedGamepad *extendedProfile = self.gameController.extendedGamepad;
if (extendedProfile == nil)
return; // controller doesn't support extendedGamepad profile
extendedProfile.leftTrigger.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) {
[self controllerButtonPressed:pressed keyCode:NKCODE_BUTTON_9]; // Select
};
extendedProfile.rightTrigger.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) {
[self controllerButtonPressed:pressed keyCode:NKCODE_BUTTON_10]; // Start
};
#if defined(__IPHONE_12_1) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_12_1
if ([extendedProfile respondsToSelector:@selector(leftThumbstickButton)] && extendedProfile.leftThumbstickButton != nil) {
extendedProfile.leftThumbstickButton.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) {
[self controllerButtonPressed:pressed keyCode:NKCODE_BUTTON_11];
};
}
if ([extendedProfile respondsToSelector:@selector(rightThumbstickButton)] && extendedProfile.rightThumbstickButton != nil) {
extendedProfile.rightThumbstickButton.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) {
[self controllerButtonPressed:pressed keyCode:NKCODE_BUTTON_12];
};
}
#endif
#if defined(__IPHONE_13_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0
if ([extendedProfile respondsToSelector:@selector(buttonOptions)] && extendedProfile.buttonOptions != nil) {
extendedProfile.buttonOptions.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) {
[self controllerButtonPressed:pressed keyCode:NKCODE_BUTTON_13];
};
}
if ([extendedProfile respondsToSelector:@selector(buttonMenu)] && extendedProfile.buttonMenu != nil) {
extendedProfile.buttonMenu.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) {
[self controllerButtonPressed:pressed keyCode:NKCODE_BUTTON_14];
};
}
#endif
#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) {
[self controllerButtonPressed:pressed keyCode:NKCODE_BUTTON_15];
};
}
#endif
extendedProfile.leftThumbstick.xAxis.valueChangedHandler = ^(GCControllerAxisInput *axis, float value) {
AxisInput axisInput;
axisInput.deviceId = DEVICE_ID_PAD_0;
axisInput.axisId = JOYSTICK_AXIS_X;
axisInput.value = value;
NativeAxis(&axisInput, 1);
};
extendedProfile.leftThumbstick.yAxis.valueChangedHandler = ^(GCControllerAxisInput *axis, float value) {
AxisInput axisInput;
axisInput.deviceId = DEVICE_ID_PAD_0;
axisInput.axisId = JOYSTICK_AXIS_Y;
axisInput.value = -value;
NativeAxis(&axisInput, 1);
};
// Map right thumbstick as another analog stick, particularly useful for controllers like the DualShock 3/4 when connected to an iOS device
extendedProfile.rightThumbstick.xAxis.valueChangedHandler = ^(GCControllerAxisInput *axis, float value) {
AxisInput axisInput;
axisInput.deviceId = DEVICE_ID_PAD_0;
axisInput.axisId = JOYSTICK_AXIS_Z;
axisInput.value = value;
NativeAxis(&axisInput, 1);
};
extendedProfile.rightThumbstick.yAxis.valueChangedHandler = ^(GCControllerAxisInput *axis, float value) {
AxisInput axisInput;
axisInput.deviceId = DEVICE_ID_PAD_0;
axisInput.axisId = JOYSTICK_AXIS_RZ;
axisInput.value = -value;
NativeAxis(&axisInput, 1);
};
}
#endif
void setCameraSize(int width, int height) {
[cameraHelper setCameraSize: width h:height];
}
void startVideo() {
[cameraHelper startVideo];
}
void stopVideo() {
[cameraHelper stopVideo];
}
-(void) PushCameraImageIOS:(long long)len buffer:(unsigned char*)data {
Camera::pushCameraImage(len, data);
}
void startLocation() {
[locationHelper startLocationUpdates];
}
void stopLocation() {
[locationHelper stopLocationUpdates];
}
-(void) SetGpsDataIOS:(CLLocation *)newLocation {
GPS::setGpsData((long long)newLocation.timestamp.timeIntervalSince1970,
newLocation.horizontalAccuracy/5.0,
newLocation.coordinate.latitude, newLocation.coordinate.longitude,
newLocation.altitude,
MAX(newLocation.speed * 3.6, 0.0), /* m/s to km/h */
0 /* bearing */);
}
@end
void System_LaunchUrl(LaunchUrlType urlType, char const* url)
{
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:[NSString stringWithCString:url encoding:NSStringEncodingConversionAllowLossy]]];
}
void bindDefaultFBO()
{
[sharedViewController bindDefaultFBO];
}
void EnableFZ(){};
void DisableFZ(){};