android/project/jni/android-support.cpp
changeset 4726 9076cdb027af
child 4953 4f40b11e1045
equal deleted inserted replaced
4725:4eb9d3c7fdd2 4726:9076cdb027af
       
     1 /*******************************************************************************
       
     2  This file links the Java side of Android with libsdl
       
     3 *******************************************************************************/
       
     4 #include <jni.h>
       
     5 #include <sys/time.h>
       
     6 #include <time.h>
       
     7 #include <android/log.h>
       
     8 #include <stdint.h>
       
     9 #include <stdio.h>
       
    10 #include <stdlib.h>
       
    11 #include <math.h>
       
    12 #include <pthread.h>
       
    13 
       
    14 #define DEBUG
       
    15 
       
    16 
       
    17 /*******************************************************************************
       
    18                                Globals
       
    19 *******************************************************************************/
       
    20 static long _getTime(void){
       
    21 	struct timeval  now;
       
    22 	gettimeofday(&now, NULL);
       
    23 	return (long)(now.tv_sec*1000 + now.tv_usec/1000);
       
    24 }
       
    25 
       
    26 JNIEnv* mEnv = NULL;
       
    27 JNIEnv* mAudioThreadEnv = NULL; //See the note below for why this is necessary
       
    28 JavaVM* mVM = NULL;
       
    29 
       
    30 //Main activity
       
    31 jclass mActivityInstance;
       
    32 
       
    33 //method signatures
       
    34 jmethodID midCreateGLContext;
       
    35 jmethodID midFlipBuffers;
       
    36 jmethodID midEnableFeature;
       
    37 jmethodID midUpdateAudio;
       
    38 
       
    39 extern "C" int SDL_main();
       
    40 extern "C" int Android_OnKeyDown(int keycode);
       
    41 extern "C" int Android_OnKeyUp(int keycode);
       
    42 extern "C" void Android_SetScreenResolution(int width, int height);
       
    43 extern "C" void Android_OnResize(int width, int height, int format);
       
    44 extern "C" int SDL_SendQuit();
       
    45 extern "C" void Android_EnableFeature(int featureid, bool enabled);
       
    46 
       
    47 //If we're not the active app, don't try to render
       
    48 bool bRenderingEnabled = false;
       
    49 
       
    50 //Feature IDs
       
    51 static const int FEATURE_AUDIO = 1;
       
    52 static const int FEATURE_ACCEL = 2;
       
    53 
       
    54 //Accelerometer data storage
       
    55 float fLastAccelerometer[3];
       
    56 
       
    57 
       
    58 /*******************************************************************************
       
    59                  Functions called by JNI
       
    60 *******************************************************************************/	
       
    61 
       
    62 //Library init
       
    63 extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved){
       
    64 
       
    65     JNIEnv* env = NULL;
       
    66     jint result = -1;
       
    67 
       
    68     if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
       
    69         return result;
       
    70     }
       
    71 
       
    72     mEnv = env;
       
    73 
       
    74     __android_log_print(ANDROID_LOG_INFO, "SDL", "JNI: OnLoad");
       
    75 
       
    76     jclass cls = mEnv->FindClass ("org/libsdl/app/SDLActivity"); 
       
    77     mActivityInstance = cls;
       
    78     midCreateGLContext = mEnv->GetStaticMethodID(cls,"createGLContext","()V");
       
    79     midFlipBuffers = mEnv->GetStaticMethodID(cls,"flipBuffers","()V");
       
    80     midEnableFeature = mEnv->GetStaticMethodID(cls,"enableFeature","(II)V");
       
    81     midUpdateAudio = mEnv->GetStaticMethodID(cls,"updateAudio","([B)V");
       
    82 
       
    83     if(!midCreateGLContext || !midFlipBuffers || !midEnableFeature ||
       
    84         !midUpdateAudio){
       
    85         __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: Bad mids\n");
       
    86     }else{
       
    87 #ifdef DEBUG
       
    88         __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: Good mids\n");
       
    89 #endif
       
    90     }
       
    91     
       
    92     return JNI_VERSION_1_4;
       
    93 }
       
    94 
       
    95 //Start up the SDL app
       
    96 extern "C" void Java_org_libsdl_app_SDLActivity_nativeInit( JNIEnv* env, 
       
    97                                                                 jobject obj ){ 
       
    98                                                                    
       
    99 	__android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: Native Init");
       
   100 
       
   101 	mEnv = env;
       
   102 	bRenderingEnabled = true;
       
   103 
       
   104 	Android_EnableFeature(FEATURE_ACCEL, true);
       
   105 
       
   106     SDL_main();
       
   107 }
       
   108 
       
   109 //Keydown
       
   110 extern "C" void Java_org_libsdl_app_SDLActivity_onNativeKeyDown(JNIEnv* env, 
       
   111                jobject obj, jint keycode){
       
   112     
       
   113     int r = Android_OnKeyDown(keycode);
       
   114 #ifdef DEBUG
       
   115     __android_log_print(ANDROID_LOG_INFO, "SDL", 
       
   116                         "SDL: native key down %d, %d\n", keycode, r);
       
   117 #endif
       
   118                         
       
   119 }
       
   120 
       
   121 //Keyup
       
   122 extern "C" void Java_org_libsdl_app_SDLActivity_onNativeKeyUp(JNIEnv* env, 
       
   123                jobject obj, jint keycode){
       
   124     
       
   125     int r = Android_OnKeyUp(keycode);
       
   126 #ifdef DEBUG
       
   127     __android_log_print(ANDROID_LOG_INFO, "SDL", 
       
   128                         "SDL: native key up %d, %d\n", keycode, r);
       
   129 #endif
       
   130                         
       
   131 }
       
   132 
       
   133 //Touch
       
   134 extern "C" void Java_org_libsdl_app_SDLActivity_onNativeTouch(JNIEnv* env, 
       
   135                jobject obj, jint action, jfloat x, jfloat y, jfloat p){
       
   136 
       
   137 #ifdef DEBUG
       
   138     __android_log_print(ANDROID_LOG_INFO, "SDL", 
       
   139                         "SDL: native touch event %d @ %f/%f, pressure %f\n", 
       
   140                         action, x, y, p);
       
   141 #endif
       
   142 
       
   143     //TODO: Pass this off to the SDL multitouch stuff
       
   144                         
       
   145 }
       
   146 
       
   147 //Quit
       
   148 extern "C" void Java_org_libsdl_app_SDLActivity_nativeQuit( JNIEnv*  env, 
       
   149                                                                 jobject obj ){    
       
   150 
       
   151     //Stop rendering as we're no longer in the foreground
       
   152 	bRenderingEnabled = false;
       
   153 
       
   154     //Inject a SDL_QUIT event
       
   155     int r = SDL_SendQuit();
       
   156 
       
   157     __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: Native quit %d", r);        
       
   158 }
       
   159 
       
   160 //Screen size
       
   161 extern "C" void Java_org_libsdl_app_SDLActivity_nativeSetScreenSize(
       
   162                 JNIEnv*  env, jobject obj, jint width, jint height){
       
   163 
       
   164     __android_log_print(ANDROID_LOG_INFO, "SDL", 
       
   165                         "SDL: Set screen size on init: %d/%d\n", width, height);
       
   166     Android_SetScreenResolution(width, height);
       
   167                         
       
   168 }
       
   169 
       
   170 //Resize
       
   171 extern "C" void Java_org_libsdl_app_SDLActivity_onNativeResize(
       
   172                                         JNIEnv*  env, jobject obj, jint width, 
       
   173                                         jint height, jint format){
       
   174     Android_OnResize(width, height, format);
       
   175 }
       
   176 
       
   177 extern "C" void Java_org_libsdl_app_SDLActivity_onNativeAccel(
       
   178                                         JNIEnv*  env, jobject obj,
       
   179                                         jfloat x, jfloat y, jfloat z){
       
   180     fLastAccelerometer[0] = x;
       
   181     fLastAccelerometer[1] = y;
       
   182     fLastAccelerometer[2] = z;   
       
   183 }
       
   184 
       
   185 
       
   186 
       
   187 /*******************************************************************************
       
   188              Functions called by SDL into Java
       
   189 *******************************************************************************/
       
   190 extern "C" void Android_CreateContext(){
       
   191 	__android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: sdl_create_context()\n");
       
   192 
       
   193 	bRenderingEnabled = true;
       
   194 
       
   195     mEnv->CallStaticVoidMethod(mActivityInstance, midCreateGLContext ); 
       
   196 }
       
   197 
       
   198 extern "C" void Android_Render(){
       
   199 
       
   200     if(!bRenderingEnabled){
       
   201         return;
       
   202     }
       
   203 
       
   204     //When we get here, we've accumulated a full frame    
       
   205     mEnv->CallStaticVoidMethod(mActivityInstance, midFlipBuffers ); 
       
   206 }
       
   207 
       
   208 extern "C" void Android_EnableFeature(int featureid, bool enabled){
       
   209 
       
   210     mEnv->CallStaticVoidMethod(mActivityInstance, midEnableFeature, 
       
   211                                 featureid, (int)enabled); 
       
   212 }
       
   213 
       
   214 extern "C" void Android_UpdateAudioBuffer(unsigned char *buf, int len){
       
   215 
       
   216     //Annoyingly we can't just call into Java from any thread. Because the audio
       
   217     //callback is dispatched from the SDL audio thread (that wasn't made from
       
   218     //java, we have to do some magic here to let the JVM know about the thread.
       
   219     //Because everything it touches on the Java side is static anyway, it's 
       
   220     //not a big deal, just annoying.
       
   221     if(!mAudioThreadEnv){
       
   222         __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: Need to set up audio thread env\n");
       
   223 
       
   224         mVM->AttachCurrentThread(&mAudioThreadEnv, NULL);
       
   225 
       
   226         __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: ok\n");
       
   227     }
       
   228     
       
   229     jbyteArray arr = mAudioThreadEnv->NewByteArray(len);
       
   230 
       
   231     //blah. We probably should rework this so we avoid the copy. 
       
   232     mAudioThreadEnv->SetByteArrayRegion(arr, 0, len, (jbyte *)buf);
       
   233     
       
   234     __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: copied\n");
       
   235 
       
   236     mAudioThreadEnv->CallStaticVoidMethod(  mActivityInstance, 
       
   237                                             midUpdateAudio, arr );
       
   238 
       
   239     __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: invoked\n");
       
   240     
       
   241 }
       
   242