Commit 47f39b3a 王帅

package update

1 个父辈 65aa9a90
正在显示 736 个修改的文件 包含 25 行增加4726 行删除
......@@ -14,14 +14,14 @@ MonoBehaviour:
m_EditorClassIdentifier:
m_PixelRect:
serializedVersion: 2
x: -1
x: 11
y: 66
width: 1512
height: 836
m_ShowMode: 4
m_Title:
m_RootView: {fileID: 2}
m_MinSize: {x: 875, y: 492}
m_MinSize: {x: 875, y: 300}
m_MaxSize: {x: 10000, y: 10000}
m_Maximized: 0
--- !u!114 &2
......@@ -46,7 +46,7 @@ MonoBehaviour:
y: 0
width: 1512
height: 836
m_MinSize: {x: 875, y: 492}
m_MinSize: {x: 875, y: 300}
m_MaxSize: {x: 10000, y: 10000}
--- !u!114 &3
MonoBehaviour:
......@@ -96,7 +96,7 @@ MonoBehaviour:
m_MinSize: {x: 911, y: 442}
m_MaxSize: {x: 22006, y: 10021}
vertical: 0
controlID: 33
controlID: 123
--- !u!114 &5
MonoBehaviour:
m_ObjectHideFlags: 52
......@@ -142,7 +142,7 @@ MonoBehaviour:
m_MinSize: {x: 201, y: 442}
m_MaxSize: {x: 4001, y: 8042}
vertical: 1
controlID: 34
controlID: 124
--- !u!114 &7
MonoBehaviour:
m_ObjectHideFlags: 52
......@@ -186,7 +186,7 @@ MonoBehaviour:
serializedVersion: 2
x: 877
y: 0
width: 298
width: 359
height: 786
m_MinSize: {x: 232, y: 271}
m_MaxSize: {x: 10002, y: 10021}
......@@ -210,9 +210,9 @@ MonoBehaviour:
m_Children: []
m_Position:
serializedVersion: 2
x: 1175
x: 1236
y: 0
width: 337
width: 276
height: 786
m_MinSize: {x: 276, y: 71}
m_MaxSize: {x: 4001, y: 4021}
......@@ -294,7 +294,7 @@ MonoBehaviour:
m_Tooltip:
m_Pos:
serializedVersion: 2
x: 644
x: 656
y: 96
width: 230
height: 765
......@@ -302,9 +302,9 @@ MonoBehaviour:
m_SceneHierarchy:
m_TreeViewState:
scrollPos: {x: 0, y: 0}
m_SelectedIDs:
m_SelectedIDs: c8380000
m_LastClickedID: 0
m_ExpandedIDs: 04f8ffff20f8ffff22f8ffffb8f9ffffd4f9ffff66faffff66fbffff1e3b0000
m_ExpandedIDs: a2f9ffffbef9ffff50faffff66fbffff
m_RenameOverlay:
m_UserAcceptedRename: 0
m_Name:
......@@ -349,9 +349,9 @@ MonoBehaviour:
m_Tooltip:
m_Pos:
serializedVersion: 2
x: 1174
x: 1247
y: 96
width: 336
width: 275
height: 765
m_ViewDataDictionary: {fileID: 0}
m_OpenAddComponentMenu: 0
......@@ -387,9 +387,9 @@ MonoBehaviour:
m_Tooltip:
m_Pos:
serializedVersion: 2
x: 876
x: 888
y: 96
width: 296
width: 357
height: 765
m_ViewDataDictionary: {fileID: 0}
m_SearchFilter:
......@@ -405,20 +405,20 @@ MonoBehaviour:
m_SkipHidden: 0
m_SearchArea: 1
m_Folders:
- Assets/AASDKDemo/Scripts
- Assets/StreamingAssets
m_ViewMode: 1
m_StartGridSize: 16
m_LastFolders:
- Assets/AASDKDemo/Scripts
- Assets/StreamingAssets
m_LastFoldersGridSize: 16
m_LastProjectPath: /Users/ws/Desktop/Zplay/ZAnti-Addiction/ZAnti-Addiction-Unity/AASDK-Unity
m_LockTracker:
m_IsLocked: 0
m_FolderTreeState:
scrollPos: {x: 0, y: 0}
m_SelectedIDs: b6380000
m_LastClickedID: 14518
m_ExpandedIDs: 000000007e38000080380000823800008438000086380000883800008a3800008c3800008e3800009038000000ca9a3b
m_SelectedIDs: c0380000
m_LastClickedID: 14528
m_ExpandedIDs: 000000007e38000080380000823800008438000086380000883800009038000000ca9a3b
m_RenameOverlay:
m_UserAcceptedRename: 0
m_Name:
......@@ -434,7 +434,7 @@ MonoBehaviour:
m_IsRenaming: 0
m_OriginalEventType: 11
m_IsRenamingFilename: 1
m_ClientGUIView: {fileID: 8}
m_ClientGUIView: {fileID: 0}
m_SearchString:
m_CreateAssetUtility:
m_EndAction: {fileID: 0}
......@@ -501,7 +501,7 @@ MonoBehaviour:
m_ScrollPosition: {x: 0, y: 0}
m_GridSize: 16
m_SkipHiddenPackages: 0
m_DirectoriesAreaWidth: 154
m_DirectoriesAreaWidth: 178
--- !u!114 &15
MonoBehaviour:
m_ObjectHideFlags: 52
......@@ -523,7 +523,7 @@ MonoBehaviour:
m_Tooltip:
m_Pos:
serializedVersion: 2
x: -1
x: 11
y: 499
width: 644
height: 362
......@@ -615,7 +615,7 @@ MonoBehaviour:
m_Tooltip:
m_Pos:
serializedVersion: 2
x: -1
x: 11
y: 96
width: 644
height: 382
......
{
"process_id" : 48984,
"process_id" : 84579,
"version" : "2019.4.39f1c1",
"app_path" : "/Applications/Unity/Hub/Editor/2019.4.39f1c1/Unity.app",
"app_contents_path" : "/Applications/Unity/Hub/Editor/2019.4.39f1c1/Unity.app/Contents"
......
<linker>
<assembly fullname="UnityEngine">
<type fullname="UnityEngine.Object" preserve="nothing"/>
<type fullname="UnityEditor.VFXManager" preserve="nothing"/>
<type fullname="UnityEditor.PlayerSettings" preserve="nothing"/>
<type fullname="UnityEngine.Material" preserve="nothing"/>
<type fullname="UnityEngine.TextAsset" preserve="nothing"/>
<type fullname="UnityEngine.Shader" preserve="nothing"/>
<type fullname="UnityEditor.MonoScript" preserve="nothing"/>
<type fullname="UnityEditor.AudioManager" preserve="nothing"/>
<type fullname="UnityEditor.PhysicsManager" preserve="nothing"/>
<type fullname="UnityEditor.TimeManager" preserve="nothing"/>
<type fullname="UnityEditor.InputManager" preserve="nothing"/>
<type fullname="UnityEditor.TagManager" preserve="nothing"/>
<type fullname="UnityEditor.MonoManager" preserve="nothing"/>
<type fullname="UnityEngine.Rendering.GraphicsSettings" preserve="nothing"/>
<type fullname="UnityEngine.QualitySettings" preserve="nothing"/>
<type fullname="UnityEditor.Physics2DSettings" preserve="nothing"/>
<type fullname="UnityEngine.AudioBehaviour" preserve="nothing"/>
<type fullname="UnityEngine.Canvas" preserve="nothing"/>
<type fullname="UnityEngine.RectTransform" preserve="nothing"/>
<type fullname="UnityEngine.LightmapSettings" preserve="nothing"/>
<type fullname="UnityEngine.Sprite" preserve="nothing"/>
<type fullname="UnityEngine.Texture2D" preserve="nothing"/>
<type fullname="UnityEngine.Behaviour" preserve="nothing"/>
<type fullname="UnityEngine.MonoBehaviour" preserve="nothing"/>
<type fullname="UnityEngine.Transform" preserve="nothing"/>
<type fullname="UnityEngine.Component" preserve="nothing"/>
<type fullname="UnityEngine.GameObject" preserve="nothing"/>
<type fullname="UnityEngine.RenderSettings" preserve="nothing"/>
<type fullname="UnityEngine.AudioListener" preserve="nothing"/>
<type fullname="UnityEngine.Font" preserve="nothing"/>
<type fullname="UnityEngine.CanvasRenderer" preserve="nothing"/>
<type fullname="UnityEngine.Light" preserve="nothing"/>
<type fullname="UnityEngine.Texture" preserve="nothing"/>
<type fullname="UnityEngine.Cubemap" preserve="nothing"/>
<type fullname="UnityEngine.Camera" preserve="nothing"/>
</assembly>
<assembly fullname="Assembly-CSharp">
<type fullname="AASDKDemoScript" preserve="nothing"/>
</assembly>
<assembly fullname="UnityEngine.UI">
<type fullname="UnityEngine.EventSystems.EventSystem" preserve="nothing"/>
<type fullname="UnityEngine.EventSystems.StandaloneInputModule" preserve="nothing"/>
<type fullname="UnityEngine.UI.Button" preserve="nothing"/>
<type fullname="UnityEngine.UI.CanvasScaler" preserve="nothing"/>
<type fullname="UnityEngine.UI.GraphicRaycaster" preserve="nothing"/>
<type fullname="UnityEngine.UI.Image" preserve="nothing"/>
<type fullname="UnityEngine.UI.InputField" preserve="nothing"/>
<type fullname="UnityEngine.UI.Text" preserve="nothing"/>
</assembly>
</linker>
{"report":{"modules":[{"name":"Animation","dependencies":[{"name":"Animator","scenes":[],"dependencyType":0,"icon":null},{"name":"AnimatorController","scenes":[],"dependencyType":1,"icon":null},{"name":"AnimatorOverrideController","scenes":[],"dependencyType":0,"icon":null},{"name":"RuntimeAnimatorController","scenes":[],"dependencyType":1,"icon":null}]},{"name":"Audio","dependencies":[{"name":"AudioBehaviour","scenes":["Assets/AASDKDemo/Scenes/AASDKDemoScene.unity"],"dependencyType":0,"icon":null},{"name":"AudioClip","scenes":[],"dependencyType":0,"icon":null},{"name":"AudioListener","scenes":["Assets/AASDKDemo/Scenes/AASDKDemoScene.unity"],"dependencyType":0,"icon":null},{"name":"AudioManager","scenes":[],"dependencyType":1,"icon":null},{"name":"SampleClip","scenes":[],"dependencyType":1,"icon":null}]},{"name":"Core","dependencies":[{"name":"Behaviour","scenes":[],"dependencyType":1,"icon":null},{"name":"BuildSettings","scenes":[],"dependencyType":1,"icon":null},{"name":"Camera","scenes":["Assets/AASDKDemo/Scenes/AASDKDemoScene.unity"],"dependencyType":0,"icon":null},{"name":"Component","scenes":[],"dependencyType":1,"icon":null},{"name":"ComputeShader","scenes":[],"dependencyType":0,"icon":null},{"name":"Cubemap","scenes":["Assets/AASDKDemo/Scenes/AASDKDemoScene.unity"],"dependencyType":0,"icon":null},{"name":"CubemapArray","scenes":[],"dependencyType":0,"icon":null},{"name":"DelayedCallManager","scenes":[],"dependencyType":1,"icon":null},{"name":"EditorExtension","scenes":[],"dependencyType":1,"icon":null},{"name":"GameManager","scenes":[],"dependencyType":1,"icon":null},{"name":"GameObject","scenes":["Assets/AASDKDemo/Scenes/AASDKDemoScene.unity"],"dependencyType":0,"icon":null},{"name":"GlobalGameManager","scenes":[],"dependencyType":1,"icon":null},{"name":"GraphicsSettings","scenes":[],"dependencyType":0,"icon":null},{"name":"InputManager","scenes":[],"dependencyType":1,"icon":null},{"name":"LevelGameManager","scenes":[],"dependencyType":1,"icon":null},{"name":"Light","scenes":["Assets/AASDKDemo/Scenes/AASDKDemoScene.unity"],"dependencyType":0,"icon":null},{"name":"LightmapSettings","scenes":["Assets/AASDKDemo/Scenes/AASDKDemoScene.unity"],"dependencyType":0,"icon":null},{"name":"LightProbes","scenes":[],"dependencyType":0,"icon":null},{"name":"LowerResBlitTexture","scenes":[],"dependencyType":0,"icon":null},{"name":"Material","scenes":["Assets/AASDKDemo/Scenes/AASDKDemoScene.unity"],"dependencyType":0,"icon":null},{"name":"Mesh","scenes":[],"dependencyType":0,"icon":null},{"name":"MeshFilter","scenes":[],"dependencyType":0,"icon":null},{"name":"MeshRenderer","scenes":[],"dependencyType":0,"icon":null},{"name":"MonoBehaviour","scenes":["Assets/AASDKDemo/Scenes/AASDKDemoScene.unity"],"dependencyType":0,"icon":null},{"name":"MonoManager","scenes":[],"dependencyType":1,"icon":null},{"name":"MonoScript","scenes":["Assets/AASDKDemo/Scenes/AASDKDemoScene.unity"],"dependencyType":1,"icon":null},{"name":"NamedObject","scenes":["Assets/AASDKDemo/Scenes/AASDKDemoScene.unity"],"dependencyType":1,"icon":null},{"name":"Object","scenes":["Assets/AASDKDemo/Scenes/AASDKDemoScene.unity"],"dependencyType":0,"icon":null},{"name":"PlayerSettings","scenes":[],"dependencyType":1,"icon":null},{"name":"PreloadData","scenes":[],"dependencyType":0,"icon":null},{"name":"QualitySettings","scenes":[],"dependencyType":0,"icon":null},{"name":"RectTransform","scenes":["Assets/AASDKDemo/Scenes/AASDKDemoScene.unity"],"dependencyType":0,"icon":null},{"name":"ReflectionProbe","scenes":[],"dependencyType":0,"icon":null},{"name":"Renderer","scenes":[],"dependencyType":1,"icon":null},{"name":"RenderSettings","scenes":["Assets/AASDKDemo/Scenes/AASDKDemoScene.unity"],"dependencyType":0,"icon":null},{"name":"RenderTexture","scenes":[],"dependencyType":0,"icon":null},{"name":"ResourceManager","scenes":[],"dependencyType":1,"icon":null},{"name":"RuntimeInitializeOnLoadManager","scenes":[],"dependencyType":1,"icon":null},{"name":"ScriptMapper","scenes":[],"dependencyType":1,"icon":null},{"name":"Shader","scenes":["Assets/AASDKDemo/Scenes/AASDKDemoScene.unity"],"dependencyType":0,"icon":null},{"name":"Sprite","scenes":["Assets/AASDKDemo/Scenes/AASDKDemoScene.unity"],"dependencyType":0,"icon":null},{"name":"SpriteAtlas","scenes":[],"dependencyType":0,"icon":null},{"name":"SpriteRenderer","scenes":[],"dependencyType":0,"icon":null},{"name":"TagManager","scenes":[],"dependencyType":1,"icon":null},{"name":"TextAsset","scenes":["Assets/AASDKDemo/Scenes/AASDKDemoScene.unity"],"dependencyType":0,"icon":null},{"name":"Texture","scenes":[],"dependencyType":1,"icon":null},{"name":"Texture2D","scenes":["Assets/AASDKDemo/Scenes/AASDKDemoScene.unity"],"dependencyType":0,"icon":null},{"name":"Texture2DArray","scenes":[],"dependencyType":0,"icon":null},{"name":"Texture3D","scenes":[],"dependencyType":0,"icon":null},{"name":"TimeManager","scenes":[],"dependencyType":1,"icon":null},{"name":"Transform","scenes":[],"dependencyType":1,"icon":null},{"name":"Required by Animation Module","scenes":[],"dependencyType":2,"icon":"package/com.unity.modules.animation"},{"name":"Required by Audio Module","scenes":[],"dependencyType":2,"icon":"package/com.unity.modules.audio"},{"name":"Required by GameCenter Module","scenes":[],"dependencyType":2,"icon":"package/com.unity.modules.gamecenter"},{"name":"Required by ImageConversion Module","scenes":[],"dependencyType":2,"icon":"package/com.unity.modules.imageconversion"},{"name":"Required by IMGUI Module","scenes":[],"dependencyType":2,"icon":"package/com.unity.modules.imgui"},{"name":"Required by InputLegacy Module","scenes":[],"dependencyType":2,"icon":"package/com.unity.modules.inputlegacy"},{"name":"Required by TextRendering Module","scenes":[],"dependencyType":2,"icon":"package/com.unity.modules.textrendering"},{"name":"Required by UI Module","scenes":[],"dependencyType":2,"icon":"package/com.unity.modules.ui"}]},{"name":"GameCenter","dependencies":[]},{"name":"ImageConversion","dependencies":[{"name":"Required by GameCenter Module","scenes":[],"dependencyType":2,"icon":"package/com.unity.modules.gamecenter"}]},{"name":"IMGUI","dependencies":[]},{"name":"InputLegacy","dependencies":[{"name":"Required by IMGUI Module","scenes":[],"dependencyType":2,"icon":"package/com.unity.modules.imgui"}]},{"name":"SharedInternals","dependencies":[{"name":"Required by Animation Module","scenes":[],"dependencyType":2,"icon":"package/com.unity.modules.animation"},{"name":"Required by Audio Module","scenes":[],"dependencyType":2,"icon":"package/com.unity.modules.audio"},{"name":"Required by Core Module","scenes":[],"dependencyType":2,"icon":"package/com.unity.modules.core"},{"name":"Required by GameCenter Module","scenes":[],"dependencyType":2,"icon":"package/com.unity.modules.gamecenter"},{"name":"Required by ImageConversion Module","scenes":[],"dependencyType":2,"icon":"package/com.unity.modules.imageconversion"},{"name":"Required by IMGUI Module","scenes":[],"dependencyType":2,"icon":"package/com.unity.modules.imgui"},{"name":"Required by InputLegacy Module","scenes":[],"dependencyType":2,"icon":"package/com.unity.modules.inputlegacy"},{"name":"Required by TextRendering Module","scenes":[],"dependencyType":2,"icon":"package/com.unity.modules.textrendering"},{"name":"Required by UI Module","scenes":[],"dependencyType":2,"icon":"package/com.unity.modules.ui"}]},{"name":"TextRendering","dependencies":[{"name":"Font","scenes":["Assets/AASDKDemo/Scenes/AASDKDemoScene.unity"],"dependencyType":0,"icon":null},{"name":"Required by IMGUI Module","scenes":[],"dependencyType":2,"icon":"package/com.unity.modules.imgui"},{"name":"Required by UI Module","scenes":[],"dependencyType":2,"icon":"package/com.unity.modules.ui"}]},{"name":"UI","dependencies":[{"name":"Canvas","scenes":["Assets/AASDKDemo/Scenes/AASDKDemoScene.unity"],"dependencyType":0,"icon":null},{"name":"CanvasGroup","scenes":[],"dependencyType":0,"icon":null},{"name":"CanvasRenderer","scenes":["Assets/AASDKDemo/Scenes/AASDKDemoScene.unity"],"dependencyType":0,"icon":null}]}]}}
\ No newline at end of file
-out="/Users/ws/Desktop/Zplay/ZAnti-Addiction/ZAnti-Addiction-Unity/AASDK-Unity/Temp/StagingArea/Data/Managed/tempStrip" -x="/Users/ws/Desktop/Zplay/ZAnti-Addiction/ZAnti-Addiction-Unity/AASDK-Unity/Temp/StagingArea/Data/Managed/../platform_native_link.xml" -x="/var/folders/3f/mrlf6c5d7qn5tdqc_msdhxl40000gn/T/tmp2c1f8a53.tmp" -x="/Users/ws/Desktop/Zplay/ZAnti-Addiction/ZAnti-Addiction-Unity/AASDK-Unity/Temp/StagingArea/Data/Managed/TypesInScenes.xml" -d="/Users/ws/Desktop/Zplay/ZAnti-Addiction/ZAnti-Addiction-Unity/AASDK-Unity/Temp/StagingArea/Data/Managed" --include-unity-root-assembly="/Users/ws/Desktop/Zplay/ZAnti-Addiction/ZAnti-Addiction-Unity/AASDK-Unity/Temp/StagingArea/Data/Managed/Assembly-CSharp.dll" --include-unity-root-assembly="/Users/ws/Desktop/Zplay/ZAnti-Addiction/ZAnti-Addiction-Unity/AASDK-Unity/Temp/StagingArea/Data/Managed/UnityEngine.UI.dll" --dotnetruntime=il2cpp --dotnetprofile=unityaot --use-editor-options --include-directory="/Users/ws/Desktop/Zplay/ZAnti-Addiction/ZAnti-Addiction-Unity/AASDK-Unity/Temp/StagingArea/Data/Managed" --rule-set=Conservative --editor-data-file="/Users/ws/Desktop/Zplay/ZAnti-Addiction/ZAnti-Addiction-Unity/AASDK-Unity/Temp/StagingArea/Data/Managed/EditorToUnityLinkerData.json" --platform=iOS --enable-engine-module-stripping --engine-modules-asset-file="/Applications/Unity/Hub/Editor/2019.4.39f1c1/PlaybackEngines/iOSSupport/Whitelists/../modules.asset"
\ No newline at end of file
wait-for-native-debugger=0
vr-enabled=0
hdr-display-enabled=0
此文件的差异太大,无法显示。
#pragma once
// Enabling this will force app to do a hard crash instead of a nice exit when UnhandledException
// is thrown. This will force iOS to generate a standard crash report, that can be submitted to
// iTunes by app users and inspected by developers.
#define ENABLE_IOS_CRASH_REPORTING 1
// Enabling this will add a custom Objective-C Uncaught Exception handler, which will print out
// exception information to console.
#define ENABLE_OBJC_UNCAUGHT_EXCEPTION_HANDLER 1
// Enable custom crash reporter to capture crashes. Crash logs will be available to scripts via
// CrashReport API.
#define ENABLE_CUSTOM_CRASH_REPORTER 0
// Enable submission of custom crash reports to Unity servers. This will enable custom crash
// reporter.
#define ENABLE_CRASH_REPORT_SUBMISSION 0
#if ENABLE_CRASH_REPORT_SUBMISSION && !ENABLE_CUSTOM_CRASH_REPORTER
#undef ENABLE_CUSTOM_CRASH_REPORTER
#define ENABLE_CUSTOM_CRASH_REPORTER 1
#endif
#if PLATFORM_TVOS
#undef ENABLE_CUSTOM_CRASH_REPORTER
#define ENABLE_CUSTOM_CRASH_REPORTER 0
#endif
extern "C" void UnityInstallPostCrashCallback();
void InitCrashHandling();
#import "PLCrashReporter.h"
#import "CrashReporter.h"
#include "UndefinePlatforms.h"
#include <mach-o/ldsyms.h>
#include "RedefinePlatforms.h"
extern "C" NSString* UnityGetCrashReportsPath();
static NSUncaughtExceptionHandler* gsCrashReporterUEHandler = NULL;
static decltype(_mh_execute_header) * sExecuteHeader = NULL;
extern "C" void UnitySetExecuteMachHeader(const decltype(_mh_execute_header)* header)
{
sExecuteHeader = header;
}
extern "C" const decltype(_mh_execute_header) * UnityGetExecuteMachHeader() {
return sExecuteHeader;
}
static void SavePendingCrashReport()
{
if (![[UnityPLCrashReporter sharedReporter] hasPendingCrashReport])
return;
NSFileManager *fm = [NSFileManager defaultManager];
NSError *error;
if (![fm createDirectoryAtPath: UnityGetCrashReportsPath() withIntermediateDirectories: YES attributes: nil error: &error])
{
::printf("CrashReporter: could not create crash report directory: %s\n", [[error localizedDescription] UTF8String]);
return;
}
NSData *data = [[UnityPLCrashReporter sharedReporter] loadPendingCrashReportDataAndReturnError: &error];
if (data == nil)
{
::printf("CrashReporter: failed to load crash report data: %s\n", [[error localizedDescription] UTF8String]);
return;
}
NSString* file = [UnityGetCrashReportsPath() stringByAppendingPathComponent: @"crash-"];
unsigned long long seconds = (unsigned long long)[[NSDate date] timeIntervalSince1970];
file = [file stringByAppendingString: [NSString stringWithFormat: @"%llu", seconds]];
file = [file stringByAppendingString: @".plcrash"];
if ([data writeToFile: file atomically: YES])
{
::printf("CrashReporter: saved pending crash report.\n");
if (![[UnityPLCrashReporter sharedReporter] purgePendingCrashReportAndReturnError: &error])
{
::printf("CrashReporter: couldn't remove pending report: %s\n", [[error localizedDescription] UTF8String]);
}
}
else
{
::printf("CrashReporter: couldn't save crash report.\n");
}
// Now copy out a pending version that we can delete if/when we send it
file = [UnityGetCrashReportsPath() stringByAppendingPathComponent: @"crash-pending.plcrash"];
if ([data writeToFile: file atomically: YES])
{
::printf("CrashReporter: saved copy of pending crash report.\n");
}
else
{
::printf("CrashReporter: couldn't save copy of pending crash report.\n");
}
}
static void InitCrashReporter()
{
NSError *error;
UnityInstallPostCrashCallback();
if ([[UnityPLCrashReporter sharedReporter] enableCrashReporterAndReturnError: &error])
::printf("CrashReporter: initialized\n");
else
NSLog(@"CrashReporter: could not enable crash reporter: %@", error);
SavePendingCrashReport();
}
static void UncaughtExceptionHandler(NSException *exception)
{
NSLog(@"Uncaught exception: %@: %@\n%@", [exception name], [exception reason], [exception callStackSymbols]);
if (gsCrashReporterUEHandler)
gsCrashReporterUEHandler(exception);
}
static void InitObjCUEHandler()
{
// Crash reporter sets its own handler, so we have to save it and call it manually
gsCrashReporterUEHandler = NSGetUncaughtExceptionHandler();
NSSetUncaughtExceptionHandler(&UncaughtExceptionHandler);
}
void InitCrashHandling()
{
#if ENABLE_CUSTOM_CRASH_REPORTER
InitCrashReporter();
#endif
#if ENABLE_OBJC_UNCAUGHT_EXCEPTION_HANDLER
InitObjCUEHandler();
#endif
}
// This function will be called when AppDomain.CurrentDomain.UnhandledException event is triggered.
// When running on device the app will do a hard crash and it will generate a crash log.
extern "C" void CrashedCheckBelowForHintsWhy()
{
#if ENABLE_IOS_CRASH_REPORTING || ENABLE_CUSTOM_CRASH_REPORTER
// Make app crash hard here
__builtin_trap();
// Just in case above doesn't work
abort();
#endif
}
/* SINGLE CPP FILE TO GENERATE SEAMLESS BRIDGE BETWEEN BINARIES < SHARED ENGINE LIBRARY WITH ABSTRACT EXTERN FUNCTIONS> | < PLAYER EXECUTABLE WITH ABSTRACT FUNCTION IMPLEMENTATION >
1. if building shared engine library this file will:
define body for Unity* methods that proxy call to actual method
actual method will be set later from outside with respective call to SetUnity*Body
defines SetUnity*Body method to set actual method for call, theese functions are exported from library
2. if building player against shared engine library this file will:
calls SetUnity*Body providing actual method to be called by shared engine library later
wraps all SetUnity*Body calls in one single method SetAllUnityFunctionsForDynamicPlayerLib
- notes:
file will be included only if development / il2ccp and:
- for xcode project if BuildSettings.UseDynamicPlayerLib is true
- for player if (build.pl staticLib=1, jam BUILD_IOS_DYNAMIC_PLAYER=1)
DynamicLibEngineAPI-functions.h include list of functions to proxy calls from player to trampoline
- each function inlist is defined with UnityExternCall or UnityExternCall4StaticMember
*/
// deal with __VA_ARGS__ to convert them to formated lists with provided M macro
#define VA_ARGS_COUNT(...) INTERNAL_GET_ARG_COUNT_PRIVATE(0, ## __VA_ARGS__, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define INTERNAL_GET_ARG_COUNT_PRIVATE(_0, _1_, _2_, _3_, _4_, _5_, _6_, _7_, _8_, _9_, _10_, _11_, _12_, _13_, _14_, _15_, _16_, _17_, _18_, _19_, _20_, count, ...) count
#define JOIN_VA_ARGS_0(M, ...)
#define JOIN_VA_ARGS_1(M, T1) M(T1,1)
#define JOIN_VA_ARGS_2(M, T1, T2) M(T1,1), M(T2,2)
#define JOIN_VA_ARGS_3(M, T1, T2, T3) M(T1,1), M(T2,2), M(T3,3)
#define JOIN_VA_ARGS_4(M, T1, T2, T3, T4) M(T1,1), M(T2,2), M(T3,3), M(T4,4)
#define JOIN_VA_ARGS_5(M, T1, T2, T3, T4, T5) M(T1,1), M(T2,2), M(T3,3), M(T4,4), M(T5,5)
#define JOIN_VA_ARGS_6(M, T1, T2, T3, T4, T5, T6) M(T1,1), M(T2,2), M(T3,3), M(T4,4), M(T5,5), M(T6,6)
#define JOIN_VA_ARGS_7(M, T1, T2, T3, T4, T5, T6, T7) M(T1,1), M(T2,2), M(T3,3), M(T4,4), M(T5,5), M(T6,6), M(T7,7)
#define JOIN_VA_ARGS_8(M, T1, T2, T3, T4, T5, T6, T7, T8) M(T1,1), M(T2,2), M(T3,3), M(T4,4), M(T5,5), M(T6,6), M(T7,7), M(T8,8)
#define JOIN_VA_ARGS_9(M, T1, T2, T3, T4, T5, T6, T7, T8, T9) M(T1,1), M(T2,2), M(T3,3), M(T4,4), M(T5,5), M(T6,6), M(T7,7), M(T8,8), M(T9,9)
#define JOIN_VA_ARGS___(M, N, ...) JOIN_VA_ARGS_##N(M, __VA_ARGS__ )
#define JOIN_VA_ARGS__(M, N, ...) JOIN_VA_ARGS___(M,N,__VA_ARGS__)
#define JOIN_VA_ARGS_(M, ...) JOIN_VA_ARGS__(M,VA_ARGS_COUNT(__VA_ARGS__), __VA_ARGS__)
#define JOIN_VA_ARGS(M, ...) JOIN_VA_ARGS_(M,__VA_ARGS__)
// convert to function definition params:
// egz: VA_ARGS_TO_PARAMS(int, char, bool) expands to: int p3, char p2, bool p1
#define VA_JOIN_AS_PARAMS(type, index) type p##index
#define VA_ARGS_TO_PARAMS(...) JOIN_VA_ARGS(VA_JOIN_AS_PARAMS,__VA_ARGS__)
// convert to function call params
// egz: VA_ARGS_TO_CALL(int,char,bool) exapnds to: p3, p2, p1
#define VA_JOIN_AS_CALL(type, index) p##index
#define VA_ARGS_TO_CALL(...) JOIN_VA_ARGS(VA_JOIN_AS_CALL,__VA_ARGS__)
#ifndef UNITY_ENGINE_DYNAMICLIB_MODE
#define UNITY_ENGINE_DYNAMICLIB_MODE 0
#endif
#if UNITY_ENGINE_DYNAMICLIB_MODE
// [ part of Unity Player ]
// this part generates Unity* functions that act as proxy to call actual function from trampoline
// for each function in DynamicLibEngineAPI-functions.h will be generated proxy function
// proxy for extern "C" function
// egz: UnityExternCall(int, UnityTestFunctionName, int);
// will expand to:
// static int(*gPtrUnityTestFunctionName)(int) = nullptr;
// extern "C" int UnityTestFunctionName(int p1) {
// assert(gPtrUnityTestFunctionName) != nullptr);
// return gPtrUnityTestFunctionName(p1);
// }
// __attribute__((visibility("default")))
// extern "C" void SetUnityTestFunctionNameBody(decltype(&UnityTestFunctionName) fPtr) {
// gPtrUnityTestFunctionName = fPtr;
// }
#define UnityExternCall(returnType, funcName, ...) \
static returnType(*gPtr##funcName)(__VA_ARGS__) = nullptr; \
extern "C" returnType funcName(VA_ARGS_TO_PARAMS(__VA_ARGS__)) {\
assert(gPtr##funcName != nullptr); \
return gPtr##funcName(VA_ARGS_TO_CALL(__VA_ARGS__)); \
} \
__attribute__((visibility("default"))) \
extern "C" void Set##funcName##Body(decltype(&funcName) fPtr) { \
gPtr##funcName = fPtr; \
}
// proxy for class static methods
// egz: UnityExternCall4StaticMember(int, MyClass MyMethod, int);
// will expand to:
// static int(*gPtrMyClassMyMethod)(int) = nullptr;
// int MyClass::MyMethod(int p1) {
// assert(gPtrMyClassMyMethod) != nullptr);
// return gPtrMyClassMyMethod(p1);
// }
// __attribute__((visibility("default")))
// extern "C" void SetMyClassMyMethodBody(decltype(gPtrMyClassMyMethod) fPtr) {
// gPtrMyClassMyMethod = fPtr;
// }
#define UnityExternCall4StaticMember(returnType, className, funcName, ...) \
static returnType(*gPtr##className##funcName)(__VA_ARGS__) = nullptr; \
returnType className::funcName(VA_ARGS_TO_PARAMS(__VA_ARGS__)) { \
assert(gPtr##className##funcName != nullptr); \
return gPtr##className##funcName(VA_ARGS_TO_CALL(__VA_ARGS__)); \
} \
__attribute__((visibility("default"))) \
extern "C" void Set##className##funcName##Body(decltype(gPtr##className##funcName) fPtr) { \
gPtr##className##funcName = fPtr; \
}
#include "PlatformDependent/iPhonePlayer/Trampoline/Classes/Unity/UnitySharedDecls.h"
#include "PlatformDependent/iPhonePlayer/Trampoline/Classes/Unity/UnityRendering.h"
#include "PlatformDependent/iPhonePlayer/TrampolineInterface.h"
#include "Runtime/Graphics/DisplayManager.h"
#include "Runtime/Input/LocationService.h"
#import <UIKit/UIKit.h>
#include "External/baselib/builds/Include/PreExternalInclude.h"
#include <mach-o/ldsyms.h>
#include "External/baselib/builds/Include/PostExternalInclude.h"
#include "DynamicLibEngineAPI-functions.h"
#undef UnityExternCall
#undef UnityExternCall4StaticMember
#else
// [ part of Xcode project ]
// for each function defined in DynamicLibEngineAPI-functions.h will be generated SetUnity*Body function
// for extern "C" functions
// egz: UnityExternCall(int, UnityTestFunctionName, int);
// will expand to:
// extern "C" UnityTestFunctionName(int);
// extern "C" SetUnityTestFunctionName(decltype(&UnityTestFunctionName));
#define UnityExternCall(returnType, funcName, ...) \
extern "C" returnType funcName(__VA_ARGS__); \
extern "C" void Set##funcName##Body(decltype(&funcName));
// for class static method
// egz: UnityExternCall4StaticMember(int, MyClass MyMethod, int);
// will expand to:
// extern "C" void SetMyClassMyMethodBody(decltype(&MyClass::MyMethod));
#define UnityExternCall4StaticMember(returnType, className, funcName, ...) \
extern "C" void Set##className##funcName##Body(decltype(&className::funcName));
#include "UnityRendering.h"
#include "Classes/iPhone_Sensors.h"
#include "UndefinePlatforms.h"
#include <mach-o/ldsyms.h>
#include "RedefinePlatforms.h"
#include "DynamicLibEngineAPI-functions.h"
#undef UnityExternCall
#undef UnityExternCall4StaticMember
// single function to call every Set*Body function from DynamicLibEngineAPI-functions.h
#define UnityExternCall(returnType, funcName, ...) Set##funcName##Body(funcName);
#define UnityExternCall4StaticMember(returnType, className, funcName, ...) Set##className##funcName##Body(className::funcName)
extern "C" void SetAllUnityFunctionsForDynamicPlayerLib()
{
#include "DynamicLibEngineAPI-functions.h"
}
#undef UnityExternCall
#undef UnityExternCall4StaticMember
#endif
/*
* Author: Landon Fuller <landonf@plausiblelabs.com>
*
* Copyright (c) 2008-2009 Plausible Labs Cooperative, Inc.
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#import <Foundation/Foundation.h>
/**
* @ingroup functions
*
* Prototype of a callback function used to execute additional user code with signal information as provided
* by PLCrashReporter. Called upon completion of crash handling, after the crash report has been written to disk.
*
* @param info The signal info.
* @param uap The crash's threads context.
* @param context The API client's supplied context value.
*
* @sa @ref async_safety
* @sa PLCrashReporter::setPostCrashCallbacks:
*/
typedef void (*UnityPLCrashReporterPostCrashSignalCallback)(siginfo_t *info, ucontext_t *uap, void *context);
/**
* @ingroup types
*
* This structure contains callbacks supported by PLCrashReporter to allow the host application to perform
* additional tasks prior to program termination after a crash has occured.
*
* @sa @ref async_safety
*/
typedef struct UnityPLCrashReporterCallbacks
{
/** The version number of this structure. If not one of the defined version numbers for this type, the behavior
* is undefined. The current version of this structure is 0. */
uint16_t version;
/** An arbitrary user-supplied context value. This value may be NULL. */
void *context;
/** The callback used to report caught signal information. In version 0 of this structure, all crashes will be
* reported via this function. */
UnityPLCrashReporterPostCrashSignalCallback handleSignal;
} UnityPLCrashReporterCallbacks;
@interface UnityPLCrashReporter : NSObject
{
@private
/** YES if the crash reporter has been enabled */
BOOL _enabled;
/** Application identifier */
NSString *_applicationIdentifier;
/** Application version */
NSString *_applicationVersion;
/** Path to the crash reporter internal data directory */
NSString *_crashReportDirectory;
}
+ (UnityPLCrashReporter *)sharedReporter;
- (BOOL)hasPendingCrashReport;
- (NSData *)loadPendingCrashReportData;
- (NSData *)loadPendingCrashReportDataAndReturnError:(NSError **)outError;
- (NSData *)generateLiveReport;
- (NSData *)generateLiveReportAndReturnError:(NSError **)outError;
- (BOOL)purgePendingCrashReport;
- (BOOL)purgePendingCrashReportAndReturnError:(NSError **)outError;
- (BOOL)enableCrashReporter;
- (BOOL)enableCrashReporterAndReturnError:(NSError **)outError;
- (void)setCrashCallbacks:(UnityPLCrashReporterCallbacks *)callbacks;
@end
#pragma once
#include "LifeCycleListener.h"
@protocol AppDelegateListener<LifeCycleListener>
@optional
// these do not have apple defined notifications, so we use our own notifications
// notification will be posted from
// - (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken
// notification user data is deviceToken
- (void)didRegisterForRemoteNotificationsWithDeviceToken:(NSNotification*)notification;
// notification will be posted from
// - (void)application:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)error
// notification user data is error
- (void)didFailToRegisterForRemoteNotificationsWithError:(NSNotification*)notification;
// notification will be posted from
// - (void)application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary*)userInfo
// notification user data is userInfo
- (void)didReceiveRemoteNotification:(NSNotification*)notification;
// notification will be posted from
// - (void)application:(UIApplication*)application didReceiveLocalNotification:(UILocalNotification*)notification
// notification user data is notification
- (void)didReceiveLocalNotification:(NSNotification*)notification;
// notification will be posted from
// - (BOOL)application:(UIApplication*)application openURL:(NSURL*)url sourceApplication:(NSString*)sourceApplication annotation:(id)annotation
// notification user data is the NSDictionary containing all the params
- (void)onOpenURL:(NSNotification*)notification;
// notification will be posted from
// - (BOOL)application:(UIApplication*)application willFinishLaunchingWithOptions:(NSDictionary*)launchOptions
// notification user data is the NSDictionary containing launchOptions
- (void)applicationWillFinishLaunchingWithOptions:(NSNotification*)notification;
// notification will be posted from
// - (void)application:(UIApplication*)application handleEventsForBackgroundURLSession:(nonnull NSString *)identifier completionHandler:(nonnull void (^)())completionHandler
// notification user data is NSDictionary with one item where key is session identifier and value is completion handler
- (void)onHandleEventsForBackgroundURLSession:(NSNotification*)notification;
// these are just hooks to existing notifications
- (void)applicationDidReceiveMemoryWarning:(NSNotification*)notification;
- (void)applicationSignificantTimeChange:(NSNotification*)notification;
- (void)applicationWillChangeStatusBarFrame:(NSNotification*)notification;
- (void)applicationWillChangeStatusBarOrientation:(NSNotification*)notification;
@end
void UnityRegisterAppDelegateListener(id<AppDelegateListener> obj);
void UnityUnregisterAppDelegateListener(id<AppDelegateListener> obj);
extern "C" __attribute__((visibility("default"))) NSString* const kUnityDidRegisterForRemoteNotificationsWithDeviceToken;
extern "C" __attribute__((visibility("default"))) NSString* const kUnityDidFailToRegisterForRemoteNotificationsWithError;
extern "C" __attribute__((visibility("default"))) NSString* const kUnityDidReceiveRemoteNotification;
extern "C" __attribute__((visibility("default"))) NSString* const kUnityDidReceiveLocalNotification;
extern "C" __attribute__((visibility("default"))) NSString* const kUnityOnOpenURL;
extern "C" __attribute__((visibility("default"))) NSString* const kUnityWillFinishLaunchingWithOptions;
extern "C" __attribute__((visibility("default"))) NSString* const kUnityHandleEventsForBackgroundURLSession;
#include "AppDelegateListener.h"
#define DEFINE_NOTIFICATION(name) extern "C" __attribute__((visibility ("default"))) NSString* const name = @#name;
DEFINE_NOTIFICATION(kUnityDidRegisterForRemoteNotificationsWithDeviceToken);
DEFINE_NOTIFICATION(kUnityDidFailToRegisterForRemoteNotificationsWithError);
DEFINE_NOTIFICATION(kUnityDidReceiveRemoteNotification);
DEFINE_NOTIFICATION(kUnityDidReceiveLocalNotification);
DEFINE_NOTIFICATION(kUnityOnOpenURL);
DEFINE_NOTIFICATION(kUnityWillFinishLaunchingWithOptions);
DEFINE_NOTIFICATION(kUnityHandleEventsForBackgroundURLSession);
#undef DEFINE_NOTIFICATION
void UnityRegisterAppDelegateListener(id<AppDelegateListener> obj)
{
#define REGISTER_SELECTOR(sel, notif_name) \
if([obj respondsToSelector:sel]) \
[[NSNotificationCenter defaultCenter] addObserver:obj \
selector:sel \
name:notif_name \
object:nil \
]; \
UnityRegisterLifeCycleListener(obj);
REGISTER_SELECTOR(@selector(didRegisterForRemoteNotificationsWithDeviceToken:), kUnityDidRegisterForRemoteNotificationsWithDeviceToken);
REGISTER_SELECTOR(@selector(didFailToRegisterForRemoteNotificationsWithError:), kUnityDidFailToRegisterForRemoteNotificationsWithError);
REGISTER_SELECTOR(@selector(didReceiveRemoteNotification:), kUnityDidReceiveRemoteNotification);
REGISTER_SELECTOR(@selector(didReceiveLocalNotification:), kUnityDidReceiveLocalNotification);
REGISTER_SELECTOR(@selector(onOpenURL:), kUnityOnOpenURL);
REGISTER_SELECTOR(@selector(applicationDidReceiveMemoryWarning:), UIApplicationDidReceiveMemoryWarningNotification);
REGISTER_SELECTOR(@selector(applicationSignificantTimeChange:), UIApplicationSignificantTimeChangeNotification);
#if !PLATFORM_TVOS
REGISTER_SELECTOR(@selector(applicationWillChangeStatusBarFrame:), UIApplicationWillChangeStatusBarFrameNotification);
REGISTER_SELECTOR(@selector(applicationWillChangeStatusBarOrientation:), UIApplicationWillChangeStatusBarOrientationNotification);
#endif
REGISTER_SELECTOR(@selector(applicationWillFinishLaunchingWithOptions:), kUnityWillFinishLaunchingWithOptions);
REGISTER_SELECTOR(@selector(onHandleEventsForBackgroundURLSession:), kUnityHandleEventsForBackgroundURLSession);
#undef REGISTER_SELECTOR
}
void UnityUnregisterAppDelegateListener(id<AppDelegateListener> obj)
{
UnityUnregisterLifeCycleListener(obj);
[[NSNotificationCenter defaultCenter] removeObserver: obj name: kUnityDidRegisterForRemoteNotificationsWithDeviceToken object: nil];
[[NSNotificationCenter defaultCenter] removeObserver: obj name: kUnityDidFailToRegisterForRemoteNotificationsWithError object: nil];
[[NSNotificationCenter defaultCenter] removeObserver: obj name: kUnityDidReceiveRemoteNotification object: nil];
[[NSNotificationCenter defaultCenter] removeObserver: obj name: kUnityDidReceiveLocalNotification object: nil];
[[NSNotificationCenter defaultCenter] removeObserver: obj name: kUnityOnOpenURL object: nil];
[[NSNotificationCenter defaultCenter] removeObserver: obj name: UIApplicationDidReceiveMemoryWarningNotification object: nil];
[[NSNotificationCenter defaultCenter] removeObserver: obj name: UIApplicationSignificantTimeChangeNotification object: nil];
#if !PLATFORM_TVOS
[[NSNotificationCenter defaultCenter] removeObserver: obj name: UIApplicationWillChangeStatusBarFrameNotification object: nil];
[[NSNotificationCenter defaultCenter] removeObserver: obj name: UIApplicationWillChangeStatusBarOrientationNotification object: nil];
#endif
}
#pragma once
// important app life-cycle events
@protocol LifeCycleListener<NSObject>
@optional
- (void)didFinishLaunching:(NSNotification*)notification;
- (void)didBecomeActive:(NSNotification*)notification;
- (void)willResignActive:(NSNotification*)notification;
- (void)didEnterBackground:(NSNotification*)notification;
- (void)willEnterForeground:(NSNotification*)notification;
- (void)willTerminate:(NSNotification*)notification;
- (void)unityDidUnload:(NSNotification*)notification;
- (void)unityDidQuit:(NSNotification*)notification;
@end
void UnityRegisterLifeCycleListener(id<LifeCycleListener> obj);
void UnityUnregisterLifeCycleListener(id<LifeCycleListener> obj);
#ifdef __cplusplus
extern "C" {
#endif
extern __attribute__((visibility("default"))) NSString* const kUnityDidUnload;
extern __attribute__((visibility("default"))) NSString* const kUnityDidQuit;
#ifdef __cplusplus
} // extern "C"
#endif
#include "LifeCycleListener.h"
#define DEFINE_NOTIFICATION(name) extern "C" __attribute__((visibility ("default"))) NSString* const name = @#name;
DEFINE_NOTIFICATION(kUnityDidUnload);
DEFINE_NOTIFICATION(kUnityDidQuit);
void UnityRegisterLifeCycleListener(id<LifeCycleListener> obj)
{
#define REGISTER_SELECTOR(sel, notif_name) \
if([obj respondsToSelector:sel]) \
[[NSNotificationCenter defaultCenter] addObserver:obj \
selector:sel \
name:notif_name \
object:nil \
]; \
REGISTER_SELECTOR(@selector(didFinishLaunching:), UIApplicationDidFinishLaunchingNotification);
REGISTER_SELECTOR(@selector(didBecomeActive:), UIApplicationDidBecomeActiveNotification);
REGISTER_SELECTOR(@selector(willResignActive:), UIApplicationWillResignActiveNotification);
REGISTER_SELECTOR(@selector(didEnterBackground:), UIApplicationDidEnterBackgroundNotification);
REGISTER_SELECTOR(@selector(willEnterForeground:), UIApplicationWillEnterForegroundNotification);
REGISTER_SELECTOR(@selector(willTerminate:), UIApplicationWillTerminateNotification);
REGISTER_SELECTOR(@selector(unityDidUnload:), kUnityDidUnload);
REGISTER_SELECTOR(@selector(unityDidQuit:), kUnityDidQuit);
#undef REGISTER_SELECTOR
}
void UnityUnregisterLifeCycleListener(id<LifeCycleListener> obj)
{
[[NSNotificationCenter defaultCenter] removeObserver: obj name: UIApplicationDidFinishLaunchingNotification object: nil];
[[NSNotificationCenter defaultCenter] removeObserver: obj name: UIApplicationDidBecomeActiveNotification object: nil];
[[NSNotificationCenter defaultCenter] removeObserver: obj name: UIApplicationWillResignActiveNotification object: nil];
[[NSNotificationCenter defaultCenter] removeObserver: obj name: UIApplicationDidEnterBackgroundNotification object: nil];
[[NSNotificationCenter defaultCenter] removeObserver: obj name: UIApplicationWillEnterForegroundNotification object: nil];
[[NSNotificationCenter defaultCenter] removeObserver: obj name: UIApplicationWillTerminateNotification object: nil];
[[NSNotificationCenter defaultCenter] removeObserver: obj name: kUnityDidUnload object: nil];
[[NSNotificationCenter defaultCenter] removeObserver: obj name: kUnityDidQuit object: nil];
}
#pragma once
#include "LifeCycleListener.h"
struct UnityDisplaySurfaceBase; // Unity/UnityRendering.h
struct RenderingSurfaceParams; // Unity/DisplayManager.h
// due to delicate nature of render loop we have just one delegate in app
// if you need to use several rendering delegates you need to do one of:
// 1. create custom delegate that will have code to combine effects by itself
// 2. use helper that simply holds array of delegates (which will work only in easiest cases)
@protocol RenderPluginDelegate<LifeCycleListener, NSObject>
@required
// this will be called right after gles intialization.
// surface pointer will never be changed, so you should keep it.
// the only valid fields in there as of now are layer and context
- (void)mainDisplayInited:(struct UnityDisplaySurfaceBase*)surface;
@optional
// this will be called before recreating main display surface (from [UnityView recreateRenderingSurface])
// you can tweak params here.
// use it for enabling CVTextureCache support and the likes
- (void)onBeforeMainDisplaySurfaceRecreate:(struct RenderingSurfaceParams*)params;
// this will be called right after recreating main display surface (from [UnityView recreateRenderingSurface])
// as [UnityView recreateRenderingSurface] is the only place where unity itself will trigger surface recreate
// you can use this method to update your rendering depending on changes
- (void)onAfterMainDisplaySurfaceRecreate;
// this will be called after frame render and msaa resolve but before blitting to system FB
// you can expect that frame contents are ready (though still in target resolution)
// use it for anylizing/postprocessing rendered frame, taking screenshot and the like
// you should use targetFB if it is not 0
// otherwise use systemFB (covers case of intermediate fb not needed: no msaa, native res, no CVTextureCache involved)
- (void)onFrameResolved;
@end
// simple helper for common plugin stuff
// you can implement protocol directly, but subclassing this will provide some common implementation
@interface RenderPluginDelegate : NSObject<RenderPluginDelegate>
{
struct UnityDisplaySurfaceBase* mainDisplaySurface;
}
- (void)mainDisplayInited:(struct UnityDisplaySurfaceBase*)surface;
@end
// simple helper to have an array of render delegates.
// be warned that it works in simplest cases only, when there is no interop between delegates
@interface RenderPluginArrayDelegate : RenderPluginDelegate
{
NSArray* delegateArray;
}
@property(nonatomic, retain) NSArray* delegateArray;
- (void)mainDisplayInited:(struct UnityDisplaySurfaceBase*)surface;
- (void)onBeforeMainDisplaySurfaceRecreate:(struct RenderingSurfaceParams*)params;
- (void)onAfterMainDisplaySurfaceRecreate;
- (void)onFrameResolved;
- (void)didBecomeActive:(NSNotification*)notification;
- (void)willResignActive:(NSNotification*)notification;
- (void)didEnterBackground:(NSNotification*)notification;
- (void)willEnterForeground:(NSNotification*)notification;
- (void)willTerminate:(NSNotification*)notification;
@end
#include "RenderPluginDelegate.h"
@implementation RenderPluginDelegate
- (void)mainDisplayInited:(struct UnityDisplaySurfaceBase*)surface
{
mainDisplaySurface = surface;
// TODO: move lifecycle to init?
UnityRegisterLifeCycleListener(self);
}
@end
#define CALL_METHOD_ON_ARRAY(method) \
do{ \
for(id<RenderPluginDelegate> del in delegateArray) \
{ \
if([del respondsToSelector:@selector(method)]) \
[del method]; \
} \
} while(0)
#define CALL_METHOD_ON_ARRAY_ARG(method, arg) \
do{ \
for(id<RenderPluginDelegate> del in delegateArray) \
{ \
if([del respondsToSelector:@selector(method:)]) \
[del method:arg]; \
} \
} while(0)
@implementation RenderPluginArrayDelegate
@synthesize delegateArray;
- (void)mainDisplayInited:(struct UnityDisplaySurfaceBase*)surface
{
[super mainDisplayInited: surface];
CALL_METHOD_ON_ARRAY_ARG(mainDisplayInited, surface);
}
- (void)onBeforeMainDisplaySurfaceRecreate:(struct RenderingSurfaceParams*)params
{
CALL_METHOD_ON_ARRAY_ARG(onBeforeMainDisplaySurfaceRecreate, params);
}
- (void)onAfterMainDisplaySurfaceRecreate;
{
CALL_METHOD_ON_ARRAY(onAfterMainDisplaySurfaceRecreate);
}
- (void)onFrameResolved;
{
CALL_METHOD_ON_ARRAY(onFrameResolved);
}
- (void)didBecomeActive:(NSNotification*)notification
{
CALL_METHOD_ON_ARRAY_ARG(didBecomeActive, notification);
}
- (void)willResignActive:(NSNotification*)notification
{
CALL_METHOD_ON_ARRAY_ARG(willResignActive, notification);
}
- (void)didEnterBackground:(NSNotification*)notification
{
CALL_METHOD_ON_ARRAY_ARG(didEnterBackground, notification);
}
- (void)willEnterForeground:(NSNotification*)notification
{
CALL_METHOD_ON_ARRAY_ARG(willEnterForeground, notification);
}
- (void)willTerminate:(NSNotification*)notification
{
CALL_METHOD_ON_ARRAY_ARG(willTerminate, notification);
}
@end
#undef CALL_METHOD_ON_ARRAY
#undef CALL_METHOD_ON_ARRAY_ARG
#pragma once
#import <Foundation/NSNotification.h>
// view changes on the main view controller
@protocol UnityViewControllerListener<NSObject>
@optional
- (void)viewWillLayoutSubviews:(NSNotification*)notification;
- (void)viewDidLayoutSubviews:(NSNotification*)notification;
- (void)viewWillDisappear:(NSNotification*)notification;
- (void)viewDidDisappear:(NSNotification*)notification;
- (void)viewWillAppear:(NSNotification*)notification;
- (void)viewDidAppear:(NSNotification*)notification;
- (void)interfaceWillChangeOrientation:(NSNotification*)notification;
- (void)interfaceDidChangeOrientation:(NSNotification*)notification;
@end
@protocol UnityViewControllerNotifications<NSObject>
@optional
- (void)onViewWillLayoutSubviews;
- (void)onViewDidLayoutSubviews;
- (void)onViewDidDisappear:(BOOL)animated;
- (void)onViewWillDisappear:(BOOL)animated;
- (void)onViewDidAppear:(BOOL)animated;
- (void)onViewWillAppear:(BOOL)animated;
@end
// this default delegate will send notifications for UnityViewControllerListener
@interface UnityViewControllerNotificationsDefaultSender : NSObject<UnityViewControllerNotifications>
- (void)onViewWillLayoutSubviews;
- (void)onViewDidLayoutSubviews;
- (void)onViewDidDisappear:(BOOL)animated;
- (void)onViewWillDisappear:(BOOL)animated;
- (void)onViewDidAppear:(BOOL)animated;
- (void)onViewWillAppear:(BOOL)animated;
@end
void UnityRegisterViewControllerListener(id<UnityViewControllerListener> obj);
void UnityUnregisterViewControllerListener(id<UnityViewControllerListener> obj);
extern "C" __attribute__((visibility("default"))) NSString* const kUnityViewWillLayoutSubviews;
extern "C" __attribute__((visibility("default"))) NSString* const kUnityViewDidLayoutSubviews;
extern "C" __attribute__((visibility("default"))) NSString* const kUnityViewWillDisappear;
extern "C" __attribute__((visibility("default"))) NSString* const kUnityViewDidDisappear;
extern "C" __attribute__((visibility("default"))) NSString* const kUnityViewWillAppear;
extern "C" __attribute__((visibility("default"))) NSString* const kUnityViewDidAppear;
extern "C" __attribute__((visibility("default"))) NSString* const kUnityInterfaceWillChangeOrientation;
extern "C" __attribute__((visibility("default"))) NSString* const kUnityInterfaceDidChangeOrientation;
#include "UnityViewControllerListener.h"
#include <UIKit/UIApplication.h>
#define DEFINE_NOTIFICATION(name) extern "C" __attribute__((visibility ("default"))) NSString* const name = @#name;
DEFINE_NOTIFICATION(kUnityViewWillLayoutSubviews);
DEFINE_NOTIFICATION(kUnityViewDidLayoutSubviews);
DEFINE_NOTIFICATION(kUnityViewWillDisappear);
DEFINE_NOTIFICATION(kUnityViewDidDisappear);
DEFINE_NOTIFICATION(kUnityViewWillAppear);
DEFINE_NOTIFICATION(kUnityViewDidAppear);
DEFINE_NOTIFICATION(kUnityInterfaceWillChangeOrientation);
DEFINE_NOTIFICATION(kUnityInterfaceDidChangeOrientation);
#undef DEFINE_NOTIFICATION
void UnityRegisterViewControllerListener(id<UnityViewControllerListener> obj)
{
#define REGISTER_SELECTOR(sel, notif_name) \
if([obj respondsToSelector:sel]) \
[[NSNotificationCenter defaultCenter] addObserver:obj selector:sel name:notif_name object:nil]; \
REGISTER_SELECTOR(@selector(viewWillLayoutSubviews:), kUnityViewWillLayoutSubviews);
REGISTER_SELECTOR(@selector(viewDidLayoutSubviews:), kUnityViewDidLayoutSubviews);
REGISTER_SELECTOR(@selector(viewWillDisappear:), kUnityViewWillDisappear);
REGISTER_SELECTOR(@selector(viewDidDisappear:), kUnityViewDidDisappear);
REGISTER_SELECTOR(@selector(viewWillAppear:), kUnityViewWillAppear);
REGISTER_SELECTOR(@selector(viewDidAppear:), kUnityViewDidAppear);
REGISTER_SELECTOR(@selector(interfaceWillChangeOrientation:), kUnityInterfaceWillChangeOrientation);
REGISTER_SELECTOR(@selector(interfaceDidChangeOrientation:), kUnityInterfaceDidChangeOrientation);
#undef REGISTER_SELECTOR
}
void UnityUnregisterViewControllerListener(id<UnityViewControllerListener> obj)
{
[[NSNotificationCenter defaultCenter] removeObserver: obj name: kUnityViewWillLayoutSubviews object: nil];
[[NSNotificationCenter defaultCenter] removeObserver: obj name: kUnityViewDidLayoutSubviews object: nil];
[[NSNotificationCenter defaultCenter] removeObserver: obj name: kUnityViewWillDisappear object: nil];
[[NSNotificationCenter defaultCenter] removeObserver: obj name: kUnityViewDidDisappear object: nil];
[[NSNotificationCenter defaultCenter] removeObserver: obj name: kUnityViewWillAppear object: nil];
[[NSNotificationCenter defaultCenter] removeObserver: obj name: kUnityViewDidAppear object: nil];
[[NSNotificationCenter defaultCenter] removeObserver: obj name: kUnityInterfaceWillChangeOrientation object: nil];
[[NSNotificationCenter defaultCenter] removeObserver: obj name: kUnityInterfaceDidChangeOrientation object: nil];
}
extern void AppController_SendUnityViewControllerNotification(NSString* name);
@implementation UnityViewControllerNotificationsDefaultSender
- (void)onViewWillLayoutSubviews
{
AppController_SendUnityViewControllerNotification(kUnityViewWillLayoutSubviews);
}
- (void)onViewDidLayoutSubviews
{
AppController_SendUnityViewControllerNotification(kUnityViewDidLayoutSubviews);
}
- (void)onViewDidDisappear:(BOOL)animated
{
AppController_SendUnityViewControllerNotification(kUnityViewDidDisappear);
}
- (void)onViewWillDisappear:(BOOL)animated
{
AppController_SendUnityViewControllerNotification(kUnityViewWillDisappear);
}
- (void)onViewDidAppear:(BOOL)animated
{
AppController_SendUnityViewControllerNotification(kUnityViewDidAppear);
}
- (void)onViewWillAppear:(BOOL)animated
{
AppController_SendUnityViewControllerNotification(kUnityViewWillAppear);
}
@end
//
// Prefix header
//
#include "Preprocessor.h"
#ifdef __OBJC__
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#endif
#include "UnityTrampolineConfigure.h"
#include "UnityInterface.h"
#ifndef __OBJC__
#if USE_IL2CPP_PCH
#include "il2cpp_precompiled_header.h"
#endif
#endif
#ifndef TARGET_IPHONE_SIMULATOR
#define TARGET_IPHONE_SIMULATOR 0
#endif
#define printf_console printf
#pragma once
#include <Availability.h>
#include <TargetConditionals.h>
//------------------------------------------------------------------------------
//
// ensuring proper compiler/xcode/whatever selection
//
#ifndef __clang__
#error Please use clang compiler.
#endif
// NOT the best way but apple do not care about adding extensions properly
#if __clang_major__ < 9
#error Please use Xcode 9.0 or newer
#endif
#if !defined(__IPHONE_11_0) || __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_11_0
#error Please use iOS SDK 11.0 or newer
#endif
#if defined(TARGET_OS_TV) && TARGET_OS_TV && !defined(__TVOS_11_0)
#error Please use tvOS SDK 11.0 or newer
#endif
#if TARGET_OS_IOS && (!defined(__IPHONE_10_0) || __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_10_0)
#error Please target iOS 10.0 or newer
#endif
#if TARGET_OS_TV && (!defined(__TVOS_10_0) || __TV_OS_VERSION_MIN_REQUIRED < __TVOS_10_0)
#error Please target tvOS 10.0 or newer
#endif
//------------------------------------------------------------------------------
//
// defines for target platform
//
#define UNITY_TRAMPOLINE_IN_USE 1
#if defined(TARGET_OS_TV) && TARGET_OS_TV
#define PLATFORM_TVOS 1
#define PLATFORM_IOS 0
#else
#define PLATFORM_TVOS 0
#define PLATFORM_IOS 1
#endif
#define PLATFORM_OSX 0
//------------------------------------------------------------------------------
//
// defines for sdk/target version
//
#if !TARGET_IPHONE_SIMULATOR && !TARGET_TVOS_SIMULATOR
#define UNITY_CAN_USE_METAL 1
#elif TARGET_IPHONE_SIMULATOR && defined(__IPHONE_13_0)
#define UNITY_CAN_USE_METAL 1
#elif TARGET_TVOS_SIMULATOR && defined(__TVOS_13_0)
#define UNITY_CAN_USE_METAL 1
#else
#define UNITY_CAN_USE_METAL 0
#endif
// It's hard to figure out which SDK we are using as the availability macros defined in the SDK
// have various quirks.
//
// It's not possible to use *_VERSION_MAX_ALLOWED macros because they not always corresponded to
// the SDK version. In particular, __TV_OS_VERSION_MAX_ALLOWED was out of sync in all Xcode dot
// releases except the first so far.
//
// The highest __IPHONE_X_Y or __TVOS_X_Y macro that is defined in Availability.h correctly
// corresponds to the version of the SDK (at least in each Xcode version since 6.0 up to 9.0).
// However, some other headers (e.g. System/Library/Frameworks/QuartzCore.framework/Headers/CABase.h
// in SDKs up to 9.3) may define the macros itself and this does not correspond to the what's in
// Availability.h. Thus we make sure to include "Preprocessor.h" before the CABase.h header.
#if defined(CABASE_H)
#error "Please include Preprocessor.h before other includes"
#endif
#if defined(__IPHONE_10_0)
#define UNITY_HAS_IOSSDK_10_0 1
#else
#define UNITY_HAS_IOSSDK_10_0 0
#endif
#if defined(__IPHONE_10_2)
#define UNITY_HAS_IOSSDK_10_2 1
#else
#define UNITY_HAS_IOSSDK_10_2 0
#endif
#if defined(__IPHONE_10_3)
#define UNITY_HAS_IOSSDK_10_3 1
#else
#define UNITY_HAS_IOSSDK_10_3 0
#endif
#if defined(__IPHONE_11_0)
#define UNITY_HAS_IOSSDK_11_0 1
#else
#define UNITY_HAS_IOSSDK_11_0 0
#endif
#if defined(__IPHONE_11_1)
#define UNITY_HAS_IOSSDK_11_1 1
#else
#define UNITY_HAS_IOSSDK_11_1 0
#endif
#if defined(__IPHONE_12_0)
#define UNITY_HAS_IOSSDK_12_0 1
#else
#define UNITY_HAS_IOSSDK_12_0 0
#endif
#if defined(__IPHONE_13_0)
#define UNITY_HAS_IOSSDK_13_0 1
#else
#define UNITY_HAS_IOSSDK_13_0 0
#endif
#if defined(__IPHONE_14_0)
#define UNITY_HAS_IOSSDK_14_0 1
#else
#define UNITY_HAS_IOSSDK_14_0 0
#endif
#if defined(__IPHONE_15_0)
#define UNITY_HAS_IOSSDK_15_0 1
#else
#define UNITY_HAS_IOSSDK_15_0 0
#endif
#if defined(__TVOS_10_0)
#define UNITY_HAS_TVOSSDK_10_0 1
#else
#define UNITY_HAS_TVOSSDK_10_0 0
#endif
#if defined(__TVOS_10_2)
#define UNITY_HAS_TVOSSDK_10_2 1
#else
#define UNITY_HAS_TVOSSDK_10_2 0
#endif
#if defined(__TVOS_11_0)
#define UNITY_HAS_TVOSSDK_11_0 1
#else
#define UNITY_HAS_TVOSSDK_11_0 0
#endif
#if defined(__TVOS_12_0)
#define UNITY_HAS_TVOSSDK_12_0 1
#else
#define UNITY_HAS_TVOSSDK_12_0 0
#endif
#if defined(__TVOS_13_0)
#define UNITY_HAS_TVOSSDK_13_0 1
#else
#define UNITY_HAS_TVOSSDK_13_0 0
#endif
#if defined(__TVOS_14_0)
#define UNITY_HAS_TVOSSDK_14_0 1
#else
#define UNITY_HAS_TVOSSDK_14_0 0
#endif
#if defined(__TVOS_15_0)
#define UNITY_HAS_TVOSSDK_15_0 1
#else
#define UNITY_HAS_TVOSSDK_15_0 0
#endif
// The following UNITY_USES_* flags disable functionality in the trampoline project
// whenever the user does not use it from his scripts. We detect the API usage and
// adjust the value of these flags whenever the project is built (including when the
// project is appended)
#define UNITY_USES_REMOTE_NOTIFICATIONS 1
#define UNITY_USES_WEBCAM 0
#define UNITY_USES_MICROPHONE 0
#define UNITY_USES_REPLAY_KIT 0
#define UNITY_USES_IAD 1
#define UNITY_SNAPSHOT_VIEW_ON_APPLICATION_PAUSE 0
#define UNITY_DEVELOPER_BUILD 0
#define UNITY_USES_DYNAMIC_PLAYER_LIB 0
#define UNITY_USES_LOCATION 0
#define USE_IL2CPP_PCH 0
#define UNITY_SUPPORT_ROTATION PLATFORM_IOS
#if PLATFORM_TVOS
#define UNITY_TVOS_ORIENTATION landscapeLeft
#endif
#if PLATFORM_IOS // available in ios9 sdk which is min requirement
#define UNITY_REPLAY_KIT_AVAILABLE UNITY_USES_REPLAY_KIT
#elif PLATFORM_TVOS // available in tvos10 sdk which is min requirement
#define UNITY_REPLAY_KIT_AVAILABLE UNITY_USES_REPLAY_KIT && defined(__TVOS_10_0)
#else
#define UNITY_REPLAY_KIT_AVAILABLE 0
#endif
// On tvOS simulator we implement a fake remote as tvOS simulator does not support controllers (yet)
#define UNITY_TVOS_SIMULATOR_FAKE_REMOTE (PLATFORM_TVOS && TARGET_TVOS_SIMULATOR)
#pragma once
struct Quaternion4f
{
float x, y, z, w;
};
static Quaternion4f gQuatRot[4] =
{ // { x*sin(theta/2), y*sin(theta/2), z*sin(theta/2), cos(theta/2) }
// => { 0, 0, sin(theta/2), cos(theta/2) } (since <vec> = { 0, 0, +/-1})
{ 0.f, 0.f, 0.f /*sin(0)*/, 1.f /*cos(0)*/}, // ROTATION_0, theta = 0 rad
{ 0.f, 0.f, (float)sqrt(2) * 0.5f /*sin(pi/4)*/, -(float)sqrt(2) * 0.5f /*cos(pi/4)*/}, // ROTATION_90, theta = pi/4 rad
{ 0.f, 0.f, 1.f /*sin(pi/2)*/, 0.f /*cos(pi/2)*/}, // ROTATION_180, theta = pi rad
{ 0.f, 0.f, -(float)sqrt(2) * 0.5f /*sin(3pi/4)*/, -(float)sqrt(2) * 0.5f /*cos(3pi/4)*/} // ROTATION_270, theta = 3pi/2 rad
};
inline void QuatMultiply(Quaternion4f& result, const Quaternion4f& lhs, const Quaternion4f& rhs)
{
result.x = lhs.w * rhs.x + lhs.x * rhs.w + lhs.y * rhs.z - lhs.z * rhs.y;
result.y = lhs.w * rhs.y + lhs.y * rhs.w + lhs.z * rhs.x - lhs.x * rhs.z;
result.z = lhs.w * rhs.z + lhs.z * rhs.w + lhs.x * rhs.y - lhs.y * rhs.x;
result.w = lhs.w * rhs.w - lhs.x * rhs.x - lhs.y * rhs.y - lhs.z * rhs.z;
}
inline Quaternion4f QuatMultiply(const Quaternion4f& lhs, const Quaternion4f& rhs)
{
Quaternion4f output;
QuatMultiply(output, lhs, rhs);
return output;
}
inline Quaternion4f QuatMake(float x, float y, float z, float w)
{
Quaternion4f q = {x, y, z, w};
return q;
}
inline Quaternion4f QuatIdentity()
{
return gQuatRot[0];
}
inline Quaternion4f QuatScale(const Quaternion4f& q, float s)
{
return QuatMake(s * q.x, s * q.y, s * q.z, s * q.w);
}
inline float QuatNormSquared(const Quaternion4f& q)
{
return q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w;
}
inline Quaternion4f QuatConjugate(const Quaternion4f& q)
{
return QuatMake(-q.x, -q.y, -q.z, q.w);
}
inline Quaternion4f QuatInverse(const Quaternion4f& q)
{
return QuatScale(QuatConjugate(q), 1.0f / QuatNormSquared(q));
}
inline Vector3f QuatToEuler(const Quaternion4f& q)
{
return VecMake(
atan2f(2.0f * (q.w * q.y + q.x * q.z),
1.0f - 2.0f * (q.y * q.y + q.x * q.x)),
asinf(2.0f * (q.w * q.x - q.z * q.y)),
atan2f(2.0f * (q.w * q.z + q.y * q.x),
1.0f - 2.0f * (q.x * q.x + q.z * q.z)));
}
inline float QuatNorm(const Quaternion4f& q)
{
return sqrtf(QuatNormSquared(q));
}
inline Quaternion4f QuatNormalize(const Quaternion4f& q)
{
return QuatScale(q, 1.0f / QuatNorm(q));
}
inline Quaternion4f QuatDifference(const Quaternion4f& a, const Quaternion4f& b)
{
return QuatMultiply(QuatInverse(b), a);
}
inline Quaternion4f QuatRotationFromTo(const Vector3f& src, const Vector3f& dest)
{
// Based on Stan Melax's article in Game Programming Gems
float mag0 = VecMagnitude(src);
if (mag0 < FLT_EPSILON)
return QuatIdentity();
float mag1 = VecMagnitude(dest);
if (mag1 < FLT_EPSILON)
return QuatIdentity();
Vector3f v0 = VecScale(1.0f / mag0, src);
Vector3f v1 = VecScale(1.0f / mag1, dest);
float d = VecDotProduct(v0, v1);
// If dot == 1, vectors are the same
if (d >= (1.0f - 1e-6f))
return QuatIdentity();
if (d < (1e-6f - 1.0f))
return gQuatRot[2];
float s = sqrtf((1.0f + d) * 2.0f);
float i = 1.0f / s;
Vector3f c = VecCrossProduct(v0, v1);
return QuatNormalize(QuatMake(
c.x * i, c.y * i, c.z * i, s * 0.5f));
}
// DO NOT PUT #pragma once or include guard check here
// This header is designed to be able to be included multiple times
// This header is used to redefine platforms after they were temporary undefined by UndefinePlatforms.h
// Please make sure to always use this paired with the UndefinePlatforms.h header.
//
// ex.
//
// #include "UndefinePlatforms.h"
// #include "Some3rdParty.h"
// #include "RedefinePlatforms.h"
#ifndef DETAIL__PLATFORMS_HAD_BEEN_UNDEFINED_BY_UNDEFINEPLATFORMS_H
#error "DefinePlatforms.h can only be used after UndefinePlatforms.h got included before."
#endif
#undef DETAIL__PLATFORMS_HAD_BEEN_UNDEFINED_BY_UNDEFINEPLATFORMS_H
// define all other platforms to 0
#undef PLATFORM_WIN
#if defined(DETAIL__TEMP_PLATFORM_WIN_WAS_1)
#undef DETAIL__TEMP_PLATFORM_WIN_WAS_1
#define PLATFORM_WIN 1
#else
#define PLATFORM_WIN 0
#endif
#undef PLATFORM_OSX
#if defined(DETAIL__TEMP_PLATFORM_OSX_WAS_1)
#undef DETAIL__TEMP_PLATFORM_OSX_WAS_1
#define PLATFORM_OSX 1
#else
#define PLATFORM_OSX 0
#endif
#undef PLATFORM_LINUX
#if defined(DETAIL__TEMP_PLATFORM_LINUX_WAS_1)
#undef DETAIL__TEMP_PLATFORM_LINUX_WAS_1
#define PLATFORM_LINUX 1
#else
#define PLATFORM_LINUX 0
#endif
#undef PLATFORM_WINRT
#if defined(DETAIL__TEMP_PLATFORM_WINRT_WAS_1)
#undef DETAIL__TEMP_PLATFORM_WINRT_WAS_1
#define PLATFORM_WINRT 1
#else
#define PLATFORM_WINRT 0
#endif
#undef PLATFORM_FAMILY_WINDOWSGAMES
#if defined(DETAIL__TEMP_PLATFORM_FAMILY_WINDOWSGAMES_WAS_1)
#undef DETAIL__TEMP_PLATFORM_FAMILY_WINDOWSGAMES_WAS_1
#define PLATFORM_FAMILY_WINDOWSGAMES 1
#else
#define PLATFORM_FAMILY_WINDOWSGAMES 0
#endif
#undef PLATFORM_WEBGL
#if defined(DETAIL__TEMP_PLATFORM_WEBGL_WAS_1)
#undef DETAIL__TEMP_PLATFORM_WEBGL_WAS_1
#define PLATFORM_WEBGL 1
#else
#define PLATFORM_WEBGL 0
#endif
#undef PLATFORM_ANDROID
#if defined(DETAIL__TEMP_PLATFORM_ANDROID_WAS_1)
#undef DETAIL__TEMP_PLATFORM_ANDROID_WAS_1
#define PLATFORM_ANDROID 1
#else
#define PLATFORM_ANDROID 0
#endif
#undef PLATFORM_PS4
#if defined(DETAIL__TEMP_PLATFORM_PS4_WAS_1)
#undef DETAIL__TEMP_PLATFORM_PS4_WAS_1
#define PLATFORM_PS4 1
#else
#define PLATFORM_PS4 0
#endif
#undef PLATFORM_IPHONE
#if defined(DETAIL__TEMP_PLATFORM_IPHONE_WAS_1)
#undef DETAIL__TEMP_PLATFORM_IPHONE_WAS_1
#define PLATFORM_IPHONE 1
#else
#define PLATFORM_IPHONE 0
#endif
#undef PLATFORM_IOS
#if defined(DETAIL__TEMP_PLATFORM_IOS_WAS_1)
#undef DETAIL__TEMP_PLATFORM_IOS_WAS_1
#define PLATFORM_IOS 1
#else
#define PLATFORM_IOS 0
#endif
#undef PLATFORM_TVOS
#if defined(DETAIL__TEMP_PLATFORM_TVOS_WAS_1)
#undef DETAIL__TEMP_PLATFORM_TVOS_WAS_1
#define PLATFORM_TVOS 1
#else
#define PLATFORM_TVOS 0
#endif
#undef PLATFORM_XBOXONE
#if defined(DETAIL__TEMP_PLATFORM_XBOXONE_WAS_1)
#undef DETAIL__TEMP_PLATFORM_XBOXONE_WAS_1
#define PLATFORM_XBOXONE 1
#else
#define PLATFORM_XBOXONE 0
#endif
#undef PLATFORM_SWITCH
#if defined(DETAIL__TEMP_PLATFORM_SWITCH_WAS_1)
#undef DETAIL__TEMP_PLATFORM_SWITCH_WAS_1
#define PLATFORM_SWITCH 1
#else
#define PLATFORM_SWITCH 0
#endif
#undef PLATFORM_LUMIN
#if defined(DETAIL__TEMP_PLATFORM_LUMIN_WAS_1)
#undef DETAIL__TEMP_PLATFORM_LUMIN_WAS_1
#define PLATFORM_LUMIN 1
#else
#define PLATFORM_LUMIN 0
#endif
#undef PLATFORM_GGP
#if defined(DETAIL__TEMP_PLATFORM_GGP_WAS_1)
#undef DETAIL__TEMP_PLATFORM_GGP_WAS_1
#define PLATFORM_GGP 1
#else
#define PLATFORM_GGP 0
#endif
#undef PLATFORM_NETBSD
#if defined(DETAIL__TEMP_PLATFORM_NETBSD_WAS_1)
#undef DETAIL__TEMP_PLATFORM_NETBSD_WAS_1
#define PLATFORM_NETBSD 1
#else
#define PLATFORM_NETBSD 0
#endif
#pragma once
void ShowActivityIndicator(UIView* parent, int style);
void ShowActivityIndicator(UIView* parent);
void HideActivityIndicator();
#include "ActivityIndicator.h"
#include "OrientationSupport.h"
@interface ActivityIndicator : UIActivityIndicatorView
{
UIView* _parent;
}
@end
static ActivityIndicator* _activityIndicator = nil;
@implementation ActivityIndicator
- (void)show:(UIView*)parent
{
_parent = parent;
[parent addSubview: self];
[self startAnimating];
}
- (void)layoutSubviews
{
self.center = CGPointMake([_parent bounds].size.width / 2, [_parent bounds].size.height / 2);
}
@end
void ShowActivityIndicator(UIView* parent, int style)
{
if (_activityIndicator != nil)
return;
if (style >= 0)
{
_activityIndicator = [[ActivityIndicator alloc] initWithActivityIndicatorStyle: (UIActivityIndicatorViewStyle)style];
_activityIndicator.contentScaleFactor = [UIScreen mainScreen].scale;
}
if (_activityIndicator != nil)
[_activityIndicator show: parent];
}
void ShowActivityIndicator(UIView* parent)
{
ShowActivityIndicator(parent, UnityGetShowActivityIndicatorOnLoading());
}
void HideActivityIndicator()
{
if (_activityIndicator)
{
[_activityIndicator stopAnimating];
[_activityIndicator removeFromSuperview];
_activityIndicator = nil;
}
}
extern "C" void UnityStartActivityIndicator()
{
// AppleTV does not support activity indicators
ShowActivityIndicator(UnityGetGLView());
}
extern "C" void UnityStopActivityIndicator()
{
HideActivityIndicator();
}
#pragma once
typedef struct
{
const char* text;
const char* placeholder;
UIKeyboardType keyboardType;
UITextAutocorrectionType autocorrectionType;
UITextSpellCheckingType spellcheckingType;
UIKeyboardAppearance appearance;
BOOL multiline;
BOOL secure;
int characterLimit;
}
KeyboardShowParam;
@interface KeyboardDelegate : NSObject<UITextFieldDelegate, UITextViewDelegate>
{
}
- (BOOL)textFieldShouldReturn:(UITextField*)textField;
- (void)textInputDone:(id)sender;
- (void)textInputCancel:(id)sender;
- (void)textInputLostFocus;
- (void)textViewDidChange:(UITextView *)textView;
- (void)keyboardWillShow:(NSNotification*)notification;
- (void)keyboardDidShow:(NSNotification*)notification;
- (void)keyboardWillHide:(NSNotification*)notification;
- (void)becomeFirstResponder;
// on older devices initial keyboard creation might be slow, so it is good to init in on initial loading.
// on the other hand, if you dont use keyboard (or use it rarely), you can avoid having all related stuff in memory:
// keyboard will be created on demand anyway (in Instance method)
+ (void)Initialize;
+ (KeyboardDelegate*)Instance;
+ (void)Destroy;
- (id)init;
- (void)setKeyboardParams:(KeyboardShowParam)param;
- (void)show;
- (void)hide;
- (void)positionInput:(CGRect)keyboardRect x:(float)x y:(float)y;
- (void)shouldHideInput:(BOOL)hide;
+ (void)StartReorientation;
+ (void)FinishReorientation;
- (CGRect)queryArea;
- (NSString*)getText;
- (void)setText:(NSString*)newText;
- (BOOL)hasExternalKeyboard;
@property (readonly, nonatomic, getter = queryArea) CGRect area;
@property (readonly, nonatomic) BOOL active;
@property (readonly, nonatomic) KeyboardStatus status;
@property (retain, nonatomic, getter = getText, setter = setText:) NSString* text;
@property (assign, nonatomic) int characterLimit;
@property (readonly, nonatomic) BOOL canGetSelection;
@property (nonatomic, getter = querySelection, setter = assignSelection:) NSRange selection;
@end
#pragma once
#include <CoreGraphics/CGAffineTransform.h>
#if !PLATFORM_TVOS
ScreenOrientation ConvertToUnityScreenOrientation(UIInterfaceOrientation hwOrient);
UIInterfaceOrientation ConvertToIosScreenOrientation(ScreenOrientation orient);
#endif
#if !PLATFORM_TVOS
UIInterfaceOrientation UIViewControllerInterfaceOrientation(UIViewController* controller);
#endif
ScreenOrientation UIViewControllerOrientation(UIViewController* controller);
CGAffineTransform TransformForOrientation(ScreenOrientation curOrient);
CGAffineTransform TransformBetweenOrientations(ScreenOrientation fromOrient, ScreenOrientation toOrient);
ScreenOrientation OrientationAfterTransform(ScreenOrientation curOrient, CGAffineTransform transform);
void OrientView(UIViewController* host, UIView* view, ScreenOrientation to);
#include "OrientationSupport.h"
#include <math.h>
CGAffineTransform TransformForOrientation(ScreenOrientation orient)
{
switch (orient)
{
case portrait: return CGAffineTransformIdentity;
case portraitUpsideDown: return CGAffineTransformMakeRotation(M_PI);
case landscapeLeft: return CGAffineTransformMakeRotation(M_PI_2);
case landscapeRight: return CGAffineTransformMakeRotation(-M_PI_2);
default: return CGAffineTransformIdentity;
}
return CGAffineTransformIdentity;
}
CGAffineTransform TransformBetweenOrientations(ScreenOrientation fromOrient, ScreenOrientation toOrient)
{
CGAffineTransform fromTransform = TransformForOrientation(fromOrient);
CGAffineTransform toTransform = TransformForOrientation(toOrient);
return CGAffineTransformConcat(CGAffineTransformInvert(fromTransform), toTransform);
}
#if !PLATFORM_TVOS
UIInterfaceOrientation ConvertToIosScreenOrientation(ScreenOrientation orient)
{
switch (orient)
{
case portrait: return UIInterfaceOrientationPortrait;
case portraitUpsideDown: return UIInterfaceOrientationPortraitUpsideDown;
// landscape left/right have switched values in device/screen orientation
// though unity docs are adjusted with device orientation values, so swap here
case landscapeLeft: return UIInterfaceOrientationLandscapeRight;
case landscapeRight: return UIInterfaceOrientationLandscapeLeft;
case orientationUnknown: return (UIInterfaceOrientation)UIInterfaceOrientationUnknown;
default: return UIInterfaceOrientationPortrait;
}
return UIInterfaceOrientationPortrait;
}
ScreenOrientation ConvertToUnityScreenOrientation(UIInterfaceOrientation orient)
{
switch (orient)
{
case UIInterfaceOrientationPortrait: return portrait;
case UIInterfaceOrientationPortraitUpsideDown: return portraitUpsideDown;
// landscape left/right have switched values in device/screen orientation
// though unity docs are adjusted with device orientation values, so swap here
case UIInterfaceOrientationLandscapeLeft: return landscapeRight;
case UIInterfaceOrientationLandscapeRight: return landscapeLeft;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wswitch"
case UIInterfaceOrientationUnknown: return orientationUnknown;
#pragma clang diagnostic pop
default: return portrait;
}
}
// Replacement for UIViewController.interfaceOrientation which is obsolete since iOS 8.0
UIInterfaceOrientation UIViewControllerInterfaceOrientation(UIViewController* c)
{
CGPoint fixedPoint = [c.view.window.screen.coordinateSpace convertPoint: CGPointMake(0.0, 0.0) toCoordinateSpace: c.view.window.screen.fixedCoordinateSpace];
if (fabs(fixedPoint.x) < FLT_EPSILON)
{
if (fabs(fixedPoint.y) < FLT_EPSILON)
return UIInterfaceOrientationPortrait;
else
return UIInterfaceOrientationLandscapeLeft;
}
else
{
if (fabs(fixedPoint.y) < FLT_EPSILON)
return UIInterfaceOrientationLandscapeRight;
else
return UIInterfaceOrientationPortraitUpsideDown;
}
}
#endif
ScreenOrientation UIViewControllerOrientation(UIViewController* controller)
{
#if PLATFORM_TVOS
return UNITY_TVOS_ORIENTATION;
#else
return ConvertToUnityScreenOrientation(UIViewControllerInterfaceOrientation(controller));
#endif
}
ScreenOrientation OrientationAfterTransform(ScreenOrientation curOrient, CGAffineTransform transform)
{
int rotDeg = (int)::roundf(::atan2f(transform.b, transform.a) * (180 / M_PI));
assert(rotDeg == 0 || rotDeg == 90 || rotDeg == -90 || rotDeg == 180 || rotDeg == -180);
if (rotDeg == 0)
{
return curOrient;
}
else if ((rotDeg == 180) || (rotDeg == -180))
{
if (curOrient == portrait)
return portraitUpsideDown;
else if (curOrient == portraitUpsideDown)
return portrait;
else if (curOrient == landscapeRight)
return landscapeLeft;
else if (curOrient == landscapeLeft)
return landscapeRight;
}
else if (rotDeg == 90)
{
if (curOrient == portrait)
return landscapeLeft;
else if (curOrient == portraitUpsideDown)
return landscapeRight;
else if (curOrient == landscapeRight)
return portrait;
else if (curOrient == landscapeLeft)
return portraitUpsideDown;
}
else if (rotDeg == -90)
{
if (curOrient == portrait)
return landscapeRight;
else if (curOrient == portraitUpsideDown)
return landscapeLeft;
else if (curOrient == landscapeRight)
return portraitUpsideDown;
else if (curOrient == landscapeLeft)
return portrait;
}
::printf("rotation unhandled: %d\n", rotDeg);
return curOrient;
}
void OrientView(UIViewController* host, UIView* view, ScreenOrientation to)
{
ScreenOrientation fromController = UIViewControllerOrientation(host);
CGAffineTransform transform = TransformBetweenOrientations(fromController, to);
// this is for unity-inited orientation. In that case we need to manually adjust bounds if changing portrait/landscape
// the easiest way would be to manually rotate current bounds (to acknowledge the fact that we do NOT rotate controller itself)
// NB: as we use current view bounds we need to use view transform to properly adjust them
CGRect rect = view.bounds;
CGSize ext = CGSizeApplyAffineTransform(rect.size, CGAffineTransformConcat(CGAffineTransformInvert(view.transform), transform));
view.transform = transform;
view.bounds = CGRectMake(0, 0, ::fabs(ext.width), ::fabs(ext.height));
}
#pragma once
#include "UnityViewControllerBase.h"
@interface SplashScreen : UIImageView
{
}
+ (SplashScreen*)Instance;
@end
@interface SplashScreenController : UnityViewControllerBase
{
}
+ (SplashScreenController*)Instance;
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator;
@end
void ShowSplashScreen(UIWindow* window);
void HideSplashScreen();
#include "SplashScreen.h"
#include "UnityViewControllerBase.h"
#include "OrientationSupport.h"
#include "Unity/ObjCRuntime.h"
#include "UI/UnityView.h"
#include <cstring>
#include "Unity/UnitySharedDecls.h"
#include <utility>
static SplashScreen* _splash = nil;
static SplashScreenController* _controller = nil;
@implementation SplashScreen
{
UIImageView* m_ImageView;
UIView* m_XibView;
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame: frame];
return self;
}
- (void)createUI
{
NSString* launchScreen = [[NSBundle mainBundle].infoDictionary[@"UILaunchStoryboardName"] stringByDeletingPathExtension];
const bool hasXIB = [[NSBundle mainBundle] pathForResource: launchScreen ofType: @"nib"] != nil;
if (hasXIB)
{
self->m_XibView = [[[NSBundle mainBundle] loadNibNamed: launchScreen owner: nil options: nil] objectAtIndex: 0];
[self addSubview: self->m_XibView];
}
else
{
#if !PLATFORM_TVOS
NSAssert(NO, @"no storyboard/xib was provided.");
#endif
// we still support launch images on tvos, but unlike iOS there are only two options and no orientations
UIImage* launchImage = nil;
if ([UIScreen mainScreen].scale > 1.0)
launchImage = [UIImage imageNamed: @"LaunchImage@2x"];
if (!launchImage)
launchImage = [UIImage imageNamed: @"LaunchImage@"];
self->m_ImageView = [[UIImageView alloc] initWithImage: launchImage];
[self addSubview: self->m_ImageView];
}
}
- (void)updateOrientation:(ScreenOrientation)orient withSupportedOrientations:(const OrientationMask&)supportedOrientations
{
CGFloat scale = UnityScreenScaleFactor([UIScreen mainScreen]);
UnityReportResizeView(self.bounds.size.width * scale, self.bounds.size.height * scale, orient);
ReportSafeAreaChangeForView(self);
// for iOS only xib/storyboard are supported, for tvOS (launch images are supported) no orientation takes place at all
}
- (void)layoutSubviews
{
if (self->m_XibView)
self->m_XibView.frame = self.bounds;
else if (self->m_ImageView)
self->m_ImageView.frame = self.bounds;
}
+ (SplashScreen*)Instance
{
return _splash;
}
- (void)freeSubviews
{
m_ImageView = nil;
m_XibView = nil;
}
@end
@implementation SplashScreenController
{
OrientationMask _supportedOrientations;
}
- (id)init
{
self = [super init];
if (self)
{
self->_supportedOrientations = { false, false, false, false };
}
return self;
}
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
ScreenOrientation curOrient = UIViewControllerOrientation(self);
ScreenOrientation newOrient = OrientationAfterTransform(curOrient, [coordinator targetTransform]);
[_splash updateOrientation: newOrient withSupportedOrientations: self->_supportedOrientations];
[super viewWillTransitionToSize: size withTransitionCoordinator: coordinator];
}
- (void)initImpl
{
NSArray* supportedOrientation = [[[NSBundle mainBundle] infoDictionary] objectForKey: @"UISupportedInterfaceOrientations"];
// splash will be shown way before unity is inited so we need to override autorotation handling with values read from info.plist
self->_supportedOrientations.portrait = [supportedOrientation containsObject: @"UIInterfaceOrientationPortrait"];
self->_supportedOrientations.portraitUpsideDown = [supportedOrientation containsObject: @"UIInterfaceOrientationPortraitUpsideDown"];
self->_supportedOrientations.landscapeLeft = [supportedOrientation containsObject: @"UIInterfaceOrientationLandscapeRight"];
self->_supportedOrientations.landscapeRight = [supportedOrientation containsObject: @"UIInterfaceOrientationLandscapeLeft"];
// special handling of devices/ios that do not support upside down orientation
if (!UnityDeviceSupportsUpsideDown())
{
self->_supportedOrientations.portraitUpsideDown = false;
OrientationMask om = self->_supportedOrientations;
const bool anySupported = om.portrait || om.landscapeLeft || om.landscapeRight;
if (!anySupported)
{
self->_supportedOrientations.portrait = true;
printf_console("This device does not support UpsideDown orientation, so we switched to Portrait.\n");
}
}
}
- (instancetype)initWithCoder:(NSCoder *)coder
{
if ((self = [super initWithCoder: coder]))
[self initImpl];
return self;
}
- (void)create:(UIWindow*)window
{
[self initImpl];
_splash = [[SplashScreen alloc] initWithFrame: [[UIScreen mainScreen] bounds]];
_splash.contentScaleFactor = UnityScreenScaleFactor([UIScreen mainScreen]);
_splash.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
_splash.autoresizesSubviews = YES;
[_splash createUI];
window.rootViewController = self;
self.view = _splash;
[window addSubview: _splash];
[window bringSubviewToFront: _splash];
ScreenOrientation orient = UIViewControllerOrientation(self);
[_splash updateOrientation: orient withSupportedOrientations: self->_supportedOrientations];
OrientView([SplashScreenController Instance], _splash, orient);
}
#if PLATFORM_IOS
- (BOOL)shouldAutorotate
{
return YES;
}
- (NSUInteger)supportedInterfaceOrientations
{
NSUInteger ret = 0;
if (self->_supportedOrientations.portrait)
ret |= (1 << UIInterfaceOrientationPortrait);
if (self->_supportedOrientations.portraitUpsideDown)
ret |= (1 << UIInterfaceOrientationPortraitUpsideDown);
if (self->_supportedOrientations.landscapeLeft)
ret |= (1 << UIInterfaceOrientationLandscapeRight);
if (self->_supportedOrientations.landscapeRight)
ret |= (1 << UIInterfaceOrientationLandscapeLeft);
return ret;
}
#endif
+ (SplashScreenController*)Instance
{
return _controller;
}
@end
void ShowSplashScreen(UIWindow* window)
{
NSString* launchScreen = [[NSBundle mainBundle].infoDictionary[@"UILaunchStoryboardName"] stringByDeletingPathExtension];
#if PLATFORM_IOS
// since launch images are no longer supported on ios we MUST have UILaunchStoryboardName filled
assert(launchScreen != nil && @"UILaunchStoryboardName key is missing from info.plist");
#endif
const bool hasStoryboard = launchScreen != nil && [[NSBundle mainBundle] pathForResource: launchScreen ofType: @"storyboardc"] != nil;
if (hasStoryboard)
{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName: launchScreen bundle: [NSBundle mainBundle]];
// on ios13 we can finally tweak initial storyboard view controller: use unity base view controller
// this way we can handle orientations/status-bar/whatever-we-want-to-tweak uniformly
// as we still support xcode pre-11 we must do this weird dance of checking for both sdk and runtime version
// otherwise it fails to compile (due to unknown selector)
#if (PLATFORM_IOS && defined(__IPHONE_13_0)) || (PLATFORM_TVOS && defined(__TVOS_13_0))
if (@available(iOS 13.0, tvOS 13.0, *))
{
_controller = [storyboard instantiateInitialViewControllerWithCreator:^(NSCoder *coder) {
return [[SplashScreenController alloc] initWithCoder: coder];
}];
}
else
#endif
{
_controller = [storyboard instantiateInitialViewController];
}
window.rootViewController = _controller;
}
else
{
_controller = [[SplashScreenController alloc] init];
[_controller create: window];
}
[window makeKeyAndVisible];
}
void HideSplashScreen()
{
if (_splash)
{
[_splash removeFromSuperview];
[_splash freeSubviews];
}
_splash = nil;
_controller = nil;
}
#if PLATFORM_IOS
// This definition is here only for compiler to know about selector requestReview
@interface UnityStoreReviewController
+ + requestReview;
@end
bool UnityRequestStoreReview()
{
Class classSKStoreReviewController = NSClassFromString(@"SKStoreReviewController");
if (!classSKStoreReviewController || ![classSKStoreReviewController respondsToSelector: @selector(requestReview)])
return false;
[classSKStoreReviewController performSelector: @selector(requestReview)];
return true;
}
#endif
#pragma once
#include "UnityAppController.h"
#include <AvailabilityMacros.h>
@interface UnityAppController (ViewHandling)
// tweaking view hierarchy and handling of orientation
// there are 3 main uses cases regarding UI handling:
//
// 1. normal game case: you shouldnt care about all this at all
//
// 2. you need some not-so-trivial overlayed views and/or minor UI tweaking
// most likely all you need is to subscribe to "orientation changed" notification
// or in case you have per-orientation UI logic override willTransitionToViewController
//
// 3. you create UI-rich app where unity view is just one of many
// in that case you might want to create your own controllers and implement transitions on top
// also instead of orientUnity: (and Screen.orientation in script) you should use orientInterface
// override this if you need customized unityview (subclassing)
// if you simply want different root view, tweak view hierarchy in createAutorotatingUnityViewController
- (UnityView*)createUnityView;
// for view controllers we discern between platforms that do support orientation (e.g. iOS) and the ones that dont (e.g. tvOS)
// both have concept of "default" view controller: for iOS it will be auto-rotating one (with possible constraints) and "simple" controller otherwise
// in case of supporting orientation we will discern case of fixed-orientation view controller (that seems to be the only way to handle it robustly)
// _unityView will be inited at the point of calling any of "create view controller" methods
// please note that these are actual "create" methods: there is no need to tweak hierarchy right away
- (UIViewController*)createUnityViewControllerDefault;
#if UNITY_SUPPORT_ROTATION
- (UIViewController*)createUnityViewControllerForOrientation:(UIInterfaceOrientation)orient;
#endif
#if UNITY_SUPPORT_ROTATION
// if you override these you need to call super
// if your root controller is not subclassed from UnityViewControllerBase, call these when rotation is happening
- (void)interfaceWillChangeOrientationTo:(UIInterfaceOrientation)toInterfaceOrientation;
- (void)interfaceDidChangeOrientationFrom:(UIInterfaceOrientation)fromInterfaceOrientation;
#endif
// handling of changing ViewControllers:
// willStartWithViewController: will be called on startup, when creating view hierarchy
// willTransitionToViewController:fromViewController: didTransitionToViewController:fromViewController:
// are called before/after we are doing some magic to switch to new root controller due to forced orientation change
// by default:
// willStartWithViewController: will make _unityView as root view
// willTransitionToViewController:fromViewController: will do nothing
// didTransitionToViewController:fromViewController: will send orientation events to unity view
// you can use them to tweak view hierarchy if needed
- (void)willStartWithViewController:(UIViewController*)controller;
- (void)willTransitionToViewController:(UIViewController*)toController fromViewController:(UIViewController*)fromController;
- (void)didTransitionToViewController:(UIViewController*)toController fromViewController:(UIViewController*)fromController;
// override this if you want to have custom snapshot view.
// by default it will capture the frame drawn inside applicationWillResignActive specifically to let app respond to OnApplicationPause
// will be called on every applicationWillResignActive; returned view will be released in applicationDidBecomeActive
// NB: case of returning nil will be handled gracefully
- (UIView*)createSnapshotView;
// you should not override these methods
// creates initial UI hierarchy (e.g. splash screen) and calls willStartWithViewController
- (void)createUI;
// shows game itself (hides splash, and bring _rootView to front)
- (void)showGameUI;
// returns the topmost presentedViewController if there is one, or just rootViewController
- (UIViewController*)topMostController;
// will create the correct view controller for requested orientation/autorotation
- (UIViewController*)createRootViewController;
// old deprecated methods: no longer used
// the caveat is: there are some issues in clang related to method deprecation
// which results in warnings not being generated for overriding deprecated methods (in some circumstances).
// so instead of deprecating these methods we just remove them and will check at runtime if user have them and whine about it
//- (UnityView*)createUnityViewImpl DEPRECATED_MSG_ATTRIBUTE("Will not be called. Override createUnityView");
//- (void)createViewHierarchyImpl DEPRECATED_MSG_ATTRIBUTE("Will not be called. Override willStartWithViewController");
//- (void)createViewHierarchy DEPRECATED_MSG_ATTRIBUTE("Is not implemented. Use createUI");
@end
#if UNITY_SUPPORT_ROTATION
@interface UnityAppController (OrientationSupport)
// will create the correct view controller for given orientation
- (UIViewController*)createRootViewControllerForOrientation:(UIInterfaceOrientation)orientation;
// forcibly orient interface
- (void)orientInterface:(UIInterfaceOrientation)orient;
// check unity requested orientation and applies it
- (void)checkOrientationRequest;
- (void)orientUnity:(UIInterfaceOrientation)orient __deprecated_msg("use orientInterface instead.");
@end
#endif
#import "UnityView.h"
#include "UI/Keyboard.h"
#include <sys/time.h>
#include <map>
#include <vector>
static NSArray* keyboardCommands = nil;
extern "C" int UnityGetAppleTVRemoteAllowExitToMenu();
extern "C" void UnitySetAppleTVRemoteAllowExitToMenu(int val);
@implementation UnityView (Keyboard)
// Keyboard shortcuts don't provide events for key up
// Keyboard shortcut callbacks are called with 0.4 (first time) and 0.1 (following times) seconds interval while pressing the key
// Below we implement key expiration mechanism where key up event is generated if shortcut callback
// is not called for specific key for more than <kKeyTimeoutInSeconds>
typedef std::map<int, double> KeyMap;
static const double kKeyTimeoutInSeconds = 0.5;
static KeyMap& GetKeyMap()
{
static KeyMap s_Map;
return s_Map;
}
static double GetTimeInSeconds()
{
timeval now;
gettimeofday(&now, NULL);
return now.tv_sec + now.tv_usec / 1000000.0;
}
- (void)createKeyboard
{
// only English keyboard layout is supported
NSString* baseLayout = @"1234567890-=qwertyuiop[]asdfghjkl;'\\`zxcvbnm,./!@#$%^&*()_+{}:\"|<>?~ \t\r\b\\";
NSString* numpadLayout = @"1234567890-=*+/.\r";
NSString* upperCaseLetters = @"QWERTYUIOPASDFGHJKLZXCVBNM";
size_t sizeOfKeyboardCommands = baseLayout.length + numpadLayout.length + upperCaseLetters.length + 11;
NSMutableArray* commands = [NSMutableArray arrayWithCapacity: sizeOfKeyboardCommands];
for (NSInteger i = 0; i < baseLayout.length; ++i)
{
NSString* input = [baseLayout substringWithRange: NSMakeRange(i, 1)];
[commands addObject: [UIKeyCommand keyCommandWithInput: input modifierFlags: kNilOptions action: @selector(handleCommand:)]];
}
for (NSInteger i = 0; i < numpadLayout.length; ++i)
{
NSString* input = [numpadLayout substringWithRange: NSMakeRange(i, 1)];
[commands addObject: [UIKeyCommand keyCommandWithInput: input modifierFlags: UIKeyModifierNumericPad action: @selector(handleCommand:)]];
}
for (NSInteger i = 0; i < upperCaseLetters.length; ++i)
{
NSString* input = [upperCaseLetters substringWithRange: NSMakeRange(i, 1)];
[commands addObject: [UIKeyCommand keyCommandWithInput: input modifierFlags: UIKeyModifierShift action: @selector(handleCommand:)]];
}
// up, down, left, right, esc
[commands addObject: [UIKeyCommand keyCommandWithInput: UIKeyInputUpArrow modifierFlags: kNilOptions action: @selector(handleCommand:)]];
[commands addObject: [UIKeyCommand keyCommandWithInput: UIKeyInputDownArrow modifierFlags: kNilOptions action: @selector(handleCommand:)]];
[commands addObject: [UIKeyCommand keyCommandWithInput: UIKeyInputLeftArrow modifierFlags: kNilOptions action: @selector(handleCommand:)]];
[commands addObject: [UIKeyCommand keyCommandWithInput: UIKeyInputRightArrow modifierFlags: kNilOptions action: @selector(handleCommand:)]];
[commands addObject: [UIKeyCommand keyCommandWithInput: UIKeyInputEscape modifierFlags: kNilOptions action: @selector(handleCommand:)]];
// caps Lock, shift, control, option, command
[commands addObject: [UIKeyCommand keyCommandWithInput: @"" modifierFlags: UIKeyModifierAlphaShift action: @selector(handleCommand:)]];
[commands addObject: [UIKeyCommand keyCommandWithInput: @"" modifierFlags: UIKeyModifierShift action: @selector(handleCommand:)]];
[commands addObject: [UIKeyCommand keyCommandWithInput: @"" modifierFlags: UIKeyModifierControl action: @selector(handleCommand:)]];
[commands addObject: [UIKeyCommand keyCommandWithInput: @"" modifierFlags: UIKeyModifierAlternate action: @selector(handleCommand:)]];
[commands addObject: [UIKeyCommand keyCommandWithInput: @"" modifierFlags: UIKeyModifierCommand action: @selector(handleCommand:)]];
keyboardCommands = commands.copy;
}
- (NSArray*)keyCommands
{
//keyCommands take control of buttons over UITextView, that's why need to return nil if text input field is active or we have an external keyboard attached AND a first responder
if ([[KeyboardDelegate Instance] status] == Visible || ([[KeyboardDelegate Instance] hasExternalKeyboard] && [self hasFirstResponderInHeirachy: UnityGetGLView()]))
return nil;
if (keyboardCommands == nil)
{
[self createKeyboard];
}
return keyboardCommands;
}
- (bool)hasFirstResponderInHeirachy:(UIView*)view
{
if (view.isFirstResponder)
return true;
for (UIView* subview in view.subviews)
{
if ([self hasFirstResponderInHeirachy: subview])
return true;
}
return false;
}
- (bool)isValidCodeForButton:(int)code
{
return (code > 0 && code < 128);
}
- (void)handleCommand:(UIKeyCommand *)command
{
NSString* input = command.input;
UIKeyModifierFlags modifierFlags = command.modifierFlags;
char inputChar = ([input length] > 0) ? [input characterAtIndex: 0] : 0;
int code = (int)inputChar; // ASCII code
UnitySendKeyboardCommand(command);
if (![self isValidCodeForButton: code])
{
code = 0;
}
if ((modifierFlags & UIKeyModifierAlphaShift) != 0)
code = UnityStringToKey("caps lock");
if ((modifierFlags & UIKeyModifierShift) != 0)
code = UnityStringToKey("left shift");
if ((modifierFlags & UIKeyModifierControl) != 0)
code = UnityStringToKey("left ctrl");
if ((modifierFlags & UIKeyModifierAlternate) != 0)
code = UnityStringToKey("left alt");
if ((modifierFlags & UIKeyModifierCommand) != 0)
code = UnityStringToKey("left cmd");
if ((modifierFlags & UIKeyModifierNumericPad) != 0)
{
switch (inputChar)
{
case '0':
code = UnityStringToKey("[0]");
break;
case '1':
code = UnityStringToKey("[1]");
break;
case '2':
code = UnityStringToKey("[2]");
break;
case '3':
code = UnityStringToKey("[3]");
break;
case '4':
code = UnityStringToKey("[4]");
break;
case '5':
code = UnityStringToKey("[5]");
break;
case '6':
code = UnityStringToKey("[6]");
break;
case '7':
code = UnityStringToKey("[7]");
break;
case '8':
code = UnityStringToKey("[8]");
break;
case '9':
code = UnityStringToKey("[9]");
break;
case '-':
code = UnityStringToKey("[-]");
break;
case '=':
code = UnityStringToKey("equals");
break;
case '*':
code = UnityStringToKey("[*]");
break;
case '+':
code = UnityStringToKey("[+]");
break;
case '/':
code = UnityStringToKey("[/]");
break;
case '.':
code = UnityStringToKey("[.]");
break;
case '\r':
code = UnityStringToKey("enter");
break;
default:
break;
}
}
if (input == UIKeyInputUpArrow)
code = UnityStringToKey("up");
else if (input == UIKeyInputDownArrow)
code = UnityStringToKey("down");
else if (input == UIKeyInputRightArrow)
code = UnityStringToKey("right");
else if (input == UIKeyInputLeftArrow)
code = UnityStringToKey("left");
else if (input == UIKeyInputEscape)
code = UnityStringToKey("escape");
KeyMap::iterator item = GetKeyMap().find(code);
if (item == GetKeyMap().end())
{
// New key is down, register it and its time
UnitySetKeyboardKeyState(code, true);
GetKeyMap()[code] = GetTimeInSeconds();
}
else
{
// Still holding the key, update its time
item->second = GetTimeInSeconds();
}
}
- (void)processKeyboard
{
KeyMap& map = GetKeyMap();
if (map.size() == 0)
return;
std::vector<int> keysToUnpress;
double nowTime = GetTimeInSeconds();
for (KeyMap::iterator item = map.begin();
item != map.end();
item++)
{
// Key has expired, register it for key up event
if (nowTime - item->second > kKeyTimeoutInSeconds)
keysToUnpress.push_back(item->first);
}
for (std::vector<int>::iterator item = keysToUnpress.begin();
item != keysToUnpress.end();
item++)
{
map.erase(*item);
UnitySetKeyboardKeyState(*item, false);
}
}
@end
#pragma once
@interface UnityView (iOS)
// will simply update content orientation (it might be tweaked in layoutSubviews, due to disagreement between unity and view controller)
- (void)willRotateToOrientation:(UIInterfaceOrientation)toOrientation fromOrientation:(UIInterfaceOrientation)fromOrientation;
// will recreate gles backing if needed and repaint once to make sure we dont have black frame creeping in
- (void)didRotate;
- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event;
- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event;
- (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event;
- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event;
@end
#if PLATFORM_IOS
#import "UnityView.h"
#import "UnityAppController+Rendering.h"
#include "OrientationSupport.h"
extern bool _unityAppReady;
@interface UnityView ()
@property (nonatomic, readwrite) ScreenOrientation contentOrientation;
@end
@implementation UnityView (iOS)
- (void)willRotateToOrientation:(UIInterfaceOrientation)toOrientation fromOrientation:(UIInterfaceOrientation)fromOrientation;
{
// to support the case of interface and unity content orientation being different
// we will cheat a bit:
// we will calculate transform between interface orientations and apply it to unity view orientation
// you can still tweak unity view as you see fit in AppController, but this is what you want in 99% of cases
ScreenOrientation to = ConvertToUnityScreenOrientation(toOrientation);
ScreenOrientation from = ConvertToUnityScreenOrientation(fromOrientation);
if (fromOrientation == UIInterfaceOrientationUnknown)
_curOrientation = to;
else
_curOrientation = OrientationAfterTransform(_curOrientation, TransformBetweenOrientations(from, to));
_viewIsRotating = YES;
}
- (void)didRotate
{
if (_shouldRecreateView)
{
[self recreateRenderingSurface];
}
_viewIsRotating = NO;
}
- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event { UnitySendTouchesBegin(touches, event); }
- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event { UnitySendTouchesEnded(touches, event); }
- (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event { UnitySendTouchesCancelled(touches, event); }
- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event { UnitySendTouchesMoved(touches, event); }
@end
#endif // PLATFORM_IOS
#pragma once
@interface UnityView (tvOS)
- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event;
- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event;
- (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event;
- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event;
#if UNITY_TVOS_SIMULATOR_FAKE_REMOTE
- (void)pressesBegan:(NSSet<UIPress*>*)presses withEvent:(UIEvent*)event;
- (void)pressesEnded:(NSSet<UIPress*>*)presses withEvent:(UIEvent*)event;
#endif
@end
#if PLATFORM_TVOS
#import "UnityView.h"
#include "iphone_Sensors.h"
@implementation UnityView (tvOS)
- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event
{
#if UNITY_TVOS_SIMULATOR_FAKE_REMOTE
ReportSimulatedRemoteTouchesBegan(self, touches);
#endif
if (UnityGetAppleTVRemoteTouchesEnabled())
UnitySendTouchesBegin(touches, event);
}
- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event
{
#if UNITY_TVOS_SIMULATOR_FAKE_REMOTE
ReportSimulatedRemoteTouchesEnded(self, touches);
#endif
if (UnityGetAppleTVRemoteTouchesEnabled())
UnitySendTouchesEnded(touches, event);
}
- (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event
{
#if UNITY_TVOS_SIMULATOR_FAKE_REMOTE
ReportSimulatedRemoteTouchesEnded(self, touches);
#endif
if (UnityGetAppleTVRemoteTouchesEnabled())
UnitySendTouchesCancelled(touches, event);
}
- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event
{
#if UNITY_TVOS_SIMULATOR_FAKE_REMOTE
ReportSimulatedRemoteTouchesMoved(self, touches);
#endif
if (UnityGetAppleTVRemoteTouchesEnabled())
UnitySendTouchesMoved(touches, event);
}
#if UNITY_TVOS_SIMULATOR_FAKE_REMOTE
- (void)pressesBegan:(NSSet<UIPress*>*)presses withEvent:(UIEvent*)event
{
for (UIPress *press in presses)
ReportSimulatedRemoteButtonPress(press.type);
}
- (void)pressesEnded:(NSSet<UIPress*>*)presses withEvent:(UIEvent*)event
{
for (UIPress *press in presses)
ReportSimulatedRemoteButtonRelease(press.type);
}
#endif
@end
#endif // PLATFORM_TVOS
#pragma once
@interface UnityRenderingView : UIView
{
}
+ (void)InitializeForAPI:(UnityRenderingAPI)api;
@end
@interface UnityView : UnityRenderingView
{
@private ScreenOrientation _curOrientation;
@private BOOL _shouldRecreateView;
@private BOOL _viewIsRotating;
}
// we take scale factor into account because gl backbuffer size depends on it
- (id)initWithFrame:(CGRect)frame scaleFactor:(CGFloat)scale;
- (id)initWithFrame:(CGRect)frame;
- (id)initFromMainScreen;
// in here we will go through subviews and call onUnityUpdateViewLayout selector (if present)
// that allows to handle simple overlay child view layout without doing view controller magic
- (void)layoutSubviews;
- (void)recreateRenderingSurfaceIfNeeded;
- (void)recreateRenderingSurface;
// will match script-side Screen.orientation
@property (nonatomic, readonly) ScreenOrientation contentOrientation;
@end
@interface UnityView (Deprecated)
- (void)recreateGLESSurfaceIfNeeded __deprecated_msg("use recreateRenderingSurfaceIfNeeded instead.");
- (void)recreateGLESSurface __deprecated_msg("use recreateRenderingSurface instead.");
@end
@interface UnityView (Keyboard)
- (void)processKeyboard;
@end
@interface UnityView (UnityAppController)
// if we know that unity view bounds have changed but need to update unity-side size/orientation immediately
// otherwise the update will be delayed to next layoutSubviews
- (void)boundsUpdated;
@end
#if PLATFORM_IOS
#include "UnityView+iOS.h"
#elif PLATFORM_TVOS
#include "UnityView+tvOS.h"
#endif
void ReportSafeAreaChangeForView(UIView* view);
// Computes safe area for a view in Unity coordinate system (origin of the view
// is bottom-left, as compared to standard top-left)
CGRect ComputeSafeArea(UIView* view);
CGSize GetCutoutToScreenRatio();
#pragma once
@interface UnityViewControllerBase (iOS)
- (BOOL)shouldAutorotate;
- (BOOL)prefersStatusBarHidden;
- (UIStatusBarStyle)preferredStatusBarStyle;
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator;
@end
// for better handling of user-imposed screen orientation we will have specific ViewController implementations
// view controllers constrained to one orientation
@interface UnityPortraitOnlyViewController : UnityViewControllerBase
{
}
@end
@interface UnityPortraitUpsideDownOnlyViewController : UnityViewControllerBase
{
}
@end
@interface UnityLandscapeLeftOnlyViewController : UnityViewControllerBase
{
}
@end
@interface UnityLandscapeRightOnlyViewController : UnityViewControllerBase
{
}
@end
// this is default view controller implementation (autorotation enabled)
@interface UnityDefaultViewController : UnityViewControllerBase
{
}
// we have well defined points where we should update supported orientations:
// on init and inside [UnityAppController checkOrientationRequest]
// note that the latter will recreate default view controller if supported orientations conflict with the current orientation
// this is done as opposed to [UnityDefaultViewController supportedInterfaceOrientations] poking unity for that
// as this might happen in "random" places, out-of-sync with our handling of "orientation constraints were changed at unity side"
- (void)updateSupportedOrientations;
@end
NSUInteger EnabledAutorotationInterfaceOrientations();
#if PLATFORM_IOS
#import "UnityViewControllerBase.h"
#import "UnityAppController.h"
#include "OrientationSupport.h"
#include "Keyboard.h"
#include "UnityView.h"
#include "PluginBase/UnityViewControllerListener.h"
#include "UnityAppController.h"
#include "UnityAppController+ViewHandling.h"
#include "Unity/ObjCRuntime.h"
// when returning from presenting UIViewController we might need to update app orientation to "correct" one, as we wont get rotation notification
@interface UnityAppController ()
- (void)updateAppOrientation:(UIInterfaceOrientation)orientation;
@end
@implementation UnityViewControllerBase (iOS)
ScreenOrientation _currentOrientation;
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear: animated];
_currentOrientation = UIViewControllerOrientation(self);
AppController_SendUnityViewControllerNotification(kUnityViewDidAppear);
}
- (BOOL)shouldAutorotate
{
return YES;
}
- (BOOL)prefersStatusBarHidden
{
static bool _PrefersStatusBarHidden = true;
static bool _PrefersStatusBarHiddenInited = false;
if (!_PrefersStatusBarHiddenInited)
{
NSNumber* hidden = [[[NSBundle mainBundle] infoDictionary] objectForKey: @"UIStatusBarHidden"];
_PrefersStatusBarHidden = hidden ? [hidden boolValue] : YES;
_PrefersStatusBarHiddenInited = true;
}
return _PrefersStatusBarHidden;
}
- (UIStatusBarStyle)preferredStatusBarStyle
{
static UIStatusBarStyle _PreferredStatusBarStyle = UIStatusBarStyleDefault;
static bool _PreferredStatusBarStyleInited = false;
if (!_PreferredStatusBarStyleInited)
{
NSString* style = [[[NSBundle mainBundle] infoDictionary] objectForKey: @"UIStatusBarStyle"];
if (style && [style isEqualToString: @"UIStatusBarStyleLightContent"])
_PreferredStatusBarStyle = UIStatusBarStyleLightContent;
_PreferredStatusBarStyleInited = true;
}
return _PreferredStatusBarStyle;
}
- (UIRectEdge)preferredScreenEdgesDeferringSystemGestures
{
UIRectEdge res = UIRectEdgeNone;
if (UnityGetDeferSystemGesturesTopEdge())
res |= UIRectEdgeTop;
if (UnityGetDeferSystemGesturesBottomEdge())
res |= UIRectEdgeBottom;
if (UnityGetDeferSystemGesturesLeftEdge())
res |= UIRectEdgeLeft;
if (UnityGetDeferSystemGesturesRightEdge())
res |= UIRectEdgeRight;
return res;
}
- (BOOL)prefersHomeIndicatorAutoHidden
{
return UnityGetHideHomeButton();
}
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
// Dropped UIViewControllerOrientation(self) usage to calculate current orientation because
// in some cases this method is called after screen has already turned so
// UIViewControllerOrientation(self) might give inconsistant results
ScreenOrientation curOrient = _currentOrientation;
ScreenOrientation newOrient = OrientationAfterTransform(curOrient, [coordinator targetTransform]);
_currentOrientation = newOrient;
// in case of presentation controller it will take control over orientations
// so to avoid crazy corner cases, make default view controller to ignore "wrong" orientations
// as they will come only in case of presentation view controller and will be reverted anyway
// NB: we still want to pass message to super, we just want to skip unity-specific magic
NSUInteger targetMask = 1 << ConvertToIosScreenOrientation(newOrient);
if (([self supportedInterfaceOrientations] & targetMask) != 0)
{
[UIView setAnimationsEnabled: UnityUseAnimatedAutorotation() ? YES : NO];
[KeyboardDelegate StartReorientation];
[GetAppController() interfaceWillChangeOrientationTo: ConvertToIosScreenOrientation(newOrient)];
[coordinator animateAlongsideTransition: nil completion:^(id<UIViewControllerTransitionCoordinatorContext> context) {
[self.view setNeedsLayout];
[GetAppController() interfaceDidChangeOrientationFrom: ConvertToIosScreenOrientation(curOrient)];
[KeyboardDelegate FinishReorientation];
[UIView setAnimationsEnabled: YES];
}];
}
[super viewWillTransitionToSize: size withTransitionCoordinator: coordinator];
}
@end
@implementation UnityDefaultViewController
// these will be updated in one place where we "sync" UI side orientation handling to unity side
NSUInteger _supportedOrientations;
- (id)init
{
if ((self = [super init]))
{
NSAssert(UnityShouldAutorotate(), @"UnityDefaultViewController should be used only if unity is set to autorotate");
_supportedOrientations = EnabledAutorotationInterfaceOrientations();
}
return self;
}
- (void)updateSupportedOrientations
{
_supportedOrientations = EnabledAutorotationInterfaceOrientations();
}
- (NSUInteger)supportedInterfaceOrientations
{
return _supportedOrientations;
}
@end
@implementation UnityPortraitOnlyViewController
- (NSUInteger)supportedInterfaceOrientations
{
return 1 << UIInterfaceOrientationPortrait;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationPortrait;
}
- (void)viewWillAppear:(BOOL)animated
{
[GetAppController() updateAppOrientation: UIInterfaceOrientationPortrait];
[super viewWillAppear: animated];
}
@end
@implementation UnityPortraitUpsideDownOnlyViewController
- (NSUInteger)supportedInterfaceOrientations
{
return 1 << UIInterfaceOrientationPortraitUpsideDown;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationPortraitUpsideDown;
}
- (void)viewWillAppear:(BOOL)animated
{
[GetAppController() updateAppOrientation: UIInterfaceOrientationPortraitUpsideDown];
[super viewWillAppear: animated];
}
@end
@implementation UnityLandscapeLeftOnlyViewController
- (NSUInteger)supportedInterfaceOrientations
{
return 1 << UIInterfaceOrientationLandscapeLeft;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationLandscapeLeft;
}
- (void)viewWillAppear:(BOOL)animated
{
[GetAppController() updateAppOrientation: UIInterfaceOrientationLandscapeLeft];
[super viewWillAppear: animated];
}
@end
@implementation UnityLandscapeRightOnlyViewController
- (NSUInteger)supportedInterfaceOrientations
{
return 1 << UIInterfaceOrientationLandscapeRight;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationLandscapeRight;
}
- (void)viewWillAppear:(BOOL)animated
{
[GetAppController() updateAppOrientation: UIInterfaceOrientationLandscapeRight];
[super viewWillAppear: animated];
}
@end
NSUInteger EnabledAutorotationInterfaceOrientations()
{
NSUInteger ret = 0;
if (UnityIsOrientationEnabled(portrait))
ret |= (1 << UIInterfaceOrientationPortrait);
if (UnityDeviceSupportsUpsideDown() && UnityIsOrientationEnabled(portraitUpsideDown))
ret |= (1 << UIInterfaceOrientationPortraitUpsideDown);
if (UnityIsOrientationEnabled(landscapeLeft))
ret |= (1 << UIInterfaceOrientationLandscapeRight);
if (UnityIsOrientationEnabled(landscapeRight))
ret |= (1 << UIInterfaceOrientationLandscapeLeft);
return ret;
}
#endif // PLATFORM_IOS
#pragma once
//for tvOS we need just one view controller subclass as there is no screen orientation here
@interface UnityDefaultViewController : UnityViewControllerBase
{
}
@end
#if PLATFORM_TVOS
#import "UnityViewControllerBase.h"
#import "UnityAppController.h"
@implementation UnityDefaultViewController
@end
#endif // PLATFORM_TVOS
#pragma once
#import <UIKit/UIKit.h>
#import "PluginBase/UnityViewControllerListener.h"
#if PLATFORM_IOS
#define UNITY_VIEW_CONTROLLER_BASE_CLASS UIViewController
#elif PLATFORM_TVOS
#import <GameController/GCController.h>
#define UNITY_VIEW_CONTROLLER_BASE_CLASS GCEventViewController
#endif
@interface UnityViewControllerBase : UNITY_VIEW_CONTROLLER_BASE_CLASS
{
id<UnityViewControllerNotifications> _notificationDelegate;
}
- (void)viewWillLayoutSubviews;
- (void)viewDidLayoutSubviews;
- (void)viewDidDisappear:(BOOL)animated;
- (void)viewWillDisappear:(BOOL)animated;
- (void)viewDidAppear:(BOOL)animated;
- (void)viewWillAppear:(BOOL)animated;
@property (nonatomic, retain) id<UnityViewControllerNotifications> notificationDelegate;
@end
#if PLATFORM_IOS
#include "UnityViewControllerBase+iOS.h"
#elif PLATFORM_TVOS
#include "UnityViewControllerBase+tvOS.h"
#endif
// this should be used to create view controller that plays nicely with unity and account for player settings
UnityViewControllerBase* AllocUnityViewController(void);
UnityViewControllerBase* AllocUnityDefaultViewController(void);
#if UNITY_SUPPORT_ROTATION
UnityViewControllerBase* AllocUnitySingleOrientationViewController(UIInterfaceOrientation orient);
#endif
#import "UnityViewControllerBase.h"
#import "UnityAppController.h"
#import "UnityAppController+ViewHandling.h"
#include "OrientationSupport.h"
@implementation UnityViewControllerBase
@synthesize notificationDelegate = _notificationDelegate;
- (id)init
{
if ((self = [super init]))
self.modalPresentationStyle = UIModalPresentationFullScreen;
return self;
}
- (void)viewWillLayoutSubviews
{
[super viewWillLayoutSubviews];
[_notificationDelegate onViewWillLayoutSubviews];
}
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
[_notificationDelegate onViewDidLayoutSubviews];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear: animated];
[_notificationDelegate onViewDidDisappear: animated];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear: animated];
[_notificationDelegate onViewWillDisappear: animated];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear: animated];
[_notificationDelegate onViewDidAppear: animated];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear: animated];
[_notificationDelegate onViewWillAppear: animated];
}
@end
UnityViewControllerBase* AllocUnityDefaultViewController()
{
return [UnityDefaultViewController alloc];
}
#if UNITY_SUPPORT_ROTATION
UnityViewControllerBase* AllocUnitySingleOrientationViewController(UIInterfaceOrientation orient)
{
switch (orient)
{
case UIInterfaceOrientationPortrait: return [UnityPortraitOnlyViewController alloc];
case UIInterfaceOrientationPortraitUpsideDown: return [UnityPortraitUpsideDownOnlyViewController alloc];
case UIInterfaceOrientationLandscapeLeft: return [UnityLandscapeLeftOnlyViewController alloc];
case UIInterfaceOrientationLandscapeRight: return [UnityLandscapeRightOnlyViewController alloc];
default: assert(false && "bad UIInterfaceOrientation provided");
}
return nil;
}
#endif
UnityViewControllerBase* AllocUnityViewController()
{
#if UNITY_SUPPORT_ROTATION
if (UnityShouldAutorotate())
return AllocUnityDefaultViewController();
UIInterfaceOrientation orient = ConvertToIosScreenOrientation((ScreenOrientation)UnityRequestedScreenOrientation());
return AllocUnitySingleOrientationViewController(orient);
#else
return AllocUnityDefaultViewController();
#endif
}
// DO NOT PUT #pragma once or include guard check here
// This header is designed to be able to be included multiple times
// This header is used to temporary undefine all platform definitions in case there is a naming conflict with
// 3rd party code. Please make sure to always use this paired with the RedefinePlatforms.h header.
//
// ex.
//
// #include "UndefinePlatforms.h"
// #include "Some3rdParty.h"
// #include "RedefinePlatforms.h"
#ifdef DETAIL__PLATFORMS_HAD_BEEN_UNDEFINED_BY_UNDEFINEPLATFORMS_H
#error "UndefinePlatforms.h has been included more than once or RedefinePlatforms.h is missing."
#endif
// define all other platforms to 0
#if PLATFORM_WIN
#define DETAIL__TEMP_PLATFORM_WIN_WAS_1
#endif
#undef PLATFORM_WIN
#if PLATFORM_OSX
#define DETAIL__TEMP_PLATFORM_OSX_WAS_1
#endif
#undef PLATFORM_OSX
#if PLATFORM_LINUX
#define DETAIL__TEMP_PLATFORM_LINUX_WAS_1
#endif
#undef PLATFORM_LINUX
#if PLATFORM_WINRT
#define DETAIL__TEMP_PLATFORM_WINRT_WAS_1
#endif
#undef PLATFORM_WINRT
#if PLATFORM_FAMILY_WINDOWSGAMES
#define DETAIL__TEMP_PLATFORM_FAMILY_WINDOWSGAMES_WAS_1
#endif
#undef PLATFORM_FAMILY_WINDOWSGAMES
#if PLATFORM_WEBGL
#define DETAIL__TEMP_PLATFORM_WEBGL_WAS_1
#endif
#undef PLATFORM_WEBGL
#if PLATFORM_ANDROID
#define DETAIL__TEMP_PLATFORM_ANDROID_WAS_1
#endif
#undef PLATFORM_ANDROID
#if PLATFORM_PS4
#define DETAIL__TEMP_PLATFORM_PS4_WAS_1
#endif
#undef PLATFORM_PS4
#if PLATFORM_IPHONE
#define DETAIL__TEMP_PLATFORM_IPHONE_WAS_1
#endif
#undef PLATFORM_IPHONE
#if PLATFORM_IOS
#define DETAIL__TEMP_PLATFORM_IOS_WAS_1
#endif
#undef PLATFORM_IOS
#if PLATFORM_TVOS
#define DETAIL__TEMP_PLATFORM_TVOS_WAS_1
#endif
#undef PLATFORM_TVOS
#if PLATFORM_XBOXONE
#define DETAIL__TEMP_PLATFORM_XBOXONE_WAS_1
#endif
#undef PLATFORM_XBOXONE
#if PLATFORM_SWITCH
#define DETAIL__TEMP_PLATFORM_SWITCH_WAS_1
#endif
#undef PLATFORM_SWITCH
#if PLATFORM_LUMIN
#define DETAIL__TEMP_PLATFORM_LUMIN_WAS_1
#endif
#undef PLATFORM_LUMIN
#if PLATFORM_GGP
#define DETAIL__TEMP_PLATFORM_GGP_WAS_1
#endif
#undef PLATFORM_GGP
#if PLATFORM_NETBSD
#define DETAIL__TEMP_PLATFORM_NETBSD_WAS_1
#endif
#undef PLATFORM_NETBSD
#define DETAIL__PLATFORMS_HAD_BEEN_UNDEFINED_BY_UNDEFINEPLATFORMS_H
#pragma once
enum
{
avCapturePermissionUnknown = 0,
avCapturePermissionGranted = 1,
avCapturePermissionDenied = 2,
};
enum
{
avVideoCapture = 1,
avAudioCapture = 2,
};
extern "C" int UnityGetAVCapturePermission(int captureType);
extern "C" void UnityRequestAVCapturePermission(int captureType, void* userData);
#include "AVCapture.h"
#include <AVFoundation/AVFoundation.h>
static NSString* MediaTypeFromEnum(int captureType)
{
if (captureType == avAudioCapture)
return AVMediaTypeAudio;
else if (captureType == avVideoCapture)
return AVMediaTypeVideo;
return nil;
}
extern "C" int UnityGetAVCapturePermission(int captureType)
{
NSString* mediaType = MediaTypeFromEnum(captureType);
if (mediaType == nil)
return avCapturePermissionDenied;
#if !PLATFORM_TVOS && (UNITY_USES_WEBCAM || UNITY_USES_MICROPHONE)
NSInteger status = AVAuthorizationStatusAuthorized;
status = [AVCaptureDevice authorizationStatusForMediaType: mediaType];
if (status == AVAuthorizationStatusNotDetermined)
return avCapturePermissionUnknown;
else if (status == AVAuthorizationStatusAuthorized)
return avCapturePermissionGranted;
#endif
return avCapturePermissionDenied;
}
extern "C" void UnityRequestAVCapturePermission(int captureType, void* userData)
{
#if !PLATFORM_TVOS && (UNITY_USES_WEBCAM || UNITY_USES_MICROPHONE)
NSString* mediaType = MediaTypeFromEnum(captureType);
if (mediaType == nil)
return;
[AVCaptureDevice requestAccessForMediaType: mediaType completionHandler:^(BOOL granted) {
UnityReportAVCapturePermission(userData);
}];
#endif
}
#pragma once
// small helper for getting texture from CMSampleBuffer
typedef struct
CMVideoSampling
{
void* cvTextureCache;
void* cvTextureCacheTexture;
void* cvImageBuffer;
}
CMVideoSampling;
void CMVideoSampling_Initialize(CMVideoSampling* sampling);
void CMVideoSampling_Uninitialize(CMVideoSampling* sampling);
intptr_t CMVideoSampling_ImageBuffer(CMVideoSampling* sampling, CVImageBufferRef buffer, size_t* w, size_t* h);
intptr_t CMVideoSampling_SampleBuffer(CMVideoSampling* sampling, void* buffer, size_t* w, size_t* h); // buffer is CMSampleBufferRef
intptr_t CMVideoSampling_LastSampledTexture(CMVideoSampling* sampling);
#include "CMVideoSampling.h"
#include "CVTextureCache.h"
#include "GlesHelper.h"
#include <OpenGLES/ES3/glext.h>
#include <AVFoundation/AVFoundation.h>
void CMVideoSampling_Initialize(CMVideoSampling* sampling)
{
::memset(sampling, 0x00, sizeof(CMVideoSampling));
sampling->cvTextureCache = CreateCVTextureCache();
}
void CMVideoSampling_Uninitialize(CMVideoSampling* sampling)
{
if (sampling->cvImageBuffer)
{
CFRelease(sampling->cvImageBuffer);
sampling->cvImageBuffer = 0;
}
if (sampling->cvTextureCacheTexture)
{
CFRelease(sampling->cvTextureCacheTexture);
sampling->cvTextureCacheTexture = 0;
}
if (sampling->cvTextureCache)
{
CFRelease(sampling->cvTextureCache);
sampling->cvTextureCache = 0;
}
}
intptr_t CMVideoSampling_ImageBuffer(CMVideoSampling* sampling, CVImageBufferRef buffer, size_t* w, size_t* h)
{
intptr_t retTex = 0;
if (sampling->cvImageBuffer)
CFRelease(sampling->cvImageBuffer);
sampling->cvImageBuffer = buffer;
CFRetain(sampling->cvImageBuffer);
*w = CVPixelBufferGetWidth((CVImageBufferRef)sampling->cvImageBuffer);
*h = CVPixelBufferGetHeight((CVImageBufferRef)sampling->cvImageBuffer);
if (sampling->cvTextureCacheTexture)
{
CFRelease(sampling->cvTextureCacheTexture);
FlushCVTextureCache(sampling->cvTextureCache);
sampling->cvTextureCacheTexture = nil;
}
OSType pixelFormat = CVPixelBufferGetPixelFormatType(buffer);
switch (pixelFormat)
{
case kCVPixelFormatType_32BGRA:
sampling->cvTextureCacheTexture = CreateBGRA32TextureFromCVTextureCache(sampling->cvTextureCache, sampling->cvImageBuffer, *w, *h);
break;
#if UNITY_HAS_IOSSDK_11_0
case kCVPixelFormatType_DepthFloat16:
sampling->cvTextureCacheTexture = CreateHalfFloatTextureFromCVTextureCache(sampling->cvTextureCache, sampling->cvImageBuffer, *w, *h);
break;
#endif
default:
#define FourCC2Str(fourcc) (const char[]){*(((char*)&fourcc)+3), *(((char*)&fourcc)+2), *(((char*)&fourcc)+1), *(((char*)&fourcc)+0),0}
::printf("CMVideoSampling_SampleBuffer: unexpected pixel format \'%s\'\n", FourCC2Str(pixelFormat));
break;
}
if (sampling->cvTextureCacheTexture)
retTex = GetTextureFromCVTextureCache(sampling->cvTextureCacheTexture);
if (UnitySelectedRenderingAPI() == apiOpenGLES2 || UnitySelectedRenderingAPI() == apiOpenGLES3)
{
GLint oldTexBinding = 0;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldTexBinding);
glBindTexture(GL_TEXTURE_2D, (GLuint)retTex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glBindTexture(GL_TEXTURE_2D, oldTexBinding);
}
return retTex;
}
intptr_t CMVideoSampling_SampleBuffer(CMVideoSampling* sampling, void* buffer, size_t* w, size_t* h)
{
return CMVideoSampling_ImageBuffer(sampling, CMSampleBufferGetImageBuffer((CMSampleBufferRef)buffer), w, h);
}
intptr_t CMVideoSampling_LastSampledTexture(CMVideoSampling* sampling)
{
return GetTextureFromCVTextureCache(sampling->cvTextureCacheTexture);
}
#pragma once
// depending on selected rendering api it will be or GLES or Metal texture cache
// returns CVOpenGLESTextureCacheRef/CVMetalTextureCacheRef
void* CreateCVTextureCache();
// cache = CVOpenGLESTextureCacheRef/CVMetalTextureCacheRef
void FlushCVTextureCache(void* cache);
// returns CVOpenGLESTextureRef/CVMetalTextureRef
// cache = CVOpenGLESTextureCacheRef/CVMetalTextureCacheRef
// image = CVImageBufferRef/CVPixelBufferRef
void* CreateBGRA32TextureFromCVTextureCache(void* cache, void* image, size_t w, size_t h);
void* CreateHalfFloatTextureFromCVTextureCache(void* cache, void* image, size_t w, size_t h);
// texture = CVOpenGLESTextureRef
unsigned GetGLTextureFromCVTextureCache(void* texture);
// texture = CVMetalTextureRef
MTLTextureRef GetMetalTextureFromCVTextureCache(void* texture);
// texture = CVOpenGLESTextureRef/CVMetalTextureRef
uintptr_t GetTextureFromCVTextureCache(void* texture);
// returns CVPixelBufferRef
// enforces kCVPixelFormatType_32BGRA
void* CreatePixelBufferForCVTextureCache(size_t w, size_t h);
// returns CVOpenGLESTextureRef
// cache = CVOpenGLESTextureCacheRef
// pb = CVPixelBufferRef (out)
// enforces rgba texture with bgra backing
void* CreateReadableRTFromCVTextureCache(void* cache, size_t w, size_t h, void** pb);
// texture = CVOpenGLESTextureRef/CVMetalTextureRef
int IsCVTextureFlipped(void* texture);
#include "CVTextureCache.h"
#include "DisplayManager.h"
#include <OpenGLES/ES2/glext.h>
#include <OpenGLES/ES3/gl.h>
#include <OpenGLES/ES3/glext.h>
#include <CoreVideo/CVOpenGLESTextureCache.h>
#include "UnityMetalSupport.h"
#if UNITY_CAN_USE_METAL
#include <CoreVideo/CVMetalTextureCache.h>
#else
typedef void* CVMetalTextureCacheRef;
typedef void* CVMetalTextureRef;
const CFStringRef kCVPixelBufferMetalCompatibilityKey = CFSTR("MetalCompatibility");
inline CVReturn CVMetalTextureCacheCreate(CFAllocatorRef, CFDictionaryRef, MTLDeviceRef, CFDictionaryRef, CVMetalTextureCacheRef*) { return 0; }
inline CVReturn CVMetalTextureCacheCreateTextureFromImage(CFAllocatorRef, CVMetalTextureCacheRef, CVImageBufferRef, CFDictionaryRef, MTLPixelFormat, size_t, size_t, size_t, CVMetalTextureRef*) { return 0; }
inline void CVMetalTextureCacheFlush(CVMetalTextureCacheRef, uint64_t options) {}
inline MTLTextureRef CVMetalTextureGetTexture(CVMetalTextureRef) { return nil; }
inline Boolean CVMetalTextureIsFlipped(CVMetalTextureRef) { return 0; }
#endif
void* CreateCVTextureCache()
{
void* ret = 0;
CVReturn err = 0;
if (UnitySelectedRenderingAPI() == apiMetal)
err = CVMetalTextureCacheCreate(kCFAllocatorDefault, 0, UnityGetMetalDevice(), 0, (CVMetalTextureCacheRef*)&ret);
else
err = CVOpenGLESTextureCacheCreate(kCFAllocatorDefault, 0, UnityGetMainScreenContextGLES(), 0, (CVOpenGLESTextureCacheRef*)&ret);
if (err)
{
::printf("Error at CVOpenGLESTextureCacheCreate: %d", err);
ret = 0;
}
return ret;
}
void FlushCVTextureCache(void* cache)
{
if (UnitySelectedRenderingAPI() == apiMetal)
CVMetalTextureCacheFlush((CVMetalTextureCacheRef)cache, 0);
else
CVOpenGLESTextureCacheFlush((CVOpenGLESTextureCacheRef)cache, 0);
}
void* CreateBGRA32TextureFromCVTextureCache(void* cache, void* image, size_t w, size_t h)
{
void* texture = 0;
CVReturn err = 0;
if (UnitySelectedRenderingAPI() == apiMetal)
{
err = CVMetalTextureCacheCreateTextureFromImage(
kCFAllocatorDefault, (CVMetalTextureCacheRef)cache, (CVImageBufferRef)image, 0,
(MTLPixelFormat)((UnityDisplaySurfaceMTL*)GetMainDisplaySurface())->colorFormat, w, h, 0, (CVMetalTextureRef*)&texture
);
}
else
{
err = CVOpenGLESTextureCacheCreateTextureFromImage(
kCFAllocatorDefault, (CVOpenGLESTextureCacheRef)cache, (CVImageBufferRef)image, 0,
GL_TEXTURE_2D, GL_RGBA, (GLsizei)w, (GLsizei)h, GL_BGRA_EXT, GL_UNSIGNED_BYTE,
0, (CVOpenGLESTextureRef*)&texture
);
}
if (err)
{
::printf("Error at CVOpenGLESTextureCacheCreateTextureFromImage: %d\n", err);
texture = 0;
}
return texture;
}
void* CreateHalfFloatTextureFromCVTextureCache(void* cache, void* image, size_t w, size_t h)
{
void* texture = 0;
CVReturn err = 0;
if (UnitySelectedRenderingAPI() == apiMetal)
{
err = CVMetalTextureCacheCreateTextureFromImage(
kCFAllocatorDefault, (CVMetalTextureCacheRef)cache, (CVImageBufferRef)image, 0,
MTLPixelFormatR16Float, w, h, 0, (CVMetalTextureRef*)&texture
);
}
else if (UnitySelectedRenderingAPI() == apiOpenGLES3)
{
err = CVOpenGLESTextureCacheCreateTextureFromImage(
kCFAllocatorDefault, (CVOpenGLESTextureCacheRef)cache, (CVImageBufferRef)image, 0,
GL_TEXTURE_2D, GL_R16F, (GLsizei)w, (GLsizei)h, GL_RED, GL_HALF_FLOAT,
0, (CVOpenGLESTextureRef*)&texture
);
}
else // OpenGLES2
{
err = CVOpenGLESTextureCacheCreateTextureFromImage(
kCFAllocatorDefault, (CVOpenGLESTextureCacheRef)cache, (CVImageBufferRef)image, 0,
GL_TEXTURE_2D, GL_RED_EXT, (GLsizei)w, (GLsizei)h, GL_RED_EXT, GL_HALF_FLOAT_OES,
0, (CVOpenGLESTextureRef*)&texture
);
}
if (err)
{
::printf("Error at CVOpenGLESTextureCacheCreateTextureFromImage: %d\n", err);
texture = 0;
}
return texture;
}
unsigned GetGLTextureFromCVTextureCache(void* texture)
{
assert(UnitySelectedRenderingAPI() != apiMetal);
return CVOpenGLESTextureGetName((CVOpenGLESTextureRef)texture);
}
id<MTLTexture> GetMetalTextureFromCVTextureCache(void* texture)
{
assert(UnitySelectedRenderingAPI() == apiMetal);
return CVMetalTextureGetTexture((CVMetalTextureRef)texture);
}
uintptr_t GetTextureFromCVTextureCache(void* texture)
{
if (UnitySelectedRenderingAPI() == apiMetal)
return (uintptr_t)(__bridge void*)GetMetalTextureFromCVTextureCache(texture);
else
return (uintptr_t)GetGLTextureFromCVTextureCache(texture);
}
void* CreatePixelBufferForCVTextureCache(size_t w, size_t h)
{
NSString* apiKey = UnitySelectedRenderingAPI() == apiMetal ? (__bridge NSString*)kCVPixelBufferMetalCompatibilityKey
: (__bridge NSString*)kCVPixelBufferOpenGLESCompatibilityKey;
CVPixelBufferRef pb = 0;
NSDictionary* options = @{ (__bridge NSString*)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA),
(__bridge NSString*)kCVPixelBufferWidthKey: @(w),
(__bridge NSString*)kCVPixelBufferHeightKey: @(h),
apiKey: @(YES),
(__bridge NSString*)kCVPixelBufferIOSurfacePropertiesKey: @{}};
CVPixelBufferCreate(kCFAllocatorDefault, w, h, kCVPixelFormatType_32BGRA, (__bridge CFDictionaryRef)options, &pb);
return pb;
}
void* CreateReadableRTFromCVTextureCache(void* cache, size_t w, size_t h, void** pb)
{
*pb = CreatePixelBufferForCVTextureCache(w, h);
return CreateBGRA32TextureFromCVTextureCache(cache, *pb, w, h);
}
int IsCVTextureFlipped(void* texture)
{
if (UnitySelectedRenderingAPI() == apiMetal)
return CVMetalTextureIsFlipped((CVMetalTextureRef)texture);
else
return CVOpenGLESTextureIsFlipped((CVOpenGLESTextureRef)texture);
}
#pragma once
#import <AVFoundation/AVFoundation.h>
#if UNITY_HAS_IOSSDK_11_0
#define UNITY_HAS_COLORANDDEPTH_CAMERA 1
#else
#define UNITY_HAS_COLORANDDEPTH_CAMERA 0
#endif
@interface CameraCaptureController : NSObject<AVCaptureVideoDataOutputSampleBufferDelegate
#if UNITY_HAS_COLORANDDEPTH_CAMERA
, AVCaptureDataOutputSynchronizerDelegate
#endif
>
- (bool)initCapture:(AVCaptureDevice*)device;
- (bool)initCapture:(AVCaptureDevice*)device preset:(NSString*)preset fps:(float)fps;
- (void)setCaptureFPS:(float)fps;
#if UNITY_HAS_COLORANDDEPTH_CAMERA
- (bool)initColorAndDepthCameraCapture:(AVCaptureDevice*)device preset:(NSString*)preset fps:(float)fps isDepth:(bool)isDepth;
- (void)initColorAndDepthCameraCaptureSession;
- (void)clearColorAndDepthCameraCaptureSession;
- (void)captureOutput:(AVCaptureOutput*)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection*)connection;
- (void)depthDataOutput:(AVCaptureDepthDataOutput*)captureDepthOutput didOutputDepthData:(AVDepthData*)depthData timestamp:(CMTime)timestamp connection:(AVCaptureConnection*)connection;
- (void)dataOutputSynchronizer:(AVCaptureDataOutputSynchronizer *)synchronizer didOutputSynchronizedDataCollection:(AVCaptureSynchronizedDataCollection *)synchronizedDataCollection;
+ (NSMutableArray<CameraCaptureController*>*)getActiveColorAndDepthCameraControllers;
+ (void)addColorAndDepthCameraController:(CameraCaptureController*)controller;
+ (void)removeColorAndDepthCameraController:(CameraCaptureController*)controller;
+ (void)clearColorAndDepthCameraControllers;
+ (CameraCaptureController*)findColorAndDepthCameraController:(AVCaptureDevice*)device isDepth:(bool)isDepth;
#endif
- (void)capturePixelBufferToMemBuffer:(uint8_t*)dst;
- (int)isCVTextureFlipped;
+ (BOOL)focusPointSupported:(AVCaptureDevice*)captureDevice withFocusMode:(AVCaptureFocusMode)focusMode;
- (int)setFocusPointWithX:(float)x Y:(float)y;
- (int)setFocusPoint;
- (void)start;
- (void)pause;
- (void)stop;
@property (nonatomic, retain) AVCaptureDevice* captureDevice;
@property (nonatomic, retain) AVCaptureSession* captureSession;
@property (nonatomic, retain) AVCaptureDeviceInput* captureInput;
@property (nonatomic, retain) AVCaptureVideoDataOutput* captureOutput;
#if UNITY_HAS_COLORANDDEPTH_CAMERA
@property (nonatomic, retain) AVCaptureDepthDataOutput* captureDepthOutput;
@property (nonatomic, retain) AVCaptureDataOutputSynchronizer* captureSynchronizer;
#endif
- (float)pickAvailableFrameRate:(float)fps;
@end
enum WebCamKind
{
kWebCamWideAngle = 1,
kWebCamTelephoto = 2,
kWebCamColorAndDepth = 3,
};
@interface CameraCaptureDevice : NSObject
- (bool)isColorAndDepthCaptureDevice;
- (WebCamKind)getKind;
- (void)fillCaptureDeviceResolutions;
- (NSString*)pickPresetFromWidth:(int)w height:(int)h;
- (bool)initCaptureForController:(CameraCaptureController*)controller width:(int)w height:(int)h fps:(float)fps isDepth:(bool)isDepth;
+ (bool)initialized;
+ (void)createCameraCaptureDevicesArray;
+ (void)addCameraCaptureDevice:(AVCaptureDevice*)device;
@end
#pragma once
#include "UnityRendering.h"
#include "GlesHelper.h"
#include <UIKit/UIKit.h>
@class EAGLContext;
@class UnityView;
@interface DisplayConnection : NSObject
- (id)init:(UIScreen*)targetScreen;
- (void)dealloc;
- (void)createView:(BOOL)useForRendering showRightAway:(BOOL)showRightAway;
- (void)createView:(BOOL)useForRendering;
- (void)createWithWindow:(UIWindow*)window andView:(UIView*)view;
- (UnityDisplaySurfaceBase*)initRendering;
- (void)recreateSurface:(RenderingSurfaceParams)params;
- (void)destroySurface;
- (void)shouldShowWindow:(BOOL)show;
- (void)requestRenderingResolution:(CGSize)res;
- (void)present;
@property (readonly, copy, nonatomic) UIScreen* screen;
@property (readonly, copy, nonatomic) UIWindow* window;
@property (readonly, copy, nonatomic) UIView* view;
@property (readonly, nonatomic) CGSize screenSize;
@property (readonly, nonatomic) UnityDisplaySurfaceBase* surface;
@end
@interface DisplayManager : NSObject
- (id)objectForKeyedSubscript:(id)key;
- (BOOL)displayAvailable:(UIScreen*)targetScreen;
- (void)updateDisplayListCacheInUnity;
- (void)startFrameRendering;
- (void)present;
- (void)endFrameRendering;
- (void)enumerateDisplaysWithBlock:(void (^)(DisplayConnection* conn))block;
- (void)enumerateNonMainDisplaysWithBlock:(void (^)(DisplayConnection* conn))block;
+ (void)Initialize;
+ (DisplayManager*)Instance;
+ (void)Destroy;
@property (readonly, nonatomic) DisplayConnection* mainDisplay;
@property (readonly, nonatomic) NSUInteger displayCount;
@end
inline DisplayConnection* GetMainDisplay()
{
return [DisplayManager Instance].mainDisplay;
}
inline UnityDisplaySurfaceBase* GetMainDisplaySurface()
{
return GetMainDisplay().surface;
}
#pragma once
struct UnityDisplaySurfaceBase;
#ifdef __OBJC__
@class EAGLContext;
#else
typedef struct objc_object EAGLContext;
#endif
extern "C" bool AllocateRenderBufferStorageFromEAGLLayer(void* eaglContext, void* eaglLayer);
extern "C" void DeallocateRenderBufferStorageFromEAGLLayer(void* eaglContext);
extern "C" EAGLContext* UnityCreateContextEAGL(EAGLContext * parent, int api);
extern "C" void UnityMakeCurrentContextEAGL(EAGLContext* context);
extern "C" EAGLContext* UnityGetCurrentContextEAGL();
#if __OBJC__
class
EAGLContextSetCurrentAutoRestore
{
public:
EAGLContext* old;
EAGLContext* cur;
EAGLContextSetCurrentAutoRestore(EAGLContext* cur);
EAGLContextSetCurrentAutoRestore(UnityDisplaySurfaceBase* surface);
~EAGLContextSetCurrentAutoRestore();
};
#endif // __OBJC__
#include "EAGLContextHelper.h"
#include "UnityRendering.h"
#import <QuartzCore/QuartzCore.h>
#import <OpenGLES/EAGL.h>
#import <OpenGLES/ES2/gl.h>
#import <OpenGLES/ES2/glext.h>
extern "C" bool AllocateRenderBufferStorageFromEAGLLayer(void* eaglContext, void* eaglLayer)
{
return [(__bridge EAGLContext*)eaglContext renderbufferStorage: GL_RENDERBUFFER fromDrawable: (__bridge CAEAGLLayer*)eaglLayer];
}
extern "C" void DeallocateRenderBufferStorageFromEAGLLayer(void* eaglContext)
{
// After deprecating OpenGL ES, Apple implement gles driver in metal.
// Alas, it seem that on older iOS versions (< 13.0) there seems to be a bug in
// [EAGLContext renderbufferStorage: fromDrawable:nil]
// resulting in metal validation failure.
// Thankfully this code path is taken only to delete the backbuffer, so this is not that bad:
// we go there only on exit/going-to-background or unloading unity library
// If we look at the metal - all this would mean drawable recreation (and this happens inside gles driver)
// so memory-wise we should be still fine ignoring this completely
if (UnityiOS130orNewer())
[(__bridge EAGLContext*)eaglContext renderbufferStorage: GL_RENDERBUFFER fromDrawable: nil];
}
extern "C" EAGLContext* UnityCreateContextEAGL(EAGLContext * parent, int api)
{
const int targetApi = parent ? (int)parent.API : api;
EAGLSharegroup* group = parent ? parent.sharegroup : nil;
return [[EAGLContext alloc] initWithAPI: (EAGLRenderingAPI)targetApi sharegroup: group];
}
extern "C" void UnityMakeCurrentContextEAGL(EAGLContext* context)
{
[EAGLContext setCurrentContext: context];
}
extern "C" EAGLContext* UnityGetCurrentContextEAGL()
{
return [EAGLContext currentContext];
}
EAGLContextSetCurrentAutoRestore::EAGLContextSetCurrentAutoRestore(EAGLContext* cur_) : old([EAGLContext currentContext]), cur(cur_)
{
if (old != cur)
{
[EAGLContext setCurrentContext: cur];
UnityOnSetCurrentGLContext(cur);
}
}
EAGLContextSetCurrentAutoRestore::EAGLContextSetCurrentAutoRestore(UnityDisplaySurfaceBase* surface)
: old(surface->api == apiMetal ? nil : [EAGLContext currentContext]),
cur(surface->api == apiMetal ? nil : ((UnityDisplaySurfaceGLES*)surface)->context)
{
if (old != cur)
{
[EAGLContext setCurrentContext: cur];
UnityOnSetCurrentGLContext(cur);
}
}
EAGLContextSetCurrentAutoRestore::~EAGLContextSetCurrentAutoRestore()
{
if (old != cur)
{
[EAGLContext setCurrentContext: old];
if (old)
UnityOnSetCurrentGLContext(old);
}
}
#include <sys/xattr.h>
#include "UnityInterface.h"
#include <cstring>
static NSString* bundleIdWithData = nil;
extern "C" void UnitySetDataBundleDirWithBundleId(const char* bundleId)
{
if (bundleId) bundleIdWithData = [NSString stringWithUTF8String: bundleId];
else bundleIdWithData = nil;
}
extern "C" const char* UnityDataBundleDir()
{
static const char* dir = NULL;
if (dir == NULL)
{
if (bundleIdWithData == nil)
dir = AllocCString([[NSBundle mainBundle] bundlePath]);
else
dir = AllocCString([[NSBundle bundleWithIdentifier: bundleIdWithData] bundlePath]);
}
return dir;
}
#define RETURN_SPECIAL_DIR(dir) \
do { \
static const char* var = NULL; \
if (var == NULL) \
var = AllocCString(NSSearchPathForDirectoriesInDomains(dir, NSUserDomainMask, YES)[0]); \
return var; \
} while (0)
extern "C" const char* UnityDocumentsDir()
{
RETURN_SPECIAL_DIR(NSDocumentDirectory);
}
extern "C" const char* UnityLibraryDir()
{
RETURN_SPECIAL_DIR(NSLibraryDirectory);
}
extern "C" const char* UnityCachesDir()
{
RETURN_SPECIAL_DIR(NSCachesDirectory);
}
#undef RETURN_SPECIAL_DIR
extern "C" int UnityUpdateNoBackupFlag(const char* path, int setFlag)
{
int result;
if (setFlag)
{
u_int8_t b = 1;
result = ::setxattr(path, "com.apple.MobileBackup", &b, 1, 0, 0);
}
else
{
result = ::removexattr(path, "com.apple.MobileBackup", 0);
}
return result == 0 ? 1 : 0;
}
extern "C" const char* const* UnityFontFallbacks()
{
/* The following is the family names of fonts that are used as fallbacks
for characters that were not fount in user-specified fonts. Add more
fonts and/or reorder the list to fit your needs. For certain character
NOTE: Some similar Chinese, Japanese and Korean characters share the
character number in Unicode, but are written differently. To display
such characters properly, correct font must be selected. We reorder
the fonts list on the first run of this function.
*/
static const char** cachedFonts = NULL;
if (cachedFonts == NULL)
{
const int fontsToReorderCount = 4;
static const char* defaultFonts[] =
{
// first fontsToReorderCount items will be reordered if needed.
"Hiragino Kaku Gothic ProN", // Japanese characters
"Heiti TC", // Traditional Chinese characters (on 9.0 OS substitutes this with "PingFang TC")
"Heiti SC", // Simplified Chinese characters (on 9.0 OS substitutes this with "PingFang SC")
"Apple SD Gothic Neo", // Korean characters
".Sukhumvit Set UI", // Thai characters since 8.2 until 9.x
"AppleGothic",
"Noto Sans Yi", // Yi characters on 9.0 (not available on tvOS)
"Helvetica",
"Helvetica Neue",
"Arial Hebrew", // Hebrew since 9.0
"Kohinoor Devanagari", // Hindi since 9.0
"Kohinoor Bangla", // Bengali since 9.0
"Kohinoor Telugu", // Telugu since 9.0
"Lao Sangam MN", // Lao
"Geeza Pro", // Arabic
"Kailasa", // Tibetan since iOS 10.0
".PhoneFallback", // Armenian, Braille, Georgian, Thai, various symbols since iOS 10.0
// Note that iOS itself prefers Thonburi font for the Thai characters, but our font subsystem
// can't display combining characters for some reason
".LastResort",
NULL
};
// The default works for Japanese, we won't reorder in that case
static const char* koFontOrder[] =
{
"Apple SD Gothic Neo", // Korean characters
"Hiragino Kaku Gothic ProN", // Japanese characters
"Heiti TC", // Traditional Chinese characters (on 9.0 OS substitutes this with "PingFang TC")
"Heiti SC", // Simplified Chinese characters (on 9.0 OS substitutes this with "PingFang SC")
};
static const char* zhFontOrder[] =
{
"Heiti TC", // Traditional Chinese characters (on 9.0 OS substitutes this with "PingFang TC")
"Heiti SC", // Simplified Chinese characters (on 9.0 OS substitutes this with "PingFang SC")
"Hiragino Kaku Gothic ProN", // Japanese characters
"Apple SD Gothic Neo", // Korean characters
};
const char* lang = UnitySystemLanguage();
const char** fontOrderOverride = NULL;
if (std::strncmp(lang, "ko", 2) == 0)
fontOrderOverride = koFontOrder;
if (std::strncmp(lang, "zh", 2) == 0)
fontOrderOverride = zhFontOrder;
if (fontOrderOverride)
{
for (int i = 0; i < fontsToReorderCount; ++i)
defaultFonts[i] = fontOrderOverride[i];
}
cachedFonts = defaultFonts;
}
return cachedFonts;
}
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#import <AVKit/AVKit.h>
#import <UIKit/UIGestureRecognizerSubclass.h>
#include "UnityAppController.h"
#include "UI/UnityView.h"
#include "UI/UnityViewControllerBase.h"
#include "UI/OrientationSupport.h"
#include "UI/UnityAppController+ViewHandling.h"
#include "Unity/ObjCRuntime.h"
#include "Unity/VideoPlayer.h"
#include "PluginBase/UnityViewControllerListener.h"
@interface UICancelGestureRecognizer : UITapGestureRecognizer
@end
@interface AVKitVideoPlayback : NSObject<VideoPlayerDelegate, UIViewControllerTransitioningDelegate, UIGestureRecognizerDelegate>
{
AVPlayerViewController* videoViewController;
VideoPlayer* videoPlayer;
UIColor* bgColor;
const NSString* videoGravity;
BOOL showControls;
BOOL cancelOnTouch;
}
- (void)onPlayerReady;
- (void)onPlayerDidFinishPlayingVideo;
- (id)initAndPlay:(NSURL*)url bgColor:(UIColor*)color showControls:(BOOL)controls videoGravity:(const NSString*)scaling cancelOnTouch:(BOOL)cot;
- (void)actuallyStartTheMovie:(NSURL*)url;
- (void)finish;
@end
static AVKitVideoPlayback* _AVKitVideoPlayback = nil;
@implementation AVKitVideoPlayback
#if PLATFORM_IOS
static void AVPlayerViewController_SetAllowsPictureInPicturePlayback_OldIOSImpl(id self_, SEL _cmd, BOOL allow) {}
static NSUInteger supportedInterfaceOrientations_DefaultImpl(id self_, SEL _cmd)
{
return GetAppController().rootViewController.supportedInterfaceOrientations;
}
static bool prefersStatusBarHidden_DefaultImpl(id self_, SEL _cmd)
{
if (_AVKitVideoPlayback) // video is still playing
return _AVKitVideoPlayback->videoViewController.showsPlaybackControls ? NO : YES;
else // video has beed stopped
return GetAppController().rootViewController.prefersStatusBarHidden;
}
#endif
+ (void)initialize
{
if (self == [AVKitVideoPlayback class])
{
#if PLATFORM_IOS
class_replaceMethod([AVPlayerViewController class], @selector(supportedInterfaceOrientations), (IMP)&supportedInterfaceOrientations_DefaultImpl, UIViewController_supportedInterfaceOrientations_Enc);
class_replaceMethod([AVPlayerViewController class], @selector(prefersStatusBarHidden), (IMP)&prefersStatusBarHidden_DefaultImpl, UIViewController_prefersStatusBarHidden_Enc);
#endif
}
}
- (id)initAndPlay:(NSURL*)url bgColor:(UIColor*)color showControls:(BOOL)controls videoGravity:(const NSString*)scaling cancelOnTouch:(BOOL)cot
{
if ((self = [super init]))
{
UnityPause(1);
showControls = controls;
videoGravity = scaling;
bgColor = color;
cancelOnTouch = cot;
[self performSelector: @selector(actuallyStartTheMovie:) withObject: url afterDelay: 0];
}
return self;
}
- (void)dealloc
{
[self finish];
}
- (void)actuallyStartTheMovie:(NSURL*)url
{
@autoreleasepool
{
videoViewController = [[AVPlayerViewController alloc] init];
videoViewController.showsPlaybackControls = showControls;
videoViewController.view.backgroundColor = bgColor;
videoViewController.videoGravity = (NSString*)videoGravity;
videoViewController.transitioningDelegate = self;
#if PLATFORM_IOS
videoViewController.allowsPictureInPicturePlayback = NO;
#endif
#if PLATFORM_TVOS
// In tvOS clicking Menu button while video is playing will exit the app. So when
// app disables exiting to menu behavior, we need to catch the click and ignore it.
if (!UnityGetAppleTVRemoteAllowExitToMenu())
{
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(handleTap:)];
tapRecognizer.allowedPressTypes = @[@(UIPressTypeMenu)];
[videoViewController.view addGestureRecognizer: tapRecognizer];
}
#endif
if (cancelOnTouch)
{
UICancelGestureRecognizer *cancelTouch = [[UICancelGestureRecognizer alloc] initWithTarget: self action: @selector(handleTap:)];
cancelTouch.delegate = self;
[videoViewController.view addGestureRecognizer: cancelTouch];
}
videoPlayer = [[VideoPlayer alloc] init];
videoPlayer.delegate = self;
[videoPlayer loadVideo: url];
}
}
- (void)handleTap:(UITapGestureRecognizer*)sender
{
if (cancelOnTouch && (sender.state == UIGestureRecognizerStateEnded))
[self finish];
}
- (void)onPlayerReady
{
videoViewController.player = videoPlayer.player;
CGSize screenSize = GetAppController().rootView.bounds.size;
BOOL ret = [VideoPlayer CheckScalingModeAspectFill: videoPlayer.videoSize screenSize: screenSize];
if (ret == YES && [videoViewController.videoGravity isEqualToString: AVLayerVideoGravityResizeAspect] == YES)
{
videoViewController.videoGravity = AVLayerVideoGravityResizeAspectFill;
}
[videoPlayer playVideoPlayer];
#if PLATFORM_TVOS
GetAppController().window.rootViewController = videoViewController;
#else
UIViewController *viewController = [GetAppController() topMostController];
if ([viewController isEqual: videoViewController] == NO && [videoViewController isBeingPresented] == NO)
[viewController presentViewController: videoViewController animated: NO completion: nil];
#endif
}
- (void)onPlayerDidFinishPlayingVideo
{
[self finish];
}
- (void)onPlayerTryResume
{
if (![videoPlayer isPlaying])
[videoPlayer resume];
}
- (void)onPlayerError:(NSError*)error
{
[self finish];
}
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed
{
if ([dismissed isEqual: videoViewController] == YES)
{
[self finish];
}
return nil;
}
- (void)finish
{
@synchronized(self)
{
#if PLATFORM_TVOS
GetAppController().window.rootViewController = GetAppController().rootViewController;
#else
UIViewController *viewController = [GetAppController() topMostController];
if ([viewController isEqual: videoViewController] == YES && [viewController isBeingDismissed] == NO)
[viewController dismissViewControllerAnimated: NO completion: nil];
#endif
[videoPlayer unloadPlayer];
videoPlayer = nil;
videoViewController = nil;
_AVKitVideoPlayback = nil;
#if PLATFORM_TVOS
UnityCancelTouches();
#endif
if (UnityIsPaused())
UnityPause(0);
}
}
@end
@implementation UICancelGestureRecognizer
//instead of having lots of UITapGestureRecognizers with different finger numbers
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
[self setState: UIGestureRecognizerStateRecognized];
}
@end
extern "C" void UnityPlayFullScreenVideo(const char* path, const float* color, unsigned controls, unsigned scaling)
{
const BOOL cancelOnTouch[] = { NO, NO, YES, NO };
UIColor* bgColor = [UIColor colorWithRed: color[0] green: color[1] blue: color[2] alpha: color[3]];
const bool isURL = ::strstr(path, "://") != 0;
NSURL* url = nil;
if (isURL)
{
url = [NSURL URLWithString: [NSString stringWithUTF8String: path]];
}
else
{
NSString* relPath = path[0] == '/' ? [NSString stringWithUTF8String: path] : [NSString stringWithFormat: @"Data/Raw/%s", path];
NSString* fullPath = [[NSString stringWithUTF8String: UnityDataBundleDir()] stringByAppendingPathComponent: relPath];
url = [NSURL fileURLWithPath: fullPath];
}
const BOOL showControls[] = { YES, YES, NO, NO };
const NSString* videoGravity[] =
{
AVLayerVideoGravityResizeAspectFill, // ???
AVLayerVideoGravityResizeAspect,
AVLayerVideoGravityResizeAspectFill,
AVLayerVideoGravityResize,
};
if (_AVKitVideoPlayback)
[_AVKitVideoPlayback finish];
_AVKitVideoPlayback = [[AVKitVideoPlayback alloc] initAndPlay: url bgColor: bgColor
showControls: showControls[controls] videoGravity: videoGravity[scaling] cancelOnTouch: cancelOnTouch[controls]];
}
extern "C" void UnityStopFullScreenVideoIfPlaying()
{
if (_AVKitVideoPlayback)
[_AVKitVideoPlayback finish];
}
extern "C" int UnityIsFullScreenPlaying()
{
return _AVKitVideoPlayback ? 1 : 0;
}
extern "C" void TryResumeFullScreenVideo()
{
if (_AVKitVideoPlayback)
[_AVKitVideoPlayback onPlayerTryResume];
}
#pragma once
#ifdef __OBJC__
@class CAEAGLLayer;
@class EAGLContext;
#else
typedef struct objc_object CAEAGLLayer;
typedef struct objc_object EAGLContext;
#endif
#define MSAA_DEFAULT_SAMPLE_COUNT 1
// in case of rendering to non-native resolution the texture filter we will use for upscale blit
#define GLES_UPSCALE_FILTER GL_LINEAR
//#define GLES_UPSCALE_FILTER GL_NEAREST
// if gles support MSAA. We will need to recreate unity view if AA samples count was changed
extern bool _supportsMSAA;
#ifdef __cplusplus
extern "C" {
#endif
void CheckGLESError(const char* file, int line);
#ifdef __cplusplus
} // extern "C"
#endif
// Unity Native Plugin API copyright © 2015 Unity Technologies ApS
//
// Licensed under the Unity Companion License for Unity - dependent projects--see[Unity Companion License](http://www.unity3d.com/legal/licenses/Unity_Companion_License).
//
// Unless expressly provided otherwise, the Software under this license is made available strictly on an “AS IS” BASIS WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED.Please review the license for details on these and other terms and conditions.
#pragma once
#include "IUnityInterface.h"
// Has to match the GfxDeviceRenderer enum
typedef enum UnityGfxRenderer
{
//kUnityGfxRendererOpenGL = 0, // Legacy OpenGL, removed
//kUnityGfxRendererD3D9 = 1, // Direct3D 9, removed
kUnityGfxRendererD3D11 = 2, // Direct3D 11
kUnityGfxRendererNull = 4, // "null" device (used in batch mode)
kUnityGfxRendererOpenGLES20 = 8, // OpenGL ES 2.0
kUnityGfxRendererOpenGLES30 = 11, // OpenGL ES 3.0
//kUnityGfxRendererGXM = 12, // PlayStation Vita, removed
kUnityGfxRendererPS4 = 13, // PlayStation 4
kUnityGfxRendererXboxOne = 14, // Xbox One
kUnityGfxRendererMetal = 16, // iOS Metal
kUnityGfxRendererOpenGLCore = 17, // OpenGL core
kUnityGfxRendererD3D12 = 18, // Direct3D 12
kUnityGfxRendererVulkan = 21, // Vulkan
kUnityGfxRendererNvn = 22, // Nintendo Switch NVN API
kUnityGfxRendererXboxOneD3D12 = 23, // MS XboxOne Direct3D 12
kUnityGfxRendererGameCoreXboxOne = 24, // GameCore Xbox One
kUnityGfxRendererGameCoreXboxSeries = 25, // GameCore Xbox Series
kUnityGfxRendererPS5 = 26 // PS5
} UnityGfxRenderer;
typedef enum UnityGfxDeviceEventType
{
kUnityGfxDeviceEventInitialize = 0,
kUnityGfxDeviceEventShutdown = 1,
kUnityGfxDeviceEventBeforeReset = 2,
kUnityGfxDeviceEventAfterReset = 3,
} UnityGfxDeviceEventType;
typedef void (UNITY_INTERFACE_API * IUnityGraphicsDeviceEventCallback)(UnityGfxDeviceEventType eventType);
// Should only be used on the rendering thread unless noted otherwise.
UNITY_DECLARE_INTERFACE(IUnityGraphics)
{
UnityGfxRenderer(UNITY_INTERFACE_API * GetRenderer)(); // Thread safe
// This callback will be called when graphics device is created, destroyed, reset, etc.
// It is possible to miss the kUnityGfxDeviceEventInitialize event in case plugin is loaded at a later time,
// when the graphics device is already created.
void(UNITY_INTERFACE_API * RegisterDeviceEventCallback)(IUnityGraphicsDeviceEventCallback callback);
void(UNITY_INTERFACE_API * UnregisterDeviceEventCallback)(IUnityGraphicsDeviceEventCallback callback);
int(UNITY_INTERFACE_API * ReserveEventIDRange)(int count); // reserves 'count' event IDs. Plugins should use the result as a base index when issuing events back and forth to avoid event id clashes.
};
UNITY_REGISTER_INTERFACE_GUID(0x7CBA0A9CA4DDB544ULL, 0x8C5AD4926EB17B11ULL, IUnityGraphics)
// Certain Unity APIs (GL.IssuePluginEvent, CommandBuffer.IssuePluginEvent) can callback into native plugins.
// Provide them with an address to a function of this signature.
typedef void (UNITY_INTERFACE_API * UnityRenderingEvent)(int eventId);
typedef void (UNITY_INTERFACE_API * UnityRenderingEventAndData)(int eventId, void* data);
// Unity Native Plugin API copyright © 2015 Unity Technologies ApS
//
// Licensed under the Unity Companion License for Unity - dependent projects--see[Unity Companion License](http://www.unity3d.com/legal/licenses/Unity_Companion_License).
//
// Unless expressly provided otherwise, the Software under this license is made available strictly on an “AS IS” BASIS WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED.Please review the license for details on these and other terms and conditions.
#pragma once
#include "IUnityInterface.h"
#ifndef __OBJC__
#error metal plugin is objc code.
#endif
#ifndef __clang__
#error only clang compiler is supported.
#endif
@class NSBundle;
@protocol MTLDevice;
@protocol MTLCommandBuffer;
@protocol MTLCommandEncoder;
@protocol MTLTexture;
@class MTLRenderPassDescriptor;
UNITY_DECLARE_INTERFACE(IUnityGraphicsMetalV1)
{
NSBundle* (UNITY_INTERFACE_API * MetalBundle)();
id<MTLDevice>(UNITY_INTERFACE_API * MetalDevice)();
id<MTLCommandBuffer>(UNITY_INTERFACE_API * CurrentCommandBuffer)();
// for custom rendering support there are two scenarios:
// you want to use current in-flight MTLCommandEncoder (NB: it might be nil)
id<MTLCommandEncoder>(UNITY_INTERFACE_API * CurrentCommandEncoder)();
// or you might want to create your own encoder.
// In that case you should end unity's encoder before creating your own and end yours before returning control to unity
void(UNITY_INTERFACE_API * EndCurrentCommandEncoder)();
// returns MTLRenderPassDescriptor used to create current MTLCommandEncoder
MTLRenderPassDescriptor* (UNITY_INTERFACE_API * CurrentRenderPassDescriptor)();
// converting trampoline UnityRenderBufferHandle into native RenderBuffer
UnityRenderBuffer(UNITY_INTERFACE_API * RenderBufferFromHandle)(void* bufferHandle);
// access to RenderBuffer's texure
// NB: you pass here *native* RenderBuffer, acquired by calling (C#) RenderBuffer.GetNativeRenderBufferPtr
// AAResolvedTextureFromRenderBuffer will return nil in case of non-AA RenderBuffer or if called for depth RenderBuffer
// StencilTextureFromRenderBuffer will return nil in case of no-stencil RenderBuffer or if called for color RenderBuffer
id<MTLTexture>(UNITY_INTERFACE_API * TextureFromRenderBuffer)(UnityRenderBuffer buffer);
id<MTLTexture>(UNITY_INTERFACE_API * AAResolvedTextureFromRenderBuffer)(UnityRenderBuffer buffer);
id<MTLTexture>(UNITY_INTERFACE_API * StencilTextureFromRenderBuffer)(UnityRenderBuffer buffer);
};
UNITY_REGISTER_INTERFACE_GUID(0x29F8F3D03833465EULL, 0x92138551C15D823DULL, IUnityGraphicsMetalV1)
// deprecated: please use versioned interface above
UNITY_DECLARE_INTERFACE(IUnityGraphicsMetal)
{
NSBundle* (UNITY_INTERFACE_API * MetalBundle)();
id<MTLDevice>(UNITY_INTERFACE_API * MetalDevice)();
id<MTLCommandBuffer>(UNITY_INTERFACE_API * CurrentCommandBuffer)();
id<MTLCommandEncoder>(UNITY_INTERFACE_API * CurrentCommandEncoder)();
void(UNITY_INTERFACE_API * EndCurrentCommandEncoder)();
MTLRenderPassDescriptor* (UNITY_INTERFACE_API * CurrentRenderPassDescriptor)();
UnityRenderBuffer(UNITY_INTERFACE_API * RenderBufferFromHandle)(void* bufferHandle);
id<MTLTexture>(UNITY_INTERFACE_API * TextureFromRenderBuffer)(UnityRenderBuffer buffer);
id<MTLTexture>(UNITY_INTERFACE_API * AAResolvedTextureFromRenderBuffer)(UnityRenderBuffer buffer);
id<MTLTexture>(UNITY_INTERFACE_API * StencilTextureFromRenderBuffer)(UnityRenderBuffer buffer);
};
UNITY_REGISTER_INTERFACE_GUID(0x992C8EAEA95811E5ULL, 0x9A62C4B5B9876117ULL, IUnityGraphicsMetal)
// Unity Native Plugin API copyright © 2015 Unity Technologies ApS
//
// Licensed under the Unity Companion License for Unity - dependent projects--see[Unity Companion License](http://www.unity3d.com/legal/licenses/Unity_Companion_License).
//
// Unless expressly provided otherwise, the Software under this license is made available strictly on an “AS IS” BASIS WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED.Please review the license for details on these and other terms and conditions.
#pragma once
// Unity native plugin API
// Compatible with C99
#if defined(__CYGWIN32__)
#define UNITY_INTERFACE_API __stdcall
#define UNITY_INTERFACE_EXPORT __declspec(dllexport)
#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(_WIN64) || defined(WINAPI_FAMILY)
#define UNITY_INTERFACE_API __stdcall
#define UNITY_INTERFACE_EXPORT __declspec(dllexport)
#elif defined(__MACH__) || defined(__ANDROID__) || defined(__linux__) || defined(LUMIN)
#define UNITY_INTERFACE_API
#define UNITY_INTERFACE_EXPORT __attribute__ ((visibility ("default")))
#else
#define UNITY_INTERFACE_API
#define UNITY_INTERFACE_EXPORT
#endif
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// IUnityInterface is a registry of interfaces we choose to expose to plugins.
//
// USAGE:
// ---------
// To retrieve an interface a user can do the following from a plugin, assuming they have the header file for the interface:
//
// IMyInterface * ptr = registry->Get<IMyInterface>();
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Unity Interface GUID
// Ensures global uniqueness.
//
// Template specialization is used to produce a means of looking up a GUID from its interface type at compile time.
// The net result should compile down to passing around the GUID.
//
// UNITY_REGISTER_INTERFACE_GUID should be placed in the header file of any interface definition outside of all namespaces.
// The interface structure and the registration GUID are all that is required to expose the interface to other systems.
struct UnityInterfaceGUID
{
#ifdef __cplusplus
UnityInterfaceGUID(unsigned long long high, unsigned long long low)
: m_GUIDHigh(high)
, m_GUIDLow(low)
{
}
UnityInterfaceGUID(const UnityInterfaceGUID& other)
{
m_GUIDHigh = other.m_GUIDHigh;
m_GUIDLow = other.m_GUIDLow;
}
UnityInterfaceGUID& operator=(const UnityInterfaceGUID& other)
{
m_GUIDHigh = other.m_GUIDHigh;
m_GUIDLow = other.m_GUIDLow;
return *this;
}
bool Equals(const UnityInterfaceGUID& other) const { return m_GUIDHigh == other.m_GUIDHigh && m_GUIDLow == other.m_GUIDLow; }
bool LessThan(const UnityInterfaceGUID& other) const { return m_GUIDHigh < other.m_GUIDHigh || (m_GUIDHigh == other.m_GUIDHigh && m_GUIDLow < other.m_GUIDLow); }
#endif
unsigned long long m_GUIDHigh;
unsigned long long m_GUIDLow;
};
#ifdef __cplusplus
inline bool operator==(const UnityInterfaceGUID& left, const UnityInterfaceGUID& right) { return left.Equals(right); }
inline bool operator!=(const UnityInterfaceGUID& left, const UnityInterfaceGUID& right) { return !left.Equals(right); }
inline bool operator<(const UnityInterfaceGUID& left, const UnityInterfaceGUID& right) { return left.LessThan(right); }
inline bool operator>(const UnityInterfaceGUID& left, const UnityInterfaceGUID& right) { return right.LessThan(left); }
inline bool operator>=(const UnityInterfaceGUID& left, const UnityInterfaceGUID& right) { return !operator<(left, right); }
inline bool operator<=(const UnityInterfaceGUID& left, const UnityInterfaceGUID& right) { return !operator>(left, right); }
#else
typedef struct UnityInterfaceGUID UnityInterfaceGUID;
#endif
#ifdef __cplusplus
#define UNITY_DECLARE_INTERFACE(NAME) \
struct NAME : IUnityInterface
// Generic version of GetUnityInterfaceGUID to allow us to specialize it
// per interface below. The generic version has no actual implementation
// on purpose.
//
// If you get errors about return values related to this method then
// you have forgotten to include UNITY_REGISTER_INTERFACE_GUID with
// your interface, or it is not visible at some point when you are
// trying to retrieve or add an interface.
template<typename TYPE>
inline const UnityInterfaceGUID GetUnityInterfaceGUID();
// This is the macro you provide in your public interface header
// outside of a namespace to allow us to map between type and GUID
// without the user having to worry about it when attempting to
// add or retrieve and interface from the registry.
#define UNITY_REGISTER_INTERFACE_GUID(HASHH, HASHL, TYPE) \
template<> \
inline const UnityInterfaceGUID GetUnityInterfaceGUID<TYPE>() \
{ \
return UnityInterfaceGUID(HASHH,HASHL); \
}
// Same as UNITY_REGISTER_INTERFACE_GUID but allows the interface to live in
// a particular namespace. As long as the namespace is visible at the time you call
// GetUnityInterfaceGUID< INTERFACETYPE >() or you explicitly qualify it in the template
// calls this will work fine, only the macro here needs to have the additional parameter
#define UNITY_REGISTER_INTERFACE_GUID_IN_NAMESPACE(HASHH, HASHL, TYPE, NAMESPACE) \
const UnityInterfaceGUID TYPE##_GUID(HASHH, HASHL); \
template<> \
inline const UnityInterfaceGUID GetUnityInterfaceGUID< NAMESPACE :: TYPE >() \
{ \
return UnityInterfaceGUID(HASHH,HASHL); \
}
// These macros allow for C compatibility in user code.
#define UNITY_GET_INTERFACE_GUID(TYPE) GetUnityInterfaceGUID< TYPE >()
#else
#define UNITY_DECLARE_INTERFACE(NAME) \
typedef struct NAME NAME; \
struct NAME
// NOTE: This has the downside that one some compilers it will not get stripped from all compilation units that
// can see a header containing this constant. However, it's only for C compatibility and thus should have
// minimal impact.
#define UNITY_REGISTER_INTERFACE_GUID(HASHH, HASHL, TYPE) \
const UnityInterfaceGUID TYPE##_GUID = {HASHH, HASHL};
// In general namespaces are going to be a problem for C code any interfaces we expose in a namespace are
// not going to be usable from C.
#define UNITY_REGISTER_INTERFACE_GUID_IN_NAMESPACE(HASHH, HASHL, TYPE, NAMESPACE)
// These macros allow for C compatibility in user code.
#define UNITY_GET_INTERFACE_GUID(TYPE) TYPE##_GUID
#endif
// Using this in user code rather than INTERFACES->Get<TYPE>() will be C compatible for those places in plugins where
// this may be needed. Unity code itself does not need this.
#define UNITY_GET_INTERFACE(INTERFACES, TYPE) (TYPE*)INTERFACES->GetInterfaceSplit (UNITY_GET_INTERFACE_GUID(TYPE).m_GUIDHigh, UNITY_GET_INTERFACE_GUID(TYPE).m_GUIDLow);
#ifdef __cplusplus
struct IUnityInterface
{
};
#else
typedef void IUnityInterface;
#endif
typedef struct IUnityInterfaces
{
// Returns an interface matching the guid.
// Returns nullptr if the given interface is unavailable in the active Unity runtime.
IUnityInterface* (UNITY_INTERFACE_API * GetInterface)(UnityInterfaceGUID guid);
// Registers a new interface.
void(UNITY_INTERFACE_API * RegisterInterface)(UnityInterfaceGUID guid, IUnityInterface * ptr);
// Split APIs for C
IUnityInterface* (UNITY_INTERFACE_API * GetInterfaceSplit)(unsigned long long guidHigh, unsigned long long guidLow);
void(UNITY_INTERFACE_API * RegisterInterfaceSplit)(unsigned long long guidHigh, unsigned long long guidLow, IUnityInterface * ptr);
#ifdef __cplusplus
// Helper for GetInterface.
template<typename INTERFACE>
INTERFACE* Get()
{
return static_cast<INTERFACE*>(GetInterface(GetUnityInterfaceGUID<INTERFACE>()));
}
// Helper for RegisterInterface.
template<typename INTERFACE>
void Register(IUnityInterface* ptr)
{
RegisterInterface(GetUnityInterfaceGUID<INTERFACE>(), ptr);
}
#endif
} IUnityInterfaces;
#ifdef __cplusplus
extern "C" {
#endif
// If exported by a plugin, this function will be called when the plugin is loaded.
void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API UnityPluginLoad(IUnityInterfaces* unityInterfaces);
// If exported by a plugin, this function will be called when the plugin is about to be unloaded.
void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API UnityPluginUnload();
#ifdef __cplusplus
}
#endif
struct RenderSurfaceBase;
typedef struct RenderSurfaceBase* UnityRenderBuffer;
typedef unsigned int UnityTextureID;
#pragma once
#define ENABLE_INTERNAL_PROFILER 0
// 4.x ENABLE_BLOCK_ON_GPU_PROFILER and 5.x ENABLE_GPU_TIMING were removed in favor of using xcode tools
// INCLUDE_OPENGLES_IN_RENDER_TIME was removed
#if ENABLE_INTERNAL_PROFILER
void Profiler_InitProfiler();
void Profiler_UninitProfiler();
void Profiler_FrameStart();
void Profiler_FrameEnd();
void Profiler_FramePresent(const UnityFrameStats*);
void Profiler_StartMSAAResolve();
void Profiler_EndMSAAResolve();
#else
inline void Profiler_InitProfiler() {}
inline void Profiler_UninitProfiler() {}
inline void Profiler_FrameStart() {}
inline void Profiler_FrameEnd() {}
inline void Profiler_FramePresent(const struct UnityFrameStats*) {}
inline void Profiler_StartMSAAResolve() {}
inline void Profiler_EndMSAAResolve() {}
#endif // ENABLE_INTERNAL_PROFILER
#pragma once
#include <objc/objc.h>
#include <objc/runtime.h>
#include <objc/message.h>
// simulator and device differ in how they want objc_msgSendXXX to be called:
// device wants objc_msgSendXXX to be casted to proper type (same as selector we want to call)
// while simulator wants to call them directly
#if TARGET_IPHONE_SIMULATOR || TARGET_TVOS_SIMULATOR
#define UNITY_OBJC_SEND_MSG(selectorType, msgSendFunc) msgSendFunc
#else
#define UNITY_OBJC_SEND_MSG(selectorType, msgSendFunc) ((selectorType)msgSendFunc)
#endif
#define UNITY_OBJC_FORWARD_TO_SUPER(self_, super_, selector, selectorType, ...) \
do { \
struct objc_super super = { .receiver = self_, .super_class = super_ }; \
UNITY_OBJC_SEND_MSG(selectorType, objc_msgSendSuper)(&super, selector, __VA_ARGS__); \
} while(0)
#define UNITY_OBJC_CALL_ON_SELF(self_, selector, selectorType, ...) \
do { \
UNITY_OBJC_SEND_MSG(selectorType, objc_msgSend)(self_, selector, __VA_ARGS__); \
} while(0)
// method type encoding for methods we override
// to get this you need to do: method_getTypeEncoding(class_getInstanceMethod(class, sel)) or method_getTypeEncoding(class_getClassMethod(class, sel))
#define UIView_LayerClass_Enc "#8@0:4"
#define UIViewController_supportedInterfaceOrientations_Enc "Q16@0:8"
#define UIViewController_prefersStatusBarHidden_Enc "B16@0:8"
#define UIScreen_maximumFramesPerSecond_Enc "q16@0:8"
#define UIView_safeAreaInsets_Enc "{UIEdgeInsets=dddd}16@0:8"
#import "Foundation/Foundation.h"
#if ENABLE_IOS_ON_DEMAND_RESOURCES
#import "Foundation/NSBundle.h"
#endif
typedef void (*OnDemandResourcesRequestCompleteHandler)(void* handlerData, const char* error);
#if ENABLE_IOS_ON_DEMAND_RESOURCES
struct OnDemandResourcesRequestData
{
NSBundleResourceRequest* request;
};
extern "C" OnDemandResourcesRequestData* UnityOnDemandResourcesCreateRequest(NSSet * tags, OnDemandResourcesRequestCompleteHandler handler, void* handlerData)
{
OnDemandResourcesRequestData* data = new OnDemandResourcesRequestData();
data->request = [[NSBundleResourceRequest alloc] initWithTags: tags];
[data->request beginAccessingResourcesWithCompletionHandler:^(NSError* error) {
dispatch_async(dispatch_get_main_queue(), ^{
const char* errorMessage = error ? [[error localizedDescription] UTF8String] : NULL;
handler(handlerData, errorMessage);
});
}];
return data;
}
extern "C" void UnityOnDemandResourcesRelease(OnDemandResourcesRequestData* data)
{
[data->request endAccessingResources];
delete data;
}
extern "C" float UnityOnDemandResourcesGetProgress(OnDemandResourcesRequestData* data)
{
return data->request.progress.fractionCompleted;
}
extern "C" float UnityOnDemandResourcesGetLoadingPriority(OnDemandResourcesRequestData* data)
{
float priority = (float)data->request.loadingPriority;
return priority;
}
extern "C" void UnityOnDemandResourcesSetLoadingPriority(OnDemandResourcesRequestData* data, float priority)
{
if (priority < 0.0f)
priority = 0.0f;
if (priority > 1.0f)
data->request.loadingPriority = NSBundleResourceRequestLoadingPriorityUrgent;
else
data->request.loadingPriority = (double)priority;
}
extern "C" NSString* UnityOnDemandResourcesGetResourcePath(OnDemandResourcesRequestData * data, const char* resource)
{
NSString* path = [[data->request bundle] pathForResource: [NSString stringWithUTF8String: resource] ofType: nil];
return path;
}
#else // ENABLE_IOS_ON_DEMAND_RESOURCES
struct OnDemandResourcesRequestData
{
};
extern "C" OnDemandResourcesRequestData* UnityOnDemandResourcesCreateRequest(NSSet * tags, OnDemandResourcesRequestCompleteHandler handler, void* handlerData)
{
OnDemandResourcesRequestData* data = new OnDemandResourcesRequestData();
if (handler)
handler(handlerData, NULL);
return data;
}
extern "C" void UnityOnDemandResourcesRelease(OnDemandResourcesRequestData* data)
{
delete data;
}
extern "C" float UnityOnDemandResourcesGetProgress(OnDemandResourcesRequestData* data)
{
return 1.0f;
}
extern "C" float UnityOnDemandResourcesGetLoadingPriority(OnDemandResourcesRequestData* data)
{
return 0.5;
}
extern "C" void UnityOnDemandResourcesSetLoadingPriority(OnDemandResourcesRequestData* data, float priority)
{
}
extern "C" NSString* UnityOnDemandResourcesGetResourcePath(OnDemandResourcesRequestData * data, const char* resource)
{
return [NSString stringWithUTF8String: resource];
}
#endif // ENABLE_IOS_ON_DEMAND_RESOURCES
支持 Markdown 格式
你添加了 0 到此讨论。请谨慎行事。
Finish editing this message first!