diff options
Diffstat (limited to 'platform')
59 files changed, 1319 insertions, 1188 deletions
diff --git a/platform/SCsub b/platform/SCsub index 2019a30be7..0f9c2047a0 100644 --- a/platform/SCsub +++ b/platform/SCsub @@ -18,10 +18,13 @@ for platform in env.platform_apis: reg_apis_inc += '\n' reg_apis += '}\n\n' unreg_apis += '}\n' + +# NOTE: It is safe to generate this file here, since this is still execute serially with open_utf8('register_platform_apis.gen.cpp', 'w') as f: - f.write(reg_apis_inc) - f.write(reg_apis) - f.write(unreg_apis) + f.write(reg_apis_inc) + f.write(reg_apis) + f.write(unreg_apis) + platform_sources.append('register_platform_apis.gen.cpp') lib = env.add_library('platform', platform_sources) diff --git a/platform/android/audio_driver_jandroid.cpp b/platform/android/audio_driver_jandroid.cpp index 3d80e76707..b9f1f1eab0 100644 --- a/platform/android/audio_driver_jandroid.cpp +++ b/platform/android/audio_driver_jandroid.cpp @@ -78,9 +78,9 @@ Error AudioDriverAndroid::init() { // __android_log_print(ANDROID_LOG_VERBOSE, "SDL", "SDL audio: opening device"); JNIEnv *env = ThreadAndroid::get_env(); - int mix_rate = GLOBAL_DEF("audio/mix_rate", 44100); + int mix_rate = GLOBAL_DEF_RST("audio/mix_rate", 44100); - int latency = GLOBAL_DEF("audio/output_latency", 25); + int latency = GLOBAL_DEF_RST("audio/output_latency", 25); unsigned int buffer_size = next_power_of_2(latency * mix_rate / 1000); if (OS::get_singleton()->is_stdout_verbose()) { print_line("audio buffer size: " + itos(buffer_size)); diff --git a/platform/android/audio_driver_opensl.cpp b/platform/android/audio_driver_opensl.cpp index e6bd3ff253..28e3ea962f 100644 --- a/platform/android/audio_driver_opensl.cpp +++ b/platform/android/audio_driver_opensl.cpp @@ -42,7 +42,8 @@ void AudioDriverOpenSL::_buffer_callback( /* SLuint32 eventFlags, const void * pBuffer, SLuint32 bufferSize, - SLuint32 dataUsed*/) { + SLuint32 dataUsed*/ +) { bool mix = true; @@ -145,9 +146,6 @@ void AudioDriverOpenSL::start() { res = (*sl)->GetInterface(sl, SL_IID_ENGINE, (void *)&EngineItf); ERR_FAIL_COND(res != SL_RESULT_SUCCESS); - /* Initialize arrays required[] and iidArray[] */ - SLboolean required[MAX_NUMBER_INTERFACES]; - SLInterfaceID iidArray[MAX_NUMBER_INTERFACES]; { const SLInterfaceID ids[1] = { SL_IID_ENVIRONMENTALREVERB }; @@ -187,10 +185,7 @@ void AudioDriverOpenSL::start() { //cntxt.pDataBase = (void*)&pcmData; //cntxt.pData = cntxt.pDataBase; //cntxt.size = sizeof(pcmData); - /* Set arrays required[] and iidArray[] for SEEK interface - (PlayItf is implicit) */ - required[0] = SL_BOOLEAN_TRUE; - iidArray[0] = SL_IID_BUFFERQUEUE; + /* Create the music player */ { diff --git a/platform/android/audio_driver_opensl.h b/platform/android/audio_driver_opensl.h index 2022bad02a..88cb122414 100644 --- a/platform/android/audio_driver_opensl.h +++ b/platform/android/audio_driver_opensl.h @@ -74,7 +74,8 @@ class AudioDriverOpenSL : public AudioDriver { /* SLuint32 eventFlags, const void * pBuffer, SLuint32 bufferSize, - SLuint32 dataUsed*/); + SLuint32 dataUsed*/ + ); static void _buffer_callbacks( SLAndroidSimpleBufferQueueItf queueItf, diff --git a/platform/android/detect.py b/platform/android/detect.py index 971368db17..ada36e2814 100644 --- a/platform/android/detect.py +++ b/platform/android/detect.py @@ -139,8 +139,13 @@ def configure(env): ## Build type if (env["target"].startswith("release")): - env.Append(LINKFLAGS=['-O2']) - env.Append(CPPFLAGS=['-O2', '-DNDEBUG', '-ffast-math', '-funsafe-math-optimizations', '-fomit-frame-pointer']) + if (env["optimize"] == "speed"): #optimize for speed (default) + env.Append(LINKFLAGS=['-O2']) + env.Append(CPPFLAGS=['-O2', '-DNDEBUG', '-ffast-math', '-funsafe-math-optimizations', '-fomit-frame-pointer']) + else: #optimize for size + env.Append(CPPFLAGS=['-Os', '-DNDEBUG']) + env.Append(LINKFLAGS=['-Os']) + if (can_vectorize): env.Append(CPPFLAGS=['-ftree-vectorize']) if (env["target"] == "release_debug"): diff --git a/platform/android/dir_access_jandroid.cpp b/platform/android/dir_access_jandroid.cpp index 3e40b59de9..ee5ae156b7 100644 --- a/platform/android/dir_access_jandroid.cpp +++ b/platform/android/dir_access_jandroid.cpp @@ -153,7 +153,6 @@ String DirAccessJAndroid::get_current_dir() { bool DirAccessJAndroid::file_exists(String p_file) { - JNIEnv *env = ThreadAndroid::get_env(); String sd; if (current_dir == "") sd = p_file; diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index c3ff157f99..9ad0219746 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -228,7 +228,7 @@ class EditorExportAndroid : public EditorExportPlatform { }; Vector<Device> devices; - bool devices_changed; + volatile bool devices_changed; Mutex *device_lock; Thread *device_thread; volatile bool quit_request; @@ -528,11 +528,9 @@ class EditorExportAndroid : public EditorExportPlatform { bool exported = false; for (int i = 0; i < p_so.tags.size(); ++i) { // shared objects can be fat (compatible with multiple ABIs) - int start_pos = 0; int abi_index = abis.find(p_so.tags[i]); if (abi_index != -1) { exported = true; - start_pos = abi_index + 1; String abi = abis[abi_index]; String dst_path = "lib/" + abi + "/" + p_so.path.get_file(); Vector<uint8_t> array = FileAccess::get_file_as_array(p_so.path); @@ -667,11 +665,11 @@ class EditorExportAndroid : public EditorExportPlatform { ucstring.resize(len + 1); for (uint32_t j = 0; j < len; j++) { uint16_t c = decode_uint16(&p_manifest[string_at + 2 + 2 * j]); - ucstring[j] = c; + ucstring.write[j] = c; } string_end = MAX(string_at + 2 + 2 * len, string_end); - ucstring[len] = 0; - string_table[i] = ucstring.ptr(); + ucstring.write[len] = 0; + string_table.write[i] = ucstring.ptr(); } //print_line("String "+itos(i)+": "+string_table[i]); @@ -718,13 +716,13 @@ class EditorExportAndroid : public EditorExportPlatform { if (tname == "manifest" && attrname == "package") { print_line("FOUND package"); - string_table[attr_value] = get_package_name(package_name); + string_table.write[attr_value] = get_package_name(package_name); } if (tname == "manifest" && /*nspace=="android" &&*/ attrname == "versionCode") { print_line("FOUND versionCode"); - encode_uint32(version_code, &p_manifest[iofs + 16]); + encode_uint32(version_code, &p_manifest.write[iofs + 16]); } if (tname == "manifest" && /*nspace=="android" &&*/ attrname == "versionName") { @@ -733,12 +731,12 @@ class EditorExportAndroid : public EditorExportPlatform { if (attr_value == 0xFFFFFFFF) { WARN_PRINT("Version name in a resource, should be plaintext") } else - string_table[attr_value] = version_name; + string_table.write[attr_value] = version_name; } if (tname == "activity" && /*nspace=="android" &&*/ attrname == "screenOrientation") { - encode_uint32(orientation == 0 ? 0 : 1, &p_manifest[iofs + 16]); + encode_uint32(orientation == 0 ? 0 : 1, &p_manifest.write[iofs + 16]); } if (tname == "uses-feature" && /*nspace=="android" &&*/ attrname == "glEsVersion") { @@ -749,19 +747,19 @@ class EditorExportAndroid : public EditorExportPlatform { if (attrname == "smallScreens") { - encode_uint32(screen_support_small ? 0xFFFFFFFF : 0, &p_manifest[iofs + 16]); + encode_uint32(screen_support_small ? 0xFFFFFFFF : 0, &p_manifest.write[iofs + 16]); } else if (attrname == "normalScreens") { - encode_uint32(screen_support_normal ? 0xFFFFFFFF : 0, &p_manifest[iofs + 16]); + encode_uint32(screen_support_normal ? 0xFFFFFFFF : 0, &p_manifest.write[iofs + 16]); } else if (attrname == "largeScreens") { - encode_uint32(screen_support_large ? 0xFFFFFFFF : 0, &p_manifest[iofs + 16]); + encode_uint32(screen_support_large ? 0xFFFFFFFF : 0, &p_manifest.write[iofs + 16]); } else if (attrname == "xlargeScreens") { - encode_uint32(screen_support_xlarge ? 0xFFFFFFFF : 0, &p_manifest[iofs + 16]); + encode_uint32(screen_support_xlarge ? 0xFFFFFFFF : 0, &p_manifest.write[iofs + 16]); } } @@ -813,45 +811,45 @@ class EditorExportAndroid : public EditorExportPlatform { } // start tag - encode_uint16(0x102, &p_manifest[ofs]); // type - encode_uint16(16, &p_manifest[ofs + 2]); // headersize - encode_uint32(56, &p_manifest[ofs + 4]); // size - encode_uint32(0, &p_manifest[ofs + 8]); // lineno - encode_uint32(-1, &p_manifest[ofs + 12]); // comment - encode_uint32(-1, &p_manifest[ofs + 16]); // ns - encode_uint32(attr_uses_permission_string, &p_manifest[ofs + 20]); // name - encode_uint16(20, &p_manifest[ofs + 24]); // attr_start - encode_uint16(20, &p_manifest[ofs + 26]); // attr_size - encode_uint16(1, &p_manifest[ofs + 28]); // num_attrs - encode_uint16(0, &p_manifest[ofs + 30]); // id_index - encode_uint16(0, &p_manifest[ofs + 32]); // class_index - encode_uint16(0, &p_manifest[ofs + 34]); // style_index + encode_uint16(0x102, &p_manifest.write[ofs]); // type + encode_uint16(16, &p_manifest.write[ofs + 2]); // headersize + encode_uint32(56, &p_manifest.write[ofs + 4]); // size + encode_uint32(0, &p_manifest.write[ofs + 8]); // lineno + encode_uint32(-1, &p_manifest.write[ofs + 12]); // comment + encode_uint32(-1, &p_manifest.write[ofs + 16]); // ns + encode_uint32(attr_uses_permission_string, &p_manifest.write[ofs + 20]); // name + encode_uint16(20, &p_manifest.write[ofs + 24]); // attr_start + encode_uint16(20, &p_manifest.write[ofs + 26]); // attr_size + encode_uint16(1, &p_manifest.write[ofs + 28]); // num_attrs + encode_uint16(0, &p_manifest.write[ofs + 30]); // id_index + encode_uint16(0, &p_manifest.write[ofs + 32]); // class_index + encode_uint16(0, &p_manifest.write[ofs + 34]); // style_index // attribute - encode_uint32(ns_android_string, &p_manifest[ofs + 36]); // ns - encode_uint32(attr_name_string, &p_manifest[ofs + 40]); // 'name' - encode_uint32(perm_string, &p_manifest[ofs + 44]); // raw_value - encode_uint16(8, &p_manifest[ofs + 48]); // typedvalue_size - p_manifest[ofs + 50] = 0; // typedvalue_always0 - p_manifest[ofs + 51] = 0x03; // typedvalue_type (string) - encode_uint32(perm_string, &p_manifest[ofs + 52]); // typedvalue reference + encode_uint32(ns_android_string, &p_manifest.write[ofs + 36]); // ns + encode_uint32(attr_name_string, &p_manifest.write[ofs + 40]); // 'name' + encode_uint32(perm_string, &p_manifest.write[ofs + 44]); // raw_value + encode_uint16(8, &p_manifest.write[ofs + 48]); // typedvalue_size + p_manifest.write[ofs + 50] = 0; // typedvalue_always0 + p_manifest.write[ofs + 51] = 0x03; // typedvalue_type (string) + encode_uint32(perm_string, &p_manifest.write[ofs + 52]); // typedvalue reference ofs += 56; // end tag - encode_uint16(0x103, &p_manifest[ofs]); // type - encode_uint16(16, &p_manifest[ofs + 2]); // headersize - encode_uint32(24, &p_manifest[ofs + 4]); // size - encode_uint32(0, &p_manifest[ofs + 8]); // lineno - encode_uint32(-1, &p_manifest[ofs + 12]); // comment - encode_uint32(-1, &p_manifest[ofs + 16]); // ns - encode_uint32(attr_uses_permission_string, &p_manifest[ofs + 20]); // name + encode_uint16(0x103, &p_manifest.write[ofs]); // type + encode_uint16(16, &p_manifest.write[ofs + 2]); // headersize + encode_uint32(24, &p_manifest.write[ofs + 4]); // size + encode_uint32(0, &p_manifest.write[ofs + 8]); // lineno + encode_uint32(-1, &p_manifest.write[ofs + 12]); // comment + encode_uint32(-1, &p_manifest.write[ofs + 16]); // ns + encode_uint32(attr_uses_permission_string, &p_manifest.write[ofs + 20]); // name ofs += 24; } // copy footer back in - memcpy(&p_manifest[ofs], manifest_end.ptr(), manifest_end.size()); + memcpy(&p_manifest.write[ofs], manifest_end.ptr(), manifest_end.size()); } } break; } @@ -866,19 +864,19 @@ class EditorExportAndroid : public EditorExportPlatform { for (uint32_t i = 0; i < string_table_begins; i++) { - ret[i] = p_manifest[i]; + ret.write[i] = p_manifest[i]; } ofs = 0; for (int i = 0; i < string_table.size(); i++) { - encode_uint32(ofs, &ret[string_table_begins + i * 4]); + encode_uint32(ofs, &ret.write[string_table_begins + i * 4]); ofs += string_table[i].length() * 2 + 2 + 2; } ret.resize(ret.size() + ofs); string_data_offset = ret.size() - ofs; - uint8_t *chars = &ret[string_data_offset]; + uint8_t *chars = &ret.write[string_data_offset]; for (int i = 0; i < string_table.size(); i++) { String s = string_table[i]; @@ -905,15 +903,15 @@ class EditorExportAndroid : public EditorExportPlatform { uint32_t extra = (p_manifest.size() - string_table_ends); ret.resize(new_stable_end + extra); for (uint32_t i = 0; i < extra; i++) - ret[new_stable_end + i] = p_manifest[string_table_ends + i]; + ret.write[new_stable_end + i] = p_manifest[string_table_ends + i]; while (ret.size() % 4) ret.push_back(0); - encode_uint32(ret.size(), &ret[4]); //update new file size + encode_uint32(ret.size(), &ret.write[4]); //update new file size - encode_uint32(new_stable_end - 8, &ret[12]); //update new string table size - encode_uint32(string_table.size(), &ret[16]); //update new number of strings - encode_uint32(string_data_offset - 8, &ret[28]); //update new string data offset + encode_uint32(new_stable_end - 8, &ret.write[12]); //update new string table size + encode_uint32(string_table.size(), &ret.write[16]); //update new number of strings + encode_uint32(string_data_offset - 8, &ret.write[28]); //update new string data offset //print_line("file size: "+itos(ret.size())); @@ -937,9 +935,9 @@ class EditorExportAndroid : public EditorExportPlatform { Vector<uint8_t> str8; str8.resize(len + 1); for (uint32_t i = 0; i < len; i++) { - str8[i] = p_bytes[offset + i]; + str8.write[i] = p_bytes[offset + i]; } - str8[len] = 0; + str8.write[len] = 0; String str; str.parse_utf8((const char *)str8.ptr()); return str; @@ -1003,18 +1001,18 @@ class EditorExportAndroid : public EditorExportPlatform { for (uint32_t i = 0; i < string_table_begins; i++) { - ret[i] = p_manifest[i]; + ret.write[i] = p_manifest[i]; } int ofs = 0; for (int i = 0; i < string_table.size(); i++) { - encode_uint32(ofs, &ret[string_table_begins + i * 4]); + encode_uint32(ofs, &ret.write[string_table_begins + i * 4]); ofs += string_table[i].length() * 2 + 2 + 2; } ret.resize(ret.size() + ofs); - uint8_t *chars = &ret[ret.size() - ofs]; + uint8_t *chars = &ret.write[ret.size() - ofs]; for (int i = 0; i < string_table.size(); i++) { String s = string_table[i]; @@ -1033,19 +1031,19 @@ class EditorExportAndroid : public EditorExportPlatform { ret.push_back(0); //change flags to not use utf8 - encode_uint32(string_flags & ~0x100, &ret[28]); + encode_uint32(string_flags & ~0x100, &ret.write[28]); //change length - encode_uint32(ret.size() - 12, &ret[16]); + encode_uint32(ret.size() - 12, &ret.write[16]); //append the rest... int rest_from = 12 + string_block_len; int rest_to = ret.size(); int rest_len = (p_manifest.size() - rest_from); ret.resize(ret.size() + (p_manifest.size() - rest_from)); for (int i = 0; i < rest_len; i++) { - ret[rest_to + i] = p_manifest[rest_from + i]; + ret.write[rest_to + i] = p_manifest[rest_from + i]; } //finally update the size - encode_uint32(ret.size(), &ret[4]); + encode_uint32(ret.size(), &ret.write[4]); p_manifest = ret; //printf("end\n"); @@ -1154,7 +1152,10 @@ public: virtual bool poll_devices() { bool dc = devices_changed; - devices_changed = false; + if (dc) { + // don't clear unless we're reporting true, to avoid race + devices_changed = false; + } return dc; } @@ -1643,7 +1644,7 @@ public: //add comandline Vector<uint8_t> clf; clf.resize(4); - encode_uint32(cl.size(), &clf[0]); + encode_uint32(cl.size(), &clf.write[0]); for (int i = 0; i < cl.size(); i++) { print_line(itos(i) + " param: " + cl[i]); @@ -1653,8 +1654,8 @@ public: if (!length) continue; clf.resize(base + 4 + length); - encode_uint32(length, &clf[base]); - copymem(&clf[base + 4], txt.ptr(), length); + encode_uint32(length, &clf.write[base]); + copymem(&clf.write[base + 4], txt.ptr(), length); } zip_fileinfo zipfi = get_zip_fileinfo(); @@ -1857,9 +1858,9 @@ public: run_icon->create_from_image(img); device_lock = Mutex::create(); - device_thread = Thread::create(_device_poll_thread, this); devices_changed = true; quit_request = false; + device_thread = Thread::create(_device_poll_thread, this); } ~EditorExportAndroid() { diff --git a/platform/android/java/src/org/godotengine/godot/Godot.java b/platform/android/java/src/org/godotengine/godot/Godot.java index 8a2d789dc5..ef798fc790 100644 --- a/platform/android/java/src/org/godotengine/godot/Godot.java +++ b/platform/android/java/src/org/godotengine/godot/Godot.java @@ -297,7 +297,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC runOnUiThread(new Runnable() { @Override public void run() { - view.setKeepScreenOn("True".equals(GodotLib.getGlobal("display/driver/keep_screen_on"))); + view.setKeepScreenOn("True".equals(GodotLib.getGlobal("display/window/energy_saving/keep_screen_on"))); } }); } diff --git a/platform/android/java/src/org/godotengine/godot/payments/ConsumeTask.java b/platform/android/java/src/org/godotengine/godot/payments/ConsumeTask.java index afe5f81b6d..5d94e77cd7 100644 --- a/platform/android/java/src/org/godotengine/godot/payments/ConsumeTask.java +++ b/platform/android/java/src/org/godotengine/godot/payments/ConsumeTask.java @@ -66,7 +66,6 @@ abstract public class ConsumeTask { } final String token = _token; new AsyncTask<String, String, String>() { - @Override protected String doInBackground(String... params) { try { @@ -89,7 +88,6 @@ abstract public class ConsumeTask { error(param); } } - } .execute(); } diff --git a/platform/android/java/src/org/godotengine/godot/payments/PaymentsManager.java b/platform/android/java/src/org/godotengine/godot/payments/PaymentsManager.java index b7bf2362cc..d4c7380424 100644 --- a/platform/android/java/src/org/godotengine/godot/payments/PaymentsManager.java +++ b/platform/android/java/src/org/godotengine/godot/payments/PaymentsManager.java @@ -113,7 +113,6 @@ public class PaymentsManager { public void requestPurchase(final String sku, String transactionId) { new PurchaseTask(mService, Godot.getInstance()) { - @Override protected void error(String message) { godotPaymentV3.callbackFail(message); @@ -128,7 +127,6 @@ public class PaymentsManager { protected void alreadyOwned() { godotPaymentV3.callbackAlreadyOwned(sku); } - } .purchase(sku, transactionId); } @@ -139,7 +137,6 @@ public class PaymentsManager { public void consumeUnconsumedPurchases() { new ReleaseAllConsumablesTask(mService, activity) { - @Override protected void success(String sku, String receipt, String signature, String token) { godotPaymentV3.callbackSuccessProductMassConsumed(receipt, signature, sku); @@ -208,14 +205,12 @@ public class PaymentsManager { public void processPurchaseResponse(int resultCode, Intent data) { new HandlePurchaseTask(activity) { - @Override protected void success(final String sku, final String signature, final String ticket) { godotPaymentV3.callbackSuccess(ticket, signature, sku); if (auto_consume) { new ConsumeTask(mService, activity) { - @Override protected void success(String ticket) { } @@ -245,12 +240,10 @@ public class PaymentsManager { public void validatePurchase(String purchaseToken, final String sku) { new ValidateTask(activity, godotPaymentV3) { - @Override protected void success() { new ConsumeTask(mService, activity) { - @Override protected void success(String ticket) { godotPaymentV3.callbackSuccess(ticket, null, sku); @@ -283,7 +276,6 @@ public class PaymentsManager { public void consume(final String sku) { new ConsumeTask(mService, activity) { - @Override protected void success(String ticket) { godotPaymentV3.callbackSuccessProductMassConsumed(ticket, "", sku); diff --git a/platform/android/java/src/org/godotengine/godot/payments/ReleaseAllConsumablesTask.java b/platform/android/java/src/org/godotengine/godot/payments/ReleaseAllConsumablesTask.java index e00e37f9d1..eccc6f671b 100644 --- a/platform/android/java/src/org/godotengine/godot/payments/ReleaseAllConsumablesTask.java +++ b/platform/android/java/src/org/godotengine/godot/payments/ReleaseAllConsumablesTask.java @@ -88,7 +88,6 @@ abstract public class ReleaseAllConsumablesTask { String signature = mySignatures.get(i); //Log.d("godot", "A punto de consumir un item con token:" + token + "\n" + receipt); new GenericConsumeTask(context, mService, sku, receipt, signature, token) { - @Override public void onSuccess(String sku, String receipt, String signature, String token) { ReleaseAllConsumablesTask.this.success(sku, receipt, signature, token); diff --git a/platform/android/java/src/org/godotengine/godot/payments/ValidateTask.java b/platform/android/java/src/org/godotengine/godot/payments/ValidateTask.java index 1eb9d001e0..0626e50bb1 100644 --- a/platform/android/java/src/org/godotengine/godot/payments/ValidateTask.java +++ b/platform/android/java/src/org/godotengine/godot/payments/ValidateTask.java @@ -63,7 +63,6 @@ abstract public class ValidateTask { public void validatePurchase(final String sku) { new AsyncTask<String, String, String>() { - private ProgressDialog dialog; @Override @@ -113,7 +112,6 @@ abstract public class ValidateTask { error(e.getMessage()); } } - } .execute(); } diff --git a/platform/android/java_glue.cpp b/platform/android/java_glue.cpp index e6240ad9e9..8bb1c38345 100644 --- a/platform/android/java_glue.cpp +++ b/platform/android/java_glue.cpp @@ -880,7 +880,6 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jo const char **cmdline = NULL; int cmdlen = 0; - bool use_apk_expansion = false; if (p_cmdline) { cmdlen = env->GetArrayLength(p_cmdline); if (cmdlen) { @@ -891,9 +890,6 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jo jstring string = (jstring)env->GetObjectArrayElement(p_cmdline, i); const char *rawString = env->GetStringUTFChars(string, 0); - if (rawString && strcmp(rawString, "--main-pack") == 0) { - use_apk_expansion = true; - } cmdline[i] = rawString; } diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp index 9188f09f21..f9eda9dff1 100644 --- a/platform/android/os_android.cpp +++ b/platform/android/os_android.cpp @@ -124,6 +124,10 @@ void OS_Android::set_opengl_extensions(const char *p_gl_extensions) { gl_extensions = p_gl_extensions; } +int OS_Android::get_current_video_driver() const { + return video_driver_index; +} + Error OS_Android::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) { bool use_gl3 = get_gl_version_code_func() >= 0x00030000; @@ -136,9 +140,11 @@ Error OS_Android::initialize(const VideoMode &p_desired, int p_video_driver, int if (use_gl2) { RasterizerGLES2::register_config(); RasterizerGLES2::make_current(); + video_driver_index = VIDEO_DRIVER_GLES2; } else { RasterizerGLES3::register_config(); RasterizerGLES3::make_current(); + video_driver_index = VIDEO_DRIVER_GLES3; } visual_server = memnew(VisualServerRaster); @@ -351,8 +357,8 @@ void OS_Android::process_touch(int p_what, int p_pointer, const Vector<TouchPos> touch.resize(p_points.size()); for (int i = 0; i < p_points.size(); i++) { - touch[i].id = p_points[i].id; - touch[i].pos = p_points[i].pos; + touch.write[i].id = p_points[i].id; + touch.write[i].pos = p_points[i].pos; } //send touch @@ -393,7 +399,7 @@ void OS_Android::process_touch(int p_what, int p_pointer, const Vector<TouchPos> ev->set_position(p_points[idx].pos); ev->set_relative(p_points[idx].pos - touch[i].pos); input->parse_input_event(ev); - touch[i].pos = p_points[idx].pos; + touch.write[i].pos = p_points[idx].pos; } } break; diff --git a/platform/android/os_android.h b/platform/android/os_android.h index ac901d4832..c4220906a3 100644 --- a/platform/android/os_android.h +++ b/platform/android/os_android.h @@ -137,6 +137,7 @@ private: AlertFunc alert_func; //power_android *power_manager; + int video_driver_index; public: // functions used by main to initialize/deintialize the OS @@ -146,6 +147,8 @@ public: virtual int get_audio_driver_count() const; virtual const char *get_audio_driver_name(int p_driver) const; + virtual int get_current_video_driver() const; + virtual void initialize_core(); virtual Error initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); diff --git a/platform/android/thread_jandroid.cpp b/platform/android/thread_jandroid.cpp index e85813605f..b13baf69c2 100644 --- a/platform/android/thread_jandroid.cpp +++ b/platform/android/thread_jandroid.cpp @@ -132,7 +132,7 @@ JNIEnv *ThreadAndroid::get_env() { } JNIEnv *env = NULL; - int status = java_vm->AttachCurrentThread(&env, NULL); + java_vm->AttachCurrentThread(&env, NULL); return env; } diff --git a/platform/haiku/audio_driver_media_kit.cpp b/platform/haiku/audio_driver_media_kit.cpp index 278a994c54..1f901c4919 100644 --- a/platform/haiku/audio_driver_media_kit.cpp +++ b/platform/haiku/audio_driver_media_kit.cpp @@ -43,7 +43,7 @@ Error AudioDriverMediaKit::init() { speaker_mode = SPEAKER_MODE_STEREO; channels = 2; - int latency = GLOBAL_DEF("audio/output_latency", 25); + int latency = GLOBAL_DEF_RST("audio/output_latency", 25); buffer_size = next_power_of_2(latency * mix_rate / 1000); samples_in = memnew_arr(int32_t, buffer_size * channels); diff --git a/platform/haiku/os_haiku.cpp b/platform/haiku/os_haiku.cpp index 97fab5ca0d..209cb5cec4 100644 --- a/platform/haiku/os_haiku.cpp +++ b/platform/haiku/os_haiku.cpp @@ -80,6 +80,10 @@ const char *OS_Haiku::get_video_driver_name(int p_driver) const { return "GLES3"; } +int OS_Haiku::get_current_video_driver() const { + return video_driver_index; +} + Error OS_Haiku::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) { main_loop = NULL; current_video_mode = p_desired; @@ -124,6 +128,8 @@ Error OS_Haiku::initialize(const VideoMode &p_desired, int p_video_driver, int p } */ + video_driver_index = p_video_driver; + input = memnew(InputDefault); window->SetInput(input); diff --git a/platform/haiku/os_haiku.h b/platform/haiku/os_haiku.h index 615ae682ef..13d4420bde 100644 --- a/platform/haiku/os_haiku.h +++ b/platform/haiku/os_haiku.h @@ -51,6 +51,7 @@ private: Rasterizer *rasterizer; VisualServer *visual_server; VideoMode current_video_mode; + int video_driver_index; PowerHaiku *power_manager; #ifdef MEDIA_KIT_ENABLED @@ -66,6 +67,7 @@ private: protected: virtual int get_video_driver_count() const; virtual const char *get_video_driver_name(int p_driver) const; + virtual int get_current_video_driver() const; virtual Error initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); virtual void finalize(); diff --git a/platform/iphone/app_delegate.mm b/platform/iphone/app_delegate.mm index dd5ce4ab10..cc4985eb0c 100644 --- a/platform/iphone/app_delegate.mm +++ b/platform/iphone/app_delegate.mm @@ -643,7 +643,7 @@ static int frame_count = 0; view_controller.view = glView; window.rootViewController = view_controller; - _set_keep_screen_on(bool(GLOBAL_DEF("display/window/keep_screen_on", true)) ? YES : NO); + _set_keep_screen_on(bool(GLOBAL_DEF("display/window/energy_saving/keep_screen_on", true)) ? YES : NO); glView.useCADisplayLink = bool(GLOBAL_DEF("display.iOS/use_cadisplaylink", true)) ? YES : NO; printf("cadisaplylink: %d", glView.useCADisplayLink); diff --git a/platform/iphone/detect.py b/platform/iphone/detect.py index 25674c2b47..b13a1e9643 100644 --- a/platform/iphone/detect.py +++ b/platform/iphone/detect.py @@ -47,8 +47,12 @@ def configure(env): if (env["target"].startswith("release")): env.Append(CPPFLAGS=['-DNDEBUG', '-DNS_BLOCK_ASSERTIONS=1']) - env.Append(CPPFLAGS=['-O2', '-ftree-vectorize', '-fomit-frame-pointer', '-ffast-math', '-funsafe-math-optimizations']) - env.Append(LINKFLAGS=['-O2']) + if (env["optimize"] == "speed"): #optimize for speed (default) + env.Append(CPPFLAGS=['-O2', '-ftree-vectorize', '-fomit-frame-pointer', '-ffast-math', '-funsafe-math-optimizations']) + env.Append(LINKFLAGS=['-O2']) + else: #optimize for size + env.Append(CPPFLAGS=['-Os', '-ftree-vectorize']) + env.Append(LINKFLAGS=['-Os']) if env["target"] == "release_debug": env.Append(CPPFLAGS=['-DDEBUG_ENABLED']) diff --git a/platform/iphone/export/export.cpp b/platform/iphone/export/export.cpp index 4c1e02baf7..e59c81a148 100644 --- a/platform/iphone/export/export.cpp +++ b/platform/iphone/export/export.cpp @@ -276,7 +276,7 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_ CharString cs = strnew.utf8(); pfile.resize(cs.size() - 1); for (int i = 0; i < cs.size() - 1; i++) { - pfile[i] = cs[i]; + pfile.write[i] = cs[i]; } } @@ -489,7 +489,7 @@ private: ret.resize(sizeof(num) * 2); for (int i = 0; i < sizeof(num) * 2; ++i) { uint8_t four_bits = (num >> (sizeof(num) * 8 - (i + 1) * 4)) & 0xF; - ret[i] = _hex_char(four_bits); + ret.write[i] = _hex_char(four_bits); } return String::utf8(ret.ptr(), ret.size()); } @@ -587,7 +587,7 @@ void EditorExportPlatformIOS::_add_assets_to_project(Vector<uint8_t> &p_project_ CharString cs = str.utf8(); p_project_data.resize(cs.size() - 1); for (int i = 0; i < cs.size() - 1; i++) { - p_project_data[i] = cs[i]; + p_project_data.write[i] = cs[i]; } } @@ -781,7 +781,9 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p int ret = unzGoToFirstFile(src_pkg_zip); Vector<uint8_t> project_file_data; while (ret == UNZ_OK) { +#if defined(OSX_ENABLED) || defined(X11_ENABLED) bool is_execute = false; +#endif //get filename unz_file_info info; @@ -812,7 +814,9 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p continue; //ignore! } found_library = true; +#if defined(OSX_ENABLED) || defined(X11_ENABLED) is_execute = true; +#endif file = "godot_ios.a"; } if (file == project_file) { @@ -855,7 +859,7 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p f->close(); memdelete(f); -#ifdef OSX_ENABLED +#if defined(OSX_ENABLED) || defined(X11_ENABLED) if (is_execute) { // we need execute rights on this file chmod(file.utf8().get_data(), 0755); diff --git a/platform/iphone/game_center.mm b/platform/iphone/game_center.mm index 57ff79f7bc..e210bfb862 100644 --- a/platform/iphone/game_center.mm +++ b/platform/iphone/game_center.mm @@ -139,7 +139,6 @@ Error GameCenter::post_score(Variant p_score) { [GKScore reportScores:@[ reporter ] withCompletionHandler:^(NSError *error) { - Dictionary ret; ret["type"] = "post_score"; if (error == nil) { @@ -177,7 +176,6 @@ Error GameCenter::award_achievement(Variant p_params) { [GKAchievement reportAchievements:@[ achievement ] withCompletionHandler:^(NSError *error) { - Dictionary ret; ret["type"] = "award_achievement"; if (error == nil) { @@ -196,7 +194,6 @@ Error GameCenter::award_achievement(Variant p_params) { void GameCenter::request_achievement_descriptions() { [GKAchievementDescription loadAchievementDescriptionsWithCompletionHandler:^(NSArray *descriptions, NSError *error) { - Dictionary ret; ret["type"] = "achievement_descriptions"; if (error == nil) { @@ -252,7 +249,6 @@ void GameCenter::request_achievement_descriptions() { void GameCenter::request_achievements() { [GKAchievement loadAchievementsWithCompletionHandler:^(NSArray *achievements, NSError *error) { - Dictionary ret; ret["type"] = "achievements"; if (error == nil) { @@ -347,7 +343,6 @@ Error GameCenter::request_identity_verification_signature() { GKLocalPlayer *player = [GKLocalPlayer localPlayer]; [player generateIdentityVerificationSignatureWithCompletionHandler:^(NSURL *publicKeyUrl, NSData *signature, NSData *salt, uint64_t timestamp, NSError *error) { - Dictionary ret; ret["type"] = "identity_verification_signature"; if (error == nil) { diff --git a/platform/iphone/os_iphone.cpp b/platform/iphone/os_iphone.cpp index f618c80a77..a4538a6673 100644 --- a/platform/iphone/os_iphone.cpp +++ b/platform/iphone/os_iphone.cpp @@ -64,11 +64,6 @@ OSIPhone *OSIPhone::get_singleton() { return (OSIPhone *)OS::get_singleton(); }; -uint8_t OSIPhone::get_orientations() const { - - return supported_orientations; -}; - extern int gl_view_base_fb; // from gl_view.mm void OSIPhone::set_data_dir(String p_dir) { @@ -98,13 +93,13 @@ void OSIPhone::initialize_core() { set_data_dir(data_dir); }; +int OSIPhone::get_current_video_driver() const { + return video_driver_index; +} + Error OSIPhone::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) { - supported_orientations = 0; - supported_orientations |= ((GLOBAL_DEF("video_mode/allow_horizontal", true) ? 1 : 0) << LandscapeLeft); - supported_orientations |= ((GLOBAL_DEF("video_mode/allow_horizontal_flipped", false) ? 1 : 0) << LandscapeRight); - supported_orientations |= ((GLOBAL_DEF("video_mode/allow_vertical", false) ? 1 : 0) << PortraitDown); - supported_orientations |= ((GLOBAL_DEF("video_mode/allow_vertical_flipped", false) ? 1 : 0) << PortraitUp); + video_driver_index = p_video_driver; //this may be misleading RasterizerGLES3::register_config(); RasterizerGLES3::make_current(); diff --git a/platform/iphone/os_iphone.h b/platform/iphone/os_iphone.h index 7d73a6fe5c..db2912ad93 100644 --- a/platform/iphone/os_iphone.h +++ b/platform/iphone/os_iphone.h @@ -47,14 +47,6 @@ class OSIPhone : public OS_Unix { -public: - enum Orientations { - PortraitDown, - PortraitUp, - LandscapeLeft, - LandscapeRight, - }; - private: enum { MAX_MOUSE_COUNT = 8, @@ -64,8 +56,6 @@ private: static HashMap<String, void *> dynamic_symbol_lookup_table; friend void register_dynamic_symbol(char *name, void *address); - uint8_t supported_orientations; - VisualServer *visual_server; AudioDriverCoreAudio audio_driver; @@ -87,6 +77,8 @@ private: virtual int get_video_driver_count() const; virtual const char *get_video_driver_name(int p_driver) const; + virtual int get_current_video_driver() const; + virtual void initialize_core(); virtual Error initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); @@ -122,6 +114,8 @@ private: int virtual_keyboard_height; + int video_driver_index; + public: bool iterate(); diff --git a/platform/iphone/view_controller.mm b/platform/iphone/view_controller.mm index cdaae0cb81..f75f0fd812 100644 --- a/platform/iphone/view_controller.mm +++ b/platform/iphone/view_controller.mm @@ -83,51 +83,36 @@ int add_cmdline(int p_argc, char **p_args) { printf("*********** did receive memory warning!\n"); }; -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)p_orientation { - - if (/*OSIPhone::get_singleton() == NULL*/ TRUE) { - - printf("checking on info.plist\n"); - NSArray *arr = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"UISupportedInterfaceOrientations"]; - switch (p_orientation) { - - case UIInterfaceOrientationLandscapeLeft: - return [arr indexOfObject:@"UIInterfaceOrientationLandscapeLeft"] != NSNotFound ? YES : NO; - - case UIInterfaceOrientationLandscapeRight: - return [arr indexOfObject:@"UIInterfaceOrientationLandscapeRight"] != NSNotFound ? YES : NO; - - case UIInterfaceOrientationPortrait: - return [arr indexOfObject:@"UIInterfaceOrientationPortrait"] != NSNotFound ? YES : NO; - - case UIInterfaceOrientationPortraitUpsideDown: - return [arr indexOfObject:@"UIInterfaceOrientationPortraitUpsideDown"] != NSNotFound ? YES : NO; - - default: - return NO; - } - }; - - uint8_t supported = OSIPhone::get_singleton()->get_orientations(); - switch (p_orientation) { - - case UIInterfaceOrientationLandscapeLeft: - return supported & (1 << OSIPhone::LandscapeLeft) ? YES : NO; - - case UIInterfaceOrientationLandscapeRight: - return supported & (1 << OSIPhone::LandscapeRight) ? YES : NO; - - case UIInterfaceOrientationPortrait: - return supported & (1 << OSIPhone::PortraitDown) ? YES : NO; - - case UIInterfaceOrientationPortraitUpsideDown: - return supported & (1 << OSIPhone::PortraitUp) ? YES : NO; - +- (BOOL)shouldAutorotate { + switch (OS::get_singleton()->get_screen_orientation()) { + case OS::SCREEN_SENSOR: + case OS::SCREEN_SENSOR_LANDSCAPE: + case OS::SCREEN_SENSOR_PORTRAIT: + return YES; default: return NO; } }; +- (UIInterfaceOrientationMask)supportedInterfaceOrientations { + switch (OS::get_singleton()->get_screen_orientation()) { + case OS::SCREEN_PORTRAIT: + return UIInterfaceOrientationMaskPortrait; + case OS::SCREEN_REVERSE_LANDSCAPE: + return UIInterfaceOrientationMaskLandscapeRight; + case OS::SCREEN_REVERSE_PORTRAIT: + return UIInterfaceOrientationMaskPortraitUpsideDown; + case OS::SCREEN_SENSOR_LANDSCAPE: + return UIInterfaceOrientationMaskLandscape; + case OS::SCREEN_SENSOR_PORTRAIT: + return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown; + case OS::SCREEN_SENSOR: + return UIInterfaceOrientationMaskAll; + case OS::SCREEN_LANDSCAPE: + return UIInterfaceOrientationMaskLandscapeLeft; + } +}; + - (BOOL)prefersStatusBarHidden { return YES; } diff --git a/platform/javascript/dom_keys.h b/platform/javascript/dom_keys.inc index 4edca63c6d..dc8d67d52b 100644 --- a/platform/javascript/dom_keys.h +++ b/platform/javascript/dom_keys.inc @@ -1,5 +1,5 @@ /*************************************************************************/ -/* dom_keys.h */ +/* dom_keys.inc */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,9 +28,6 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef DOM_KEYS_H -#define DOM_KEYS_H - #include "os/keyboard.h" // https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode#Constants_for_keyCode_value @@ -295,8 +292,8 @@ int dom2godot_scancode(int dom_keycode) { //case DOM_VK_SELECT: return KEY_UNKNOWN; - case DOM_VK_PRINTSCREEN: // this is the usual printScreen key - case DOM_VK_PRINT: // maybe for alt+printScreen or physical printers? + case DOM_VK_PRINTSCREEN: + case DOM_VK_PRINT: return KEY_PRINT; //case DOM_VK_EXECUTE: return KEY_UNKNOWN; @@ -311,11 +308,11 @@ int dom2godot_scancode(int dom_keycode) { case DOM_VK_SLEEP: return KEY_STANDBY; - // these are numpad keys according to MDN + // Numpad keys case DOM_VK_MULTIPLY: return KEY_KP_MULTIPLY; case DOM_VK_ADD: return KEY_KP_ADD; case DOM_VK_SEPARATOR: - return KEY_KP_PERIOD; // good enough? + return KEY_KP_PERIOD; // Good enough? case DOM_VK_SUBTRACT: return KEY_KP_SUBTRACT; case DOM_VK_DECIMAL: return KEY_KP_PERIOD; case DOM_VK_DIVIDE: @@ -376,10 +373,8 @@ int dom2godot_scancode(int dom_keycode) { case DOM_VK_QUOTE: return KEY_APOSTROPHE; - // rest is OEM/unusual + // The rest is OEM/unusual. default: return KEY_UNKNOWN; }; } - -#endif diff --git a/platform/javascript/export/export.cpp b/platform/javascript/export/export.cpp index 9591850662..7cff6ba172 100644 --- a/platform/javascript/export/export.cpp +++ b/platform/javascript/export/export.cpp @@ -95,7 +95,7 @@ void EditorExportPlatformJavaScript::_fix_html(Vector<uint8_t> &p_html, const Re CharString cs = str_export.utf8(); p_html.resize(cs.length()); for (int i = 0; i < cs.length(); i++) { - p_html[i] = cs[i]; + p_html.write[i] = cs[i]; } } diff --git a/platform/javascript/javascript_main.cpp b/platform/javascript/javascript_main.cpp index 68a2d72464..3829e8d406 100644 --- a/platform/javascript/javascript_main.cpp +++ b/platform/javascript/javascript_main.cpp @@ -28,17 +28,11 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "emscripten.h" #include "io/resource_loader.h" #include "main/main.h" #include "os_javascript.h" -OS_JavaScript *os = NULL; - -static void main_loop() { - - os->main_loop_iterate(); -} +#include <emscripten/emscripten.h> extern "C" EMSCRIPTEN_KEEPALIVE void main_after_fs_sync(char *p_idbfs_err) { @@ -46,18 +40,18 @@ extern "C" EMSCRIPTEN_KEEPALIVE void main_after_fs_sync(char *p_idbfs_err) { if (!idbfs_err.empty()) { print_line("IndexedDB not available: " + idbfs_err); } - os->set_idbfs_available(idbfs_err.empty()); - // Ease up compatibility + OS_JavaScript *os = OS_JavaScript::get_singleton(); + os->set_idb_available(idbfs_err.empty()); + // Ease up compatibility. ResourceLoader::set_abort_on_missing_resources(false); Main::start(); - os->main_loop_begin(); - emscripten_set_main_loop(main_loop, 0, false); + os->run_async(); } int main(int argc, char *argv[]) { - // sync from persistent state into memory and then - // run the 'main_after_fs_sync' function + // Sync from persistent state into memory and then + // run the 'main_after_fs_sync' function. /* clang-format off */ EM_ASM( FS.mkdir('/userfs'); @@ -68,9 +62,10 @@ int main(int argc, char *argv[]) { ); /* clang-format on */ - os = new OS_JavaScript(argv[0], NULL); - Error err = Main::setup(argv[0], argc - 1, &argv[1]); + new OS_JavaScript(argc, argv); + // TODO: Check error return value. + Main::setup(argv[0], argc - 1, &argv[1]); return 0; - // continued async in main_after_fs_sync() from syncfs() callback + // Continued async in main_after_fs_sync() from the syncfs() callback. } diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp index 6c6e4d2d1c..b9d586e233 100644 --- a/platform/javascript/os_javascript.cpp +++ b/platform/javascript/os_javascript.cpp @@ -30,290 +30,196 @@ #include "os_javascript.h" -#include "core/engine.h" -#include "core/io/file_access_buffered_fa.h" -#include "dom_keys.h" -#include "drivers/gles2/rasterizer_gles2.h" -#include "drivers/gles3/rasterizer_gles3.h" -#include "drivers/unix/dir_access_unix.h" -#include "drivers/unix/file_access_unix.h" +#include "gles2/rasterizer_gles2.h" +#include "gles3/rasterizer_gles3.h" +#include "io/file_access_buffered_fa.h" #include "main/main.h" #include "servers/visual/visual_server_raster.h" +#include "unix/dir_access_unix.h" +#include "unix/file_access_unix.h" #include <emscripten.h> #include <stdlib.h> +#include "dom_keys.inc" + #define DOM_BUTTON_LEFT 0 #define DOM_BUTTON_MIDDLE 1 #define DOM_BUTTON_RIGHT 2 +#define DOM_BUTTON_XBUTTON1 3 +#define DOM_BUTTON_XBUTTON2 4 -template <typename T> -static void dom2godot_mod(T emscripten_event_ptr, Ref<InputEventWithModifiers> godot_event) { - - godot_event->set_shift(emscripten_event_ptr->shiftKey); - godot_event->set_alt(emscripten_event_ptr->altKey); - godot_event->set_control(emscripten_event_ptr->ctrlKey); - godot_event->set_metakey(emscripten_event_ptr->metaKey); -} - -int OS_JavaScript::get_video_driver_count() const { +// Window (canvas) - return VIDEO_DRIVER_MAX; -} - -const char *OS_JavaScript::get_video_driver_name(int p_driver) const { - - switch (p_driver) { - case VIDEO_DRIVER_GLES3: - return "GLES3"; - case VIDEO_DRIVER_GLES2: - return "GLES2"; - } - ERR_EXPLAIN("Invalid video driver index " + itos(p_driver)); - ERR_FAIL_V(NULL); -} - -int OS_JavaScript::get_audio_driver_count() const { - - return 1; -} - -const char *OS_JavaScript::get_audio_driver_name(int p_driver) const { +static void focus_canvas() { - return "JavaScript"; + /* clang-format off */ + EM_ASM( + Module.canvas.focus(); + ); + /* clang-format on */ } -void OS_JavaScript::initialize_core() { +static bool is_canvas_focused() { - OS_Unix::initialize_core(); - FileAccess::make_default<FileAccessBufferedFA<FileAccessUnix> >(FileAccess::ACCESS_RESOURCES); + /* clang-format off */ + return EM_ASM_INT_V( + return document.activeElement == Module.canvas; + ); + /* clang-format on */ } -static EM_BOOL _browser_resize_callback(int event_type, const EmscriptenUiEvent *ui_event, void *user_data) { +static bool cursor_inside_canvas = true; - ERR_FAIL_COND_V(event_type != EMSCRIPTEN_EVENT_RESIZE, false); +EM_BOOL OS_JavaScript::browser_resize_callback(int p_event_type, const EmscriptenUiEvent *p_event, void *p_user_data) { - OS_JavaScript *os = static_cast<OS_JavaScript *>(user_data); // The order of the fullscreen change event and the window size change - // event varies, even within just one browser, so defer handling - os->request_canvas_size_adjustment(); + // event varies, even within just one browser, so defer handling. + get_singleton()->canvas_size_adjustment_requested = true; return false; } -static EM_BOOL _fullscreen_change_callback(int event_type, const EmscriptenFullscreenChangeEvent *event, void *user_data) { - - ERR_FAIL_COND_V(event_type != EMSCRIPTEN_EVENT_FULLSCREENCHANGE, false); +EM_BOOL OS_JavaScript::fullscreen_change_callback(int p_event_type, const EmscriptenFullscreenChangeEvent *p_event, void *p_user_data) { - OS_JavaScript *os = static_cast<OS_JavaScript *>(user_data); - String id = String::utf8(event->id); - // empty id is canvas - if (id.empty() || id == "canvas") { - - OS::VideoMode vm = os->get_video_mode(); - // this event property is the only reliable information on - // browser fullscreen state - vm.fullscreen = event->isFullscreen; - os->set_video_mode(vm); - os->request_canvas_size_adjustment(); + OS_JavaScript *os = get_singleton(); + // Empty ID is canvas. + String target_id = String::utf8(p_event->id); + if (target_id.empty() || target_id == "canvas") { + // This event property is the only reliable data on + // browser fullscreen state. + os->video_mode.fullscreen = p_event->isFullscreen; + os->canvas_size_adjustment_requested = true; } return false; } -static InputDefault *_input; - -static bool is_canvas_focused() { +void OS_JavaScript::set_video_mode(const VideoMode &p_video_mode, int p_screen) { - /* clang-format off */ - return EM_ASM_INT_V( - return document.activeElement == Module.canvas; - ); - /* clang-format on */ + video_mode = p_video_mode; } -static void focus_canvas() { +OS::VideoMode OS_JavaScript::get_video_mode(int p_screen) const { - /* clang-format off */ - EM_ASM( - Module.canvas.focus(); - ); - /* clang-format on */ + return video_mode; } -static bool _cursor_inside_canvas = true; - -static bool is_cursor_inside_canvas() { +Size2 OS_JavaScript::get_screen_size(int p_screen) const { - return _cursor_inside_canvas; + EmscriptenFullscreenChangeEvent ev; + EMSCRIPTEN_RESULT result = emscripten_get_fullscreen_status(&ev); + ERR_FAIL_COND_V(result != EMSCRIPTEN_RESULT_SUCCESS, Size2()); + return Size2(ev.screenWidth, ev.screenHeight); } -static EM_BOOL _mousebutton_callback(int event_type, const EmscriptenMouseEvent *mouse_event, void *user_data) { - - ERR_FAIL_COND_V(event_type != EMSCRIPTEN_EVENT_MOUSEDOWN && event_type != EMSCRIPTEN_EVENT_MOUSEUP, false); - - Ref<InputEventMouseButton> ev; - ev.instance(); - ev->set_pressed(event_type == EMSCRIPTEN_EVENT_MOUSEDOWN); - ev->set_position(Point2(mouse_event->canvasX, mouse_event->canvasY)); - ev->set_global_position(ev->get_position()); - dom2godot_mod(mouse_event, ev); - - switch (mouse_event->button) { - case DOM_BUTTON_LEFT: ev->set_button_index(BUTTON_LEFT); break; - case DOM_BUTTON_MIDDLE: ev->set_button_index(BUTTON_MIDDLE); break; - case DOM_BUTTON_RIGHT: ev->set_button_index(BUTTON_RIGHT); break; - default: return false; - } +void OS_JavaScript::set_window_size(const Size2 p_size) { - int mask = _input->get_mouse_button_mask(); - int button_flag = 1 << (ev->get_button_index() - 1); - if (ev->is_pressed()) { - // Since the event is consumed, focus manually. The containing iframe, - // if used, may not have focus yet, so focus even if already focused. - focus_canvas(); - mask |= button_flag; - } else if (mask & button_flag) { - mask &= ~button_flag; + windowed_size = p_size; + if (is_window_fullscreen()) { + window_maximized = false; + set_window_fullscreen(false); + } else if (is_window_maximized()) { + set_window_maximized(false); } else { - // release event, but press was outside the canvas, so ignore - return false; + video_mode.width = p_size.x; + video_mode.height = p_size.y; + emscripten_set_canvas_size(p_size.x, p_size.y); } - ev->set_button_mask(mask); - - _input->parse_input_event(ev); - // Prevent multi-click text selection and wheel-click scrolling anchor. - // Context menu is prevented through contextmenu event. - return true; } -static EM_BOOL _mousemove_callback(int event_type, const EmscriptenMouseEvent *mouse_event, void *user_data) { - - ERR_FAIL_COND_V(event_type != EMSCRIPTEN_EVENT_MOUSEMOVE, false); - OS_JavaScript *os = static_cast<OS_JavaScript *>(user_data); - int input_mask = _input->get_mouse_button_mask(); - Point2 pos = Point2(mouse_event->canvasX, mouse_event->canvasY); - // outside the canvas, only read mouse movement if dragging started inside - // the canvas; imitating desktop app behaviour - if (!is_cursor_inside_canvas() && !input_mask) - return false; - - Ref<InputEventMouseMotion> ev; - ev.instance(); - dom2godot_mod(mouse_event, ev); - ev->set_button_mask(input_mask); - - ev->set_position(pos); - ev->set_global_position(ev->get_position()); - - ev->set_relative(Vector2(mouse_event->movementX, mouse_event->movementY)); - _input->set_mouse_position(ev->get_position()); - ev->set_speed(_input->get_last_mouse_speed()); +Size2 OS_JavaScript::get_window_size() const { - _input->parse_input_event(ev); - // don't suppress mouseover/leave events - return false; + int canvas[3]; + emscripten_get_canvas_size(canvas, canvas + 1, canvas + 2); + return Size2(canvas[0], canvas[1]); } -static EM_BOOL _wheel_callback(int event_type, const EmscriptenWheelEvent *wheel_event, void *user_data) { +void OS_JavaScript::set_window_maximized(bool p_enabled) { - ERR_FAIL_COND_V(event_type != EMSCRIPTEN_EVENT_WHEEL, false); - if (!is_canvas_focused()) { - if (is_cursor_inside_canvas()) { - focus_canvas(); - } else { - return false; - } + window_maximized = p_enabled; + if (is_window_fullscreen()) { + set_window_fullscreen(false); + return; } + // Calling emscripten_enter_soft_fullscreen mutltiple times hides all + // page elements except the canvas permanently, so track state. + if (p_enabled && !soft_fullscreen_enabled) { - Ref<InputEventMouseButton> ev; - ev.instance(); - ev->set_button_mask(_input->get_mouse_button_mask()); - ev->set_position(_input->get_mouse_position()); - ev->set_global_position(ev->get_position()); - - ev->set_shift(_input->is_key_pressed(KEY_SHIFT)); - ev->set_alt(_input->is_key_pressed(KEY_ALT)); - ev->set_control(_input->is_key_pressed(KEY_CONTROL)); - ev->set_metakey(_input->is_key_pressed(KEY_META)); - - if (wheel_event->deltaY < 0) - ev->set_button_index(BUTTON_WHEEL_UP); - else if (wheel_event->deltaY > 0) - ev->set_button_index(BUTTON_WHEEL_DOWN); - else if (wheel_event->deltaX > 0) - ev->set_button_index(BUTTON_WHEEL_LEFT); - else if (wheel_event->deltaX < 0) - ev->set_button_index(BUTTON_WHEEL_RIGHT); - else - return false; - - // Different browsers give wildly different delta values, and we can't - // interpret deltaMode, so use default value for wheel events' factor + EmscriptenFullscreenStrategy strategy; + strategy.scaleMode = EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH; + strategy.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_STDDEF; + strategy.filteringMode = EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT; + strategy.canvasResizedCallback = NULL; + emscripten_enter_soft_fullscreen(NULL, &strategy); + soft_fullscreen_enabled = true; + video_mode.width = get_window_size().width; + video_mode.height = get_window_size().height; + } else if (!p_enabled) { - ev->set_pressed(true); - _input->parse_input_event(ev); + emscripten_exit_soft_fullscreen(); + soft_fullscreen_enabled = false; + video_mode.width = windowed_size.width; + video_mode.height = windowed_size.height; + emscripten_set_canvas_size(video_mode.width, video_mode.height); + } +} - ev->set_pressed(false); - _input->parse_input_event(ev); +bool OS_JavaScript::is_window_maximized() const { - return true; + return window_maximized; } -static Point2 _prev_touches[32]; +void OS_JavaScript::set_window_fullscreen(bool p_enabled) { -static EM_BOOL _touchpress_callback(int event_type, const EmscriptenTouchEvent *touch_event, void *user_data) { - - ERR_FAIL_COND_V( - event_type != EMSCRIPTEN_EVENT_TOUCHSTART && - event_type != EMSCRIPTEN_EVENT_TOUCHEND && - event_type != EMSCRIPTEN_EVENT_TOUCHCANCEL, - false); + if (p_enabled == is_window_fullscreen()) { + return; + } - Ref<InputEventScreenTouch> ev; - ev.instance(); - int lowest_id_index = -1; - for (int i = 0; i < touch_event->numTouches; ++i) { + // Just request changes here, if successful, canvas is resized in + // _browser_resize_callback or _fullscreen_change_callback. + EMSCRIPTEN_RESULT result; + if (p_enabled) { + if (window_maximized) { + // Soft fullsreen during real fulllscreen can cause issues. + set_window_maximized(false); + window_maximized = true; + } + EmscriptenFullscreenStrategy strategy; + strategy.scaleMode = EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH; + strategy.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_STDDEF; + strategy.filteringMode = EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT; + strategy.canvasResizedCallback = NULL; + emscripten_request_fullscreen_strategy(NULL, false, &strategy); + } else { + result = emscripten_exit_fullscreen(); + if (result != EMSCRIPTEN_RESULT_SUCCESS) { + ERR_PRINTS("Failed to exit fullscreen: Code " + itos(result)); + } + } +} - const EmscriptenTouchPoint &touch = touch_event->touches[i]; - if (lowest_id_index == -1 || touch.identifier < touch_event->touches[lowest_id_index].identifier) - lowest_id_index = i; - if (!touch.isChanged) - continue; - ev->set_index(touch.identifier); - ev->set_position(Point2(touch.canvasX, touch.canvasY)); - _prev_touches[i] = ev->get_position(); - ev->set_pressed(event_type == EMSCRIPTEN_EVENT_TOUCHSTART); +bool OS_JavaScript::is_window_fullscreen() const { - _input->parse_input_event(ev); - } - return true; + return video_mode.fullscreen; } -static EM_BOOL _touchmove_callback(int event_type, const EmscriptenTouchEvent *touch_event, void *user_data) { +void OS_JavaScript::get_fullscreen_mode_list(List<VideoMode> *p_list, int p_screen) const { - ERR_FAIL_COND_V(event_type != EMSCRIPTEN_EVENT_TOUCHMOVE, false); + Size2 screen = get_screen_size(); + p_list->push_back(OS::VideoMode(screen.width, screen.height, true)); +} - Ref<InputEventScreenDrag> ev; - ev.instance(); - int lowest_id_index = -1; - for (int i = 0; i < touch_event->numTouches; ++i) { +// Keys - const EmscriptenTouchPoint &touch = touch_event->touches[i]; - if (lowest_id_index == -1 || touch.identifier < touch_event->touches[lowest_id_index].identifier) - lowest_id_index = i; - if (!touch.isChanged) - continue; - ev->set_index(touch.identifier); - ev->set_position(Point2(touch.canvasX, touch.canvasY)); - Point2 &prev = _prev_touches[i]; - ev->set_relative(ev->get_position() - prev); - prev = ev->get_position(); +template <typename T> +static void dom2godot_mod(T *emscripten_event_ptr, Ref<InputEventWithModifiers> godot_event) { - _input->parse_input_event(ev); - } - return true; + godot_event->set_shift(emscripten_event_ptr->shiftKey); + godot_event->set_alt(emscripten_event_ptr->altKey); + godot_event->set_control(emscripten_event_ptr->ctrlKey); + godot_event->set_metakey(emscripten_event_ptr->metaKey); } -static Ref<InputEventKey> _setup_key_event(const EmscriptenKeyboardEvent *emscripten_event) { +static Ref<InputEventKey> setup_key_event(const EmscriptenKeyboardEvent *emscripten_event) { Ref<InputEventKey> ev; ev.instance(); @@ -322,9 +228,9 @@ static Ref<InputEventKey> _setup_key_event(const EmscriptenKeyboardEvent *emscri ev->set_scancode(dom2godot_scancode(emscripten_event->keyCode)); String unicode = String::utf8(emscripten_event->key); - // check if empty or multi-character (e.g. `CapsLock`) + // Check if empty or multi-character (e.g. `CapsLock`). if (unicode.length() != 1) { - // might be empty as well, but better than nonsense + // Might be empty as well, but better than nonsense. unicode = String::utf8(emscripten_event->charValue); } if (unicode.length() == 1) { @@ -334,175 +240,115 @@ static Ref<InputEventKey> _setup_key_event(const EmscriptenKeyboardEvent *emscri return ev; } -static Ref<InputEventKey> deferred_key_event; - -static EM_BOOL _keydown_callback(int event_type, const EmscriptenKeyboardEvent *key_event, void *user_data) { - - ERR_FAIL_COND_V(event_type != EMSCRIPTEN_EVENT_KEYDOWN, false); +EM_BOOL OS_JavaScript::keydown_callback(int p_event_type, const EmscriptenKeyboardEvent *p_event, void *p_user_data) { - Ref<InputEventKey> ev = _setup_key_event(key_event); + OS_JavaScript *os = get_singleton(); + Ref<InputEventKey> ev = setup_key_event(p_event); ev->set_pressed(true); if (ev->get_unicode() == 0 && keycode_has_unicode(ev->get_scancode())) { - // defer to keypress event for legacy unicode retrieval - deferred_key_event = ev; - return false; // do not suppress keypress event + // Defer to keypress event for legacy unicode retrieval. + os->deferred_key_event = ev; + // Do not suppress keypress event. + return false; } - _input->parse_input_event(ev); + os->input->parse_input_event(ev); return true; } -static EM_BOOL _keypress_callback(int event_type, const EmscriptenKeyboardEvent *key_event, void *user_data) { - - ERR_FAIL_COND_V(event_type != EMSCRIPTEN_EVENT_KEYPRESS, false); +EM_BOOL OS_JavaScript::keypress_callback(int p_event_type, const EmscriptenKeyboardEvent *p_event, void *p_user_data) { - deferred_key_event->set_unicode(key_event->charCode); - _input->parse_input_event(deferred_key_event); + OS_JavaScript *os = get_singleton(); + os->deferred_key_event->set_unicode(p_event->charCode); + os->input->parse_input_event(os->deferred_key_event); return true; } -static EM_BOOL _keyup_callback(int event_type, const EmscriptenKeyboardEvent *key_event, void *user_data) { - - ERR_FAIL_COND_V(event_type != EMSCRIPTEN_EVENT_KEYUP, false); +EM_BOOL OS_JavaScript::keyup_callback(int p_event_type, const EmscriptenKeyboardEvent *p_event, void *p_user_data) { - Ref<InputEventKey> ev = _setup_key_event(key_event); + Ref<InputEventKey> ev = setup_key_event(p_event); ev->set_pressed(false); - _input->parse_input_event(ev); + get_singleton()->input->parse_input_event(ev); return ev->get_scancode() != KEY_UNKNOWN && ev->get_scancode() != 0; } -static EM_BOOL joy_callback_func(int p_type, const EmscriptenGamepadEvent *p_event, void *p_user) { - OS_JavaScript *os = (OS_JavaScript *)OS::get_singleton(); - if (os) { - return os->joy_connection_changed(p_type, p_event); - } - return false; +// Mouse + +Point2 OS_JavaScript::get_mouse_position() const { + + return input->get_mouse_position(); } -extern "C" EMSCRIPTEN_KEEPALIVE void send_notification(int notif) { +int OS_JavaScript::get_mouse_button_state() const { - if (notif == MainLoop::NOTIFICATION_WM_MOUSE_ENTER || notif == MainLoop::NOTIFICATION_WM_MOUSE_EXIT) { - _cursor_inside_canvas = notif == MainLoop::NOTIFICATION_WM_MOUSE_ENTER; - } - OS_JavaScript::get_singleton()->get_main_loop()->notification(notif); + return input->get_mouse_button_mask(); } -Error OS_JavaScript::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) { +EM_BOOL OS_JavaScript::mouse_button_callback(int p_event_type, const EmscriptenMouseEvent *p_event, void *p_user_data) { - print_line("Init OS"); + OS_JavaScript *os = get_singleton(); - EmscriptenWebGLContextAttributes attributes; - emscripten_webgl_init_context_attributes(&attributes); - attributes.alpha = false; - attributes.antialias = false; - ERR_FAIL_INDEX_V(p_video_driver, VIDEO_DRIVER_MAX, ERR_INVALID_PARAMETER); - switch (p_video_driver) { - case VIDEO_DRIVER_GLES3: - attributes.majorVersion = 2; - RasterizerGLES3::register_config(); - RasterizerGLES3::make_current(); - break; - case VIDEO_DRIVER_GLES2: - attributes.majorVersion = 1; - RasterizerGLES2::register_config(); - RasterizerGLES2::make_current(); - break; + Ref<InputEventMouseButton> ev; + ev.instance(); + ev->set_pressed(p_event_type == EMSCRIPTEN_EVENT_MOUSEDOWN); + ev->set_position(Point2(p_event->canvasX, p_event->canvasY)); + ev->set_global_position(ev->get_position()); + dom2godot_mod(p_event, ev); + switch (p_event->button) { + case DOM_BUTTON_LEFT: ev->set_button_index(BUTTON_LEFT); break; + case DOM_BUTTON_MIDDLE: ev->set_button_index(BUTTON_MIDDLE); break; + case DOM_BUTTON_RIGHT: ev->set_button_index(BUTTON_RIGHT); break; + case DOM_BUTTON_XBUTTON1: ev->set_button_index(BUTTON_XBUTTON1); break; + case DOM_BUTTON_XBUTTON2: ev->set_button_index(BUTTON_XBUTTON2); break; + default: return false; } - EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx = emscripten_webgl_create_context(NULL, &attributes); - ERR_EXPLAIN("WebGL " + itos(attributes.majorVersion) + ".0 not available"); - ERR_FAIL_COND_V(emscripten_webgl_make_context_current(ctx) != EMSCRIPTEN_RESULT_SUCCESS, ERR_UNAVAILABLE); - video_mode = p_desired; - // can't fulfil fullscreen request due to browser security - video_mode.fullscreen = false; - /* clang-format off */ - if (EM_ASM_INT_V({ return Module.resizeCanvasOnStart })) { - /* clang-format on */ - set_window_size(Size2(video_mode.width, video_mode.height)); + int mask = os->input->get_mouse_button_mask(); + int button_flag = 1 << (ev->get_button_index() - 1); + if (ev->is_pressed()) { + // Since the event is consumed, focus manually. The containing iframe, + // if exists, may not have focus yet, so focus even if already focused. + focus_canvas(); + mask |= button_flag; + } else if (mask & button_flag) { + mask &= ~button_flag; } else { - set_window_size(get_window_size()); + // Received release event, but press was outside the canvas, so ignore. + return false; } + ev->set_button_mask(mask); - char locale_ptr[16]; - /* clang-format off */ - EM_ASM_ARGS({ - stringToUTF8(Module.locale, $0, 16); - }, locale_ptr); - /* clang-format on */ - setenv("LANG", locale_ptr, true); - - print_line("Init Audio"); - - AudioDriverManager::initialize(p_audio_driver); - - print_line("Init VS"); - - visual_server = memnew(VisualServerRaster()); - // visual_server->cursor_set_visible(false, 0); - - print_line("Init Physicsserver"); - - input = memnew(InputDefault); - _input = input; - -#define EM_CHECK(ev) \ - if (result != EMSCRIPTEN_RESULT_SUCCESS) \ - ERR_PRINTS("Error while setting " #ev " callback: Code " + itos(result)) -#define SET_EM_CALLBACK(target, ev, cb) \ - result = emscripten_set_##ev##_callback(target, this, true, &cb); \ - EM_CHECK(ev) -#define SET_EM_CALLBACK_NODATA(ev, cb) \ - result = emscripten_set_##ev##_callback(NULL, true, &cb); \ - EM_CHECK(ev) - - EMSCRIPTEN_RESULT result; - SET_EM_CALLBACK("#window", mousemove, _mousemove_callback) - SET_EM_CALLBACK("#canvas", mousedown, _mousebutton_callback) - SET_EM_CALLBACK("#window", mouseup, _mousebutton_callback) - SET_EM_CALLBACK("#window", wheel, _wheel_callback) - SET_EM_CALLBACK("#window", touchstart, _touchpress_callback) - SET_EM_CALLBACK("#window", touchmove, _touchmove_callback) - SET_EM_CALLBACK("#window", touchend, _touchpress_callback) - SET_EM_CALLBACK("#window", touchcancel, _touchpress_callback) - SET_EM_CALLBACK("#canvas", keydown, _keydown_callback) - SET_EM_CALLBACK("#canvas", keypress, _keypress_callback) - SET_EM_CALLBACK("#canvas", keyup, _keyup_callback) - SET_EM_CALLBACK(NULL, resize, _browser_resize_callback) - SET_EM_CALLBACK(NULL, fullscreenchange, _fullscreen_change_callback) - SET_EM_CALLBACK_NODATA(gamepadconnected, joy_callback_func) - SET_EM_CALLBACK_NODATA(gamepaddisconnected, joy_callback_func) - -#undef SET_EM_CALLBACK_NODATA -#undef SET_EM_CALLBACK -#undef EM_CHECK - - visual_server->init(); - - return OK; + os->input->parse_input_event(ev); + // Prevent multi-click text selection and wheel-click scrolling anchor. + // Context menu is prevented through contextmenu event. + return true; } -void OS_JavaScript::set_main_loop(MainLoop *p_main_loop) { +EM_BOOL OS_JavaScript::mousemove_callback(int p_event_type, const EmscriptenMouseEvent *p_event, void *p_user_data) { - main_loop = p_main_loop; - input->set_main_loop(p_main_loop); -} - -void OS_JavaScript::delete_main_loop() { + OS_JavaScript *os = get_singleton(); - memdelete(main_loop); -} + int input_mask = os->input->get_mouse_button_mask(); + Point2 pos = Point2(p_event->canvasX, p_event->canvasY); + // For motion outside the canvas, only read mouse movement if dragging + // started inside the canvas; imitating desktop app behaviour. + if (!cursor_inside_canvas && !input_mask) + return false; -void OS_JavaScript::finalize() { + Ref<InputEventMouseMotion> ev; + ev.instance(); + dom2godot_mod(p_event, ev); + ev->set_button_mask(input_mask); - memdelete(input); -} + ev->set_position(pos); + ev->set_global_position(ev->get_position()); -void OS_JavaScript::alert(const String &p_alert, const String &p_title) { + ev->set_relative(Vector2(p_event->movementX, p_event->movementY)); + os->input->set_mouse_position(ev->get_position()); + ev->set_speed(os->input->get_last_mouse_speed()); - /* clang-format off */ - EM_ASM_({ - window.alert(UTF8ToString($0)); - }, p_alert.utf8().get_data()); - /* clang-format on */ + os->input->parse_input_event(ev); + // Don't suppress mouseover/-leave events. + return false; } static const char *godot2dom_cursor(OS::CursorShape p_shape) { @@ -530,7 +376,7 @@ static const char *godot2dom_cursor(OS::CursorShape p_shape) { } } -void OS_JavaScript::set_css_cursor(const char *p_cursor) { +static void set_css_cursor(const char *p_cursor) { /* clang-format off */ EM_ASM_({ @@ -539,7 +385,7 @@ void OS_JavaScript::set_css_cursor(const char *p_cursor) { /* clang-format on */ } -const char *OS_JavaScript::get_css_cursor() const { +static const char *get_css_cursor() { char cursor[16]; /* clang-format off */ @@ -550,9 +396,20 @@ const char *OS_JavaScript::get_css_cursor() const { return cursor; } +void OS_JavaScript::set_cursor_shape(CursorShape p_shape) { + + ERR_FAIL_INDEX(p_shape, CURSOR_MAX); + + cursor_shape = p_shape; + if (get_mouse_mode() != MOUSE_MODE_HIDDEN) + set_css_cursor(godot2dom_cursor(cursor_shape)); +} + +void OS_JavaScript::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { +} + void OS_JavaScript::set_mouse_mode(OS::MouseMode p_mode) { - ERR_FAIL_INDEX(p_mode, MOUSE_MODE_CONFINED + 1); ERR_EXPLAIN("MOUSE_MODE_CONFINED is not supported for the HTML5 platform"); ERR_FAIL_COND(p_mode == MOUSE_MODE_CONFINED); if (p_mode == get_mouse_mode()) @@ -580,190 +437,308 @@ void OS_JavaScript::set_mouse_mode(OS::MouseMode p_mode) { OS::MouseMode OS_JavaScript::get_mouse_mode() const { - if (!strcmp(get_css_cursor(), "none")) + if (String::utf8(get_css_cursor()) == "none") return MOUSE_MODE_HIDDEN; EmscriptenPointerlockChangeEvent ev; emscripten_get_pointerlock_status(&ev); - return ev.isActive && (strcmp(ev.id, "canvas") == 0) ? MOUSE_MODE_CAPTURED : MOUSE_MODE_VISIBLE; + return (ev.isActive && String::utf8(ev.id) == "canvas") ? MOUSE_MODE_CAPTURED : MOUSE_MODE_VISIBLE; } -Point2 OS_JavaScript::get_mouse_position() const { +// Wheel - return input->get_mouse_position(); -} +EM_BOOL OS_JavaScript::wheel_callback(int p_event_type, const EmscriptenWheelEvent *p_event, void *p_user_data) { -int OS_JavaScript::get_mouse_button_state() const { + ERR_FAIL_COND_V(p_event_type != EMSCRIPTEN_EVENT_WHEEL, false); + if (!is_canvas_focused()) { + if (cursor_inside_canvas) { + focus_canvas(); + } else { + return false; + } + } - return input->get_mouse_button_mask(); -} + InputDefault *input = get_singleton()->input; + Ref<InputEventMouseButton> ev; + ev.instance(); + ev->set_button_mask(input->get_mouse_button_mask()); + ev->set_position(input->get_mouse_position()); + ev->set_global_position(ev->get_position()); -void OS_JavaScript::set_window_title(const String &p_title) { + ev->set_shift(input->is_key_pressed(KEY_SHIFT)); + ev->set_alt(input->is_key_pressed(KEY_ALT)); + ev->set_control(input->is_key_pressed(KEY_CONTROL)); + ev->set_metakey(input->is_key_pressed(KEY_META)); - /* clang-format off */ - EM_ASM_({ - document.title = UTF8ToString($0); - }, p_title.utf8().get_data()); - /* clang-format on */ -} + if (p_event->deltaY < 0) + ev->set_button_index(BUTTON_WHEEL_UP); + else if (p_event->deltaY > 0) + ev->set_button_index(BUTTON_WHEEL_DOWN); + else if (p_event->deltaX > 0) + ev->set_button_index(BUTTON_WHEEL_LEFT); + else if (p_event->deltaX < 0) + ev->set_button_index(BUTTON_WHEEL_RIGHT); + else + return false; -//interesting byt not yet -//void set_clipboard(const String& p_text); -//String get_clipboard() const; + // Different browsers give wildly different delta values, and we can't + // interpret deltaMode, so use default value for wheel events' factor. -void OS_JavaScript::set_video_mode(const VideoMode &p_video_mode, int p_screen) { + ev->set_pressed(true); + input->parse_input_event(ev); - video_mode = p_video_mode; + ev->set_pressed(false); + input->parse_input_event(ev); + + return true; } -OS::VideoMode OS_JavaScript::get_video_mode(int p_screen) const { +// Touch - return video_mode; +bool OS_JavaScript::has_touchscreen_ui_hint() const { + + /* clang-format off */ + return EM_ASM_INT_V( + return 'ontouchstart' in window; + ); + /* clang-format on */ } -Size2 OS_JavaScript::get_screen_size(int p_screen) const { +EM_BOOL OS_JavaScript::touch_press_callback(int p_event_type, const EmscriptenTouchEvent *p_event, void *p_user_data) { - EmscriptenFullscreenChangeEvent ev; - EMSCRIPTEN_RESULT result = emscripten_get_fullscreen_status(&ev); - ERR_FAIL_COND_V(result != EMSCRIPTEN_RESULT_SUCCESS, Size2()); - return Size2(ev.screenWidth, ev.screenHeight); -} + OS_JavaScript *os = get_singleton(); + Ref<InputEventScreenTouch> ev; + ev.instance(); + int lowest_id_index = -1; + for (int i = 0; i < p_event->numTouches; ++i) { -void OS_JavaScript::set_window_size(const Size2 p_size) { + const EmscriptenTouchPoint &touch = p_event->touches[i]; + if (lowest_id_index == -1 || touch.identifier < p_event->touches[lowest_id_index].identifier) + lowest_id_index = i; + if (!touch.isChanged) + continue; + ev->set_index(touch.identifier); + ev->set_position(Point2(touch.canvasX, touch.canvasY)); + os->touches[i] = ev->get_position(); + ev->set_pressed(p_event_type == EMSCRIPTEN_EVENT_TOUCHSTART); - windowed_size = p_size; - if (is_window_fullscreen()) { - window_maximized = false; - set_window_fullscreen(false); - } else if (is_window_maximized()) { - set_window_maximized(false); - } else { - video_mode.width = p_size.x; - video_mode.height = p_size.y; - emscripten_set_canvas_size(p_size.x, p_size.y); + os->input->parse_input_event(ev); } + return true; } -Size2 OS_JavaScript::get_window_size() const { +EM_BOOL OS_JavaScript::touchmove_callback(int p_event_type, const EmscriptenTouchEvent *p_event, void *p_user_data) { - int canvas[3]; - emscripten_get_canvas_size(canvas, canvas + 1, canvas + 2); - return Size2(canvas[0], canvas[1]); -} + OS_JavaScript *os = get_singleton(); + Ref<InputEventScreenDrag> ev; + ev.instance(); + int lowest_id_index = -1; + for (int i = 0; i < p_event->numTouches; ++i) { -void OS_JavaScript::set_window_maximized(bool p_enabled) { + const EmscriptenTouchPoint &touch = p_event->touches[i]; + if (lowest_id_index == -1 || touch.identifier < p_event->touches[lowest_id_index].identifier) + lowest_id_index = i; + if (!touch.isChanged) + continue; + ev->set_index(touch.identifier); + ev->set_position(Point2(touch.canvasX, touch.canvasY)); + Point2 &prev = os->touches[i]; + ev->set_relative(ev->get_position() - prev); + prev = ev->get_position(); - window_maximized = p_enabled; - if (is_window_fullscreen()) { - set_window_fullscreen(false); - return; + os->input->parse_input_event(ev); } - // Calling emscripten_enter_soft_fullscreen mutltiple times hides all - // page elements except the canvas permanently, so track state - if (p_enabled && !soft_fs_enabled) { + return true; +} - EmscriptenFullscreenStrategy strategy; - strategy.scaleMode = EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH; - strategy.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_STDDEF; - strategy.filteringMode = EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT; - strategy.canvasResizedCallback = NULL; - emscripten_enter_soft_fullscreen(NULL, &strategy); - soft_fs_enabled = true; - video_mode.width = get_window_size().width; - video_mode.height = get_window_size().height; - } else if (!p_enabled) { +// Gamepad - emscripten_exit_soft_fullscreen(); - soft_fs_enabled = false; - video_mode.width = windowed_size.width; - video_mode.height = windowed_size.height; - emscripten_set_canvas_size(video_mode.width, video_mode.height); +EM_BOOL OS_JavaScript::gamepad_change_callback(int p_event_type, const EmscriptenGamepadEvent *p_event, void *p_user_data) { + + InputDefault *input = get_singleton()->input; + if (p_event_type == EMSCRIPTEN_EVENT_GAMEPADCONNECTED) { + + String guid = ""; + if (String::utf8(p_event->mapping) == "standard") + guid = "Default HTML5 Gamepad"; + input->joy_connection_changed(p_event->index, true, String::utf8(p_event->id), guid); + } else { + input->joy_connection_changed(p_event->index, false, ""); } + return true; } -void OS_JavaScript::set_window_fullscreen(bool p_enable) { +void OS_JavaScript::process_joypads() { - if (p_enable == is_window_fullscreen()) { - return; - } + int joypad_count = emscripten_get_num_gamepads(); + for (int joypad = 0; joypad < joypad_count; joypad++) { + EmscriptenGamepadEvent state; + emscripten_get_gamepad_status(joypad, &state); + if (state.connected) { - // only requesting changes here, if successful, canvas is resized in - // _browser_resize_callback or _fullscreen_change_callback - EMSCRIPTEN_RESULT result; - if (p_enable) { - if (window_maximized) { - // soft fs during real fs can cause issues - set_window_maximized(false); - window_maximized = true; - } - EmscriptenFullscreenStrategy strategy; - strategy.scaleMode = EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH; - strategy.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_STDDEF; - strategy.filteringMode = EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT; - strategy.canvasResizedCallback = NULL; - emscripten_request_fullscreen_strategy(NULL, false, &strategy); - } else { - result = emscripten_exit_fullscreen(); - if (result != EMSCRIPTEN_RESULT_SUCCESS) { - ERR_PRINTS("Failed to exit fullscreen: Code " + itos(result)); + int button_count = MIN(state.numButtons, 18); + int axis_count = MIN(state.numAxes, 8); + for (int button = 0; button < button_count; button++) { + + float value = state.analogButton[button]; + if (String::utf8(state.mapping) == "standard" && (button == JOY_ANALOG_L2 || button == JOY_ANALOG_R2)) { + InputDefault::JoyAxis joy_axis; + joy_axis.min = 0; + joy_axis.value = value; + input->joy_axis(joypad, button, joy_axis); + } else { + input->joy_button(joypad, button, value); + } + } + for (int axis = 0; axis < axis_count; axis++) { + + InputDefault::JoyAxis joy_axis; + joy_axis.min = -1; + joy_axis.value = state.axis[axis]; + input->joy_axis(joypad, axis, joy_axis); + } } } } -bool OS_JavaScript::is_window_fullscreen() const { +bool OS_JavaScript::is_joy_known(int p_device) { - return video_mode.fullscreen; + return input->is_joy_mapped(p_device); } -void OS_JavaScript::request_canvas_size_adjustment() { +String OS_JavaScript::get_joy_guid(int p_device) const { - canvas_size_adjustment_requested = true; + return input->get_joy_guid_remapped(p_device); } -void OS_JavaScript::get_fullscreen_mode_list(List<VideoMode> *p_list, int p_screen) const { +// Video - Size2 screen = get_screen_size(); - p_list->push_back(OS::VideoMode(screen.width, screen.height, true)); +int OS_JavaScript::get_video_driver_count() const { + + return VIDEO_DRIVER_MAX; } -String OS_JavaScript::get_name() { +const char *OS_JavaScript::get_video_driver_name(int p_driver) const { - return "HTML5"; + switch (p_driver) { + case VIDEO_DRIVER_GLES3: + return "GLES3"; + case VIDEO_DRIVER_GLES2: + return "GLES2"; + } + ERR_EXPLAIN("Invalid video driver index " + itos(p_driver)); + ERR_FAIL_V(NULL); } -MainLoop *OS_JavaScript::get_main_loop() const { +// Audio - return main_loop; +int OS_JavaScript::get_audio_driver_count() const { + + return 1; } -bool OS_JavaScript::can_draw() const { +const char *OS_JavaScript::get_audio_driver_name(int p_driver) const { - return true; //always? + return "JavaScript"; } -void OS_JavaScript::set_cursor_shape(CursorShape p_shape) { +// Lifecycle +int OS_JavaScript::get_current_video_driver() const { + return video_driver_index; +} - ERR_FAIL_INDEX(p_shape, CURSOR_MAX); +void OS_JavaScript::initialize_core() { - cursor_shape = p_shape; - if (get_mouse_mode() != MOUSE_MODE_HIDDEN) - set_css_cursor(godot2dom_cursor(cursor_shape)); + OS_Unix::initialize_core(); + FileAccess::make_default<FileAccessBufferedFA<FileAccessUnix> >(FileAccess::ACCESS_RESOURCES); } -void OS_JavaScript::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { -} +Error OS_JavaScript::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) { -void OS_JavaScript::main_loop_begin() { + EmscriptenWebGLContextAttributes attributes; + emscripten_webgl_init_context_attributes(&attributes); + attributes.alpha = false; + attributes.antialias = false; + ERR_FAIL_INDEX_V(p_video_driver, VIDEO_DRIVER_MAX, ERR_INVALID_PARAMETER); + switch (p_video_driver) { + case VIDEO_DRIVER_GLES3: + attributes.majorVersion = 2; + RasterizerGLES3::register_config(); + RasterizerGLES3::make_current(); + break; + case VIDEO_DRIVER_GLES2: + attributes.majorVersion = 1; + RasterizerGLES2::register_config(); + RasterizerGLES2::make_current(); + break; + } + + video_driver_index = p_video_driver; + EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx = emscripten_webgl_create_context(NULL, &attributes); + ERR_EXPLAIN("WebGL " + itos(attributes.majorVersion) + ".0 not available"); + ERR_FAIL_COND_V(emscripten_webgl_make_context_current(ctx) != EMSCRIPTEN_RESULT_SUCCESS, ERR_UNAVAILABLE); + + video_mode = p_desired; + // Can't fulfil fullscreen request during start-up due to browser security. + video_mode.fullscreen = false; + /* clang-format off */ + if (EM_ASM_INT_V({ return Module.resizeCanvasOnStart })) { + /* clang-format on */ + set_window_size(Size2(video_mode.width, video_mode.height)); + } else { + set_window_size(get_window_size()); + } - if (main_loop) - main_loop->init(); + char locale_ptr[16]; + /* clang-format off */ + EM_ASM_ARGS({ + stringToUTF8(Module.locale, $0, 16); + }, locale_ptr); + /* clang-format on */ + setenv("LANG", locale_ptr, true); + + AudioDriverManager::initialize(p_audio_driver); + VisualServer *visual_server = memnew(VisualServerRaster()); + input = memnew(InputDefault); + + EMSCRIPTEN_RESULT result; +#define EM_CHECK(ev) \ + if (result != EMSCRIPTEN_RESULT_SUCCESS) \ + ERR_PRINTS("Error while setting " #ev " callback: Code " + itos(result)) +#define SET_EM_CALLBACK(target, ev, cb) \ + result = emscripten_set_##ev##_callback(target, NULL, true, &cb); \ + EM_CHECK(ev) +#define SET_EM_CALLBACK_NOTARGET(ev, cb) \ + result = emscripten_set_##ev##_callback(NULL, true, &cb); \ + EM_CHECK(ev) + // These callbacks from Emscripten's html5.h suffice to access most + // JavaScript APIs. For APIs that are not (sufficiently) exposed, EM_ASM + // is used below. + SET_EM_CALLBACK("#window", mousemove, mousemove_callback) + SET_EM_CALLBACK("#canvas", mousedown, mouse_button_callback) + SET_EM_CALLBACK("#window", mouseup, mouse_button_callback) + SET_EM_CALLBACK("#window", wheel, wheel_callback) + SET_EM_CALLBACK("#window", touchstart, touch_press_callback) + SET_EM_CALLBACK("#window", touchmove, touchmove_callback) + SET_EM_CALLBACK("#window", touchend, touch_press_callback) + SET_EM_CALLBACK("#window", touchcancel, touch_press_callback) + SET_EM_CALLBACK("#canvas", keydown, keydown_callback) + SET_EM_CALLBACK("#canvas", keypress, keypress_callback) + SET_EM_CALLBACK("#canvas", keyup, keyup_callback) + SET_EM_CALLBACK(NULL, resize, browser_resize_callback) + SET_EM_CALLBACK(NULL, fullscreenchange, fullscreen_change_callback) + SET_EM_CALLBACK_NOTARGET(gamepadconnected, gamepad_change_callback) + SET_EM_CALLBACK_NOTARGET(gamepaddisconnected, gamepad_change_callback) +#undef SET_EM_CALLBACK_NODATA +#undef SET_EM_CALLBACK +#undef EM_CHECK /* clang-format off */ EM_ASM_ARGS({ const send_notification = cwrap('send_notification', null, ['number']); - const notifs = arguments; - (['mouseover', 'mouseleave', 'focus', 'blur']).forEach(function(event, i) { - Module.canvas.addEventListener(event, send_notification.bind(null, notifs[i])); + const notifications = arguments; + (['mouseover', 'mouseleave', 'focus', 'blur']).forEach(function(event, index) { + Module.canvas.addEventListener(event, send_notification.bind(null, notifications[index])); }); }, MainLoop::NOTIFICATION_WM_MOUSE_ENTER, @@ -772,22 +747,44 @@ void OS_JavaScript::main_loop_begin() { MainLoop::NOTIFICATION_WM_FOCUS_OUT ); /* clang-format on */ + + visual_server->init(); + + return OK; } -bool OS_JavaScript::main_loop_iterate() { +void OS_JavaScript::set_main_loop(MainLoop *p_main_loop) { - if (!main_loop) - return false; + main_loop = p_main_loop; + input->set_main_loop(p_main_loop); +} + +MainLoop *OS_JavaScript::get_main_loop() const { + + return main_loop; +} + +void OS_JavaScript::run_async() { + + main_loop->init(); + emscripten_set_main_loop(main_loop_callback, -1, false); +} + +void OS_JavaScript::main_loop_callback() { + + get_singleton()->main_loop_iterate(); +} + +bool OS_JavaScript::main_loop_iterate() { - if (idbfs_available && time_to_save_sync >= 0) { - int64_t newtime = get_ticks_msec(); - int64_t elapsed = newtime - last_sync_time; - last_sync_time = newtime; + if (is_userfs_persistent() && sync_wait_time >= 0) { + int64_t current_time = get_ticks_msec(); + int64_t elapsed_time = current_time - last_sync_check_time; + last_sync_check_time = current_time; - time_to_save_sync -= elapsed; + sync_wait_time -= elapsed_time; - if (time_to_save_sync < 0) { - //time to sync, for real + if (sync_wait_time < 0) { /* clang-format off */ EM_ASM( FS.syncfs(function(err) { @@ -812,121 +809,101 @@ bool OS_JavaScript::main_loop_iterate() { return Main::iteration(); } -void OS_JavaScript::main_loop_end() { +void OS_JavaScript::delete_main_loop() { - if (main_loop) - main_loop->finish(); + memdelete(main_loop); } -void OS_JavaScript::process_accelerometer(const Vector3 &p_accelerometer) { +void OS_JavaScript::finalize() { - input->set_accelerometer(p_accelerometer); + memdelete(input); } -bool OS_JavaScript::has_touchscreen_ui_hint() const { +// Miscellaneous - /* clang-format off */ - return EM_ASM_INT_V( - return 'ontouchstart' in window; - ); - /* clang-format on */ +extern "C" EMSCRIPTEN_KEEPALIVE void send_notification(int p_notification) { + + if (p_notification == MainLoop::NOTIFICATION_WM_MOUSE_ENTER || p_notification == MainLoop::NOTIFICATION_WM_MOUSE_EXIT) { + cursor_inside_canvas = p_notification == MainLoop::NOTIFICATION_WM_MOUSE_ENTER; + } + OS_JavaScript::get_singleton()->get_main_loop()->notification(p_notification); } -void OS_JavaScript::main_loop_request_quit() { +bool OS_JavaScript::_check_internal_feature_support(const String &p_feature) { + + if (p_feature == "HTML5" || p_feature == "web") + return true; + +#ifdef JAVASCRIPT_EVAL_ENABLED + if (p_feature == "JavaScript") + return true; +#endif + + EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx = emscripten_webgl_get_current_context(); + // All extensions are already automatically enabled, this function allows + // checking WebGL extension support without inline JavaScript + if (p_feature == "s3tc") + return emscripten_webgl_enable_extension(ctx, "WEBGL_compressed_texture_s3tc_srgb"); + if (p_feature == "etc") + return emscripten_webgl_enable_extension(ctx, "WEBGL_compressed_texture_etc1"); + if (p_feature == "etc2") + return emscripten_webgl_enable_extension(ctx, "WEBGL_compressed_texture_etc"); - if (main_loop) - main_loop->notification(MainLoop::NOTIFICATION_WM_QUIT_REQUEST); + return false; } -Error OS_JavaScript::shell_open(String p_uri) { +void OS_JavaScript::alert(const String &p_alert, const String &p_title) { + /* clang-format off */ EM_ASM_({ - window.open(UTF8ToString($0), '_blank'); - }, p_uri.utf8().get_data()); + window.alert(UTF8ToString($0)); + }, p_alert.utf8().get_data()); /* clang-format on */ - return OK; } -String OS_JavaScript::get_resource_dir() const { +void OS_JavaScript::set_window_title(const String &p_title) { - return "/"; //javascript has it's own filesystem for resources inside the APK + /* clang-format off */ + EM_ASM_({ + document.title = UTF8ToString($0); + }, p_title.utf8().get_data()); + /* clang-format on */ } -String OS_JavaScript::get_user_data_dir() const { - - /* - if (get_user_data_dir_func) - return get_user_data_dir_func(); - */ - return "/userfs"; -}; - String OS_JavaScript::get_executable_path() const { return OS::get_executable_path(); } -void OS_JavaScript::_close_notification_funcs(const String &p_file, int p_flags) { +Error OS_JavaScript::shell_open(String p_uri) { - OS_JavaScript *os = static_cast<OS_JavaScript *>(get_singleton()); - if (os->idbfs_available && p_file.begins_with("/userfs") && p_flags & FileAccess::WRITE) { - os->last_sync_time = OS::get_singleton()->get_ticks_msec(); - os->time_to_save_sync = 5000; //five seconds since last save - } + // Open URI in a new tab, browser will deal with it by protocol. + /* clang-format off */ + EM_ASM_({ + window.open(UTF8ToString($0), '_blank'); + }, p_uri.utf8().get_data()); + /* clang-format on */ + return OK; } -void OS_JavaScript::process_joypads() { - - int joy_count = emscripten_get_num_gamepads(); - for (int i = 0; i < joy_count; i++) { - EmscriptenGamepadEvent state; - emscripten_get_gamepad_status(i, &state); - if (state.connected) { +String OS_JavaScript::get_name() { - int num_buttons = MIN(state.numButtons, 18); - int num_axes = MIN(state.numAxes, 8); - for (int j = 0; j < num_buttons; j++) { + return "HTML5"; +} - float value = state.analogButton[j]; - if (String(state.mapping) == "standard" && (j == 6 || j == 7)) { - InputDefault::JoyAxis jx; - jx.min = 0; - jx.value = value; - input->joy_axis(i, j, jx); - } else { - input->joy_button(i, j, value); - } - } - for (int j = 0; j < num_axes; j++) { +bool OS_JavaScript::can_draw() const { - InputDefault::JoyAxis jx; - jx.min = -1; - jx.value = state.axis[j]; - input->joy_axis(i, j, jx); - } - } - } + return true; // Always? } -bool OS_JavaScript::joy_connection_changed(int p_type, const EmscriptenGamepadEvent *p_event) { - if (p_type == EMSCRIPTEN_EVENT_GAMEPADCONNECTED) { +String OS_JavaScript::get_user_data_dir() const { - String guid = ""; - if (String(p_event->mapping) == "standard") - guid = "Default HTML5 Gamepad"; - input->joy_connection_changed(p_event->index, true, String(p_event->id), guid); - } else { - input->joy_connection_changed(p_event->index, false, ""); - } - return true; -} + return "/userfs"; +}; -bool OS_JavaScript::is_joy_known(int p_device) { - return input->is_joy_mapped(p_device); -} +String OS_JavaScript::get_resource_dir() const { -String OS_JavaScript::get_joy_guid(int p_device) const { - return input->get_joy_guid_remapped(p_device); + return "/"; } OS::PowerState OS_JavaScript::get_power_state() { @@ -947,59 +924,53 @@ int OS_JavaScript::get_power_percent_left() { return -1; } -bool OS_JavaScript::_check_internal_feature_support(const String &p_feature) { +void OS_JavaScript::file_access_close_callback(const String &p_file, int p_flags) { - if (p_feature == "HTML5" || p_feature == "web") - return true; - -#ifdef JAVASCRIPT_EVAL_ENABLED - if (p_feature == "JavaScript") - return true; -#endif + OS_JavaScript *os = get_singleton(); + if (os->is_userfs_persistent() && p_file.begins_with("/userfs") && p_flags & FileAccess::WRITE) { + os->last_sync_check_time = OS::get_singleton()->get_ticks_msec(); + // Wait five seconds in case more files are about to be closed. + os->sync_wait_time = 5000; + } +} - EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx = emscripten_webgl_get_current_context(); - // all extensions are already automatically enabled, this function allows - // checking WebGL extension support without inline JavaScript - if (p_feature == "s3tc" && emscripten_webgl_enable_extension(ctx, "WEBGL_compressed_texture_s3tc_srgb")) - return true; - if (p_feature == "etc" && emscripten_webgl_enable_extension(ctx, "WEBGL_compressed_texture_etc1")) - return true; - if (p_feature == "etc2" && emscripten_webgl_enable_extension(ctx, "WEBGL_compressed_texture_etc")) - return true; +void OS_JavaScript::set_idb_available(bool p_idb_available) { - return false; + idb_available = p_idb_available; } -void OS_JavaScript::set_idbfs_available(bool p_idbfs_available) { +bool OS_JavaScript::is_userfs_persistent() const { - idbfs_available = p_idbfs_available; + return idb_available; } -bool OS_JavaScript::is_userfs_persistent() const { +OS_JavaScript *OS_JavaScript::get_singleton() { - return idbfs_available; + return static_cast<OS_JavaScript *>(OS::get_singleton()); } -OS_JavaScript::OS_JavaScript(const char *p_execpath, GetUserDataDirFunc p_get_user_data_dir_func) { +OS_JavaScript::OS_JavaScript(int p_argc, char *p_argv[]) { + + List<String> arguments; + for (int i = 1; i < p_argc; i++) { + arguments.push_back(String::utf8(p_argv[i])); + } + set_cmdline(p_argv[0], arguments); - set_cmdline(p_execpath, get_cmdline_args()); - main_loop = NULL; window_maximized = false; - soft_fs_enabled = false; + soft_fullscreen_enabled = false; canvas_size_adjustment_requested = false; - get_user_data_dir_func = p_get_user_data_dir_func; - FileAccessUnix::close_notification_func = _close_notification_funcs; + main_loop = NULL; - idbfs_available = false; - time_to_save_sync = -1; + idb_available = false; + sync_wait_time = -1; + + AudioDriverManager::add_driver(&audio_driver_javascript); Vector<Logger *> loggers; loggers.push_back(memnew(StdLogger)); _set_logger(memnew(CompositeLogger(loggers))); - AudioDriverManager::add_driver(&audio_driver_javascript); -} - -OS_JavaScript::~OS_JavaScript() { + FileAccessUnix::close_notification_func = file_access_close_callback; } diff --git a/platform/javascript/os_javascript.h b/platform/javascript/os_javascript.h index 46eb1b3f13..915320fe39 100644 --- a/platform/javascript/os_javascript.h +++ b/platform/javascript/os_javascript.h @@ -32,51 +32,59 @@ #define OS_JAVASCRIPT_H #include "audio_driver_javascript.h" -#include "drivers/unix/os_unix.h" #include "main/input_default.h" -#include "os/input.h" -#include "os/main_loop.h" #include "servers/audio_server.h" #include "servers/visual/rasterizer.h" +#include "unix/os_unix.h" #include <emscripten/html5.h> -typedef String (*GetUserDataDirFunc)(); - class OS_JavaScript : public OS_Unix { - bool idbfs_available; - int64_t time_to_save_sync; - int64_t last_sync_time; - - VisualServer *visual_server; - AudioDriverJavaScript audio_driver_javascript; - - InputDefault *input; + VideoMode video_mode; Vector2 windowed_size; bool window_maximized; - bool soft_fs_enabled; + bool soft_fullscreen_enabled; bool canvas_size_adjustment_requested; - VideoMode video_mode; + + InputDefault *input; + Ref<InputEventKey> deferred_key_event; CursorShape cursor_shape; + Point2 touches[32]; + MainLoop *main_loop; + AudioDriverJavaScript audio_driver_javascript; + + bool idb_available; + int64_t sync_wait_time; + int64_t last_sync_check_time; + + static EM_BOOL browser_resize_callback(int p_event_type, const EmscriptenUiEvent *p_event, void *p_user_data); + static EM_BOOL fullscreen_change_callback(int p_event_type, const EmscriptenFullscreenChangeEvent *p_event, void *p_user_data); + + static EM_BOOL keydown_callback(int p_event_type, const EmscriptenKeyboardEvent *p_event, void *p_user_data); + static EM_BOOL keypress_callback(int p_event_type, const EmscriptenKeyboardEvent *p_event, void *p_user_data); + static EM_BOOL keyup_callback(int p_event_type, const EmscriptenKeyboardEvent *p_event, void *p_user_data); + + static EM_BOOL mousemove_callback(int p_event_type, const EmscriptenMouseEvent *p_event, void *p_user_data); + static EM_BOOL mouse_button_callback(int p_event_type, const EmscriptenMouseEvent *p_event, void *p_user_data); - GetUserDataDirFunc get_user_data_dir_func; + static EM_BOOL wheel_callback(int p_event_type, const EmscriptenWheelEvent *p_event, void *p_user_data); - static void _close_notification_funcs(const String &p_file, int p_flags); + static EM_BOOL touch_press_callback(int p_event_type, const EmscriptenTouchEvent *p_event, void *p_user_data); + static EM_BOOL touchmove_callback(int p_event_type, const EmscriptenTouchEvent *p_event, void *p_user_data); + static EM_BOOL gamepad_change_callback(int p_event_type, const EmscriptenGamepadEvent *p_event, void *p_user_data); void process_joypads(); - void set_css_cursor(const char *); - const char *get_css_cursor() const; + static void main_loop_callback(); -public: - // functions used by main to initialize/deintialize the OS - virtual int get_video_driver_count() const; - virtual const char *get_video_driver_name(int p_driver) const; + static void file_access_close_callback(const String &p_file, int p_flags); - virtual int get_audio_driver_count() const; - virtual const char *get_audio_driver_name(int p_driver) const; + int video_driver_index; + +protected: + virtual int get_current_video_driver() const; virtual void initialize_core(); virtual Error initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); @@ -86,77 +94,64 @@ public: virtual void finalize(); - typedef int64_t ProcessID; - - //static OS* get_singleton(); - - virtual void alert(const String &p_alert, const String &p_title = "ALERT!"); - - virtual void set_mouse_mode(MouseMode p_mode); - virtual MouseMode get_mouse_mode() const; - virtual Point2 get_mouse_position() const; - virtual int get_mouse_button_state() const; - virtual void set_window_title(const String &p_title); + virtual bool _check_internal_feature_support(const String &p_feature); - //virtual void set_clipboard(const String& p_text); - //virtual String get_clipboard() const; +public: + // Override return type to make writing static callbacks less tedious. + static OS_JavaScript *get_singleton(); virtual void set_video_mode(const VideoMode &p_video_mode, int p_screen = 0); virtual VideoMode get_video_mode(int p_screen = 0) const; virtual void get_fullscreen_mode_list(List<VideoMode> *p_list, int p_screen = 0) const; - virtual Size2 get_screen_size(int p_screen = -1) const; - virtual void set_window_size(const Size2); virtual Size2 get_window_size() const; virtual void set_window_maximized(bool p_enabled); - virtual bool is_window_maximized() const { return window_maximized; } - virtual void set_window_fullscreen(bool p_enable); + virtual bool is_window_maximized() const; + virtual void set_window_fullscreen(bool p_enabled); virtual bool is_window_fullscreen() const; + virtual Size2 get_screen_size(int p_screen = -1) const; - void request_canvas_size_adjustment(); + virtual Point2 get_mouse_position() const; + virtual int get_mouse_button_state() const; + virtual void set_cursor_shape(CursorShape p_shape); + virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot); + virtual void set_mouse_mode(MouseMode p_mode); + virtual MouseMode get_mouse_mode() const; - virtual String get_name(); - virtual MainLoop *get_main_loop() const; + virtual bool has_touchscreen_ui_hint() const; - virtual bool can_draw() const; + virtual bool is_joy_known(int p_device); + virtual String get_joy_guid(int p_device) const; - virtual bool is_userfs_persistent() const; + virtual int get_video_driver_count() const; + virtual const char *get_video_driver_name(int p_driver) const; - virtual void set_cursor_shape(CursorShape p_shape); - virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot); + virtual int get_audio_driver_count() const; + virtual const char *get_audio_driver_name(int p_driver) const; - void main_loop_begin(); + virtual MainLoop *get_main_loop() const; + void run_async(); bool main_loop_iterate(); - void main_loop_request_quit(); - void main_loop_end(); - void main_loop_focusout(); - void main_loop_focusin(); - virtual bool has_touchscreen_ui_hint() const; - - virtual Error shell_open(String p_uri); - virtual String get_user_data_dir() const; + virtual void alert(const String &p_alert, const String &p_title = "ALERT!"); + virtual void set_window_title(const String &p_title); String get_executable_path() const; - virtual String get_resource_dir() const; - - void process_accelerometer(const Vector3 &p_accelerometer); - void push_input(const Ref<InputEvent> &p_ev); + virtual Error shell_open(String p_uri); + virtual String get_name(); + virtual bool can_draw() const; - virtual bool is_joy_known(int p_device); - virtual String get_joy_guid(int p_device) const; - bool joy_connection_changed(int p_type, const EmscriptenGamepadEvent *p_event); + virtual String get_resource_dir() const; + virtual String get_user_data_dir() const; virtual OS::PowerState get_power_state(); virtual int get_power_seconds_left(); virtual int get_power_percent_left(); - virtual bool _check_internal_feature_support(const String &p_feature); - - void set_idbfs_available(bool p_idbfs_available); + void set_idb_available(bool p_idb_available); + virtual bool is_userfs_persistent() const; - OS_JavaScript(const char *p_execpath, GetUserDataDirFunc p_get_user_data_dir_func); - ~OS_JavaScript(); + OS_JavaScript(int p_argc, char *p_argv[]); }; #endif diff --git a/platform/osx/SCsub b/platform/osx/SCsub index 4dfa46528a..5c973c30c2 100644 --- a/platform/osx/SCsub +++ b/platform/osx/SCsub @@ -3,14 +3,8 @@ import os Import('env') -def make_debug(target, source, env): - if (env["macports_clang"] != 'no'): - mpprefix = os.environ.get("MACPORTS_PREFIX", "/opt/local") - mpclangver = env["macports_clang"] - os.system(mpprefix + '/libexec/llvm-' + mpclangver + '/bin/llvm-dsymutil {0} -o {0}.dSYM'.format(target[0])) - else: - os.system('dsymutil {0} -o {0}.dSYM'.format(target[0])) - os.system('strip -u -r {0}'.format(target[0])) +from platform_methods import run_in_subprocess +import platform_osx_builders files = [ 'crash_handler_osx.mm', @@ -25,5 +19,5 @@ files = [ prog = env.add_program('#bin/godot', files) if (env["debug_symbols"] == "full" or env["debug_symbols"] == "yes") and env["separate_debug_symbols"]: - env.AddPostAction(prog, make_debug) + env.AddPostAction(prog, run_in_subprocess(platform_osx_builders.make_debug_osx)) diff --git a/platform/osx/detect.py b/platform/osx/detect.py index 72b8aa99f8..8a0883eca3 100644 --- a/platform/osx/detect.py +++ b/platform/osx/detect.py @@ -39,14 +39,21 @@ def configure(env): ## Build type if (env["target"] == "release"): - env.Prepend(CCFLAGS=['-O3', '-ffast-math', '-fomit-frame-pointer', '-ftree-vectorize', '-msse2']) + if (env["optimize"] == "speed"): #optimize for speed (default) + env.Prepend(CCFLAGS=['-O3', '-ffast-math', '-fomit-frame-pointer', '-ftree-vectorize', '-msse2']) + else: #optimize for size + env.Prepend(CCFLAGS=['-Os','-ftree-vectorize', '-msse2']) + if (env["debug_symbols"] == "yes"): env.Prepend(CCFLAGS=['-g1']) if (env["debug_symbols"] == "full"): env.Prepend(CCFLAGS=['-g2']) elif (env["target"] == "release_debug"): - env.Prepend(CCFLAGS=['-O2', '-DDEBUG_ENABLED']) + if (env["optimize"] == "speed"): #optimize for speed (default) + env.Prepend(CCFLAGS=['-O2', '-DDEBUG_ENABLED']) + else: #optimize for size + env.Prepend(CCFLAGS=['-Os', '-DDEBUG_ENABLED']) if (env["debug_symbols"] == "yes"): env.Prepend(CCFLAGS=['-g1']) if (env["debug_symbols"] == "full"): @@ -108,8 +115,8 @@ def configure(env): ## Flags env.Append(CPPPATH=['#platform/osx']) - env.Append(CPPFLAGS=['-DOSX_ENABLED', '-DUNIX_ENABLED', '-DGLES_ENABLED', '-DAPPLE_STYLE_KEYS', '-DCOREAUDIO_ENABLED']) - env.Append(LINKFLAGS=['-framework', 'Cocoa', '-framework', 'Carbon', '-framework', 'OpenGL', '-framework', 'AGL', '-framework', 'AudioUnit', '-framework', 'CoreAudio', '-lz', '-framework', 'IOKit', '-framework', 'ForceFeedback']) + env.Append(CPPFLAGS=['-DOSX_ENABLED', '-DUNIX_ENABLED', '-DGLES_ENABLED', '-DAPPLE_STYLE_KEYS', '-DCOREAUDIO_ENABLED', '-DCOREMIDI_ENABLED']) + env.Append(LINKFLAGS=['-framework', 'Cocoa', '-framework', 'Carbon', '-framework', 'OpenGL', '-framework', 'AGL', '-framework', 'AudioUnit', '-framework', 'CoreAudio', '-framework', 'CoreMIDI', '-lz', '-framework', 'IOKit', '-framework', 'ForceFeedback']) env.Append(LIBS=['pthread']) env.Append(CPPFLAGS=['-mmacosx-version-min=10.9']) diff --git a/platform/osx/export/export.cpp b/platform/osx/export/export.cpp index db265812fa..b630e4f223 100644 --- a/platform/osx/export/export.cpp +++ b/platform/osx/export/export.cpp @@ -137,10 +137,10 @@ void EditorExportPlatformOSX::_make_icon(const Ref<Image> &p_icon, Vector<uint8_ Vector<uint8_t> data; data.resize(8); - data[0] = 'i'; - data[1] = 'c'; - data[2] = 'n'; - data[3] = 's'; + data.write[0] = 'i'; + data.write[1] = 'c'; + data.write[2] = 'n'; + data.write[3] = 's'; const char *name[] = { "ic09", "ic08", "ic07", "icp6", "icp5", "icp4" }; int index = 0; @@ -160,19 +160,19 @@ void EditorExportPlatformOSX::_make_icon(const Ref<Image> &p_icon, Vector<uint8_ int ofs = data.size(); uint32_t len = f->get_len(); data.resize(data.size() + len + 8); - f->get_buffer(&data[ofs + 8], len); + f->get_buffer(&data.write[ofs + 8], len); memdelete(f); len += 8; len = BSWAP32(len); - copymem(&data[ofs], name[index], 4); - encode_uint32(len, &data[ofs + 4]); + copymem(&data.write[ofs], name[index], 4); + encode_uint32(len, &data.write[ofs + 4]); index++; size /= 2; } uint32_t total_len = data.size(); total_len = BSWAP32(total_len); - encode_uint32(total_len, &data[4]); + encode_uint32(total_len, &data.write[4]); p_data = data; } @@ -210,7 +210,7 @@ void EditorExportPlatformOSX::_fix_plist(const Ref<EditorExportPreset> &p_preset CharString cs = strnew.utf8(); plist.resize(cs.size() - 1); for (int i = 0; i < cs.size() - 1; i++) { - plist[i] = cs[i]; + plist.write[i] = cs[i]; } } diff --git a/platform/osx/joypad_osx.cpp b/platform/osx/joypad_osx.cpp index 20ceadca9d..365b39c573 100644 --- a/platform/osx/joypad_osx.cpp +++ b/platform/osx/joypad_osx.cpp @@ -271,7 +271,7 @@ void JoypadOSX::_device_removed(int p_id) { ERR_FAIL_COND(device == -1); input->joy_connection_changed(p_id, false, ""); - device_list[device].free(); + device_list.write[device].free(); device_list.remove(device); } @@ -460,19 +460,19 @@ void JoypadOSX::process_joypads() { poll_joypads(); for (int i = 0; i < device_list.size(); i++) { - joypad &joy = device_list[i]; + joypad &joy = device_list.write[i]; for (int j = 0; j < joy.axis_elements.size(); j++) { - rec_element &elem = joy.axis_elements[j]; + rec_element &elem = joy.axis_elements.write[j]; int value = joy.get_hid_element_state(&elem); input->joy_axis(joy.id, j, axis_correct(value, elem.min, elem.max)); } for (int j = 0; j < joy.button_elements.size(); j++) { - int value = joy.get_hid_element_state(&joy.button_elements[j]); + int value = joy.get_hid_element_state(&joy.button_elements.write[j]); input->joy_button(joy.id, j, (value >= 1)); } for (int j = 0; j < joy.hat_elements.size(); j++) { - rec_element &elem = joy.hat_elements[j]; + rec_element &elem = joy.hat_elements.write[j]; int value = joy.get_hid_element_state(&elem); int hat_value = process_hat_value(elem.min, elem.max, value); input->joy_hat(joy.id, hat_value); @@ -495,7 +495,7 @@ void JoypadOSX::process_joypads() { } void JoypadOSX::joypad_vibration_start(int p_id, float p_magnitude, float p_duration, uint64_t p_timestamp) { - joypad *joy = &device_list[get_joy_index(p_id)]; + joypad *joy = &device_list.write[get_joy_index(p_id)]; joy->ff_timestamp = p_timestamp; joy->ff_effect.dwDuration = p_duration * FF_SECONDS; joy->ff_effect.dwGain = p_magnitude * FF_FFNOMINALMAX; @@ -504,7 +504,7 @@ void JoypadOSX::joypad_vibration_start(int p_id, float p_magnitude, float p_dura } void JoypadOSX::joypad_vibration_stop(int p_id, uint64_t p_timestamp) { - joypad *joy = &device_list[get_joy_index(p_id)]; + joypad *joy = &device_list.write[get_joy_index(p_id)]; joy->ff_timestamp = p_timestamp; FFEffectStop(joy->ff_object); } @@ -596,7 +596,7 @@ JoypadOSX::JoypadOSX() { JoypadOSX::~JoypadOSX() { for (int i = 0; i < device_list.size(); i++) { - device_list[i].free(); + device_list.write[i].free(); } IOHIDManagerUnscheduleFromRunLoop(hid_manager, CFRunLoopGetCurrent(), GODOT_JOY_LOOP_RUN_MODE); diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h index 7bd5b16f36..686e3f8c90 100644 --- a/platform/osx/os_osx.h +++ b/platform/osx/os_osx.h @@ -33,6 +33,7 @@ #include "crash_handler_osx.h" #include "drivers/coreaudio/audio_driver_coreaudio.h" +#include "drivers/coremidi/core_midi.h" #include "drivers/unix/os_unix.h" #include "joypad_osx.h" #include "main/input_default.h" @@ -74,6 +75,7 @@ public: IP_Unix *ip_unix; AudioDriverCoreAudio audio_driver; + MIDIDriverCoreMidi midi_driver; InputDefault *input; JoypadOSX *joypad_osx; @@ -137,6 +139,9 @@ public: void _update_window(); + int video_driver_index; + virtual int get_current_video_driver() const; + protected: virtual void initialize_core(); virtual Error initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm index 4ece1e0325..7bf274310d 100644 --- a/platform/osx/os_osx.mm +++ b/platform/osx/os_osx.mm @@ -95,7 +95,7 @@ static void push_to_key_event_buffer(const OS_OSX::KeyEvent &p_event) { if (OS_OSX::singleton->key_event_pos >= buffer.size()) { buffer.resize(1 + OS_OSX::singleton->key_event_pos); } - buffer[OS_OSX::singleton->key_event_pos++] = p_event; + buffer.write[OS_OSX::singleton->key_event_pos++] = p_event; } static int mouse_x = 0; @@ -602,8 +602,8 @@ static void _mouseDownEvent(NSEvent *event, int index, int mask, bool pressed) { mm->set_position(pos); mm->set_global_position(pos); Vector2 relativeMotion = Vector2(); - relativeMotion.x = [event deltaX] * OS_OSX::singleton->_mouse_scale([[event window] backingScaleFactor]); - relativeMotion.y = [event deltaY] * OS_OSX::singleton->_mouse_scale([[event window] backingScaleFactor]); + relativeMotion.x = [event deltaX] * OS_OSX::singleton -> _mouse_scale([[event window] backingScaleFactor]); + relativeMotion.y = [event deltaY] * OS_OSX::singleton -> _mouse_scale([[event window] backingScaleFactor]); mm->set_relative(relativeMotion); get_key_modifier_state([event modifierFlags], mm); @@ -625,10 +625,18 @@ static void _mouseDownEvent(NSEvent *event, int index, int mask, bool pressed) { - (void)otherMouseDown:(NSEvent *)event { - if ((int)[event buttonNumber] != 2) - return; + if ((int)[event buttonNumber] == 2) { + _mouseDownEvent(event, BUTTON_MIDDLE, BUTTON_MASK_MIDDLE, true); + + } else if ((int)[event buttonNumber] == 3) { + _mouseDownEvent(event, BUTTON_XBUTTON1, BUTTON_MASK_XBUTTON1, true); - _mouseDownEvent(event, BUTTON_MIDDLE, BUTTON_MASK_MIDDLE, true); + } else if ((int)[event buttonNumber] == 4) { + _mouseDownEvent(event, BUTTON_XBUTTON2, BUTTON_MASK_XBUTTON2, true); + + } else { + return; + } } - (void)otherMouseDragged:(NSEvent *)event { @@ -637,10 +645,18 @@ static void _mouseDownEvent(NSEvent *event, int index, int mask, bool pressed) { - (void)otherMouseUp:(NSEvent *)event { - if ((int)[event buttonNumber] != 2) - return; + if ((int)[event buttonNumber] == 2) { + _mouseDownEvent(event, BUTTON_MIDDLE, BUTTON_MASK_MIDDLE, false); + + } else if ((int)[event buttonNumber] == 3) { + _mouseDownEvent(event, BUTTON_XBUTTON1, BUTTON_MASK_XBUTTON1, false); - _mouseDownEvent(event, BUTTON_MIDDLE, BUTTON_MASK_MIDDLE, false); + } else if ((int)[event buttonNumber] == 4) { + _mouseDownEvent(event, BUTTON_XBUTTON2, BUTTON_MASK_XBUTTON2, false); + + } else { + return; + } } - (void)mouseExited:(NSEvent *)event { @@ -1160,6 +1176,10 @@ static void displays_arrangement_changed(CGDirectDisplayID display_id, CGDisplay displays_arrangement_dirty = true; } +int OS_OSX::get_current_video_driver() const { + return video_driver_index; +} + Error OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) { /*** OSX INITIALIZATION ***/ @@ -1256,6 +1276,8 @@ Error OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_a ADD_ATTR2(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core); } + video_driver_index = p_video_driver; + ADD_ATTR2(NSOpenGLPFAColorSize, colorBits); /* @@ -1329,6 +1351,8 @@ Error OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_a AudioDriverManager::initialize(p_audio_driver); + midi_driver.open(); + input = memnew(InputDefault); joypad_osx = memnew(JoypadOSX); @@ -2381,7 +2405,7 @@ void OS_OSX::process_key_events() { Ref<InputEventKey> k; for (int i = 0; i < key_event_pos; i++) { - KeyEvent &ke = key_event_buffer[i]; + const KeyEvent &ke = key_event_buffer[i]; if ((i == 0 && ke.scancode == 0) || (i > 0 && key_event_buffer[i - 1].scancode == 0)) { k.instance(); diff --git a/platform/osx/platform_osx_builders.py b/platform/osx/platform_osx_builders.py new file mode 100644 index 0000000000..81997f674b --- /dev/null +++ b/platform/osx/platform_osx_builders.py @@ -0,0 +1,21 @@ +"""Functions used to generate source files during build time + +All such functions are invoked in a subprocess on Windows to prevent build flakiness. + +""" +import os +from platform_methods import subprocess_main + + +def make_debug_osx(target, source, env): + if (env["macports_clang"] != 'no'): + mpprefix = os.environ.get("MACPORTS_PREFIX", "/opt/local") + mpclangver = env["macports_clang"] + os.system(mpprefix + '/libexec/llvm-' + mpclangver + '/bin/llvm-dsymutil {0} -o {0}.dSYM'.format(target[0])) + else: + os.system('dsymutil {0} -o {0}.dSYM'.format(target[0])) + os.system('strip -u -r {0}'.format(target[0])) + + +if __name__ == '__main__': + subprocess_main(globals()) diff --git a/platform/server/os_server.cpp b/platform/server/os_server.cpp index 3b1be780d4..1c17780ad7 100644 --- a/platform/server/os_server.cpp +++ b/platform/server/os_server.cpp @@ -28,16 +28,17 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "os_server.h" + #include "drivers/dummy/audio_driver_dummy.h" #include "drivers/dummy/rasterizer_dummy.h" #include "drivers/dummy/texture_loader_dummy.h" #include "print_string.h" #include "servers/visual/visual_server_raster.h" -#include <stdio.h> -#include <stdlib.h> #include "main/main.h" +#include <stdio.h> +#include <stdlib.h> #include <unistd.h> int OS_Server::get_video_driver_count() const { @@ -58,6 +59,10 @@ const char *OS_Server::get_audio_driver_name(int p_driver) const { return "Dummy"; } +int OS_Server::get_current_video_driver() const { + return video_driver_index; +} + void OS_Server::initialize_core() { crash_handler.initialize(); @@ -73,6 +78,8 @@ Error OS_Server::initialize(const VideoMode &p_desired, int p_video_driver, int RasterizerDummy::make_current(); + video_driver_index = p_video_driver; // unused in server platform, but should still be initialized + visual_server = memnew(VisualServerRaster); visual_server->init(); diff --git a/platform/server/os_server.h b/platform/server/os_server.h index f1a880ecc2..07d70e5236 100644 --- a/platform/server/os_server.h +++ b/platform/server/os_server.h @@ -30,12 +30,12 @@ #ifndef OS_SERVER_H #define OS_SERVER_H -#include "../x11/crash_handler_x11.h" -#include "../x11/power_x11.h" #include "drivers/dummy/texture_loader_dummy.h" #include "drivers/rtaudio/audio_driver_rtaudio.h" #include "drivers/unix/os_unix.h" #include "main/input_default.h" +#include "platform/x11/crash_handler_x11.h" +#include "platform/x11/power_x11.h" #include "servers/audio_server.h" #include "servers/visual/rasterizer.h" #include "servers/visual_server.h" @@ -47,7 +47,6 @@ class OS_Server : public OS_Unix { - //Rasterizer *rasterizer; VisualServer *visual_server; VideoMode current_videomode; List<String> args; @@ -66,12 +65,14 @@ class OS_Server : public OS_Unix { CrashHandler crash_handler; + int video_driver_index; + ResourceFormatDummyTexture *resource_loader_dummy; protected: virtual int get_video_driver_count() const; virtual const char *get_video_driver_name(int p_driver) const; - + virtual int get_current_video_driver() const; virtual int get_audio_driver_count() const; virtual const char *get_audio_driver_name(int p_driver) const; diff --git a/platform/uwp/app.cpp b/platform/uwp/app.cpp index c18aa36402..b769925849 100644 --- a/platform/uwp/app.cpp +++ b/platform/uwp/app.cpp @@ -143,14 +143,13 @@ void App::SetWindow(CoreWindow ^ p_window) { window->KeyUp += ref new TypedEventHandler<CoreWindow ^, KeyEventArgs ^>(this, &App::OnKeyUp); + os->set_window(window); + unsigned int argc; char **argv = get_command_line(&argc); Main::setup("uwp", argc, argv, false); - // The CoreWindow has been created, so EGL can be initialized. - ContextEGL *context = memnew(ContextEGL(window)); - os->set_gl_context(context); UpdateWindowSize(Size(window->Bounds.Width, window->Bounds.Height)); Main::setup2(); @@ -513,7 +512,7 @@ char **App::get_command_line(unsigned int *out_argc) { if (f == NULL) { - wprintf(L"Couldn't open command line file."); + wprintf(L"Couldn't open command line file.\n"); return fail_cl; } @@ -527,7 +526,7 @@ char **App::get_command_line(unsigned int *out_argc) { if (r < 4) { fclose(f); - wprintf(L"Wrong cmdline length."); + wprintf(L"Wrong cmdline length.\n"); return (fail_cl); } @@ -539,7 +538,7 @@ char **App::get_command_line(unsigned int *out_argc) { if (r < 4) { fclose(f); - wprintf(L"Wrong cmdline param length."); + wprintf(L"Wrong cmdline param length.\n"); return (fail_cl); } @@ -547,7 +546,7 @@ char **App::get_command_line(unsigned int *out_argc) { if (strlen > CMD_MAX_LEN) { fclose(f); - wprintf(L"Wrong command length."); + wprintf(L"Wrong command length.\n"); return (fail_cl); } @@ -568,7 +567,7 @@ char **App::get_command_line(unsigned int *out_argc) { delete[] arg; fclose(f); - wprintf(L"Error reading command."); + wprintf(L"Error reading command.\n"); return (fail_cl); } } diff --git a/platform/uwp/export/export.cpp b/platform/uwp/export/export.cpp index 35c0b30ce4..ebc2c2d7a2 100644 --- a/platform/uwp/export/export.cpp +++ b/platform/uwp/export/export.cpp @@ -301,37 +301,37 @@ Vector<uint8_t> AppxPackager::make_file_header(FileMeta p_file_meta) { int offs = 0; // Write magic - offs += buf_put_int32(FILE_HEADER_MAGIC, &buf[offs]); + offs += buf_put_int32(FILE_HEADER_MAGIC, &buf.write[offs]); // Version - offs += buf_put_int16(ZIP_VERSION, &buf[offs]); + offs += buf_put_int16(ZIP_VERSION, &buf.write[offs]); // Special flag - offs += buf_put_int16(GENERAL_PURPOSE, &buf[offs]); + offs += buf_put_int16(GENERAL_PURPOSE, &buf.write[offs]); // Compression - offs += buf_put_int16(p_file_meta.compressed ? Z_DEFLATED : 0, &buf[offs]); + offs += buf_put_int16(p_file_meta.compressed ? Z_DEFLATED : 0, &buf.write[offs]); // File date and time - offs += buf_put_int32(0, &buf[offs]); + offs += buf_put_int32(0, &buf.write[offs]); // CRC-32 - offs += buf_put_int32(p_file_meta.file_crc32, &buf[offs]); + offs += buf_put_int32(p_file_meta.file_crc32, &buf.write[offs]); // Compressed size - offs += buf_put_int32(p_file_meta.compressed_size, &buf[offs]); + offs += buf_put_int32(p_file_meta.compressed_size, &buf.write[offs]); // Uncompressed size - offs += buf_put_int32(p_file_meta.uncompressed_size, &buf[offs]); + offs += buf_put_int32(p_file_meta.uncompressed_size, &buf.write[offs]); // File name length - offs += buf_put_int16(p_file_meta.name.length(), &buf[offs]); + offs += buf_put_int16(p_file_meta.name.length(), &buf.write[offs]); // Extra data length - offs += buf_put_int16(0, &buf[offs]); + offs += buf_put_int16(0, &buf.write[offs]); // File name - offs += buf_put_string(p_file_meta.name, &buf[offs]); + offs += buf_put_string(p_file_meta.name, &buf.write[offs]); // Done! return buf; @@ -344,47 +344,47 @@ void AppxPackager::store_central_dir_header(const FileMeta &p_file, bool p_do_ha buf.resize(buf.size() + BASE_CENTRAL_DIR_SIZE + p_file.name.length()); // Write magic - offs += buf_put_int32(CENTRAL_DIR_MAGIC, &buf[offs]); + offs += buf_put_int32(CENTRAL_DIR_MAGIC, &buf.write[offs]); // ZIP versions - offs += buf_put_int16(ZIP_ARCHIVE_VERSION, &buf[offs]); - offs += buf_put_int16(ZIP_VERSION, &buf[offs]); + offs += buf_put_int16(ZIP_ARCHIVE_VERSION, &buf.write[offs]); + offs += buf_put_int16(ZIP_VERSION, &buf.write[offs]); // General purpose flag - offs += buf_put_int16(GENERAL_PURPOSE, &buf[offs]); + offs += buf_put_int16(GENERAL_PURPOSE, &buf.write[offs]); // Compression - offs += buf_put_int16(p_file.compressed ? Z_DEFLATED : 0, &buf[offs]); + offs += buf_put_int16(p_file.compressed ? Z_DEFLATED : 0, &buf.write[offs]); // Modification date/time - offs += buf_put_int32(0, &buf[offs]); + offs += buf_put_int32(0, &buf.write[offs]); // Crc-32 - offs += buf_put_int32(p_file.file_crc32, &buf[offs]); + offs += buf_put_int32(p_file.file_crc32, &buf.write[offs]); // File sizes - offs += buf_put_int32(p_file.compressed_size, &buf[offs]); - offs += buf_put_int32(p_file.uncompressed_size, &buf[offs]); + offs += buf_put_int32(p_file.compressed_size, &buf.write[offs]); + offs += buf_put_int32(p_file.uncompressed_size, &buf.write[offs]); // File name length - offs += buf_put_int16(p_file.name.length(), &buf[offs]); + offs += buf_put_int16(p_file.name.length(), &buf.write[offs]); // Extra field length - offs += buf_put_int16(0, &buf[offs]); + offs += buf_put_int16(0, &buf.write[offs]); // Comment length - offs += buf_put_int16(0, &buf[offs]); + offs += buf_put_int16(0, &buf.write[offs]); // Disk number start, internal/external file attributes for (int i = 0; i < 8; i++) { - buf[offs++] = 0; + buf.write[offs++] = 0; } // Relative offset - offs += buf_put_int32(p_file.zip_offset, &buf[offs]); + offs += buf_put_int32(p_file.zip_offset, &buf.write[offs]); // File name - offs += buf_put_string(p_file.name, &buf[offs]); + offs += buf_put_string(p_file.name, &buf.write[offs]); // Done! } @@ -397,62 +397,62 @@ Vector<uint8_t> AppxPackager::make_end_of_central_record() { int offs = 0; // Write magic - offs += buf_put_int32(ZIP64_END_OF_CENTRAL_DIR_MAGIC, &buf[offs]); + offs += buf_put_int32(ZIP64_END_OF_CENTRAL_DIR_MAGIC, &buf.write[offs]); // Size of this record - offs += buf_put_int64(ZIP64_END_OF_CENTRAL_DIR_SIZE, &buf[offs]); + offs += buf_put_int64(ZIP64_END_OF_CENTRAL_DIR_SIZE, &buf.write[offs]); // Version (yes, twice) - offs += buf_put_int16(ZIP_ARCHIVE_VERSION, &buf[offs]); - offs += buf_put_int16(ZIP_ARCHIVE_VERSION, &buf[offs]); + offs += buf_put_int16(ZIP_ARCHIVE_VERSION, &buf.write[offs]); + offs += buf_put_int16(ZIP_ARCHIVE_VERSION, &buf.write[offs]); // Disk number for (int i = 0; i < 8; i++) { - buf[offs++] = 0; + buf.write[offs++] = 0; } // Number of entries (total and per disk) - offs += buf_put_int64(file_metadata.size(), &buf[offs]); - offs += buf_put_int64(file_metadata.size(), &buf[offs]); + offs += buf_put_int64(file_metadata.size(), &buf.write[offs]); + offs += buf_put_int64(file_metadata.size(), &buf.write[offs]); // Size of central dir - offs += buf_put_int64(central_dir_data.size(), &buf[offs]); + offs += buf_put_int64(central_dir_data.size(), &buf.write[offs]); // Central dir offset - offs += buf_put_int64(central_dir_offset, &buf[offs]); + offs += buf_put_int64(central_dir_offset, &buf.write[offs]); ////// ZIP64 locator // Write magic for zip64 central dir locator - offs += buf_put_int32(ZIP64_END_DIR_LOCATOR_MAGIC, &buf[offs]); + offs += buf_put_int32(ZIP64_END_DIR_LOCATOR_MAGIC, &buf.write[offs]); // Disk number for (int i = 0; i < 4; i++) { - buf[offs++] = 0; + buf.write[offs++] = 0; } // Relative offset - offs += buf_put_int64(end_of_central_dir_offset, &buf[offs]); + offs += buf_put_int64(end_of_central_dir_offset, &buf.write[offs]); // Number of disks - offs += buf_put_int32(1, &buf[offs]); + offs += buf_put_int32(1, &buf.write[offs]); /////// End of zip directory // Write magic for end central dir - offs += buf_put_int32(END_OF_CENTRAL_DIR_MAGIC, &buf[offs]); + offs += buf_put_int32(END_OF_CENTRAL_DIR_MAGIC, &buf.write[offs]); // Dummy stuff for Zip64 for (int i = 0; i < 4; i++) { - buf[offs++] = 0x0; + buf.write[offs++] = 0x0; } for (int i = 0; i < 12; i++) { - buf[offs++] = 0xFF; + buf.write[offs++] = 0xFF; } // Size of comments for (int i = 0; i < 2; i++) { - buf[offs++] = 0; + buf.write[offs++] = 0; } // Done! @@ -508,7 +508,7 @@ void AppxPackager::add_file(String p_file_name, const uint8_t *p_buffer, size_t size_t block_size = (p_len - step) > BLOCK_SIZE ? BLOCK_SIZE : (p_len - step); for (uint32_t i = 0; i < block_size; i++) { - strm_in[i] = p_buffer[step + i]; + strm_in.write[i] = p_buffer[step + i]; } BlockHash bh; @@ -530,14 +530,14 @@ void AppxPackager::add_file(String p_file_name, const uint8_t *p_buffer, size_t int start = file_buffer.size(); file_buffer.resize(file_buffer.size() + bh.compressed_size); for (uint32_t i = 0; i < bh.compressed_size; i++) - file_buffer[start + i] = strm_out[i]; + file_buffer.write[start + i] = strm_out[i]; } else { bh.compressed_size = block_size; //package->store_buffer(strm_in.ptr(), block_size); int start = file_buffer.size(); file_buffer.resize(file_buffer.size() + block_size); for (uint32_t i = 0; i < bh.compressed_size; i++) - file_buffer[start + i] = strm_in[i]; + file_buffer.write[start + i] = strm_in[i]; } meta.hashes.push_back(bh); @@ -560,7 +560,7 @@ void AppxPackager::add_file(String p_file_name, const uint8_t *p_buffer, size_t int start = file_buffer.size(); file_buffer.resize(file_buffer.size() + (strm.total_out - total_out_before)); for (uint32_t i = 0; i < (strm.total_out - total_out_before); i++) - file_buffer[start + i] = strm_out[i]; + file_buffer.write[start + i] = strm_out[i]; deflateEnd(&strm); meta.compressed_size = strm.total_out; @@ -864,7 +864,7 @@ class EditorExportUWP : public EditorExportPlatform { r_ret.resize(result.length()); for (int i = 0; i < result.length(); i++) - r_ret[i] = result.utf8().get(i); + r_ret.write[i] = result.utf8().get(i); return r_ret; } @@ -1371,8 +1371,8 @@ public: CharString txt = cl[i].utf8(); int base = clf.size(); clf.resize(base + 4 + txt.length()); - encode_uint32(txt.length(), &clf[base]); - copymem(&clf[base + 4], txt.ptr(), txt.length()); + encode_uint32(txt.length(), &clf.write[base]); + copymem(&clf.write[base + 4], txt.ptr(), txt.length()); print_line(itos(i) + " param: " + cl[i]); } diff --git a/platform/uwp/gl_context_egl.cpp b/platform/uwp/gl_context_egl.cpp index 88c9c8d687..6c60b27f5a 100644 --- a/platform/uwp/gl_context_egl.cpp +++ b/platform/uwp/gl_context_egl.cpp @@ -93,12 +93,26 @@ Error ContextEGL::initialize() { EGLint numConfigs = 0; EGLint majorVersion = 1; - EGLint minorVersion = 0; + EGLint minorVersion; + if (driver == GLES_2_0) { + minorVersion = 0; + } else { + minorVersion = 5; + } EGLDisplay display = EGL_NO_DISPLAY; EGLContext context = EGL_NO_CONTEXT; EGLSurface surface = EGL_NO_SURFACE; EGLConfig config = nullptr; - EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE, EGL_NONE }; + EGLint contextAttribs[3]; + if (driver == GLES_2_0) { + contextAttribs[0] = EGL_CONTEXT_CLIENT_VERSION; + contextAttribs[1] = 2; + contextAttribs[2] = EGL_NONE; + } else { + contextAttribs[0] = EGL_CONTEXT_CLIENT_VERSION; + contextAttribs[1] = 3; + contextAttribs[2] = EGL_NONE; + } try { @@ -114,7 +128,8 @@ Error ContextEGL::initialize() { // EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER is an optimization that can have large performance benefits on mobile devices. // Its syntax is subject to change, though. Please update your Visual Studio templates if you experience compilation issues with it. - //EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER, EGL_TRUE, + EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER, + EGL_TRUE, // EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE is an option that enables ANGLE to automatically call // the IDXGIDevice3::Trim method on behalf of the application when it gets suspended. @@ -193,13 +208,12 @@ void ContextEGL::cleanup() { } }; -ContextEGL::ContextEGL(CoreWindow ^ p_window) : +ContextEGL::ContextEGL(CoreWindow ^ p_window, Driver p_driver) : mEglDisplay(EGL_NO_DISPLAY), mEglContext(EGL_NO_CONTEXT), - mEglSurface(EGL_NO_SURFACE) { - - window = p_window; -}; + mEglSurface(EGL_NO_SURFACE), + driver(p_driver), + window(p_window) {} ContextEGL::~ContextEGL() { diff --git a/platform/uwp/gl_context_egl.h b/platform/uwp/gl_context_egl.h index 527baf1054..df0108c124 100644 --- a/platform/uwp/gl_context_egl.h +++ b/platform/uwp/gl_context_egl.h @@ -42,6 +42,13 @@ using namespace Windows::UI::Core; class ContextEGL : public ContextGL { +public: + enum Driver { + GLES_2_0, + GLES_3_0, + }; + +private: CoreWindow ^ window; EGLDisplay mEglDisplay; @@ -53,6 +60,8 @@ class ContextEGL : public ContextGL { bool vsync; + Driver driver; + public: virtual void release_current(); @@ -70,7 +79,7 @@ public: void cleanup(); - ContextEGL(CoreWindow ^ p_window); + ContextEGL(CoreWindow ^ p_window, Driver p_driver); ~ContextEGL(); }; diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp index d00da3dbcd..8549a44ce5 100644 --- a/platform/uwp/os_uwp.cpp +++ b/platform/uwp/os_uwp.cpp @@ -30,6 +30,7 @@ #include "os_uwp.h" +#include "drivers/gles2/rasterizer_gles2.h" #include "drivers/gles3/rasterizer_gles3.h" #include "drivers/unix/ip_unix.h" #include "drivers/windows/dir_access_windows.h" @@ -66,12 +67,7 @@ using namespace Windows::ApplicationModel::DataTransfer; using namespace concurrency; int OSUWP::get_video_driver_count() const { - - return 1; -} -const char *OSUWP::get_video_driver_name(int p_driver) const { - - return "GLES3"; + return 2; } Size2 OSUWP::get_window_size() const { @@ -81,6 +77,10 @@ Size2 OSUWP::get_window_size() const { return size; } +int OSUWP::get_current_video_driver() const { + return video_driver_index; +} + void OSUWP::set_window_size(const Size2 p_size) { Windows::Foundation::Size new_size; @@ -133,18 +133,6 @@ void OSUWP::set_keep_screen_on(bool p_enabled) { OS::set_keep_screen_on(p_enabled); } -int OSUWP::get_audio_driver_count() const { - - return AudioDriverManager::get_driver_count(); -} - -const char *OSUWP::get_audio_driver_name(int p_driver) const { - - AudioDriver *driver = AudioDriverManager::get_driver(p_driver); - ERR_FAIL_COND_V(!driver, ""); - return AudioDriverManager::get_driver(p_driver)->get_name(); -} - void OSUWP::initialize_core() { last_button_state = 0; @@ -185,10 +173,9 @@ bool OSUWP::can_draw() const { return !minimized; }; -void OSUWP::set_gl_context(ContextEGL *p_context) { - - gl_context = p_context; -}; +void OSUWP::set_window(Windows::UI::Core::CoreWindow ^ p_window) { + window = p_window; +} void OSUWP::screen_size_changed() { @@ -200,6 +187,11 @@ Error OSUWP::initialize(const VideoMode &p_desired, int p_video_driver, int p_au main_loop = NULL; outside = true; + if (p_video_driver == VIDEO_DRIVER_GLES2) { + gl_context = memnew(ContextEGL(window, ContextEGL::GLES_2_0)); + } else { + gl_context = memnew(ContextEGL(window, ContextEGL::GLES_3_0)); + } gl_context->initialize(); VideoMode vm; vm.width = gl_context->get_window_width(); @@ -240,10 +232,17 @@ Error OSUWP::initialize(const VideoMode &p_desired, int p_video_driver, int p_au gl_context->make_current(); - RasterizerGLES3::register_config(); - RasterizerGLES3::make_current(); + if (p_video_driver == VIDEO_DRIVER_GLES2) { + RasterizerGLES2::register_config(); + RasterizerGLES2::make_current(); + } else { + RasterizerGLES3::register_config(); + RasterizerGLES3::make_current(); + } gl_context->set_use_vsync(vm.use_vsync); + video_driver_index = p_video_driver; + visual_server = memnew(VisualServerRaster); // FIXME: Reimplement threaded rendering? Or remove? /* @@ -297,7 +296,7 @@ Error OSUWP::initialize(const VideoMode &p_desired, int p_video_driver, int p_au if (is_keep_screen_on()) display_request->RequestActive(); - set_keep_screen_on(GLOBAL_DEF("display/window/keep_screen_on", true)); + set_keep_screen_on(GLOBAL_DEF("display/window/energy_saving/keep_screen_on", true)); return OK; } @@ -392,7 +391,6 @@ void OSUWP::ManagedType::update_clipboard() { if (data->Contains(StandardDataFormats::Text)) { create_task(data->GetTextAsync()).then([this](Platform::String ^ clipboard_content) { - this->clipboard = clipboard_content; }); } diff --git a/platform/uwp/os_uwp.h b/platform/uwp/os_uwp.h index 95afdab469..3b48063fe9 100644 --- a/platform/uwp/os_uwp.h +++ b/platform/uwp/os_uwp.h @@ -96,8 +96,10 @@ private: int pressrc; ContextEGL *gl_context; + Windows::UI::Core::CoreWindow ^ window; VideoMode video_mode; + int video_driver_index; MainLoop *main_loop; @@ -153,10 +155,7 @@ private: // functions used by main to initialize/deintialize the OS protected: virtual int get_video_driver_count() const; - virtual const char *get_video_driver_name(int p_driver) const; - - virtual int get_audio_driver_count() const; - virtual const char *get_audio_driver_name(int p_driver) const; + virtual int get_current_video_driver() const; virtual void initialize_core(); virtual Error initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); @@ -231,7 +230,7 @@ public: virtual bool _check_internal_feature_support(const String &p_feature); - void set_gl_context(ContextEGL *p_context); + void set_window(Windows::UI::Core::CoreWindow ^ p_window); void screen_size_changed(); virtual void release_rendering_thread(); diff --git a/platform/windows/SCsub b/platform/windows/SCsub index ed3827353d..53ed3bf887 100644 --- a/platform/windows/SCsub +++ b/platform/windows/SCsub @@ -3,15 +3,8 @@ import os Import('env') -def make_debug_mingw(target, source, env): - mingw_prefix = "" - if (env["bits"] == "32"): - mingw_prefix = env["mingw_prefix_32"] - else: - mingw_prefix = env["mingw_prefix_64"] - os.system(mingw_prefix + 'objcopy --only-keep-debug {0} {0}.debugsymbols'.format(target[0])) - os.system(mingw_prefix + 'strip --strip-debug --strip-unneeded {0}'.format(target[0])) - os.system(mingw_prefix + 'objcopy --add-gnu-debuglink={0}.debugsymbols {0}'.format(target[0])) +from platform_methods import run_in_subprocess +import platform_windows_builders common_win = [ "context_gl_win.cpp", @@ -40,4 +33,4 @@ if env['vsproj']: if not os.getenv("VCINSTALLDIR"): if (env["debug_symbols"] == "full" or env["debug_symbols"] == "yes") and env["separate_debug_symbols"]: - env.AddPostAction(prog, make_debug_mingw) + env.AddPostAction(prog, run_in_subprocess(platform_windows_builders.make_debug_mingw)) diff --git a/platform/windows/context_gl_win.cpp b/platform/windows/context_gl_win.cpp index d312fbcb12..a158237418 100644 --- a/platform/windows/context_gl_win.cpp +++ b/platform/windows/context_gl_win.cpp @@ -106,9 +106,9 @@ Error ContextGL_Win::initialize() { PFD_SUPPORT_OPENGL | // Format Must Support OpenGL PFD_DOUBLEBUFFER, PFD_TYPE_RGBA, - 24, + OS::get_singleton()->is_layered_allowed() ? 32 : 24, 0, 0, 0, 0, 0, 0, // Color Bits Ignored - 0, // No Alpha Buffer + OS::get_singleton()->is_layered_allowed() ? 8 : 0, // Alpha Buffer 0, // Shift Bit Ignored 0, // No Accumulation Buffer 0, 0, 0, 0, // Accumulation Bits Ignored diff --git a/platform/windows/detect.py b/platform/windows/detect.py index 05806d2fe8..34fc3e09b5 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -166,12 +166,18 @@ def configure_msvc(env, manual_msvc_config): # Build type if (env["target"] == "release"): - env.Append(CCFLAGS=['/O2']) + if (env["optimize"] == "speed"): #optimize for speed (default) + env.Append(CCFLAGS=['/O2']) + else: # optimize for size + env.Append(CCFLAGS=['/O1']) env.Append(LINKFLAGS=['/SUBSYSTEM:WINDOWS']) env.Append(LINKFLAGS=['/ENTRY:mainCRTStartup']) elif (env["target"] == "release_debug"): - env.Append(CCFLAGS=['/O2']) + if (env["optimize"] == "speed"): #optimize for speed (default) + env.Append(CCFLAGS=['/O2']) + else: # optimize for size + env.Append(CCFLAGS=['/O1']) env.AppendUnique(CPPDEFINES = ['DEBUG_ENABLED']) env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE']) @@ -200,7 +206,8 @@ def configure_msvc(env, manual_msvc_config): env.AppendUnique(CPPDEFINES = ['WINDOWS_ENABLED', 'OPENGL_ENABLED', 'RTAUDIO_ENABLED', 'WASAPI_ENABLED', - 'TYPED_METHOD_BIND', 'WIN32', 'MSVC', + 'WINMIDI_ENABLED', 'TYPED_METHOD_BIND', + 'WIN32', 'MSVC', {'WINVER' : '$target_win_version', '_WIN32_WINNT': '$target_win_version'}]) if env["bits"] == "64": @@ -247,10 +254,14 @@ def configure_mingw(env): if (env["target"] == "release"): env.Append(CCFLAGS=['-msse2']) - if (env["bits"] == "64"): - env.Append(CCFLAGS=['-O3']) - else: - env.Append(CCFLAGS=['-O2']) + if (env["optimize"] == "speed"): #optimize for speed (default) + if (env["bits"] == "64"): + env.Append(CCFLAGS=['-O3']) + else: + env.Append(CCFLAGS=['-O2']) + else: #optimize for size + env.Prepend(CCFLAGS=['-Os']) + env.Append(LINKFLAGS=['-Wl,--subsystem,windows']) @@ -265,7 +276,11 @@ def configure_mingw(env): env.Prepend(CCFLAGS=['-g1']) if (env["debug_symbols"] == "full"): env.Prepend(CCFLAGS=['-g2']) - + if (env["optimize"] == "speed"): #optimize for speed (default) + env.Append(CCFLAGS=['-O2']) + else: #optimize for size + env.Prepend(CCFLAGS=['-Os']) + elif (env["target"] == "debug"): env.Append(CCFLAGS=['-g3', '-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED']) diff --git a/platform/windows/godot_win.cpp b/platform/windows/godot_win.cpp index 80f53dd1a1..504a9a0380 100644 --- a/platform/windows/godot_win.cpp +++ b/platform/windows/godot_win.cpp @@ -176,8 +176,8 @@ int _main() { } int main(int _argc, char **_argv) { -// _argc and _argv are ignored -// we are going to use the WideChar version of them instead + // _argc and _argv are ignored + // we are going to use the WideChar version of them instead #ifdef CRASH_HANDLER_EXCEPTION __try { diff --git a/platform/windows/lang_table.h b/platform/windows/lang_table.h index 1a966b502a..78bfadfeae 100644 --- a/platform/windows/lang_table.h +++ b/platform/windows/lang_table.h @@ -186,6 +186,7 @@ static const _WinLocale _win_locales[] = { { "zh_CN", LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED }, { "zh_HK", LANG_CHINESE, SUBLANG_CHINESE_HONGKONG }, { "zh_SG", LANG_CHINESE, SUBLANG_CHINESE_SINGAPORE }, + { "zh_TW", LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL }, { 0, 0, 0 }, }; diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 216be1064a..bd76db8796 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -434,11 +434,12 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) bmask |= (wParam & MK_LBUTTON) ? (1 << 0) : 0; bmask |= (wParam & MK_RBUTTON) ? (1 << 1) : 0; bmask |= (wParam & MK_MBUTTON) ? (1 << 2) : 0; + bmask |= (wParam & MK_XBUTTON1) ? (1 << 7) : 0; + bmask |= (wParam & MK_XBUTTON2) ? (1 << 8) : 0; mm->set_button_mask(bmask); last_button_state = mm->get_button_mask(); - /*mm->get_button_mask()|=(wParam&MK_XBUTTON1)?(1<<5):0; - mm->get_button_mask()|=(wParam&MK_XBUTTON2)?(1<<6):0;*/ + mm->set_position(Vector2(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); mm->set_global_position(Vector2(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); @@ -495,153 +496,168 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) case WM_LBUTTONDBLCLK: case WM_MBUTTONDBLCLK: case WM_RBUTTONDBLCLK: - /*case WM_XBUTTONDOWN: - case WM_XBUTTONUP: */ { - - Ref<InputEventMouseButton> mb; - mb.instance(); - - switch (uMsg) { - case WM_LBUTTONDOWN: { - mb->set_pressed(true); - mb->set_button_index(1); - } break; - case WM_LBUTTONUP: { - mb->set_pressed(false); - mb->set_button_index(1); - } break; - case WM_MBUTTONDOWN: { - mb->set_pressed(true); - mb->set_button_index(3); - - } break; - case WM_MBUTTONUP: { - mb->set_pressed(false); - mb->set_button_index(3); - } break; - case WM_RBUTTONDOWN: { - mb->set_pressed(true); - mb->set_button_index(2); - } break; - case WM_RBUTTONUP: { - mb->set_pressed(false); - mb->set_button_index(2); - } break; - case WM_LBUTTONDBLCLK: { - - mb->set_pressed(true); - mb->set_button_index(1); - mb->set_doubleclick(true); - } break; - case WM_RBUTTONDBLCLK: { - - mb->set_pressed(true); - mb->set_button_index(2); - mb->set_doubleclick(true); - } break; - case WM_MBUTTONDBLCLK: { - - mb->set_pressed(true); - mb->set_button_index(3); - mb->set_doubleclick(true); - } break; - case WM_MOUSEWHEEL: { - - mb->set_pressed(true); - int motion = (short)HIWORD(wParam); - if (!motion) - return 0; - - if (motion > 0) - mb->set_button_index(BUTTON_WHEEL_UP); - else - mb->set_button_index(BUTTON_WHEEL_DOWN); - - } break; - case WM_MOUSEHWHEEL: { - - mb->set_pressed(true); - int motion = (short)HIWORD(wParam); - if (!motion) - return 0; - - if (motion < 0) { - mb->set_button_index(BUTTON_WHEEL_LEFT); - mb->set_factor(fabs((double)motion / (double)WHEEL_DELTA)); - } else { - mb->set_button_index(BUTTON_WHEEL_RIGHT); - mb->set_factor(fabs((double)motion / (double)WHEEL_DELTA)); - } - } break; - /* - case WM_XBUTTONDOWN: { - mb->is_pressed()=true; - mb->get_button_index()=(HIWORD(wParam)==XBUTTON1)?6:7; + case WM_XBUTTONDBLCLK: + case WM_XBUTTONDOWN: + case WM_XBUTTONUP: { + + Ref<InputEventMouseButton> mb; + mb.instance(); + + switch (uMsg) { + case WM_LBUTTONDOWN: { + mb->set_pressed(true); + mb->set_button_index(1); } break; - case WM_XBUTTONUP: - mb->is_pressed()=true; - mb->get_button_index()=(HIWORD(wParam)==XBUTTON1)?6:7; - } break;*/ - default: { return 0; } - } + case WM_LBUTTONUP: { + mb->set_pressed(false); + mb->set_button_index(1); + } break; + case WM_MBUTTONDOWN: { + mb->set_pressed(true); + mb->set_button_index(3); - mb->set_control((wParam & MK_CONTROL) != 0); - mb->set_shift((wParam & MK_SHIFT) != 0); - mb->set_alt(alt_mem); - //mb->get_alt()=(wParam&MK_MENU)!=0; - int bmask = 0; - bmask |= (wParam & MK_LBUTTON) ? (1 << 0) : 0; - bmask |= (wParam & MK_RBUTTON) ? (1 << 1) : 0; - bmask |= (wParam & MK_MBUTTON) ? (1 << 2) : 0; - mb->set_button_mask(bmask); - - last_button_state = mb->get_button_mask(); - /* - mb->get_button_mask()|=(wParam&MK_XBUTTON1)?(1<<5):0; - mb->get_button_mask()|=(wParam&MK_XBUTTON2)?(1<<6):0;*/ - mb->set_position(Vector2(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); - - if (mouse_mode == MOUSE_MODE_CAPTURED) { - - mb->set_position(Vector2(old_x, old_y)); - } + } break; + case WM_MBUTTONUP: { + mb->set_pressed(false); + mb->set_button_index(3); + } break; + case WM_RBUTTONDOWN: { + mb->set_pressed(true); + mb->set_button_index(2); + } break; + case WM_RBUTTONUP: { + mb->set_pressed(false); + mb->set_button_index(2); + } break; + case WM_LBUTTONDBLCLK: { + + mb->set_pressed(true); + mb->set_button_index(1); + mb->set_doubleclick(true); + } break; + case WM_RBUTTONDBLCLK: { - if (uMsg != WM_MOUSEWHEEL && uMsg != WM_MOUSEHWHEEL) { - if (mb->is_pressed()) { + mb->set_pressed(true); + mb->set_button_index(2); + mb->set_doubleclick(true); + } break; + case WM_MBUTTONDBLCLK: { - if (++pressrc > 0) - SetCapture(hWnd); - } else { + mb->set_pressed(true); + mb->set_button_index(3); + mb->set_doubleclick(true); + } break; + case WM_MOUSEWHEEL: { - if (--pressrc <= 0) { - ReleaseCapture(); - pressrc = 0; - } + mb->set_pressed(true); + int motion = (short)HIWORD(wParam); + if (!motion) + return 0; + + if (motion > 0) + mb->set_button_index(BUTTON_WHEEL_UP); + else + mb->set_button_index(BUTTON_WHEEL_DOWN); + + } break; + case WM_MOUSEHWHEEL: { + + mb->set_pressed(true); + int motion = (short)HIWORD(wParam); + if (!motion) + return 0; + + if (motion < 0) { + mb->set_button_index(BUTTON_WHEEL_LEFT); + mb->set_factor(fabs((double)motion / (double)WHEEL_DELTA)); + } else { + mb->set_button_index(BUTTON_WHEEL_RIGHT); + mb->set_factor(fabs((double)motion / (double)WHEEL_DELTA)); } - } else if (mouse_mode != MOUSE_MODE_CAPTURED) { - // for reasons unknown to mankind, wheel comes in screen cordinates - POINT coords; - coords.x = mb->get_position().x; - coords.y = mb->get_position().y; + } break; + case WM_XBUTTONDOWN: { - ScreenToClient(hWnd, &coords); + mb->set_pressed(true); + if (HIWORD(wParam) == XBUTTON1) + mb->set_button_index(BUTTON_XBUTTON1); + else + mb->set_button_index(BUTTON_XBUTTON2); + } break; + case WM_XBUTTONUP: { - mb->set_position(Vector2(coords.x, coords.y)); - } + mb->set_pressed(false); + if (HIWORD(wParam) == XBUTTON1) + mb->set_button_index(BUTTON_XBUTTON1); + else + mb->set_button_index(BUTTON_XBUTTON2); + } break; + case WM_XBUTTONDBLCLK: { - mb->set_global_position(mb->get_position()); + mb->set_pressed(true); + if (HIWORD(wParam) == XBUTTON1) + mb->set_button_index(BUTTON_XBUTTON1); + else + mb->set_button_index(BUTTON_XBUTTON2); + mb->set_doubleclick(true); + } break; + default: { return 0; } + } + + mb->set_control((wParam & MK_CONTROL) != 0); + mb->set_shift((wParam & MK_SHIFT) != 0); + mb->set_alt(alt_mem); + //mb->get_alt()=(wParam&MK_MENU)!=0; + int bmask = 0; + bmask |= (wParam & MK_LBUTTON) ? (1 << 0) : 0; + bmask |= (wParam & MK_RBUTTON) ? (1 << 1) : 0; + bmask |= (wParam & MK_MBUTTON) ? (1 << 2) : 0; + bmask |= (wParam & MK_XBUTTON1) ? (1 << 7) : 0; + bmask |= (wParam & MK_XBUTTON2) ? (1 << 8) : 0; + mb->set_button_mask(bmask); + + last_button_state = mb->get_button_mask(); + mb->set_position(Vector2(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); + + if (mouse_mode == MOUSE_MODE_CAPTURED) { + + mb->set_position(Vector2(old_x, old_y)); + } + + if (uMsg != WM_MOUSEWHEEL && uMsg != WM_MOUSEHWHEEL) { + if (mb->is_pressed()) { + + if (++pressrc > 0) + SetCapture(hWnd); + } else { - if (main_loop) { - input->parse_input_event(mb); - if (mb->is_pressed() && mb->get_button_index() > 3) { - //send release for mouse wheel - Ref<InputEventMouseButton> mbd = mb->duplicate(); - mbd->set_pressed(false); - input->parse_input_event(mbd); + if (--pressrc <= 0) { + ReleaseCapture(); + pressrc = 0; } } + } else if (mouse_mode != MOUSE_MODE_CAPTURED) { + // for reasons unknown to mankind, wheel comes in screen cordinates + POINT coords; + coords.x = mb->get_position().x; + coords.y = mb->get_position().y; + + ScreenToClient(hWnd, &coords); + + mb->set_position(Vector2(coords.x, coords.y)); } - break; + + mb->set_global_position(mb->get_position()); + + if (main_loop) { + input->parse_input_event(mb); + if (mb->is_pressed() && mb->get_button_index() > 3 && mb->get_button_index() < 8) { + //send release for mouse wheel + Ref<InputEventMouseButton> mbd = mb->duplicate(); + mbd->set_pressed(false); + input->parse_input_event(mbd); + } + } + } break; case WM_SIZE: { int window_w = LOWORD(lParam); @@ -996,6 +1012,10 @@ typedef enum _SHC_PROCESS_DPI_AWARENESS { SHC_PROCESS_PER_MONITOR_DPI_AWARE = 2 } SHC_PROCESS_DPI_AWARENESS; +int OS_Windows::get_current_video_driver() const { + return video_driver_index; +} + Error OS_Windows::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) { main_loop = NULL; @@ -1165,6 +1185,8 @@ Error OS_Windows::initialize(const VideoMode &p_desired, int p_video_driver, int RasterizerGLES3::make_current(); } + video_driver_index = p_video_driver; // FIXME TODO - FIX IF DRIVER DETECTION HAPPENS AND GLES2 MUST BE USED + gl_context->set_use_vsync(video_mode.use_vsync); #endif @@ -1197,6 +1219,10 @@ Error OS_Windows::initialize(const VideoMode &p_desired, int p_video_driver, int AudioDriverManager::initialize(p_audio_driver); +#ifdef WINMIDI_ENABLED + driver_midi.open(); +#endif + TRACKMOUSEEVENT tme; tme.cbSize = sizeof(TRACKMOUSEEVENT); tme.dwFlags = TME_LEAVE; @@ -1325,6 +1351,10 @@ void OS_Windows::set_main_loop(MainLoop *p_main_loop) { void OS_Windows::finalize() { +#ifdef WINMIDI_ENABLED + driver_midi.close(); +#endif + if (main_loop) memdelete(main_loop); @@ -2269,7 +2299,7 @@ Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments, Vector<CharType> modstr; //windows wants to change this no idea why modstr.resize(cmdline.size()); for (int i = 0; i < cmdline.size(); i++) - modstr[i] = cmdline[i]; + modstr.write[i] = cmdline[i]; int ret = CreateProcessW(NULL, modstr.ptrw(), NULL, NULL, 0, NORMAL_PRIORITY_CLASS, NULL, NULL, si_w, &pi.pi); ERR_FAIL_COND_V(ret == 0, ERR_CANT_FORK); @@ -2340,7 +2370,7 @@ void OS_Windows::set_icon(const Ref<Image> &p_icon) { int icon_len = 40 + h * w * 4; Vector<BYTE> v; v.resize(icon_len); - BYTE *icon_bmp = &v[0]; + BYTE *icon_bmp = v.ptrw(); encode_uint32(40, &icon_bmp[0]); encode_uint32(w, &icon_bmp[4]); diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index 19af63bae0..69c7d851b8 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -35,6 +35,7 @@ #include "crash_handler_win.h" #include "drivers/rtaudio/audio_driver_rtaudio.h" #include "drivers/wasapi/audio_driver_wasapi.h" +#include "drivers/winmidi/win_midi.h" #include "os/input.h" #include "os/os.h" #include "power_windows.h" @@ -134,6 +135,7 @@ class OS_Windows : public OS { PowerWindows *power_manager; + int video_driver_index; #ifdef WASAPI_ENABLED AudioDriverWASAPI driver_wasapi; #endif @@ -143,6 +145,9 @@ class OS_Windows : public OS { #ifdef XAUDIO2_ENABLED AudioDriverXAudio2 driver_xaudio2; #endif +#ifdef WINMIDI_ENABLED + MIDIDriverWinMidi driver_midi; +#endif CrashHandler crash_handler; @@ -153,6 +158,8 @@ class OS_Windows : public OS { // functions used by main to initialize/deintialize the OS protected: + virtual int get_current_video_driver() const; + virtual void initialize_core(); virtual Error initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); diff --git a/platform/windows/platform_windows_builders.py b/platform/windows/platform_windows_builders.py new file mode 100644 index 0000000000..a1ad3b8b50 --- /dev/null +++ b/platform/windows/platform_windows_builders.py @@ -0,0 +1,22 @@ +"""Functions used to generate source files during build time + +All such functions are invoked in a subprocess on Windows to prevent build flakiness. + +""" +import os +from platform_methods import subprocess_main + + +def make_debug_mingw(target, source, env): + mingw_prefix = "" + if (env["bits"] == "32"): + mingw_prefix = env["mingw_prefix_32"] + else: + mingw_prefix = env["mingw_prefix_64"] + os.system(mingw_prefix + 'objcopy --only-keep-debug {0} {0}.debugsymbols'.format(target[0])) + os.system(mingw_prefix + 'strip --strip-debug --strip-unneeded {0}'.format(target[0])) + os.system(mingw_prefix + 'objcopy --add-gnu-debuglink={0}.debugsymbols {0}'.format(target[0])) + + +if __name__ == '__main__': + subprocess_main(globals()) diff --git a/platform/x11/SCsub b/platform/x11/SCsub index d0f77892ef..d3901eb798 100644 --- a/platform/x11/SCsub +++ b/platform/x11/SCsub @@ -3,10 +3,8 @@ import os Import('env') -def make_debug(target, source, env): - os.system('objcopy --only-keep-debug {0} {0}.debugsymbols'.format(target[0])) - os.system('strip --strip-debug --strip-unneeded {0}'.format(target[0])) - os.system('objcopy --add-gnu-debuglink={0}.debugsymbols {0}'.format(target[0])) +from platform_methods import run_in_subprocess +import platform_x11_builders common_x11 = [ "context_gl_x11.cpp", @@ -20,4 +18,4 @@ common_x11 = [ prog = env.add_program('#bin/godot', ['godot_x11.cpp'] + common_x11) if (env["debug_symbols"] == "full" or env["debug_symbols"] == "yes") and env["separate_debug_symbols"]: - env.AddPostAction(prog, make_debug) + env.AddPostAction(prog, run_in_subprocess(platform_x11_builders.make_debug_x11)) diff --git a/platform/x11/detect.py b/platform/x11/detect.py index 09e16ad078..6a7a426804 100644 --- a/platform/x11/detect.py +++ b/platform/x11/detect.py @@ -62,6 +62,7 @@ def get_opts(): EnumVariable('debug_symbols', 'Add debugging symbols to release builds', 'yes', ('yes', 'no', 'full')), BoolVariable('separate_debug_symbols', 'Create a separate file containing debugging symbols', False), BoolVariable('touch', 'Enable touch events', True), + BoolVariable('execinfo', 'Use libexecinfo on systems where glibc is not available', False), ] @@ -81,14 +82,22 @@ def configure(env): if (env["target"] == "release"): # -O3 -ffast-math is identical to -Ofast. We need to split it out so we can selectively disable # -ffast-math in code for which it generates wrong results. - env.Prepend(CCFLAGS=['-O3', '-ffast-math']) + if (env["optimize"] == "speed"): #optimize for speed (default) + env.Prepend(CCFLAGS=['-O3', '-ffast-math']) + else: #optimize for size + env.Prepend(CCFLAGS=['-Os']) + if (env["debug_symbols"] == "yes"): env.Prepend(CCFLAGS=['-g1']) if (env["debug_symbols"] == "full"): env.Prepend(CCFLAGS=['-g2']) elif (env["target"] == "release_debug"): - env.Prepend(CCFLAGS=['-O2', '-ffast-math', '-DDEBUG_ENABLED']) + if (env["optimize"] == "speed"): #optimize for speed (default) + env.Prepend(CCFLAGS=['-O2', '-ffast-math', '-DDEBUG_ENABLED']) + else: #optimize for size + env.Prepend(CCFLAGS=['-Os', '-DDEBUG_ENABLED']) + if (env["debug_symbols"] == "yes"): env.Prepend(CCFLAGS=['-g1']) if (env["debug_symbols"] == "full"): @@ -240,7 +249,7 @@ def configure(env): if (os.system("pkg-config --exists alsa") == 0): # 0 means found print("Enabling ALSA") - env.Append(CPPFLAGS=["-DALSA_ENABLED"]) + env.Append(CPPFLAGS=["-DALSA_ENABLED", "-DALSAMIDI_ENABLED"]) env.ParseConfig('pkg-config alsa --cflags --libs') else: print("ALSA libraries not found, disabling driver") @@ -276,6 +285,9 @@ def configure(env): env.Append(LIBS=['dl']) if (platform.system().find("BSD") >= 0): + env["execinfo"] = True + + if env["execinfo"]: env.Append(LIBS=['execinfo']) ## Cross-compilation diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp index 2bc85f76c9..9d1e3291b7 100644 --- a/platform/x11/os_x11.cpp +++ b/platform/x11/os_x11.cpp @@ -84,6 +84,10 @@ void OS_X11::initialize_core() { OS_Unix::initialize_core(); } +int OS_X11::get_current_video_driver() const { + return video_driver_index; +} + Error OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) { long im_event_mask = 0; @@ -285,6 +289,8 @@ Error OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_a } break; } + video_driver_index = p_video_driver; // FIXME TODO - FIX IF DRIVER DETECTION HAPPENS AND GLES2 MUST BE USED + context_gl->set_use_vsync(current_videomode.use_vsync); #endif @@ -336,6 +342,10 @@ Error OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_a AudioDriverManager::initialize(p_audio_driver); +#ifdef ALSAMIDI_ENABLED + driver_alsamidi.open(); +#endif + ERR_FAIL_COND_V(!visual_server, ERR_UNAVAILABLE); ERR_FAIL_COND_V(x11_window == 0, ERR_UNAVAILABLE); @@ -600,6 +610,9 @@ void OS_X11::finalize() { memdelete(debugger_connection_console); } */ +#ifdef ALSAMIDI_ENABLED + driver_alsamidi.close(); +#endif #ifdef JOYDEV_ENABLED memdelete(joypad); @@ -1825,8 +1838,8 @@ void OS_X11::process_xevents() { GrabModeAsync, GrabModeAsync, x11_window, None, CurrentTime); } #ifdef TOUCH_ENABLED - // Grab touch devices to avoid OS gesture interference - /*for (int i = 0; i < touch.devices.size(); ++i) { + // Grab touch devices to avoid OS gesture interference + /*for (int i = 0; i < touch.devices.size(); ++i) { XIGrabDevice(x11_display, touch.devices[i], x11_window, CurrentTime, None, XIGrabModeAsync, XIGrabModeAsync, False, &touch.event_mask); }*/ #endif @@ -2092,7 +2105,7 @@ void OS_X11::process_xevents() { Vector<String> files = String((char *)p.data).split("\n", false); for (int i = 0; i < files.size(); i++) { - files[i] = files[i].replace("file://", "").replace("%20", " ").strip_escapes(); + files.write[i] = files[i].replace("file://", "").replace("%20", " ").strip_escapes(); } main_loop->drop_files(files); @@ -2574,12 +2587,12 @@ void OS_X11::set_icon(const Ref<Image> &p_icon) { pd.resize(2 + w * h); - pd[0] = w; - pd[1] = h; + pd.write[0] = w; + pd.write[1] = h; PoolVector<uint8_t>::Read r = img->get_data().read(); - long *wr = &pd[2]; + long *wr = &pd.write[2]; uint8_t const *pr = r.ptr(); for (int i = 0; i < w * h; i++) { diff --git a/platform/x11/os_x11.h b/platform/x11/os_x11.h index 8cab23fe63..44455a2d8d 100644 --- a/platform/x11/os_x11.h +++ b/platform/x11/os_x11.h @@ -38,6 +38,7 @@ #include "servers/visual_server.h" //#include "servers/visual/visual_server_wrap_mt.h" #include "drivers/alsa/audio_driver_alsa.h" +#include "drivers/alsamidi/alsa_midi.h" #include "drivers/pulseaudio/audio_driver_pulseaudio.h" #include "joypad_linux.h" #include "main/input_default.h" @@ -168,6 +169,10 @@ class OS_X11 : public OS_Unix { AudioDriverALSA driver_alsa; #endif +#ifdef ALSAMIDI_ENABLED + MIDIDriverALSAMidi driver_alsamidi; +#endif + #ifdef PULSEAUDIO_ENABLED AudioDriverPulseAudio driver_pulseaudio; #endif @@ -180,6 +185,7 @@ class OS_X11 : public OS_Unix { CrashHandler crash_handler; + int video_driver_index; int audio_driver_index; unsigned int capture_idle; bool maximized; @@ -195,6 +201,8 @@ class OS_X11 : public OS_Unix { Bool xrandr_ext_ok; protected: + virtual int get_current_video_driver() const; + virtual void initialize_core(); virtual Error initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); virtual void finalize(); diff --git a/platform/x11/platform_x11_builders.py b/platform/x11/platform_x11_builders.py new file mode 100644 index 0000000000..5ff0c6fb14 --- /dev/null +++ b/platform/x11/platform_x11_builders.py @@ -0,0 +1,17 @@ +"""Functions used to generate source files during build time + +All such functions are invoked in a subprocess on Windows to prevent build flakiness. + +""" +import os +from platform_methods import subprocess_main + + +def make_debug_x11(target, source, env): + os.system('objcopy --only-keep-debug {0} {0}.debugsymbols'.format(target[0])) + os.system('strip --strip-debug --strip-unneeded {0}'.format(target[0])) + os.system('objcopy --add-gnu-debuglink={0}.debugsymbols {0}'.format(target[0])) + + +if __name__ == '__main__': + subprocess_main(globals()) |