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