Make GDNative work on Android

The changes include work done to ensure that GDNative apps and Nim
integration specifically can run on Android. The changes have been
tested on our WIP game, which uses godot-nim and depends on several
third-party .so libs, and Platformer demo to ensure nothing got broken.

 - .so libraries are exported to lib/ folder in .apk, instead of assets/,
   because that's where Android expects them to be and it resolves the
   library name into "lib/<ABI>/<name>", where <ABI> is the ABI matching
   the current device. So we establish the convention that Android .so
   files in the project must be located in the folder corresponding to
   the ABI they were compiled for.

 - Godot callbacks (event handlers) are now called from the same thread
   from which Main::iteration is called. It is also what Godot now
   considers to be the main thread, because Main::setup is also called
   from there. This makes threading on Android more consistent with
   other platforms, making the code that depends on Thread::get_main_id
   more portable (GDNative has such code).

 - Sizes of GDNative API types have been fixed to work on 32-bit
   platforms.
This commit is contained in:
Ruslan Mustakov 2017-08-18 21:17:35 +07:00
parent 8b9026c05e
commit 5ccdeccb6e
22 changed files with 447 additions and 321 deletions

View File

@ -1098,10 +1098,20 @@ bool Main::start() {
test = args[i + 1];
} else if (args[i] == "--export") {
editor = true; //needs editor
_export_preset = args[i + 1];
if (i + 1 < args.size()) {
_export_preset = args[i + 1];
} else {
ERR_PRINT("Export preset name not specified");
return false;
}
} else if (args[i] == "--export-debug") {
editor = true; //needs editor
_export_preset = args[i + 1];
if (i + 1 < args.size()) {
_export_preset = args[i + 1];
} else {
ERR_PRINT("Export preset name not specified");
return false;
}
export_debug = true;
} else {
// The parameter does not match anything known, don't skip the next argument

View File

@ -40,7 +40,7 @@
const String init_symbol = "godot_gdnative_init";
const String terminate_symbol = "godot_gdnative_terminate";
String GDNativeLibrary::platform_names[NUM_PLATFORMS] = {
String GDNativeLibrary::platform_names[NUM_PLATFORMS + 1] = {
"X11_32bit",
"X11_64bit",
"Windows_32bit",
@ -48,11 +48,15 @@ String GDNativeLibrary::platform_names[NUM_PLATFORMS] = {
"OSX",
"Android",
"iOS",
"WebAssembly"
"iOS_32bit",
"iOS_64bit",
"WebAssembly",
""
};
String GDNativeLibrary::platform_lib_ext[NUM_PLATFORMS] = {
String GDNativeLibrary::platform_lib_ext[NUM_PLATFORMS + 1] = {
"so",
"so",
"dll",
@ -60,21 +64,30 @@ String GDNativeLibrary::platform_lib_ext[NUM_PLATFORMS] = {
"dylib",
"so",
"dylib",
"dylib",
"wasm"
"wasm",
""
};
// TODO(karroffel): make this actually do the right thing.
GDNativeLibrary::Platform GDNativeLibrary::current_platform =
#if defined(X11_ENABLED)
X11_64BIT;
(sizeof(void *) == 8 ? X11_64BIT : X11_32BIT);
#elif defined(WINDOWS_ENABLED)
WINDOWS_64BIT;
(sizeof(void *) == 8 ? WINDOWS_64BIT : WINDOWS_32BIT);
#elif defined(OSX_ENABLED)
OSX;
#elif defined(IPHONE_ENABLED)
(sizeof(void *) == 8 ? IOS_64BIT : IOS_32BIT);
#elif defined(ANDROID_ENABLED)
ANDROID;
#elif defined(JAVASCRIPT_ENABLED)
WASM;
#else
X11_64BIT; // need a sensible default..
NUM_PLATFORMS;
#endif
GDNativeLibrary::GDNativeLibrary()
@ -151,7 +164,10 @@ String GDNativeLibrary::get_library_path(StringName p_platform) const {
}
String GDNativeLibrary::get_active_library_path() const {
return library_paths[GDNativeLibrary::current_platform];
if (GDNativeLibrary::current_platform != NUM_PLATFORMS) {
return library_paths[GDNativeLibrary::current_platform];
}
return "";
}
GDNative::GDNative() {

View File

@ -48,11 +48,17 @@ class GDNativeLibrary : public Resource {
// NOTE(karroffel): I heard OSX 32 bit is dead, so 64 only
OSX,
// TODO(karroffel): all different android versions and archs
// Android .so files must be located in directories corresponding to Android ABI names:
// https://developer.android.com/ndk/guides/abis.html
// Android runtime will select the matching library depending on the device.
// The value here must simply point to the .so name, for example:
// "res://libmy_gdnative.so" or "libmy_gdnative.so",
// while in the project the actual paths can be "lib/android/armeabi-v7a/libmy_gdnative.so",
// "lib/android/arm64-v8a/libmy_gdnative.so".
ANDROID,
// TODO(karroffe): all different iOS versions and archs
IOS,
IOS_32BIT,
IOS_64BIT,
// TODO(karroffel): figure out how to deal with web stuff at all...
WASM,
@ -64,10 +70,9 @@ class GDNativeLibrary : public Resource {
};
static String platform_names[NUM_PLATFORMS];
static String platform_lib_ext[NUM_PLATFORMS];
static String platform_names[NUM_PLATFORMS + 1];
static String platform_lib_ext[NUM_PLATFORMS + 1];
// TODO(karroffel): make this actually do something lol.
static Platform current_platform;
String library_paths[NUM_PLATFORMS];

View File

@ -37,7 +37,7 @@ extern "C" {
#include <stdint.h>
#define GODOT_ARRAY_SIZE 8
#define GODOT_ARRAY_SIZE sizeof(void *)
#ifndef GODOT_CORE_API_GODOT_ARRAY_TYPE_DEFINED
#define GODOT_CORE_API_GODOT_ARRAY_TYPE_DEFINED

View File

@ -36,7 +36,7 @@ extern "C" {
#include <stdint.h>
#define GODOT_DICTIONARY_SIZE 8
#define GODOT_DICTIONARY_SIZE sizeof(void *)
#ifndef GODOT_CORE_API_GODOT_DICTIONARY_TYPE_DEFINED
#define GODOT_CORE_API_GODOT_DICTIONARY_TYPE_DEFINED

View File

@ -56,7 +56,7 @@ extern "C" {
#define GDAPI GDCALLINGCONV
#endif
#else
#define GDCALLINGCONV __attribute__((sysv_abi))
#define GDCALLINGCONV __attribute__((sysv_abi, visibility("default")))
#define GDAPI GDCALLINGCONV
#endif

View File

@ -36,7 +36,7 @@ extern "C" {
#include <stdint.h>
#define GODOT_NODE_PATH_SIZE 8
#define GODOT_NODE_PATH_SIZE sizeof(void *)
#ifndef GODOT_CORE_API_GODOT_NODE_PATH_TYPE_DEFINED
#define GODOT_CORE_API_GODOT_NODE_PATH_TYPE_DEFINED

View File

@ -38,7 +38,7 @@ extern "C" {
/////// PoolByteArray
#define GODOT_POOL_BYTE_ARRAY_SIZE 8
#define GODOT_POOL_BYTE_ARRAY_SIZE sizeof(void *)
#ifndef GODOT_CORE_API_GODOT_POOL_BYTE_ARRAY_TYPE_DEFINED
#define GODOT_CORE_API_GODOT_POOL_BYTE_ARRAY_TYPE_DEFINED
@ -49,7 +49,7 @@ typedef struct {
/////// PoolIntArray
#define GODOT_POOL_INT_ARRAY_SIZE 8
#define GODOT_POOL_INT_ARRAY_SIZE sizeof(void *)
#ifndef GODOT_CORE_API_GODOT_POOL_INT_ARRAY_TYPE_DEFINED
#define GODOT_CORE_API_GODOT_POOL_INT_ARRAY_TYPE_DEFINED
@ -60,7 +60,7 @@ typedef struct {
/////// PoolRealArray
#define GODOT_POOL_REAL_ARRAY_SIZE 8
#define GODOT_POOL_REAL_ARRAY_SIZE sizeof(void *)
#ifndef GODOT_CORE_API_GODOT_POOL_REAL_ARRAY_TYPE_DEFINED
#define GODOT_CORE_API_GODOT_POOL_REAL_ARRAY_TYPE_DEFINED
@ -71,7 +71,7 @@ typedef struct {
/////// PoolStringArray
#define GODOT_POOL_STRING_ARRAY_SIZE 8
#define GODOT_POOL_STRING_ARRAY_SIZE sizeof(void *)
#ifndef GODOT_CORE_API_GODOT_POOL_STRING_ARRAY_TYPE_DEFINED
#define GODOT_CORE_API_GODOT_POOL_STRING_ARRAY_TYPE_DEFINED
@ -82,7 +82,7 @@ typedef struct {
/////// PoolVector2Array
#define GODOT_POOL_VECTOR2_ARRAY_SIZE 8
#define GODOT_POOL_VECTOR2_ARRAY_SIZE sizeof(void *)
#ifndef GODOT_CORE_API_GODOT_POOL_VECTOR2_ARRAY_TYPE_DEFINED
#define GODOT_CORE_API_GODOT_POOL_VECTOR2_ARRAY_TYPE_DEFINED
@ -93,7 +93,7 @@ typedef struct {
/////// PoolVector3Array
#define GODOT_POOL_VECTOR3_ARRAY_SIZE 8
#define GODOT_POOL_VECTOR3_ARRAY_SIZE sizeof(void *)
#ifndef GODOT_CORE_API_GODOT_POOL_VECTOR3_ARRAY_TYPE_DEFINED
#define GODOT_CORE_API_GODOT_POOL_VECTOR3_ARRAY_TYPE_DEFINED
@ -104,7 +104,7 @@ typedef struct {
/////// PoolColorArray
#define GODOT_POOL_COLOR_ARRAY_SIZE 8
#define GODOT_POOL_COLOR_ARRAY_SIZE sizeof(void *)
#ifndef GODOT_CORE_API_GODOT_POOL_COLOR_ARRAY_TYPE_DEFINED
#define GODOT_CORE_API_GODOT_POOL_COLOR_ARRAY_TYPE_DEFINED

View File

@ -36,7 +36,7 @@ extern "C" {
#include <stdint.h>
#define GODOT_RID_SIZE 8
#define GODOT_RID_SIZE sizeof(void *)
#ifndef GODOT_CORE_API_GODOT_RID_TYPE_DEFINED
#define GODOT_CORE_API_GODOT_RID_TYPE_DEFINED

View File

@ -37,7 +37,7 @@ extern "C" {
#include <stdint.h>
#include <wchar.h>
#define GODOT_STRING_SIZE 8
#define GODOT_STRING_SIZE sizeof(void *)
#ifndef GODOT_CORE_API_GODOT_STRING_TYPE_DEFINED
#define GODOT_CORE_API_GODOT_STRING_TYPE_DEFINED

View File

@ -36,7 +36,7 @@ extern "C" {
#include <stdint.h>
#define GODOT_VARIANT_SIZE 24
#define GODOT_VARIANT_SIZE (16 + sizeof(void *))
#ifndef GODOT_CORE_API_GODOT_VARIANT_TYPE_DEFINED
#define GODOT_CORE_API_GODOT_VARIANT_TYPE_DEFINED

View File

@ -58,7 +58,7 @@ extern "C" {
#define GDAPI GDCALLINGCONV
#endif
#else
#define GDCALLINGCONV __attribute__((sysv_abi))
#define GDCALLINGCONV __attribute__((sysv_abi, visibility("default")))
#define GDAPI GDCALLINGCONV
#endif

View File

@ -994,6 +994,8 @@ void NativeScriptLanguage::init_library(const Ref<GDNativeLibrary> &lib) {
#endif
// See if this library was "registered" already.
const String &lib_path = lib->get_active_library_path();
ERR_EXPLAIN(lib->get_name() + " does not have a library for the current platform");
ERR_FAIL_COND(lib_path.length() == 0);
Map<String, Ref<GDNative> >::Element *E = library_gdnatives.find(lib_path);
if (!E) {

View File

@ -240,7 +240,7 @@ def configure(env):
env.Append(CPPPATH=['#platform/android'])
env.Append(CPPFLAGS=['-DANDROID_ENABLED', '-DUNIX_ENABLED', '-DNO_FCNTL', '-DMPC_FIXED_POINT'])
env.Append(LIBS=['OpenSLES', 'EGL', 'GLESv3', 'android', 'log', 'z'])
env.Append(LIBS=['OpenSLES', 'EGL', 'GLESv3', 'android', 'log', 'z', 'dl'])
# TODO: Move that to opus module's config
if("module_opus_enabled" in env and env["module_opus_enabled"] != "no"):

View File

@ -468,11 +468,36 @@ class EditorExportAndroid : public EditorExportPlatform {
return zipfi;
}
static Error save_apk_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total) {
static Set<String> get_abis() {
Set<String> abis;
abis.insert("armeabi");
abis.insert("armeabi-v7a");
abis.insert("arm64-v8a");
abis.insert("x86");
abis.insert("x86_64");
abis.insert("mips");
abis.insert("mips64");
return abis;
}
static Error save_apk_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total) {
APKExportData *ed = (APKExportData *)p_userdata;
String dst_path = p_path;
dst_path = dst_path.replace_first("res://", "assets/");
static Set<String> android_abis = get_abis();
if (dst_path.ends_with(".so")) {
String abi = dst_path.get_base_dir().get_file().strip_edges(); // parent dir name
if (android_abis.has(abi)) {
dst_path = "lib/" + abi + "/" + dst_path.get_file();
} else {
String err = "Dynamic libraries must be located in the folder named after Android ABI they were compiled for. " +
p_path + " does not follow this convention.";
ERR_PRINT(err.utf8().get_data());
return ERR_FILE_BAD_PATH;
}
} else {
dst_path = dst_path.replace_first("res://", "assets/");
}
zip_fileinfo zipfi = get_zip_fileinfo();
@ -1375,15 +1400,15 @@ public:
}
}
if (file == "lib/x86/libgodot_android.so" && !export_x86) {
if (file == "lib/x86/*.so" && !export_x86) {
skip = true;
}
if (file.match("lib/armeabi*/libgodot_android.so") && !export_arm) {
if (file.match("lib/armeabi*/*.so") && !export_arm) {
skip = true;
}
if (file.match("lib/arm64*/libgodot_android.so") && !export_arm64) {
if (file.match("lib/arm64*/*.so") && !export_arm64) {
skip = true;
}

View File

@ -92,7 +92,7 @@ import android.os.SystemClock;
public class Godot extends Activity implements SensorEventListener, IDownloaderClient
{
{
static final int MAX_SINGLETONS = 64;
private IStub mDownloaderClientStub;
@ -139,9 +139,9 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
com.godot.game.R.string.text_button_pause;
mPauseButton.setText(stringResourceID);
}
static public class SingletonBase {
protected void registerClass(String p_name, String[] p_methods) {
GodotLib.singleton(p_name,this);
@ -210,6 +210,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
*/
private String[] command_line;
private boolean use_apk_expansion;
public GodotView mView;
private boolean godot_initialized=false;
@ -264,27 +265,40 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
layout = new FrameLayout(this);
layout.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT));
setContentView(layout);
// GodotEditText layout
GodotEditText edittext = new GodotEditText(this);
GodotEditText edittext = new GodotEditText(this);
edittext.setLayoutParams(new ViewGroup.LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.WRAP_CONTENT));
// ...add to FrameLayout
layout.addView(edittext);
mView = new GodotView(getApplication(),io,use_gl2,use_32_bits, this);
layout.addView(mView,new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT));
setKeepScreenOn(GodotLib.getGlobal("display/driver/keep_screen_on").equals("True"));
edittext.setView(mView);
io.setEdit(edittext);
edittext.setView(mView);
io.setEdit(edittext);
// Ad layout
adLayout = new RelativeLayout(this);
adLayout.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT));
layout.addView(adLayout);
final String[] current_command_line = command_line;
final GodotView view = mView;
mView.queueEvent(new Runnable() {
@Override
public void run() {
GodotLib.setup(current_command_line);
runOnUiThread(new Runnable() {
@Override
public void run() {
view.setKeepScreenOn("True".equals(GodotLib.getGlobal("display/driver/keep_screen_on")));
}
});
}
});
}
public void setKeepScreenOn(final boolean p_enabled) {
keep_screen_on = p_enabled;
if (mView != null){
@ -315,13 +329,13 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
}
});
}
private static Godot _self;
public static Godot getInstance(){
return Godot._self;
}
private String[] getCommandLine() {
InputStream is;
@ -402,7 +416,6 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
Log.d("GODOT"," " + command_line[w]);
}
}*/
GodotLib.initialize(this,io.needsReloadHooks(),command_line,getAssets());
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_GAME);
@ -411,9 +424,12 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
mGyroscope = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
mSensorManager.registerListener(this, mGyroscope, SensorManager.SENSOR_DELAY_GAME);
GodotLib.initialize(this, io.needsReloadHooks(), getAssets(), use_apk_expansion);
result_callback = null;
mPaymentsManager = PaymentsManager.createManager(this).initService();
godot_initialized=true;
}
@ -426,7 +442,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
@Override
@Override
protected void onCreate(Bundle icicle) {
Log.d("GODOT", "** GODOT ACTIVITY CREATED HERE ***\n");
@ -437,12 +453,10 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
//window.addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
window.addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
//check for apk expansion API
if (true) {
boolean md5mismatch = false;
command_line = getCommandLine();
boolean use_apk_expansion=false;
String main_pack_md5=null;
String main_pack_key=null;
@ -528,23 +542,23 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
if (!pack_valid) {
Log.d("GODOT", "Pack Invalid, try re-downloading.");
Intent notifierIntent = new Intent(this, this.getClass());
notifierIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
notifierIntent, PendingIntent.FLAG_UPDATE_CURRENT);
int startResult;
try {
Log.d("GODOT", "INITIALIZING DOWNLOAD");
startResult = DownloaderClientMarshaller.startDownloadServiceIfRequired(
getApplicationContext(),
pendingIntent,
getApplicationContext(),
pendingIntent,
GodotDownloaderService.class);
Log.d("GODOT", "DOWNLOAD SERVICE FINISHED:" + startResult);
if (startResult != DownloaderClientMarshaller.NO_DOWNLOAD_REQUIRED) {
Log.d("GODOT", "DOWNLOAD REQUIRED");
// This is where you do set up to display the download
@ -563,7 +577,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
mCellMessage = findViewById(com.godot.game.R.id.approveCellular);
mPauseButton = (Button) findViewById(com.godot.game.R.id.pauseButton);
mWiFiSettingsButton = (Button) findViewById(com.godot.game.R.id.wifiSettingsButton);
return;
} else{
Log.d("GODOT", "NO DOWNLOAD REQUIRED");
@ -582,7 +596,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
initializeGodot();
//instanceSingleton( new GodotFacebook(this) );
@ -590,14 +604,14 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
@Override protected void onDestroy(){
if(mPaymentsManager != null ) mPaymentsManager.destroy();
for(int i=0;i<singleton_count;i++) {
singletons[i].onMainDestroy();
}
super.onDestroy();
}
@Override protected void onPause() {
super.onPause();
if (!godot_initialized){
@ -607,8 +621,13 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
return;
}
mView.onPause();
mView.queueEvent(new Runnable() {
@Override
public void run() {
GodotLib.focusout();
}
});
mSensorManager.unregisterListener(this);
GodotLib.focusout();
for(int i=0;i<singleton_count;i++) {
singletons[i].onMainPause();
@ -625,10 +644,16 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
}
mView.onResume();
mView.queueEvent(new Runnable() {
@Override
public void run() {
GodotLib.focusin();
}
});
mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_GAME);
mSensorManager.registerListener(this, mMagnetometer, SensorManager.SENSOR_DELAY_GAME);
mSensorManager.registerListener(this, mGyroscope, SensorManager.SENSOR_DELAY_GAME);
GodotLib.focusin();
if(use_immersive && Build.VERSION.SDK_INT >= 19.0){ // check if the application runs on an android 4.4+
Window window = getWindow();
window.getDecorView().setSystemUiVisibility(
@ -644,8 +669,8 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
singletons[i].onMainResume();
}
}
@ -670,32 +695,39 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
@Override public void onSensorChanged(SensorEvent event) {
Display display = ((WindowManager) getSystemService(WINDOW_SERVICE)).getDefaultDisplay();
int displayRotation = display.getRotation();
float[] adjustedValues = new float[3];
final int axisSwap[][] = {
{ 1, -1, 0, 1 }, // ROTATION_0
{-1, -1, 1, 0 }, // ROTATION_90
{-1, 1, 0, 1 }, // ROTATION_180
{ 1, 1, 1, 0 } }; // ROTATION_270
{ 1, -1, 0, 1 }, // ROTATION_0
{-1, -1, 1, 0 }, // ROTATION_90
{-1, 1, 0, 1 }, // ROTATION_180
{ 1, 1, 1, 0 } }; // ROTATION_270
final int[] as = axisSwap[displayRotation];
adjustedValues[0] = (float)as[0] * event.values[ as[2] ];
adjustedValues[1] = (float)as[1] * event.values[ as[3] ];
final int[] as = axisSwap[displayRotation];
adjustedValues[0] = (float)as[0] * event.values[ as[2] ];
adjustedValues[1] = (float)as[1] * event.values[ as[3] ];
adjustedValues[2] = event.values[2];
float x = adjustedValues[0];
float y = adjustedValues[1];
float z = adjustedValues[2];
int typeOfSensor = event.sensor.getType();
if (typeOfSensor == event.sensor.TYPE_ACCELEROMETER) {
GodotLib.accelerometer(x,y,z);
}
if (typeOfSensor == event.sensor.TYPE_MAGNETIC_FIELD) {
GodotLib.magnetometer(x,y,z);
}
if (typeOfSensor == event.sensor.TYPE_GYROSCOPE) {
GodotLib.gyroscope(x,y,z);
final float x = adjustedValues[0];
final float y = adjustedValues[1];
final float z = adjustedValues[2];
final int typeOfSensor = event.sensor.getType();
if (mView != null) {
mView.queueEvent(new Runnable() {
@Override
public void run() {
if (typeOfSensor == Sensor.TYPE_ACCELEROMETER) {
GodotLib.accelerometer(x,y,z);
}
if (typeOfSensor == Sensor.TYPE_MAGNETIC_FIELD) {
GodotLib.magnetometer(x,y,z);
}
if (typeOfSensor == Sensor.TYPE_GYROSCOPE) {
GodotLib.gyroscope(x,y,z);
}
}
});
}
}
@ -722,7 +754,14 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
@Override public void onBackPressed() {
System.out.printf("** BACK REQUEST!\n");
//GodotLib.back();
if (mView != null) {
mView.queueEvent(new Runnable() {
@Override
public void run() {
GodotLib.back();
}
});
}
}
public void forceQuit() {
@ -733,7 +772,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
private boolean obbIsCorrupted(String f, String main_pack_md5){
try {
InputStream fis = new FileInputStream(f);
@ -780,58 +819,64 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
}
//@Override public boolean dispatchTouchEvent (MotionEvent event) {
public boolean gotTouchEvent(MotionEvent event) {
public boolean gotTouchEvent(final MotionEvent event) {
super.onTouchEvent(event);
int evcount=event.getPointerCount();
final int evcount=event.getPointerCount();
if (evcount==0)
return true;
int[] arr = new int[event.getPointerCount()*3];
if (mView != null) {
final int[] arr = new int[event.getPointerCount()*3];
for(int i=0;i<event.getPointerCount();i++) {
for(int i=0;i<event.getPointerCount();i++) {
arr[i*3+0]=(int)event.getPointerId(i);
arr[i*3+1]=(int)event.getX(i);
arr[i*3+2]=(int)event.getY(i);
}
arr[i*3+0]=(int)event.getPointerId(i);
arr[i*3+1]=(int)event.getX(i);
arr[i*3+2]=(int)event.getY(i);
}
//System.out.printf("gaction: %d\n",event.getAction());
switch(event.getAction()&MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: {
GodotLib.touch(0,0,evcount,arr);
//System.out.printf("action down at: %f,%f\n", event.getX(),event.getY());
} break;
case MotionEvent.ACTION_MOVE: {
GodotLib.touch(1,0,evcount,arr);
/*
for(int i=0;i<event.getPointerCount();i++) {
System.out.printf("%d - moved to: %f,%f\n",i, event.getX(i),event.getY(i));
//System.out.printf("gaction: %d\n",event.getAction());
final int action = event.getAction() & MotionEvent.ACTION_MASK;
mView.queueEvent(new Runnable() {
@Override
public void run() {
switch(action) {
case MotionEvent.ACTION_DOWN: {
GodotLib.touch(0,0,evcount,arr);
//System.out.printf("action down at: %f,%f\n", event.getX(),event.getY());
} break;
case MotionEvent.ACTION_MOVE: {
GodotLib.touch(1,0,evcount,arr);
/*
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 MotionEvent.ACTION_POINTER_UP: {
final int indexPointUp = event.getActionIndex();
final int pointer_idx = event.getPointerId(indexPointUp);
GodotLib.touch(4,pointer_idx,evcount,arr);
//System.out.printf("%d - s.up at: %f,%f\n",pointer_idx, event.getX(pointer_idx),event.getY(pointer_idx));
} break;
case MotionEvent.ACTION_POINTER_DOWN: {
int pointer_idx = event.getActionIndex();
GodotLib.touch(3,pointer_idx,evcount,arr);
//System.out.printf("%d - s.down at: %f,%f\n",pointer_idx, event.getX(pointer_idx),event.getY(pointer_idx));
} break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP: {
GodotLib.touch(2,0,evcount,arr);
/*
for(int i=0;i<event.getPointerCount();i++) {
System.out.printf("%d - up! %f,%f\n",i, event.getX(i),event.getY(i));
}
*/
} break;
}
}
*/
} break;
case MotionEvent.ACTION_POINTER_UP: {
final int indexPointUp = event.getActionIndex();
final int pointer_idx = event.getPointerId(indexPointUp);
GodotLib.touch(4,pointer_idx,evcount,arr);
//System.out.printf("%d - s.up at: %f,%f\n",pointer_idx, event.getX(pointer_idx),event.getY(pointer_idx));
} break;
case MotionEvent.ACTION_POINTER_DOWN: {
int pointer_idx = event.getActionIndex();
GodotLib.touch(3,pointer_idx,evcount,arr);
//System.out.printf("%d - s.down at: %f,%f\n",pointer_idx, event.getX(pointer_idx),event.getY(pointer_idx));
} break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP: {
GodotLib.touch(2,0,evcount,arr);
/*
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 true;
}
@ -864,7 +909,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
private void queueEvent(Runnable runnable) {
// TODO Auto-generated method stub
}
public PaymentsManager getPaymentsManager() {
@ -988,7 +1033,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
mProgressFraction.setText(Helpers.getDownloadProgressString
(progress.mOverallProgress,
progress.mOverallTotal));
}
}

View File

@ -37,7 +37,7 @@ public class GodotLib {
public static GodotIO io;
static {
System.loadLibrary("godot_android");
System.loadLibrary("godot_android");
}
/**
@ -45,7 +45,8 @@ public class GodotLib {
* @param height the current view height
*/
public static native void initialize(Godot p_instance,boolean need_reload_hook,String[] p_cmdline,Object p_asset_manager);
public static native void initialize(Godot p_instance,boolean need_reload_hook,Object p_asset_manager, boolean use_apk_expansion);
public static native void setup(String[] p_cmdline);
public static native void resize(int width, int height,boolean reload);
public static native void newcontext(boolean p_32_bits);
public static native void back();

View File

@ -89,7 +89,7 @@ public class GodotPaymentV3 extends Godot.SingletonBase {
}
public void callbackSuccess(String ticket, String signature, String sku) {
GodotLib.callobject(purchaseCallbackId, "purchase_success", new Object[]{ticket, signature, sku});
GodotLib.calldeferred(purchaseCallbackId, "purchase_success", new Object[]{ticket, signature, sku});
}
public void callbackSuccessProductMassConsumed(String ticket, String signature, String sku) {

View File

@ -208,8 +208,9 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener {
@Override public void onInputDeviceAdded(int deviceId) {
joystick joy = new joystick();
joy.device_id = deviceId;
int id = joy_devices.size();
final int id = joy_devices.size();
InputDevice device = mInputManager.getInputDevice(deviceId);
final String name = device.getName();
joy.name = device.getName();
joy.axes = new ArrayList<InputDevice.MotionRange>();
joy.hats = new ArrayList<InputDevice.MotionRange>();
@ -224,19 +225,29 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener {
}
}
joy_devices.add(joy);
GodotLib.joyconnectionchanged(id, true, joy.name);
queueEvent(new Runnable() {
@Override
public void run() {
GodotLib.joyconnectionchanged(id, true, name);
}
});
}
@Override public void onInputDeviceRemoved(int deviceId) {
int id = find_joy_device(deviceId);
final int id = find_joy_device(deviceId);
joy_devices.remove(id);
GodotLib.joyconnectionchanged(id, false, "");
queueEvent(new Runnable() {
@Override
public void run() {
GodotLib.joyconnectionchanged(id, false, "");
}
});
}
@Override public void onInputDeviceChanged(int deviceId) {
}
@Override public boolean onKeyUp(int keyCode, KeyEvent event) {
@Override public boolean onKeyUp(final int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
return true;
@ -249,22 +260,38 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener {
int source = event.getSource();
if ((source & InputDevice.SOURCE_JOYSTICK) != 0 || (source & InputDevice.SOURCE_DPAD) != 0 || (source & InputDevice.SOURCE_GAMEPAD) != 0) {
int button = get_godot_button(keyCode);
int device = find_joy_device(event.getDeviceId());
final int button = get_godot_button(keyCode);
final int device = find_joy_device(event.getDeviceId());
GodotLib.joybutton(device, button, false);
queueEvent(new Runnable() {
@Override
public void run() {
GodotLib.joybutton(device, button, false);
}
});
return true;
} else {
GodotLib.key(keyCode, event.getUnicodeChar(0), false);
final int chr = event.getUnicodeChar(0);
queueEvent(new Runnable() {
@Override
public void run() {
GodotLib.key(keyCode, chr, false);
}
});
};
return super.onKeyUp(keyCode, event);
};
@Override public boolean onKeyDown(int keyCode, KeyEvent event) {
@Override public boolean onKeyDown(final int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
GodotLib.back();
queueEvent(new Runnable() {
@Override
public void run() {
GodotLib.back();
}
});
// press 'back' button should not terminate program
//normal handle 'back' event in game logic
return true;
@ -281,16 +308,26 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener {
if (event.getRepeatCount() > 0) // ignore key echo
return true;
int button = get_godot_button(keyCode);
int device = find_joy_device(event.getDeviceId());
final int button = get_godot_button(keyCode);
final int device = find_joy_device(event.getDeviceId());
//Log.e(TAG, String.format("joy button down! button %x, %d, device %d", keyCode, button, device));
GodotLib.joybutton(device, button, true);
queueEvent(new Runnable() {
@Override
public void run() {
GodotLib.joybutton(device, button, true);
}
});
return true;
} else {
GodotLib.key(keyCode, event.getUnicodeChar(0), true);
final int chr = event.getUnicodeChar(0);
queueEvent(new Runnable() {
@Override
public void run() {
GodotLib.key(keyCode, chr, true);
}
});
};
return super.onKeyDown(keyCode, event);
}
@ -299,21 +336,32 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener {
if ((event.getSource() & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK && event.getAction() == MotionEvent.ACTION_MOVE) {
int device_id = find_joy_device(event.getDeviceId());
final int device_id = find_joy_device(event.getDeviceId());
joystick joy = joy_devices.get(device_id);
for (int i = 0; i < joy.axes.size(); i++) {
InputDevice.MotionRange range = joy.axes.get(i);
float value = (event.getAxisValue(range.getAxis()) - range.getMin() ) / range.getRange() * 2.0f - 1.0f;
final float value = (event.getAxisValue(range.getAxis()) - range.getMin() ) / range.getRange() * 2.0f - 1.0f;
//Log.e(TAG, String.format("axis event: %d, value %f", i, value));
GodotLib.joyaxis(device_id, i, value);
final int idx = i;
queueEvent(new Runnable() {
@Override
public void run() {
GodotLib.joyaxis(device_id, idx, value);
}
});
}
for (int i = 0; i < joy.hats.size(); i+=2) {
int hatX = Math.round(event.getAxisValue(joy.hats.get(i).getAxis()));
int hatY = Math.round(event.getAxisValue(joy.hats.get(i+1).getAxis()));
final int hatX = Math.round(event.getAxisValue(joy.hats.get(i).getAxis()));
final int hatY = Math.round(event.getAxisValue(joy.hats.get(i+1).getAxis()));
//Log.e(TAG, String.format("HAT EVENT %d, %d", hatX, hatY));
GodotLib.joyhat(device_id, hatX, hatY);
queueEvent(new Runnable() {
@Override
public void run() {
GodotLib.joyhat(device_id, hatX, hatY);
}
});
}
return true;
};

View File

@ -89,8 +89,13 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene
//Log.d(TAG, "beforeTextChanged(" + pCharSequence + ")start: " + start + ",count: " + count + ",after: " + after);
for (int i=0;i<count;i++){
GodotLib.key(KeyEvent.KEYCODE_DEL, 0, true);
GodotLib.key(KeyEvent.KEYCODE_DEL, 0, false);
mView.queueEvent(new Runnable() {
@Override
public void run() {
GodotLib.key(KeyEvent.KEYCODE_DEL, 0, true);
GodotLib.key(KeyEvent.KEYCODE_DEL, 0, false);
}
});
}
}
@ -99,9 +104,14 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene
//Log.d(TAG, "onTextChanged(" + pCharSequence + ")start: " + start + ",count: " + count + ",before: " + before);
for (int i=start;i<start+count;i++){
int ch = pCharSequence.charAt(i);
GodotLib.key(0, ch, true);
GodotLib.key(0, ch, false);
final int ch = pCharSequence.charAt(i);
mView.queueEvent(new Runnable() {
@Override
public void run() {
GodotLib.key(0, ch, true);
GodotLib.key(0, ch, false);
}
});
}
}
@ -111,8 +121,14 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene
if (this.mEdit == pTextView && this.isFullScreenEdit()) {
// user press the action button, delete all old text and insert new text
for (int i = this.mOriginText.length(); i > 0; i--) {
GodotLib.key(KeyEvent.KEYCODE_DEL, 0, true);
GodotLib.key(KeyEvent.KEYCODE_DEL, 0, false);
mView.queueEvent(new Runnable() {
@Override
public void run() {
GodotLib.key(KeyEvent.KEYCODE_DEL, 0, true);
GodotLib.key(KeyEvent.KEYCODE_DEL, 0, false);
}
});
/*
if (BuildConfig.DEBUG) {
Log.d(TAG, "deleteBackward");
@ -131,9 +147,14 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene
}
for(int i = 0; i < text.length(); i++) {
int ch = text.codePointAt(i);
GodotLib.key(0, ch, true);
GodotLib.key(0, ch, false);
final int ch = text.codePointAt(i);
mView.queueEvent(new Runnable() {
@Override
public void run() {
GodotLib.key(0, ch, true);
GodotLib.key(0, ch, false);
}
});
}
/*
if (BuildConfig.DEBUG) {
@ -141,7 +162,7 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene
}
*/
}
if (pActionID == EditorInfo.IME_ACTION_DONE) {
this.mView.requestFocus();
}

View File

@ -613,8 +613,6 @@ static List<JAndroidPointerEvent> pointer_events;
static List<Ref<InputEvent> > key_events;
static List<OS_Android::JoypadEvent> joy_events;
static bool initialized = false;
static Mutex *input_mutex = NULL;
static Mutex *suspend_mutex = NULL;
static int step = 0;
static bool resized = false;
static bool resized_reload = false;
@ -756,7 +754,7 @@ static void _alert(const String &p_message, const String &p_title) {
env->CallVoidMethod(_godot_instance, _alertDialog, jStrMessage, jStrTitle);
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *env, jobject obj, jobject activity, jboolean p_need_reload_hook, jobjectArray p_cmdline, jobject p_asset_manager) {
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *env, jobject obj, jobject activity, jboolean p_need_reload_hook, jobject p_asset_manager, jboolean p_use_apk_expansion) {
__android_log_print(ANDROID_LOG_INFO, "godot", "**INIT EVENT! - %p\n", env);
@ -826,36 +824,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *en
AudioDriverAndroid::setup(gob);
}
const char **cmdline = NULL;
int cmdlen = 0;
bool use_apk_expansion = false;
if (p_cmdline) {
cmdlen = env->GetArrayLength(p_cmdline);
if (cmdlen) {
cmdline = (const char **)malloc((env->GetArrayLength(p_cmdline) + 1) * sizeof(const char *));
cmdline[cmdlen] = NULL;
for (int i = 0; i < cmdlen; i++) {
jstring string = (jstring)env->GetObjectArrayElement(p_cmdline, i);
const char *rawString = env->GetStringUTFChars(string, 0);
if (!rawString) {
__android_log_print(ANDROID_LOG_INFO, "godot", "cmdline arg %i is null\n", i);
} else {
//__android_log_print(ANDROID_LOG_INFO,"godot","cmdline arg %i is: %s\n",i,rawString);
if (strcmp(rawString, "--main_pack") == 0)
use_apk_expansion = true;
}
cmdline[i] = rawString;
}
}
}
__android_log_print(ANDROID_LOG_INFO, "godot", "CMDLINE LEN %i - APK EXPANSION %I\n", cmdlen, int(use_apk_expansion));
os_android = new OS_Android(_gfx_init_func, env, _open_uri, _get_data_dir, _get_locale, _get_model, _get_screen_dpi, _show_vk, _hide_vk, _set_screen_orient, _get_unique_id, _get_system_dir, _play_video, _is_video_playing, _pause_video, _stop_video, _set_keep_screen_on, _alert, use_apk_expansion);
os_android = new OS_Android(_gfx_init_func, env, _open_uri, _get_data_dir, _get_locale, _get_model, _get_screen_dpi, _show_vk, _hide_vk, _set_screen_orient, _get_unique_id, _get_system_dir, _play_video, _is_video_playing, _pause_video, _stop_video, _set_keep_screen_on, _alert, p_use_apk_expansion);
os_android->set_need_reload_hooks(p_need_reload_hook);
char wd[500];
@ -864,62 +833,10 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *en
__android_log_print(ANDROID_LOG_INFO, "godot", "test construction %i\n", tst.a);
__android_log_print(ANDROID_LOG_INFO, "godot", "running from dir %s\n", wd);
__android_log_print(ANDROID_LOG_INFO, "godot", "**SETUP");
Error err = Main::setup("apk", cmdlen, (char **)cmdline, false);
if (err != OK) {
__android_log_print(ANDROID_LOG_INFO, "godot", "*****UNABLE TO SETUP");
return; //should exit instead and print the error
}
__android_log_print(ANDROID_LOG_INFO, "godot", "*****SETUP OK");
//video driver is determined here, because once initialized, it can't be changed
String vd = ProjectSettings::get_singleton()->get("display/driver");
// String vd = ProjectSettings::get_singleton()->get("display/driver");
env->CallVoidMethod(_godot_instance, _on_video_init, (jboolean) true);
__android_log_print(ANDROID_LOG_INFO, "godot", "**START");
input_mutex = Mutex::create();
suspend_mutex = Mutex::create();
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_resize(JNIEnv *env, jobject obj, jint width, jint height, jboolean reload) {
__android_log_print(ANDROID_LOG_INFO, "godot", "^_^_^_^_^ resize %lld, %i, %i\n", Thread::get_caller_id(), width, height);
if (os_android)
os_android->set_display_size(Size2(width, height));
/*input_mutex->lock();
resized=true;
if (reload)
resized_reload=true;
new_size=Size2(width,height);
input_mutex->unlock();*/
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv *env, jobject obj, bool p_32_bits) {
__android_log_print(ANDROID_LOG_INFO, "godot", "^_^_^_^_^ newcontext %lld\n", Thread::get_caller_id());
if (os_android) {
os_android->set_context_is_16_bits(!p_32_bits);
}
if (os_android && step > 0) {
os_android->reload_gfx();
}
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_back(JNIEnv *env, jobject obj) {
input_mutex->lock();
go_back_request = true;
input_mutex->unlock();
}
static void _initialize_java_modules() {
@ -985,36 +902,106 @@ static void _initialize_java_modules() {
}
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, jobject obj) {
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jobject obj, jobjectArray p_cmdline) {
ThreadAndroid::setup_thread();
//__android_log_print(ANDROID_LOG_INFO,"godot","**STEP EVENT! - %p-%i\n",env,Thread::get_caller_id());
__android_log_print(ANDROID_LOG_INFO, "godot", "**SETUP");
suspend_mutex->lock();
input_mutex->lock();
//first time step happens, initialize
const char **cmdline = NULL;
int cmdlen = 0;
bool use_apk_expansion = false;
if (p_cmdline) {
cmdlen = env->GetArrayLength(p_cmdline);
if (cmdlen) {
cmdline = (const char **)malloc((env->GetArrayLength(p_cmdline) + 1) * sizeof(const char *));
cmdline[cmdlen] = NULL;
for (int i = 0; i < cmdlen; i++) {
jstring string = (jstring)env->GetObjectArrayElement(p_cmdline, i);
const char *rawString = env->GetStringUTFChars(string, 0);
if (!rawString) {
__android_log_print(ANDROID_LOG_INFO, "godot", "cmdline arg %i is null\n", i);
} else {
//__android_log_print(ANDROID_LOG_INFO,"godot","cmdline arg %i is: %s\n",i,rawString);
if (strcmp(rawString, "-main_pack") == 0)
use_apk_expansion = true;
}
cmdline[i] = rawString;
}
}
}
__android_log_print(ANDROID_LOG_INFO, "godot", "CMDLINE LEN %i - APK EXPANSION %i\n", cmdlen, int(use_apk_expansion));
#if 0
char *args[]={"-test","render",NULL};
__android_log_print(ANDROID_LOG_INFO,"godot","pre asdasd setup...");
Error err = Main::setup("apk",2,args,false);
#else
Error err = Main::setup("apk", cmdlen, (char **)cmdline, false);
#endif
if (cmdline) {
free(cmdline);
}
if (err != OK) {
__android_log_print(ANDROID_LOG_INFO, "godot", "*****UNABLE TO SETUP");
return; //should exit instead and print the error
}
__android_log_print(ANDROID_LOG_INFO, "godot", "*****SETUP OK");
java_class_wrapper = memnew(JavaClassWrapper(_godot_instance));
ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("JavaClassWrapper", java_class_wrapper));
_initialize_java_modules();
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_resize(JNIEnv *env, jobject obj, jint width, jint height, jboolean reload) {
__android_log_print(ANDROID_LOG_INFO, "godot", "^_^_^_^_^ resize %lld, %i, %i\n", Thread::get_caller_id(), width, height);
if (os_android)
os_android->set_display_size(Size2(width, height));
/*input_mutex->lock();
resized=true;
if (reload)
resized_reload=true;
new_size=Size2(width,height);
input_mutex->unlock();*/
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv *env, jobject obj, bool p_32_bits) {
__android_log_print(ANDROID_LOG_INFO, "godot", "^_^_^_^_^ newcontext %lld\n", Thread::get_caller_id());
if (os_android) {
os_android->set_context_is_16_bits(!p_32_bits);
}
if (os_android && step > 0) {
os_android->reload_gfx();
}
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_back(JNIEnv *env, jobject obj) {
go_back_request = true;
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, jobject obj) {
if (step == 0) {
// ugly hack to initialize the rest of the engine
// because of the way android forces you to do everything with threads
java_class_wrapper = memnew(JavaClassWrapper(_godot_instance));
ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("JavaClassWrapper", java_class_wrapper));
_initialize_java_modules();
__android_log_print(ANDROID_LOG_INFO, "godot", "**FIRST_STEP");
// Since Godot is initialized on the UI thread, _main_thread_id was set to that thread's id,
// but for Godot purposes, the main thread is the one running the game loop
Main::setup2(Thread::get_caller_id());
++step;
suspend_mutex->unlock();
input_mutex->unlock();
return;
};
}
if (step == 1) {
if (!Main::start()) {
input_mutex->unlock();
suspend_mutex->lock();
return; //should exit instead and print the error
}
@ -1022,6 +1009,8 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, job
++step;
}
//__android_log_print(ANDROID_LOG_INFO,"godot","**STEP EVENT! - %p-%i\n",env,Thread::get_caller_id());
while (pointer_events.size()) {
JAndroidPointerEvent jpe = pointer_events.front()->get();
@ -1052,8 +1041,6 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, job
go_back_request = false;
}
input_mutex->unlock();
os_android->process_accelerometer(accelerometer);
os_android->process_magnetometer(magnetometer);
@ -1067,8 +1054,6 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, job
env->CallVoidMethod(_godot_instance, _finish);
__android_log_print(ANDROID_LOG_INFO, "godot", "**FINISH REQUEST!!! - %p-%i\n", env, Thread::get_caller_id());
}
suspend_mutex->unlock();
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch(JNIEnv *env, jobject obj, jint ev, jint pointer, jint count, jintArray positions) {
@ -1091,11 +1076,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch(JNIEnv *env, jo
jpe.points = points;
jpe.what = ev;
input_mutex->lock();
pointer_events.push_back(jpe);
input_mutex->unlock();
/*
if (os_android)
os_android->process_touch(ev,pointer,points);
@ -1365,9 +1346,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joybutton(JNIEnv *env
jevent.index = p_button;
jevent.pressed = p_pressed;
input_mutex->lock();
joy_events.push_back(jevent);
input_mutex->unlock();
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyaxis(JNIEnv *env, jobject obj, jint p_device, jint p_axis, jfloat p_value) {
@ -1378,9 +1357,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyaxis(JNIEnv *env,
jevent.index = p_axis;
jevent.value = p_value;
input_mutex->lock();
joy_events.push_back(jevent);
input_mutex->unlock();
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyhat(JNIEnv *env, jobject obj, jint p_device, jint p_hat_x, jint p_hat_y) {
@ -1401,9 +1378,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyhat(JNIEnv *env, j
hat |= InputDefault::HAT_MASK_DOWN;
}
jevent.hat = hat;
input_mutex->lock();
joy_events.push_back(jevent);
input_mutex->unlock();
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyconnectionchanged(JNIEnv *env, jobject obj, jint p_device, jboolean p_connected, jstring p_name) {
@ -1437,54 +1412,31 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_key(JNIEnv *env, jobj
go_back_request = true;
}
input_mutex->lock();
key_events.push_back(ievent);
input_mutex->unlock();
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_accelerometer(JNIEnv *env, jobject obj, jfloat x, jfloat y, jfloat z) {
input_mutex->lock();
accelerometer = Vector3(x, y, z);
input_mutex->unlock();
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_magnetometer(JNIEnv *env, jobject obj, jfloat x, jfloat y, jfloat z) {
input_mutex->lock();
magnetometer = Vector3(x, y, z);
input_mutex->unlock();
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_gyroscope(JNIEnv *env, jobject obj, jfloat x, jfloat y, jfloat z) {
input_mutex->lock();
gyroscope = Vector3(x, y, z);
input_mutex->unlock();
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_focusin(JNIEnv *env, jobject obj) {
if (!suspend_mutex)
return;
suspend_mutex->lock();
if (os_android && step > 0)
os_android->main_loop_focusin();
suspend_mutex->unlock();
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_focusout(JNIEnv *env, jobject obj) {
if (!suspend_mutex)
return;
suspend_mutex->lock();
if (os_android && step > 0)
os_android->main_loop_focusout();
suspend_mutex->unlock();
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_audio(JNIEnv *env, jobject obj) {

View File

@ -36,7 +36,8 @@
#include <jni.h>
extern "C" {
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *env, jobject obj, jobject activity, jboolean p_need_reload_hook, jobjectArray p_cmdline, jobject p_asset_manager);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *env, jobject obj, jobject activity, jboolean p_need_reload_hook, jobject p_asset_manager, jboolean p_use_apk_expansion);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jobject obj, jobjectArray p_cmdline);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_resize(JNIEnv *env, jobject obj, jint width, jint height, jboolean reload);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv *env, jobject obj, bool p_32_bits);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, jobject obj);