author | Sam Lantinga <slouken@libsdl.org> |
Tue, 04 Jan 2011 15:25:49 -0800 | |
changeset 4957 | 5e42031a8d70 |
parent 4953 | 4f40b11e1045 |
permissions | -rw-r--r-- |
4726 | 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 |
||
4953
4f40b11e1045
Fixed prototype for SDL_main()
Sam Lantinga <slouken@libsdl.org>
parents:
4726
diff
changeset
|
39 |
extern "C" int SDL_main(int argc, char *argv[]); |
4726 | 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 |
||
4957
5e42031a8d70
Need to set something valid for argc/argv
Sam Lantinga <slouken@libsdl.org>
parents:
4953
diff
changeset
|
106 |
char *argv[2]; |
5e42031a8d70
Need to set something valid for argc/argv
Sam Lantinga <slouken@libsdl.org>
parents:
4953
diff
changeset
|
107 |
argv[0] = strdup("SDL_app"); |
5e42031a8d70
Need to set something valid for argc/argv
Sam Lantinga <slouken@libsdl.org>
parents:
4953
diff
changeset
|
108 |
argv[1] = NULL; |
5e42031a8d70
Need to set something valid for argc/argv
Sam Lantinga <slouken@libsdl.org>
parents:
4953
diff
changeset
|
109 |
SDL_main(1, argv); |
4726 | 110 |
} |
111 |
||
112 |
//Keydown |
|
113 |
extern "C" void Java_org_libsdl_app_SDLActivity_onNativeKeyDown(JNIEnv* env, |
|
114 |
jobject obj, jint keycode){ |
|
115 |
||
116 |
int r = Android_OnKeyDown(keycode); |
|
117 |
#ifdef DEBUG |
|
118 |
__android_log_print(ANDROID_LOG_INFO, "SDL", |
|
119 |
"SDL: native key down %d, %d\n", keycode, r); |
|
120 |
#endif |
|
121 |
||
122 |
} |
|
123 |
||
124 |
//Keyup |
|
125 |
extern "C" void Java_org_libsdl_app_SDLActivity_onNativeKeyUp(JNIEnv* env, |
|
126 |
jobject obj, jint keycode){ |
|
127 |
||
128 |
int r = Android_OnKeyUp(keycode); |
|
129 |
#ifdef DEBUG |
|
130 |
__android_log_print(ANDROID_LOG_INFO, "SDL", |
|
131 |
"SDL: native key up %d, %d\n", keycode, r); |
|
132 |
#endif |
|
133 |
||
134 |
} |
|
135 |
||
136 |
//Touch |
|
137 |
extern "C" void Java_org_libsdl_app_SDLActivity_onNativeTouch(JNIEnv* env, |
|
138 |
jobject obj, jint action, jfloat x, jfloat y, jfloat p){ |
|
139 |
||
140 |
#ifdef DEBUG |
|
141 |
__android_log_print(ANDROID_LOG_INFO, "SDL", |
|
142 |
"SDL: native touch event %d @ %f/%f, pressure %f\n", |
|
143 |
action, x, y, p); |
|
144 |
#endif |
|
145 |
||
146 |
//TODO: Pass this off to the SDL multitouch stuff |
|
147 |
||
148 |
} |
|
149 |
||
150 |
//Quit |
|
151 |
extern "C" void Java_org_libsdl_app_SDLActivity_nativeQuit( JNIEnv* env, |
|
152 |
jobject obj ){ |
|
153 |
||
154 |
//Stop rendering as we're no longer in the foreground |
|
155 |
bRenderingEnabled = false; |
|
156 |
||
157 |
//Inject a SDL_QUIT event |
|
158 |
int r = SDL_SendQuit(); |
|
159 |
||
160 |
__android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: Native quit %d", r); |
|
161 |
} |
|
162 |
||
163 |
//Screen size |
|
164 |
extern "C" void Java_org_libsdl_app_SDLActivity_nativeSetScreenSize( |
|
165 |
JNIEnv* env, jobject obj, jint width, jint height){ |
|
166 |
||
167 |
__android_log_print(ANDROID_LOG_INFO, "SDL", |
|
168 |
"SDL: Set screen size on init: %d/%d\n", width, height); |
|
169 |
Android_SetScreenResolution(width, height); |
|
170 |
||
171 |
} |
|
172 |
||
173 |
//Resize |
|
174 |
extern "C" void Java_org_libsdl_app_SDLActivity_onNativeResize( |
|
175 |
JNIEnv* env, jobject obj, jint width, |
|
176 |
jint height, jint format){ |
|
177 |
Android_OnResize(width, height, format); |
|
178 |
} |
|
179 |
||
180 |
extern "C" void Java_org_libsdl_app_SDLActivity_onNativeAccel( |
|
181 |
JNIEnv* env, jobject obj, |
|
182 |
jfloat x, jfloat y, jfloat z){ |
|
183 |
fLastAccelerometer[0] = x; |
|
184 |
fLastAccelerometer[1] = y; |
|
185 |
fLastAccelerometer[2] = z; |
|
186 |
} |
|
187 |
||
188 |
||
189 |
||
190 |
/******************************************************************************* |
|
191 |
Functions called by SDL into Java |
|
192 |
*******************************************************************************/ |
|
193 |
extern "C" void Android_CreateContext(){ |
|
194 |
__android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: sdl_create_context()\n"); |
|
195 |
||
196 |
bRenderingEnabled = true; |
|
197 |
||
198 |
mEnv->CallStaticVoidMethod(mActivityInstance, midCreateGLContext ); |
|
199 |
} |
|
200 |
||
201 |
extern "C" void Android_Render(){ |
|
202 |
||
203 |
if(!bRenderingEnabled){ |
|
204 |
return; |
|
205 |
} |
|
206 |
||
207 |
//When we get here, we've accumulated a full frame |
|
208 |
mEnv->CallStaticVoidMethod(mActivityInstance, midFlipBuffers ); |
|
209 |
} |
|
210 |
||
211 |
extern "C" void Android_EnableFeature(int featureid, bool enabled){ |
|
212 |
||
213 |
mEnv->CallStaticVoidMethod(mActivityInstance, midEnableFeature, |
|
214 |
featureid, (int)enabled); |
|
215 |
} |
|
216 |
||
217 |
extern "C" void Android_UpdateAudioBuffer(unsigned char *buf, int len){ |
|
218 |
||
219 |
//Annoyingly we can't just call into Java from any thread. Because the audio |
|
220 |
//callback is dispatched from the SDL audio thread (that wasn't made from |
|
221 |
//java, we have to do some magic here to let the JVM know about the thread. |
|
222 |
//Because everything it touches on the Java side is static anyway, it's |
|
223 |
//not a big deal, just annoying. |
|
224 |
if(!mAudioThreadEnv){ |
|
225 |
__android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: Need to set up audio thread env\n"); |
|
226 |
||
227 |
mVM->AttachCurrentThread(&mAudioThreadEnv, NULL); |
|
228 |
||
229 |
__android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: ok\n"); |
|
230 |
} |
|
231 |
||
232 |
jbyteArray arr = mAudioThreadEnv->NewByteArray(len); |
|
233 |
||
234 |
//blah. We probably should rework this so we avoid the copy. |
|
235 |
mAudioThreadEnv->SetByteArrayRegion(arr, 0, len, (jbyte *)buf); |
|
236 |
||
237 |
__android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: copied\n"); |
|
238 |
||
239 |
mAudioThreadEnv->CallStaticVoidMethod( mActivityInstance, |
|
240 |
midUpdateAudio, arr ); |
|
241 |
||
242 |
__android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: invoked\n"); |
|
243 |
||
244 |
} |
|
245 |