4726
|
1 package org.libsdl.app;
|
|
2
|
|
3 import javax.microedition.khronos.egl.EGLConfig;
|
|
4 import javax.microedition.khronos.opengles.GL10;
|
|
5 import javax.microedition.khronos.egl.*;
|
|
6
|
|
7 import android.app.*;
|
|
8 import android.content.*;
|
|
9 import android.view.*;
|
|
10 import android.os.*;
|
|
11 import android.util.Log;
|
|
12 import android.graphics.*;
|
|
13 import android.text.method.*;
|
|
14 import android.text.*;
|
|
15 import android.media.*;
|
|
16 import android.hardware.*;
|
|
17 import android.content.*;
|
|
18
|
|
19 import java.lang.*;
|
|
20
|
|
21
|
|
22 /**
|
|
23 SDL Activity
|
|
24 */
|
|
25 public class SDLActivity extends Activity {
|
|
26
|
|
27 //Main components
|
|
28 private static SDLActivity mSingleton;
|
|
29 private static SDLSurface mSurface;
|
|
30
|
|
31 //Audio
|
|
32 private static AudioTrack mAudioTrack;
|
|
33 private static boolean bAudioIsEnabled;
|
|
34
|
|
35 //Sensors
|
|
36 private static boolean bAccelIsEnabled;
|
|
37
|
|
38 //feature IDs. Must match up on the C side as well.
|
|
39 private static int FEATURE_AUDIO = 1;
|
|
40 private static int FEATURE_ACCEL = 2;
|
|
41
|
|
42 //Load the .so
|
|
43 static {
|
|
44 System.loadLibrary("sdlapp");
|
|
45 }
|
|
46
|
|
47 //Setup
|
|
48 protected void onCreate(Bundle savedInstanceState) {
|
|
49 super.onCreate(savedInstanceState);
|
|
50
|
|
51 //So we can call stuff from static callbacks
|
|
52 mSingleton = this;
|
|
53
|
|
54 //Set up the surface
|
|
55 mSurface = new SDLSurface(getApplication());
|
|
56 setContentView(mSurface);
|
|
57 SurfaceHolder holder = mSurface.getHolder();
|
|
58 holder.setType(SurfaceHolder.SURFACE_TYPE_GPU);
|
|
59
|
|
60 }
|
|
61
|
|
62 //Audio
|
|
63 public static boolean initAudio(){
|
|
64
|
|
65 //blah. Hardcoded things are bad. FIXME when we have more sound stuff
|
|
66 //working properly.
|
|
67 mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
|
|
68 11025,
|
|
69 AudioFormat.CHANNEL_CONFIGURATION_MONO,
|
|
70 AudioFormat.ENCODING_PCM_8BIT,
|
|
71 2048,
|
|
72 AudioTrack.MODE_STREAM);
|
|
73 bAudioIsEnabled = true;
|
|
74 return true;
|
|
75 }
|
|
76
|
|
77 //Accel
|
|
78 public static boolean initAccel(){
|
|
79 mSurface.enableSensor(Sensor.TYPE_ACCELEROMETER, true);
|
|
80 bAccelIsEnabled = true;
|
|
81 return true;
|
|
82 }
|
|
83
|
|
84 public static boolean closeAccel(){
|
|
85 mSurface.enableSensor(Sensor.TYPE_ACCELEROMETER, false);
|
|
86 bAccelIsEnabled = false;
|
|
87 return true;
|
|
88 }
|
|
89
|
|
90
|
|
91 //Events
|
|
92 protected void onPause() {
|
|
93 super.onPause();
|
|
94 }
|
|
95
|
|
96 protected void onResume() {
|
|
97 super.onResume();
|
|
98 }
|
|
99
|
|
100
|
|
101
|
|
102
|
|
103
|
|
104 //C functions we call
|
|
105 public static native void nativeInit();
|
|
106 public static native void nativeQuit();
|
|
107 public static native void nativeSetScreenSize(int width, int height);
|
|
108 public static native void onNativeKeyDown(int keycode);
|
|
109 public static native void onNativeKeyUp(int keycode);
|
|
110 public static native void onNativeTouch(int action, float x,
|
|
111 float y, float p);
|
|
112 public static native void onNativeResize(int x, int y, int format);
|
|
113 public static native void onNativeAccel(float x, float y, float z);
|
|
114
|
|
115
|
|
116
|
|
117 //Java functions called from C
|
|
118 private static void createGLContext(){
|
|
119 mSurface.initEGL();
|
|
120 }
|
|
121
|
|
122 public static void flipBuffers(){
|
|
123 mSurface.flipEGL();
|
|
124 }
|
|
125
|
|
126 public static void updateAudio(byte [] buf){
|
|
127
|
|
128 if(mAudioTrack == null){
|
|
129 return;
|
|
130 }
|
|
131
|
|
132 mAudioTrack.write(buf, 0, buf.length);
|
|
133 mAudioTrack.play();
|
|
134
|
|
135 Log.v("SDL","Played some audio");
|
|
136 }
|
|
137
|
|
138 public static void enableFeature(int featureid, int enabled){
|
|
139 Log.v("SDL","Feature " + featureid + " = " + enabled);
|
|
140
|
|
141 //Yuck. This is all horribly inelegent. If it gets to more than a few
|
|
142 //'features' I'll rip this out and make something nicer, I promise :)
|
|
143 if(featureid == FEATURE_AUDIO){
|
|
144 if(enabled == 1){
|
|
145 initAudio();
|
|
146 }else{
|
|
147 //We don't have one of these yet...
|
|
148 //closeAudio();
|
|
149 }
|
|
150 }
|
|
151
|
|
152 else if(featureid == FEATURE_ACCEL){
|
|
153 if(enabled == 1){
|
|
154 initAccel();
|
|
155 }else{
|
|
156 closeAccel();
|
|
157 }
|
|
158 }
|
|
159 }
|
|
160
|
|
161
|
|
162
|
|
163
|
|
164
|
|
165
|
|
166
|
|
167 }
|
|
168
|
|
169 /**
|
|
170 Simple nativeInit() runnable
|
|
171 */
|
|
172 class SDLRunner implements Runnable{
|
|
173 public void run(){
|
|
174 //SDLActivity.initAudio();
|
|
175
|
|
176 //Runs SDL_main()
|
|
177 SDLActivity.nativeInit();
|
|
178
|
|
179 Log.v("SDL","SDL thread terminated");
|
|
180 }
|
|
181 }
|
|
182
|
|
183
|
|
184 /**
|
|
185 SDLSurface. This is what we draw on, so we need to know when it's created
|
|
186 in order to do anything useful.
|
|
187
|
|
188 Because of this, that's where we set up the SDL thread
|
|
189 */
|
|
190 class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
|
|
191 View.OnKeyListener, View.OnTouchListener, SensorEventListener {
|
|
192
|
|
193 //This is what SDL runs in. It invokes SDL_main(), eventually
|
|
194 private Thread mSDLThread;
|
|
195
|
|
196 //EGL private objects
|
|
197 private EGLContext mEGLContext;
|
|
198 private EGLSurface mEGLSurface;
|
|
199 private EGLDisplay mEGLDisplay;
|
|
200
|
|
201 //Sensors
|
|
202 private static SensorManager mSensorManager;
|
|
203
|
|
204 //Startup
|
|
205 public SDLSurface(Context context) {
|
|
206 super(context);
|
|
207 getHolder().addCallback(this);
|
|
208
|
|
209 setFocusable(true);
|
|
210 setFocusableInTouchMode(true);
|
|
211 requestFocus();
|
|
212 setOnKeyListener(this);
|
|
213 setOnTouchListener(this);
|
|
214
|
|
215 mSensorManager = (SensorManager)context.getSystemService("sensor");
|
|
216 }
|
|
217
|
|
218 //Called when we have a valid drawing surface
|
|
219 public void surfaceCreated(SurfaceHolder holder) {
|
|
220 Log.v("SDL","Surface created");
|
|
221
|
|
222 int width = getWidth();
|
|
223 int height = getHeight();
|
|
224
|
|
225 //Set the width and height variables in C before we start SDL so we have
|
|
226 //it available on init
|
|
227 SDLActivity.nativeSetScreenSize(width, height);
|
|
228
|
|
229 //Now start up the C app thread
|
|
230 mSDLThread = new Thread(new SDLRunner(), "SDLThread");
|
|
231 mSDLThread.start();
|
|
232 }
|
|
233
|
|
234 //Called when we lose the surface
|
|
235 public void surfaceDestroyed(SurfaceHolder holder) {
|
|
236 Log.v("SDL","Surface destroyed");
|
|
237
|
|
238 SDLActivity.nativeQuit();
|
|
239
|
|
240 //Now wait for the SDL thread to quit
|
|
241 try{
|
|
242 mSDLThread.wait();
|
|
243 }catch(Exception e){
|
|
244 Log.v("SDL","Problem stopping thread: " + e);
|
|
245 }
|
|
246 }
|
|
247
|
|
248 //Called when the surface is resized
|
|
249 public void surfaceChanged(SurfaceHolder holder, int format,
|
|
250 int width, int height) {
|
|
251 Log.v("SDL","Surface resized");
|
|
252
|
|
253 SDLActivity.onNativeResize(width, height, format);
|
|
254 }
|
|
255
|
|
256 //unused
|
|
257 public void onDraw(Canvas canvas) {}
|
|
258
|
|
259
|
|
260 //EGL functions
|
|
261 public boolean initEGL(){
|
|
262 Log.v("SDL","Starting up");
|
|
263
|
|
264 try{
|
|
265
|
|
266 EGL10 egl = (EGL10)EGLContext.getEGL();
|
|
267
|
|
268 EGLDisplay dpy = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
|
|
269
|
|
270 int[] version = new int[2];
|
|
271 egl.eglInitialize(dpy, version);
|
|
272
|
|
273 int[] configSpec = {
|
|
274 //EGL10.EGL_DEPTH_SIZE, 16,
|
|
275 EGL10.EGL_NONE
|
|
276 };
|
|
277 EGLConfig[] configs = new EGLConfig[1];
|
|
278 int[] num_config = new int[1];
|
|
279 egl.eglChooseConfig(dpy, configSpec, configs, 1, num_config);
|
|
280 EGLConfig config = configs[0];
|
|
281
|
|
282 EGLContext ctx = egl.eglCreateContext(dpy, config, EGL10.EGL_NO_CONTEXT, null);
|
|
283
|
|
284 EGLSurface surface = egl.eglCreateWindowSurface(dpy, config, this, null);
|
|
285
|
|
286 egl.eglMakeCurrent(dpy, surface, surface, ctx);
|
|
287
|
|
288 mEGLContext = ctx;
|
|
289 mEGLDisplay = dpy;
|
|
290 mEGLSurface = surface;
|
|
291
|
|
292
|
|
293 }catch(Exception e){
|
|
294 Log.v("SDL", e + "");
|
|
295 for(StackTraceElement s : e.getStackTrace()){
|
|
296 Log.v("SDL", s.toString());
|
|
297 }
|
|
298 }
|
|
299 Log.v("SDL","Done making!");
|
|
300
|
|
301 return true;
|
|
302 }
|
|
303
|
|
304 //EGL buffer flip
|
|
305 public void flipEGL(){
|
|
306 try{
|
|
307
|
|
308 EGL10 egl = (EGL10)EGLContext.getEGL();
|
|
309 GL10 gl = (GL10)mEGLContext.getGL();
|
|
310
|
|
311 egl.eglWaitNative(EGL10.EGL_NATIVE_RENDERABLE, null);
|
|
312
|
|
313 //drawing here
|
|
314
|
|
315 egl.eglWaitGL();
|
|
316
|
|
317 egl.eglSwapBuffers(mEGLDisplay, mEGLSurface);
|
|
318
|
|
319
|
|
320 }catch(Exception e){
|
|
321 Log.v("SDL", "flipEGL(): " + e);
|
|
322
|
|
323 for(StackTraceElement s : e.getStackTrace()){
|
|
324 Log.v("SDL", s.toString());
|
|
325 }
|
|
326 }
|
|
327 }
|
|
328
|
|
329
|
|
330
|
|
331 //Key events
|
|
332 public boolean onKey(View v, int keyCode, KeyEvent event){
|
|
333
|
|
334 if(event.getAction() == KeyEvent.ACTION_DOWN){
|
|
335 SDLActivity.onNativeKeyDown(keyCode);
|
|
336 return true;
|
|
337 }
|
|
338
|
|
339 else if(event.getAction() == KeyEvent.ACTION_UP){
|
|
340 SDLActivity.onNativeKeyUp(keyCode);
|
|
341 return true;
|
|
342 }
|
|
343
|
|
344 return false;
|
|
345 }
|
|
346
|
|
347 //Touch events
|
|
348 public boolean onTouch(View v, MotionEvent event){
|
|
349
|
|
350 int action = event.getAction();
|
|
351 float x = event.getX();
|
|
352 float y = event.getY();
|
|
353 float p = event.getPressure();
|
|
354
|
|
355 //TODO: Anything else we need to pass?
|
|
356 SDLActivity.onNativeTouch(action, x, y, p);
|
|
357 return true;
|
|
358 }
|
|
359
|
|
360 //Sensor events
|
|
361 public void enableSensor(int sensortype, boolean enabled){
|
|
362 //TODO: This uses getDefaultSensor - what if we have >1 accels?
|
|
363 if(enabled){
|
|
364 mSensorManager.registerListener(this,
|
|
365 mSensorManager.getDefaultSensor(sensortype),
|
|
366 SensorManager.SENSOR_DELAY_GAME, null);
|
|
367 }else{
|
|
368 mSensorManager.unregisterListener(this,
|
|
369 mSensorManager.getDefaultSensor(sensortype));
|
|
370 }
|
|
371 }
|
|
372
|
|
373 public void onAccuracyChanged(Sensor sensor, int accuracy){
|
|
374 //TODO
|
|
375 }
|
|
376
|
|
377 public void onSensorChanged(SensorEvent event){
|
|
378 if(event.sensor.getType() == Sensor.TYPE_ACCELEROMETER){
|
|
379 SDLActivity.onNativeAccel( event.values[0],
|
|
380 event.values[1],
|
|
381 event.values[2] );
|
|
382 }
|
|
383 }
|
|
384
|
|
385
|
|
386 }
|
|
387
|
|
388
|