1 /*************************************************************************/
2 /* godot_android.cpp */
3 /*************************************************************************/
4 /* This file is part of: */
5 /* GODOT ENGINE */
6 /* https://godotengine.org */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
9 /* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
10 /* */
11 /* Permission is hereby granted, free of charge, to any person obtaining */
12 /* a copy of this software and associated documentation files (the */
13 /* "Software"), to deal in the Software without restriction, including */
14 /* without limitation the rights to use, copy, modify, merge, publish, */
15 /* distribute, sublicense, and/or sell copies of the Software, and to */
16 /* permit persons to whom the Software is furnished to do so, subject to */
17 /* the following conditions: */
18 /* */
19 /* The above copyright notice and this permission notice shall be */
20 /* included in all copies or substantial portions of the Software. */
21 /* */
22 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
25 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29 /*************************************************************************/
30 #ifdef ANDROID_NATIVE_ACTIVITY
31
32 #include <errno.h>
33 #include <jni.h>
34
35 #include <EGL/egl.h>
36 #include <GLES2/gl2.h>
37
38 #include "file_access_android.h"
39 #include "globals.h"
40 #include "main/main.h"
41 #include "os_android.h"
42 #include <android/log.h>
43 #include <android/sensor.h>
44 #include <android/window.h>
45 #include <android_native_app_glue.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <unistd.h>
49 #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "godot", __VA_ARGS__))
50 #define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "godot", __VA_ARGS__))
51
52 extern "C" {
53 JNIEXPORT void JNICALL Java_org_godotengine_godot_Godot_registerSingleton(JNIEnv *env, jobject obj, jstring name, jobject p_object);
54 JNIEXPORT void JNICALL Java_org_godotengine_godot_Godot_registerMethod(JNIEnv *env, jobject obj, jstring sname, jstring name, jstring ret, jobjectArray args);
55 JNIEXPORT jstring JNICALL Java_org_godotengine_godot_Godot_getGlobal(JNIEnv *env, jobject obj, jstring path);
56 };
57
58 class JNISingleton : public Object {
59
60 OBJ_TYPE(JNISingleton, Object);
61
62 struct MethodData {
63
64 jmethodID method;
65 Variant::Type ret_type;
66 Vector<Variant::Type> argtypes;
67 };
68
69 jobject instance;
70 Map<StringName, MethodData> method_map;
71 JNIEnv *env;
72
73 public:
update_env(JNIEnv * p_env)74 void update_env(JNIEnv *p_env) { env = p_env; }
75
call(const StringName & p_method,const Variant ** p_args,int p_argcount,Variant::CallError & r_error)76 virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error) {
77
78 r_error.error = Variant::CallError::CALL_OK;
79
80 Map<StringName, MethodData>::Element *E = method_map.find(p_method);
81 if (!E) {
82
83 r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD;
84 return Variant();
85 }
86
87 int ac = E->get().argtypes.size();
88 if (ac < p_argcount) {
89
90 r_error.error = Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
91 r_error.argument = ac;
92 return Variant();
93 }
94
95 if (ac > p_argcount) {
96
97 r_error.error = Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
98 r_error.argument = ac;
99 return Variant();
100 }
101
102 for (int i = 0; i < p_argcount; i++) {
103
104 if (!Variant::can_convert(p_args[i]->get_type(), E->get().argtypes[i])) {
105
106 r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
107 r_error.argument = i;
108 r_error.expected = E->get().argtypes[i];
109 }
110 }
111
112 jvalue *v = NULL;
113
114 if (p_argcount) {
115
116 v = (jvalue *)alloca(sizeof(jvalue) * p_argcount);
117 }
118
119 for (int i = 0; i < p_argcount; i++) {
120
121 switch (E->get().argtypes[i]) {
122
123 case Variant::BOOL: {
124
125 v[i].z = *p_args[i];
126 } break;
127 case Variant::INT: {
128
129 v[i].i = *p_args[i];
130 } break;
131 case Variant::REAL: {
132
133 v[i].f = *p_args[i];
134 } break;
135 case Variant::STRING: {
136
137 String s = *p_args[i];
138 jstring jStr = env->NewStringUTF(s.utf8().get_data());
139 v[i].l = jStr;
140 } break;
141 case Variant::STRING_ARRAY: {
142
143 DVector<String> sarray = *p_args[i];
144 jobjectArray arr = env->NewObjectArray(sarray.size(), env->FindClass("java/lang/String"), env->NewStringUTF(""));
145
146 for (int j = 0; j < sarray.size(); j++) {
147
148 env->SetObjectArrayElement(arr, j, env->NewStringUTF(sarray[i].utf8().get_data()));
149 }
150 v[i].l = arr;
151
152 } break;
153 case Variant::INT_ARRAY: {
154
155 DVector<int> array = *p_args[i];
156 jintArray arr = env->NewIntArray(array.size());
157 DVector<int>::Read r = array.read();
158 env->SetIntArrayRegion(arr, 0, array.size(), r.ptr());
159 v[i].l = arr;
160
161 } break;
162 case Variant::REAL_ARRAY: {
163
164 DVector<float> array = *p_args[i];
165 jfloatArray arr = env->NewFloatArray(array.size());
166 DVector<float>::Read r = array.read();
167 env->SetFloatArrayRegion(arr, 0, array.size(), r.ptr());
168 v[i].l = arr;
169
170 } break;
171 default: {
172
173 ERR_FAIL_V(Variant());
174 } break;
175 }
176 }
177
178 Variant ret;
179
180 switch (E->get().ret_type) {
181
182 case Variant::NIL: {
183
184 env->CallVoidMethodA(instance, E->get().method, v);
185 } break;
186 case Variant::BOOL: {
187
188 ret = env->CallBooleanMethodA(instance, E->get().method, v);
189 } break;
190 case Variant::INT: {
191
192 ret = env->CallIntMethodA(instance, E->get().method, v);
193 } break;
194 case Variant::REAL: {
195
196 ret = env->CallFloatMethodA(instance, E->get().method, v);
197 } break;
198 case Variant::STRING: {
199
200 jobject o = env->CallObjectMethodA(instance, E->get().method, v);
201 String singname = env->GetStringUTFChars((jstring)o, NULL);
202 } break;
203 case Variant::STRING_ARRAY: {
204
205 jobjectArray arr = (jobjectArray)env->CallObjectMethodA(instance, E->get().method, v);
206
207 int stringCount = env->GetArrayLength(arr);
208 DVector<String> sarr;
209
210 for (int i = 0; i < stringCount; i++) {
211 jstring string = (jstring)env->GetObjectArrayElement(arr, i);
212 const char *rawString = env->GetStringUTFChars(string, 0);
213 sarr.push_back(String(rawString));
214 }
215
216 ret = sarr;
217
218 } break;
219 case Variant::INT_ARRAY: {
220
221 jintArray arr = (jintArray)env->CallObjectMethodA(instance, E->get().method, v);
222
223 int fCount = env->GetArrayLength(arr);
224 DVector<int> sarr;
225 sarr.resize(fCount);
226
227 DVector<int>::Write w = sarr.write();
228 env->GetIntArrayRegion(arr, 0, fCount, w.ptr());
229 w = DVector<int>::Write();
230 ret = sarr;
231 } break;
232 case Variant::REAL_ARRAY: {
233
234 jfloatArray arr = (jfloatArray)env->CallObjectMethodA(instance, E->get().method, v);
235
236 int fCount = env->GetArrayLength(arr);
237 DVector<float> sarr;
238 sarr.resize(fCount);
239
240 DVector<float>::Write w = sarr.write();
241 env->GetFloatArrayRegion(arr, 0, fCount, w.ptr());
242 w = DVector<float>::Write();
243 ret = sarr;
244 } break;
245 default: {
246
247 ERR_FAIL_V(Variant());
248 } break;
249 }
250
251 return ret;
252 }
253
get_instance() const254 jobject get_instance() const {
255
256 return instance;
257 }
set_instance(jobject p_instance)258 void set_instance(jobject p_instance) {
259
260 instance = p_instance;
261 }
262
add_method(const StringName & p_name,jmethodID p_method,const Vector<Variant::Type> & p_args,Variant::Type p_ret_type)263 void add_method(const StringName &p_name, jmethodID p_method, const Vector<Variant::Type> &p_args, Variant::Type p_ret_type) {
264
265 MethodData md;
266 md.method = p_method;
267 md.argtypes = p_args;
268 md.ret_type = p_ret_type;
269 method_map[p_name] = md;
270 }
271
JNISingleton()272 JNISingleton() {}
273 };
274
275 //JNIEnv *JNISingleton::env=NULL;
276
277 static HashMap<String, JNISingleton *> jni_singletons;
278
279 struct engine {
280 struct android_app *app;
281 OS_Android *os;
282 JNIEnv *jni;
283
284 ASensorManager *sensorManager;
285 const ASensor *accelerometerSensor;
286 const ASensor *gravitySensor;
287 const ASensor *magnetometerSensor;
288 const ASensor *gyroscopeSensor;
289 ASensorEventQueue *sensorEventQueue;
290
291 bool display_active;
292 bool requested_quit;
293 int animating;
294 EGLDisplay display;
295 EGLSurface surface;
296 EGLContext context;
297 int32_t width;
298 int32_t height;
299 };
300
301 /**
302 * Initialize an EGL context for the current display.
303 */
engine_init_display(struct engine * engine,bool p_gl2)304 static int engine_init_display(struct engine *engine, bool p_gl2) {
305 // initialize OpenGL ES and EGL
306
307 /*
308 * Here specify the attributes of the desired configuration.
309 * Below, we select an EGLConfig with at least 8 bits per color
310 * component compatible with on-screen windows
311 */
312 const EGLint gl2_attribs[] = {
313 // EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
314 EGL_BLUE_SIZE, 4,
315 EGL_GREEN_SIZE, 4,
316 EGL_RED_SIZE, 4,
317 EGL_ALPHA_SIZE, 0,
318 EGL_DEPTH_SIZE, 16,
319 EGL_STENCIL_SIZE, EGL_DONT_CARE,
320 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
321 EGL_NONE
322 };
323
324 const EGLint gl1_attribs[] = {
325 // EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
326 EGL_BLUE_SIZE, 4,
327 EGL_GREEN_SIZE, 4,
328 EGL_RED_SIZE, 4,
329 EGL_ALPHA_SIZE, 0,
330 EGL_DEPTH_SIZE, 16,
331 EGL_STENCIL_SIZE, EGL_DONT_CARE,
332 EGL_NONE
333 };
334
335 const EGLint *attribs = p_gl2 ? gl2_attribs : gl1_attribs;
336
337 EGLint w, h, dummy, format;
338 EGLint numConfigs;
339 EGLConfig config;
340 EGLSurface surface;
341 EGLContext context;
342
343 EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
344
345 eglInitialize(display, 0, 0);
346
347 /* Here, the application chooses the configuration it desires. In this
348 * sample, we have a very simplified selection process, where we pick
349 * the first EGLConfig that matches our criteria */
350
351 eglChooseConfig(display, attribs, &config, 1, &numConfigs);
352
353 LOGI("Num configs: %i\n", numConfigs);
354
355 /* EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is
356 * guaranteed to be accepted by ANativeWindow_setBuffersGeometry().
357 * As soon as we picked a EGLConfig, we can safely reconfigure the
358 * ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID. */
359 eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format);
360
361 ANativeWindow_setBuffersGeometry(engine->app->window, 0, 0, format);
362 //ANativeWindow_setFlags(engine->app->window, 0, 0, format|);
363
364 surface = eglCreateWindowSurface(display, config, engine->app->window, NULL);
365
366 const EGLint context_attribs[] = {
367 EGL_CONTEXT_CLIENT_VERSION, 2,
368 EGL_NONE
369 };
370 context = eglCreateContext(display, config, EGL_NO_CONTEXT, p_gl2 ? context_attribs : NULL);
371
372 if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) {
373 LOGW("Unable to eglMakeCurrent");
374 return -1;
375 }
376
377 eglQuerySurface(display, surface, EGL_WIDTH, &w);
378 eglQuerySurface(display, surface, EGL_HEIGHT, &h);
379
380 //engine->os->set_egl_extensions(eglQueryString(display,EGL_EXTENSIONS));
381 engine->os->init_video_mode(w, h);
382
383 engine->display = display;
384 engine->context = context;
385 engine->surface = surface;
386 engine->width = w;
387 engine->height = h;
388 engine->display_active = true;
389
390 //engine->state.angle = 0;
391
392 // Initialize GL state.
393 //glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
394 glEnable(GL_CULL_FACE);
395 // glShadeModel(GL_SMOOTH);
396 glDisable(GL_DEPTH_TEST);
397 LOGI("GL Version: %s - %s %s\n", glGetString(GL_VERSION), glGetString(GL_VENDOR), glGetString(GL_RENDERER));
398
399 return 0;
400 }
401
engine_draw_frame(struct engine * engine)402 static void engine_draw_frame(struct engine *engine) {
403 if (engine->display == NULL) {
404 // No display.
405 return;
406 }
407
408 // Just fill the screen with a color.
409 //glClearColor(0,1,0,1);
410 //glClear(GL_COLOR_BUFFER_BIT);
411 if (engine->os && engine->os->main_loop_iterate() == true) {
412
413 engine->requested_quit = true;
414 return; //should exit instead
415 }
416
417 eglSwapBuffers(engine->display, engine->surface);
418 }
419
engine_term_display(struct engine * engine)420 static void engine_term_display(struct engine *engine) {
421 if (engine->display != EGL_NO_DISPLAY) {
422 eglMakeCurrent(engine->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
423 if (engine->context != EGL_NO_CONTEXT) {
424 eglDestroyContext(engine->display, engine->context);
425 }
426 if (engine->surface != EGL_NO_SURFACE) {
427 eglDestroySurface(engine->display, engine->surface);
428 }
429 eglTerminate(engine->display);
430 }
431
432 engine->animating = 0;
433 engine->display = EGL_NO_DISPLAY;
434 engine->context = EGL_NO_CONTEXT;
435 engine->surface = EGL_NO_SURFACE;
436 engine->display_active = false;
437 }
438
439 /**
440 * Process the next input event.
441 */
engine_handle_input(struct android_app * app,AInputEvent * event)442 static int32_t engine_handle_input(struct android_app *app, AInputEvent *event) {
443 struct engine *engine = (struct engine *)app->userData;
444
445 if (!engine->os)
446 return 0;
447
448 switch (AInputEvent_getType(event)) {
449
450 case AINPUT_EVENT_TYPE_KEY: {
451
452 int ac = AKeyEvent_getAction(event);
453 switch (ac) {
454
455 case AKEY_EVENT_ACTION_DOWN: {
456
457 int32_t code = AKeyEvent_getKeyCode(event);
458 if (code == AKEYCODE_BACK) {
459
460 //AInputQueue_finishEvent(AInputQueue* queue, AInputEvent* event, int handled);
461 if (engine->os)
462 engine->os->main_loop_request_quit();
463 return 1;
464 }
465
466 } break;
467 case AKEY_EVENT_ACTION_UP: {
468
469 } break;
470 }
471
472 } break;
473 case AINPUT_EVENT_TYPE_MOTION: {
474
475 Vector<OS_Android::TouchPos> touchvec;
476
477 int pc = AMotionEvent_getPointerCount(event);
478
479 touchvec.resize(pc);
480
481 for (int i = 0; i < pc; i++) {
482
483 touchvec[i].pos.x = AMotionEvent_getX(event, i);
484 touchvec[i].pos.y = AMotionEvent_getY(event, i);
485 touchvec[i].id = AMotionEvent_getPointerId(event, i);
486 }
487
488 //System.out.printf("gaction: %d\n",event.getAction());
489 int pidx = (AMotionEvent_getAction(event) & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> 8;
490 switch (AMotionEvent_getAction(event) & AMOTION_EVENT_ACTION_MASK) {
491
492 case AMOTION_EVENT_ACTION_DOWN: {
493 engine->os->process_touch(0, 0, touchvec);
494
495 //System.out.printf("action down at: %f,%f\n", event.getX(),event.getY());
496 } break;
497 case AMOTION_EVENT_ACTION_MOVE: {
498 engine->os->process_touch(1, 0, touchvec);
499 //for(int i=0;i<event.getPointerCount();i++) {
500 // System.out.printf("%d - moved to: %f,%f\n",i, event.getX(i),event.getY(i));
501 //}
502 } break;
503 case AMOTION_EVENT_ACTION_POINTER_UP: {
504
505 engine->os->process_touch(4, pidx, touchvec);
506 //System.out.printf("%d - s.up at: %f,%f\n",pointer_idx, event.getX(pointer_idx),event.getY(pointer_idx));
507 } break;
508 case AMOTION_EVENT_ACTION_POINTER_DOWN: {
509 engine->os->process_touch(3, pidx, touchvec);
510 //System.out.printf("%d - s.down at: %f,%f\n",pointer_idx, event.getX(pointer_idx),event.getY(pointer_idx));
511 } break;
512 case AMOTION_EVENT_ACTION_CANCEL:
513 case AMOTION_EVENT_ACTION_UP: {
514 engine->os->process_touch(2, 0, touchvec);
515 //for(int i=0;i<event.getPointerCount();i++) {
516 // System.out.printf("%d - up! %f,%f\n",i, event.getX(i),event.getY(i));
517 //}
518 } break;
519 }
520
521 return 1;
522 } break;
523 }
524
525 return 0;
526 }
527
528 /**
529 * Process the next main command.
530 */
531
_gfx_init(void * ud,bool p_gl2)532 static void _gfx_init(void *ud, bool p_gl2) {
533
534 struct engine *engine = (struct engine *)ud;
535 engine_init_display(engine, p_gl2);
536 }
537
engine_handle_cmd(struct android_app * app,int32_t cmd)538 static void engine_handle_cmd(struct android_app *app, int32_t cmd) {
539 struct engine *engine = (struct engine *)app->userData;
540 // LOGI("**** CMD %i\n",cmd);
541 switch (cmd) {
542 case APP_CMD_SAVE_STATE:
543 // The system has asked us to save our current state. Do so.
544 //engine->app->savedState = malloc(sizeof(struct saved_state));
545 //*((struct saved_state*)engine->app->savedState) = engine->state;
546 //engine->app->savedStateSize = sizeof(struct saved_state);
547 break;
548 case APP_CMD_CONFIG_CHANGED:
549 case APP_CMD_WINDOW_RESIZED: {
550
551 #if 0
552 // android blows
553 if (engine->display_active) {
554
555 EGLint w,h;
556 eglQuerySurface(engine->display, engine->surface, EGL_WIDTH, &w);
557 eglQuerySurface(engine->display, engine->surface, EGL_HEIGHT, &h);
558 engine->os->init_video_mode(w,h);
559 engine_draw_frame(engine);
560
561 }
562 #else
563
564 if (engine->display_active) {
565
566 EGLint w, h;
567 eglQuerySurface(engine->display, engine->surface, EGL_WIDTH, &w);
568 eglQuerySurface(engine->display, engine->surface, EGL_HEIGHT, &h);
569 // if (w==engine->os->get_video_mode().width && h==engine->os->get_video_mode().height)
570 // break;
571
572 engine_term_display(engine);
573 }
574
575 engine->os->reload_gfx();
576 engine_draw_frame(engine);
577 engine->animating = 1;
578
579 /*
580 EGLint w,h;
581 eglQuerySurface(engine->display, engine->surface, EGL_WIDTH, &w);
582 eglQuerySurface(engine->display, engine->surface, EGL_HEIGHT, &h);
583 engine->os->init_video_mode(w,h);
584
585 }*/
586
587 #endif
588
589 } break;
590 case APP_CMD_INIT_WINDOW:
591 //The window is being shown, get it ready.
592 // LOGI("INIT WINDOW");
593 if (engine->app->window != NULL) {
594
595 if (engine->os == NULL) {
596
597 //do initialization here, when there's OpenGL! hackish but the only way
598 engine->os = new OS_Android(_gfx_init, engine);
599
600 // char *args[]={"-test","gui",NULL};
601 __android_log_print(ANDROID_LOG_INFO, "godot", "pre asdasd setup...");
602 #if 0
603 Error err = Main::setup("apk",2,args);
604 #else
605 Error err = Main::setup("apk", 0, NULL);
606
607 String modules = Globals::get_singleton()->get("android/modules");
608 Vector<String> mods = modules.split(",", false);
609 mods.push_back("GodotOS");
610 __android_log_print(ANDROID_LOG_INFO, "godot", "mod count: %i", mods.size());
611
612 if (mods.size()) {
613
614 jclass activityClass = engine->jni->FindClass("android/app/NativeActivity");
615
616 jmethodID getClassLoader = engine->jni->GetMethodID(activityClass, "getClassLoader", "()Ljava/lang/ClassLoader;");
617
618 jobject cls = engine->jni->CallObjectMethod(app->activity->clazz, getClassLoader);
619
620 jclass classLoader = engine->jni->FindClass("java/lang/ClassLoader");
621
622 jmethodID findClass = engine->jni->GetMethodID(classLoader, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
623
624 static JNINativeMethod methods[] = {
625 { "registerSingleton", "(Ljava/lang/String;Ljava/lang/Object;)V", (void *)&Java_org_godotengine_godot_Godot_registerSingleton },
626 { "registerMethod", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;)V", (void *)&Java_org_godotengine_godot_Godot_registerMethod },
627 { "getGlobal", "(Ljava/lang/String;)Ljava/lang/String;", (void *)&Java_org_godotengine_godot_Godot_getGlobal },
628 };
629
630 jstring gstrClassName = engine->jni->NewStringUTF("org/godotengine/godot/Godot");
631 jclass GodotClass = (jclass)engine->jni->CallObjectMethod(cls, findClass, gstrClassName);
632
633 __android_log_print(ANDROID_LOG_INFO, "godot", "godot ****^*^*?^*^*class data %x", GodotClass);
634
635 engine->jni->RegisterNatives(GodotClass, methods, sizeof(methods) / sizeof(methods[0]));
636
637 for (int i = 0; i < mods.size(); i++) {
638
639 String m = mods[i];
640 //jclass singletonClass = engine->jni->FindClass(m.utf8().get_data());
641
642 jstring strClassName = engine->jni->NewStringUTF(m.utf8().get_data());
643 jclass singletonClass = (jclass)engine->jni->CallObjectMethod(cls, findClass, strClassName);
644
645 __android_log_print(ANDROID_LOG_INFO, "godot", "****^*^*?^*^*class data %x", singletonClass);
646 jmethodID initialize = engine->jni->GetStaticMethodID(singletonClass, "initialize", "(Landroid/app/Activity;)Lorg/godotengine/godot/Godot$SingletonBase;");
647
648 jobject obj = engine->jni->CallStaticObjectMethod(singletonClass, initialize, app->activity->clazz);
649 __android_log_print(ANDROID_LOG_INFO, "godot", "****^*^*?^*^*class instance %x", obj);
650 jobject gob = engine->jni->NewGlobalRef(obj);
651 }
652 }
653
654 #endif
655
656 if (!Main::start())
657 return; //should exit instead and print the error
658
659 engine->os->main_loop_begin();
660 } else {
661 //i guess recreate resources?
662 engine->os->reload_gfx();
663 }
664
665 engine->animating = 1;
666 engine_draw_frame(engine);
667 }
668 break;
669 case APP_CMD_TERM_WINDOW:
670 // The window is being hidden or closed, clean it up.
671 // LOGI("TERM WINDOW");
672 engine_term_display(engine);
673 break;
674 case APP_CMD_GAINED_FOCUS:
675 // When our app gains focus, we start monitoring the accelerometer.
676 if (engine->accelerometerSensor != NULL) {
677 ASensorEventQueue_enableSensor(engine->sensorEventQueue,
678 engine->accelerometerSensor);
679 // We'd like to get 60 events per second (in us).
680 ASensorEventQueue_setEventRate(engine->sensorEventQueue,
681 engine->accelerometerSensor, (1000L / 60) * 1000);
682 }
683 // and start monitoring our gravity vector
684 if (engine->gravitySensor != NULL) {
685 ASensorEventQueue_enableSensor(engine->sensorEventQueue,
686 engine->gravitySensor);
687 // We'd like to get 60 events per second (in us).
688 ASensorEventQueue_setEventRate(engine->sensorEventQueue,
689 engine->gravitySensor, (1000L / 60) * 1000);
690 }
691 // Also start monitoring the magnetometer.
692 if (engine->magnetometerSensor != NULL) {
693 ASensorEventQueue_enableSensor(engine->sensorEventQueue,
694 engine->magnetometerSensor);
695 // We'd like to get 60 events per second (in us).
696 ASensorEventQueue_setEventRate(engine->sensorEventQueue,
697 engine->magnetometerSensor, (1000L / 60) * 1000);
698 }
699 // And the gyroscope.
700 if (engine->gyroscopeSensor != NULL) {
701 ASensorEventQueue_enableSensor(engine->sensorEventQueue,
702 engine->gyroscopeSensor);
703 // We'd like to get 60 events per second (in us).
704 ASensorEventQueue_setEventRate(engine->sensorEventQueue,
705 engine->gyroscopeSensor, (1000L / 60) * 1000);
706 }
707 engine->animating = 1;
708 break;
709 case APP_CMD_LOST_FOCUS:
710 // When our app loses focus, we stop monitoring the sensors.
711 // This is to avoid consuming battery while not being used.
712 if (engine->accelerometerSensor != NULL) {
713 ASensorEventQueue_disableSensor(engine->sensorEventQueue,
714 engine->accelerometerSensor);
715 }
716 if (engine->gravitySensor != NULL) {
717 ASensorEventQueue_disableSensor(engine->sensorEventQueue,
718 engine->gravitySensor);
719 }
720 if (engine->magnetometerSensor != NULL) {
721 ASensorEventQueue_disableSensor(engine->sensorEventQueue,
722 engine->magnetometerSensor);
723 }
724 if (engine->gyroscopeSensor != NULL) {
725 ASensorEventQueue_disableSensor(engine->sensorEventQueue,
726 engine->gyroscopeSensor);
727 }
728 // Also stop animating.
729 engine->animating = 0;
730 engine_draw_frame(engine);
731 break;
732 }
733 }
734
android_main(struct android_app * state)735 void android_main(struct android_app *state) {
736 struct engine engine;
737 // Make sure glue isn't stripped.
738 app_dummy();
739
740 memset(&engine, 0, sizeof(engine));
741 state->userData = &engine;
742 state->onAppCmd = engine_handle_cmd;
743 state->onInputEvent = engine_handle_input;
744 engine.app = state;
745 engine.requested_quit = false;
746 engine.os = NULL;
747 engine.display_active = false;
748
749 FileAccessAndroid::asset_manager = state->activity->assetManager;
750
751 // Prepare to monitor sensors
752 engine.sensorManager = ASensorManager_getInstance();
753 engine.accelerometerSensor = ASensorManager_getDefaultSensor(engine.sensorManager,
754 ASENSOR_TYPE_ACCELEROMETER);
755 engine.gravitySensor = ASensorManager_getDefaultSensor(engine.sensorManager,
756 ASENSOR_TYPE_GRAVITY);
757 engine.magnetometerSensor = ASensorManager_getDefaultSensor(engine.sensorManager,
758 ASENSOR_TYPE_MAGNETIC_FIELD);
759 engine.gyroscopeSensor = ASensorManager_getDefaultSensor(engine.sensorManager,
760 ASENSOR_TYPE_GYROSCOPE);
761 engine.sensorEventQueue = ASensorManager_createEventQueue(engine.sensorManager,
762 state->looper, LOOPER_ID_USER, NULL, NULL);
763
764 ANativeActivity_setWindowFlags(state->activity, AWINDOW_FLAG_FULLSCREEN | AWINDOW_FLAG_KEEP_SCREEN_ON, 0);
765
766 state->activity->vm->AttachCurrentThread(&engine.jni, NULL);
767
768 // loop waiting for stuff to do.
769
770 while (1) {
771 // Read all pending events.
772 int ident;
773 int events;
774 struct android_poll_source *source;
775
776 // If not animating, we will block forever waiting for events.
777 // If animating, we loop until all events are read, then continue
778 // to draw the next frame of animation.
779
780 int nullmax = 50;
781 while ((ident = ALooper_pollAll(engine.animating ? 0 : -1, NULL, &events,
782 (void **)&source)) >= 0) {
783
784 // Process this event.
785
786 if (source != NULL) {
787 // LOGI("process\n");
788 source->process(state, source);
789 } else {
790 nullmax--;
791 if (nullmax < 0)
792 break;
793 }
794
795 // If a sensor has data, process it now.
796 // LOGI("events\n");
797 if (ident == LOOPER_ID_USER) {
798 if (engine.accelerometerSensor != NULL || engine.gravitySensor != NULL || engine.magnetometerSensor != NULL || engine.gyroscopeSensor != NULL) {
799 ASensorEvent event;
800 while (ASensorEventQueue_getEvents(engine.sensorEventQueue,
801 &event, 1) > 0) {
802
803 if (engine.os) {
804 if (event.acceleration != NULL) {
805 engine.os->process_accelerometer(Vector3(event.acceleration.x, event.acceleration.y,
806 event.acceleration.z));
807 }
808 if (event.gravity != NULL) {
809 engine.os->process_gravitymeter(Vector3(event.gravity.x, event.gravity.y,
810 event.gravity.z));
811 }
812 if (event.magnetic != NULL) {
813 engine.os->process_magnetometer(Vector3(event.magnetic.x, event.magnetic.y,
814 event.magnetic.z));
815 }
816 if (event.vector != NULL) {
817 engine.os->process_gyroscope(Vector3(event.vector.x, event.vector.y,
818 event.vector.z));
819 }
820 }
821 }
822 }
823 }
824
825 // Check if we are exiting.
826 if (state->destroyRequested != 0) {
827 if (engine.os) {
828 engine.os->main_loop_request_quit();
829 }
830 state->destroyRequested = 0;
831 }
832
833 if (engine.requested_quit) {
834 engine_term_display(&engine);
835 exit(0);
836 return;
837 }
838
839 // LOGI("end\n");
840 }
841
842 // LOGI("engine animating? %i\n",engine.animating);
843
844 if (engine.animating) {
845 //do os render
846
847 engine_draw_frame(&engine);
848 //LOGI("TERM WINDOW");
849 }
850 }
851 }
852
Java_org_godotengine_godot_Godot_registerSingleton(JNIEnv * env,jobject obj,jstring name,jobject p_object)853 JNIEXPORT void JNICALL Java_org_godotengine_godot_Godot_registerSingleton(JNIEnv *env, jobject obj, jstring name, jobject p_object) {
854
855 String singname = env->GetStringUTFChars(name, NULL);
856 JNISingleton *s = memnew(JNISingleton);
857 s->update_env(env);
858 s->set_instance(env->NewGlobalRef(p_object));
859 jni_singletons[singname] = s;
860
861 Globals::get_singleton()->add_singleton(Globals::Singleton(singname, s));
862 }
863
get_jni_type(const String & p_type)864 static Variant::Type get_jni_type(const String &p_type) {
865
866 static struct {
867 const char *name;
868 Variant::Type type;
869 } _type_to_vtype[] = {
870 { "void", Variant::NIL },
871 { "boolean", Variant::BOOL },
872 { "int", Variant::INT },
873 { "float", Variant::REAL },
874 { "java.lang.String", Variant::STRING },
875 { "[I", Variant::INT_ARRAY },
876 { "[F", Variant::REAL_ARRAY },
877 { "[Ljava.lang.String;", Variant::STRING_ARRAY },
878 { NULL, Variant::NIL }
879 };
880
881 int idx = 0;
882
883 while (_type_to_vtype[idx].name) {
884
885 if (p_type == _type_to_vtype[idx].name)
886 return _type_to_vtype[idx].type;
887
888 idx++;
889 }
890
891 return Variant::NIL;
892 }
893
get_jni_sig(const String & p_type)894 static const char *get_jni_sig(const String &p_type) {
895
896 static struct {
897 const char *name;
898 const char *sig;
899 } _type_to_vtype[] = {
900 { "void", "V" },
901 { "boolean", "Z" },
902 { "int", "I" },
903 { "float", "F" },
904 { "java.lang.String", "Ljava/lang/String;" },
905 { "[I", "[I" },
906 { "[F", "[F" },
907 { "[Ljava.lang.String;", "[Ljava/lang/String;" },
908 { NULL, "V" }
909 };
910
911 int idx = 0;
912
913 while (_type_to_vtype[idx].name) {
914
915 if (p_type == _type_to_vtype[idx].name)
916 return _type_to_vtype[idx].sig;
917
918 idx++;
919 }
920
921 return "";
922 }
923
Java_org_godotengine_godot_Godot_getGlobal(JNIEnv * env,jobject obj,jstring path)924 JNIEXPORT jstring JNICALL Java_org_godotengine_godot_Godot_getGlobal(JNIEnv *env, jobject obj, jstring path) {
925
926 String js = env->GetStringUTFChars(path, NULL);
927
928 return env->NewStringUTF(Globals::get_singleton()->get(js).operator String().utf8().get_data());
929 }
930
Java_org_godotengine_godot_Godot_registerMethod(JNIEnv * env,jobject obj,jstring sname,jstring name,jstring ret,jobjectArray args)931 JNIEXPORT void JNICALL Java_org_godotengine_godot_Godot_registerMethod(JNIEnv *env, jobject obj, jstring sname, jstring name, jstring ret, jobjectArray args) {
932
933 String singname = env->GetStringUTFChars(sname, NULL);
934
935 ERR_FAIL_COND(!jni_singletons.has(singname));
936
937 JNISingleton *s = jni_singletons.get(singname);
938
939 String mname = env->GetStringUTFChars(name, NULL);
940 String retval = env->GetStringUTFChars(ret, NULL);
941 Vector<Variant::Type> types;
942 String cs = "(";
943
944 int stringCount = env->GetArrayLength(args);
945
946 for (int i = 0; i < stringCount; i++) {
947
948 jstring string = (jstring)env->GetObjectArrayElement(args, i);
949 const char *rawString = env->GetStringUTFChars(string, 0);
950 types.push_back(get_jni_type(String(rawString)));
951 cs += get_jni_sig(String(rawString));
952 }
953
954 cs += ")";
955 cs += get_jni_sig(retval);
956 jclass cls = env->GetObjectClass(s->get_instance());
957 jmethodID mid = env->GetMethodID(cls, mname.ascii().get_data(), cs.ascii().get_data());
958 if (!mid) {
959
960 print_line("Failed getting method id: " + mname);
961 }
962
963 s->add_method(mname, mid, types, get_jni_type(retval));
964 }
965
966 #endif
967