Slide 1

Slide 1 text

Porting from iOS to Android Manish Mathai Game Programmer@Rolocule Lessons Learned

Slide 2

Slide 2 text

roloengine iOS Games Touch Squash (2009) Super Badminton (2010) Flick Tennis (2011) Motion Tennis (2013)

Slide 3

Slide 3 text

roloengine Android Games Flick Tennis (2013) ….. More coming soon

Slide 4

Slide 4 text

roloengine iOS Internals • Written in Obj-C • OpenGL ES 2.0 for rendering • OpenAL for audio • Custom Physics engine • Custom Animation engine • Custom asset format for models, animations

Slide 5

Slide 5 text

Decision time Completely Native NDK provided “NativeActivity” Pros :- ● Almost Ultimate control over memory management ● Faster (?) Cons :- ● No UI support ● Many APIs not available via NDK Standard UI combined with C/C++ code invoked via JNI Pros :- ● Easy access to java APIs ● Leverage standard UI Cons :- ● Adds GC overhead on UI ● UI communication a hassle Hybrid approach vs

Slide 6

Slide 6 text

roloengine iOS Android Internals • Written in Obj-C C++ (NDK) & Java (UI) • OpenGL ES 2.0 for rendering • OpenAL-soft for audio • Custom Physics engine • Custom Animation engine • Custom asset format for models, animations

Slide 7

Slide 7 text

Rendering • Competent OpenGL ES 2.0 implementations from Android 2.3 onwards. • DO NOT MIX OpenGL 1.0 & 2.0 calls. • Recreate glBegin() / glEnd(), glPushMatrix() / glPopMatrix semantics in 2.0 if needed.

Slide 8

Slide 8 text

OpenGL context creation Pure Native a.k.a the hard way static int engine_init_display(struct engine* engine) { const EGLint attribs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_BLUE_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_RED_SIZE, 8, EGL_NONE }; EGLint w, h, dummy, format; EGLint numConfigs; EGLConfig config; EGLSurface surface; EGLContext context; EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);

Slide 9

Slide 9 text

OpenGL context creation eglInitialize(display, 0, 0); eglChooseConfig(display, attribs, &config, 1, &numConfigs); eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format); surface = eglCreateWindowSurface(display, config, engine->app->window, NULL); context = eglCreateContext(display, config, NULL, NULL); if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) { LOGW("Unable to eglMakeCurrent"); return -1; } return 0; }

Slide 10

Slide 10 text

OpenGL context creation Context creation in Java GLSurfaceView mGLView = new GLSurfaceView(this); mGLView.setRenderer(new GLRenderer()); class GLRenderer implements GLSurfaceView.Renderer { … public native void native_render(); public void onDrawFrame(GL10 gl) { native_render(); } }

Slide 11

Slide 11 text

OpenGL context creation Rendering via JNI calls to C/C++ JNIEXPORT void JNICALL Java_com_example_package_native_render(JNIEnv *env_, jobject obj_) { // Drawing code goes here }

Slide 12

Slide 12 text

OpenGL Tips • All OpenGL calls on render thread. All UI changes in UI thread. • Avoid touching Java heap during the game loop. • Block OpenGL thread on application pause.

Slide 13

Slide 13 text

Audio • Java APIs (SoundPool & Media Player) vs Native API OpenSL ES • OpenSL ES has a horrible & convoluted API • OpenAL-soft - Software impl of OpenAL with OpenEL ES as the backend https://github.com/AerialX/openal-soft-android

Slide 14

Slide 14 text

C++ utils & tools • Boost - surprisingly easy to build https://github.com/MysticTreeGames/Boost-for-Android Boost::Bind, Boost::IO • tinyxml2 - small and efficient XML parser https://github.com/leethomason/tinyxml2 • libpng + libzip for compressed textures

Slide 15

Slide 15 text

UI • Android is stingy with memory (16-24MB) • Easy to hit OOM with large bitmaps. • Modern phones (1 GB+ RAM) too Solution :- BitmapFactory.Options options = new BitmapFactory.Options(); options.inPurgeable = true; options.inInputShareable = true;

Slide 16

Slide 16 text

UI • Layouts for all screen sizes a must, for consistent UI placement. • Stock android fonts are limited.

Slide 17

Slide 17 text

Thank You ! [email protected]