docs/README-ios.md
author Sam Lantinga <slouken@libsdl.org>
Mon, 29 Oct 2018 19:58:59 -0700
changeset 12371 41b93d8303d6
parent 12368 9bb50edccc46
permissions -rw-r--r--
Backed out changeset 9bb50edccc46, SDL_JOYSTICK_HIDAPI is only used on iOS for Steam Controller support, which is not publicly available.
slime73@9810
     1
iOS
slime73@9810
     2
======
slime73@9810
     3
gabomdq@9023
     4
==============================================================================
slime73@9810
     5
Building the Simple DirectMedia Layer for iOS 5.1+
gabomdq@9023
     6
==============================================================================
gabomdq@9023
     7
slime73@9810
     8
Requirements: Mac OS X 10.8 or later and the iOS 7+ SDK.
gabomdq@9023
     9
slouken@11400
    10
Instructions:
slouken@11400
    11
slouken@11548
    12
1.  Open SDL.xcodeproj (located in Xcode-iOS/SDL) in Xcode.
slouken@11548
    13
2.  Select your desired target, and hit build.
gabomdq@9023
    14
gabomdq@9023
    15
There are three build targets:
gabomdq@9023
    16
- libSDL.a:
gabomdq@9023
    17
	Build SDL as a statically linked library
philipp@9066
    18
- testsdl:
gabomdq@9023
    19
	Build a test program (there are known test failures which are fine)
gabomdq@9023
    20
- Template:
gabomdq@9023
    21
	Package a project template together with the SDL for iPhone static libraries and copies of the SDL headers.  The template includes proper references to the SDL library and headers, skeleton code for a basic SDL program, and placeholder graphics for the application icon and startup screen.
gabomdq@9023
    22
philipp@9066
    23
gabomdq@9023
    24
==============================================================================
gabomdq@9023
    25
Build SDL for iOS from the command line
gabomdq@9023
    26
==============================================================================
gabomdq@9023
    27
slouken@11548
    28
1. cd (PATH WHERE THE SDL CODE IS)/build-scripts
slouken@11548
    29
2. ./iosbuild.sh
gabomdq@9023
    30
gabomdq@9023
    31
If everything goes fine, you should see a build/ios directory, inside there's
gabomdq@9023
    32
two directories "lib" and "include". 
gabomdq@9023
    33
"include" contains a copy of the SDL headers that you'll need for your project,
gabomdq@9023
    34
make sure to configure XCode to look for headers there.
gabomdq@9023
    35
"lib" contains find two files, libSDL2.a and libSDL2main.a, you have to add both 
gabomdq@9023
    36
to your XCode project. These libraries contain three architectures in them,
gabomdq@9023
    37
armv6 for legacy devices, armv7, and i386 (for the simulator).
gabomdq@9023
    38
By default, iosbuild.sh will autodetect the SDK version you have installed using 
gabomdq@9023
    39
xcodebuild -showsdks, and build for iOS >= 3.0, you can override this behaviour 
gabomdq@9023
    40
by setting the MIN_OS_VERSION variable, ie:
gabomdq@9023
    41
gabomdq@9023
    42
MIN_OS_VERSION=4.2 ./iosbuild.sh
gabomdq@9023
    43
gabomdq@9023
    44
==============================================================================
gabomdq@9023
    45
Using the Simple DirectMedia Layer for iOS
gabomdq@9023
    46
==============================================================================
gabomdq@9023
    47
gabomdq@9023
    48
FIXME: This needs to be updated for the latest methods
gabomdq@9023
    49
gabomdq@9023
    50
Here is the easiest method:
slime73@9995
    51
1.  Build the SDL library (libSDL2.a) and the iPhone SDL Application template.
slime73@9995
    52
2.  Install the iPhone SDL Application template by copying it to one of Xcode's template directories.  I recommend creating a directory called "SDL" in "/Developer/Platforms/iOS.platform/Developer/Library/Xcode/Project Templates/" and placing it there.
philipp@9064
    53
3.  Start a new project using the template.  The project should be immediately ready for use with SDL.
gabomdq@9023
    54
gabomdq@9023
    55
Here is a more manual method:
slime73@9995
    56
1.  Create a new iOS view based application.
slime73@9995
    57
2.  Build the SDL static library (libSDL2.a) for iOS and include them in your project.  Xcode will ignore the library that is not currently of the correct architecture, hence your app will work both on iOS and in the iOS Simulator.
gabomdq@9023
    58
3.  Include the SDL header files in your project.
slime73@9995
    59
4.  Remove the ApplicationDelegate.h and ApplicationDelegate.m files -- SDL for iOS provides its own UIApplicationDelegate.  Remove MainWindow.xib -- SDL for iOS produces its user interface programmatically.
slime73@9995
    60
5.  Delete the contents of main.m and program your app as a regular SDL program instead.  You may replace main.m with your own main.c, but you must tell Xcode not to use the project prefix file, as it includes Objective-C code.
gabomdq@9023
    61
slime73@9995
    62
==============================================================================
slime73@9995
    63
Notes -- Retina / High-DPI and window sizes
slime73@9995
    64
==============================================================================
slime73@9995
    65
slime73@9995
    66
Window and display mode sizes in SDL are in "screen coordinates" (or "points",
slime73@9995
    67
in Apple's terminology) rather than in pixels. On iOS this means that a window
philipp@9997
    68
created on an iPhone 6 will have a size in screen coordinates of 375 x 667,
slime73@9995
    69
rather than a size in pixels of 750 x 1334. All iOS apps are expected to
slime73@9995
    70
size their content based on screen coordinates / points rather than pixels,
slime73@9995
    71
as this allows different iOS devices to have different pixel densities
slime73@9995
    72
(Retina versus non-Retina screens, etc.) without apps caring too much.
slime73@9995
    73
slime73@9995
    74
By default SDL will not use the full pixel density of the screen on
slime73@9995
    75
Retina/high-dpi capable devices. Use the SDL_WINDOW_ALLOW_HIGHDPI flag when
slime73@9995
    76
creating your window to enable high-dpi support.
slime73@9995
    77
philipp@10167
    78
When high-dpi support is enabled, SDL_GetWindowSize() and display mode sizes
slime73@9995
    79
will still be in "screen coordinates" rather than pixels, but the window will
slime73@9995
    80
have a much greater pixel density when the device supports it, and the
philipp@10167
    81
SDL_GL_GetDrawableSize() or SDL_GetRendererOutputSize() functions (depending on
slime73@9995
    82
whether raw OpenGL or the SDL_Render API is used) can be queried to determine
slime73@9995
    83
the size in pixels of the drawable screen framebuffer.
slime73@9995
    84
slime73@9995
    85
Some OpenGL ES functions such as glViewport expect sizes in pixels rather than
slime73@9995
    86
sizes in screen coordinates. When doing 2D rendering with OpenGL ES, an
slime73@9995
    87
orthographic projection matrix using the size in screen coordinates
philipp@10167
    88
(SDL_GetWindowSize()) can be used in order to display content at the same scale
slime73@9995
    89
no matter whether a Retina device is used or not.
philipp@9066
    90
gabomdq@9023
    91
==============================================================================
gabomdq@9023
    92
Notes -- Application events
gabomdq@9023
    93
==============================================================================
gabomdq@9023
    94
gabomdq@9023
    95
On iOS the application goes through a fixed life cycle and you will get
gabomdq@9023
    96
notifications of state changes via application events. When these events
gabomdq@9023
    97
are delivered you must handle them in an event callback because the OS may
gabomdq@9023
    98
not give you any processing time after the events are delivered.
gabomdq@9023
    99
gabomdq@9023
   100
e.g.
gabomdq@9023
   101
philipp@9050
   102
    int HandleAppEvents(void *userdata, SDL_Event *event)
gabomdq@9023
   103
    {
philipp@9050
   104
        switch (event->type)
philipp@9050
   105
        {
philipp@9050
   106
        case SDL_APP_TERMINATING:
philipp@9050
   107
            /* Terminate the app.
philipp@9050
   108
               Shut everything down before returning from this function.
philipp@9050
   109
            */
philipp@9050
   110
            return 0;
philipp@9050
   111
        case SDL_APP_LOWMEMORY:
philipp@9050
   112
            /* You will get this when your app is paused and iOS wants more memory.
philipp@9050
   113
               Release as much memory as possible.
philipp@9050
   114
            */
philipp@9050
   115
            return 0;
philipp@9050
   116
        case SDL_APP_WILLENTERBACKGROUND:
philipp@9050
   117
            /* Prepare your app to go into the background.  Stop loops, etc.
philipp@9050
   118
               This gets called when the user hits the home button, or gets a call.
philipp@9050
   119
            */
philipp@9050
   120
            return 0;
philipp@9050
   121
        case SDL_APP_DIDENTERBACKGROUND:
philipp@9050
   122
            /* This will get called if the user accepted whatever sent your app to the background.
philipp@9050
   123
               If the user got a phone call and canceled it, you'll instead get an SDL_APP_DIDENTERFOREGROUND event and restart your loops.
philipp@9050
   124
               When you get this, you have 5 seconds to save all your state or the app will be terminated.
philipp@9050
   125
               Your app is NOT active at this point.
philipp@9050
   126
            */
philipp@9050
   127
            return 0;
philipp@9050
   128
        case SDL_APP_WILLENTERFOREGROUND:
philipp@9050
   129
            /* This call happens when your app is coming back to the foreground.
philipp@9050
   130
               Restore all your state here.
philipp@9050
   131
            */
philipp@9050
   132
            return 0;
philipp@9050
   133
        case SDL_APP_DIDENTERFOREGROUND:
philipp@9050
   134
            /* Restart your loops here.
philipp@9050
   135
               Your app is interactive and getting CPU again.
philipp@9050
   136
            */
philipp@9050
   137
            return 0;
philipp@9050
   138
        default:
philipp@9050
   139
            /* No special processing, add it to the event queue */
philipp@9050
   140
            return 1;
philipp@9050
   141
        }
philipp@9050
   142
    }
philipp@9050
   143
    
philipp@9050
   144
    int main(int argc, char *argv[])
philipp@9050
   145
    {
philipp@9050
   146
        SDL_SetEventFilter(HandleAppEvents, NULL);
philipp@9050
   147
    
philipp@9050
   148
        ... run your main loop
philipp@9050
   149
    
gabomdq@9023
   150
        return 0;
gabomdq@9023
   151
    }
gabomdq@9023
   152
gabomdq@9023
   153
    
gabomdq@9023
   154
==============================================================================
gabomdq@9023
   155
Notes -- Accelerometer as Joystick
gabomdq@9023
   156
==============================================================================
gabomdq@9023
   157
gabomdq@9023
   158
SDL for iPhone supports polling the built in accelerometer as a joystick device.  For an example on how to do this, see the accelerometer.c in the demos directory.
gabomdq@9023
   159
philipp@10167
   160
The main thing to note when using the accelerometer with SDL is that while the iPhone natively reports accelerometer as floating point values in units of g-force, SDL_JoystickGetAxis() reports joystick values as signed integers.  Hence, in order to convert between the two, some clamping and scaling is necessary on the part of the iPhone SDL joystick driver.  To convert SDL_JoystickGetAxis() reported values BACK to units of g-force, simply multiply the values by SDL_IPHONE_MAX_GFORCE / 0x7FFF.
gabomdq@9023
   161
gabomdq@9023
   162
==============================================================================
gabomdq@9023
   163
Notes -- OpenGL ES
gabomdq@9023
   164
==============================================================================
gabomdq@9023
   165
slime73@9810
   166
Your SDL application for iOS uses OpenGL ES for video by default.
gabomdq@9023
   167
philipp@10167
   168
OpenGL ES for iOS supports several display pixel formats, such as RGBA8 and RGB565, which provide a 32 bit and 16 bit color buffer respectively. By default, the implementation uses RGB565, but you may use RGBA8 by setting each color component to 8 bits in SDL_GL_SetAttribute().
gabomdq@9023
   169
gabomdq@9023
   170
If your application doesn't use OpenGL's depth buffer, you may find significant performance improvement by setting SDL_GL_DEPTH_SIZE to 0.
gabomdq@9023
   171
slime73@9810
   172
Finally, if your application completely redraws the screen each frame, you may find significant performance improvement by setting the attribute SDL_GL_RETAINED_BACKING to 0.
slime73@9810
   173
slime73@9810
   174
OpenGL ES on iOS doesn't use the traditional system-framebuffer setup provided in other operating systems. Special care must be taken because of this:
slime73@9810
   175
philipp@10167
   176
- The drawable Renderbuffer must be bound to the GL_RENDERBUFFER binding point when SDL_GL_SwapWindow() is called.
philipp@10167
   177
- The drawable Framebuffer Object must be bound while rendering to the screen and when SDL_GL_SwapWindow() is called.
slime73@9810
   178
- If multisample antialiasing (MSAA) is used and glReadPixels is used on the screen, the drawable framebuffer must be resolved to the MSAA resolve framebuffer (via glBlitFramebuffer or glResolveMultisampleFramebufferAPPLE), and the MSAA resolve framebuffer must be bound to the GL_READ_FRAMEBUFFER binding point, before glReadPixels is called.
slime73@9810
   179
philipp@10167
   180
The above objects can be obtained via SDL_GetWindowWMInfo() (in SDL_syswm.h).
gabomdq@9023
   181
gabomdq@9023
   182
==============================================================================
gabomdq@9023
   183
Notes -- Keyboard
gabomdq@9023
   184
==============================================================================
gabomdq@9023
   185
gabomdq@9023
   186
The SDL keyboard API has been extended to support on-screen keyboards:
gabomdq@9023
   187
gabomdq@9023
   188
void SDL_StartTextInput()
gabomdq@9023
   189
	-- enables text events and reveals the onscreen keyboard.
philipp@9066
   190
gabomdq@9023
   191
void SDL_StopTextInput()
gabomdq@9023
   192
	-- disables text events and hides the onscreen keyboard.
philipp@9066
   193
gabomdq@9023
   194
SDL_bool SDL_IsTextInputActive()
gabomdq@9023
   195
	-- returns whether or not text events are enabled (and the onscreen keyboard is visible)
gabomdq@9023
   196
philipp@9066
   197
gabomdq@9023
   198
==============================================================================
gabomdq@9023
   199
Notes -- Reading and Writing files
gabomdq@9023
   200
==============================================================================
gabomdq@9023
   201
gabomdq@9023
   202
Each application installed on iPhone resides in a sandbox which includes its own Application Home directory.  Your application may not access files outside this directory.
gabomdq@9023
   203
gabomdq@9023
   204
Once your application is installed its directory tree looks like:
gabomdq@9023
   205
philipp@9066
   206
    MySDLApp Home/
philipp@9066
   207
        MySDLApp.app
philipp@9066
   208
        Documents/
philipp@9066
   209
        Library/
philipp@9066
   210
            Preferences/
philipp@9066
   211
        tmp/
gabomdq@9023
   212
gabomdq@9023
   213
When your SDL based iPhone application starts up, it sets the working directory to the main bundle (MySDLApp Home/MySDLApp.app), where your application resources are stored.  You cannot write to this directory.  Instead, I advise you to write document files to "../Documents/" and preferences to "../Library/Preferences".  
gabomdq@9023
   214
gabomdq@9023
   215
More information on this subject is available here:
gabomdq@9023
   216
http://developer.apple.com/library/ios/#documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/Introduction/Introduction.html
gabomdq@9023
   217
gabomdq@9023
   218
==============================================================================
gabomdq@9023
   219
Notes -- iPhone SDL limitations
gabomdq@9023
   220
==============================================================================
gabomdq@9023
   221
gabomdq@9023
   222
Windows:
philipp@10167
   223
	Full-size, single window applications only.  You cannot create multi-window SDL applications for iPhone OS.  The application window will fill the display, though you have the option of turning on or off the menu-bar (pass SDL_CreateWindow() the flag SDL_WINDOW_BORDERLESS).
gabomdq@9023
   224
gabomdq@9023
   225
Textures:
gabomdq@9023
   226
	The optimal texture formats on iOS are SDL_PIXELFORMAT_ABGR8888, SDL_PIXELFORMAT_ABGR8888, SDL_PIXELFORMAT_BGR888, and SDL_PIXELFORMAT_RGB24 pixel formats.
gabomdq@9023
   227
gabomdq@9023
   228
Loading Shared Objects:
slime73@9810
   229
	This is disabled by default since it seems to break the terms of the iOS SDK agreement for iOS versions prior to iOS 8. It can be re-enabled in SDL_config_iphoneos.h.
gabomdq@9023
   230
gabomdq@9023
   231
==============================================================================
gabomdq@9023
   232
Game Center 
gabomdq@9023
   233
==============================================================================
gabomdq@9023
   234
slime73@9995
   235
Game Center integration might require that you break up your main loop in order to yield control back to the system. In other words, instead of running an endless main loop, you run each frame in a callback function, using:
philipp@9066
   236
philipp@9066
   237
    int SDL_iPhoneSetAnimationCallback(SDL_Window * window, int interval, void (*callback)(void*), void *callbackParam);
gabomdq@9023
   238
gabomdq@9023
   239
This will set up the given function to be called back on the animation callback, and then you have to return from main() to let the Cocoa event loop run.
gabomdq@9023
   240
gabomdq@9023
   241
e.g.
gabomdq@9023
   242
philipp@9050
   243
    extern "C"
philipp@9050
   244
    void ShowFrame(void*)
philipp@9050
   245
    {
philipp@9066
   246
        ... do event handling, frame logic and rendering ...
philipp@9050
   247
    }
philipp@9050
   248
    
philipp@9050
   249
    int main(int argc, char *argv[])
philipp@9050
   250
    {
philipp@9050
   251
        ... initialize game ...
philipp@9050
   252
    
philipp@9050
   253
    #if __IPHONEOS__
philipp@9066
   254
        // Initialize the Game Center for scoring and matchmaking
philipp@9066
   255
        InitGameCenter();
philipp@9050
   256
    
philipp@9066
   257
        // Set up the game to run in the window animation callback on iOS
philipp@9066
   258
        // so that Game Center and so forth works correctly.
philipp@9066
   259
        SDL_iPhoneSetAnimationCallback(window, 1, ShowFrame, NULL);
philipp@9050
   260
    #else
philipp@9066
   261
        while ( running ) {
philipp@9066
   262
            ShowFrame(0);
philipp@9066
   263
            DelayFrame();
philipp@9066
   264
        }
philipp@9050
   265
    #endif
philipp@9066
   266
        return 0;
philipp@9050
   267
    }
slouken@11522
   268
slouken@11522
   269
==============================================================================
slouken@11522
   270
Deploying to older versions of iOS
slouken@11522
   271
==============================================================================
slouken@11522
   272
slouken@11522
   273
SDL supports deploying to older versions of iOS than are supported by the latest version of Xcode, all the way back to iOS 6.1
slouken@11522
   274
slouken@11522
   275
In order to do that you need to download an older version of Xcode:
slouken@11522
   276
https://developer.apple.com/download/more/?name=Xcode
slouken@11522
   277
slouken@11522
   278
Open the package contents of the older Xcode and your newer version of Xcode and copy over the folders in Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport
slouken@11522
   279
slouken@11522
   280
Then open the file Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/SDKSettings.plist and add the versions of iOS you want to deploy to the key Root/DefaultProperties/DEPLOYMENT_TARGET_SUGGESTED_VALUES
slouken@11522
   281
slouken@11522
   282
Open your project and set your deployment target to the desired version of iOS
slouken@11522
   283
slouken@11522
   284
Finally, remove GameController from the list of frameworks linked by your application and edit the build settings for "Other Linker Flags" and add -weak_framework GameController