diff options
Diffstat (limited to 'platform')
55 files changed, 1024 insertions, 1489 deletions
diff --git a/platform/android/detect.py b/platform/android/detect.py index 13fc4ee810..966de832e8 100644 --- a/platform/android/detect.py +++ b/platform/android/detect.py @@ -2,6 +2,7 @@ import os import sys import string import platform +from distutils.version import LooseVersion def is_active(): @@ -25,7 +26,7 @@ def get_opts(): ('ndk_platform', 'Target platform (android-<api>, e.g. "android-18")', "android-18"), EnumVariable('android_arch', 'Target architecture', "armv7", ('armv7', 'armv6', 'arm64v8', 'x86')), BoolVariable('android_neon', 'Enable NEON support (armv7 only)', True), - BoolVariable('android_stl', 'Enable Android STL support (for modules)', False), + BoolVariable('android_stl', 'Enable Android STL support (for modules)', True) ] @@ -178,12 +179,24 @@ def configure(env): env['RANLIB'] = tools_path + "/ranlib" env['AS'] = tools_path + "/as" - sysroot = env["ANDROID_NDK_ROOT"] + "/platforms/" + env['ndk_platform'] + "/" + env['ARCH'] common_opts = ['-fno-integrated-as', '-gcc-toolchain', gcc_toolchain_path] + lib_sysroot = env["ANDROID_NDK_ROOT"] + "/platforms/" + env['ndk_platform'] + "/" + env['ARCH'] + ## Compile flags - env.Append(CPPFLAGS=["-isystem", sysroot + "/usr/include"]) + ndk_version = get_ndk_version(env["ANDROID_NDK_ROOT"]) + if ndk_version != None and LooseVersion(ndk_version) >= LooseVersion("15.0.4075724"): + print("Using NDK unified headers") + sysroot = env["ANDROID_NDK_ROOT"] + "/sysroot" + env.Append(CPPFLAGS=["-isystem", sysroot + "/usr/include"]) + env.Append(CPPFLAGS=["-isystem", sysroot + "/usr/include/" + abi_subpath]) + # For unified headers this define has to be set manually + env.Append(CPPFLAGS=["-D__ANDROID_API__=" + str(int(env['ndk_platform'].split("-")[1]))]) + else: + print("Using NDK deprecated headers") + env.Append(CPPFLAGS=["-isystem", lib_sysroot + "/usr/include"]) + env.Append(CPPFLAGS='-fpic -ffunction-sections -funwind-tables -fstack-protector-strong -fvisibility=hidden -fno-strict-aliasing'.split()) env.Append(CPPFLAGS='-DNO_STATVFS -DGLES2_ENABLED'.split()) @@ -224,7 +237,7 @@ def configure(env): ## Link flags - env['LINKFLAGS'] = ['-shared', '--sysroot=' + sysroot, '-Wl,--warn-shared-textrel'] + env['LINKFLAGS'] = ['-shared', '--sysroot=' + lib_sysroot, '-Wl,--warn-shared-textrel'] if env["android_arch"] == "armv7": env.Append(LINKFLAGS='-Wl,--fix-cortex-a8'.split()) env.Append(LINKFLAGS='-Wl,--no-undefined -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now'.split()) @@ -248,3 +261,18 @@ def configure(env): if (env["android_arch"] == "armv6" or env["android_arch"] == "armv7"): env.Append(CFLAGS=["-DOPUS_ARM_OPT"]) env.opus_fixed_point = "yes" + +# Return NDK version string in source.properties (adapted from the Chromium project). +def get_ndk_version(path): + if path == None: + return None + prop_file_path = os.path.join(path, "source.properties") + try: + with open(prop_file_path) as prop_file: + for line in prop_file: + key_value = map(lambda x: string.strip(x), line.split("=")) + if key_value[0] == "Pkg.Revision": + return key_value[1] + except: + print("Could not read source prop file '%s'" % prop_file_path) + return None diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index 9fe1f291d6..79be1501a7 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -267,7 +267,6 @@ class EditorExportAndroid : public EditorExportPlatform { if (different) { - print_line("DIFFERENT!"); Vector<Device> ndevices; for (int i = 0; i < ldevices.size(); i++) { diff --git a/platform/android/godot_android.cpp b/platform/android/godot_android.cpp index 8235683496..abe5e3b77a 100644 --- a/platform/android/godot_android.cpp +++ b/platform/android/godot_android.cpp @@ -669,6 +669,14 @@ static void engine_handle_cmd(struct android_app *app, int32_t cmd) { ASensorEventQueue_setEventRate(engine->sensorEventQueue, engine->accelerometerSensor, (1000L / 60) * 1000); } + // start monitoring gravity + if (engine->gravitySensor != NULL) { + ASensorEventQueue_enableSensor(engine->sensorEventQueue, + engine->gravitySensor); + // We'd like to get 60 events per second (in us). + ASensorEventQueue_setEventRate(engine->sensorEventQueue, + engine->gravitySensor, (1000L / 60) * 1000); + } // Also start monitoring the magnetometer. if (engine->magnetometerSensor != NULL) { ASensorEventQueue_enableSensor(engine->sensorEventQueue, @@ -694,6 +702,10 @@ static void engine_handle_cmd(struct android_app *app, int32_t cmd) { ASensorEventQueue_disableSensor(engine->sensorEventQueue, engine->accelerometerSensor); } + if (engine->gravitySensor != NULL) { + ASensorEventQueue_disableSensor(engine->sensorEventQueue, + engine->gravitySensor); + } if (engine->magnetometerSensor != NULL) { ASensorEventQueue_disableSensor(engine->sensorEventQueue, engine->magnetometerSensor); @@ -729,6 +741,8 @@ void android_main(struct android_app *app) { engine.sensorManager = ASensorManager_getInstance(); engine.accelerometerSensor = ASensorManager_getDefaultSensor(engine.sensorManager, ASENSOR_TYPE_ACCELEROMETER); + engine.gravitySensor = ASensorManager_getDefaultSensor(engine.sensorManager, + ASENSOR_TYPE_GRAVITY); engine.magnetometerSensor = ASensorManager_getDefaultSensor(engine.sensorManager, ASENSOR_TYPE_MAGNETIC_FIELD); engine.gyroscopeSensor = ASensorManager_getDefaultSensor(engine.sensorManager, diff --git a/platform/android/java/gradlew.bat b/platform/android/java/gradlew.bat index aec99730b4..8a0b282aa6 100644 --- a/platform/android/java/gradlew.bat +++ b/platform/android/java/gradlew.bat @@ -1,90 +1,90 @@ -@if "%DEBUG%" == "" @echo off
-@rem ##########################################################################
-@rem
-@rem Gradle startup script for Windows
-@rem
-@rem ##########################################################################
-
-@rem Set local scope for the variables with windows NT shell
-if "%OS%"=="Windows_NT" setlocal
-
-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS=
-
-set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
-set APP_BASE_NAME=%~n0
-set APP_HOME=%DIRNAME%
-
-@rem Find java.exe
-if defined JAVA_HOME goto findJavaFromJavaHome
-
-set JAVA_EXE=java.exe
-%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto init
-
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:findJavaFromJavaHome
-set JAVA_HOME=%JAVA_HOME:"=%
-set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-
-if exist "%JAVA_EXE%" goto init
-
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:init
-@rem Get command-line arguments, handling Windowz variants
-
-if not "%OS%" == "Windows_NT" goto win9xME_args
-if "%@eval[2+2]" == "4" goto 4NT_args
-
-:win9xME_args
-@rem Slurp the command line arguments.
-set CMD_LINE_ARGS=
-set _SKIP=2
-
-:win9xME_args_slurp
-if "x%~1" == "x" goto execute
-
-set CMD_LINE_ARGS=%*
-goto execute
-
-:4NT_args
-@rem Get arguments from the 4NT Shell from JP Software
-set CMD_LINE_ARGS=%$
-
-:execute
-@rem Setup the command line
-
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
-
-@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
-
-:end
-@rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
-
-:fail
-rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
-rem the _cmd.exe /c_ return code!
-if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
-
-:mainEnd
-if "%OS%"=="Windows_NT" endlocal
-
-:omega
+@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/platform/android/java/src/org/godotengine/godot/Godot.java b/platform/android/java/src/org/godotengine/godot/Godot.java index 053dfa631a..41dcba5c2c 100644 --- a/platform/android/java/src/org/godotengine/godot/Godot.java +++ b/platform/android/java/src/org/godotengine/godot/Godot.java @@ -191,6 +191,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC protected void onMainPause() {} protected void onMainResume() {} protected void onMainDestroy() {} + protected boolean onMainBackPressed() { return false; } protected void onGLDrawFrame(GL10 gl) {} protected void onGLSurfaceChanged(GL10 gl, int width, int height) {} // singletons will always miss first onGLSurfaceChanged call @@ -218,6 +219,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC private SensorManager mSensorManager; private Sensor mAccelerometer; + private Sensor mGravity; private Sensor mMagnetometer; private Sensor mGyroscope; @@ -434,6 +436,8 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_GAME); + mGravity = mSensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY); + mSensorManager.registerListener(this, mGravity, SensorManager.SENSOR_DELAY_GAME); mMagnetometer = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); mSensorManager.registerListener(this, mMagnetometer, SensorManager.SENSOR_DELAY_GAME); mGyroscope = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE); @@ -666,6 +670,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC } }); mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_GAME); + mSensorManager.registerListener(this, mGravity, SensorManager.SENSOR_DELAY_GAME); mSensorManager.registerListener(this, mMagnetometer, SensorManager.SENSOR_DELAY_GAME); mSensorManager.registerListener(this, mGyroscope, SensorManager.SENSOR_DELAY_GAME); @@ -733,13 +738,16 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC @Override public void run() { if (typeOfSensor == Sensor.TYPE_ACCELEROMETER) { - GodotLib.accelerometer(x,y,z); + GodotLib.accelerometer(-x,y,-z); + } + if (typeOfSensor == Sensor.TYPE_GRAVITY) { + GodotLib.gravity(-x,y,-z); } if (typeOfSensor == Sensor.TYPE_MAGNETIC_FIELD) { - GodotLib.magnetometer(x,y,z); + GodotLib.magnetometer(-x,y,-z); } if (typeOfSensor == Sensor.TYPE_GYROSCOPE) { - GodotLib.gyroscope(x,y,z); + GodotLib.gyroscope(x,-y,z); } } }); @@ -767,9 +775,16 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC */ @Override public void onBackPressed() { + boolean shouldQuit = true; + + for(int i=0;i<singleton_count;i++) { + if (singletons[i].onMainBackPressed()) { + shouldQuit = false; + } + } System.out.printf("** BACK REQUEST!\n"); - if (mView != null) { + if (shouldQuit && mView != null) { mView.queueEvent(new Runnable() { @Override public void run() { diff --git a/platform/android/java/src/org/godotengine/godot/GodotLib.java b/platform/android/java/src/org/godotengine/godot/GodotLib.java index e0ed4cd38c..6b84ad6555 100644 --- a/platform/android/java/src/org/godotengine/godot/GodotLib.java +++ b/platform/android/java/src/org/godotengine/godot/GodotLib.java @@ -53,6 +53,7 @@ public class GodotLib { public static native void step(); public static native void touch(int what,int pointer,int howmany, int[] arr); public static native void accelerometer(float x, float y, float z); + public static native void gravity(float x, float y, float z); public static native void magnetometer(float x, float y, float z); public static native void gyroscope(float x, float y, float z); public static native void key(int p_scancode, int p_unicode_char, boolean p_pressed); diff --git a/platform/android/java/src/org/godotengine/godot/GodotView.java b/platform/android/java/src/org/godotengine/godot/GodotView.java index 3c2ad7cc59..b807b952d4 100644 --- a/platform/android/java/src/org/godotengine/godot/GodotView.java +++ b/platform/android/java/src/org/godotengine/godot/GodotView.java @@ -285,13 +285,7 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener { @Override public boolean onKeyDown(final int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { - queueEvent(new Runnable() { - @Override - public void run() { - GodotLib.back(); - } - }); - + activity.onBackPressed(); // press 'back' button should not terminate program //normal handle 'back' event in game logic return true; diff --git a/platform/android/java_glue.cpp b/platform/android/java_glue.cpp index 0b193f5882..87f20bee91 100644 --- a/platform/android/java_glue.cpp +++ b/platform/android/java_glue.cpp @@ -608,6 +608,7 @@ static bool resized = false; static bool resized_reload = false; static Size2 new_size; static Vector3 accelerometer; +static Vector3 gravity; static Vector3 magnetometer; static Vector3 gyroscope; static HashMap<String, JNISingleton *> jni_singletons; @@ -1012,6 +1013,8 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, job os_android->process_accelerometer(accelerometer); + os_android->process_gravity(gravity); + os_android->process_magnetometer(magnetometer); os_android->process_gyroscope(gyroscope); @@ -1386,6 +1389,10 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_accelerometer(JNIEnv accelerometer = Vector3(x, y, z); } +JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_gravity(JNIEnv *env, jobject obj, jfloat x, jfloat y, jfloat z) { + gravity = Vector3(x, y, z); +} + JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_magnetometer(JNIEnv *env, jobject obj, jfloat x, jfloat y, jfloat z) { magnetometer = Vector3(x, y, z); } diff --git a/platform/android/java_glue.h b/platform/android/java_glue.h index 0aa2489813..4790c65617 100644 --- a/platform/android/java_glue.h +++ b/platform/android/java_glue.h @@ -50,6 +50,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyhat(JNIEnv *env, j JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyconnectionchanged(JNIEnv *env, jobject obj, jint p_device, jboolean p_connected, jstring p_name); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_audio(JNIEnv *env, jobject obj); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_accelerometer(JNIEnv *env, jobject obj, jfloat x, jfloat y, jfloat z); +JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_gravity(JNIEnv *env, jobject obj, jfloat x, jfloat y, jfloat z); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_magnetometer(JNIEnv *env, jobject obj, jfloat x, jfloat y, jfloat z); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_gyroscope(JNIEnv *env, jobject obj, jfloat x, jfloat y, jfloat z); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_focusin(JNIEnv *env, jobject obj); diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp index 473a093077..a36df0675c 100644 --- a/platform/android/os_android.cpp +++ b/platform/android/os_android.cpp @@ -65,12 +65,6 @@ const char *OS_Android::get_video_driver_name(int p_driver) const { return "GLES2"; } - -OS::VideoMode OS_Android::get_default_video_mode() const { - - return OS::VideoMode(); -} - int OS_Android::get_audio_driver_count() const { return 1; @@ -123,7 +117,9 @@ void OS_Android::initialize_core() { void OS_Android::initialize_logger() { Vector<Logger *> loggers; loggers.push_back(memnew(AndroidLogger)); - loggers.push_back(memnew(RotatedFileLogger("user://logs/log.txt"))); + // FIXME: Reenable once we figure out how to get this properly in user:// + // instead of littering the user's working dirs (res:// + pwd) with log files (GH-12277) + //loggers.push_back(memnew(RotatedFileLogger("user://logs/log.txt"))); _set_logger(memnew(CompositeLogger(loggers))); } @@ -155,11 +151,6 @@ void OS_Android::initialize(const VideoMode &p_desired, int p_video_driver, int AudioDriverManager::initialize(p_audio_driver); - physics_server = memnew(PhysicsServerSW); - physics_server->init(); - physics_2d_server = Physics2DServerWrapMT::init_server<Physics2DServerSW>(); - physics_2d_server->init(); - input = memnew(InputDefault); input->set_fallback_mapping("Default Android Gamepad"); @@ -499,6 +490,11 @@ void OS_Android::process_accelerometer(const Vector3 &p_accelerometer) { input->set_accelerometer(p_accelerometer); } +void OS_Android::process_gravity(const Vector3 &p_gravity) { + + input->set_gravity(p_gravity); +} + void OS_Android::process_magnetometer(const Vector3 &p_magnetometer) { input->set_magnetometer(p_magnetometer); diff --git a/platform/android/os_android.h b/platform/android/os_android.h index 0c78c198a8..750afa7a14 100644 --- a/platform/android/os_android.h +++ b/platform/android/os_android.h @@ -38,9 +38,6 @@ #include "os/main_loop.h" //#include "power_android.h" #include "servers/audio_server.h" -#include "servers/physics/physics_server_sw.h" -#include "servers/physics_2d/physics_2d_server_sw.h" -#include "servers/physics_2d/physics_2d_server_wrap_mt.h" #include "servers/visual/rasterizer.h" #ifdef ANDROID_NATIVE_ACTIVITY @@ -106,8 +103,6 @@ private: bool use_16bits_fbo; VisualServer *visual_server; - PhysicsServer *physics_server; - Physics2DServer *physics_2d_server; mutable String data_dir_cache; @@ -146,8 +141,6 @@ public: virtual int get_video_driver_count() const; virtual const char *get_video_driver_name(int p_driver) const; - virtual VideoMode get_default_video_mode() const; - virtual int get_audio_driver_count() const; virtual const char *get_audio_driver_name(int p_driver) const; @@ -226,6 +219,7 @@ public: virtual String get_system_dir(SystemDir p_dir) const; void process_accelerometer(const Vector3 &p_accelerometer); + void process_gravity(const Vector3 &p_gravity); void process_magnetometer(const Vector3 &p_magnetometer); void process_gyroscope(const Vector3 &p_gyroscope); void process_touch(int p_what, int p_pointer, const Vector<TouchPos> &p_points); diff --git a/platform/android/platform_config.h b/platform/android/platform_config.h index b1c3f027f3..b1f51c9256 100644 --- a/platform/android/platform_config.h +++ b/platform/android/platform_config.h @@ -28,3 +28,4 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include <alloca.h> +#include <malloc.h> diff --git a/platform/haiku/os_haiku.cpp b/platform/haiku/os_haiku.cpp index 1d52752f21..0c34e39655 100644 --- a/platform/haiku/os_haiku.cpp +++ b/platform/haiku/os_haiku.cpp @@ -79,10 +79,6 @@ const char *OS_Haiku::get_video_driver_name(int p_driver) const { return "GLES2"; } -OS::VideoMode OS_Haiku::get_default_video_mode() const { - return OS::VideoMode(800, 600, false); -} - void OS_Haiku::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) { main_loop = NULL; current_video_mode = p_desired; @@ -130,13 +126,6 @@ void OS_Haiku::initialize(const VideoMode &p_desired, int p_video_driver, int p_ window->Show(); visual_server->init(); - physics_server = memnew(PhysicsServerSW); - physics_server->init(); - physics_2d_server = memnew(Physics2DServerSW); - // TODO: enable multithreaded PS - //physics_2d_server = Physics2DServerWrapMT::init_server<Physics2DServerSW>(); - physics_2d_server->init(); - AudioDriverManager::initialize(p_audio_driver); power_manager = memnew(PowerHaiku); @@ -153,12 +142,6 @@ void OS_Haiku::finalize() { memdelete(visual_server); memdelete(rasterizer); - physics_server->finish(); - memdelete(physics_server); - - physics_2d_server->finish(); - memdelete(physics_2d_server); - memdelete(input); #if defined(OPENGL_ENABLED) diff --git a/platform/haiku/os_haiku.h b/platform/haiku/os_haiku.h index d929f7e43b..86148f1fb4 100644 --- a/platform/haiku/os_haiku.h +++ b/platform/haiku/os_haiku.h @@ -38,8 +38,6 @@ #include "main/input_default.h" #include "power_haiku.h" #include "servers/audio_server.h" -#include "servers/physics_2d/physics_2d_server_sw.h" -#include "servers/physics_server.h" #include "servers/visual/rasterizer.h" #include "servers/visual_server.h" @@ -52,8 +50,6 @@ private: Rasterizer *rasterizer; VisualServer *visual_server; VideoMode current_video_mode; - PhysicsServer *physics_server; - Physics2DServer *physics_2d_server; PowerHaiku *power_manager; #ifdef MEDIA_KIT_ENABLED @@ -69,7 +65,6 @@ private: protected: virtual int get_video_driver_count() const; virtual const char *get_video_driver_name(int p_driver) const; - virtual VideoMode get_default_video_mode() const; virtual void 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 65cafbd6d4..8f2893e69e 100644 --- a/platform/iphone/app_delegate.mm +++ b/platform/iphone/app_delegate.mm @@ -638,6 +638,9 @@ static int frame_count = 0; mainViewController = view_controller; + // prevent to stop music in another background app + [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient error:nil]; + #ifdef MODULE_GAME_ANALYTICS_ENABLED printf("********************* didFinishLaunchingWithOptions\n"); if (!ProjectSettings::get_singleton()->has("mobileapptracker/advertiser_id")) { diff --git a/platform/iphone/detect.py b/platform/iphone/detect.py index 00d8a59f74..993a93ff89 100644 --- a/platform/iphone/detect.py +++ b/platform/iphone/detect.py @@ -47,8 +47,8 @@ def configure(env): if (env["target"].startswith("release")): env.Append(CPPFLAGS=['-DNDEBUG', '-DNS_BLOCK_ASSERTIONS=1']) - env.Append(CPPFLAGS=['-O2', '-flto', '-ftree-vectorize', '-fomit-frame-pointer', '-ffast-math', '-funsafe-math-optimizations']) - env.Append(LINKFLAGS=['-O2', '-flto']) + env.Append(CPPFLAGS=['-O2', '-ftree-vectorize', '-fomit-frame-pointer', '-ffast-math', '-funsafe-math-optimizations']) + env.Append(LINKFLAGS=['-O2']) if env["target"] == "release_debug": env.Append(CPPFLAGS=['-DDEBUG_ENABLED']) @@ -56,6 +56,10 @@ def configure(env): elif (env["target"] == "debug"): env.Append(CPPFLAGS=['-D_DEBUG', '-DDEBUG=1', '-gdwarf-2', '-O0', '-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED']) + if (env["use_lto"]): + env.Append(CPPFLAGS=['-flto']) + env.Append(LINKFLAGS=['-flto']) + ## Architecture if env["ios_sim"] or env["arch"] == "x86": # i386, simulator diff --git a/platform/iphone/export/export.cpp b/platform/iphone/export/export.cpp index c91781ce1d..0507ef19d6 100644 --- a/platform/iphone/export/export.cpp +++ b/platform/iphone/export/export.cpp @@ -397,7 +397,7 @@ Error EditorExportPlatformIOS::_codesign(String p_file, void *p_userdata) { codesign_args.push_back("-s"); codesign_args.push_back(data->preset->get(data->debug ? "application/code_sign_identity_debug" : "application/code_sign_identity_release")); codesign_args.push_back(p_file); - return OS::get_singleton()->execute("/usr/bin/codesign", codesign_args, true); + return OS::get_singleton()->execute("codesign", codesign_args, true); } return OK; } @@ -592,7 +592,15 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p return err; #ifdef OSX_ENABLED - ep.step("Making .xcarchive", 2); + ep.step("Code-signing dylibs", 2); + DirAccess *dylibs_dir = DirAccess::open(dest_dir + "dylibs"); + ERR_FAIL_COND_V(!dylibs_dir, ERR_CANT_OPEN); + CodesignData codesign_data(p_preset, p_debug); + err = _walk_dir_recursive(dylibs_dir, _codesign, &codesign_data); + memdelete(dylibs_dir); + ERR_FAIL_COND_V(err, err); + + ep.step("Making .xcarchive", 3); String archive_path = p_path.get_basename() + ".xcarchive"; List<String> archive_args; archive_args.push_back("-project"); @@ -608,15 +616,7 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p archive_args.push_back("archive"); archive_args.push_back("-archivePath"); archive_args.push_back(archive_path); - err = OS::get_singleton()->execute("/usr/bin/xcodebuild", archive_args, true); - ERR_FAIL_COND_V(err, err); - - ep.step("Code-signing dylibs", 3); - DirAccess *dylibs_dir = DirAccess::open(archive_path + "/Products/Applications/" + binary_name + ".app/dylibs"); - ERR_FAIL_COND_V(!dylibs_dir, ERR_CANT_OPEN); - CodesignData codesign_data(p_preset, p_debug); - err = _walk_dir_recursive(dylibs_dir, _codesign, &codesign_data); - memdelete(dylibs_dir); + err = OS::get_singleton()->execute("xcodebuild", archive_args, true); ERR_FAIL_COND_V(err, err); ep.step("Making .ipa", 4); @@ -628,7 +628,7 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p export_args.push_back(dest_dir + "export_options.plist"); export_args.push_back("-exportPath"); export_args.push_back(dest_dir); - err = OS::get_singleton()->execute("/usr/bin/xcodebuild", export_args, true); + err = OS::get_singleton()->execute("xcodebuild", export_args, true); ERR_FAIL_COND_V(err, err); #else print_line(".ipa can only be built on macOS. Leaving XCode project without building the package."); diff --git a/platform/iphone/game_center.h b/platform/iphone/game_center.h index c0a7830fe9..21f40fa362 100644 --- a/platform/iphone/game_center.h +++ b/platform/iphone/game_center.h @@ -43,11 +43,13 @@ class GameCenter : public Object { List<Variant> pending_events; - bool connected; + bool authenticated; + + void return_connect_error(const char *p_error_description); public: - Error connect(); - bool is_connected(); + void connect(); + bool is_authenticated(); Error post_score(Variant p_score); Error award_achievement(Variant p_params); @@ -55,6 +57,7 @@ public: void request_achievements(); void request_achievement_descriptions(); Error show_game_center(Variant p_params); + Error request_identity_verification_signature(); void game_center_closed(); diff --git a/platform/iphone/game_center.mm b/platform/iphone/game_center.mm index 3955b9f0aa..531b80eee3 100644 --- a/platform/iphone/game_center.mm +++ b/platform/iphone/game_center.mm @@ -49,8 +49,7 @@ extern "C" { GameCenter *GameCenter::instance = NULL; void GameCenter::_bind_methods() { - ClassDB::bind_method(D_METHOD("connect"), &GameCenter::connect); - ClassDB::bind_method(D_METHOD("is_connected"), &GameCenter::is_connected); + ClassDB::bind_method(D_METHOD("is_authenticated"), &GameCenter::is_authenticated); ClassDB::bind_method(D_METHOD("post_score"), &GameCenter::post_score); ClassDB::bind_method(D_METHOD("award_achievement"), &GameCenter::award_achievement); @@ -58,24 +57,41 @@ void GameCenter::_bind_methods() { ClassDB::bind_method(D_METHOD("request_achievements"), &GameCenter::request_achievements); ClassDB::bind_method(D_METHOD("request_achievement_descriptions"), &GameCenter::request_achievement_descriptions); ClassDB::bind_method(D_METHOD("show_game_center"), &GameCenter::show_game_center); + ClassDB::bind_method(D_METHOD("request_identity_verification_signature"), &GameCenter::request_identity_verification_signature); ClassDB::bind_method(D_METHOD("get_pending_event_count"), &GameCenter::get_pending_event_count); ClassDB::bind_method(D_METHOD("pop_pending_event"), &GameCenter::pop_pending_event); }; -Error GameCenter::connect() { +void GameCenter::return_connect_error(const char *p_error_description) { + authenticated = false; + Dictionary ret; + ret["type"] = "authentication"; + ret["result"] = "error"; + ret["error_code"] = 0; + ret["error_description"] = p_error_description; + pending_events.push_back(ret); +} + +void GameCenter::connect() { //if this class isn't available, game center isn't implemented if ((NSClassFromString(@"GKLocalPlayer")) == nil) { - GameCenter::get_singleton()->connected = false; - return ERR_UNAVAILABLE; + return_connect_error("GameCenter not available"); + return; } GKLocalPlayer *player = [GKLocalPlayer localPlayer]; - ERR_FAIL_COND_V(![player respondsToSelector:@selector(authenticateHandler)], ERR_UNAVAILABLE); + if (![player respondsToSelector:@selector(authenticateHandler)]) { + return_connect_error("GameCenter doesn't respond to 'authenticateHandler'"); + return; + } ViewController *root_controller = (ViewController *)((AppDelegate *)[[UIApplication sharedApplication] delegate]).window.rootViewController; - ERR_FAIL_COND_V(!root_controller, FAILED); + if (!root_controller) { + return_connect_error("Window doesn't have root ViewController"); + return; + } // This handler is called several times. First when the view needs to be shown, then again // after the view is cancelled or the user logs in. Or if the user's already logged in, it's @@ -90,23 +106,21 @@ Error GameCenter::connect() { if (player.isAuthenticated) { ret["result"] = "ok"; ret["player_id"] = [player.playerID UTF8String]; - GameCenter::get_singleton()->connected = true; + GameCenter::get_singleton()->authenticated = true; } else { ret["result"] = "error"; ret["error_code"] = error.code; ret["error_description"] = [error.localizedDescription UTF8String]; - GameCenter::get_singleton()->connected = false; + GameCenter::get_singleton()->authenticated = false; }; pending_events.push_back(ret); }; }); - - return OK; }; -bool GameCenter::is_connected() { - return connected; +bool GameCenter::is_authenticated() { + return authenticated; }; Error GameCenter::post_score(Variant p_score) { @@ -117,7 +131,7 @@ Error GameCenter::post_score(Variant p_score) { String category = params["category"]; NSString *cat_str = [[[NSString alloc] initWithUTF8String:category.utf8().get_data()] autorelease]; - GKScore *reporter = [[[GKScore alloc] initWithCategory:cat_str] autorelease]; + GKScore *reporter = [[[GKScore alloc] initWithLeaderboardIdentifier:cat_str] autorelease]; reporter.value = score; ERR_FAIL_COND_V([GKScore respondsToSelector:@selector(reportScores)], ERR_UNAVAILABLE); @@ -326,6 +340,34 @@ Error GameCenter::show_game_center(Variant p_params) { return OK; }; +Error GameCenter::request_identity_verification_signature() { + + ERR_FAIL_COND_V(!is_authenticated(), ERR_UNAUTHORIZED); + + 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) { + ret["result"] = "ok"; + ret["public_key_url"] = [publicKeyUrl.absoluteString UTF8String]; + ret["signature"] = [[signature base64EncodedStringWithOptions:0] UTF8String]; + ret["salt"] = [[salt base64EncodedStringWithOptions:0] UTF8String]; + ret["timestamp"] = timestamp; + ret["player_id"] = [player.playerID UTF8String]; + } else { + ret["result"] = "error"; + ret["error_code"] = error.code; + ret["error_description"] = [error.localizedDescription UTF8String]; + }; + + pending_events.push_back(ret); + }]; + + return OK; +}; + void GameCenter::game_center_closed() { Dictionary ret; @@ -354,7 +396,7 @@ GameCenter *GameCenter::get_singleton() { GameCenter::GameCenter() { ERR_FAIL_COND(instance != NULL); instance = this; - connected = false; + authenticated = false; }; GameCenter::~GameCenter(){}; diff --git a/platform/iphone/os_iphone.cpp b/platform/iphone/os_iphone.cpp index 08792b8631..0685e961c3 100644 --- a/platform/iphone/os_iphone.cpp +++ b/platform/iphone/os_iphone.cpp @@ -62,11 +62,6 @@ OSIPhone *OSIPhone::get_singleton() { return (OSIPhone *)OS::get_singleton(); }; -OS::VideoMode OSIPhone::get_default_video_mode() const { - - return video_mode; -}; - uint8_t OSIPhone::get_orientations() const { return supported_orientations; @@ -104,7 +99,9 @@ void OSIPhone::initialize_core() { void OSIPhone::initialize_logger() { Vector<Logger *> loggers; loggers.push_back(memnew(SyslogLogger)); - loggers.push_back(memnew(RotatedFileLogger("user://logs/log.txt"))); + // FIXME: Reenable once we figure out how to get this properly in user:// + // instead of littering the user's working dirs (res:// + pwd) with log files (GH-12277) + //loggers.push_back(memnew(RotatedFileLogger("user://logs/log.txt"))); _set_logger(memnew(CompositeLogger(loggers))); } @@ -136,13 +133,6 @@ void OSIPhone::initialize(const VideoMode &p_desired, int p_video_driver, int p_ AudioDriverManager::add_driver(&audio_driver); AudioDriverManager::initialize(p_audio_driver); - // init physics servers - physics_server = memnew(PhysicsServerSW); - physics_server->init(); - //physics_2d_server = memnew( Physics2DServerSW ); - physics_2d_server = Physics2DServerWrapMT::init_server<Physics2DServerSW>(); - physics_2d_server->init(); - input = memnew(InputDefault); /* @@ -382,12 +372,6 @@ void OSIPhone::finalize() { memdelete(visual_server); // memdelete(rasterizer); - physics_server->finish(); - memdelete(physics_server); - - physics_2d_server->finish(); - memdelete(physics_2d_server); - memdelete(input); }; diff --git a/platform/iphone/os_iphone.h b/platform/iphone/os_iphone.h index e70ac9ba98..6627fddf08 100644 --- a/platform/iphone/os_iphone.h +++ b/platform/iphone/os_iphone.h @@ -41,9 +41,6 @@ #include "in_app_store.h" #include "main/input_default.h" #include "servers/audio_server.h" -#include "servers/physics/physics_server_sw.h" -#include "servers/physics_2d/physics_2d_server_sw.h" -#include "servers/physics_2d/physics_2d_server_wrap_mt.h" #include "servers/visual/rasterizer.h" #include "servers/visual_server.h" @@ -66,8 +63,6 @@ private: uint8_t supported_orientations; VisualServer *visual_server; - PhysicsServer *physics_server; - Physics2DServer *physics_2d_server; AudioDriverCoreAudio audio_driver; @@ -88,8 +83,6 @@ private: virtual int get_video_driver_count() const; virtual const char *get_video_driver_name(int p_driver) const; - virtual VideoMode get_default_video_mode() const; - virtual void initialize_logger(); virtual void initialize_core(); virtual void initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); diff --git a/platform/javascript/SCsub b/platform/javascript/SCsub index f01d9367d2..e3015d87b9 100644 --- a/platform/javascript/SCsub +++ b/platform/javascript/SCsub @@ -6,8 +6,8 @@ javascript_files = [ "os_javascript.cpp", "audio_driver_javascript.cpp", "javascript_main.cpp", - "audio_server_javascript.cpp", "power_javascript.cpp", + "http_client_javascript.cpp", "javascript_eval.cpp", ] @@ -19,7 +19,7 @@ javascript_objects = [] for x in javascript_files: javascript_objects.append(env_javascript.Object(x)) -env.Append(LINKFLAGS=["-s", "EXPORTED_FUNCTIONS=\"['_main','_audio_server_mix_function','_main_after_fs_sync','_send_notification']\""]) +env.Append(LINKFLAGS=["-s", "EXPORTED_FUNCTIONS=\"['_main','_main_after_fs_sync','_send_notification']\""]) # output file name without file extension basename = "godot" + env["PROGSUFFIX"] @@ -43,6 +43,12 @@ else: js = env.Program(['#bin/godot'] + implicit_targets, javascript_objects, PROGSUFFIX=env['PROGSUFFIX'] + '.js')[0]; zip_files.append(InstallAs(zip_dir.File('godot.js'), js)) +js_libraries = [] +js_libraries.append(env.File('http_request.js')) +for lib in js_libraries: + env.Append(LINKFLAGS=['--js-library', lib.path]) +env.Depends(js, js_libraries) + postjs = env.File('engine.js') env.Depends(js, [prejs, postjs]) env.Append(LINKFLAGS=['--pre-js', prejs.path]) diff --git a/platform/javascript/audio_driver_javascript.cpp b/platform/javascript/audio_driver_javascript.cpp index 4c0e5fd966..9633472cd2 100644 --- a/platform/javascript/audio_driver_javascript.cpp +++ b/platform/javascript/audio_driver_javascript.cpp @@ -29,31 +29,86 @@ /*************************************************************************/ #include "audio_driver_javascript.h" -#include <string.h> +#include <emscripten.h> -#define MAX_NUMBER_INTERFACES 3 -#define MAX_NUMBER_OUTPUT_DEVICES 6 - -/* Structure for passing information to callback function */ - -//AudioDriverJavaScript* AudioDriverJavaScript::s_ad=NULL; +AudioDriverJavaScript *AudioDriverJavaScript::singleton_js = NULL; const char *AudioDriverJavaScript::get_name() const { return "JavaScript"; } +extern "C" EMSCRIPTEN_KEEPALIVE void js_audio_driver_mix_function(int p_frames) { + + //print_line("MIXI! "+itos(p_frames)); + AudioDriverJavaScript::singleton_js->mix_to_js(p_frames); +} + +void AudioDriverJavaScript::mix_to_js(int p_frames) { + + int todo = p_frames; + int offset = 0; + + while (todo) { + + int tomix = MIN(todo, INTERNAL_BUFFER_SIZE); + + audio_server_process(p_frames, stream_buffer); + for (int i = 0; i < tomix * internal_buffer_channels; i++) { + internal_buffer[i] = float(stream_buffer[i] >> 16) / 32768.0; + } + + /* clang-format off */ + EM_ASM_ARGS({ + var data = HEAPF32.subarray($0 / 4, $0 / 4 + $2 * 2); + + for (var channel = 0; channel < _as_output_buffer.numberOfChannels; channel++) { + var outputData = _as_output_buffer.getChannelData(channel); + // Loop through samples + for (var sample = 0; sample < $2; sample++) { + // make output equal to the same as the input + outputData[sample + $1] = data[sample * 2 + channel]; + } + } + }, internal_buffer, offset, tomix); + /* clang-format on */ + + todo -= tomix; + offset += tomix; + } +} + Error AudioDriverJavaScript::init() { return OK; } void AudioDriverJavaScript::start() { + + internal_buffer = memnew_arr(float, INTERNAL_BUFFER_SIZE *internal_buffer_channels); + stream_buffer = memnew_arr(int32_t, INTERNAL_BUFFER_SIZE * 4); //max 4 channels + + /* clang-format off */ + mix_rate = EM_ASM_INT({ + _as_audioctx = new (window.AudioContext || window.webkitAudioContext); + _as_script_node = _as_audioctx.createScriptProcessor($0, 0, $1); + _as_script_node.connect(_as_audioctx.destination); + console.log(_as_script_node.bufferSize); + var jsAudioDriverMixFunction = cwrap('js_audio_driver_mix_function', null, ['number']); + + _as_script_node.onaudioprocess = function(audioProcessingEvent) { + // The output buffer contains the samples that will be modified and played + _as_output_buffer = audioProcessingEvent.outputBuffer; + jsAudioDriverMixFunction([_as_output_buffer.getChannelData(0).length]); + }; + return _as_audioctx.sampleRate; + }, INTERNAL_BUFFER_SIZE, internal_buffer_channels); + /* clang-format on */ } int AudioDriverJavaScript::get_mix_rate() const { - return 44100; + return mix_rate; } AudioDriver::SpeakerMode AudioDriverJavaScript::get_speaker_mode() const { @@ -63,7 +118,7 @@ AudioDriver::SpeakerMode AudioDriverJavaScript::get_speaker_mode() const { void AudioDriverJavaScript::lock() { - /* + /*no locking, as threads are not supported if (active && mutex) mutex->lock(); */ @@ -71,7 +126,7 @@ void AudioDriverJavaScript::lock() { void AudioDriverJavaScript::unlock() { - /* + /*no locking, as threads are not supported if (active && mutex) mutex->unlock(); */ @@ -81,4 +136,8 @@ void AudioDriverJavaScript::finish() { } AudioDriverJavaScript::AudioDriverJavaScript() { + + internal_buffer_channels = 2; + mix_rate = DEFAULT_MIX_RATE; + singleton_js = this; } diff --git a/platform/javascript/audio_driver_javascript.h b/platform/javascript/audio_driver_javascript.h index c5cebe800f..b265c4e030 100644 --- a/platform/javascript/audio_driver_javascript.h +++ b/platform/javascript/audio_driver_javascript.h @@ -32,10 +32,21 @@ #include "servers/audio_server.h" -#include "os/mutex.h" - class AudioDriverJavaScript : public AudioDriver { + + enum { + INTERNAL_BUFFER_SIZE = 4096, + }; + + int mix_rate; + float *internal_buffer; + int internal_buffer_channels; + int32_t *stream_buffer; + public: + void mix_to_js(int p_frames); + static AudioDriverJavaScript *singleton_js; + virtual const char *get_name() const; virtual Error init(); diff --git a/platform/javascript/audio_server_javascript.cpp b/platform/javascript/audio_server_javascript.cpp deleted file mode 100644 index ab9f66ce5b..0000000000 --- a/platform/javascript/audio_server_javascript.cpp +++ /dev/null @@ -1,853 +0,0 @@ -/*************************************************************************/ -/* audio_server_javascript.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ -#include "audio_server_javascript.h" - -// FIXME: Needs to be ported to the new AudioServer API in 3.0 -#if 0 -#include "emscripten.h" - -AudioMixer *AudioServerJavascript::get_mixer() { - - return NULL; -} - -void AudioServerJavascript::audio_mixer_chunk_callback(int p_frames){ - - -} - - -RID AudioServerJavascript::sample_create(SampleFormat p_format, bool p_stereo, int p_length) { - - Sample *sample = memnew( Sample ); - sample->format=p_format; - sample->stereo=p_stereo; - sample->length=p_length; - sample->loop_begin=0; - sample->loop_end=p_length; - sample->loop_format=SAMPLE_LOOP_NONE; - sample->mix_rate=44100; - sample->index=-1; - - return sample_owner.make_rid(sample); - -} - -void AudioServerJavascript::sample_set_description(RID p_sample, const String& p_description){ - - -} -String AudioServerJavascript::sample_get_description(RID p_sample) const{ - - return String(); -} - -AudioServerJavascript::SampleFormat AudioServerJavascript::sample_get_format(RID p_sample) const{ - - return SAMPLE_FORMAT_PCM8; -} -bool AudioServerJavascript::sample_is_stereo(RID p_sample) const{ - - const Sample *sample = sample_owner.get(p_sample); - ERR_FAIL_COND_V(!sample,false); - return sample->stereo; - -} -int AudioServerJavascript::sample_get_length(RID p_sample) const{ - const Sample *sample = sample_owner.get(p_sample); - ERR_FAIL_COND_V(!sample,0); - return sample->length; -} -const void* AudioServerJavascript::sample_get_data_ptr(RID p_sample) const{ - - return NULL; -} - -void AudioServerJavascript::sample_set_data(RID p_sample, const PoolVector<uint8_t>& p_buffer){ - - Sample *sample = sample_owner.get(p_sample); - ERR_FAIL_COND(!sample); - int chans = sample->stereo?2:1; - - Vector<float> buffer; - buffer.resize(sample->length*chans); - PoolVector<uint8_t>::Read r=p_buffer.read(); - if (sample->format==SAMPLE_FORMAT_PCM8) { - const int8_t*ptr = (const int8_t*)r.ptr(); - for(int i=0;i<sample->length*chans;i++) { - buffer[i]=ptr[i]/128.0; - } - } else if (sample->format==SAMPLE_FORMAT_PCM16){ - const int16_t*ptr = (const int16_t*)r.ptr(); - for(int i=0;i<sample->length*chans;i++) { - buffer[i]=ptr[i]/32768.0; - } - } else { - ERR_EXPLAIN("Unsupported for now"); - ERR_FAIL(); - } - - sample->tmp_data=buffer; - - - -} -PoolVector<uint8_t> AudioServerJavascript::sample_get_data(RID p_sample) const{ - - - return PoolVector<uint8_t>(); -} - -void AudioServerJavascript::sample_set_mix_rate(RID p_sample,int p_rate){ - Sample *sample = sample_owner.get(p_sample); - ERR_FAIL_COND(!sample); - sample->mix_rate=p_rate; - -} - -int AudioServerJavascript::sample_get_mix_rate(RID p_sample) const{ - const Sample *sample = sample_owner.get(p_sample); - ERR_FAIL_COND_V(!sample,0); - return sample->mix_rate; -} - - -void AudioServerJavascript::sample_set_loop_format(RID p_sample,SampleLoopFormat p_format){ - - Sample *sample = sample_owner.get(p_sample); - ERR_FAIL_COND(!sample); - sample->loop_format=p_format; - -} - -AudioServerJavascript::SampleLoopFormat AudioServerJavascript::sample_get_loop_format(RID p_sample) const { - - const Sample *sample = sample_owner.get(p_sample); - ERR_FAIL_COND_V(!sample,SAMPLE_LOOP_NONE); - return sample->loop_format; -} - -void AudioServerJavascript::sample_set_loop_begin(RID p_sample,int p_pos){ - - Sample *sample = sample_owner.get(p_sample); - ERR_FAIL_COND(!sample); - sample->loop_begin=p_pos; - -} -int AudioServerJavascript::sample_get_loop_begin(RID p_sample) const{ - - const Sample *sample = sample_owner.get(p_sample); - ERR_FAIL_COND_V(!sample,0); - return sample->loop_begin; -} - -void AudioServerJavascript::sample_set_loop_end(RID p_sample,int p_pos){ - - Sample *sample = sample_owner.get(p_sample); - ERR_FAIL_COND(!sample); - sample->loop_end=p_pos; - -} -int AudioServerJavascript::sample_get_loop_end(RID p_sample) const{ - - const Sample *sample = sample_owner.get(p_sample); - ERR_FAIL_COND_V(!sample,0); - return sample->loop_end; -} - - -/* VOICE API */ - -RID AudioServerJavascript::voice_create(){ - - Voice *voice = memnew( Voice ); - - voice->index=voice_base; - voice->volume=1.0; - voice->pan=0.0; - voice->pan_depth=.0; - voice->pan_height=0.0; - voice->chorus=0; - voice->reverb_type=REVERB_SMALL; - voice->reverb=0; - voice->mix_rate=-1; - voice->positional=false; - voice->active=false; - - /* clang-format off */ - EM_ASM_( { - _as_voices[$0] = null; - _as_voice_gain[$0] = _as_audioctx.createGain(); - _as_voice_pan[$0] = _as_audioctx.createStereoPanner(); - _as_voice_gain[$0].connect(_as_voice_pan[$0]); - _as_voice_pan[$0].connect(_as_audioctx.destination); - }, voice_base); - /* clang-format on */ - - voice_base++; - - return voice_owner.make_rid( voice ); -} - -void AudioServerJavascript::voice_play(RID p_voice, RID p_sample){ - - Voice* voice=voice_owner.get(p_voice); - ERR_FAIL_COND(!voice); - Sample *sample=sample_owner.get(p_sample); - ERR_FAIL_COND(!sample); - - // due to how webaudio works, sample cration is deferred until used - // sorry! WebAudio absolutely sucks - - - if (sample->index==-1) { - //create sample if not created - ERR_FAIL_COND(sample->tmp_data.size()==0); - sample->index=sample_base; - /* clang-format off */ - EM_ASM_({ - _as_samples[$0] = _as_audioctx.createBuffer($1, $2, $3); - }, sample_base, sample->stereo ? 2 : 1, sample->length, sample->mix_rate); - /* clang-format on */ - - sample_base++; - int chans = sample->stereo?2:1; - - - for(int i=0;i<chans;i++) { - /* clang-format off */ - EM_ASM_({ - _as_edited_buffer = _as_samples[$0].getChannelData($1); - }, sample->index, i); - /* clang-format on */ - - for(int j=0;j<sample->length;j++) { - /* clang-format off */ - EM_ASM_({ - _as_edited_buffer[$0] = $1; - }, j, sample->tmp_data[j * chans + i]); - /* clang-format on */ - } - } - - sample->tmp_data.clear(); - } - - - voice->sample_mix_rate=sample->mix_rate; - if (voice->mix_rate==-1) { - voice->mix_rate=voice->sample_mix_rate; - } - - float freq_diff = Math::log(float(voice->mix_rate)/float(voice->sample_mix_rate))/Math::log(2.0); - int detune = int(freq_diff*1200.0); - - /* clang-format off */ - EM_ASM_({ - if (_as_voices[$0] !== null) { - _as_voices[$0].stop(); //stop and byebye - } - _as_voices[$0] = _as_audioctx.createBufferSource(); - _as_voices[$0].connect(_as_voice_gain[$0]); - _as_voices[$0].buffer = _as_samples[$1]; - _as_voices[$0].loopStart.value = $1; - _as_voices[$0].loopEnd.value = $2; - _as_voices[$0].loop.value = $3; - _as_voices[$0].detune.value = $6; - _as_voice_pan[$0].pan.value = $4; - _as_voice_gain[$0].gain.value = $5; - _as_voices[$0].start(); - _as_voices[$0].onended = function() { - _as_voices[$0].disconnect(_as_voice_gain[$0]); - _as_voices[$0] = null; - } - }, voice->index, sample->index, sample->mix_rate * sample->loop_begin, sample->mix_rate * sample->loop_end, sample->loop_format != SAMPLE_LOOP_NONE, voice->pan, voice->volume * fx_volume_scale, detune); - /* clang-format on */ - - voice->active=true; -} - -void AudioServerJavascript::voice_set_volume(RID p_voice, float p_volume){ - - Voice* voice=voice_owner.get(p_voice); - ERR_FAIL_COND(!voice); - - voice->volume=p_volume; - - if (voice->active) { - /* clang-format off */ - EM_ASM_({ - _as_voice_gain[$0].gain.value = $1; - }, voice->index, voice->volume * fx_volume_scale); - /* clang-format on */ - } - -} -void AudioServerJavascript::voice_set_pan(RID p_voice, float p_pan, float p_depth,float height){ - - Voice* voice=voice_owner.get(p_voice); - ERR_FAIL_COND(!voice); - - voice->pan=p_pan; - voice->pan_depth=p_depth; - voice->pan_height=height; - - if (voice->active) { - /* clang-format off */ - EM_ASM_({ - _as_voice_pan[$0].pan.value = $1; - }, voice->index, voice->pan); - /* clang-format on */ - } -} -void AudioServerJavascript::voice_set_filter(RID p_voice, FilterType p_type, float p_cutoff, float p_resonance, float p_gain){ - -} -void AudioServerJavascript::voice_set_chorus(RID p_voice, float p_chorus ){ - -} -void AudioServerJavascript::voice_set_reverb(RID p_voice, ReverbRoomType p_room_type, float p_reverb){ - -} -void AudioServerJavascript::voice_set_mix_rate(RID p_voice, int p_mix_rate){ - - Voice* voice=voice_owner.get(p_voice); - ERR_FAIL_COND(!voice); - - voice->mix_rate=p_mix_rate; - - if (voice->active) { - - float freq_diff = Math::log(float(voice->mix_rate)/float(voice->sample_mix_rate))/Math::log(2.0); - int detune = int(freq_diff*1200.0); - /* clang-format off */ - EM_ASM_({ - _as_voices[$0].detune.value = $1; - }, voice->index, detune); - /* clang-format on */ - } -} -void AudioServerJavascript::voice_set_positional(RID p_voice, bool p_positional){ - -} - -float AudioServerJavascript::voice_get_volume(RID p_voice) const{ - - Voice* voice=voice_owner.get(p_voice); - ERR_FAIL_COND_V(!voice,0); - - return voice->volume; -} -float AudioServerJavascript::voice_get_pan(RID p_voice) const{ - - Voice* voice=voice_owner.get(p_voice); - ERR_FAIL_COND_V(!voice,0); - - return voice->pan; -} -float AudioServerJavascript::voice_get_pan_depth(RID p_voice) const{ - Voice* voice=voice_owner.get(p_voice); - ERR_FAIL_COND_V(!voice,0); - - return voice->pan_depth; -} -float AudioServerJavascript::voice_get_pan_height(RID p_voice) const{ - - Voice* voice=voice_owner.get(p_voice); - ERR_FAIL_COND_V(!voice,0); - - return voice->pan_height; -} -AudioServerJavascript::FilterType AudioServerJavascript::voice_get_filter_type(RID p_voice) const{ - - return FILTER_NONE; -} -float AudioServerJavascript::voice_get_filter_cutoff(RID p_voice) const{ - - return 0; -} -float AudioServerJavascript::voice_get_filter_resonance(RID p_voice) const{ - - return 0; -} -float AudioServerJavascript::voice_get_chorus(RID p_voice) const{ - - return 0; -} -AudioServerJavascript::ReverbRoomType AudioServerJavascript::voice_get_reverb_type(RID p_voice) const{ - - return REVERB_SMALL; -} -float AudioServerJavascript::voice_get_reverb(RID p_voice) const{ - - return 0; -} - -int AudioServerJavascript::voice_get_mix_rate(RID p_voice) const{ - - return 44100; -} - -bool AudioServerJavascript::voice_is_positional(RID p_voice) const{ - - return false; -} - -void AudioServerJavascript::voice_stop(RID p_voice){ - - Voice* voice=voice_owner.get(p_voice); - ERR_FAIL_COND(!voice); - - if (voice->active) { - /* clang-format off */ - EM_ASM_({ - if (_as_voices[$0] !== null) { - _as_voices[$0].stop(); - _as_voices[$0].disconnect(_as_voice_gain[$0]); - _as_voices[$0] = null; - } - }, voice->index); - /* clang-format on */ - - voice->active=false; - } - - -} -bool AudioServerJavascript::voice_is_active(RID p_voice) const{ - Voice* voice=voice_owner.get(p_voice); - ERR_FAIL_COND_V(!voice,false); - - return voice->active; -} - -/* STREAM API */ - -RID AudioServerJavascript::audio_stream_create(AudioStream *p_stream) { - - - Stream *s = memnew(Stream); - s->audio_stream=p_stream; - s->event_stream=NULL; - s->active=false; - s->E=NULL; - s->volume_scale=1.0; - p_stream->set_mix_rate(webaudio_mix_rate); - - return stream_owner.make_rid(s); -} - -RID AudioServerJavascript::event_stream_create(EventStream *p_stream) { - - - Stream *s = memnew(Stream); - s->audio_stream=NULL; - s->event_stream=p_stream; - s->active=false; - s->E=NULL; - s->volume_scale=1.0; - //p_stream->set_mix_rate(AudioDriverJavascript::get_singleton()->get_mix_rate()); - - return stream_owner.make_rid(s); - - -} - - -void AudioServerJavascript::stream_set_active(RID p_stream, bool p_active) { - - - Stream *s = stream_owner.get(p_stream); - ERR_FAIL_COND(!s); - - if (s->active==p_active) - return; - - s->active=p_active; - if (p_active) - s->E=active_audio_streams.push_back(s); - else { - active_audio_streams.erase(s->E); - s->E=NULL; - } -} - -bool AudioServerJavascript::stream_is_active(RID p_stream) const { - - Stream *s = stream_owner.get(p_stream); - ERR_FAIL_COND_V(!s,false); - return s->active; -} - -void AudioServerJavascript::stream_set_volume_scale(RID p_stream, float p_scale) { - - Stream *s = stream_owner.get(p_stream); - ERR_FAIL_COND(!s); - s->volume_scale=p_scale; - -} - -float AudioServerJavascript::stream_set_volume_scale(RID p_stream) const { - - Stream *s = stream_owner.get(p_stream); - ERR_FAIL_COND_V(!s,0); - return s->volume_scale; - -} - - -/* Audio Physics API */ - -void AudioServerJavascript::free(RID p_id){ - - if (voice_owner.owns(p_id)) { - Voice* voice=voice_owner.get(p_id); - ERR_FAIL_COND(!voice); - - if (voice->active) { - /* clang-format off */ - EM_ASM_({ - if (_as_voices[$0] !== null) { - _as_voices[$0].stop(); - _as_voices[$0].disconnect(_as_voice_gain[$0]); - } - }, voice->index); - /* clang-format on */ - } - - /* clang-format off */ - EM_ASM_({ - delete _as_voices[$0]; - _as_voice_gain[$0].disconnect(_as_voice_pan[$0]); - delete _as_voice_gain[$0]; - _as_voice_pan[$0].disconnect(_as_audioctx.destination); - delete _as_voice_pan[$0]; - }, voice->index); - /* clang-format on */ - - voice_owner.free(p_id); - memdelete(voice); - - } else if (sample_owner.owns(p_id)) { - - Sample *sample = sample_owner.get(p_id); - ERR_FAIL_COND(!sample); - - /* clang-format off */ - EM_ASM_({ - delete _as_samples[$0]; - }, sample->index); - /* clang-format on */ - - sample_owner.free(p_id); - memdelete(sample); - - } else if (stream_owner.owns(p_id)) { - - - Stream *s=stream_owner.get(p_id); - - if (s->active) { - stream_set_active(p_id,false); - } - - memdelete(s); - stream_owner.free(p_id); - } -} - -extern "C" { - - -void audio_server_mix_function(int p_frames) { - - //print_line("MIXI! "+itos(p_frames)); - static_cast<AudioServerJavascript*>(AudioServerJavascript::get_singleton())->mix_to_js(p_frames); -} - -} - -void AudioServerJavascript::mix_to_js(int p_frames) { - - - //process in chunks to make sure to never process more than INTERNAL_BUFFER_SIZE - int todo=p_frames; - int offset=0; - - while(todo) { - - int tomix=MIN(todo,INTERNAL_BUFFER_SIZE); - driver_process_chunk(tomix); - - /* clang-format off */ - EM_ASM_({ - var data = HEAPF32.subarray($0 / 4, $0 / 4 + $2 * 2); - - for (var channel = 0; channel < _as_output_buffer.numberOfChannels; channel++) { - var outputData = _as_output_buffer.getChannelData(channel); - // Loop through samples - for (var sample = 0; sample < $2; sample++) { - // make output equal to the same as the input - outputData[sample + $1] = data[sample * 2 + channel]; - } - } - }, internal_buffer, offset, tomix); - /* clang-format on */ - - todo-=tomix; - offset+=tomix; - } -} - -void AudioServerJavascript::init(){ - - /* - // clang-format off - EM_ASM( - console.log('server is ' + audio_server); - ); - // clang-format on - */ - - - //int latency = GLOBAL_DEF("javascript/audio_latency",16384); - - internal_buffer_channels=2; - internal_buffer = memnew_arr(float,INTERNAL_BUFFER_SIZE*internal_buffer_channels); - stream_buffer = memnew_arr(int32_t,INTERNAL_BUFFER_SIZE*4); //max 4 channels - - stream_volume=0.3; - - int buffer_latency=16384; - - /* clang-format off */ - EM_ASM_( { - _as_script_node = _as_audioctx.createScriptProcessor($0, 0, 2); - _as_script_node.connect(_as_audioctx.destination); - console.log(_as_script_node.bufferSize); - - _as_script_node.onaudioprocess = function(audioProcessingEvent) { - // The output buffer contains the samples that will be modified and played - _as_output_buffer = audioProcessingEvent.outputBuffer; - audio_server_mix_function(_as_output_buffer.getChannelData(0).length); - } - }, buffer_latency); - /* clang-format on */ - - -} - -void AudioServerJavascript::finish(){ - -} -void AudioServerJavascript::update(){ - - for(List<Stream*>::Element *E=active_audio_streams.front();E;) { //stream might be removed durnig this callback - - List<Stream*>::Element *N=E->next(); - - if (E->get()->audio_stream) - E->get()->audio_stream->update(); - - E=N; - } -} - -/* MISC config */ - -void AudioServerJavascript::lock(){ - -} -void AudioServerJavascript::unlock(){ - -} -int AudioServerJavascript::get_default_channel_count() const{ - - return 1; -} -int AudioServerJavascript::get_default_mix_rate() const{ - - return 44100; -} - -void AudioServerJavascript::set_stream_global_volume_scale(float p_volume){ - - stream_volume_scale=p_volume; -} -void AudioServerJavascript::set_fx_global_volume_scale(float p_volume){ - - fx_volume_scale=p_volume; -} -void AudioServerJavascript::set_event_voice_global_volume_scale(float p_volume){ - -} - -float AudioServerJavascript::get_stream_global_volume_scale() const{ - return 1; -} -float AudioServerJavascript::get_fx_global_volume_scale() const{ - - return 1; -} -float AudioServerJavascript::get_event_voice_global_volume_scale() const{ - - return 1; -} - -uint32_t AudioServerJavascript::read_output_peak() const{ - - return 0; -} - -AudioServerJavascript *AudioServerJavascript::singleton=NULL; - -AudioServer *AudioServerJavascript::get_singleton() { - return singleton; -} - -double AudioServerJavascript::get_mix_time() const{ - - return 0; -} -double AudioServerJavascript::get_output_delay() const { - - return 0; -} - - -void AudioServerJavascript::driver_process_chunk(int p_frames) { - - - - int samples=p_frames*internal_buffer_channels; - - for(int i=0;i<samples;i++) { - internal_buffer[i]=0; - } - - - for(List<Stream*>::Element *E=active_audio_streams.front();E;E=E->next()) { - - ERR_CONTINUE(!E->get()->active); // bug? - - - AudioStream *as=E->get()->audio_stream; - if (!as) - continue; - - int channels=as->get_channel_count(); - if (channels==0) - continue; // does not want mix - if (!as->mix(stream_buffer,p_frames)) - continue; //nothing was mixed!! - - int32_t stream_vol_scale=(stream_volume*stream_volume_scale*E->get()->volume_scale)*(1<<STREAM_SCALE_BITS); - -#define STRSCALE(m_val) ((((m_val >> STREAM_SCALE_BITS) * stream_vol_scale) >> 8) / 8388608.0) - switch(channels) { - case 1: { - - for(int i=0;i<p_frames;i++) { - - internal_buffer[(i<<1)+0]+=STRSCALE(stream_buffer[i]); - internal_buffer[(i<<1)+1]+=STRSCALE(stream_buffer[i]); - } - } break; - case 2: { - - for(int i=0;i<p_frames*2;i++) { - - internal_buffer[i]+=STRSCALE(stream_buffer[i]); - } - } break; - case 4: { - - for(int i=0;i<p_frames;i++) { - - internal_buffer[(i<<2)+0]+=STRSCALE((stream_buffer[(i<<2)+0]+stream_buffer[(i<<2)+2])>>1); - internal_buffer[(i<<2)+1]+=STRSCALE((stream_buffer[(i<<2)+1]+stream_buffer[(i<<2)+3])>>1); - } - } break; - - - } - -#undef STRSCALE - } -} - - -/*void AudioServerSW::driver_process(int p_frames,int32_t *p_buffer) { - - - _output_delay=p_frames/double(AudioDriverSW::get_singleton()->get_mix_rate()); - //process in chunks to make sure to never process more than INTERNAL_BUFFER_SIZE - int todo=p_frames; - while(todo) { - - int tomix=MIN(todo,INTERNAL_BUFFER_SIZE); - driver_process_chunk(tomix,p_buffer); - p_buffer+=tomix; - todo-=tomix; - } - - -}*/ - -AudioServerJavascript::AudioServerJavascript() { - - singleton=this; - sample_base=1; - voice_base=1; - /* clang-format off */ - EM_ASM( - _as_samples = {}; - _as_voices = {}; - _as_voice_pan = {}; - _as_voice_gain = {}; - - _as_audioctx = new (window.AudioContext || window.webkitAudioContext)(); - - audio_server_mix_function = Module.cwrap('audio_server_mix_function', 'void', ['number']); - ); - /* clang-format on */ - - /* clang-format off */ - webaudio_mix_rate = EM_ASM_INT_V( - return _as_audioctx.sampleRate; - ); - /* clang-format on */ - print_line("WEBAUDIO MIX RATE: "+itos(webaudio_mix_rate)); - event_voice_scale=1.0; - fx_volume_scale=1.0; - stream_volume_scale=1.0; - -} -#endif diff --git a/platform/javascript/audio_server_javascript.h b/platform/javascript/audio_server_javascript.h deleted file mode 100644 index 0773459f56..0000000000 --- a/platform/javascript/audio_server_javascript.h +++ /dev/null @@ -1,229 +0,0 @@ -/*************************************************************************/ -/* audio_server_javascript.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ -#ifndef AUDIO_SERVER_JAVASCRIPT_H -#define AUDIO_SERVER_JAVASCRIPT_H - -// FIXME: Needs to be ported to the new AudioServer API in 3.0 -#if 0 -#include "servers/audio_server.h" - -class AudioServerJavascript : public AudioServer { - - GDCLASS(AudioServerJavascript,AudioServer); - - enum { - INTERNAL_BUFFER_SIZE=4096, - STREAM_SCALE_BITS=12 - - }; - - AudioMixer *get_mixer(); - void audio_mixer_chunk_callback(int p_frames); - - struct Sample { - SampleFormat format; - SampleLoopFormat loop_format; - int loop_begin; - int loop_end; - int length; - int index; - int mix_rate; - bool stereo; - - Vector<float> tmp_data; - }; - - mutable RID_Owner<Sample> sample_owner; - int sample_base; - - struct Voice { - int index; - float volume; - float pan; - float pan_depth; - float pan_height; - - float chorus; - ReverbRoomType reverb_type; - float reverb; - - int mix_rate; - int sample_mix_rate; - bool positional; - - bool active; - - }; - - mutable RID_Owner<Voice> voice_owner; - - int voice_base; - - struct Stream { - bool active; - List<Stream*>::Element *E; - AudioStream *audio_stream; - EventStream *event_stream; - float volume_scale; - }; - - List<Stream*> active_audio_streams; - - //List<Stream*> event_streams; - - float * internal_buffer; - int internal_buffer_channels; - int32_t * stream_buffer; - - mutable RID_Owner<Stream> stream_owner; - - float stream_volume; - float stream_volume_scale; - - float event_voice_scale; - float fx_volume_scale; - - - void driver_process_chunk(int p_frames); - - int webaudio_mix_rate; - - - static AudioServerJavascript *singleton; -public: - - void mix_to_js(int p_frames); - /* SAMPLE API */ - - virtual RID sample_create(SampleFormat p_format, bool p_stereo, int p_length); - - virtual void sample_set_description(RID p_sample, const String& p_description); - virtual String sample_get_description(RID p_sample) const; - - virtual SampleFormat sample_get_format(RID p_sample) const; - virtual bool sample_is_stereo(RID p_sample) const; - virtual int sample_get_length(RID p_sample) const; - virtual const void* sample_get_data_ptr(RID p_sample) const; - - - virtual void sample_set_data(RID p_sample, const PoolVector<uint8_t>& p_buffer); - virtual PoolVector<uint8_t> sample_get_data(RID p_sample) const; - - virtual void sample_set_mix_rate(RID p_sample,int p_rate); - virtual int sample_get_mix_rate(RID p_sample) const; - - virtual void sample_set_loop_format(RID p_sample,SampleLoopFormat p_format); - virtual SampleLoopFormat sample_get_loop_format(RID p_sample) const; - - virtual void sample_set_loop_begin(RID p_sample,int p_pos); - virtual int sample_get_loop_begin(RID p_sample) const; - - virtual void sample_set_loop_end(RID p_sample,int p_pos); - virtual int sample_get_loop_end(RID p_sample) const; - - - /* VOICE API */ - - virtual RID voice_create(); - - virtual void voice_play(RID p_voice, RID p_sample); - - virtual void voice_set_volume(RID p_voice, float p_volume); - virtual void voice_set_pan(RID p_voice, float p_pan, float p_depth=0,float height=0); //pan and depth go from -1 to 1 - virtual void voice_set_filter(RID p_voice, FilterType p_type, float p_cutoff, float p_resonance, float p_gain=0); - virtual void voice_set_chorus(RID p_voice, float p_chorus ); - virtual void voice_set_reverb(RID p_voice, ReverbRoomType p_room_type, float p_reverb); - virtual void voice_set_mix_rate(RID p_voice, int p_mix_rate); - virtual void voice_set_positional(RID p_voice, bool p_positional); - - virtual float voice_get_volume(RID p_voice) const; - virtual float voice_get_pan(RID p_voice) const; //pan and depth go from -1 to 1 - virtual float voice_get_pan_depth(RID p_voice) const; //pan and depth go from -1 to 1 - virtual float voice_get_pan_height(RID p_voice) const; //pan and depth go from -1 to 1 - virtual FilterType voice_get_filter_type(RID p_voice) const; - virtual float voice_get_filter_cutoff(RID p_voice) const; - virtual float voice_get_filter_resonance(RID p_voice) const; - virtual float voice_get_chorus(RID p_voice) const; - virtual ReverbRoomType voice_get_reverb_type(RID p_voice) const; - virtual float voice_get_reverb(RID p_voice) const; - - virtual int voice_get_mix_rate(RID p_voice) const; - virtual bool voice_is_positional(RID p_voice) const; - - virtual void voice_stop(RID p_voice); - virtual bool voice_is_active(RID p_voice) const; - - /* STREAM API */ - - virtual RID audio_stream_create(AudioStream *p_stream); - virtual RID event_stream_create(EventStream *p_stream); - - virtual void stream_set_active(RID p_stream, bool p_active); - virtual bool stream_is_active(RID p_stream) const; - - virtual void stream_set_volume_scale(RID p_stream, float p_scale); - virtual float stream_set_volume_scale(RID p_stream) const; - - /* Audio Physics API */ - - virtual void free(RID p_id); - - virtual void init(); - virtual void finish(); - virtual void update(); - - /* MISC config */ - - virtual void lock(); - virtual void unlock(); - virtual int get_default_channel_count() const; - virtual int get_default_mix_rate() const; - - virtual void set_stream_global_volume_scale(float p_volume); - virtual void set_fx_global_volume_scale(float p_volume); - virtual void set_event_voice_global_volume_scale(float p_volume); - - virtual float get_stream_global_volume_scale() const; - virtual float get_fx_global_volume_scale() const; - virtual float get_event_voice_global_volume_scale() const; - - virtual uint32_t read_output_peak() const; - - static AudioServer *get_singleton(); - - virtual double get_mix_time() const; //useful for video -> audio sync - virtual double get_output_delay() const; - - - AudioServerJavascript(); -}; - -#endif // AUDIO_SERVER_JAVASCRIPT_H -#endif diff --git a/platform/javascript/detect.py b/platform/javascript/detect.py index cc29ad8956..a2988d9c60 100644 --- a/platform/javascript/detect.py +++ b/platform/javascript/detect.py @@ -13,7 +13,7 @@ def get_name(): def can_build(): - return ("EMSCRIPTEN_ROOT" in os.environ) + return ("EMSCRIPTEN_ROOT" in os.environ or "EMSCRIPTEN" in os.environ) def get_opts(): @@ -66,7 +66,10 @@ def configure(env): ## Compiler configuration env['ENV'] = os.environ - env.PrependENVPath('PATH', os.environ['EMSCRIPTEN_ROOT']) + if ("EMSCRIPTEN_ROOT" in os.environ): + env.PrependENVPath('PATH', os.environ['EMSCRIPTEN_ROOT']) + elif ("EMSCRIPTEN" in os.environ): + env.PrependENVPath('PATH', os.environ['EMSCRIPTEN']) env['CC'] = 'emcc' env['CXX'] = 'em++' env['LINK'] = 'emcc' diff --git a/platform/javascript/http_client.h.inc b/platform/javascript/http_client.h.inc new file mode 100644 index 0000000000..9e4edf7848 --- /dev/null +++ b/platform/javascript/http_client.h.inc @@ -0,0 +1,48 @@ +/*************************************************************************/ +/* http_client.h.inc */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +// HTTPClient's additional private members in the javascript platform + +Error prepare_request(Method p_method, const String &p_url, const Vector<String> &p_headers); + +int xhr_id; +int read_limit; +int response_read_offset; +Status status; + +String host; +int port; +bool use_tls; +String username; +String password; + +int polled_response_code; +String polled_response_header; +PoolByteArray polled_response; diff --git a/platform/javascript/http_client_javascript.cpp b/platform/javascript/http_client_javascript.cpp new file mode 100644 index 0000000000..0b105dcb40 --- /dev/null +++ b/platform/javascript/http_client_javascript.cpp @@ -0,0 +1,282 @@ +/*************************************************************************/ +/* http_client_javascript.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#include "http_request.h" +#include "io/http_client.h" + +Error HTTPClient::connect_to_host(const String &p_host, int p_port, bool p_ssl, bool p_verify_host) { + + close(); + if (p_ssl && !p_verify_host) { + WARN_PRINT("Disabling HTTPClient's host verification is not supported for the HTML5 platform, host will be verified"); + } + + host = p_host; + if (host.begins_with("http://")) { + host.replace_first("http://", ""); + } else if (host.begins_with("https://")) { + host.replace_first("https://", ""); + } + + status = host.is_valid_ip_address() ? STATUS_CONNECTING : STATUS_RESOLVING; + port = p_port; + use_tls = p_ssl; + return OK; +} + +void HTTPClient::set_connection(const Ref<StreamPeer> &p_connection) { + + ERR_EXPLAIN("Accessing an HTTPClient's StreamPeer is not supported for the HTML5 platform"); + ERR_FAIL(); +} + +Ref<StreamPeer> HTTPClient::get_connection() const { + + ERR_EXPLAIN("Accessing an HTTPClient's StreamPeer is not supported for the HTML5 platform"); + ERR_FAIL_V(REF()); +} + +Error HTTPClient::prepare_request(Method p_method, const String &p_url, const Vector<String> &p_headers) { + + ERR_FAIL_INDEX_V(p_method, METHOD_MAX, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(status != STATUS_CONNECTED, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(host.empty(), ERR_UNCONFIGURED); + ERR_FAIL_COND_V(port < 0, ERR_UNCONFIGURED); + + static const char *_methods[HTTPClient::METHOD_MAX] = { + "GET", + "HEAD", + "POST", + "PUT", + "DELETE", + "OPTIONS", + "TRACE", + "CONNECT" + }; + + String url = (use_tls ? "https://" : "http://") + host + ":" + itos(port) + "/" + p_url; + godot_xhr_reset(xhr_id); + godot_xhr_open(xhr_id, _methods[p_method], url.utf8().get_data(), + username.empty() ? NULL : username.utf8().get_data(), + password.empty() ? NULL : password.utf8().get_data()); + + for (int i = 0; i < p_headers.size(); i++) { + int header_separator = p_headers[i].find(": "); + ERR_FAIL_COND_V(header_separator < 0, ERR_INVALID_PARAMETER); + godot_xhr_set_request_header(xhr_id, + p_headers[i].left(header_separator).utf8().get_data(), + p_headers[i].right(header_separator + 2).utf8().get_data()); + } + response_read_offset = 0; + status = STATUS_REQUESTING; + return OK; +} + +Error HTTPClient::request_raw(Method p_method, const String &p_url, const Vector<String> &p_headers, const PoolVector<uint8_t> &p_body) { + + Error err = prepare_request(p_method, p_url, p_headers); + if (err != OK) + return err; + PoolByteArray::Read read = p_body.read(); + godot_xhr_send_data(xhr_id, read.ptr(), p_body.size()); + return OK; +} + +Error HTTPClient::request(Method p_method, const String &p_url, const Vector<String> &p_headers, const String &p_body) { + + Error err = prepare_request(p_method, p_url, p_headers); + if (err != OK) + return err; + godot_xhr_send_string(xhr_id, p_body.utf8().get_data()); + return OK; +} + +void HTTPClient::close() { + + host = ""; + port = -1; + use_tls = false; + status = STATUS_DISCONNECTED; + polled_response.resize(0); + polled_response_code = 0; + polled_response_header = String(); + godot_xhr_reset(xhr_id); +} + +HTTPClient::Status HTTPClient::get_status() const { + + return status; +} + +bool HTTPClient::has_response() const { + + return !polled_response_header.empty(); +} + +bool HTTPClient::is_response_chunked() const { + + // TODO evaluate using moz-chunked-arraybuffer, fetch & ReadableStream + return false; +} + +int HTTPClient::get_response_code() const { + + return polled_response_code; +} + +Error HTTPClient::get_response_headers(List<String> *r_response) { + + if (!polled_response_header.size()) + return ERR_INVALID_PARAMETER; + + Vector<String> header_lines = polled_response_header.split("\r\n", false); + for (int i = 0; i < header_lines.size(); ++i) { + r_response->push_back(header_lines[i]); + } + polled_response_header = String(); + return OK; +} + +int HTTPClient::get_response_body_length() const { + + return polled_response.size(); +} + +PoolByteArray HTTPClient::read_response_body_chunk() { + + ERR_FAIL_COND_V(status != STATUS_BODY, PoolByteArray()); + + int to_read = MIN(read_limit, polled_response.size() - response_read_offset); + PoolByteArray chunk; + chunk.resize(to_read); + PoolByteArray::Write write = chunk.write(); + PoolByteArray::Read read = polled_response.read(); + memcpy(write.ptr(), read.ptr() + response_read_offset, to_read); + write = PoolByteArray::Write(); + read = PoolByteArray::Read(); + response_read_offset += to_read; + + if (response_read_offset == polled_response.size()) { + status = STATUS_CONNECTED; + polled_response.resize(0); + polled_response_code = 0; + polled_response_header = String(); + godot_xhr_reset(xhr_id); + } + + return chunk; +} + +void HTTPClient::set_blocking_mode(bool p_enable) { + + ERR_EXPLAIN("HTTPClient blocking mode is not supported for the HTML5 platform"); + ERR_FAIL_COND(p_enable); +} + +bool HTTPClient::is_blocking_mode_enabled() const { + + return false; +} + +void HTTPClient::set_read_chunk_size(int p_size) { + + read_limit = p_size; +} + +Error HTTPClient::poll() { + + switch (status) { + + case STATUS_DISCONNECTED: + return ERR_UNCONFIGURED; + + case STATUS_RESOLVING: + status = STATUS_CONNECTING; + return OK; + + case STATUS_CONNECTING: + status = STATUS_CONNECTED; + return OK; + + case STATUS_CONNECTED: + case STATUS_BODY: + return OK; + + case STATUS_CONNECTION_ERROR: + return ERR_CONNECTION_ERROR; + + case STATUS_REQUESTING: + polled_response_code = godot_xhr_get_status(xhr_id); + int response_length = godot_xhr_get_response_length(xhr_id); + if (response_length == 0) { + godot_xhr_ready_state_t ready_state = godot_xhr_get_ready_state(xhr_id); + if (ready_state == XHR_READY_STATE_HEADERS_RECEIVED || ready_state == XHR_READY_STATE_LOADING) { + return OK; + } else { + status = STATUS_CONNECTION_ERROR; + return ERR_CONNECTION_ERROR; + } + } + + status = STATUS_BODY; + + PoolByteArray bytes; + int len = godot_xhr_get_response_headers_length(xhr_id); + bytes.resize(len); + PoolByteArray::Write write = bytes.write(); + godot_xhr_get_response_headers(xhr_id, reinterpret_cast<char *>(write.ptr()), len); + write = PoolByteArray::Write(); + + PoolByteArray::Read read = bytes.read(); + polled_response_header = String::utf8(reinterpret_cast<const char *>(read.ptr())); + read = PoolByteArray::Read(); + + polled_response.resize(response_length); + write = polled_response.write(); + godot_xhr_get_response(xhr_id, write.ptr(), response_length); + write = PoolByteArray::Write(); + break; + } + return OK; +} + +HTTPClient::HTTPClient() { + + xhr_id = godot_xhr_new(); + read_limit = 4096; + status = STATUS_DISCONNECTED; + port = -1; + use_tls = false; + polled_response_code = 0; +} + +HTTPClient::~HTTPClient() { + + godot_xhr_free(xhr_id); +} diff --git a/platform/javascript/http_request.h b/platform/javascript/http_request.h new file mode 100644 index 0000000000..80ff3f0ba8 --- /dev/null +++ b/platform/javascript/http_request.h @@ -0,0 +1,72 @@ +/*************************************************************************/ +/* http_request.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#ifndef HTTP_REQUEST_H +#define HTTP_REQUEST_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + XHR_READY_STATE_UNSENT = 0, + XHR_READY_STATE_OPENED = 1, + XHR_READY_STATE_HEADERS_RECEIVED = 2, + XHR_READY_STATE_LOADING = 3, + XHR_READY_STATE_DONE = 4, +} godot_xhr_ready_state_t; + +extern int godot_xhr_new(); +extern void godot_xhr_reset(int p_xhr_id); +extern bool godot_xhr_free(int p_xhr_id); + +extern int godot_xhr_open(int p_xhr_id, const char *p_method, const char *p_url, const char *p_user = NULL, const char *p_password = NULL); + +extern void godot_xhr_set_request_header(int p_xhr_id, const char *p_header, const char *p_value); + +extern void godot_xhr_send_null(int p_xhr_id); +extern void godot_xhr_send_string(int p_xhr_id, const char *p_data); +extern void godot_xhr_send_data(int p_xhr_id, const void *p_data, int p_len); +extern void godot_xhr_abort(int p_xhr_id); + +/* this is an HTTPClient::ResponseCode, not ::Status */ +extern int godot_xhr_get_status(int p_xhr_id); +extern godot_xhr_ready_state_t godot_xhr_get_ready_state(int p_xhr_id); + +extern int godot_xhr_get_response_headers_length(int p_xhr_id); +extern void godot_xhr_get_response_headers(int p_xhr_id, char *r_dst, int p_len); + +extern int godot_xhr_get_response_length(int p_xhr_id); +extern void godot_xhr_get_response(int p_xhr_id, void *r_dst, int p_len); + +#ifdef __cplusplus +} +#endif + +#endif /* HTTP_REQUEST_H */ diff --git a/platform/javascript/http_request.js b/platform/javascript/http_request.js new file mode 100644 index 0000000000..f30240b41b --- /dev/null +++ b/platform/javascript/http_request.js @@ -0,0 +1,145 @@ +/*************************************************************************/ +/* http_request.js */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +var GodotHTTPRequest = { + + $GodotHTTPRequest: { + + requests: [], + + getUnusedRequestId: function() { + var idMax = GodotHTTPRequest.requests.length; + for (var potentialId = 0; potentialId < idMax; ++potentialId) { + if (GodotHTTPRequest.requests[potentialId] instanceof XMLHttpRequest) { + continue; + } + return potentialId; + } + GodotHTTPRequest.requests.push(null) + return idMax; + }, + + setupRequest: function(xhr) { + xhr.responseType = 'arraybuffer'; + }, + }, + + godot_xhr_new: function() { + var newId = GodotHTTPRequest.getUnusedRequestId(); + GodotHTTPRequest.requests[newId] = new XMLHttpRequest; + GodotHTTPRequest.setupRequest(GodotHTTPRequest.requests[newId]); + return newId; + }, + + godot_xhr_reset: function(xhrId) { + GodotHTTPRequest.requests[xhrId] = new XMLHttpRequest; + GodotHTTPRequest.setupRequest(GodotHTTPRequest.requests[xhrId]); + }, + + godot_xhr_free: function(xhrId) { + GodotHTTPRequest.requests[xhrId].abort(); + GodotHTTPRequest.requests[xhrId] = null; + }, + + godot_xhr_open: function(xhrId, method, url, user, password) { + user = user > 0 ? UTF8ToString(user) : null; + password = password > 0 ? UTF8ToString(password) : null; + GodotHTTPRequest.requests[xhrId].open(UTF8ToString(method), UTF8ToString(url), true, user, password); + }, + + godot_xhr_set_request_header: function(xhrId, header, value) { + GodotHTTPRequest.requests[xhrId].setRequestHeader(UTF8ToString(header), UTF8ToString(value)); + }, + + godot_xhr_send_null: function(xhrId) { + GodotHTTPRequest.requests[xhrId].send(); + }, + + godot_xhr_send_string: function(xhrId, strPtr) { + if (!strPtr) { + Module.printErr("Failed to send string per XHR: null pointer"); + return; + } + GodotHTTPRequest.requests[xhrId].send(UTF8ToString(strPtr)); + }, + + godot_xhr_send_data: function(xhrId, ptr, len) { + if (!ptr) { + Module.printErr("Failed to send data per XHR: null pointer"); + return; + } + if (len < 0) { + Module.printErr("Failed to send data per XHR: buffer length less than 0"); + return; + } + GodotHTTPRequest.requests[xhrId].send(HEAPU8.subarray(ptr, ptr + len)); + }, + + godot_xhr_abort: function(xhrId) { + GodotHTTPRequest.requests[xhrId].abort(); + }, + + godot_xhr_get_status: function(xhrId) { + return GodotHTTPRequest.requests[xhrId].status; + }, + + godot_xhr_get_ready_state: function(xhrId) { + return GodotHTTPRequest.requests[xhrId].readyState; + }, + + godot_xhr_get_response_headers_length: function(xhrId) { + var headers = GodotHTTPRequest.requests[xhrId].getAllResponseHeaders(); + return headers === null ? 0 : lengthBytesUTF8(headers); + }, + + godot_xhr_get_response_headers: function(xhrId, dst, len) { + var str = GodotHTTPRequest.requests[xhrId].getAllResponseHeaders(); + if (str === null) + return; + var buf = new Uint8Array(len + 1); + stringToUTF8Array(str, buf, 0, buf.length); + buf = buf.subarray(0, -1); + HEAPU8.set(buf, dst); + }, + + godot_xhr_get_response_length: function(xhrId) { + var body = GodotHTTPRequest.requests[xhrId].response; + return body === null ? 0 : body.byteLength; + }, + + godot_xhr_get_response: function(xhrId, dst, len) { + var buf = GodotHTTPRequest.requests[xhrId].response; + if (buf === null) + return; + buf = new Uint8Array(buf).subarray(0, len); + HEAPU8.set(buf, dst); + }, +}; + +autoAddDeps(GodotHTTPRequest, "$GodotHTTPRequest"); +mergeInto(LibraryManager.library, GodotHTTPRequest); diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp index f6446e77da..389d5d206e 100644 --- a/platform/javascript/os_javascript.cpp +++ b/platform/javascript/os_javascript.cpp @@ -64,11 +64,6 @@ const char *OS_JavaScript::get_video_driver_name(int p_driver) const { return "GLES3"; } -OS::VideoMode OS_JavaScript::get_default_video_mode() const { - - return OS::VideoMode(); -} - int OS_JavaScript::get_audio_driver_count() const { return 1; @@ -171,14 +166,15 @@ static EM_BOOL _mousebutton_callback(int event_type, const EmscriptenMouseEvent } 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 if (!is_canvas_focused()) { focus_canvas(); } - mask |= ev->get_button_index(); - } else if (mask & ev->get_button_index()) { - mask &= ~ev->get_button_index(); + mask |= button_flag; + } else if (mask & button_flag) { + mask &= ~button_flag; } else { // release event, but press was outside the canvas, so ignore return false; @@ -480,11 +476,6 @@ void OS_JavaScript::initialize(const VideoMode &p_desired, int p_video_driver, i print_line("Init Physicsserver"); - physics_server = memnew(PhysicsServerSW); - physics_server->init(); - physics_2d_server = memnew(Physics2DServerSW); - physics_2d_server->init(); - input = memnew(InputDefault); _input = input; diff --git a/platform/javascript/os_javascript.h b/platform/javascript/os_javascript.h index 1c939d3fd5..f478f95dd2 100644 --- a/platform/javascript/os_javascript.h +++ b/platform/javascript/os_javascript.h @@ -31,7 +31,6 @@ #define OS_JAVASCRIPT_H #include "audio_driver_javascript.h" -#include "audio_server_javascript.h" #include "drivers/unix/os_unix.h" #include "javascript_eval.h" #include "main/input_default.h" @@ -39,8 +38,6 @@ #include "os/main_loop.h" #include "power_javascript.h" #include "servers/audio_server.h" -#include "servers/physics/physics_server_sw.h" -#include "servers/physics_2d/physics_2d_server_sw.h" #include "servers/visual/rasterizer.h" #include <emscripten/html5.h> @@ -54,8 +51,6 @@ class OS_JavaScript : public OS_Unix { int64_t last_sync_time; VisualServer *visual_server; - PhysicsServer *physics_server; - Physics2DServer *physics_2d_server; AudioDriverJavaScript audio_driver_javascript; const char *gl_extensions; @@ -88,8 +83,6 @@ public: virtual int get_video_driver_count() const; virtual const char *get_video_driver_name(int p_driver) const; - virtual VideoMode get_default_video_mode() const; - virtual int get_audio_driver_count() const; virtual const char *get_audio_driver_name(int p_driver) const; diff --git a/platform/osx/crash_handler_osx.mm b/platform/osx/crash_handler_osx.mm index 2ed88db309..5635fe0187 100644 --- a/platform/osx/crash_handler_osx.mm +++ b/platform/osx/crash_handler_osx.mm @@ -29,6 +29,7 @@ /*************************************************************************/ #include "main/main.h" #include "os_osx.h" +#include "project_settings.h" #include <string.h> #include <unistd.h> diff --git a/platform/osx/export/export.cpp b/platform/osx/export/export.cpp index 0ba0ddec7d..8a6f1dc04c 100644 --- a/platform/osx/export/export.cpp +++ b/platform/osx/export/export.cpp @@ -244,7 +244,7 @@ Error EditorExportPlatformOSX::_code_sign(const Ref<EditorExportPreset> &p_prese args.push_back(p_path); String str; - Error err = OS::get_singleton()->execute("/usr/bin/codesign", args, true, NULL, &str, NULL, true); + Error err = OS::get_singleton()->execute("codesign", args, true, NULL, &str, NULL, true); ERR_FAIL_COND_V(err != OK, err); print_line("codesign: " + str); @@ -271,7 +271,7 @@ Error EditorExportPlatformOSX::_create_dmg(const String &p_dmg_path, const Strin args.push_back(p_app_path_name); String str; - Error err = OS::get_singleton()->execute("/usr/bin/hdiutil", args, true, NULL, &str, NULL, true); + Error err = OS::get_singleton()->execute("hdiutil", args, true, NULL, &str, NULL, true); ERR_FAIL_COND_V(err != OK, err); print_line("hdiutil returned: " + str); diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h index 05adfeb0f5..53f45511f9 100644 --- a/platform/osx/os_osx.h +++ b/platform/osx/os_osx.h @@ -38,9 +38,6 @@ #include "os/input.h" #include "power_osx.h" #include "servers/audio_server.h" -#include "servers/physics_2d/physics_2d_server_sw.h" -#include "servers/physics_2d/physics_2d_server_wrap_mt.h" -#include "servers/physics_server.h" #include "servers/visual/rasterizer.h" #include "servers/visual/visual_server_wrap_mt.h" #include "servers/visual_server.h" @@ -62,9 +59,6 @@ public: List<String> args; MainLoop *main_loop; - PhysicsServer *physics_server; - Physics2DServer *physics_2d_server; - IP_Unix *ip_unix; AudioDriverCoreAudio audio_driver; @@ -126,7 +120,6 @@ public: protected: virtual int get_video_driver_count() const; virtual const char *get_video_driver_name(int p_driver) const; - virtual VideoMode get_default_video_mode() const; virtual void initialize_logger(); virtual void initialize_core(); @@ -219,6 +212,9 @@ public: virtual bool _check_internal_feature_support(const String &p_feature); + virtual void set_use_vsync(bool p_enable); + virtual bool is_vsync_enabled() const; + void run(); void set_mouse_mode(MouseMode p_mode); diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm index 2c81a02014..6faa8e12ed 100644 --- a/platform/osx/os_osx.mm +++ b/platform/osx/os_osx.mm @@ -35,7 +35,6 @@ #include "os/keyboard.h" #include "print_string.h" #include "sem_osx.h" -#include "servers/physics/physics_server_sw.h" #include "servers/visual/visual_server_raster.h" #include <Carbon/Carbon.h> @@ -900,16 +899,6 @@ const char *OS_OSX::get_video_driver_name(int p_driver) const { return "GLES2"; } -OS::VideoMode OS_OSX::get_default_video_mode() const { - - VideoMode vm; - vm.width = 1024; - vm.height = 600; - vm.fullscreen = false; - vm.resizable = true; - return vm; -} - void OS_OSX::initialize_core() { crash_handler.initialize(); @@ -1092,13 +1081,6 @@ void OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_au AudioDriverManager::initialize(p_audio_driver); - // - physics_server = memnew(PhysicsServerSW); - physics_server->init(); - //physics_2d_server = memnew( Physics2DServerSW ); - physics_2d_server = Physics2DServerWrapMT::init_server<Physics2DServerSW>(); - physics_2d_server->init(); - input = memnew(InputDefault); joypad_osx = memnew(JoypadOSX); @@ -1120,12 +1102,6 @@ void OS_OSX::finalize() { visual_server->finish(); memdelete(visual_server); //memdelete(rasterizer); - - physics_server->finish(); - memdelete(physics_server); - - physics_2d_server->finish(); - memdelete(physics_2d_server); } void OS_OSX::set_main_loop(MainLoop *p_main_loop) { @@ -1206,7 +1182,9 @@ typedef UnixTerminalLogger OSXTerminalLogger; void OS_OSX::initialize_logger() { Vector<Logger *> loggers; loggers.push_back(memnew(OSXTerminalLogger)); - loggers.push_back(memnew(RotatedFileLogger("user://logs/log.txt"))); + // FIXME: Reenable once we figure out how to get this properly in user:// + // instead of littering the user's working dirs (res:// + pwd) with log files (GH-12277) + //loggers.push_back(memnew(RotatedFileLogger("user://logs/log.txt"))); _set_logger(memnew(CompositeLogger(loggers))); } @@ -1832,6 +1810,8 @@ OS::LatinKeyboardVariant OS_OSX::get_latin_keyboard_variant() const { layout = LATIN_KEYBOARD_DVORAK; } else if ([test isEqualToString:@"xvlcwk"]) { layout = LATIN_KEYBOARD_NEO; + } else if ([test isEqualToString:@"qwfpgj"]) { + layout = LATIN_KEYBOARD_COLEMAK; } [test release]; @@ -1954,6 +1934,23 @@ Error OS_OSX::move_to_trash(const String &p_path) { return OK; } +void OS_OSX::set_use_vsync(bool p_enable) { + CGLContextObj ctx = CGLGetCurrentContext(); + if (ctx) { + GLint swapInterval = p_enable ? 1 : 0; + CGLSetParameter(ctx, kCGLCPSwapInterval, &swapInterval); + } +} + +bool OS_OSX::is_vsync_enabled() const { + GLint swapInterval = 0; + CGLContextObj ctx = CGLGetCurrentContext(); + if (ctx) { + CGLGetParameter(ctx, kCGLCPSwapInterval, &swapInterval); + } + return swapInterval ? true : false; +} + OS_OSX *OS_OSX::singleton = NULL; OS_OSX::OS_OSX() { diff --git a/platform/server/detect.py b/platform/server/detect.py index 04b38f280d..ffec2af933 100644 --- a/platform/server/detect.py +++ b/platform/server/detect.py @@ -12,6 +12,9 @@ def get_name(): def can_build(): + # Doesn't build against Godot 3.0 for now, disable to avoid confusing users + return False + if (os.name != "posix" or sys.platform == "darwin"): return False diff --git a/platform/server/os_server.cpp b/platform/server/os_server.cpp index 300c5cffcc..ca73f610e4 100644 --- a/platform/server/os_server.cpp +++ b/platform/server/os_server.cpp @@ -31,7 +31,6 @@ //#include "servers/visual/rasterizer_dummy.h" #include "os_server.h" #include "print_string.h" -#include "servers/physics/physics_server_sw.h" #include <stdio.h> #include <stdlib.h> @@ -47,10 +46,6 @@ const char *OS_Server::get_video_driver_name(int p_driver) const { return "Dummy"; } -OS::VideoMode OS_Server::get_default_video_mode() const { - - return OS::VideoMode(800, 600, false); -} void OS_Server::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) { @@ -75,11 +70,6 @@ void OS_Server::initialize(const VideoMode &p_desired, int p_video_driver, int p ERR_FAIL_COND(!visual_server); visual_server->init(); - // - physics_server = memnew(PhysicsServerSW); - physics_server->init(); - physics_2d_server = memnew(Physics2DServerSW); - physics_2d_server->init(); input = memnew(InputDefault); @@ -111,12 +101,6 @@ void OS_Server::finalize() { memdelete(visual_server); //memdelete(rasterizer); - physics_server->finish(); - memdelete(physics_server); - - physics_2d_server->finish(); - memdelete(physics_2d_server); - memdelete(input); args.clear(); diff --git a/platform/server/os_server.h b/platform/server/os_server.h index ba12f649be..03f7c2a6c8 100644 --- a/platform/server/os_server.h +++ b/platform/server/os_server.h @@ -35,8 +35,6 @@ #include "drivers/unix/os_unix.h" #include "main/input_default.h" #include "servers/audio_server.h" -#include "servers/physics_2d/physics_2d_server_sw.h" -#include "servers/physics_server.h" #include "servers/visual/rasterizer.h" #include "servers/visual_server.h" @@ -56,9 +54,6 @@ class OS_Server : public OS_Unix { bool grab; - PhysicsServer *physics_server; - Physics2DServer *physics_2d_server; - virtual void delete_main_loop(); IP_Unix *ip_unix; @@ -71,7 +66,6 @@ class OS_Server : public OS_Unix { protected: virtual int get_video_driver_count() const; virtual const char *get_video_driver_name(int p_driver) const; - virtual VideoMode get_default_video_mode() const; virtual void initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); virtual void finalize(); diff --git a/platform/uwp/SCsub b/platform/uwp/SCsub index 7ee5aa2ac3..bbd329a7e5 100644 --- a/platform/uwp/SCsub +++ b/platform/uwp/SCsub @@ -8,6 +8,7 @@ files = [ '#platform/windows/packet_peer_udp_winsock.cpp', '#platform/windows/stream_peer_winsock.cpp', '#platform/windows/key_mapping_win.cpp', + '#platform/windows/windows_terminal_logger.cpp', 'joypad_uwp.cpp', 'power_uwp.cpp', 'gl_context_egl.cpp', diff --git a/platform/uwp/detect.py b/platform/uwp/detect.py index af53f97446..434c597449 100644 --- a/platform/uwp/detect.py +++ b/platform/uwp/detect.py @@ -84,7 +84,7 @@ def configure(env): ## Architecture arch = "" - if os.getenv('Platform') == "ARM": + if str(os.getenv('Platform')).lower() == "arm": print("Compiled program architecture will be an ARM executable. (forcing bits=32).") diff --git a/platform/uwp/gl_context_egl.cpp b/platform/uwp/gl_context_egl.cpp index ed3db65cdf..dafe5d5e25 100644 --- a/platform/uwp/gl_context_egl.cpp +++ b/platform/uwp/gl_context_egl.cpp @@ -101,26 +101,25 @@ Error ContextEGL::initialize() { try { - const EGLint displayAttributes[] = - { - /*EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, - EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, 9, - EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE, 3, - EGL_NONE,*/ - // These are the default display attributes, used to request ANGLE's D3D11 renderer. - // eglInitialize will only succeed with these attributes if the hardware supports D3D11 Feature Level 10_0+. - EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, - - // 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_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. - // Calling IDXGIDevice3::Trim when an application is suspended is a Windows Store application certification requirement. - EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, EGL_TRUE, - EGL_NONE, - }; + const EGLint displayAttributes[] = { + /*EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, + EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, 9, + EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE, 3, + EGL_NONE,*/ + // These are the default display attributes, used to request ANGLE's D3D11 renderer. + // eglInitialize will only succeed with these attributes if the hardware supports D3D11 Feature Level 10_0+. + EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, + + // 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_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. + // Calling IDXGIDevice3::Trim when an application is suspended is a Windows Store application certification requirement. + EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, EGL_TRUE, + EGL_NONE, + }; PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = reinterpret_cast<PFNEGLGETPLATFORMDISPLAYEXTPROC>(eglGetProcAddress("eglGetPlatformDisplayEXT")); diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp index ff5a935229..acb0ba4bca 100644 --- a/platform/uwp/os_uwp.cpp +++ b/platform/uwp/os_uwp.cpp @@ -72,11 +72,6 @@ const char *OSUWP::get_video_driver_name(int p_driver) const { return "GLES2"; } -OS::VideoMode OSUWP::get_default_video_mode() const { - - return video_mode; -} - Size2 OSUWP::get_window_size() const { Size2 size; size.width = video_mode.width; @@ -186,7 +181,9 @@ void OSUWP::initialize_core() { void OSUWP::initialize_logger() { Vector<Logger *> loggers; loggers.push_back(memnew(WindowsTerminalLogger)); - loggers.push_back(memnew(RotatedFileLogger("user://logs/log.txt"))); + // FIXME: Reenable once we figure out how to get this properly in user:// + // instead of littering the user's working dirs (res:// + pwd) with log files (GH-12277) + //loggers.push_back(memnew(RotatedFileLogger("user://logs/log.txt"))); _set_logger(memnew(CompositeLogger(loggers))); } @@ -262,13 +259,6 @@ void OSUWP::initialize(const VideoMode &p_desired, int p_video_driver, int p_aud } */ - // - physics_server = memnew(PhysicsServerSW); - physics_server->init(); - - physics_2d_server = memnew(Physics2DServerSW); - physics_2d_server->init(); - visual_server->init(); input = memnew(InputDefault); @@ -367,12 +357,6 @@ void OSUWP::finalize() { memdelete(input); - physics_server->finish(); - memdelete(physics_server); - - physics_2d_server->finish(); - memdelete(physics_2d_server); - joypad = nullptr; } diff --git a/platform/uwp/os_uwp.h b/platform/uwp/os_uwp.h index 22f8938049..2931e9b07d 100644 --- a/platform/uwp/os_uwp.h +++ b/platform/uwp/os_uwp.h @@ -40,8 +40,6 @@ #include "os/os.h" #include "power_uwp.h" #include "servers/audio_server.h" -#include "servers/physics/physics_server_sw.h" -#include "servers/physics_2d/physics_2d_server_sw.h" #include "servers/visual/rasterizer.h" #include "servers/visual_server.h" @@ -94,8 +92,6 @@ private: int old_x, old_y; Point2i center; VisualServer *visual_server; - PhysicsServer *physics_server; - Physics2DServer *physics_2d_server; int pressrc; ContextEGL *gl_context; @@ -158,8 +154,6 @@ protected: virtual int get_video_driver_count() const; virtual const char *get_video_driver_name(int p_driver) const; - virtual VideoMode get_default_video_mode() const; - virtual int get_audio_driver_count() const; virtual const char *get_audio_driver_name(int p_driver) const; diff --git a/platform/windows/context_gl_win.cpp b/platform/windows/context_gl_win.cpp index 64b6d202a1..8571f0dc65 100644 --- a/platform/windows/context_gl_win.cpp +++ b/platform/windows/context_gl_win.cpp @@ -165,7 +165,7 @@ Error ContextGL_Win::initialize() { WGL_CONTEXT_MAJOR_VERSION_ARB, 3, //we want a 3.3 context WGL_CONTEXT_MINOR_VERSION_ARB, 3, //and it shall be forward compatible so that we can only use up to date functionality - WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB | _WGL_CONTEXT_DEBUG_BIT_ARB, + WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB /*| _WGL_CONTEXT_DEBUG_BIT_ARB*/, 0 }; //zero indicates the end of the array diff --git a/platform/windows/crash_handler_win.cpp b/platform/windows/crash_handler_win.cpp index 2f5ee7956e..feea3911b2 100644 --- a/platform/windows/crash_handler_win.cpp +++ b/platform/windows/crash_handler_win.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "main/main.h" #include "os_windows.h" +#include "project_settings.h" #ifdef CRASH_HANDLER_EXCEPTION diff --git a/platform/windows/detect.py b/platform/windows/detect.py index 031b397988..fbb02c9d1b 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -44,7 +44,6 @@ def can_build(): if (os.system(mingw64 + test) == 0 or os.system(mingw32 + test) == 0): return True - print("Could not detect MinGW. Ensure its binaries are in your PATH or that MINGW32_PREFIX or MINGW64_PREFIX are properly defined.") return False @@ -65,7 +64,6 @@ def get_opts(): return [ ('mingw_prefix_32', 'MinGW prefix (Win32)', mingw32), ('mingw_prefix_64', 'MinGW prefix (Win64)', mingw64), - BoolVariable('use_lto', 'Use link time optimization (when using MingW)', False), EnumVariable('debug_symbols', 'Add debug symbols to release version', 'yes', ('yes', 'no', 'full')), ] @@ -265,10 +263,7 @@ def configure(env): if env['use_lto']: env.Append(CCFLAGS=['-flto']) - if not env['use_llvm'] and env.GetOption("num_jobs") > 1: - env.Append(LINKFLAGS=['-flto=' + str(env.GetOption("num_jobs"))]) - else: - env.Append(LINKFLAGS=['-flto']) + env.Append(LINKFLAGS=['-flto=' + str(env.GetOption("num_jobs"))]) ## Compile flags diff --git a/platform/windows/key_mapping_win.cpp b/platform/windows/key_mapping_win.cpp index 57f8e965de..76bb5d5723 100644 --- a/platform/windows/key_mapping_win.cpp +++ b/platform/windows/key_mapping_win.cpp @@ -50,7 +50,7 @@ static _WinTranslatePair _vk_to_keycode[] = { { KEY_CONTROL, VK_CONTROL }, //(0x11) - { KEY_MENU, VK_MENU }, //(0x12) + { KEY_ALT, VK_MENU }, //(0x12) { KEY_PAUSE, VK_PAUSE }, //(0x13) diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index c27e7c0d2b..0f62dbb9e8 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -42,7 +42,6 @@ #include "lang_table.h" #include "main/main.h" #include "packet_peer_udp_winsock.h" -#include "project_settings.h" #include "servers/audio_server.h" #include "servers/visual/visual_server_raster.h" #include "servers/visual/visual_server_wrap_mt.h" @@ -147,11 +146,6 @@ const char *OS_Windows::get_video_driver_name(int p_driver) const { return "GLES2"; } -OS::VideoMode OS_Windows::get_default_video_mode() const { - - return VideoMode(1024, 600, false); -} - int OS_Windows::get_audio_driver_count() const { return AudioDriverManager::get_driver_count(); @@ -209,7 +203,9 @@ void OS_Windows::initialize_core() { void OS_Windows::initialize_logger() { Vector<Logger *> loggers; loggers.push_back(memnew(WindowsTerminalLogger)); - loggers.push_back(memnew(RotatedFileLogger("user://logs/log.txt"))); + // FIXME: Reenable once we figure out how to get this properly in user:// + // instead of littering the user's working dirs (res:// + pwd) with log files (GH-12277) + //loggers.push_back(memnew(RotatedFileLogger("user://logs/log.txt"))); _set_logger(memnew(CompositeLogger(loggers))); } @@ -1056,12 +1052,6 @@ void OS_Windows::initialize(const VideoMode &p_desired, int p_video_driver, int visual_server = memnew(VisualServerWrapMT(visual_server, get_render_thread_mode() == RENDER_SEPARATE_THREAD)); } - physics_server = memnew(PhysicsServerSW); - physics_server->init(); - - physics_2d_server = Physics2DServerWrapMT::init_server<Physics2DServerSW>(); - physics_2d_server->init(); - if (!is_no_window_mode_enabled()) { ShowWindow(hWnd, SW_SHOW); // Show The Window SetForegroundWindow(hWnd); // Slightly Higher Priority @@ -1223,12 +1213,6 @@ void OS_Windows::finalize() { memdelete(debugger_connection_console); } */ - - physics_server->finish(); - memdelete(physics_server); - - physics_2d_server->finish(); - memdelete(physics_2d_server); } void OS_Windows::finalize_core() { diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index c0b8dfc691..fbd60e5f0d 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -29,8 +29,8 @@ /*************************************************************************/ #ifndef OS_WINDOWS_H #define OS_WINDOWS_H - #include "context_gl_win.h" +#include "core/project_settings.h" #include "crash_handler_win.h" #include "drivers/rtaudio/audio_driver_rtaudio.h" #include "drivers/wasapi/audio_driver_wasapi.h" @@ -38,7 +38,6 @@ #include "os/os.h" #include "power_windows.h" #include "servers/audio_server.h" -#include "servers/physics/physics_server_sw.h" #include "servers/visual/rasterizer.h" #include "servers/visual_server.h" #ifdef XAUDIO2_ENABLED @@ -47,8 +46,6 @@ #include "drivers/unix/ip_unix.h" #include "key_mapping_win.h" #include "main/input_default.h" -#include "servers/physics_2d/physics_2d_server_sw.h" -#include "servers/physics_2d/physics_2d_server_wrap_mt.h" #include <fcntl.h> #include <io.h> @@ -90,8 +87,6 @@ class OS_Windows : public OS { ContextGL_Win *gl_context; #endif VisualServer *visual_server; - PhysicsServer *physics_server; - Physics2DServer *physics_2d_server; int pressrc; HDC hDC; // Private GDI Device Context HINSTANCE hInstance; // Holds The Instance Of The Application @@ -147,8 +142,6 @@ protected: virtual int get_video_driver_count() const; virtual const char *get_video_driver_name(int p_driver) const; - virtual VideoMode get_default_video_mode() const; - virtual int get_audio_driver_count() const; virtual const char *get_audio_driver_name(int p_driver) const; diff --git a/platform/x11/crash_handler_x11.cpp b/platform/x11/crash_handler_x11.cpp index 3c54d5cbc2..005a7459f9 100644 --- a/platform/x11/crash_handler_x11.cpp +++ b/platform/x11/crash_handler_x11.cpp @@ -33,6 +33,7 @@ #include "main/main.h" #include "os_x11.h" +#include "project_settings.h" #ifdef CRASH_HANDLER_ENABLED #include <cxxabi.h> diff --git a/platform/x11/detect.py b/platform/x11/detect.py index 1f7f67fe10..6bd0ac8317 100644 --- a/platform/x11/detect.py +++ b/platform/x11/detect.py @@ -52,7 +52,6 @@ def get_opts(): BoolVariable('use_static_cpp', 'Link stdc++ statically', False), BoolVariable('use_sanitizer', 'Use LLVM compiler address sanitizer', False), BoolVariable('use_leak_sanitizer', 'Use LLVM compiler memory leaks sanitizer (implies use_sanitizer)', False), - BoolVariable('use_lto', 'Use link time optimization', False), BoolVariable('pulseaudio', 'Detect & use pulseaudio', True), BoolVariable('udev', 'Use udev for gamepad connection callbacks', False), EnumVariable('debug_symbols', 'Add debug symbols to release version', 'yes', ('yes', 'no', 'full')), @@ -101,6 +100,10 @@ def configure(env): ## Compiler configuration + if 'CXX' in env and 'clang' in env['CXX']: + # Convenience check to enforce the use_llvm overrides when CXX is clang(++) + env['use_llvm'] = True + if env['use_llvm']: if ('clang++' not in env['CXX']): env["CC"] = "clang" @@ -239,6 +242,9 @@ def configure(env): if (platform.system() == "Linux"): env.Append(LIBS=['dl']) + if (platform.system().find("BSD") >= 0): + env.Append(LIBS=['execinfo']) + ## Cross-compilation if (is64 and env["bits"] == "32"): diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp index e389c6932e..f018145d82 100644 --- a/platform/x11/os_x11.cpp +++ b/platform/x11/os_x11.cpp @@ -32,10 +32,13 @@ #include "errno.h" #include "key_mapping_x11.h" #include "print_string.h" -#include "servers/physics/physics_server_sw.h" #include "servers/visual/visual_server_raster.h" #include "servers/visual/visual_server_wrap_mt.h" + +#ifdef HAVE_MNTENT #include <mntent.h> +#endif + #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -79,10 +82,6 @@ const char *OS_X11::get_video_driver_name(int p_driver) const { return "GLES3"; } -OS::VideoMode OS_X11::get_default_video_mode() const { - return OS::VideoMode(1024, 600, false); -} - int OS_X11::get_audio_driver_count() const { return AudioDriverManager::get_driver_count(); } @@ -458,12 +457,6 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au requested = None; visual_server->init(); - // - physics_server = memnew(PhysicsServerSW); - physics_server->init(); - //physics_2d_server = memnew( Physics2DServerSW ); - physics_2d_server = Physics2DServerWrapMT::init_server<Physics2DServerSW>(); - physics_2d_server->init(); input = memnew(InputDefault); @@ -519,12 +512,6 @@ void OS_X11::finalize() { memdelete(visual_server); //memdelete(rasterizer); - physics_server->finish(); - memdelete(physics_server); - - physics_2d_server->finish(); - memdelete(physics_2d_server); - memdelete(power_manager); if (xrandr_handle) @@ -1939,7 +1926,7 @@ Error OS_X11::shell_open(String p_uri) { Error ok; List<String> args; args.push_back(p_uri); - ok = execute("/usr/bin/xdg-open", args, false); + ok = execute("xdg-open", args, false); if (ok == OK) return OK; ok = execute("gnome-open", args, false); @@ -2003,7 +1990,7 @@ String OS_X11::get_system_dir(SystemDir p_dir) const { String pipe; List<String> arg; arg.push_back(xdgparam); - Error err = const_cast<OS_X11 *>(this)->execute("/usr/bin/xdg-user-dir", arg, true, NULL, &pipe); + Error err = const_cast<OS_X11 *>(this)->execute("xdg-user-dir", arg, true, NULL, &pipe); if (err != OK) return "."; return pipe.strip_edges(); @@ -2053,7 +2040,7 @@ void OS_X11::alert(const String &p_alert, const String &p_title) { args.push_back(p_title); args.push_back(p_alert); - execute("/usr/bin/xmessage", args, true); + execute("xmessage", args, true); } void OS_X11::set_icon(const Ref<Image> &p_icon) { @@ -2182,6 +2169,7 @@ static String get_mountpoint(const String &p_path) { return ""; } +#ifdef HAVE_MNTENT dev_t dev = s.st_dev; FILE *fd = setmntent("/proc/mounts", "r"); if (!fd) { @@ -2199,6 +2187,7 @@ static String get_mountpoint(const String &p_path) { } endmntent(fd); +#endif return ""; } @@ -2236,17 +2225,49 @@ Error OS_X11::move_to_trash(const String &p_path) { List<String> args; args.push_back("-p"); args.push_back(trashcan); - Error err = execute("/bin/mkdir", args, true); + Error err = execute("mkdir", args, true); if (err == OK) { List<String> args2; args2.push_back(p_path); args2.push_back(trashcan); - err = execute("/bin/mv", args2, true); + err = execute("mv", args2, true); } return err; } +OS::LatinKeyboardVariant OS_X11::get_latin_keyboard_variant() const { + + XkbDescRec *xkbdesc = XkbAllocKeyboard(); + ERR_FAIL_COND_V(!xkbdesc, LATIN_KEYBOARD_QWERTY); + + XkbGetNames(x11_display, XkbSymbolsNameMask, xkbdesc); + ERR_FAIL_COND_V(!xkbdesc->names, LATIN_KEYBOARD_QWERTY); + ERR_FAIL_COND_V(!xkbdesc->names->symbols, LATIN_KEYBOARD_QWERTY); + + char *layout = XGetAtomName(x11_display, xkbdesc->names->symbols); + ERR_FAIL_COND_V(!layout, LATIN_KEYBOARD_QWERTY); + + Vector<String> info = String(layout).split("+"); + ERR_FAIL_INDEX_V(1, info.size(), LATIN_KEYBOARD_QWERTY); + + if (info[1].find("colemak") != -1) { + return LATIN_KEYBOARD_COLEMAK; + } else if (info[1].find("qwertz") != -1) { + return LATIN_KEYBOARD_QWERTZ; + } else if (info[1].find("azerty") != -1) { + return LATIN_KEYBOARD_AZERTY; + } else if (info[1].find("qzerty") != -1) { + return LATIN_KEYBOARD_QZERTY; + } else if (info[1].find("dvorak") != -1) { + return LATIN_KEYBOARD_DVORAK; + } else if (info[1].find("neo") != -1) { + return LATIN_KEYBOARD_NEO; + } + + return LATIN_KEYBOARD_QWERTY; +} + OS_X11::OS_X11() { #ifdef PULSEAUDIO_ENABLED diff --git a/platform/x11/os_x11.h b/platform/x11/os_x11.h index 36355f11bc..0ea5bbfdb6 100644 --- a/platform/x11/os_x11.h +++ b/platform/x11/os_x11.h @@ -42,9 +42,6 @@ #include "main/input_default.h" #include "power_x11.h" #include "servers/audio_server.h" -#include "servers/physics_2d/physics_2d_server_sw.h" -#include "servers/physics_2d/physics_2d_server_wrap_mt.h" -#include "servers/physics_server.h" #include "servers/visual/rasterizer.h" #include <X11/Xcursor/Xcursor.h> @@ -121,10 +118,8 @@ class OS_X11 : public OS_Unix { uint64_t last_click_ms; uint32_t last_button_state; - PhysicsServer *physics_server; unsigned int get_mouse_button_state(unsigned int p_x11_state); void get_key_modifier_state(unsigned int p_x11_state, Ref<InputEventWithModifiers> state); - Physics2DServer *physics_2d_server; MouseMode mouse_mode; Point2i center; @@ -182,7 +177,6 @@ class OS_X11 : public OS_Unix { protected: virtual int get_video_driver_count() const; virtual const char *get_video_driver_name(int p_driver) const; - virtual VideoMode get_default_video_mode() const; virtual int get_audio_driver_count() const; virtual const char *get_audio_driver_name(int p_driver) const; @@ -275,6 +269,8 @@ public: virtual Error move_to_trash(const String &p_path); + virtual LatinKeyboardVariant get_latin_keyboard_variant() const; + OS_X11(); }; |