12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034 |
- /*************************************************************************/
- /* godot_android.cpp */
- /*************************************************************************/
- /* This file is part of: */
- /* GODOT ENGINE */
- /* http://www.godotengine.org */
- /*************************************************************************/
- /* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
- /* */
- /* Permission is hereby granted, free of charge, to any person obtaining */
- /* a copy of this software and associated documentation files (the */
- /* "Software"), to deal in the Software without restriction, including */
- /* without limitation the rights to use, copy, modify, merge, publish, */
- /* distribute, sublicense, and/or sell copies of the Software, and to */
- /* permit persons to whom the Software is furnished to do so, subject to */
- /* the following conditions: */
- /* */
- /* The above copyright notice and this permission notice shall be */
- /* included in all copies or substantial portions of the Software. */
- /* */
- /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
- /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
- /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
- /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
- /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
- /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
- /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
- /*************************************************************************/
- #ifdef ANDROID_NATIVE_ACTIVITY
- #include <jni.h>
- #include <errno.h>
- #include <EGL/egl.h>
- #include <GLES2/gl2.h>
- #include <android/sensor.h>
- #include <android/window.h>
- #include <android/log.h>
- #include <android_native_app_glue.h>
- #include "file_access_android.h"
- #include <string.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include "os_android.h"
- #include "globals.h"
- #include "main/main.h"
- #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "godot", __VA_ARGS__))
- #define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "godot", __VA_ARGS__))
- extern "C" {
- JNIEXPORT void JNICALL Java_org_godotengine_godot_Godot_registerSingleton(JNIEnv * env, jobject obj, jstring name,jobject p_object);
- JNIEXPORT void JNICALL Java_org_godotengine_godot_Godot_registerMethod(JNIEnv * env, jobject obj, jstring sname, jstring name, jstring ret, jobjectArray args);
- JNIEXPORT jstring JNICALL Java_org_godotengine_godot_Godot_getGlobal(JNIEnv * env, jobject obj, jstring path);
- };
- class JNISingleton : public Object {
- GDCLASS( JNISingleton, Object );
- struct MethodData {
- jmethodID method;
- Variant::Type ret_type;
- Vector<Variant::Type> argtypes;
- };
- jobject instance;
- Map<StringName,MethodData> method_map;
- JNIEnv *env;
- public:
- void update_env(JNIEnv *p_env) { env=p_env; }
- virtual Variant call(const StringName& p_method,const Variant** p_args,int p_argcount,Variant::CallError &r_error) {
- print_line("attempt to call "+String(p_method));
- r_error.error=Variant::CallError::CALL_OK;
- Map<StringName,MethodData >::Element *E=method_map.find(p_method);
- if (!E) {
- print_line("no exists");
- r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
- return Variant();
- }
- int ac = E->get().argtypes.size();
- if (ac<p_argcount) {
- print_line("fewargs");
- r_error.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument=ac;
- return Variant();
- }
- if (ac>p_argcount) {
- print_line("manyargs");
- r_error.error=Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
- r_error.argument=ac;
- return Variant();
- }
- for(int i=0;i<p_argcount;i++) {
- if (!Variant::can_convert(p_args[i]->get_type(),E->get().argtypes[i])) {
- r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument=i;
- r_error.expected=E->get().argtypes[i];
- }
- }
- jvalue *v=NULL;
- if (p_argcount) {
- v=(jvalue*)alloca( sizeof(jvalue)*p_argcount );
- }
- for(int i=0;i<p_argcount;i++) {
- switch(E->get().argtypes[i]) {
- case Variant::BOOL: {
- v[i].z=*p_args[i];
- } break;
- case Variant::INT: {
- v[i].i=*p_args[i];
- } break;
- case Variant::REAL: {
- v[i].f=*p_args[i];
- } break;
- case Variant::STRING: {
- String s = *p_args[i];
- jstring jStr = env->NewStringUTF(s.utf8().get_data());
- v[i].l=jStr;
- } break;
- case Variant::STRING_ARRAY: {
- DVector<String> sarray = *p_args[i];
- jobjectArray arr = env->NewObjectArray(sarray.size(),env->FindClass("java/lang/String"),env->NewStringUTF(""));
- for(int j=0;j<sarray.size();j++) {
- env->SetObjectArrayElement(arr,j,env->NewStringUTF( sarray[i].utf8().get_data() ));
- }
- v[i].l=arr;
- } break;
- case Variant::INT_ARRAY: {
- DVector<int> array = *p_args[i];
- jintArray arr = env->NewIntArray(array.size());
- DVector<int>::Read r = array.read();
- env->SetIntArrayRegion(arr,0,array.size(),r.ptr());
- v[i].l=arr;
- } break;
- case Variant::REAL_ARRAY: {
- DVector<float> array = *p_args[i];
- jfloatArray arr = env->NewFloatArray(array.size());
- DVector<float>::Read r = array.read();
- env->SetFloatArrayRegion(arr,0,array.size(),r.ptr());
- v[i].l=arr;
- } break;
- default: {
- ERR_FAIL_V(Variant());
- } break;
- }
- }
- print_line("calling method!!");
- Variant ret;
- switch(E->get().ret_type) {
- case Variant::NIL: {
- print_line("call void");
- env->CallVoidMethodA(instance,E->get().method,v);
- } break;
- case Variant::BOOL: {
- ret = env->CallBooleanMethodA(instance,E->get().method,v);
- print_line("call bool");
- } break;
- case Variant::INT: {
- ret = env->CallIntMethodA(instance,E->get().method,v);
- print_line("call int");
- } break;
- case Variant::REAL: {
- ret = env->CallFloatMethodA(instance,E->get().method,v);
- } break;
- case Variant::STRING: {
- jobject o = env->CallObjectMethodA(instance,E->get().method,v);
- String singname = env->GetStringUTFChars((jstring)o, NULL );
- } break;
- case Variant::STRING_ARRAY: {
- jobjectArray arr = (jobjectArray)env->CallObjectMethodA(instance,E->get().method,v);
- int stringCount = env->GetArrayLength(arr);
- DVector<String> sarr;
- for (int i=0; i<stringCount; i++) {
- jstring string = (jstring) env->GetObjectArrayElement(arr, i);
- const char *rawString = env->GetStringUTFChars(string, 0);
- sarr.push_back(String(rawString));
- }
- ret=sarr;
- } break;
- case Variant::INT_ARRAY: {
- jintArray arr = (jintArray)env->CallObjectMethodA(instance,E->get().method,v);
- int fCount = env->GetArrayLength(arr);
- DVector<int> sarr;
- sarr.resize(fCount);
- DVector<int>::Write w = sarr.write();
- env->GetIntArrayRegion(arr,0,fCount,w.ptr());
- w = DVector<int>::Write();
- ret=sarr;
- } break;
- case Variant::REAL_ARRAY: {
- jfloatArray arr = (jfloatArray)env->CallObjectMethodA(instance,E->get().method,v);
- int fCount = env->GetArrayLength(arr);
- DVector<float> sarr;
- sarr.resize(fCount);
- DVector<float>::Write w = sarr.write();
- env->GetFloatArrayRegion(arr,0,fCount,w.ptr());
- w = DVector<float>::Write();
- ret=sarr;
- } break;
- default: {
- print_line("failure..");
- ERR_FAIL_V(Variant());
- } break;
- }
- print_line("success");
- return ret;
- }
- jobject get_instance() const {
- return instance;
- }
- void set_instance(jobject p_instance) {
- instance=p_instance;
- }
- void add_method(const StringName& p_name, jmethodID p_method,const Vector<Variant::Type>& p_args, Variant::Type p_ret_type) {
- MethodData md;
- md.method=p_method;
- md.argtypes=p_args;
- md.ret_type=p_ret_type;
- method_map[p_name]=md;
- }
- JNISingleton() {}
- };
- //JNIEnv *JNISingleton::env=NULL;
- static HashMap<String,JNISingleton*> jni_singletons;
- struct engine {
- struct android_app* app;
- OS_Android *os;
- JNIEnv *jni;
- ASensorManager* sensorManager;
- const ASensor* accelerometerSensor;
- const ASensor* magnetometerSensor;
- const ASensor* gyroscopeSensor;
- ASensorEventQueue* sensorEventQueue;
- bool display_active;
- bool requested_quit;
- int animating;
- EGLDisplay display;
- EGLSurface surface;
- EGLContext context;
- int32_t width;
- int32_t height;
- };
- /**
- * Initialize an EGL context for the current display.
- */
- static int engine_init_display(struct engine* engine,bool p_gl2) {
- // initialize OpenGL ES and EGL
- /*
- * Here specify the attributes of the desired configuration.
- * Below, we select an EGLConfig with at least 8 bits per color
- * component compatible with on-screen windows
- */
- const EGLint gl2_attribs[] = {
- // EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
- EGL_BLUE_SIZE, 4,
- EGL_GREEN_SIZE, 4,
- EGL_RED_SIZE, 4,
- EGL_ALPHA_SIZE, 0,
- EGL_DEPTH_SIZE, 16,
- EGL_STENCIL_SIZE, EGL_DONT_CARE,
- EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
- EGL_NONE
- };
- const EGLint gl1_attribs[] = {
- // EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
- EGL_BLUE_SIZE, 4,
- EGL_GREEN_SIZE, 4,
- EGL_RED_SIZE, 4,
- EGL_ALPHA_SIZE, 0,
- EGL_DEPTH_SIZE, 16,
- EGL_STENCIL_SIZE, EGL_DONT_CARE,
- EGL_NONE
- };
- const EGLint *attribs=p_gl2?gl2_attribs:gl1_attribs;
- EGLint w, h, dummy, format;
- EGLint numConfigs;
- EGLConfig config;
- EGLSurface surface;
- EGLContext context;
- EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- eglInitialize(display, 0, 0);
- /* Here, the application chooses the configuration it desires. In this
- * sample, we have a very simplified selection process, where we pick
- * the first EGLConfig that matches our criteria */
- eglChooseConfig(display, attribs, &config, 1, &numConfigs);
- LOGI("Num configs: %i\n",numConfigs);
- /* EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is
- * guaranteed to be accepted by ANativeWindow_setBuffersGeometry().
- * As soon as we picked a EGLConfig, we can safely reconfigure the
- * ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID. */
- eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format);
- ANativeWindow_setBuffersGeometry(engine->app->window, 0, 0, format);
- //ANativeWindow_setFlags(engine->app->window, 0, 0, format|);
- surface = eglCreateWindowSurface(display, config, engine->app->window, NULL);
- const EGLint context_attribs[] = {
- EGL_CONTEXT_CLIENT_VERSION,2,
- EGL_NONE
- };
- context = eglCreateContext(display, config, EGL_NO_CONTEXT, p_gl2?context_attribs:NULL);
- if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) {
- LOGW("Unable to eglMakeCurrent");
- return -1;
- }
- eglQuerySurface(display, surface, EGL_WIDTH, &w);
- eglQuerySurface(display, surface, EGL_HEIGHT, &h);
- print_line("INIT VIDEO MODE: "+itos(w)+","+itos(h));
- //engine->os->set_egl_extensions(eglQueryString(display,EGL_EXTENSIONS));
- engine->os->init_video_mode(w,h);
- engine->display = display;
- engine->context = context;
- engine->surface = surface;
- engine->width = w;
- engine->height = h;
- engine->display_active=true;
- //engine->state.angle = 0;
- // Initialize GL state.
- //glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
- glEnable(GL_CULL_FACE);
- // glShadeModel(GL_SMOOTH);
- glDisable(GL_DEPTH_TEST);
- LOGI("GL Version: %s - %s %s\n", glGetString(GL_VERSION),glGetString(GL_VENDOR), glGetString(GL_RENDERER));
- return 0;
- }
- static void engine_draw_frame(struct engine* engine) {
- if (engine->display == NULL) {
- // No display.
- return;
- }
- // Just fill the screen with a color.
- //glClearColor(0,1,0,1);
- //glClear(GL_COLOR_BUFFER_BIT);
- if (engine->os && engine->os->main_loop_iterate()==true) {
- engine->requested_quit=true;
- return; //should exit instead
- }
- eglSwapBuffers(engine->display, engine->surface);
- }
- static void engine_term_display(struct engine* engine) {
- if (engine->display != EGL_NO_DISPLAY) {
- eglMakeCurrent(engine->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
- if (engine->context != EGL_NO_CONTEXT) {
- eglDestroyContext(engine->display, engine->context);
- }
- if (engine->surface != EGL_NO_SURFACE) {
- eglDestroySurface(engine->display, engine->surface);
- }
- eglTerminate(engine->display);
- }
- engine->animating = 0;
- engine->display = EGL_NO_DISPLAY;
- engine->context = EGL_NO_CONTEXT;
- engine->surface = EGL_NO_SURFACE;
- engine->display_active=false;
- }
- /**
- * Process the next input event.
- */
- static int32_t engine_handle_input(struct android_app* app, AInputEvent* event) {
- struct engine* engine = (struct engine*)app->userData;
- if (!engine->os)
- return 0;
- switch(AInputEvent_getType(event)) {
- case AINPUT_EVENT_TYPE_KEY: {
- int ac = AKeyEvent_getAction(event);
- switch(ac) {
- case AKEY_EVENT_ACTION_DOWN: {
- int32_t code = AKeyEvent_getKeyCode(event);
- if (code==AKEYCODE_BACK) {
- //AInputQueue_finishEvent(AInputQueue* queue, AInputEvent* event, int handled);
- if (engine->os)
- engine->os->main_loop_request_quit();
- return 1;
- }
- } break;
- case AKEY_EVENT_ACTION_UP: {
- } break;
- }
- } break;
- case AINPUT_EVENT_TYPE_MOTION: {
- Vector<OS_Android::TouchPos> touchvec;
- int pc = AMotionEvent_getPointerCount(event);
- touchvec.resize(pc);
- for(int i=0;i<pc;i++) {
- touchvec[i].pos.x=AMotionEvent_getX(event,i);
- touchvec[i].pos.y=AMotionEvent_getY(event,i);
- touchvec[i].id=AMotionEvent_getPointerId(event,i);
- }
- //System.out.printf("gaction: %d\n",event.getAction());
- int pidx=(AMotionEvent_getAction(event)&AMOTION_EVENT_ACTION_POINTER_INDEX_MASK)>>8;
- switch(AMotionEvent_getAction(event)&AMOTION_EVENT_ACTION_MASK) {
- case AMOTION_EVENT_ACTION_DOWN: {
- engine->os->process_touch(0,0,touchvec);
- //System.out.printf("action down at: %f,%f\n", event.getX(),event.getY());
- } break;
- case AMOTION_EVENT_ACTION_MOVE: {
- engine->os->process_touch(1,0,touchvec);
- //for(int i=0;i<event.getPointerCount();i++) {
- // System.out.printf("%d - moved to: %f,%f\n",i, event.getX(i),event.getY(i));
- //}
- } break;
- case AMOTION_EVENT_ACTION_POINTER_UP: {
- engine->os->process_touch(4,pidx,touchvec);
- //System.out.printf("%d - s.up at: %f,%f\n",pointer_idx, event.getX(pointer_idx),event.getY(pointer_idx));
- } break;
- case AMOTION_EVENT_ACTION_POINTER_DOWN: {
- engine->os->process_touch(3,pidx,touchvec);
- //System.out.printf("%d - s.down at: %f,%f\n",pointer_idx, event.getX(pointer_idx),event.getY(pointer_idx));
- } break;
- case AMOTION_EVENT_ACTION_CANCEL:
- case AMOTION_EVENT_ACTION_UP: {
- engine->os->process_touch(2,0,touchvec);
- //for(int i=0;i<event.getPointerCount();i++) {
- // System.out.printf("%d - up! %f,%f\n",i, event.getX(i),event.getY(i));
- //}
- } break;
- }
- return 1;
- } break;
- }
- return 0;
- }
- /**
- * Process the next main command.
- */
- static void _gfx_init(void *ud,bool p_gl2) {
- struct engine* engine = (struct engine*)ud;
- engine_init_display(engine,p_gl2);
- }
- static void engine_handle_cmd(struct android_app* app, int32_t cmd) {
- struct engine* engine = (struct engine*)app->userData;
- // LOGI("**** CMD %i\n",cmd);
- switch (cmd) {
- case APP_CMD_SAVE_STATE:
- // The system has asked us to save our current state. Do so.
- //engine->app->savedState = malloc(sizeof(struct saved_state));
- //*((struct saved_state*)engine->app->savedState) = engine->state;
- //engine->app->savedStateSize = sizeof(struct saved_state);
- break;
- case APP_CMD_CONFIG_CHANGED:
- case APP_CMD_WINDOW_RESIZED: {
- #if 0
- // android blows
- if (engine->display_active) {
- EGLint w,h;
- eglQuerySurface(engine->display, engine->surface, EGL_WIDTH, &w);
- eglQuerySurface(engine->display, engine->surface, EGL_HEIGHT, &h);
- engine->os->init_video_mode(w,h);
- //print_line("RESIZED VIDEO MODE: "+itos(w)+","+itos(h));
- engine_draw_frame(engine);
- }
- #else
- if (engine->display_active) {
- EGLint w,h;
- eglQuerySurface(engine->display, engine->surface, EGL_WIDTH, &w);
- eglQuerySurface(engine->display, engine->surface, EGL_HEIGHT, &h);
- // if (w==engine->os->get_video_mode().width && h==engine->os->get_video_mode().height)
- // break;
- engine_term_display(engine);
- }
- engine->os->reload_gfx();
- engine_draw_frame(engine);
- engine->animating=1;
- /*
- EGLint w,h;
- eglQuerySurface(engine->display, engine->surface, EGL_WIDTH, &w);
- eglQuerySurface(engine->display, engine->surface, EGL_HEIGHT, &h);
- engine->os->init_video_mode(w,h);
- //print_line("RESIZED VIDEO MODE: "+itos(w)+","+itos(h));
- }*/
- #endif
- } break;
- case APP_CMD_INIT_WINDOW:
- //The window is being shown, get it ready.
- // LOGI("INIT WINDOW");
- if (engine->app->window != NULL) {
- if (engine->os==NULL) {
- //do initialization here, when there's OpenGL! hackish but the only way
- engine->os = new OS_Android(_gfx_init,engine);
- // char *args[]={"-test","gui",NULL};
- __android_log_print(ANDROID_LOG_INFO,"godot","pre asdasd setup...");
- #if 0
- Error err = Main::setup("apk",2,args);
- #else
- Error err = Main::setup("apk",0,NULL);
- String modules = GlobalConfig::get_singleton()->get("android/modules");
- Vector<String> mods = modules.split(",",false);
- mods.push_back("GodotOS");
- __android_log_print(ANDROID_LOG_INFO,"godot","mod count: %i",mods.size());
- if (mods.size()) {
- jclass activityClass = engine->jni->FindClass("android/app/NativeActivity");
- jmethodID getClassLoader = engine->jni->GetMethodID(activityClass,"getClassLoader", "()Ljava/lang/ClassLoader;");
- jobject cls = engine->jni->CallObjectMethod(app->activity->clazz, getClassLoader);
- jclass classLoader = engine->jni->FindClass("java/lang/ClassLoader");
- jmethodID findClass = engine->jni->GetMethodID(classLoader, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
- static JNINativeMethod methods[] = {
- {"registerSingleton", "(Ljava/lang/String;Ljava/lang/Object;)V",(void *)&Java_org_godotengine_godot_Godot_registerSingleton},
- {"registerMethod", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;)V",(void *)&Java_org_godotengine_godot_Godot_registerMethod},
- {"getGlobal", "(Ljava/lang/String;)Ljava/lang/String;", (void *)&Java_org_godotengine_godot_Godot_getGlobal},
- };
- jstring gstrClassName = engine->jni->NewStringUTF("org/godotengine/godot/Godot");
- jclass GodotClass = (jclass)engine->jni->CallObjectMethod(cls, findClass, gstrClassName);
- __android_log_print(ANDROID_LOG_INFO,"godot","godot ****^*^*?^*^*class data %x",GodotClass);
- engine->jni->RegisterNatives(GodotClass,methods,sizeof(methods)/sizeof(methods[0]));
- for (int i=0;i<mods.size();i++) {
- String m = mods[i];
- //jclass singletonClass = engine->jni->FindClass(m.utf8().get_data());
- jstring strClassName = engine->jni->NewStringUTF(m.utf8().get_data());
- jclass singletonClass = (jclass)engine->jni->CallObjectMethod(cls, findClass, strClassName);
- __android_log_print(ANDROID_LOG_INFO,"godot","****^*^*?^*^*class data %x",singletonClass);
- jmethodID initialize = engine->jni->GetStaticMethodID(singletonClass, "initialize", "(Landroid/app/Activity;)Lorg/godotengine/godot/Godot$SingletonBase;");
- jobject obj = engine->jni->CallStaticObjectMethod(singletonClass,initialize,app->activity->clazz);
- __android_log_print(ANDROID_LOG_INFO,"godot","****^*^*?^*^*class instance %x",obj);
- jobject gob = engine->jni->NewGlobalRef(obj);
- }
- }
- #endif
- if (!Main::start())
- return; //should exit instead and print the error
- engine->os->main_loop_begin();
- } else {
- //i guess recreate resources?
- engine->os->reload_gfx();
- }
- engine->animating=1;
- engine_draw_frame(engine);
- }
- break;
- case APP_CMD_TERM_WINDOW:
- // The window is being hidden or closed, clean it up.
- // LOGI("TERM WINDOW");
- engine_term_display(engine);
- break;
- case APP_CMD_GAINED_FOCUS:
- // When our app gains focus, we start monitoring the accelerometer.
- if (engine->accelerometerSensor != NULL) {
- ASensorEventQueue_enableSensor(engine->sensorEventQueue,
- engine->accelerometerSensor);
- // We'd like to get 60 events per second (in us).
- ASensorEventQueue_setEventRate(engine->sensorEventQueue,
- engine->accelerometerSensor, (1000L/60)*1000);
- }
- // Also start monitoring the magnetometer.
- if (engine->magnetometerSensor != NULL) {
- ASensorEventQueue_enableSensor(engine->sensorEventQueue,
- engine->magnetometerSensor);
- // We'd like to get 60 events per second (in us).
- ASensorEventQueue_setEventRate(engine->sensorEventQueue,
- engine->magnetometerSensor, (1000L/60)*1000);
- }
- // And the gyroscope.
- if (engine->gyroscopeSensor != NULL) {
- ASensorEventQueue_enableSensor(engine->sensorEventQueue,
- engine->gyroscopeSensor);
- // We'd like to get 60 events per second (in us).
- ASensorEventQueue_setEventRate(engine->sensorEventQueue,
- engine->gyroscopeSensor, (1000L/60)*1000);
- }
- engine->animating = 1;
- break;
- case APP_CMD_LOST_FOCUS:
- // When our app loses focus, we stop monitoring the sensors.
- // This is to avoid consuming battery while not being used.
- if (engine->accelerometerSensor != NULL) {
- ASensorEventQueue_disableSensor(engine->sensorEventQueue,
- engine->accelerometerSensor);
- }
- if (engine->magnetometerSensor != NULL) {
- ASensorEventQueue_disableSensor(engine->sensorEventQueue,
- engine->magnetometerSensor);
- }
- if (engine->gyroscopeSensor != NULL) {
- ASensorEventQueue_disableSensor(engine->sensorEventQueue,
- engine->gyroscopeSensor);
- }
- // Also stop animating.
- engine->animating = 0;
- engine_draw_frame(engine);
- break;
- }
- }
- void android_main(struct android_app* state) {
- struct engine engine;
- // Make sure glue isn't stripped.
- app_dummy();
- memset(&engine, 0, sizeof(engine));
- state->userData = &engine;
- state->onAppCmd = engine_handle_cmd;
- state->onInputEvent = engine_handle_input;
- engine.app = state;
- engine.requested_quit=false;
- engine.os=NULL;
- engine.display_active=false;
- FileAccessAndroid::asset_manager=state->activity->assetManager;
- // Prepare to monitor sensors
- engine.sensorManager = ASensorManager_getInstance();
- engine.accelerometerSensor = ASensorManager_getDefaultSensor(engine.sensorManager,
- ASENSOR_TYPE_ACCELEROMETER);
- engine.magnetometerSensor = ASensorManager_getDefaultSensor(engine.sensorManager,
- ASENSOR_TYPE_MAGNETIC_FIELD);
- engine.gyroscopeSensor = ASensorManager_getDefaultSensor(engine.sensorManager,
- ASENSOR_TYPE_GYROSCOPE);
- engine.sensorEventQueue = ASensorManager_createEventQueue(engine.sensorManager,
- state->looper, LOOPER_ID_USER, NULL, NULL);
- ANativeActivity_setWindowFlags(state->activity,AWINDOW_FLAG_FULLSCREEN|AWINDOW_FLAG_KEEP_SCREEN_ON,0);
- state->activity->vm->AttachCurrentThread(&engine.jni, NULL);
- // loop waiting for stuff to do.
- while (1) {
- // Read all pending events.
- int ident;
- int events;
- struct android_poll_source* source;
- // If not animating, we will block forever waiting for events.
- // If animating, we loop until all events are read, then continue
- // to draw the next frame of animation.
- int nullmax=50;
- while ((ident=ALooper_pollAll(engine.animating ? 0 : -1, NULL, &events,
- (void**)&source)) >= 0) {
- // Process this event.
- if (source != NULL) {
- // LOGI("process\n");
- source->process(state, source);
- } else {
- nullmax--;
- if (nullmax<0)
- break;
- }
- // If a sensor has data, process it now.
- // LOGI("events\n");
- if (ident == LOOPER_ID_USER) {
- if (engine.accelerometerSensor != NULL || engine.magnetometerSensor != NULL || engine.gyroscopeSensor != NULL) {
- ASensorEvent event;
- while (ASensorEventQueue_getEvents(engine.sensorEventQueue,
- &event, 1) > 0) {
- if (engine.os) {
- if (event.acceleration != NULL) {
- engine.os->process_accelerometer(Vector3(event.acceleration.x, event.acceleration.y,
- event.acceleration.z));
- }
- if (event.magnetic != NULL) {
- engine.os->process_magnetometer(Vector3(event.magnetic.x, event.magnetic.y,
- event.magnetic.z));
- }
- if (event.vector != NULL) {
- engine.os->process_gyroscope(Vector3(event.vector.x, event.vector.y,
- event.vector.z));
- }
- }
- }
- }
- }
- // Check if we are exiting.
- if (state->destroyRequested != 0) {
- if (engine.os) {
- engine.os->main_loop_request_quit();
- }
- state->destroyRequested=0;
- }
- if (engine.requested_quit) {
- engine_term_display(&engine);
- exit(0);
- return;
- }
- // LOGI("end\n");
- }
- // LOGI("engine animating? %i\n",engine.animating);
- if (engine.animating) {
- //do os render
- engine_draw_frame(&engine);
- //LOGI("TERM WINDOW");
- }
- }
- }
- JNIEXPORT void JNICALL Java_org_godotengine_godot_Godot_registerSingleton(JNIEnv * env, jobject obj, jstring name,jobject p_object){
- String singname = env->GetStringUTFChars( name, NULL );
- JNISingleton *s = memnew( JNISingleton );
- s->update_env(env);
- s->set_instance(env->NewGlobalRef(p_object));
- jni_singletons[singname]=s;
- GlobalConfig::get_singleton()->add_singleton(GlobalConfig::Singleton(singname,s));
- }
- static Variant::Type get_jni_type(const String& p_type) {
- static struct {
- const char *name;
- Variant::Type type;
- } _type_to_vtype[]={
- {"void",Variant::NIL},
- {"boolean",Variant::BOOL},
- {"int",Variant::INT},
- {"float",Variant::REAL},
- {"java.lang.String",Variant::STRING},
- {"[I",Variant::INT_ARRAY},
- {"[F",Variant::REAL_ARRAY},
- {"[Ljava.lang.String;",Variant::STRING_ARRAY},
- {NULL,Variant::NIL}
- };
- int idx=0;
- while (_type_to_vtype[idx].name) {
- if (p_type==_type_to_vtype[idx].name)
- return _type_to_vtype[idx].type;
- idx++;
- }
- return Variant::NIL;
- }
- static const char* get_jni_sig(const String& p_type) {
- static struct {
- const char *name;
- const char *sig;
- } _type_to_vtype[]={
- {"void","V"},
- {"boolean","Z"},
- {"int","I"},
- {"float","F"},
- {"java.lang.String","Ljava/lang/String;"},
- {"[I","[I"},
- {"[F","[F"},
- {"[Ljava.lang.String;","[Ljava/lang/String;"},
- {NULL,"V"}
- };
- int idx=0;
- while (_type_to_vtype[idx].name) {
- if (p_type==_type_to_vtype[idx].name)
- return _type_to_vtype[idx].sig;
- idx++;
- }
- return "";
- }
- JNIEXPORT jstring JNICALL Java_org_godotengine_godot_Godot_getGlobal(JNIEnv * env, jobject obj, jstring path) {
- String js = env->GetStringUTFChars( path, NULL );
- return env->NewStringUTF(GlobalConfig::get_singleton()->get(js).operator String().utf8().get_data());
- }
- JNIEXPORT void JNICALL Java_org_godotengine_godot_Godot_registerMethod(JNIEnv * env, jobject obj, jstring sname, jstring name, jstring ret, jobjectArray args){
- String singname = env->GetStringUTFChars( sname, NULL );
- ERR_FAIL_COND(!jni_singletons.has(singname));
- JNISingleton *s = jni_singletons.get(singname);
- String mname = env->GetStringUTFChars( name, NULL );
- String retval = env->GetStringUTFChars( ret, NULL );
- Vector<Variant::Type> types;
- String cs="(";
- int stringCount = env->GetArrayLength(args);
- print_line("Singl: "+singname+" Method: "+mname+" RetVal: "+retval);
- for (int i=0; i<stringCount; i++) {
- jstring string = (jstring) env->GetObjectArrayElement(args, i);
- const char *rawString = env->GetStringUTFChars(string, 0);
- types.push_back(get_jni_type(String(rawString)));
- cs+=get_jni_sig(String(rawString));
- }
- cs+=")";
- cs+=get_jni_sig(retval);
- jclass cls = env->GetObjectClass(s->get_instance());
- print_line("METHOD: "+mname+" sig: "+cs);
- jmethodID mid = env->GetMethodID(cls, mname.ascii().get_data(), cs.ascii().get_data());
- if (!mid) {
- print_line("FAILED GETTING METHOID "+mname);
- }
- s->add_method(mname,mid,types,get_jni_type(retval));
- }
- #endif
|