diff --git a/alienblaster/Application.mk b/alienblaster/Application.mk deleted file mode 100644 index 5f9cacf1a..000000000 --- a/alienblaster/Application.mk +++ /dev/null @@ -1,2 +0,0 @@ -APP_PROJECT_PATH := $(call my-dir)/project -APP_MODULES := application stlport sdl sdl_main sdl_mixer tremor sdl_image png jpeg sdl_ttf freetype diff --git a/alienblaster/build.sh b/alienblaster/build.sh new file mode 100755 index 000000000..4f19449fe --- /dev/null +++ b/alienblaster/build.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +# Set here your own NDK path if needed +export PATH=$PATH:~/src/endless_space/android-ndk-r4 + +cd project && ndk-build -j2 V=1 && ant debug && cd bin && adb install -r DemoActivity-debug.apk + diff --git a/alienblaster/project/AndroidManifest.xml b/alienblaster/project/AndroidManifest.xml index 0373b4868..b2bcf5158 100644 --- a/alienblaster/project/AndroidManifest.xml +++ b/alienblaster/project/AndroidManifest.xml @@ -3,7 +3,9 @@ package="de.schwardtnet.alienblaster" android:versionCode="1" android:versionName="1.0"> - + - + diff --git a/alienblaster/project/default.properties b/alienblaster/project/default.properties index 9d6f70d65..0b9250e02 100644 --- a/alienblaster/project/default.properties +++ b/alienblaster/project/default.properties @@ -8,6 +8,4 @@ # project structure. # Project target. -target=android-4 -# Indicates whether an apk should be generated for each density. -split.density=false +target=android-8 diff --git a/alienblaster/project/jni/application/src/game.cpp b/alienblaster/project/jni/application/src/game.cpp index 471a042a5..c733d57e9 100644 --- a/alienblaster/project/jni/application/src/game.cpp +++ b/alienblaster/project/jni/application/src/game.cpp @@ -74,13 +74,19 @@ int difficultyLevel; float actBackgroundPos; Game::Game() { + __android_log_print(ANDROID_LOG_INFO, "Alien Blaster", "Game() 1"); videoserver = new Video(); + __android_log_print(ANDROID_LOG_INFO, "Alien Blaster", "Game() 2"); screen = 0; screen = videoserver->init(); + __android_log_print(ANDROID_LOG_INFO, "Alien Blaster", "Game() 3"); settings = new Settings(); + __android_log_print(ANDROID_LOG_INFO, "Alien Blaster", "Game() 4"); intro = new Intro( screen ); + __android_log_print(ANDROID_LOG_INFO, "Alien Blaster", "Game() 5"); setDifficulty = new SetDifficulty( screen ); menuArcadeMode = new MenuArcadeMode( screen ); + __android_log_print(ANDROID_LOG_INFO, "Alien Blaster", "Game() 6"); pauseSprite = surfaceDB.loadSurface( FN_PAUSED ); youLoseSprite = surfaceDB.loadSurface( FN_YOU_LOSE ); @@ -92,6 +98,8 @@ Game::Game() { bossAlarm = Mixer::mixer().loadSample( FN_SOUND_BOSS_ALARM, 60 ); + __android_log_print(ANDROID_LOG_INFO, "Alien Blaster", "Game() 7"); + fontTime = new Font( FN_FONT_NUMBERS_TIME ); fontSizeTime = fontTime->getCharWidth(); @@ -125,18 +133,27 @@ Game::Game() { sonic1 = new Sonic(); sonic2 = new Sonic(); + __android_log_print(ANDROID_LOG_INFO, "Alien Blaster", "Game() 8"); + background = new Background(); loadLevel( FN_LEVEL_ONE_PLAYER ); + __android_log_print(ANDROID_LOG_INFO, "Alien Blaster", "Game() 9"); + SDL_Surface *loadingSprite = surfaceDB.loadSurface( FN_LOADING ); + __android_log_print(ANDROID_LOG_INFO, "Alien Blaster", "Game() 10"); SDL_Rect dest; dest.x = (SCREEN_WIDTH - loadingSprite->w ) / 2; dest.y = (SCREEN_HEIGHT - loadingSprite->h ) / 2; dest.w = loadingSprite->w; dest.h = loadingSprite->h; + __android_log_print(ANDROID_LOG_INFO, "Alien Blaster", "Game() 11"); SDL_BlitSurface( loadingSprite, 0, screen, &dest ); + __android_log_print(ANDROID_LOG_INFO, "Alien Blaster", "Game() 12"); SDL_Flip( screen ); + __android_log_print(ANDROID_LOG_INFO, "Alien Blaster", "Game() 13"); initAllSurfaces(); + __android_log_print(ANDROID_LOG_INFO, "Alien Blaster", "Game() 14"); } Game::~Game(){ diff --git a/alienblaster/project/jni/application/src/intro.cpp b/alienblaster/project/jni/application/src/intro.cpp index 2ed88919f..8fbedc985 100644 --- a/alienblaster/project/jni/application/src/intro.cpp +++ b/alienblaster/project/jni/application/src/intro.cpp @@ -31,15 +31,25 @@ using namespace std; #include "infoscreen.h" Intro::Intro( SDL_Surface *scr ) { + __android_log_print(ANDROID_LOG_INFO, "Alien Blaster", "Intro() 1"); screen = scr; + __android_log_print(ANDROID_LOG_INFO, "Alien Blaster", "Intro() 2"); introSprite = surfaceDB.loadSurface( FN_ALIENBLASTER_INTRO ); + __android_log_print(ANDROID_LOG_INFO, "Alien Blaster", "Intro() 3"); activeChoiceSprite = surfaceDB.loadSurface( FN_INTRO_SHOW_CHOICE ); + __android_log_print(ANDROID_LOG_INFO, "Alien Blaster", "Intro() 4"); font = new Font( FN_FONT_INTRO ); + __android_log_print(ANDROID_LOG_INFO, "Alien Blaster", "Intro() 5"); fontHighlighted = new Font( FN_FONT_INTRO_HIGHLIGHTED ); + __android_log_print(ANDROID_LOG_INFO, "Alien Blaster", "Intro() 6"); activeChoice = 0; + __android_log_print(ANDROID_LOG_INFO, "Alien Blaster", "Intro() 7"); choose = Mixer::mixer().loadSample( FN_SOUND_INTRO_CHOOSE, 100 ); + __android_log_print(ANDROID_LOG_INFO, "Alien Blaster", "Intro() 8"); confirm = Mixer::mixer().loadSample( FN_SOUND_INTRO_CONFIRM, 100 ); + __android_log_print(ANDROID_LOG_INFO, "Alien Blaster", "Intro() 9"); infoscreen = new Infoscreen( screen ); + __android_log_print(ANDROID_LOG_INFO, "Alien Blaster", "Intro() 10"); } Intro::~Intro() {} diff --git a/alienblaster/project/jni/application/src/main.cpp b/alienblaster/project/jni/application/src/main.cpp index c0ed125d8..8b90f8043 100644 --- a/alienblaster/project/jni/application/src/main.cpp +++ b/alienblaster/project/jni/application/src/main.cpp @@ -25,10 +25,15 @@ using namespace std; int main(int argc, char *argv[]) { + __android_log_print(ANDROID_LOG_INFO, "Alien Blaster", "main() 0"); SDL_Init(0); srand(0); + __android_log_print(ANDROID_LOG_INFO, "Alien Blaster", "main() 1"); Game game; + __android_log_print(ANDROID_LOG_INFO, "Alien Blaster", "main() 2"); game.run(); + __android_log_print(ANDROID_LOG_INFO, "Alien Blaster", "main() 3"); SDL_Quit(); + __android_log_print(ANDROID_LOG_INFO, "Alien Blaster", "main() 4"); return 0; } diff --git a/alienblaster/project/jni/application/src/mixer.cpp b/alienblaster/project/jni/application/src/mixer.cpp index 8f205dcdd..5852b2b58 100644 --- a/alienblaster/project/jni/application/src/mixer.cpp +++ b/alienblaster/project/jni/application/src/mixer.cpp @@ -24,6 +24,7 @@ using namespace std; #include #include #include +#include Mixer * mixerInstance = NULL; @@ -35,17 +36,22 @@ Mixer & Mixer::mixer() } Mixer::Mixer() { + __android_log_print(ANDROID_LOG_INFO, "Alien Blaster", "Initializing audio"); if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) { printf("Couldn't initialize SDL audio subsystem: %s\n", SDL_GetError()); + __android_log_print(ANDROID_LOG_ERROR, "Alien Blaster", "Couldn't initialize SDL audio subsystem: %s", SDL_GetError()); exit(1); } + __android_log_print(ANDROID_LOG_INFO, "Alien Blaster", "Initializing audio 2"); mixChunks = MixChunks(0); musics = Musics(0); enabled = false; + __android_log_print(ANDROID_LOG_INFO, "Alien Blaster", "Initializing audio 3"); initMixer(); lastUsedReservedChannel = 0; reservedChannels = 0; musicPlaying = MUSIC_NONE; + __android_log_print(ANDROID_LOG_INFO, "Alien Blaster", "Initializing audio done"); } Mixer::~Mixer() { @@ -55,6 +61,7 @@ Mixer::~Mixer() { } void Mixer::initMixer() { + __android_log_print(ANDROID_LOG_INFO, "Alien Blaster", "Initializing audio 4"); enabled = (Mix_OpenAudio(MIX_DEFAULT_FREQUENCY, MIX_DEFAULT_FORMAT, 1, 1024) >= 0); if (enabled) { Mix_AllocateChannels(MIXER_NUMBER_CHANNELS); @@ -66,6 +73,7 @@ void Mixer::initMixer() { fn2mus.clear(); playsOn.clear(); } + __android_log_print(ANDROID_LOG_INFO, "Alien Blaster", "Initializing audio 5"); } void Mixer::freeMixer() { diff --git a/alienblaster/project/jni/application/src/video.cpp b/alienblaster/project/jni/application/src/video.cpp index e67efe33b..d4b143551 100644 --- a/alienblaster/project/jni/application/src/video.cpp +++ b/alienblaster/project/jni/application/src/video.cpp @@ -40,14 +40,17 @@ SDL_Surface *Video::init(){ // SDL initialisation // ----------------------------------------------------- + __android_log_print(ANDROID_LOG_INFO, "Alien Blaster", "Initializing video"); fullscreen = false; if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) { printf("Couldn't initialize SDL video subsystem: %s\n", SDL_GetError()); + __android_log_print(ANDROID_LOG_ERROR, "Alien Blaster", "Couldn't initialize SDL video subsystem: %s\n", SDL_GetError()); exit(1); } screen = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, BIT_DEPTH, SDL_DOUBLEBUF /* | SDL_FULLSCREEN */ ); if (!screen) { printf("Couldn't set %dx%d, %dbit video mode: %s\n", SCREEN_WIDTH, SCREEN_HEIGHT, BIT_DEPTH, SDL_GetError()); + __android_log_print(ANDROID_LOG_ERROR, "Alien Blaster", "Couldn't set %dx%d, %dbit video mode: %s\n", SCREEN_WIDTH, SCREEN_HEIGHT, BIT_DEPTH, SDL_GetError()); exit(2); } @@ -55,6 +58,7 @@ SDL_Surface *Video::init(){ SDL_WM_SetIcon(SDL_LoadBMP( FN_ALIENBLASTER_ICON.c_str() ), NULL); SDL_ShowCursor(SDL_DISABLE); + __android_log_print(ANDROID_LOG_INFO, "Alien Blaster", "Initializing video done"); return screen; } diff --git a/alienblaster/project/jni/sdl/src/SDL_error.c b/alienblaster/project/jni/sdl/src/SDL_error.c index 894409d86..12ae27fe2 100644 --- a/alienblaster/project/jni/sdl/src/SDL_error.c +++ b/alienblaster/project/jni/sdl/src/SDL_error.c @@ -26,6 +26,10 @@ #include "SDL_error.h" #include "SDL_error_c.h" +#ifdef ANDROID +#include +#endif + /* Routine to get the thread-specific error variable */ #if SDL_THREADS_DISABLED /* !!! FIXME: what does this comment mean? Victim of Search and Replace? */ @@ -111,6 +115,9 @@ SDL_SetError(const char *fmt, ...) #ifdef DEBUG_ERROR fprintf(stderr, "SDL_SetError: %s\n", SDL_GetError()); #endif +#ifdef ANDROID + __android_log_print(ANDROID_LOG_ERROR, "libSDL", "SDL_SetError: %s", SDL_GetError()); +#endif } /* This function has a bit more overhead than most error functions diff --git a/alienblaster/project/jni/sdl/src/audio/android/SDL_androidaudio.c b/alienblaster/project/jni/sdl/src/audio/android/SDL_androidaudio.c index 1b8733d4d..96757b78a 100644 --- a/alienblaster/project/jni/sdl/src/audio/android/SDL_androidaudio.c +++ b/alienblaster/project/jni/sdl/src/audio/android/SDL_androidaudio.c @@ -100,8 +100,8 @@ static Uint8 *ANDROIDAUD_GetAudioBuf(_THIS) static int ANDROIDAUD_OpenAudio(_THIS, const char *devname, int iscapture) { + __android_log_print(ANDROID_LOG_INFO, "libSDL", "ANDROIDAUD_OpenAudio: enter"); SDL_AudioSpec *audioFormat = &this->spec; - jboolean isCopy = JNI_TRUE; int bytesPerSample; JNIEnv * jniEnv = NULL; @@ -129,32 +129,26 @@ static int ANDROIDAUD_OpenAudio(_THIS, const char *devname, int iscapture) return (-1); // TODO: enable format conversion? Don't know how to do that in SDL } - audioBufferJNI = (*jniEnv)->CallObjectMethod( jniEnv, JavaAudioThread, JavaInitAudio, + audioBufferSize = (*jniEnv)->CallIntMethod( jniEnv, JavaAudioThread, JavaInitAudio, (jint)audioFormat->freq, (jint)audioFormat->channels, (jint)(( bytesPerSample == 2 ) ? 1 : 0), (jint)audioFormat->size); - if( ! audioBufferJNI ) + if( audioBufferSize == 0 ) { __android_log_print(ANDROID_LOG_INFO, "libSDL", "ANDROIDAUD_OpenAudio(): failed to get audio buffer from JNI"); ANDROIDAUD_CloseAudio(this); return(-1); } - audioBufferJNI = (*jniEnv)->NewGlobalRef(jniEnv, audioBufferJNI); - audioBufferSize = (*jniEnv)->GetArrayLength(jniEnv, audioBufferJNI); - audioBuffer = (unsigned char *) (*jniEnv)->GetByteArrayElements(jniEnv, audioBufferJNI, &isCopy); - if( isCopy == JNI_TRUE ) - __android_log_print(ANDROID_LOG_ERROR, "libSDL", "ANDROIDAUD_OpenAudio(): JNI returns a copy of byte array - no audio will be played"); - /* We cannot call DetachCurrentThread() from main thread or we'll crash */ /* (*jniVM)->DetachCurrentThread(jniVM); */ audioFormat->samples = audioBufferSize / bytesPerSample / audioFormat->channels; audioFormat->size = audioBufferSize; - SDL_memset(audioBuffer, audioFormat->silence, audioFormat->size); SDL_CalculateAudioSpec(&this->spec); + __android_log_print(ANDROID_LOG_INFO, "libSDL", "ANDROIDAUD_OpenAudio: exit, audioBufferSize %d", audioBufferSize); return(1); } @@ -190,12 +184,13 @@ static jmethodID JavaFillBuffer = NULL; static void ANDROIDAUD_ThreadInit(_THIS) { + __android_log_print(ANDROID_LOG_INFO, "libSDL", "ANDROIDAUD_ThreadInit: enter"); jclass JavaAudioThreadClass = NULL; jmethodID JavaInitThread = NULL; - struct sched_param param; + jmethodID JavaGetBuffer = NULL; + jboolean isCopy = JNI_TRUE; (*jniVM)->AttachCurrentThread(jniVM, &jniEnvPlaying, NULL); - JavaAudioThreadClass = (*jniEnvPlaying)->GetObjectClass(jniEnvPlaying, JavaAudioThread); JavaFillBuffer = (*jniEnvPlaying)->GetMethodID(jniEnvPlaying, JavaAudioThreadClass, "fillBuffer", "()I"); @@ -203,6 +198,22 @@ static void ANDROIDAUD_ThreadInit(_THIS) /* HACK: raise our own thread priority to max to get rid of "W/AudioFlinger: write blocked for 54 msecs" errors */ JavaInitThread = (*jniEnvPlaying)->GetMethodID(jniEnvPlaying, JavaAudioThreadClass, "initAudioThread", "()I"); (*jniEnvPlaying)->CallIntMethod( jniEnvPlaying, JavaAudioThread, JavaInitThread ); + + JavaGetBuffer = (*jniEnvPlaying)->GetMethodID(jniEnvPlaying, JavaAudioThreadClass, "getBuffer", "()[B"); + audioBufferJNI = (*jniEnvPlaying)->CallObjectMethod( jniEnvPlaying, JavaAudioThread, JavaGetBuffer ); + audioBufferJNI = (*jniEnvPlaying)->NewGlobalRef(jniEnvPlaying, audioBufferJNI); + audioBuffer = (unsigned char *) (*jniEnvPlaying)->GetByteArrayElements(jniEnvPlaying, audioBufferJNI, &isCopy); + if( !audioBuffer ) + { + __android_log_print(ANDROID_LOG_ERROR, "libSDL", "ANDROIDAUD_PlayAudio() JNI::GetByteArrayElements() failed! we will crash now"); + return; + } + if( isCopy == JNI_TRUE ) + __android_log_print(ANDROID_LOG_ERROR, "libSDL", "ANDROIDAUD_OpenAudio(): JNI returns a copy of byte array - no audio will be played"); + + SDL_memset(audioBuffer, this->spec.silence, this->spec.size); + + __android_log_print(ANDROID_LOG_INFO, "libSDL", "ANDROIDAUD_ThreadInit: exit, audioBuffer %p", audioBuffer); }; static void ANDROIDAUD_ThreadDeinit(_THIS) @@ -212,18 +223,23 @@ static void ANDROIDAUD_ThreadDeinit(_THIS) static void ANDROIDAUD_PlayAudio(_THIS) { + __android_log_print(ANDROID_LOG_INFO, "libSDL", "ANDROIDAUD_PlayAudio: enter, audiobuffer %p", audioBuffer); jboolean isCopy = JNI_TRUE; (*jniEnvPlaying)->ReleaseByteArrayElements(jniEnvPlaying, audioBufferJNI, (jbyte *)audioBuffer, 0); audioBuffer = NULL; + __android_log_print(ANDROID_LOG_INFO, "libSDL", "ANDROIDAUD_PlayAudio: before JavaFillBuffer"); (*jniEnvPlaying)->CallIntMethod( jniEnvPlaying, JavaAudioThread, JavaFillBuffer ); + __android_log_print(ANDROID_LOG_INFO, "libSDL", "ANDROIDAUD_PlayAudio: after JavaFillBuffer"); audioBuffer = (unsigned char *) (*jniEnvPlaying)->GetByteArrayElements(jniEnvPlaying, audioBufferJNI, &isCopy); + if( !audioBuffer ) + __android_log_print(ANDROID_LOG_ERROR, "libSDL", "ANDROIDAUD_PlayAudio() JNI::GetByteArrayElements() failed! we will crash now"); if( isCopy == JNI_TRUE ) __android_log_print(ANDROID_LOG_INFO, "libSDL", "ANDROIDAUD_PlayAudio() JNI returns a copy of byte array - that's slow"); - + __android_log_print(ANDROID_LOG_INFO, "libSDL", "ANDROIDAUD_PlayAudio: exit audioBuffer %p", audioBuffer); } #ifndef SDL_JAVA_PACKAGE_PATH @@ -238,7 +254,7 @@ JNIEXPORT jint JNICALL JAVA_EXPORT_NAME(AudioThread_nativeAudioInitJavaCallbacks jclass JavaAudioThreadClass = NULL; JavaAudioThread = (*jniEnv)->NewGlobalRef(jniEnv, thiz); JavaAudioThreadClass = (*jniEnv)->GetObjectClass(jniEnv, JavaAudioThread); - JavaInitAudio = (*jniEnv)->GetMethodID(jniEnv, JavaAudioThreadClass, "initAudio", "(IIII)[B"); + JavaInitAudio = (*jniEnv)->GetMethodID(jniEnv, JavaAudioThreadClass, "initAudio", "(IIII)I"); JavaDeinitAudio = (*jniEnv)->GetMethodID(jniEnv, JavaAudioThreadClass, "deinitAudio", "()I"); /* __android_log_print(ANDROID_LOG_INFO, "libSDL", "nativeAudioInitJavaCallbacks(): JavaAudioThread %p JavaFillBuffer %p JavaInitAudio %p JavaDeinitAudio %p", diff --git a/alienblaster/project/jni/sdl_main/sdl_main.c b/alienblaster/project/jni/sdl_main/sdl_main.c index c76214618..ac2ace91c 100644 --- a/alienblaster/project/jni/sdl_main/sdl_main.c +++ b/alienblaster/project/jni/sdl_main/sdl_main.c @@ -28,6 +28,11 @@ JAVA_EXPORT_NAME(DemoRenderer_nativeInit) ( JNIEnv* env, jobject thiz ) int argc = 1; char * argv[] = { "sdl" }; chdir(SDL_CURDIR_PATH); + /* + __android_log_print(ANDROID_LOG_INFO, "libSDL", "Waiting 30s for debugger"); + sleep(30); // Wait for debugger to attach + __android_log_print(ANDROID_LOG_INFO, "libSDL", "Starting main()"); + */ main( argc, argv ); }; diff --git a/alienblaster/project/src/Audio.java b/alienblaster/project/src/Audio.java index 54a8568c7..213048c76 100644 --- a/alienblaster/project/src/Audio.java +++ b/alienblaster/project/src/Audio.java @@ -34,11 +34,18 @@ class AudioThread { public int fillBuffer() { - mAudio.write( mAudioBuffer, 0, mAudioBuffer.length ); + Log.i("libSDL", "JNI: fillBuffer() enter, mAudioBuffer len " + String.valueOf(mAudioBuffer.length)); + int ret = 0; + try{ + ret = mAudio.write( mAudioBuffer, 0, mAudioBuffer.length ); + } catch( Throwable t ) { + Log.i("libSDL", "JNI: fillBuffer() caught exception!"); + } + Log.i("libSDL", "JNI: fillBuffer() exit, written " + String.valueOf(ret)); return 1; } - public byte[] initAudio(int rate, int channels, int encoding, int bufSize) + public int initAudio(int rate, int channels, int encoding, int bufSize) { if( mAudio == null ) { @@ -60,7 +67,12 @@ class AudioThread { AudioTrack.MODE_STREAM ); mAudio.play(); } - return mAudioBuffer; + return mAudioBuffer.length; + } + + public byte[] getBuffer() + { + return mAudioBuffer; } public int deinitAudio() diff --git a/alienblaster/readme.txt b/alienblaster/readme.txt index 75f1eca9e..5b3439b5b 100644 --- a/alienblaster/readme.txt +++ b/alienblaster/readme.txt @@ -3,29 +3,25 @@ I did not change anything in Alien Blaster sources, except for SCREEN_WIDTH, SCREEN_HEIGHT and BIT_DEPTH constants in global.h, to support 320x480x16bpp video mode, and also made audio initialize after main() has been called, not inside static initializers. -This should be compiled with Android 1.6 SDK and NDK - google for them and install them as described in their docs. -You'll need to install Ant too -Then symlink this dir to /apps under the name "alienblaster": - ln -s `pwd` /apps/alienblaster -Then go to dir and execute: - make APP=alienblaster V=1 -Hopefully it will compile a bunch of libs under project/libs/armeabi -Then you'll have to compile Android .apk package with Java wrapper code for this lib: -Go to "project" directory and type +This should be compiled with Android 2.2 SDK and NDK r4 - google for them and install them as described in their docs +(the application will run on Android 1.6 and above, 2.2 is the first version where you can debug it). +You'll need to install Ant too. +Go to "project" directory and launch command android update project -p . - ant debug -That will create file project/bin/DemoActivity-debug.apk - use "adb install" to test it +Then go back, edit file build.sh if needed to add NDK dir to your PATH, then launch it. +Hopefully it will compile a bunch of libs under project/libs/armeabi, +create file project/bin/DemoActivity-debug.apk and install it on your device or emulator. Then you can test it by launching Alien Blaster icon from Android applications menu. -It's designed for 640x480, and GUI elements are drawn out of place, but you can play the game. -Note: The game enforces vertical screen orientation, but you may open your keyboard and use it for +It's designed for 640x480, so if you have smaller screen it will be resized. +Note: The game enforces horizontal screen orientation, you may open your keyboard and use it for additional keys - the phone will just keep current screen orientation. -Fire key is Call key ( = left Ctrl for SDL ), Change weapon is Menu key ( = left Alt for SDL ) Note that you may use Volume up/down and Camera keys as game inputs - you'll have to redefine them in game keyconfig menu. -Other keys like Home, Search and End Call will force application quit, and because -the app itself does not handle SDL_QUIT event correctly (asks for confirmation), -it will stay in memory until you reboot device (actually it won't stay in memory - it will crash :P ). -To exit correctly press Menu key - it's redirected to Escape. +Keys Home, Search and End Call will force application quit, and because +of a bug in my SDL implementation application will crash. +Back key is mapped to Escape, and both Menu and cursor keys center / trackball click are mapped to Enter. +Newer Android phones like HTC Evo have no keyboard at all, so there are just 3 usable keys - +Menu, Volume Up and Volume Down. Because of that the accelerometer is configured to trigger cursor key events. This port also supports GL ES + SDL combo - there is GLXGears demo app in project/jni/application/glxgears, remove all files from project/jni/application/src and put glxgears.c there to check if it works. @@ -33,32 +29,45 @@ Note that GL ES is NOT pure OpenGL - there are no glBegin() and glEnd() call and and generally it will take a lot of effort to port pure OpenGL application to GL ES. When porting you own app, first of all ensure that your application supports -one of 320x200, 320x240 or 480x320 display resolutions and 16 bits per pixel -(480x320 is native resolution for G1, Supersonic has 800x480). -Also there is 640x480 mode, but it's very slow on G1 to copy from memory surface (2 FPS max). -SDL_ListModes()[0] will always return native screen resolution, other modes are there for compatibility. +native RGB_565 pixel format and AUDIO_S8 or AUDIO_S16 audio format +(yes, there is RGB_565 pixelformat even for OpenGL, not BGR_565 as all other OpenGL implementation have). +HTC G1/Nexus One has native screen resolution 480x320, HTC Evo has 800x480, so design your app to support +any screen resolution. +SDL_ListModes()[0] will always return native screen resolution, you may use 640x480 or 800x600 +but it will be resized to fit the screen. To compile your own app, put your app sources into project/jni/application dir (remove Alien Blaster first), and launch script ChangeAppSettings.sh - it will put the name of your app in several places in sources. -The C++ files shall have .cpp extension to be compiled. - -Then repeat steps: - make APP=alienblaster V=1 - ant debug +The C++ files shall have .cpp extension to be compiled, rename them if necessary. +Then you should launch script ChangeAppSettings.sh - it will ask you few questions, +and change several values across project files. +Then you can launch build.sh. Application data is not bundled with app itself - it should be downloaded from net on first run. Create .ZIP file with your application data, and put it somewhere on HTTP server - ChangeAppSettings.sh will ask you for the URL. -If your app data is bigger than 5 megabytes it's better to store it on SD card, +If your app data is bigger than 5 megabytes it's better to store it on SD card, internal flash on Android is very limited. -If you'll add new libs add them to project/jni/, copy Android.mk from existing lib, and -add libname to Application.mk and project/jni//Android.mk +If you'll add new libs - add them to project/jni/, copy Android.mk from existing lib, and +add libname to project/jni//Android.mk -Audio formats currently supported are AUDIO_S8 and AUDIO_S16 (signed 8-bit and 16-bit PCM). +To debug your application launch Android 2.2 emulator or connect Android 2.2 device, +go to "project" directory and launch command + ndk-gdb --verbose --start --force +then when it fails enter command + target remote:5039 + (then answer "y") +Note that it's extremely buggy (I've succeeded to launch debug session twice from 20 tries), +you may wish to add "sleep(30);" at the beginning of main() so your app won't crash before debugger attached. +So it's best to debug with code like: + __android_log_print(ANDROID_LOG_INFO, "My App", "We somehow reached execution point #224"); Known bugs: +0. Revert to widely-used SDL 1.2, backport changes that enable hardware acceleration from SDL 1.3 +Ideally ChangeAppSettings.sh should ask you what SDL version you want to use. + 1. Application will crash on exit or when you're pressing "Home" button - the correct behavior for Android apps is to stay in memory and go to foreground when you're launching app again, that's not working yet because app will lose OpenGL context (there are rumors that it won't lose GL context in 2.1 SDK).