diff options
Diffstat (limited to 'platform')
27 files changed, 1710 insertions, 1088 deletions
diff --git a/platform/android/detect.py b/platform/android/detect.py index ce44ffbf74..7508c9ed0e 100644 --- a/platform/android/detect.py +++ b/platform/android/detect.py @@ -14,22 +14,17 @@ def get_name(): def can_build(): - import os - if (not os.environ.has_key("ANDROID_NDK_ROOT")): - return False - - return True + return (os.environ.has_key("ANDROID_NDK_ROOT")) def get_opts(): return [ - ('ANDROID_NDK_ROOT', 'the path to Android NDK', - os.environ.get("ANDROID_NDK_ROOT", 0)), - ('ndk_platform', 'compile for platform: (android-<api> , example: android-18)', "android-18"), - ('android_arch', 'select compiler architecture: (armv7/armv6/x86)', "armv7"), - ('android_neon', 'enable neon (armv7 only)', "yes"), - ('android_stl', 'enable STL support in android port (for modules)', "no") + ('ANDROID_NDK_ROOT', 'Path to the Android NDK', os.environ.get("ANDROID_NDK_ROOT", 0)), + ('ndk_platform', 'Target platform (android-<api>, e.g. "android-18")', "android-18"), + ('android_arch', 'Target architecture (armv7/armv6/x86)', "armv7"), + ('android_neon', 'Enable NEON support (armv7 only)', "yes"), + ('android_stl', 'Enable Android STL support (for modules)', "no") ] @@ -41,6 +36,7 @@ def get_flags(): def create(env): + tools = env['TOOLS'] if "mingw" in tools: tools.remove('mingw') @@ -54,7 +50,6 @@ def configure(env): # Workaround for MinGW. See: # http://www.scons.org/wiki/LongCmdLinesOnWin32 - import os if (os.name == "nt"): import subprocess @@ -92,35 +87,43 @@ def configure(env): env['SPAWN'] = mySpawn - ndk_platform = env['ndk_platform'] + ## Build type - if env['android_arch'] not in ['armv7', 'armv6', 'x86']: - env['android_arch'] = 'armv7' + if (env["target"].startswith("release")): + env.Append(LINKFLAGS=['-O2']) + env.Append(CPPFLAGS=['-O2', '-DNDEBUG', '-ffast-math', '-funsafe-math-optimizations', '-fomit-frame-pointer']) + if (can_vectorize): + env.Append(CPPFLAGS=['-ftree-vectorize']) + if (env["target"] == "release_debug"): + env.Append(CPPFLAGS=['-DDEBUG_ENABLED']) + elif (env["target"] == "debug"): + env.Append(LINKFLAGS=['-O0']) + env.Append(CPPFLAGS=['-O0', '-D_DEBUG', '-UNDEBUG', '-DDEBUG_ENABLED', + '-DDEBUG_MEMORY_ENABLED', '-g', '-fno-limit-debug-info']) - if env['android_arch'] == 'x86': - env["x86_libtheora_opt_gcc"] = True + ## Architecture - if env['PLATFORM'] == 'win32': - env.Tool('gcc') - env['SHLIBSUFFIX'] = '.so' + if env['android_arch'] not in ['armv7', 'armv6', 'x86']: + env['android_arch'] = 'armv7' neon_text = "" if env["android_arch"] == "armv7" and env['android_neon'] == 'yes': - neon_text = " (with neon)" - print("Godot Android!!!!! (" + env['android_arch'] + ")" + neon_text) - - env.Append(CPPPATH=['#platform/android']) + neon_text = " (with NEON)" + print("Building for Android (" + env['android_arch'] + ")" + neon_text) + can_vectorize = True if env['android_arch'] == 'x86': env.extra_suffix = ".x86" + env.extra_suffix target_subpath = "x86-4.9" abi_subpath = "i686-linux-android" arch_subpath = "x86" + env["x86_libtheora_opt_gcc"] = True elif env['android_arch'] == 'armv6': env.extra_suffix = ".armv6" + env.extra_suffix target_subpath = "arm-linux-androideabi-4.9" abi_subpath = "arm-linux-androideabi" arch_subpath = "armeabi" + can_vectorize = False elif env["android_arch"] == "armv7": target_subpath = "arm-linux-androideabi-4.9" abi_subpath = "arm-linux-androideabi" @@ -130,6 +133,14 @@ def configure(env): else: env.extra_suffix = ".armv7" + env.extra_suffix + ## Compiler configuration + + env['SHLIBSUFFIX'] = '.so' + + if env['PLATFORM'] == 'win32': + env.Tool('gcc') + env.use_windows_spawn_fix() + mt_link = True if (sys.platform.startswith("linux")): host_subpath = "linux-x86_64" @@ -142,10 +153,8 @@ def configure(env): mt_link = False host_subpath = "windows" - compiler_path = env["ANDROID_NDK_ROOT"] + \ - "/toolchains/llvm/prebuilt/" + host_subpath + "/bin" - gcc_toolchain_path = env["ANDROID_NDK_ROOT"] + \ - "/toolchains/" + target_subpath + "/prebuilt/" + host_subpath + compiler_path = env["ANDROID_NDK_ROOT"] + "/toolchains/llvm/prebuilt/" + host_subpath + "/bin" + gcc_toolchain_path = env["ANDROID_NDK_ROOT"] + "/toolchains/" + target_subpath + "/prebuilt/" + host_subpath tools_path = gcc_toolchain_path + "/" + abi_subpath + "/bin" # For Clang to find NDK tools in preference of those system-wide @@ -162,31 +171,28 @@ def configure(env): else: env['ARCH'] = 'arch-arm' - sysroot = env["ANDROID_NDK_ROOT"] + \ - "/platforms/" + ndk_platform + "/" + env['ARCH'] + sysroot = env["ANDROID_NDK_ROOT"] + "/platforms/" + env['ndk_platform'] + "/" + env['ARCH'] common_opts = ['-fno-integrated-as', '-gcc-toolchain', gcc_toolchain_path] + ## Compile flags + env.Append(CPPFLAGS=["-isystem", sysroot + "/usr/include"]) - env.Append(CPPFLAGS=string.split( - '-fpic -ffunction-sections -funwind-tables -fstack-protector-strong -fvisibility=hidden -fno-strict-aliasing')) + env.Append(CPPFLAGS=string.split('-fpic -ffunction-sections -funwind-tables -fstack-protector-strong -fvisibility=hidden -fno-strict-aliasing')) env.Append(CPPFLAGS=string.split('-DANDROID -DNO_STATVFS -DGLES2_ENABLED')) env['neon_enabled'] = False if env['android_arch'] == 'x86': - can_vectorize = True target_opts = ['-target', 'i686-none-linux-android'] # The NDK adds this if targeting API < 21, so we can drop it when Godot targets it at least env.Append(CPPFLAGS=['-mstackrealign']) + elif env["android_arch"] == "armv6": - can_vectorize = False target_opts = ['-target', 'armv6-none-linux-androideabi'] - env.Append(CPPFLAGS=string.split( - '-D__ARM_ARCH_6__ -march=armv6 -mfpu=vfp -mfloat-abi=softfp')) + env.Append(CPPFLAGS=string.split('-D__ARM_ARCH_6__ -march=armv6 -mfpu=vfp -mfloat-abi=softfp')) + elif env["android_arch"] == "armv7": - can_vectorize = True target_opts = ['-target', 'armv7-none-linux-androideabi'] - env.Append(CPPFLAGS=string.split( - '-D__ARM_ARCH_7__ -D__ARM_ARCH_7A__ -march=armv7-a -mfloat-abi=softfp')) + env.Append(CPPFLAGS=string.split('-D__ARM_ARCH_7__ -D__ARM_ARCH_7A__ -march=armv7-a -mfloat-abi=softfp')) if env['android_neon'] == 'yes': env['neon_enabled'] = True env.Append(CPPFLAGS=['-mfpu=neon', '-D__ARM_NEON__']) @@ -196,21 +202,20 @@ def configure(env): env.Append(CPPFLAGS=target_opts) env.Append(CPPFLAGS=common_opts) - env.Append(LIBS=['OpenSLES']) - env.Append(LIBS=['EGL', 'OpenSLES', 'android']) - env.Append(LIBS=['log', 'GLESv1_CM', 'GLESv2', 'GLESv3','z']) - - if (sys.platform.startswith("darwin")): - env['SHLIBSUFFIX'] = '.so' - - env['LINKFLAGS'] = ['-shared', '--sysroot=' + - sysroot, '-Wl,--warn-shared-textrel'] - env.Append(LINKFLAGS=string.split( - '-Wl,--fix-cortex-a8')) - env.Append(LINKFLAGS=string.split( - '-Wl,--no-undefined -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now')) - env.Append(LINKFLAGS=string.split( - '-Wl,-soname,libgodot_android.so -Wl,--gc-sections')) + if (env['android_stl'] == 'yes'): + env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"] + "/sources/cxx-stl/gnu-libstdc++/4.9/include"]) + env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"] + "/sources/cxx-stl/gnu-libstdc++/4.9/libs/" + arch_subpath + "/include"]) + env.Append(LIBPATH=[env["ANDROID_NDK_ROOT"] + "/sources/cxx-stl/gnu-libstdc++/4.9/libs/" + arch_subpath]) + env.Append(LIBS=["gnustl_static"]) + else: + env.Append(CXXFLAGS=['-fno-rtti', '-fno-exceptions', '-DNO_SAFE_CAST']) + + ## Link flags + + env['LINKFLAGS'] = ['-shared', '--sysroot=' + sysroot, '-Wl,--warn-shared-textrel'] + env.Append(LINKFLAGS=string.split('-Wl,--fix-cortex-a8')) + env.Append(LINKFLAGS=string.split('-Wl,--no-undefined -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now')) + env.Append(LINKFLAGS=string.split('-Wl,-soname,libgodot_android.so -Wl,--gc-sections')) if mt_link: env.Append(LINKFLAGS=['-Wl,--threads']) env.Append(LINKFLAGS=target_opts) @@ -221,45 +226,12 @@ def configure(env): env.Append(LIBPATH=[env["ANDROID_NDK_ROOT"] + '/toolchains/arm-linux-androideabi-4.9/prebuilt/' + host_subpath + '/' + abi_subpath + '/lib']) - if (env["target"].startswith("release")): - env.Append(LINKFLAGS=['-O2']) - env.Append(CPPFLAGS=['-O2', '-DNDEBUG', '-ffast-math', - '-funsafe-math-optimizations', '-fomit-frame-pointer']) - if (can_vectorize): - env.Append(CPPFLAGS=['-ftree-vectorize']) - if (env["target"] == "release_debug"): - env.Append(CPPFLAGS=['-DDEBUG_ENABLED']) - elif (env["target"] == "debug"): - env.Append(LINKFLAGS=['-O0']) - env.Append(CPPFLAGS=['-O0', '-D_DEBUG', '-UNDEBUG', '-DDEBUG_ENABLED', - '-DDEBUG_MEMORY_ENABLED', '-g', '-fno-limit-debug-info']) - - env.Append(CPPFLAGS=['-DANDROID_ENABLED', - '-DUNIX_ENABLED', '-DNO_FCNTL', '-DMPC_FIXED_POINT']) + env.Append(CPPPATH=['#platform/android']) + env.Append(CPPFLAGS=['-DANDROID_ENABLED', '-DUNIX_ENABLED', '-DNO_FCNTL', '-DMPC_FIXED_POINT']) + env.Append(LIBS=['OpenSLES', 'EGL', 'GLESv3', 'android', 'log', 'z']) # TODO: Move that to opus module's config if("module_opus_enabled" in env and env["module_opus_enabled"] != "no"): if (env["android_arch"] == "armv6" or env["android_arch"] == "armv7"): env.Append(CFLAGS=["-DOPUS_ARM_OPT"]) env.opus_fixed_point = "yes" - - if (env['android_stl'] == 'yes'): - env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"] + - "/sources/cxx-stl/gnu-libstdc++/4.9/include"]) - env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"] + - "/sources/cxx-stl/gnu-libstdc++/4.9/libs/" + arch_subpath + "/include"]) - env.Append(LIBPATH=[env["ANDROID_NDK_ROOT"] + - "/sources/cxx-stl/gnu-libstdc++/4.9/libs/" + arch_subpath]) - env.Append(LIBS=["gnustl_static"]) - else: - env.Append(CXXFLAGS=['-fno-rtti', '-fno-exceptions', '-DNO_SAFE_CAST']) - - import methods - env.Append(BUILDERS={'GLSL120': env.Builder( - action=methods.build_legacygl_headers, suffix='glsl.h', src_suffix='.glsl')}) - env.Append(BUILDERS={'GLSL': env.Builder( - action=methods.build_glsl_headers, suffix='glsl.h', src_suffix='.glsl')}) - env.Append(BUILDERS={'GLSL120GLES': env.Builder( - action=methods.build_gles2_headers, suffix='glsl.h', src_suffix='.glsl')}) - - env.use_windows_spawn_fix() diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index 51597526ab..a72e8aa90e 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -36,7 +36,8 @@ #include "io/zip_io.h" #include "os/file_access.h" #include "os/os.h" -#include "platform/android/logo.h" +#include "platform/android/logo.gen.h" +#include "platform/android/run_icon.gen.h" #include "version.h" #include <string.h> #if 0 @@ -2042,6 +2043,7 @@ class EditorExportAndroid : public EditorExportPlatform { GDCLASS(EditorExportAndroid, EditorExportPlatform) Ref<ImageTexture> logo; + Ref<ImageTexture> run_icon; struct Device { @@ -3036,6 +3038,10 @@ public: return OK; } + virtual Ref<Texture> get_run_icon() const { + return run_icon; + } + virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const { r_missing_templates = find_export_template("android_debug.apk") == String() || find_export_template("android_release.apk") == String(); @@ -3524,9 +3530,13 @@ public: EditorExportAndroid() { Ref<Image> img = memnew(Image(_android_logo)); - logo = Ref<ImageTexture>(memnew(ImageTexture)); + logo.instance(); logo->create_from_image(img); + img = Ref<Image>(memnew(Image(_android_run_icon))); + run_icon.instance(); + run_icon->create_from_image(img); + device_lock = Mutex::create(); device_thread = Thread::create(_device_poll_thread, this); devices_changed = true; diff --git a/platform/android/run_icon.png b/platform/android/run_icon.png Binary files differnew file mode 100644 index 0000000000..e53f8e9da5 --- /dev/null +++ b/platform/android/run_icon.png diff --git a/platform/haiku/detect.py b/platform/haiku/detect.py index 54e227cd19..c0e003a3d2 100644 --- a/platform/haiku/detect.py +++ b/platform/haiku/detect.py @@ -11,57 +11,58 @@ def get_name(): def can_build(): - if (os.name != "posix"): - return False - if (sys.platform == "darwin"): + if (os.name != "posix" or sys.platform == "darwin"): return False return True def get_opts(): + return [ ('debug_release', 'Add debug symbols to release version', 'no') ] def get_flags(): + return [ ] def configure(env): - is64 = sys.maxsize > 2**32 - - if (env["bits"] == "default"): - if (is64): - env["bits"] = "64" - else: - env["bits"] = "32" - - env.Append(CPPPATH=['#platform/haiku']) - env["CC"] = "gcc-x86" - env["CXX"] = "g++-x86" + ## Build type if (env["target"] == "release"): if (env["debug_release"] == "yes"): - env.Append(CCFLAGS=['-g2']) + env.Prepend(CCFLAGS=['-g2']) else: - env.Append(CCFLAGS=['-O3', '-ffast-math']) + env.Prepend(CCFLAGS=['-O3', '-ffast-math']) + elif (env["target"] == "release_debug"): - env.Append(CCFLAGS=['-O2', '-ffast-math', '-DDEBUG_ENABLED']) + env.Prepend(CCFLAGS=['-O2', '-ffast-math', '-DDEBUG_ENABLED']) + elif (env["target"] == "debug"): - env.Append(CCFLAGS=['-g2', '-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED']) + env.Prepend(CCFLAGS=['-g2', '-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED']) + + ## Architecture + + is64 = sys.maxsize > 2**32 + if (env["bits"] == "default"): + env["bits"] = "64" if is64 else "32" + + ## Compiler configuration + env["CC"] = "gcc-x86" + env["CXX"] = "g++-x86" + + ## Flags + + env.Append(CPPPATH=['#platform/haiku']) + env.Append(CPPFLAGS=['-DUNIX_ENABLED', '-DOPENGL_ENABLED', '-DGLES2_ENABLED', '-DGLES_OVER_GL']) + env.Append(CPPFLAGS=['-DMEDIA_KIT_ENABLED']) # env.Append(CCFLAGS=['-DFREETYPE_ENABLED']) env.Append(CPPFLAGS=['-DPTHREAD_NO_RENAME']) # TODO: enable when we have pthread_setname_np - env.Append(CPPFLAGS=['-DOPENGL_ENABLED', '-DMEDIA_KIT_ENABLED']) - env.Append(CPPFLAGS=['-DUNIX_ENABLED', '-DGLES2_ENABLED', '-DGLES_OVER_GL']) env.Append(LIBS=['be', 'game', 'media', 'network', 'bnetapi', 'z', 'GL']) - - import methods - env.Append(BUILDERS={'GLSL120': env.Builder(action=methods.build_legacygl_headers, suffix='glsl.h', src_suffix='.glsl')}) - env.Append(BUILDERS={'GLSL': env.Builder(action=methods.build_glsl_headers, suffix='glsl.h', src_suffix='.glsl')}) - env.Append(BUILDERS={'GLSL120GLES': env.Builder(action=methods.build_gles2_headers, suffix='glsl.h', src_suffix='.glsl')}) diff --git a/platform/iphone/SCsub b/platform/iphone/SCsub index 466b8241de..998d0a3f0d 100644 --- a/platform/iphone/SCsub +++ b/platform/iphone/SCsub @@ -17,17 +17,8 @@ iphone_lib = [ 'ios.mm', ] -# env.Depends('#core/math/vector3.h', 'vector3_psp.h') - -#iphone_lib = env.Library('iphone', iphone_lib) - env_ios = env.Clone() - -if env['ios_gles22_override'] == "yes": - env_ios.Append(CPPFLAGS=['-DGLES2_OVERRIDE']) - - obj = env_ios.Object('godot_iphone.cpp') prog = None diff --git a/platform/iphone/detect.py b/platform/iphone/detect.py index c20d8e90f4..1d802ff288 100644 --- a/platform/iphone/detect.py +++ b/platform/iphone/detect.py @@ -1,4 +1,5 @@ import os +import string import sys @@ -12,8 +13,6 @@ def get_name(): def can_build(): - import sys - import os if sys.platform == 'darwin' or os.environ.has_key("OSXCROSS_IOS"): return True @@ -23,13 +22,12 @@ def can_build(): def get_opts(): return [ - ('IPHONEPLATFORM', 'name of the iphone platform', 'iPhoneOS'), - ('IPHONEPATH', 'the path to iphone toolchain', '/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain'), - ('IPHONESDK', 'path to the iphone SDK', '/Applications/Xcode.app/Contents/Developer/Platforms/${IPHONEPLATFORM}.platform/Developer/SDKs/${IPHONEPLATFORM}.sdk/'), + ('IPHONEPLATFORM', 'Name of the iPhone platform', 'iPhoneOS'), + ('IPHONEPATH', 'Path to iPhone toolchain', '/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain'), + ('IPHONESDK', 'Path to the iPhone SDK', '/Applications/Xcode.app/Contents/Developer/Platforms/${IPHONEPLATFORM}.platform/Developer/SDKs/${IPHONEPLATFORM}.sdk/'), ('game_center', 'Support for game center', 'yes'), ('store_kit', 'Support for in-app store', 'yes'), ('icloud', 'Support for iCloud', 'yes'), - ('ios_gles22_override', 'Force GLES2.0 on iOS', 'yes'), ('ios_exceptions', 'Enable exceptions', 'no'), ('ios_triple', 'Triple for ios toolchain', ''), ('ios_sim', 'Build simulator binary', 'no'), @@ -45,95 +43,92 @@ def get_flags(): def configure(env): - env.Append(CPPPATH=['#platform/iphone']) + ## Build type - env['ENV']['PATH'] = env['IPHONEPATH'] + "/Developer/usr/bin/:" + env['ENV']['PATH'] + 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['CC'] = '$IPHONEPATH/usr/bin/${ios_triple}clang' - env['CXX'] = '$IPHONEPATH/usr/bin/${ios_triple}clang++' - env['AR'] = '$IPHONEPATH/usr/bin/${ios_triple}ar' - env['RANLIB'] = '$IPHONEPATH/usr/bin/${ios_triple}ranlib' + if env["target"] == "release_debug": + env.Append(CPPFLAGS=['-DDEBUG_ENABLED']) + + elif (env["target"] == "debug"): + env.Append(CPPFLAGS=['-D_DEBUG', '-DDEBUG=1', '-gdwarf-2', '-O0', '-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED']) + + ## Architecture - import string if (env["ios_sim"] == "yes" or env["arch"] == "x86"): # i386, simulator env["arch"] = "x86" env["bits"] = "32" - env.Append(CCFLAGS=string.split('-arch i386 -fobjc-abi-version=2 -fobjc-legacy-dispatch -fmessage-length=0 -fpascal-strings -fblocks -fasm-blocks -D__IPHONE_OS_VERSION_MIN_REQUIRED=40100 -isysroot $IPHONESDK -mios-simulator-version-min=4.3 -DCUSTOM_MATRIX_TRANSFORM_H=\\\"build/iphone/matrix4_iphone.h\\\" -DCUSTOM_VECTOR3_TRANSFORM_H=\\\"build/iphone/vector3_iphone.h\\\"')) elif (env["arch"] == "arm" or env["arch"] == "arm32" or env["arch"] == "armv7" or env["bits"] == "32"): # arm env["arch"] = "arm" env["bits"] = "32" - env.Append(CCFLAGS=string.split('-fno-objc-arc -arch armv7 -fmessage-length=0 -fno-strict-aliasing -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits -fpascal-strings -fblocks -isysroot $IPHONESDK -fvisibility=hidden -mthumb "-DIBOutlet=__attribute__((iboutlet))" "-DIBOutletCollection(ClassName)=__attribute__((iboutletcollection(ClassName)))" "-DIBAction=void)__attribute__((ibaction)" -miphoneos-version-min=9.0 -MMD -MT dependencies')) else: # armv64 env["arch"] = "arm64" env["bits"] = "64" + + ## Compiler configuration + + env['ENV']['PATH'] = env['IPHONEPATH'] + "/Developer/usr/bin/:" + env['ENV']['PATH'] + + env['CC'] = '$IPHONEPATH/usr/bin/${ios_triple}clang' + env['CXX'] = '$IPHONEPATH/usr/bin/${ios_triple}clang++' + env['AR'] = '$IPHONEPATH/usr/bin/${ios_triple}ar' + env['RANLIB'] = '$IPHONEPATH/usr/bin/${ios_triple}ranlib' + env['S_compiler'] = '$IPHONEPATH/Developer/usr/bin/gcc' + + ## Compile flags + + if (env["arch"] == "x86"): + env['IPHONEPLATFORM'] = 'iPhoneSimulator' + env['ENV']['MACOSX_DEPLOYMENT_TARGET'] = '10.6' + env.Append(CCFLAGS=string.split('-arch i386 -fobjc-abi-version=2 -fobjc-legacy-dispatch -fmessage-length=0 -fpascal-strings -fblocks -fasm-blocks -D__IPHONE_OS_VERSION_MIN_REQUIRED=40100 -isysroot $IPHONESDK -mios-simulator-version-min=4.3 -DCUSTOM_MATRIX_TRANSFORM_H=\\\"build/iphone/matrix4_iphone.h\\\" -DCUSTOM_VECTOR3_TRANSFORM_H=\\\"build/iphone/vector3_iphone.h\\\"')) + elif (env["arch"] == "arm"): + env.Append(CCFLAGS=string.split('-fno-objc-arc -arch armv7 -fmessage-length=0 -fno-strict-aliasing -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits -fpascal-strings -fblocks -isysroot $IPHONESDK -fvisibility=hidden -mthumb "-DIBOutlet=__attribute__((iboutlet))" "-DIBOutletCollection(ClassName)=__attribute__((iboutletcollection(ClassName)))" "-DIBAction=void)__attribute__((ibaction)" -miphoneos-version-min=9.0 -MMD -MT dependencies')) + elif (env["arch"] == "arm64"): env.Append(CCFLAGS=string.split('-fno-objc-arc -arch arm64 -fmessage-length=0 -fno-strict-aliasing -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits -fpascal-strings -fblocks -fvisibility=hidden -MMD -MT dependencies -miphoneos-version-min=9.0 -isysroot $IPHONESDK')) env.Append(CPPFLAGS=['-DNEED_LONG_INT']) env.Append(CPPFLAGS=['-DLIBYUV_DISABLE_NEON']) + if env['ios_exceptions'] == 'yes': + env.Append(CPPFLAGS=['-fexceptions']) + else: + env.Append(CPPFLAGS=['-fno-exceptions']) + + ## Link flags + if (env["arch"] == "x86"): - env['IPHONEPLATFORM'] = 'iPhoneSimulator' env.Append(LINKFLAGS=['-arch', 'i386', '-mios-simulator-version-min=4.3', '-isysroot', '$IPHONESDK', - #'-mmacosx-version-min=10.6', '-Xlinker', '-objc_abi_version', '-Xlinker', '2', - '-framework', 'AudioToolbox', - '-framework', 'AVFoundation', - '-framework', 'CoreAudio', - '-framework', 'CoreGraphics', - '-framework', 'CoreMedia', - '-framework', 'CoreMotion', - '-framework', 'Foundation', - '-framework', 'Security', - '-framework', 'UIKit', - '-framework', 'MediaPlayer', - '-framework', 'OpenGLES', - '-framework', 'QuartzCore', - '-framework', 'SystemConfiguration', - '-framework', 'GameController', '-F$IPHONESDK', ]) - elif (env["arch"] == "arm64"): - env.Append(LINKFLAGS=['-arch', 'arm64', '-Wl,-dead_strip', '-miphoneos-version-min=9.0', - '-isysroot', '$IPHONESDK', - #'-stdlib=libc++', - '-framework', 'Foundation', - '-framework', 'UIKit', - '-framework', 'CoreGraphics', - '-framework', 'OpenGLES', - '-framework', 'QuartzCore', - '-framework', 'CoreAudio', - '-framework', 'AudioToolbox', - '-framework', 'SystemConfiguration', - '-framework', 'Security', - #'-framework', 'AdSupport', - '-framework', 'MediaPlayer', - '-framework', 'AVFoundation', - '-framework', 'CoreMedia', - '-framework', 'CoreMotion', - '-framework', 'GameController', - ]) - else: - env.Append(LINKFLAGS=['-arch', 'armv7', '-Wl,-dead_strip', '-miphoneos-version-min=9.0', - '-isysroot', '$IPHONESDK', - '-framework', 'Foundation', - '-framework', 'UIKit', - '-framework', 'CoreGraphics', - '-framework', 'OpenGLES', - '-framework', 'QuartzCore', - '-framework', 'CoreAudio', - '-framework', 'AudioToolbox', - '-framework', 'SystemConfiguration', - '-framework', 'Security', - #'-framework', 'AdSupport', - '-framework', 'MediaPlayer', - '-framework', 'AVFoundation', - '-framework', 'CoreMedia', - '-framework', 'CoreMotion', - '-framework', 'GameController', - ]) - + elif (env["arch"] == "arm"): + env.Append(LINKFLAGS=['-arch', 'armv7', '-Wl,-dead_strip', '-miphoneos-version-min=9.0']) + if (env["arch"] == "arm64"): + env.Append(LINKFLAGS=['-arch', 'arm64', '-Wl,-dead_strip', '-miphoneos-version-min=9.0']) + + env.Append(LINKFLAGS=['-isysroot', '$IPHONESDK', + '-framework', 'AudioToolbox', + '-framework', 'AVFoundation', + '-framework', 'CoreAudio', + '-framework', 'CoreGraphics', + '-framework', 'CoreMedia', + '-framework', 'CoreMotion', + '-framework', 'Foundation', + '-framework', 'GameController', + '-framework', 'MediaPlayer', + '-framework', 'OpenGLES', + '-framework', 'QuartzCore', + '-framework', 'Security', + '-framework', 'SystemConfiguration', + '-framework', 'UIKit', + ]) + + # Feature options if env['game_center'] == 'yes': env.Append(CPPFLAGS=['-DGAME_CENTER_ENABLED']) env.Append(LINKFLAGS=['-framework', 'GameKit']) @@ -145,45 +140,20 @@ def configure(env): if env['icloud'] == 'yes': env.Append(CPPFLAGS=['-DICLOUD_ENABLED']) - env.Append(CPPPATH=['$IPHONESDK/usr/include', '$IPHONESDK/System/Library/Frameworks/OpenGLES.framework/Headers', '$IPHONESDK/System/Library/Frameworks/AudioUnit.framework/Headers']) + env.Append(CPPPATH=['$IPHONESDK/usr/include', + '$IPHONESDK/System/Library/Frameworks/OpenGLES.framework/Headers', + '$IPHONESDK/System/Library/Frameworks/AudioUnit.framework/Headers', + ]) - 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']) - - if env["target"] == "release_debug": - env.Append(CPPFLAGS=['-DDEBUG_ENABLED']) - - elif (env["target"] == "debug"): - - env.Append(CPPFLAGS=['-D_DEBUG', '-DDEBUG=1', '-gdwarf-2', '-O0', '-DDEBUG_ENABLED']) - env.Append(CPPFLAGS=['-DDEBUG_MEMORY_ENABLED']) - - if (env["ios_sim"] == "yes"): # TODO: Check if needed? - env['ENV']['MACOSX_DEPLOYMENT_TARGET'] = '10.6' env['ENV']['CODESIGN_ALLOCATE'] = '/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/codesign_allocate' + + env.Append(CPPPATH=['#platform/iphone']) env.Append(CPPFLAGS=['-DIPHONE_ENABLED', '-DUNIX_ENABLED', '-DGLES2_ENABLED', '-DMPC_FIXED_POINT']) # TODO: Move that to opus module's config if("module_opus_enabled" in env and env["module_opus_enabled"] != "no"): env.opus_fixed_point = "yes" - if env["arch"] == "x86": - pass - elif(env["arch"] == "arm64"): - env.Append(CFLAGS=["-DOPUS_ARM64_OPT"]) - else: + if (env["arch"] == "arm"): env.Append(CFLAGS=["-DOPUS_ARM_OPT"]) - - if env['ios_exceptions'] == 'yes': - env.Append(CPPFLAGS=['-fexceptions']) - else: - env.Append(CPPFLAGS=['-fno-exceptions']) - # env['neon_enabled']=True - env['S_compiler'] = '$IPHONEPATH/Developer/usr/bin/gcc' - - import methods - env.Append(BUILDERS={'GLSL120': env.Builder(action=methods.build_legacygl_headers, suffix='glsl.h', src_suffix='.glsl')}) - env.Append(BUILDERS={'GLSL': env.Builder(action=methods.build_glsl_headers, suffix='glsl.h', src_suffix='.glsl')}) - env.Append(BUILDERS={'GLSL120GLES': env.Builder(action=methods.build_gles2_headers, suffix='glsl.h', src_suffix='.glsl')}) + elif (env["arch"] == "arm64"): + env.Append(CFLAGS=["-DOPUS_ARM64_OPT"]) diff --git a/platform/iphone/export/export.cpp b/platform/iphone/export/export.cpp new file mode 100644 index 0000000000..0960ec8791 --- /dev/null +++ b/platform/iphone/export/export.cpp @@ -0,0 +1,347 @@ +/*************************************************************************/ +/* export.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 "export.h" +#include "editor/editor_export.h" +#include "editor/editor_node.h" +#include "editor/editor_settings.h" +#include "global_config.h" +#include "io/marshalls.h" +#include "io/resource_saver.h" +#include "io/zip_io.h" +#include "os/file_access.h" +#include "os/os.h" +#include "platform/osx/logo.gen.h" +#include "string.h" +#include "version.h" + +#include <sys/stat.h> + +class EditorExportPlatformIOS : public EditorExportPlatform { + + GDCLASS(EditorExportPlatformIOS, EditorExportPlatform); + + int version_code; + + Ref<ImageTexture> logo; + + void _fix_config_file(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &pfile, const String &p_name, const String &p_binary); + +protected: + virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features); + virtual void get_export_options(List<ExportOption> *r_options); + +public: + virtual String get_name() const { return "iOS"; } + virtual Ref<Texture> get_logo() const { return logo; } + + virtual String get_binary_extension() const { return "xcodeproj"; } + virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0); + + virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const; + + EditorExportPlatformIOS(); + ~EditorExportPlatformIOS(); +}; + +void EditorExportPlatformIOS::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) { + + // what does this need to do? +} + +void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options) { + + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_package/debug", PROPERTY_HINT_GLOBAL_FILE, "zip"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_package/release", PROPERTY_HINT_GLOBAL_FILE, "zip"), "")); + + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/name"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/info"), "Made with Godot Engine")); + // r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/icon", PROPERTY_HINT_FILE, "png"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/identifier"), "org.godotengine.iosgame")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/signature"), "godotiosgame")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/short_version"), "1.0")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/version"), "1.0")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/copyright"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/bits_mode", PROPERTY_HINT_ENUM, "Fat (32 & 64 bits),64 bits,32 bits"), 1)); + + /* probably need some more info */ +} + +void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &pfile, const String &p_name, const String &p_binary) { + + String str; + String strnew; + str.parse_utf8((const char *)pfile.ptr(), pfile.size()); + Vector<String> lines = str.split("\n"); + for (int i = 0; i < lines.size(); i++) { + if (lines[i].find("$binary") != -1) { + strnew += lines[i].replace("$binary", p_binary) + "\n"; + } else if (lines[i].find("$name") != -1) { + strnew += lines[i].replace("$name", p_name) + "\n"; + } else if (lines[i].find("$info") != -1) { + strnew += lines[i].replace("$info", p_preset->get("application/info")) + "\n"; + } else if (lines[i].find("$identifier") != -1) { + strnew += lines[i].replace("$identifier", p_preset->get("application/identifier")) + "\n"; + } else if (lines[i].find("$short_version") != -1) { + strnew += lines[i].replace("$short_version", p_preset->get("application/short_version")) + "\n"; + } else if (lines[i].find("$version") != -1) { + strnew += lines[i].replace("$version", p_preset->get("application/version")) + "\n"; + } else if (lines[i].find("$signature") != -1) { + strnew += lines[i].replace("$signature", p_preset->get("application/signature")) + "\n"; + } else if (lines[i].find("$copyright") != -1) { + strnew += lines[i].replace("$copyright", p_preset->get("application/copyright")) + "\n"; + } else { + strnew += lines[i] + "\n"; + } + } + + // !BAS! I'm assuming the 9 in the original code was a typo. I've added -1 or else it seems to also be adding our terminating zero... + // should apply the same fix in our OSX export. + CharString cs = strnew.utf8(); + pfile.resize(cs.size() - 1); + for (int i = 0; i < cs.size() - 1; i++) { + pfile[i] = cs[i]; + } +} + +Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) { + String src_pkg_name; + String dest_dir = p_path.get_base_dir() + "/"; + String binary_name = p_path.get_file().get_basename(); + + EditorProgress ep("export", "Exporting for iOS", 3); + + if (p_debug) + src_pkg_name = p_preset->get("custom_package/debug"); + else + src_pkg_name = p_preset->get("custom_package/release"); + + if (src_pkg_name == "") { + String err; + src_pkg_name = find_export_template("iphone.zip", &err); + if (src_pkg_name == "") { + EditorNode::add_io_error(err); + return ERR_FILE_NOT_FOUND; + } + } + + FileAccess *src_f = NULL; + zlib_filefunc_def io = zipio_create_io_from_file(&src_f); + + ep.step("Creating app", 0); + + unzFile src_pkg_zip = unzOpen2(src_pkg_name.utf8().get_data(), &io); + if (!src_pkg_zip) { + + EditorNode::add_io_error("Could not find template app to export:\n" + src_pkg_name); + return ERR_FILE_NOT_FOUND; + } + + ERR_FAIL_COND_V(!src_pkg_zip, ERR_CANT_OPEN); + int ret = unzGoToFirstFile(src_pkg_zip); + + String binary_to_use = "godot.iphone." + String(p_debug ? "debug" : "release") + "."; + int bits_mode = p_preset->get("application/bits_mode"); + binary_to_use += String(bits_mode == 0 ? "fat" : bits_mode == 1 ? "arm64" : "armv7"); + + print_line("binary: " + binary_to_use); + String pkg_name; + if (p_preset->get("application/name") != "") + pkg_name = p_preset->get("application/name"); // app_name + else if (String(GlobalConfig::get_singleton()->get("application/name")) != "") + pkg_name = String(GlobalConfig::get_singleton()->get("application/name")); + else + pkg_name = "Unnamed"; + + DirAccess *tmp_app_path = DirAccess::create_for_path(dest_dir); + ERR_FAIL_COND_V(!tmp_app_path, ERR_CANT_CREATE) + + /* Now process our template */ + bool found_binary = false; + int total_size = 0; + + while (ret == UNZ_OK) { + bool is_execute = false; + + //get filename + unz_file_info info; + char fname[16384]; + ret = unzGetCurrentFileInfo(src_pkg_zip, &info, fname, 16384, NULL, 0, NULL, 0); + + String file = fname; + + print_line("READ: " + file); + Vector<uint8_t> data; + data.resize(info.uncompressed_size); + + //read + unzOpenCurrentFile(src_pkg_zip); + unzReadCurrentFile(src_pkg_zip, data.ptr(), data.size()); + unzCloseCurrentFile(src_pkg_zip); + + //write + + file = file.replace_first("iphone/", ""); + + if (file == "godot_ios.xcodeproj/project.pbxproj") { + print_line("parse pbxproj"); + _fix_config_file(p_preset, data, pkg_name, binary_name); + } else if (file == "godot_ios/godot_ios-Info.plist") { + print_line("parse plist"); + _fix_config_file(p_preset, data, pkg_name, binary_name); + } else if (file.begins_with("godot.iphone")) { + if (file != binary_to_use) { + ret = unzGoToNextFile(src_pkg_zip); + continue; //ignore! + } + found_binary = true; + is_execute = true; + file = "godot_ios.iphone"; + } + + ///@TODO need to parse logo files + + if (data.size() > 0) { + file = file.replace("godot_ios", binary_name); + + print_line("ADDING: " + file + " size: " + itos(data.size())); + total_size += data.size(); + + /* write it into our folder structure */ + file = dest_dir + file; + + /* make sure this folder exists */ + String dir_name = file.get_base_dir(); + if (!tmp_app_path->dir_exists(dir_name)) { + print_line("Creating " + dir_name); + Error dir_err = tmp_app_path->make_dir_recursive(dir_name); + if (dir_err) { + ERR_PRINTS("Can't create '" + dir_name + "'."); + unzClose(src_pkg_zip); + return ERR_CANT_CREATE; + } + } + + /* write the file */ + FileAccess *f = FileAccess::open(file, FileAccess::WRITE); + if (!f) { + ERR_PRINTS("Can't write '" + file + "'."); + unzClose(src_pkg_zip); + return ERR_CANT_CREATE; + }; + f->store_buffer(data.ptr(), data.size()); + f->close(); + memdelete(f); + +#ifdef OSX_ENABLED + if (is_execute) { + // we need execute rights on this file + chmod(file.utf8().get_data(), 0755); + } +#endif + } + + ret = unzGoToNextFile(src_pkg_zip); + } + + /* we're done with our source zip */ + unzClose(src_pkg_zip); + + if (!found_binary) { + ERR_PRINTS("Requested template binary '" + binary_to_use + "' not found. It might be missing from your template archive."); + unzClose(src_pkg_zip); + return ERR_FILE_NOT_FOUND; + } + + ep.step("Making PKG", 1); + + String pack_path = dest_dir + binary_name + ".pck"; + Error err = save_pack(p_preset, pack_path); + + if (err) { + return err; + } + +#ifdef OSX_ENABLED + /* and open up xcode with our new project.... */ + List<String> args; + args.push_back(p_path); + err = OS::get_singleton()->execute("/usr/bin/open", args, false); + ERR_FAIL_COND_V(err, err); + +#endif + + return OK; +} + +bool EditorExportPlatformIOS::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const { + + bool valid = true; + String err; + + if (!exists_export_template("iphone.zip", &err)) { + valid = false; + } + + if (p_preset->get("custom_package/debug") != "" && !FileAccess::exists(p_preset->get("custom_package/debug"))) { + valid = false; + err += "Custom debug package not found.\n"; + } + + if (p_preset->get("custom_package/release") != "" && !FileAccess::exists(p_preset->get("custom_package/release"))) { + valid = false; + err += "Custom release package not found.\n"; + } + + if (!err.empty()) + r_error = err; + + return valid; +} + +EditorExportPlatformIOS::EditorExportPlatformIOS() { + + ///@TODO need to create the correct logo + // Ref<Image> img = memnew(Image(_iphone_logo)); + Ref<Image> img = memnew(Image(_osx_logo)); + logo.instance(); + logo->create_from_image(img); +} + +EditorExportPlatformIOS::~EditorExportPlatformIOS() { +} + +void register_iphone_exporter() { + + Ref<EditorExportPlatformIOS> platform; + platform.instance(); + + EditorExport::get_singleton()->add_export_platform(platform); +} diff --git a/platform/iphone/export/export.h b/platform/iphone/export/export.h new file mode 100644 index 0000000000..6e9324aed7 --- /dev/null +++ b/platform/iphone/export/export.h @@ -0,0 +1,30 @@ +/*************************************************************************/ +/* export.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. */ +/*************************************************************************/ +void register_iphone_exporter(); diff --git a/platform/javascript/detect.py b/platform/javascript/detect.py index 41fe3fb027..68c8d1eea5 100644 --- a/platform/javascript/detect.py +++ b/platform/javascript/detect.py @@ -1,6 +1,6 @@ import os -import sys import string +import sys def is_active(): @@ -12,7 +12,8 @@ def get_name(): def can_build(): - return os.environ.has_key("EMSCRIPTEN_ROOT") + + return (os.environ.has_key("EMSCRIPTEN_ROOT")) def get_opts(): @@ -27,12 +28,12 @@ def get_flags(): return [ ('tools', 'no'), - ('module_etc1_enabled', 'no'), ('module_theora_enabled', 'no'), ] def create(env): + # remove Windows' .exe suffix return env.Clone(tools=['textfile', 'zip'], PROGSUFFIX='') @@ -45,10 +46,26 @@ def escape_target_backslashes(target, source, env, for_signature): def configure(env): - env['ENV'] = os.environ - env.Append(CPPPATH=['#platform/javascript']) + ## Build type + + if (env["target"] == "release"): + env.Append(CCFLAGS=['-O3']) + env.Append(LINKFLAGS=['-O3']) + elif (env["target"] == "release_debug"): + env.Append(CCFLAGS=['-O2', '-DDEBUG_ENABLED']) + env.Append(LINKFLAGS=['-O2', '-s', 'ASSERTIONS=1']) + # retain function names at the cost of file size, for backtraces and profiling + env.Append(LINKFLAGS=['--profiling-funcs']) + + elif (env["target"] == "debug"): + env.Append(CCFLAGS=['-O1', '-D_DEBUG', '-g', '-DDEBUG_ENABLED']) + env.Append(LINKFLAGS=['-O1', '-g']) + + ## Compiler configuration + + env['ENV'] = os.environ env.PrependENVPath('PATH', os.environ['EMSCRIPTEN_ROOT']) env['CC'] = 'emcc' env['CXX'] = 'em++' @@ -57,6 +74,7 @@ def configure(env): # Emscripten's ar has issues with duplicate file names, so use cc env['AR'] = 'emcc' env['ARFLAGS'] = '-o' + if (os.name == 'nt'): # use TempFileMunge on Windows since some commands get too long for # cmd.exe even with spawn_fix @@ -68,26 +86,20 @@ def configure(env): env['OBJSUFFIX'] = '.bc' env['LIBSUFFIX'] = '.bc' - if (env["target"] == "release"): - env.Append(CCFLAGS=['-O3']) - env.Append(LINKFLAGS=['-O3']) - elif (env["target"] == "release_debug"): - env.Append(CCFLAGS=['-O2', '-DDEBUG_ENABLED']) - env.Append(LINKFLAGS=['-O2', '-s', 'ASSERTIONS=1']) - # retain function names at the cost of file size, for backtraces and profiling - env.Append(LINKFLAGS=['--profiling-funcs']) - elif (env["target"] == "debug"): - env.Append(CCFLAGS=['-O1', '-D_DEBUG', '-g', '-DDEBUG_ENABLED']) - env.Append(LINKFLAGS=['-O1', '-g']) + ## Compile flags - # TODO: Move that to opus module's config - if("module_opus_enabled" in env and env["module_opus_enabled"] != "no"): - env.opus_fixed_point = "yes" + env.Append(CPPPATH=['#platform/javascript']) + env.Append(CPPFLAGS=['-DJAVASCRIPT_ENABLED', '-DUNIX_ENABLED', '-DPTHREAD_NO_RENAME', '-DTYPED_METHOD_BIND', '-DNO_THREADS']) + env.Append(CPPFLAGS=['-DGLES3_ENABLED']) # These flags help keep the file size down env.Append(CPPFLAGS=["-fno-exceptions", '-DNO_SAFE_CAST', '-fno-rtti']) - env.Append(CPPFLAGS=['-DJAVASCRIPT_ENABLED', '-DUNIX_ENABLED', '-DPTHREAD_NO_RENAME', '-DTYPED_METHOD_BIND', '-DNO_THREADS']) - env.Append(CPPFLAGS=['-DGLES3_ENABLED']) + + if env['javascript_eval'] == 'yes': + env.Append(CPPFLAGS=['-DJAVASCRIPT_EVAL_ENABLED']) + + ## Link flags + env.Append(LINKFLAGS=['-s', 'USE_WEBGL2=1']) if (env['wasm'] == 'yes'): @@ -101,8 +113,6 @@ def configure(env): env.Append(LINKFLAGS=['-s', 'ASM_JS=1']) env.Append(LINKFLAGS=['--separate-asm']) - if env['javascript_eval'] == 'yes': - env.Append(CPPFLAGS=['-DJAVASCRIPT_EVAL_ENABLED']) - - - import methods + # TODO: Move that to opus module's config + if("module_opus_enabled" in env and env["module_opus_enabled"] != "no"): + env.opus_fixed_point = "yes" diff --git a/platform/javascript/export/export.cpp b/platform/javascript/export/export.cpp index ea388072c5..4bdfdae39e 100644 --- a/platform/javascript/export/export.cpp +++ b/platform/javascript/export/export.cpp @@ -30,7 +30,8 @@ #include "editor/editor_node.h" #include "editor_export.h" #include "io/zip_io.h" -#include "platform/javascript/logo.h" +#include "platform/javascript/logo.gen.h" +#include "platform/javascript/run_icon.gen.h" #define EXPORT_TEMPLATE_WEBASSEMBLY_RELEASE "webassembly_release.zip" #define EXPORT_TEMPLATE_WEBASSEMBLY_DEBUG "webassembly_debug.zip" @@ -42,6 +43,8 @@ class EditorExportPlatformJavaScript : public EditorExportPlatform { GDCLASS(EditorExportPlatformJavaScript, EditorExportPlatform) Ref<ImageTexture> logo; + Ref<ImageTexture> run_icon; + bool runnable_when_last_polled; void _fix_html(Vector<uint8_t> &p_html, const Ref<EditorExportPreset> &p_preset, const String &p_name, bool p_debug); void _fix_fsloader_js(Vector<uint8_t> &p_js, const String &p_pack_name, uint64_t p_pack_size); @@ -64,10 +67,12 @@ public: virtual String get_binary_extension() const; virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0); - virtual int get_device_count() const { return 1; } + virtual bool poll_devices(); + virtual int get_device_count() const; virtual String get_device_name(int p_device) const { return TTR("Run in Browser"); } virtual String get_device_info(int p_device) const { return TTR("Run exported HTML in the system's default browser."); } virtual Error run(const Ref<EditorExportPreset> &p_preset, int p_device, int p_debug_flags); + virtual Ref<Texture> get_run_icon() const; EditorExportPlatformJavaScript(); }; @@ -303,6 +308,29 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese return OK; } +bool EditorExportPlatformJavaScript::poll_devices() { + + Ref<EditorExportPreset> preset; + + for (int i = 0; i < EditorExport::get_singleton()->get_export_preset_count(); i++) { + + Ref<EditorExportPreset> ep = EditorExport::get_singleton()->get_export_preset(i); + if (ep->is_runnable() && ep->get_platform() == this) { + preset = ep; + break; + } + } + + bool prev = runnable_when_last_polled; + runnable_when_last_polled = preset.is_valid(); + return runnable_when_last_polled != prev; +} + +int EditorExportPlatformJavaScript::get_device_count() const { + + return runnable_when_last_polled; +} + Error EditorExportPlatformJavaScript::run(const Ref<EditorExportPreset> &p_preset, int p_device, int p_debug_flags) { String path = EditorSettings::get_singleton()->get_settings_path() + "/tmp/tmp_export.html"; @@ -314,11 +342,22 @@ Error EditorExportPlatformJavaScript::run(const Ref<EditorExportPreset> &p_prese return OK; } +Ref<Texture> EditorExportPlatformJavaScript::get_run_icon() const { + + return run_icon; +} + EditorExportPlatformJavaScript::EditorExportPlatformJavaScript() { Ref<Image> img = memnew(Image(_javascript_logo)); logo.instance(); logo->create_from_image(img); + + img = Ref<Image>(memnew(Image(_javascript_run_icon))); + run_icon.instance(); + run_icon->create_from_image(img); + + runnable_when_last_polled = false; } void register_javascript_exporter() { diff --git a/platform/javascript/run_icon.png b/platform/javascript/run_icon.png Binary files differnew file mode 100644 index 0000000000..dedee6f479 --- /dev/null +++ b/platform/javascript/run_icon.png diff --git a/platform/osx/detect.py b/platform/osx/detect.py index 39ee33ae82..dfefbbc1ba 100644 --- a/platform/osx/detect.py +++ b/platform/osx/detect.py @@ -1,4 +1,3 @@ - import os import sys @@ -22,9 +21,7 @@ def can_build(): def get_opts(): return [ - ('force_64_bits', 'Force 64 bits binary', 'no'), ('osxcross_sdk', 'OSXCross SDK version', 'darwin14'), - ] @@ -36,36 +33,37 @@ def get_flags(): def configure(env): - env.Append(CPPPATH=['#platform/osx']) - - if (env["bits"] == "default"): - env["bits"] = "32" + ## Build type if (env["target"] == "release"): - - env.Append(CCFLAGS=['-O2', '-ffast-math', '-fomit-frame-pointer', '-ftree-vectorize', '-msse2']) + env.Prepend(CCFLAGS=['-O2', '-ffast-math', '-fomit-frame-pointer', '-ftree-vectorize', '-msse2']) elif (env["target"] == "release_debug"): - - env.Append(CCFLAGS=['-O2', '-DDEBUG_ENABLED']) + env.Prepend(CCFLAGS=['-O2', '-DDEBUG_ENABLED']) elif (env["target"] == "debug"): + env.Prepend(CCFLAGS=['-g3', '-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED']) - env.Append(CCFLAGS=['-g3', '-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED']) + ## Architecture - if (not os.environ.has_key("OSXCROSS_ROOT")): - # regular native build - if (env["bits"] == "64"): - env.Append(CCFLAGS=['-arch', 'x86_64']) - env.Append(LINKFLAGS=['-arch', 'x86_64']) + is64 = sys.maxsize > 2**32 + if (env["bits"] == "default"): + env["bits"] = "64" if is64 else "32" + + ## Compiler configuration + + if (not os.environ.has_key("OSXCROSS_ROOT")): # regular native build + if (env["bits"] == "fat"): + env.Append(CCFLAGS=['-arch', 'i386', '-arch', 'x86_64']) + env.Append(LINKFLAGS=['-arch', 'i386', '-arch', 'x86_64']) elif (env["bits"] == "32"): env.Append(CCFLAGS=['-arch', 'i386']) env.Append(LINKFLAGS=['-arch', 'i386']) - else: - env.Append(CCFLAGS=['-arch', 'i386', '-arch', 'x86_64']) - env.Append(LINKFLAGS=['-arch', 'i386', '-arch', 'x86_64']) - else: - # osxcross build + else: # 64-bit, default + env.Append(CCFLAGS=['-arch', 'x86_64']) + env.Append(LINKFLAGS=['-arch', 'x86_64']) + + else: # osxcross build root = os.environ.get("OSXCROSS_ROOT", 0) if env["bits"] == "64": basecmd = root + "/target/bin/x86_64-apple-" + env["osxcross_sdk"] + "-" @@ -78,26 +76,22 @@ def configure(env): env['RANLIB'] = basecmd + "ranlib" env['AS'] = basecmd + "as" - env.Append(CPPFLAGS=["-DAPPLE_STYLE_KEYS"]) - env.Append(CPPFLAGS=['-DUNIX_ENABLED', '-DGLES2_ENABLED', '-DOSX_ENABLED']) - env.Append(CPPFLAGS=["-mmacosx-version-min=10.9"]) - env.Append(LIBS=['pthread']) - #env.Append(CPPFLAGS=['-F/Developer/SDKs/MacOSX10.4u.sdk/System/Library/Frameworks', '-isysroot', '/Developer/SDKs/MacOSX10.4u.sdk', '-mmacosx-version-min=10.4']) - #env.Append(LINKFLAGS=['-mmacosx-version-min=10.4', '-isysroot', '/Developer/SDKs/MacOSX10.4u.sdk', '-Wl,-syslibroot,/Developer/SDKs/MacOSX10.4u.sdk']) - env.Append(LINKFLAGS=['-framework', 'Cocoa', '-framework', 'Carbon', '-framework', 'OpenGL', '-framework', 'AGL', '-framework', 'AudioUnit', '-lz', '-framework', 'IOKit', '-framework', 'ForceFeedback']) - env.Append(LINKFLAGS=["-mmacosx-version-min=10.9"]) - if (env["CXX"] == "clang++"): env.Append(CPPFLAGS=['-DTYPED_METHOD_BIND']) env["CC"] = "clang" env["LD"] = "clang++" - import methods + ## Dependencies + + if (env['builtin_libtheora'] != 'no'): + env["x86_libtheora_opt_gcc"] = True + + ## Flags - env.Append(BUILDERS={'GLSL120': env.Builder(action=methods.build_legacygl_headers, suffix='glsl.h', src_suffix='.glsl')}) - env.Append(BUILDERS={'GLSL': env.Builder(action=methods.build_glsl_headers, suffix='glsl.h', src_suffix='.glsl')}) - env.Append(BUILDERS={'GLSL120GLES': env.Builder(action=methods.build_gles2_headers, suffix='glsl.h', src_suffix='.glsl')}) - #env.Append( BUILDERS = { 'HLSL9' : env.Builder(action = methods.build_hlsl_dx9_headers, suffix = 'hlsl.h',src_suffix = '.hlsl') } ) + env.Append(CPPPATH=['#platform/osx']) + env.Append(CPPFLAGS=['-DOSX_ENABLED', '-DUNIX_ENABLED', '-DGLES2_ENABLED', '-DAPPLE_STYLE_KEYS']) + env.Append(LINKFLAGS=['-framework', 'Cocoa', '-framework', 'Carbon', '-framework', 'OpenGL', '-framework', 'AGL', '-framework', 'AudioUnit', '-lz', '-framework', 'IOKit', '-framework', 'ForceFeedback']) + env.Append(LIBS=['pthread']) - env["x86_libtheora_opt_gcc"] = True - + env.Append(CPPFLAGS=['-mmacosx-version-min=10.9']) + env.Append(LINKFLAGS=['-mmacosx-version-min=10.9']) diff --git a/platform/osx/export/export.cpp b/platform/osx/export/export.cpp index 2033bc76a1..c81fb00b36 100644 --- a/platform/osx/export/export.cpp +++ b/platform/osx/export/export.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "export.h" #include "editor/editor_export.h" #include "editor/editor_node.h" @@ -37,511 +38,652 @@ #include "io/zip_io.h" #include "os/file_access.h" #include "os/os.h" -#include "platform/osx/logo.h" +#include "platform/osx/logo.gen.h" #include "string.h" #include "version.h" -#if 0 +#include <sys/stat.h> class EditorExportPlatformOSX : public EditorExportPlatform { - GDCLASS( EditorExportPlatformOSX,EditorExportPlatform ); - - String custom_release_package; - String custom_debug_package; - - enum BitsMode { - BITS_FAT, - BITS_64, - BITS_32 - }; + GDCLASS(EditorExportPlatformOSX, EditorExportPlatform); int version_code; - String app_name; - String info; - String icon; - String identifier; - String short_version; - String version; - String signature; - String copyright; - BitsMode bits_mode; - bool high_resolution; - Ref<ImageTexture> logo; - void _fix_plist(Vector<uint8_t>& plist, const String &p_binary); - void _make_icon(const Image& p_icon,Vector<uint8_t>& data); - + void _fix_plist(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &plist, const String &p_binary); + void _make_icon(const Ref<Image> &p_icon, Vector<uint8_t> &p_data); +#ifdef OSX_ENABLED + Error _code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path); + Error _create_dmg(const String &p_dmg_path, const String &p_pkg_name, const String &p_app_path_name); +#endif protected: - - bool _set(const StringName& p_name, const Variant& p_value); - bool _get(const StringName& p_name,Variant &r_ret) const; - void _get_property_list( List<PropertyInfo> *p_list) const; + virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features); + virtual void get_export_options(List<ExportOption> *r_options); public: - virtual String get_name() const { return "Mac OSX"; } - virtual ImageCompression get_image_compression() const { return IMAGE_COMPRESSION_BC; } virtual Ref<Texture> get_logo() const { return logo; } - - virtual bool poll_devices() { return false;} - virtual int get_device_count() const { return 0; } - virtual String get_device_name(int p_device) const { return String(); } - virtual String get_device_info(int p_device) const { return String(); } - virtual Error run(int p_device,int p_flags=0); - - virtual bool requires_password(bool p_debug) const { return false; } +#ifdef OSX_ENABLED + virtual String get_binary_extension() const { return "dmg"; } +#else virtual String get_binary_extension() const { return "zip"; } - virtual Error export_project(const String& p_path,bool p_debug,int p_flags=0); +#endif + virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0); - virtual bool can_export(String *r_error=NULL) const; + virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const; EditorExportPlatformOSX(); ~EditorExportPlatformOSX(); }; -bool EditorExportPlatformOSX::_set(const StringName& p_name, const Variant& p_value) { - - String n=p_name; - - if (n=="custom_package/debug") - custom_debug_package=p_value; - else if (n=="custom_package/release") - custom_release_package=p_value; - else if (n=="application/name") - app_name=p_value; - else if (n=="application/info") - info=p_value; - else if (n=="application/icon") - icon=p_value; - else if (n=="application/identifier") - identifier=p_value; - else if (n=="application/signature") - signature=p_value; - else if (n=="application/short_version") - short_version=p_value; - else if (n=="application/version") - version=p_value; - else if (n=="application/copyright") - copyright=p_value; - else if (n=="application/bits_mode") - bits_mode=BitsMode(int(p_value)); - else if (n=="display/high_res") - high_resolution=p_value; - else - return false; - - return true; -} - -bool EditorExportPlatformOSX::_get(const StringName& p_name,Variant &r_ret) const{ - - String n=p_name; - - if (n=="custom_package/debug") - r_ret=custom_debug_package; - else if (n=="custom_package/release") - r_ret=custom_release_package; - else if (n=="application/name") - r_ret=app_name; - else if (n=="application/info") - r_ret=info; - else if (n=="application/icon") - r_ret=icon; - else if (n=="application/identifier") - r_ret=identifier; - else if (n=="application/signature") - r_ret=signature; - else if (n=="application/short_version") - r_ret=short_version; - else if (n=="application/version") - r_ret=version; - else if (n=="application/copyright") - r_ret=copyright; - else if (n=="application/bits_mode") - r_ret=bits_mode; - else if (n=="display/high_res") - r_ret=high_resolution; - else - return false; +void EditorExportPlatformOSX::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) { - return true; + // what does this need to do? } -void EditorExportPlatformOSX::_get_property_list( List<PropertyInfo> *p_list) const{ - - p_list->push_back( PropertyInfo( Variant::STRING, "custom_package/debug", PROPERTY_HINT_GLOBAL_FILE,"zip")); - p_list->push_back( PropertyInfo( Variant::STRING, "custom_package/release", PROPERTY_HINT_GLOBAL_FILE,"zip")); - - p_list->push_back( PropertyInfo( Variant::STRING, "application/name") ); - p_list->push_back( PropertyInfo( Variant::STRING, "application/info") ); - p_list->push_back( PropertyInfo( Variant::STRING, "application/icon",PROPERTY_HINT_FILE,"png") ); - p_list->push_back( PropertyInfo( Variant::STRING, "application/identifier") ); - p_list->push_back( PropertyInfo( Variant::STRING, "application/signature") ); - p_list->push_back( PropertyInfo( Variant::STRING, "application/short_version") ); - p_list->push_back( PropertyInfo( Variant::STRING, "application/version") ); - p_list->push_back( PropertyInfo( Variant::STRING, "application/copyright") ); - p_list->push_back( PropertyInfo( Variant::INT, "application/bits_mode", PROPERTY_HINT_ENUM, "Fat (32 & 64 bits),64 bits,32 bits") ); - p_list->push_back( PropertyInfo( Variant::BOOL, "display/high_res") ); +void EditorExportPlatformOSX::get_export_options(List<ExportOption> *r_options) { + + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_package/debug", PROPERTY_HINT_GLOBAL_FILE, "zip"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_package/release", PROPERTY_HINT_GLOBAL_FILE, "zip"), "")); + + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/name"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/info"), "Made with Godot Engine")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/icon", PROPERTY_HINT_FILE, "png"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/identifier"), "org.godotengine.macgame")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/signature"), "godotmacgame")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/short_version"), "1.0")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/version"), "1.0")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/copyright"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/bits_mode", PROPERTY_HINT_ENUM, "Fat (32 & 64 bits),64 bits,32 bits"), 0)); + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "display/high_res"), false)); + +#ifdef OSX_ENABLED + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/identity"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/entitlements"), "")); +#endif } -void EditorExportPlatformOSX::_make_icon(const Image& p_icon,Vector<uint8_t>& icon) { - +void EditorExportPlatformOSX::_make_icon(const Ref<Image> &p_icon, Vector<uint8_t> &p_data) { - Ref<ImageTexture> it = memnew( ImageTexture ); - int size=512; + Ref<ImageTexture> it = memnew(ImageTexture); + int size = 512; Vector<uint8_t> data; data.resize(8); - data[0]='i'; - data[1]='c'; - data[2]='n'; - data[3]='s'; + data[0] = 'i'; + data[1] = 'c'; + data[2] = 'n'; + data[3] = 's'; - const char *name[]={"ic09","ic08","ic07","icp6","icp5","icp4"}; - int index=0; + const char *name[] = { "ic09", "ic08", "ic07", "icp6", "icp5", "icp4" }; + int index = 0; - while(size>=16) { + while (size >= 16) { - Image copy = p_icon; - copy.convert(Image::FORMAT_RGBA8); - copy.resize(size,size); + Ref<Image> copy = p_icon; // does this make sense? doesn't this just increase the reference count instead of making a copy? Do we even need a copy? + copy->convert(Image::FORMAT_RGBA8); + copy->resize(size, size); it->create_from_image(copy); - String path = EditorSettings::get_singleton()->get_settings_path()+"/tmp/icon.png"; - ResourceSaver::save(path,it); + String path = EditorSettings::get_singleton()->get_settings_path() + "/tmp/icon.png"; + ResourceSaver::save(path, it); - FileAccess *f = FileAccess::open(path,FileAccess::READ); + FileAccess *f = FileAccess::open(path, FileAccess::READ); ERR_FAIL_COND(!f); int ofs = data.size(); uint32_t len = f->get_len(); - data.resize(data.size()+len+8); - f->get_buffer(&data[ofs+8],len); + data.resize(data.size() + len + 8); + f->get_buffer(&data[ofs + 8], len); memdelete(f); - len+=8; - len=BSWAP32(len); - copymem(&data[ofs],name[index],4); - encode_uint32(len,&data[ofs+4]); + len += 8; + len = BSWAP32(len); + copymem(&data[ofs], name[index], 4); + encode_uint32(len, &data[ofs + 4]); index++; - size/=2; + size /= 2; } uint32_t total_len = data.size(); total_len = BSWAP32(total_len); - encode_uint32(total_len,&data[4]); + encode_uint32(total_len, &data[4]); - icon=data; + p_data = data; } - -void EditorExportPlatformOSX::_fix_plist(Vector<uint8_t>& plist,const String& p_binary) { - +void EditorExportPlatformOSX::_fix_plist(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &plist, const String &p_binary) { String str; String strnew; - str.parse_utf8((const char*)plist.ptr(),plist.size()); - Vector<String> lines=str.split("\n"); - for(int i=0;i<lines.size();i++) { - if (lines[i].find("$binary")!=-1) { - strnew+=lines[i].replace("$binary",p_binary)+"\n"; - } else if (lines[i].find("$name")!=-1) { - strnew+=lines[i].replace("$name",p_binary)+"\n"; - } else if (lines[i].find("$info")!=-1) { - strnew+=lines[i].replace("$info",info)+"\n"; - } else if (lines[i].find("$identifier")!=-1) { - strnew+=lines[i].replace("$identifier",identifier)+"\n"; - } else if (lines[i].find("$short_version")!=-1) { - strnew+=lines[i].replace("$short_version",short_version)+"\n"; - } else if (lines[i].find("$version")!=-1) { - strnew+=lines[i].replace("$version",version)+"\n"; - } else if (lines[i].find("$signature")!=-1) { - strnew+=lines[i].replace("$signature",signature)+"\n"; - } else if (lines[i].find("$copyright")!=-1) { - strnew+=lines[i].replace("$copyright",copyright)+"\n"; - } else if (lines[i].find("$highres")!=-1) { - strnew+=lines[i].replace("$highres",high_resolution?"<true/>":"<false/>")+"\n"; + str.parse_utf8((const char *)plist.ptr(), plist.size()); + Vector<String> lines = str.split("\n"); + for (int i = 0; i < lines.size(); i++) { + if (lines[i].find("$binary") != -1) { + strnew += lines[i].replace("$binary", p_binary) + "\n"; + } else if (lines[i].find("$name") != -1) { + strnew += lines[i].replace("$name", p_binary) + "\n"; + } else if (lines[i].find("$info") != -1) { + strnew += lines[i].replace("$info", p_preset->get("application/info")) + "\n"; + } else if (lines[i].find("$identifier") != -1) { + strnew += lines[i].replace("$identifier", p_preset->get("application/identifier")) + "\n"; + } else if (lines[i].find("$short_version") != -1) { + strnew += lines[i].replace("$short_version", p_preset->get("application/short_version")) + "\n"; + } else if (lines[i].find("$version") != -1) { + strnew += lines[i].replace("$version", p_preset->get("application/version")) + "\n"; + } else if (lines[i].find("$signature") != -1) { + strnew += lines[i].replace("$signature", p_preset->get("application/signature")) + "\n"; + } else if (lines[i].find("$copyright") != -1) { + strnew += lines[i].replace("$copyright", p_preset->get("application/copyright")) + "\n"; + } else if (lines[i].find("$highres") != -1) { + strnew += lines[i].replace("$highres", p_preset->get("display/high_res") ? "<true/>" : "<false/>") + "\n"; } else { - strnew+=lines[i]+"\n"; + strnew += lines[i] + "\n"; } } CharString cs = strnew.utf8(); - plist.resize(cs.size()); - for(int i=9;i<cs.size();i++) { - plist[i]=cs[i]; + plist.resize(cs.size() - 1); + for (int i = 0; i < cs.size() - 1; i++) { + plist[i] = cs[i]; } } -Error EditorExportPlatformOSX::export_project(const String& p_path, bool p_debug, int p_flags) { +#ifdef OSX_ENABLED +/** + If we're running the OSX version of the Godot editor we'll: + - export our application bundle to a temporary folder + - attempt to code sign it + - and then wrap it up in a DMG +**/ + +Error EditorExportPlatformOSX::_code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path) { + List<String> args; + if (p_preset->get("codesign/entitlements") != "") { + /* this should point to our entitlements.plist file that sandboxes our application, I don't know if this should also be placed in our app bundle */ + args.push_back("-entitlements"); + args.push_back(p_preset->get("codesign/entitlements")); + } + args.push_back("-s"); + args.push_back(p_preset->get("codesign/identity")); + args.push_back("-v"); /* provide some more feedback */ + args.push_back(p_path); + Error err = OS::get_singleton()->execute("/usr/bin/codesign", args, true); + ERR_FAIL_COND_V(err, err); + + return OK; +} + +Error EditorExportPlatformOSX::_create_dmg(const String &p_dmg_path, const String &p_pkg_name, const String &p_app_path_name) { + List<String> args; + args.push_back("create"); + args.push_back(p_dmg_path); + args.push_back("-volname"); + args.push_back(p_pkg_name); + args.push_back("-fs"); + args.push_back("HFS+"); + args.push_back("-srcfolder"); + args.push_back(p_app_path_name); + Error err = OS::get_singleton()->execute("/usr/bin/hdiutil", args, true); + ERR_FAIL_COND_V(err, err); - String src_pkg; + return OK; +} + +Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) { - EditorProgress ep("export","Exporting for OSX",104); + String src_pkg_name; + EditorProgress ep("export", "Exporting for OSX", 3); if (p_debug) - src_pkg=custom_debug_package; + src_pkg_name = p_preset->get("custom_package/debug"); else - src_pkg=custom_release_package; + src_pkg_name = p_preset->get("custom_package/release"); - if (src_pkg=="") { + if (src_pkg_name == "") { String err; - src_pkg=find_export_template("osx.zip", &err); - if (src_pkg=="") { + src_pkg_name = find_export_template("osx.zip", &err); + if (src_pkg_name == "") { EditorNode::add_io_error(err); return ERR_FILE_NOT_FOUND; } } - - FileAccess *src_f=NULL; + FileAccess *src_f = NULL; zlib_filefunc_def io = zipio_create_io_from_file(&src_f); - ep.step("Creating app",0); + ep.step("Creating app", 0); - unzFile pkg = unzOpen2(src_pkg.utf8().get_data(), &io); - if (!pkg) { + unzFile src_pkg_zip = unzOpen2(src_pkg_name.utf8().get_data(), &io); + if (!src_pkg_zip) { - EditorNode::add_io_error("Could not find template app to export:\n"+src_pkg); + EditorNode::add_io_error("Could not find template app to export:\n" + src_pkg_name); return ERR_FILE_NOT_FOUND; } - ERR_FAIL_COND_V(!pkg, ERR_CANT_OPEN); - int ret = unzGoToFirstFile(pkg); + ERR_FAIL_COND_V(!src_pkg_zip, ERR_CANT_OPEN); + int ret = unzGoToFirstFile(src_pkg_zip); + + String binary_to_use = "godot_osx_" + String(p_debug ? "debug" : "release") + "."; + int bits_mode = p_preset->get("application/bits_mode"); + binary_to_use += String(bits_mode == 0 ? "fat" : bits_mode == 1 ? "64" : "32"); + + print_line("binary: " + binary_to_use); + String pkg_name; + if (p_preset->get("application/name") != "") + pkg_name = p_preset->get("application/name"); // app_name + else if (String(GlobalConfig::get_singleton()->get("application/name")) != "") + pkg_name = String(GlobalConfig::get_singleton()->get("application/name")); + else + pkg_name = "Unnamed"; + + // We're on OSX so we can export to DMG, but first we create our application bundle + String tmp_app_path_name = p_path.get_base_dir() + "/" + pkg_name + ".app"; + print_line("Exporting to " + tmp_app_path_name); + DirAccess *tmp_app_path = DirAccess::create_for_path(tmp_app_path_name); + ERR_FAIL_COND_V(!tmp_app_path, ERR_CANT_CREATE) + + ///@TODO We should delete the existing application bundle especially if we attempt to code sign it, but what is a safe way to do this? Maybe call system function so it moves to trash? + // tmp_app_path->erase_contents_recursive(); + + // Create our folder structure or rely on unzip? + print_line("Creating " + tmp_app_path_name + "/Contents/MacOS"); + Error dir_err = tmp_app_path->make_dir_recursive(tmp_app_path_name + "/Contents/MacOS"); + ERR_FAIL_COND_V(dir_err, ERR_CANT_CREATE) + print_line("Creating " + tmp_app_path_name + "/Contents/Resources"); + dir_err = tmp_app_path->make_dir_recursive(tmp_app_path_name + "/Contents/Resources"); + ERR_FAIL_COND_V(dir_err, ERR_CANT_CREATE) + + /* Now process our template */ + bool found_binary = false; + int total_size = 0; + + while (ret == UNZ_OK) { + bool is_execute = false; + + //get filename + unz_file_info info; + char fname[16384]; + ret = unzGetCurrentFileInfo(src_pkg_zip, &info, fname, 16384, NULL, 0, NULL, 0); - zlib_filefunc_def io2=io; - FileAccess *dst_f=NULL; - io2.opaque=&dst_f; - zipFile dpkg=zipOpen2(p_path.utf8().get_data(),APPEND_STATUS_CREATE,NULL,&io2); + String file = fname; + + print_line("READ: " + file); + Vector<uint8_t> data; + data.resize(info.uncompressed_size); + + //read + unzOpenCurrentFile(src_pkg_zip); + unzReadCurrentFile(src_pkg_zip, data.ptr(), data.size()); + unzCloseCurrentFile(src_pkg_zip); + + //write + + file = file.replace_first("osx_template.app/", ""); + + if (file == "Contents/Info.plist") { + print_line("parse plist"); + _fix_plist(p_preset, data, pkg_name); + } + + if (file.begins_with("Contents/MacOS/godot_")) { + if (file != "Contents/MacOS/" + binary_to_use) { + ret = unzGoToNextFile(src_pkg_zip); + continue; //ignore! + } + found_binary = true; + is_execute = true; + file = "Contents/MacOS/" + pkg_name; + } + + if (file == "Contents/Resources/icon.icns") { + //see if there is an icon + String iconpath; + if (p_preset->get("application/icon") != "") + iconpath = p_preset->get("application/icon"); + else + iconpath = GlobalConfig::get_singleton()->get("application/icon"); + print_line("icon? " + iconpath); + if (iconpath != "") { + Ref<Image> icon; + icon.instance(); + icon->load(iconpath); + if (!icon->empty()) { + print_line("loaded?"); + _make_icon(icon, data); + } + } + //bleh? + } + + if (data.size() > 0) { + print_line("ADDING: " + file + " size: " + itos(data.size())); + total_size += data.size(); + + /* write it into our application bundle */ + file = tmp_app_path_name + "/" + file; + + /* write the file, need to add chmod */ + FileAccess *f = FileAccess::open(file, FileAccess::WRITE); + ERR_FAIL_COND_V(!f, ERR_CANT_CREATE) + f->store_buffer(data.ptr(), data.size()); + f->close(); + memdelete(f); + + if (is_execute) { + // we need execute rights on this file + chmod(file.utf8().get_data(), 0755); + } else { + // seems to already be set correctly + // chmod(file.utf8().get_data(), 0644); + } + } + + ret = unzGoToNextFile(src_pkg_zip); + } + + /* we're done with our source zip */ + unzClose(src_pkg_zip); + + if (!found_binary) { + ERR_PRINTS("Requested template binary '" + binary_to_use + "' not found. It might be missing from your template archive."); + unzClose(src_pkg_zip); + return ERR_FILE_NOT_FOUND; + } + + ep.step("Making PKG", 1); + + String pack_path = tmp_app_path_name + "/Contents/Resources/" + pkg_name + ".pck"; + Error err = save_pack(p_preset, pack_path); + // chmod(pack_path.utf8().get_data(), 0644); + + if (err) { + return err; + } + + /* see if we can code sign our new package */ + if (p_preset->get("codesign/identity") != "") { + ep.step("Code signing bundle", 2); + + /* the order in which we code sign is important, this is a bit of a shame or we could do this in our loop that extracts the files from our ZIP */ + + // start with our application + err = _code_sign(p_preset, tmp_app_path_name + "/Contents/MacOS/" + pkg_name); + ERR_FAIL_COND_V(err, err); + + ///@TODO we should check the contents of /Contents/Frameworks for frameworks to sign + + // we should probably loop through all resources and sign them? + err = _code_sign(p_preset, tmp_app_path_name + "/Contents/Resources/icon.icns"); + ERR_FAIL_COND_V(err, err); + err = _code_sign(p_preset, pack_path); + ERR_FAIL_COND_V(err, err); + err = _code_sign(p_preset, tmp_app_path_name + "/Contents/Info.plist"); + ERR_FAIL_COND_V(err, err); + } + + /* and finally create a DMG */ + ep.step("Making DMG", 3); + err = _create_dmg(p_path, pkg_name, tmp_app_path_name); + ERR_FAIL_COND_V(err, err); + + return OK; +} + +#else + +/** + When exporting for OSX from any other platform we don't have access to code signing or creating DMGs so we'll wrap the bundle into a zip file. + + Should probably find a nicer way to have just one export method instead of duplicating the method like this but I would the code got very + messy with switches inside of it. +**/ +Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) { + + String src_pkg_name; + + EditorProgress ep("export", "Exporting for OSX", 104); + + if (p_debug) + src_pkg_name = p_preset->get("custom_package/debug"); + else + src_pkg_name = p_preset->get("custom_package/release"); + + if (src_pkg_name == "") { + String err; + src_pkg_name = find_export_template("osx.zip", &err); + if (src_pkg_name == "") { + EditorNode::add_io_error(err); + return ERR_FILE_NOT_FOUND; + } + } + + FileAccess *src_f = NULL; + zlib_filefunc_def io = zipio_create_io_from_file(&src_f); + + ep.step("Creating app", 0); + + unzFile src_pkg_zip = unzOpen2(src_pkg_name.utf8().get_data(), &io); + if (!src_pkg_zip) { + + EditorNode::add_io_error("Could not find template app to export:\n" + src_pkg_name); + return ERR_FILE_NOT_FOUND; + } + + ERR_FAIL_COND_V(!src_pkg_zip, ERR_CANT_OPEN); + int ret = unzGoToFirstFile(src_pkg_zip); String binary_to_use = "godot_osx_" + String(p_debug ? "debug" : "release") + "."; - binary_to_use += String(bits_mode==BITS_FAT ? "fat" : bits_mode==BITS_64 ? "64" : "32"); + int bits_mode = p_preset->get("application/bits_mode"); + binary_to_use += String(bits_mode == 0 ? "fat" : bits_mode == 1 ? "64" : "32"); - print_line("binary: "+binary_to_use); + print_line("binary: " + binary_to_use); String pkg_name; - if (app_name!="") - pkg_name=app_name; - else if (String(GlobalConfig::get_singleton()->get("application/name"))!="") - pkg_name=String(GlobalConfig::get_singleton()->get("application/name")); + if (p_preset->get("application/name") != "") + pkg_name = p_preset->get("application/name"); // app_name + else if (String(GlobalConfig::get_singleton()->get("application/name")) != "") + pkg_name = String(GlobalConfig::get_singleton()->get("application/name")); else - pkg_name="Unnamed"; + pkg_name = "Unnamed"; + /* Open our destination zip file */ + zlib_filefunc_def io2 = io; + FileAccess *dst_f = NULL; + io2.opaque = &dst_f; + zipFile dst_pkg_zip = zipOpen2(p_path.utf8().get_data(), APPEND_STATUS_CREATE, NULL, &io2); bool found_binary = false; - while(ret==UNZ_OK) { + while (ret == UNZ_OK) { //get filename unz_file_info info; char fname[16384]; - ret = unzGetCurrentFileInfo(pkg,&info,fname,16384,NULL,0,NULL,0); + ret = unzGetCurrentFileInfo(src_pkg_zip, &info, fname, 16384, NULL, 0, NULL, 0); - String file=fname; + String file = fname; - print_line("READ: "+file); + print_line("READ: " + file); Vector<uint8_t> data; data.resize(info.uncompressed_size); //read - unzOpenCurrentFile(pkg); - unzReadCurrentFile(pkg,data.ptr(),data.size()); - unzCloseCurrentFile(pkg); + unzOpenCurrentFile(src_pkg_zip); + unzReadCurrentFile(src_pkg_zip, data.ptr(), data.size()); + unzCloseCurrentFile(src_pkg_zip); //write - file = file.replace_first("osx_template.app/",""); + file = file.replace_first("osx_template.app/", ""); - - if (file=="Contents/Info.plist") { + if (file == "Contents/Info.plist") { print_line("parse plist"); - _fix_plist(data,pkg_name); + _fix_plist(p_preset, data, pkg_name); } if (file.begins_with("Contents/MacOS/godot_")) { - if (file!="Contents/MacOS/"+binary_to_use) { - ret = unzGoToNextFile(pkg); + if (file != "Contents/MacOS/" + binary_to_use) { + ret = unzGoToNextFile(src_pkg_zip); continue; //ignore! } found_binary = true; - file="Contents/MacOS/"+pkg_name; + file = "Contents/MacOS/" + pkg_name; } - if (file=="Contents/Resources/icon.icns") { + if (file == "Contents/Resources/icon.icns") { //see if there is an icon - String iconpath = GlobalConfig::get_singleton()->get("application/icon"); - print_line("icon? "+iconpath); - if (iconpath!="") { - Image icon; - icon.load(iconpath); - if (!icon.empty()) { + String iconpath; + if (p_preset->get("application/icon") != "") + iconpath = p_preset->get("application/icon"); + else + iconpath = GlobalConfig::get_singleton()->get("application/icon"); + print_line("icon? " + iconpath); + if (iconpath != "") { + Ref<Image> icon; + icon.instance(); + icon->load(iconpath); + if (!icon->empty()) { print_line("loaded?"); - _make_icon(icon,data); + _make_icon(icon, data); } } //bleh? } - file=pkg_name+".app/"+file; + if (data.size() > 0) { + print_line("ADDING: " + file + " size: " + itos(data.size())); - if (data.size()>0) { - print_line("ADDING: "+file+" size: "+itos(data.size())); + /* add it to our zip file */ + file = pkg_name + ".app/" + file; zip_fileinfo fi; - fi.tmz_date.tm_hour=info.tmu_date.tm_hour; - fi.tmz_date.tm_min=info.tmu_date.tm_min; - fi.tmz_date.tm_sec=info.tmu_date.tm_sec; - fi.tmz_date.tm_mon=info.tmu_date.tm_mon; - fi.tmz_date.tm_mday=info.tmu_date.tm_mday; - fi.tmz_date.tm_year=info.tmu_date.tm_year; - fi.dosDate=info.dosDate; - fi.internal_fa=info.internal_fa; - fi.external_fa=info.external_fa; - - int err = zipOpenNewFileInZip(dpkg, - file.utf8().get_data(), - &fi, - NULL, - 0, - NULL, - 0, - NULL, - Z_DEFLATED, - Z_DEFAULT_COMPRESSION); - - print_line("OPEN ERR: "+itos(err)); - err = zipWriteInFileInZip(dpkg,data.ptr(),data.size()); - print_line("WRITE ERR: "+itos(err)); - zipCloseFileInZip(dpkg); + fi.tmz_date.tm_hour = info.tmu_date.tm_hour; + fi.tmz_date.tm_min = info.tmu_date.tm_min; + fi.tmz_date.tm_sec = info.tmu_date.tm_sec; + fi.tmz_date.tm_mon = info.tmu_date.tm_mon; + fi.tmz_date.tm_mday = info.tmu_date.tm_mday; + fi.tmz_date.tm_year = info.tmu_date.tm_year; + fi.dosDate = info.dosDate; + fi.internal_fa = info.internal_fa; + fi.external_fa = info.external_fa; + + int err = zipOpenNewFileInZip(dst_pkg_zip, + file.utf8().get_data(), + &fi, + NULL, + 0, + NULL, + 0, + NULL, + Z_DEFLATED, + Z_DEFAULT_COMPRESSION); + + print_line("OPEN ERR: " + itos(err)); + err = zipWriteInFileInZip(dst_pkg_zip, data.ptr(), data.size()); + print_line("WRITE ERR: " + itos(err)); + zipCloseFileInZip(dst_pkg_zip); } - ret = unzGoToNextFile(pkg); + ret = unzGoToNextFile(src_pkg_zip); } if (!found_binary) { - ERR_PRINTS("Requested template binary '"+binary_to_use+"' not found. It might be missing from your template archive."); - zipClose(dpkg,NULL); - unzClose(pkg); + ERR_PRINTS("Requested template binary '" + binary_to_use + "' not found. It might be missing from your template archive."); + zipClose(dst_pkg_zip, NULL); + unzClose(src_pkg_zip); return ERR_FILE_NOT_FOUND; } + ep.step("Making PKG", 1); - ep.step("Making PKG",1); - - String pack_path=EditorSettings::get_singleton()->get_settings_path()+"/tmp/data.pck"; - FileAccess *pfs = FileAccess::open(pack_path,FileAccess::WRITE); - Error err = save_pack(pfs); - memdelete(pfs); + String pack_path = EditorSettings::get_singleton()->get_settings_path() + "/tmp/" + pkg_name + ".pck"; + Error err = save_pack(p_preset, pack_path); if (err) { - zipClose(dpkg,NULL); - unzClose(pkg); + zipClose(dst_pkg_zip, NULL); + unzClose(src_pkg_zip); return err; - } { //write datapack - zipOpenNewFileInZip(dpkg, - (pkg_name+".app/Contents/Resources/data.pck").utf8().get_data(), - NULL, - NULL, - 0, - NULL, - 0, - NULL, - Z_DEFLATED, - Z_DEFAULT_COMPRESSION); - + zipOpenNewFileInZip(dst_pkg_zip, + (pkg_name + ".app/Contents/Resources/" + pkg_name + ".pck").utf8().get_data(), + NULL, + NULL, + 0, + NULL, + 0, + NULL, + Z_DEFLATED, + Z_DEFAULT_COMPRESSION); - FileAccess *pf = FileAccess::open(pack_path,FileAccess::READ); - ERR_FAIL_COND_V(!pf,ERR_CANT_OPEN); + FileAccess *pf = FileAccess::open(pack_path, FileAccess::READ); + ERR_FAIL_COND_V(!pf, ERR_CANT_OPEN); const int BSIZE = 16384; uint8_t buf[BSIZE]; - while(true) { + while (true) { - int r = pf->get_buffer(buf,BSIZE); - if (r<=0) + int r = pf->get_buffer(buf, BSIZE); + if (r <= 0) break; - zipWriteInFileInZip(dpkg,buf,r); - + zipWriteInFileInZip(dst_pkg_zip, buf, r); } - zipCloseFileInZip(dpkg); + zipCloseFileInZip(dst_pkg_zip); memdelete(pf); - } - zipClose(dpkg,NULL); - unzClose(pkg); + zipClose(dst_pkg_zip, NULL); + unzClose(src_pkg_zip); return OK; } +#endif +bool EditorExportPlatformOSX::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const { -Error EditorExportPlatformOSX::run(int p_device, int p_flags) { - - return OK; -} - - -EditorExportPlatformOSX::EditorExportPlatformOSX() { - - Image img( _osx_logo ); - logo = Ref<ImageTexture>( memnew( ImageTexture )); - logo->create_from_image(img); - - info="Made with Godot Engine"; - identifier="org.godotengine.macgame"; - signature="godotmacgame"; - short_version="1.0"; - version="1.0"; - bits_mode=BITS_FAT; - high_resolution=false; - -} - -bool EditorExportPlatformOSX::can_export(String *r_error) const { - - - bool valid=true; + bool valid = true; String err; - if (!exists_export_template("osx.zip")) { - valid=false; - err+="No export templates found.\nDownload and install export templates.\n"; + if (!exists_export_template("osx.zip", &err)) { + valid = false; } - if (custom_debug_package!="" && !FileAccess::exists(custom_debug_package)) { - valid=false; - err+="Custom debug package not found.\n"; + if (p_preset->get("custom_package/debug") != "" && !FileAccess::exists(p_preset->get("custom_package/debug"))) { + valid = false; + err += "Custom debug package not found.\n"; } - if (custom_release_package!="" && !FileAccess::exists(custom_release_package)) { - valid=false; - err+="Custom release package not found.\n"; + if (p_preset->get("custom_package/release") != "" && !FileAccess::exists(p_preset->get("custom_package/release"))) { + valid = false; + err += "Custom release package not found.\n"; } - if (r_error) - *r_error=err; + if (!err.empty()) + r_error = err; return valid; } +EditorExportPlatformOSX::EditorExportPlatformOSX() { -EditorExportPlatformOSX::~EditorExportPlatformOSX() { + Ref<Image> img = memnew(Image(_osx_logo)); + logo.instance(); + logo->create_from_image(img); +} +EditorExportPlatformOSX::~EditorExportPlatformOSX() { } -#endif void register_osx_exporter() { -#if 0 - Ref<EditorExportPlatformOSX> exporter = Ref<EditorExportPlatformOSX>( memnew(EditorExportPlatformOSX) ); - EditorImportExport::get_singleton()->add_export_platform(exporter); -#endif + Ref<EditorExportPlatformOSX> platform; + platform.instance(); + + EditorExport::get_singleton()->add_export_platform(platform); } diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h index 123816b22d..a3036b1a8a 100644 --- a/platform/osx/os_osx.h +++ b/platform/osx/os_osx.h @@ -96,6 +96,7 @@ public: CursorShape cursor_shape; MouseMode mouse_mode; + String title; bool minimized; bool maximized; bool zoomed; @@ -116,6 +117,8 @@ public: return 1.0; } + void _update_window(); + float display_scale; protected: @@ -200,6 +203,9 @@ public: virtual void request_attention(); virtual String get_joy_guid(int p_device) const; + virtual void set_borderless_window(int p_borderless); + virtual bool get_borderless_window(); + virtual PowerState get_power_state(); virtual int get_power_seconds_left(); virtual int get_power_percent_left(); diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm index 1070de724b..87c25a5356 100644 --- a/platform/osx/os_osx.mm +++ b/platform/osx/os_osx.mm @@ -53,6 +53,10 @@ #include <sys/types.h> #include <unistd.h> +#if MAC_OS_X_VERSION_MAX_ALLOWED < 101200 +#define NSWindowStyleMaskBorderless NSBorderlessWindowMask +#endif + static NSRect convertRectToBacking(NSRect contentRect) { #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 @@ -813,7 +817,13 @@ void OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_au // Don't use accumulation buffer support; it's not accelerated // Aux buffers probably aren't accelerated either - unsigned int styleMask = NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | (p_desired.resizable ? NSResizableWindowMask : 0); + unsigned int styleMask; + + if (p_desired.borderless_window) { + styleMask = NSWindowStyleMaskBorderless; + } else { + styleMask = NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | (p_desired.resizable ? NSResizableWindowMask : 0); + } window_object = [[GodotWindow alloc] initWithContentRect:NSMakeRect(0, 0, p_desired.width, p_desired.height) @@ -911,6 +921,8 @@ void OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_au [NSApp activateIgnoringOtherApps:YES]; + _update_window(); + [window_object makeKeyAndOrderFront:nil]; if (p_desired.fullscreen) @@ -970,7 +982,8 @@ void OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_au displayScale = [[screenArray objectAtIndex:i] backingScaleFactor]; } - NSRect nsrect = [[screenArray objectAtIndex:i] visibleFrame]; + // Note: Use frame to get the whole screen size + NSRect nsrect = [[screenArray objectAtIndex:i] frame]; Rect2 rect = Rect2(nsrect.origin.x, nsrect.origin.y, nsrect.size.width, nsrect.size.height); rect.position *= displayScale; rect.size *= displayScale; @@ -1125,6 +1138,7 @@ int OS_OSX::get_mouse_button_state() const { } void OS_OSX::set_window_title(const String &p_title) { + title = p_title; [window_object setTitle:[NSString stringWithUTF8String:p_title.utf8().get_data()]]; } @@ -1288,6 +1302,31 @@ Size2 OS_OSX::get_screen_size(int p_screen) const { return screens[p_screen].size; }; +void OS_OSX::_update_window() { + bool borderless_full = false; + + if (get_borderless_window()) { + NSRect frameRect = [window_object frame]; + NSRect screenRect = [[window_object screen] frame]; + + // Check if our window covers up the screen + if (frameRect.origin.x <= screenRect.origin.x && frameRect.origin.y <= frameRect.origin.y && + frameRect.size.width >= screenRect.size.width && frameRect.size.height >= screenRect.size.height) { + borderless_full = true; + } + } + + if (borderless_full) { + // If the window covers up the screen set the level to above the main menu and hide on deactivate + [window_object setLevel:NSMainMenuWindowLevel + 1]; + [window_object setHidesOnDeactivate:YES]; + } else { + // Reset these when our window is not a borderless window that covers up the screen + [window_object setLevel:NSNormalWindowLevel]; + [window_object setHidesOnDeactivate:NO]; + } +} + Point2 OS_OSX::get_window_position() const { Size2 wp([window_object frame].origin.x, [window_object frame].origin.y); @@ -1300,6 +1339,8 @@ void OS_OSX::set_window_position(const Point2 &p_position) { Point2 size = p_position; size /= display_scale; [window_object setFrame:NSMakeRect(size.x, size.y, [window_object frame].size.width, [window_object frame].size.height) display:YES]; + + _update_window(); }; Size2 OS_OSX::get_window_size() const { @@ -1311,17 +1352,22 @@ void OS_OSX::set_window_size(const Size2 p_size) { Size2 size = p_size; - // NSRect used by setFrame includes the title bar, so add it to our size.y - CGFloat menuBarHeight = [[[NSApplication sharedApplication] mainMenu] menuBarHeight]; - if (menuBarHeight != 0.f) { - size.y += menuBarHeight; + if (get_borderless_window() == false) { + // NSRect used by setFrame includes the title bar, so add it to our size.y + CGFloat menuBarHeight = [[[NSApplication sharedApplication] mainMenu] menuBarHeight]; + if (menuBarHeight != 0.f) { + size.y += menuBarHeight; #if MAC_OS_X_VERSION_MAX_ALLOWED <= 101104 - } else { - size.y += [[NSStatusBar systemStatusBar] thickness]; + } else { + size.y += [[NSStatusBar systemStatusBar] thickness]; #endif + } } + NSRect frame = [window_object frame]; [window_object setFrame:NSMakeRect(frame.origin.x, frame.origin.y, size.x, size.y) display:YES]; + + _update_window(); }; void OS_OSX::set_window_fullscreen(bool p_enabled) { @@ -1403,6 +1449,35 @@ void OS_OSX::request_attention() { [NSApp requestUserAttention:NSCriticalRequest]; } +void OS_OSX::set_borderless_window(int p_borderless) { + + // OrderOut prevents a lose focus bug with the window + [window_object orderOut:nil]; + + if (p_borderless) { + [window_object setStyleMask:NSWindowStyleMaskBorderless]; + } else { + [window_object setStyleMask:NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask]; + + // Force update of the window styles + NSRect frameRect = [window_object frame]; + [window_object setFrame:NSMakeRect(frameRect.origin.x, frameRect.origin.y, frameRect.size.width + 1, frameRect.size.height) display:NO]; + [window_object setFrame:frameRect display:NO]; + + // Restore the window title + [window_object setTitle:[NSString stringWithUTF8String:title.utf8().get_data()]]; + } + + _update_window(); + + [window_object makeKeyAndOrderFront:nil]; +} + +bool OS_OSX::get_borderless_window() { + + return [window_object styleMask] == NSWindowStyleMaskBorderless; +} + String OS_OSX::get_executable_path() const { int ret; diff --git a/platform/server/detect.py b/platform/server/detect.py index 32f3c55135..2bb4b59e94 100644 --- a/platform/server/detect.py +++ b/platform/server/detect.py @@ -1,4 +1,3 @@ - import os import sys @@ -13,17 +12,16 @@ def get_name(): def can_build(): - if (os.name != "posix"): + if (os.name != "posix" or sys.platform == "darwin"): return False - return True # enabled + return True def get_opts(): return [ - ('use_llvm', 'Use llvm compiler', 'no'), - ('force_32_bits', 'Force 32 bits binary', 'no') + ('use_llvm', 'Use the LLVM compiler', 'no'), ] @@ -35,46 +33,59 @@ def get_flags(): def configure(env): - env.Append(CPPPATH=['#platform/server']) - if (env["use_llvm"] == "yes"): - env["CC"] = "clang" - env["CXX"] = "clang++" - env["LD"] = "clang++" - - is64 = sys.maxsize > 2**32 - - if (env["bits"] == "default"): - if (is64): - env["bits"] = "64" - else: - env["bits"] = "32" - - # if (env["tools"]=="no"): - # #no tools suffix - # env['OBJSUFFIX'] = ".nt"+env['OBJSUFFIX'] - # env['LIBSUFFIX'] = ".nt"+env['LIBSUFFIX'] + ## Build type if (env["target"] == "release"): - env.Append(CCFLAGS=['-O2', '-ffast-math', '-fomit-frame-pointer']) elif (env["target"] == "release_debug"): - env.Append(CCFLAGS=['-O2', '-ffast-math', '-DDEBUG_ENABLED']) elif (env["target"] == "debug"): - env.Append(CCFLAGS=['-g2', '-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED']) + ## Architecture + + is64 = sys.maxsize > 2**32 + if (env["bits"] == "default"): + env["bits"] = "64" if is64 else "32" + + ## Compiler configuration + + if (env["use_llvm"] == "yes"): + if ('clang++' not in env['CXX']): + env["CC"] = "clang" + env["CXX"] = "clang++" + env["LD"] = "clang++" + env.Append(CPPFLAGS=['-DTYPED_METHOD_BIND']) + env.extra_suffix = ".llvm" + env.extra_suffix + + ## Dependencies - # Shared libraries, when requested + # FIXME: Check for existence of the libs before parsing their flags with pkg-config if (env['builtin_openssl'] == 'no'): + # Currently not compatible with OpenSSL 1.1.0+ + # https://github.com/godotengine/godot/issues/8624 + import subprocess + openssl_version = subprocess.check_output(['pkg-config', 'openssl', '--modversion']).strip('\n') + if (openssl_version >= "1.1.0"): + print("Error: Found system-installed OpenSSL %s, currently only supporting version 1.0.x." % openssl_version) + print("Aborting.. You can compile with 'builtin_openssl=yes' to use the bundled version.\n") + sys.exit(255) + env.ParseConfig('pkg-config openssl --cflags --libs') if (env['builtin_libwebp'] == 'no'): env.ParseConfig('pkg-config libwebp --cflags --libs') + # freetype depends on libpng and zlib, so bundling one of them while keeping others + # as shared libraries leads to weird issues + if (env['builtin_freetype'] == 'yes' or env['builtin_libpng'] == 'yes' or env['builtin_zlib'] == 'yes'): + env['builtin_freetype'] = 'yes' + env['builtin_libpng'] = 'yes' + env['builtin_zlib'] = 'yes' + if (env['builtin_freetype'] == 'no'): env.ParseConfig('pkg-config freetype2 --cflags --libs') @@ -109,11 +120,12 @@ def configure(env): if (env['builtin_libogg'] == 'no'): env.ParseConfig('pkg-config ogg --cflags --libs') + ## Flags - env.Append(CPPFLAGS=['-DSERVER_ENABLED', '-DUNIX_ENABLED']) - env.Append(LIBS=['pthread', 'z']) # TODO detect linux/BSD! + # Linkflags below this line should typically stay the last ones + if (env['builtin_zlib'] == 'no'): + env.ParseConfig('pkg-config zlib --cflags --libs') - if (env["CXX"] == "clang++"): - env.Append(CPPFLAGS=['-DTYPED_METHOD_BIND']) - env["CC"] = "clang" - env["LD"] = "clang++" + env.Append(CPPPATH=['#platform/server']) + env.Append(CPPFLAGS=['-DSERVER_ENABLED', '-DUNIX_ENABLED']) + env.Append(LIBS=['pthread']) diff --git a/platform/uwp/detect.py b/platform/uwp/detect.py index baff7f9788..ca469d0056 100644 --- a/platform/uwp/detect.py +++ b/platform/uwp/detect.py @@ -1,8 +1,7 @@ +import methods import os - -import sys import string -import methods +import sys def is_active(): @@ -26,7 +25,9 @@ def can_build(): def get_opts(): - return [] + + return [ + ] def get_flags(): @@ -39,16 +40,36 @@ def get_flags(): def configure(env): - if(env["bits"] != "default"): - print "Error: bits argument is disabled for MSVC" - print ("Bits argument is not supported for MSVC compilation. Architecture depends on the Native/Cross Compile Tools Prompt/Developer Console (or Visual Studio settings)" - + " that is being used to run SCons. As a consequence, bits argument is disabled. Run scons again without bits argument (example: scons p=uwp) and SCons will attempt to detect what MSVC compiler" - + " will be executed and inform you.") + if (env["bits"] != "default"): + print("Error: bits argument is disabled for MSVC") + print(""" + Bits argument is not supported for MSVC compilation. Architecture depends on the Native/Cross Compile Tools Prompt/Developer Console + (or Visual Studio settings) that is being used to run SCons. As a consequence, bits argument is disabled. Run scons again without bits + argument (example: scons p=uwp) and SCons will attempt to detect what MSVC compiler will be executed and inform you. + """) sys.exit() - arch = "" - env['ENV'] = os.environ + ## Build type + + if (env["target"] == "release"): + env.Append(CPPFLAGS=['/O2', '/GL']) + env.Append(CPPFLAGS=['/MD']) + env.Append(LINKFLAGS=['/SUBSYSTEM:WINDOWS', '/LTCG']) + + elif (env["target"] == "release_debug"): + env.Append(CCFLAGS=['/O2', '/Zi', '/DDEBUG_ENABLED']) + env.Append(CPPFLAGS=['/MD']) + env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE']) + + elif (env["target"] == "debug"): + env.Append(CCFLAGS=['/Zi', '/DDEBUG_ENABLED', '/DDEBUG_MEMORY_ENABLED']) + env.Append(CPPFLAGS=['/MDd']) + env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE']) + env.Append(LINKFLAGS=['/DEBUG']) + + ## Compiler configuration + env['ENV'] = os.environ vc_base_path = os.environ['VCTOOLSINSTALLDIR'] if "VCTOOLSINSTALLDIR" in os.environ else os.environ['VCINSTALLDIR'] # ANGLE @@ -60,9 +81,12 @@ def configure(env): if os.path.isfile(str(os.getenv("ANGLE_SRC_PATH")) + "/winrt/10/src/angle.sln"): env["build_angle"] = True + ## Architecture + + arch = "" if os.getenv('Platform') == "ARM": - print "Compiled program architecture will be an ARM executable. (forcing bits=32)." + print("Compiled program architecture will be an ARM executable. (forcing bits=32).") arch = "arm" env["bits"] = "32" @@ -74,17 +98,16 @@ def configure(env): env.Append(LIBPATH=[angle_root + '/winrt/10/src/Release_ARM/lib']) else: - compiler_version_str = methods.detect_visual_c_compiler_version(env['ENV']) if(compiler_version_str == "amd64" or compiler_version_str == "x86_amd64"): env["bits"] = "64" - print "Compiled program architecture will be a x64 executable (forcing bits=64)." + print("Compiled program architecture will be a x64 executable (forcing bits=64).") elif (compiler_version_str == "x86" or compiler_version_str == "amd64_x86"): env["bits"] = "32" - print "Compiled program architecture will be a x86 executable. (forcing bits=32)." + print("Compiled program architecture will be a x86 executable. (forcing bits=32).") else: - print "Failed to detect MSVC compiler architecture version... Defaulting to 32bit executable settings (forcing bits=32). Compilation attempt will continue, but SCons can not detect for what architecture this build is compiled for. You should check your settings/compilation setup." + print("Failed to detect MSVC compiler architecture version... Defaulting to 32bit executable settings (forcing bits=32). Compilation attempt will continue, but SCons can not detect for what architecture this build is compiled for. You should check your settings/compilation setup.") env["bits"] = "32" if (env["bits"] == "32"): @@ -106,48 +129,30 @@ def configure(env): env.Append(LIBPATH=[os.environ['VCINSTALLDIR'] + 'lib/store/amd64']) env.Append(LIBPATH=[angle_root + '/winrt/10/src/Release_x64/lib']) - env.Append(CPPPATH=['#platform/uwp', '#drivers/windows']) - env.Append(LINKFLAGS=['/MANIFEST:NO', '/NXCOMPAT', '/DYNAMICBASE', '/WINMD', '/APPCONTAINER', '/ERRORREPORT:PROMPT', '/NOLOGO', '/TLBID:1', '/NODEFAULTLIB:"kernel32.lib"', '/NODEFAULTLIB:"ole32.lib"']) - env.Append(CPPFLAGS=['/D', '__WRL_NO_DEFAULT_LIB__', '/D', 'WIN32']) - - env.Append(CPPFLAGS=['/AI', vc_base_path + 'lib/store/references']) - env.Append(CPPFLAGS=['/AI', vc_base_path + 'lib/x86/store/references']) - - if (env["target"] == "release"): - - env.Append(CPPFLAGS=['/O2', '/GL']) - env.Append(CPPFLAGS=['/MD']) - env.Append(LINKFLAGS=['/SUBSYSTEM:WINDOWS', '/LTCG']) + env["PROGSUFFIX"] = "." + arch + env["PROGSUFFIX"] + env["OBJSUFFIX"] = "." + arch + env["OBJSUFFIX"] + env["LIBSUFFIX"] = "." + arch + env["LIBSUFFIX"] - elif (env["target"] == "release_debug"): + ## Compile flags - env.Append(CCFLAGS=['/O2', '/Zi', '/DDEBUG_ENABLED']) - env.Append(CPPFLAGS=['/MD']) - env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE']) + env.Append(CPPPATH=['#platform/uwp', '#drivers/windows']) + env.Append(CCFLAGS=['/DUWP_ENABLED', '/DWINDOWS_ENABLED', '/DTYPED_METHOD_BIND']) + env.Append(CCFLAGS=['/DGLES2_ENABLED', '/DGL_GLEXT_PROTOTYPES', '/DEGL_EGLEXT_PROTOTYPES', '/DANGLE_ENABLED']) + winver = "0x0602" # Windows 8 is the minimum target for UWP build + env.Append(CCFLAGS=['/DWINVER=%s' % winver, '/D_WIN32_WINNT=%s' % winver]) - elif (env["target"] == "debug"): + env.Append(CPPFLAGS=['/D', '__WRL_NO_DEFAULT_LIB__', '/D', 'WIN32']) - env.Append(CCFLAGS=['/Zi', '/DDEBUG_ENABLED', '/DDEBUG_MEMORY_ENABLED']) - env.Append(CPPFLAGS=['/MDd']) - env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE']) - env.Append(LINKFLAGS=['/DEBUG']) + env.Append(CPPFLAGS=['/AI', vc_base_path + 'lib/store/references']) + env.Append(CPPFLAGS=['/AI', vc_base_path + 'lib/x86/store/references']) env.Append(CCFLAGS=string.split('/FS /MP /GS /wd"4453" /wd"28204" /wd"4291" /Zc:wchar_t /Gm- /fp:precise /D "_UNICODE" /D "UNICODE" /D "WINAPI_FAMILY=WINAPI_FAMILY_APP" /errorReport:prompt /WX- /Zc:forScope /Gd /EHsc /nologo')) env.Append(CXXFLAGS=string.split('/ZW /FS')) env.Append(CCFLAGS=['/AI', vc_base_path + '\\vcpackages', '/AI', os.environ['WINDOWSSDKDIR'] + '\\References\\CommonConfiguration\\Neutral']) - env["PROGSUFFIX"] = "." + arch + env["PROGSUFFIX"] - env["OBJSUFFIX"] = "." + arch + env["OBJSUFFIX"] - env["LIBSUFFIX"] = "." + arch + env["LIBSUFFIX"] - - env.Append(CCFLAGS=['/DUWP_ENABLED']) - env.Append(CCFLAGS=['/DWINDOWS_ENABLED']) - env.Append(CCFLAGS=['/DTYPED_METHOD_BIND']) - - env.Append(CCFLAGS=['/DGLES2_ENABLED', '/DGL_GLEXT_PROTOTYPES', '/DEGL_EGLEXT_PROTOTYPES', '/DANGLE_ENABLED']) + ## Link flags - winver = "0x0602" # Windows 8 is the minimum target for UWP build - env.Append(CCFLAGS=['/DWINVER=%s' % winver, '/D_WIN32_WINNT=%s' % winver]) + env.Append(LINKFLAGS=['/MANIFEST:NO', '/NXCOMPAT', '/DYNAMICBASE', '/WINMD', '/APPCONTAINER', '/ERRORREPORT:PROMPT', '/NOLOGO', '/TLBID:1', '/NODEFAULTLIB:"kernel32.lib"', '/NODEFAULTLIB:"ole32.lib"']) LIBS = [ 'WindowsApp', @@ -164,8 +169,3 @@ def configure(env): env['BUILDERS']['Program'] = methods.precious_program env.Append(BUILDERS={'ANGLE': env.Builder(action=angle_build_cmd)}) - - env.Append(BUILDERS={'GLSL120': env.Builder(action=methods.build_legacygl_headers, suffix='glsl.h', src_suffix='.glsl')}) - env.Append(BUILDERS={'GLSL': env.Builder(action=methods.build_glsl_headers, suffix='glsl.h', src_suffix='.glsl')}) - env.Append(BUILDERS={'HLSL9': env.Builder(action=methods.build_hlsl_dx9_headers, suffix='hlsl.h', src_suffix='.hlsl')}) - env.Append(BUILDERS={'GLSL120GLES': env.Builder(action=methods.build_gles2_headers, suffix='glsl.h', src_suffix='.glsl')}) diff --git a/platform/windows/detect.py b/platform/windows/detect.py index 5e56c1db49..a2bc5a11ab 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -1,104 +1,7 @@ -# -# tested on | Windows native | Linux cross-compilation -# ----------------------------+-------------------+--------------------------- -# Visual C++ Build Tools 2015 | WORKS | n/a -# MSVS C++ 2010 Express | WORKS | n/a -# Mingw-w64 | WORKS | WORKS -# Mingw-w32 | WORKS | WORKS -# MinGW | WORKS | untested -# -##### -# Note about Visual C++ Build Tools : -# -# - Visual C++ Build Tools is the standalone MSVC compiler : -# http://landinghub.visualstudio.com/visual-cpp-build-tools -# -##### -# Notes about MSVS C++ : -# -# - MSVC2010-Express compiles to 32bits only. -# -##### -# Notes about Mingw-w64 and Mingw-w32 under Windows : -# -# - both can be installed using the official installer : -# http://mingw-w64.sourceforge.net/download.php#mingw-builds -# -# - if you want to compile both 32bits and 64bits, don't forget to -# run the installer twice to install them both. -# -# - install them into a path that does not contain spaces -# ( example : "C:/Mingw-w32", "C:/Mingw-w64" ) -# -# - if you want to compile faster using the "-j" option, don't forget -# to install the appropriate version of the Pywin32 python extension -# available from : http://sourceforge.net/projects/pywin32/files/ -# -# - before running scons, you must add into the environment path -# the path to the "/bin" directory of the Mingw version you want -# to use : -# -# set PATH=C:/Mingw-w32/bin;%PATH% -# -# - then, scons should be able to detect gcc. -# - Mingw-w32 only compiles 32bits. -# - Mingw-w64 only compiles 64bits. -# -# - it is possible to add them both at the same time into the PATH env, -# if you also define the MINGW32_PREFIX and MINGW64_PREFIX environment -# variables. -# For instance, you could store that set of commands into a .bat script -# that you would run just before scons : -# -# set PATH=C:\mingw-w32\bin;%PATH% -# set PATH=C:\mingw-w64\bin;%PATH% -# set MINGW32_PREFIX=C:\mingw-w32\bin\ -# set MINGW64_PREFIX=C:\mingw-w64\bin\ -# -##### -# Notes about Mingw, Mingw-w64 and Mingw-w32 under Linux : -# -# - default toolchain prefixes are : -# "i586-mingw32msvc-" for MinGW -# "i686-w64-mingw32-" for Mingw-w32 -# "x86_64-w64-mingw32-" for Mingw-w64 -# -# - if both MinGW and Mingw-w32 are installed on your system -# Mingw-w32 should take the priority over MinGW. -# -# - it is possible to manually override prefixes by defining -# the MINGW32_PREFIX and MINGW64_PREFIX environment variables. -# -##### -# Notes about Mingw under Windows : -# -# - this is the MinGW version from http://mingw.org/ -# - install it into a path that does not contain spaces -# ( example : "C:/MinGW" ) -# - several DirectX headers might be missing. You can copy them into -# the C:/MinGW/include" directory from this page : -# https://code.google.com/p/mingw-lib/source/browse/trunk/working/avcodec_to_widget_5/directx_include/ -# - before running scons, add the path to the "/bin" directory : -# set PATH=C:/MinGW/bin;%PATH% -# - scons should be able to detect gcc. -# - -##### -# TODO : -# -# - finish to cleanup this script to remove all the remains of previous hacks and workarounds -# - make it work with the Windows7 SDK that is supposed to enable 64bits compilation for MSVC2010-Express -# - confirm it works well with other Visual Studio versions. -# - update the wiki about the pywin32 extension required for the "-j" option under Windows. -# - update the wiki to document MINGW32_PREFIX and MINGW64_PREFIX -# - +import methods import os - import sys -import methods - def is_active(): return True @@ -115,7 +18,7 @@ def can_build(): if (os.getenv("VCINSTALLDIR")): return True else: - print("\nMSVC not detected, attempting Mingw.") + print("\nMSVC not detected, attempting MinGW.") mingw32 = "" mingw64 = "" if (os.getenv("MINGW32_PREFIX")): @@ -126,7 +29,7 @@ def can_build(): test = "gcc --version > NUL 2>&1" if os.system(test) != 0 and os.system(mingw32 + test) != 0 and os.system(mingw64 + test) != 0: print("- could not detect gcc.") - print("Please, make sure a path to a Mingw /bin directory is accessible into the environment PATH.\n") + print("Please, make sure a path to a MinGW /bin directory is accessible into the environment PATH.\n") return False else: print("- gcc detected.") @@ -172,8 +75,8 @@ def get_opts(): mingw64 = os.getenv("MINGW64_PREFIX") return [ - ('mingw_prefix', 'Mingw Prefix', mingw32), - ('mingw_prefix_64', 'Mingw Prefix 64 bits', mingw64), + ('mingw_prefix', 'MinGW Prefix', mingw32), + ('mingw_prefix_64', 'MinGW Prefix 64 bits', mingw64), ] @@ -211,55 +114,86 @@ def configure(env): # Targeted Windows version: Vista (and later) winver = "0x0600" # Windows Vista is the minimum target for windows builds - env['is_mingw'] = False - if (os.name == "nt" and os.getenv("VCINSTALLDIR")): - # build using visual studio + if (os.name == "nt" and os.getenv("VCINSTALLDIR")): # MSVC + env['ENV']['TMP'] = os.environ['TMP'] - env.Append(CPPPATH=['#platform/windows/include']) - env.Append(LIBPATH=['#platform/windows/lib']) - env.Append(CCFLAGS=['/DWINVER=%s' % winver, '/D_WIN32_WINNT=%s' % winver]) - if (env["target"] == "release"): + ## Build type + if (env["target"] == "release"): env.Append(CCFLAGS=['/O2']) env.Append(LINKFLAGS=['/SUBSYSTEM:WINDOWS']) env.Append(LINKFLAGS=['/ENTRY:mainCRTStartup']) elif (env["target"] == "release_debug"): - env.Append(CCFLAGS=['/O2', '/DDEBUG_ENABLED']) env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE']) - elif (env["target"] == "debug_release"): + elif (env["target"] == "debug_release"): env.Append(CCFLAGS=['/Z7', '/Od']) env.Append(LINKFLAGS=['/DEBUG']) env.Append(LINKFLAGS=['/SUBSYSTEM:WINDOWS']) env.Append(LINKFLAGS=['/ENTRY:mainCRTStartup']) elif (env["target"] == "debug"): - env.Append(CCFLAGS=['/Z7', '/DDEBUG_ENABLED', '/DDEBUG_MEMORY_ENABLED', '/DD3D_DEBUG_INFO', '/Od']) env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE']) env.Append(LINKFLAGS=['/DEBUG']) - env.Append(CCFLAGS=['/MT', '/Gd', '/GR', '/nologo']) + ## Architecture + + # Note: this detection/override code from here onward should be here instead of in SConstruct because it's platform and compiler specific (MSVC/Windows) + if (env["bits"] != "default"): + print("Error: bits argument is disabled for MSVC") + print(""" + Bits argument is not supported for MSVC compilation. Architecture depends on the Native/Cross Compile Tools Prompt/Developer Console + (or Visual Studio settings) that is being used to run SCons. As a consequence, bits argument is disabled. Run scons again without bits + argument (example: scons p=windows) and SCons will attempt to detect what MSVC compiler will be executed and inform you. + """) + sys.exit() + + # Forcing bits argument because MSVC does not have a flag to set this through SCons... it's different compilers (cl.exe's) called from the proper command prompt + # that decide the architecture that is build for. Scons can only detect the os.getenviron (because vsvarsall.bat sets a lot of stuff for cl.exe to work with) + env["bits"] = "32" + env["x86_libtheora_opt_vc"] = True + + ## Compiler configuration + + env['ENV'] = os.environ + # This detection function needs the tools env (that is env['ENV'], not SCons's env), and that is why it's this far bellow in the code + compiler_version_str = methods.detect_visual_c_compiler_version(env['ENV']) + + print("Detected MSVC compiler: " + compiler_version_str) + # If building for 64bit architecture, disable assembly optimisations for 32 bit builds (theora as of writting)... vc compiler for 64bit can not compile _asm + if(compiler_version_str == "amd64" or compiler_version_str == "x86_amd64"): + env["bits"] = "64" + env["x86_libtheora_opt_vc"] = False + print("Compiled program architecture will be a 64 bit executable (forcing bits=64).") + elif (compiler_version_str == "x86" or compiler_version_str == "amd64_x86"): + print("Compiled program architecture will be a 32 bit executable. (forcing bits=32).") + else: + print("Failed to detect MSVC compiler architecture version... Defaulting to 32bit executable settings (forcing bits=32). Compilation attempt will continue, but SCons can not detect for what architecture this build is compiled for. You should check your settings/compilation setup.") + + ## Compile flags + + env.Append(CCFLAGS=['/MT', '/Gd', '/GR', '/nologo']) env.Append(CXXFLAGS=['/TP']) env.Append(CPPFLAGS=['/DMSVC', '/GR', ]) env.Append(CCFLAGS=['/I' + os.getenv("WindowsSdkDir") + "/Include"]) + env.Append(CCFLAGS=['/DWINDOWS_ENABLED']) + env.Append(CCFLAGS=['/DOPENGL_ENABLED']) env.Append(CCFLAGS=['/DRTAUDIO_ENABLED']) - env.Append(CCFLAGS=['/DWIN32']) env.Append(CCFLAGS=['/DTYPED_METHOD_BIND']) + env.Append(CCFLAGS=['/DWIN32']) + env.Append(CCFLAGS=['/DWINVER=%s' % winver, '/D_WIN32_WINNT=%s' % winver]) + if env["bits"] == "64": + env.Append(CCFLAGS=['/D_WIN64']) - env.Append(CCFLAGS=['/DOPENGL_ENABLED']) LIBS = ['winmm', 'opengl32', 'dsound', 'kernel32', 'ole32', 'oleaut32', 'user32', 'gdi32', 'IPHLPAPI', 'Shlwapi', 'wsock32', 'Ws2_32', 'shell32', 'advapi32', 'dinput8', 'dxguid'] env.Append(LINKFLAGS=[p + env["LIBSUFFIX"] for p in LIBS]) env.Append(LIBPATH=[os.getenv("WindowsSdkDir") + "/Lib"]) - if (os.getenv("DXSDK_DIR")): - DIRECTX_PATH = os.getenv("DXSDK_DIR") - else: - DIRECTX_PATH = "C:/Program Files/Microsoft DirectX SDK (March 2009)" if (os.getenv("VCINSTALLDIR")): VC_PATH = os.getenv("VCINSTALLDIR") @@ -268,51 +202,37 @@ def configure(env): env.Append(CCFLAGS=["/I" + p for p in os.getenv("INCLUDE").split(";")]) env.Append(LIBPATH=[p for p in os.getenv("LIB").split(";")]) - env.Append(CCFLAGS=["/I" + DIRECTX_PATH + "/Include"]) - env.Append(LIBPATH=[DIRECTX_PATH + "/Lib/x86"]) - env['ENV'] = os.environ - - # This detection function needs the tools env (that is env['ENV'], not SCons's env), and that is why it's this far bellow in the code - compiler_version_str = methods.detect_visual_c_compiler_version(env['ENV']) - - # Note: this detection/override code from here onward should be here instead of in SConstruct because it's platform and compiler specific (MSVC/Windows) - if(env["bits"] != "default"): - print "Error: bits argument is disabled for MSVC" - print ("Bits argument is not supported for MSVC compilation. Architecture depends on the Native/Cross Compile Tools Prompt/Developer Console (or Visual Studio settings)" - + " that is being used to run SCons. As a consequence, bits argument is disabled. Run scons again without bits argument (example: scons p=windows) and SCons will attempt to detect what MSVC compiler" - + " will be executed and inform you.") - sys.exit() - - # Forcing bits argument because MSVC does not have a flag to set this through SCons... it's different compilers (cl.exe's) called from the proper command prompt - # that decide the architecture that is build for. Scons can only detect the os.getenviron (because vsvarsall.bat sets a lot of stuff for cl.exe to work with) - env["bits"] = "32" - env["x86_libtheora_opt_vc"] = True - - print "Detected MSVC compiler: " + compiler_version_str - # If building for 64bit architecture, disable assembly optimisations for 32 bit builds (theora as of writting)... vc compiler for 64bit can not compile _asm - if(compiler_version_str == "amd64" or compiler_version_str == "x86_amd64"): - env["bits"] = "64" - env["x86_libtheora_opt_vc"] = False - print "Compiled program architecture will be a 64 bit executable (forcing bits=64)." - elif (compiler_version_str == "x86" or compiler_version_str == "amd64_x86"): - print "Compiled program architecture will be a 32 bit executable. (forcing bits=32)." - else: - print "Failed to detect MSVC compiler architecture version... Defaulting to 32bit executable settings (forcing bits=32). Compilation attempt will continue, but SCons can not detect for what architecture this build is compiled for. You should check your settings/compilation setup." - if env["bits"] == "64": - env.Append(CCFLAGS=['/D_WIN64']) # Incremental linking fix env['BUILDERS']['ProgramOriginal'] = env['BUILDERS']['Program'] env['BUILDERS']['Program'] = methods.precious_program - else: + else: # MinGW # Workaround for MinGW. See: # http://www.scons.org/wiki/LongCmdLinesOnWin32 env.use_windows_spawn_fix() - # build using mingw - env.Append(CCFLAGS=['-DWINVER=%s' % winver, '-D_WIN32_WINNT=%s' % winver]) + ## Build type + + if (env["target"] == "release"): + env.Append(CCFLAGS=['-msse2']) + + if (env["bits"] == "64"): + env.Append(CCFLAGS=['-O3']) + else: + env.Append(CCFLAGS=['-O2']) + + env.Append(LINKFLAGS=['-Wl,--subsystem,windows']) + + elif (env["target"] == "release_debug"): + env.Append(CCFLAGS=['-O2', '-DDEBUG_ENABLED']) + + elif (env["target"] == "debug"): + env.Append(CCFLAGS=['-g', '-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED']) + + ## Compiler configuration + if (os.name == "nt"): env['ENV']['TMP'] = os.environ['TMP'] # way to go scons, you can be so stupid sometimes else: @@ -339,30 +259,6 @@ def configure(env): else: nulstr = ">nul" - # if os.system(mingw_prefix+"gcc --version"+nulstr)!=0: - # #not really super consistent but.. - # print("Can't find Windows compiler: "+mingw_prefix) - # sys.exit(255) - - if (env["target"] == "release"): - - env.Append(CCFLAGS=['-msse2']) - - if (env["bits"] == "64"): - env.Append(CCFLAGS=['-O3']) - else: - env.Append(CCFLAGS=['-O2']) - - env.Append(LINKFLAGS=['-Wl,--subsystem,windows']) - - elif (env["target"] == "release_debug"): - - env.Append(CCFLAGS=['-O2', '-DDEBUG_ENABLED']) - - elif (env["target"] == "debug"): - - env.Append(CCFLAGS=['-g', '-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED']) - env["CC"] = mingw_prefix + "gcc" env['AS'] = mingw_prefix + "as" env['CXX'] = mingw_prefix + "g++" @@ -371,29 +267,15 @@ def configure(env): env['LD'] = mingw_prefix + "g++" env["x86_libtheora_opt_gcc"] = True - #env['CC'] = "winegcc" - #env['CXX'] = "wineg++" + ## Compile flags env.Append(CCFLAGS=['-DWINDOWS_ENABLED', '-mwindows']) - env.Append(CPPFLAGS=['-DRTAUDIO_ENABLED']) env.Append(CCFLAGS=['-DOPENGL_ENABLED']) + env.Append(CCFLAGS=['-DRTAUDIO_ENABLED']) + env.Append(CCFLAGS=['-DWINVER=%s' % winver, '-D_WIN32_WINNT=%s' % winver]) env.Append(LIBS=['mingw32', 'opengl32', 'dsound', 'ole32', 'd3d9', 'winmm', 'gdi32', 'iphlpapi', 'shlwapi', 'wsock32', 'ws2_32', 'kernel32', 'oleaut32', 'dinput8', 'dxguid']) - # if (env["bits"]=="32"): - # env.Append(LIBS=['gcc_s']) - # #--with-arch=i686 - # env.Append(CPPFLAGS=['-march=i686']) - # env.Append(LINKFLAGS=['-march=i686']) - - #'d3dx9d' env.Append(CPPFLAGS=['-DMINGW_ENABLED']) - # env.Append(LINKFLAGS=['-g']) # resrc - env['is_mingw'] = True env.Append(BUILDERS={'RES': env.Builder(action=build_res_file, suffix='.o', src_suffix='.rc')}) - - env.Append(BUILDERS={'GLSL120': env.Builder(action=methods.build_legacygl_headers, suffix='glsl.h', src_suffix='.glsl')}) - env.Append(BUILDERS={'GLSL': env.Builder(action=methods.build_glsl_headers, suffix='glsl.h', src_suffix='.glsl')}) - env.Append(BUILDERS={'HLSL9': env.Builder(action=methods.build_hlsl_dx9_headers, suffix='hlsl.h', src_suffix='.hlsl')}) - env.Append(BUILDERS={'GLSL120GLES': env.Builder(action=methods.build_gles2_headers, suffix='glsl.h', src_suffix='.glsl')}) diff --git a/platform/windows/export/export.cpp b/platform/windows/export/export.cpp index 3802e7e784..c9271f6266 100644 --- a/platform/windows/export/export.cpp +++ b/platform/windows/export/export.cpp @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "editor/editor_export.h" -#include "platform/windows/logo.h" +#include "platform/windows/logo.gen.h" void register_windows_exporter() { diff --git a/platform/windows/godot.ico b/platform/windows/godot.ico Binary files differindex fd5c28944f..dd611e07da 100644 --- a/platform/windows/godot.ico +++ b/platform/windows/godot.ico diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index e94529dd94..2daf580c0d 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -1410,28 +1410,21 @@ void OS_Windows::set_window_size(const Size2 p_size) { return; } - RECT crect; - GetClientRect(hWnd, &crect); + int w = p_size.width; + int h = p_size.height; RECT rect; GetWindowRect(hWnd, &rect); - int dx = (rect.right - rect.left) - (crect.right - crect.left); - int dy = (rect.bottom - rect.top) - (crect.bottom - crect.top); - rect.right = rect.left + p_size.width + dx; - rect.bottom = rect.top + p_size.height + dy; + if (video_mode.borderless_window == false) { + RECT crect; + GetClientRect(hWnd, &crect); - //print_line("PRE: "+itos(rect.left)+","+itos(rect.top)+","+itos(rect.right-rect.left)+","+itos(rect.bottom-rect.top)); - - /*if (video_mode.resizable) { - AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE); - } else { - AdjustWindowRect(&rect, WS_CAPTION | WS_POPUPWINDOW, FALSE); - }*/ - - //print_line("POST: "+itos(rect.left)+","+itos(rect.top)+","+itos(rect.right-rect.left)+","+itos(rect.bottom-rect.top)); + w += (rect.right - rect.left) - (crect.right - crect.left); + h += (rect.bottom - rect.top) - (crect.bottom - crect.top); + } - MoveWindow(hWnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, TRUE); + MoveWindow(hWnd, rect.left, rect.top, w, h, TRUE); } void OS_Windows::set_window_fullscreen(bool p_enabled) { @@ -1451,21 +1444,18 @@ void OS_Windows::set_window_fullscreen(bool p_enabled) { Point2 pos = get_screen_position(cs); Size2 size = get_screen_size(cs); - /* r.left = pos.x; - r.top = pos.y; - r.bottom = pos.y+size.y; - r.right = pos.x+size.x; -*/ - SetWindowLongPtr(hWnd, GWL_STYLE, - WS_SYSMENU | WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE); - MoveWindow(hWnd, pos.x, pos.y, size.width, size.height, TRUE); - video_mode.fullscreen = true; + _update_window_style(false); + + MoveWindow(hWnd, pos.x, pos.y, size.width, size.height, TRUE); + } else { RECT rect; + video_mode.fullscreen = false; + if (pre_fs_valid) { rect = pre_fs_rect; } else { @@ -1475,35 +1465,12 @@ void OS_Windows::set_window_fullscreen(bool p_enabled) { rect.bottom = video_mode.height; } - if (video_mode.resizable) { - - SetWindowLongPtr(hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW | WS_VISIBLE); - //AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE); - MoveWindow(hWnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, TRUE); - } else { + _update_window_style(false); - SetWindowLongPtr(hWnd, GWL_STYLE, WS_CAPTION | WS_POPUPWINDOW | WS_VISIBLE); - //AdjustWindowRect(&rect, WS_CAPTION | WS_POPUPWINDOW, FALSE); - MoveWindow(hWnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, TRUE); - } + MoveWindow(hWnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, TRUE); - video_mode.fullscreen = false; pre_fs_valid = true; - /* - DWORD dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; - DWORD dwStyle=WS_OVERLAPPEDWINDOW; - if (!video_mode.resizable) { - dwStyle &= ~WS_THICKFRAME; - dwStyle &= ~WS_MAXIMIZEBOX; - } - AdjustWindowRectEx(&pre_fs_rect, dwStyle, FALSE, dwExStyle); - video_mode.fullscreen=false; - video_mode.width=pre_fs_rect.right-pre_fs_rect.left; - video_mode.height=pre_fs_rect.bottom-pre_fs_rect.top; -*/ } - - //MoveWindow(hWnd,r.left,r.top,p_size.x,p_size.y,TRUE); } bool OS_Windows::is_window_fullscreen() const { @@ -1513,30 +1480,10 @@ void OS_Windows::set_window_resizable(bool p_enabled) { if (video_mode.resizable == p_enabled) return; - /* - GetWindowRect(hWnd,&pre_fs_rect); - DWORD dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; - DWORD dwStyle=WS_OVERLAPPEDWINDOW; - if (!p_enabled) { - dwStyle &= ~WS_THICKFRAME; - dwStyle &= ~WS_MAXIMIZEBOX; - } - AdjustWindowRectEx(&pre_fs_rect, dwStyle, FALSE, dwExStyle); - */ - - if (!video_mode.fullscreen) { - if (p_enabled) { - SetWindowLongPtr(hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW | WS_VISIBLE); - } else { - SetWindowLongPtr(hWnd, GWL_STYLE, WS_CAPTION | WS_MINIMIZEBOX | WS_POPUPWINDOW | WS_VISIBLE); - } - - RECT rect; - GetWindowRect(hWnd, &rect); - MoveWindow(hWnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, TRUE); - } video_mode.resizable = p_enabled; + + _update_window_style(); } bool OS_Windows::is_window_resizable() const { @@ -1576,13 +1523,36 @@ bool OS_Windows::is_window_maximized() const { } void OS_Windows::set_borderless_window(int p_borderless) { + if (video_mode.borderless_window == p_borderless) + return; + video_mode.borderless_window = p_borderless; + + _update_window_style(); } bool OS_Windows::get_borderless_window() { return video_mode.borderless_window; } +void OS_Windows::_update_window_style(bool repaint) { + if (video_mode.fullscreen || video_mode.borderless_window) { + SetWindowLongPtr(hWnd, GWL_STYLE, WS_SYSMENU | WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE); + } else { + if (video_mode.resizable) { + SetWindowLongPtr(hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW | WS_VISIBLE); + } else { + SetWindowLongPtr(hWnd, GWL_STYLE, WS_CAPTION | WS_MINIMIZEBOX | WS_POPUPWINDOW | WS_VISIBLE); + } + } + + if (repaint) { + RECT rect; + GetWindowRect(hWnd, &rect); + MoveWindow(hWnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, TRUE); + } +} + Error OS_Windows::open_dynamic_library(const String p_path, void *&p_library_handle) { p_library_handle = (void *)LoadLibrary(p_path.utf8().get_data()); if (!p_library_handle) { diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index 6cbdd58830..835141145f 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -133,6 +133,8 @@ class OS_Windows : public OS { void _drag_event(int p_x, int p_y, int idx); void _touch_event(bool p_pressed, int p_x, int p_y, int idx); + void _update_window_style(bool repaint = true); + // functions used by main to initialize/deintialize the OS protected: virtual int get_video_driver_count() const; diff --git a/platform/x11/detect.py b/platform/x11/detect.py index 0ba0f68393..79778136ad 100644 --- a/platform/x11/detect.py +++ b/platform/x11/detect.py @@ -1,7 +1,6 @@ - import os -import sys import platform +import sys def is_active(): @@ -14,15 +13,12 @@ def get_name(): def can_build(): - if (os.name != "posix"): + if (os.name != "posix" or sys.platform == "darwin"): return False - if sys.platform == "darwin": - return False # no x11 on mac for now - - errorval = os.system("pkg-config --version > /dev/null") - - if (errorval): + # Check the minimal dependencies + x11_error = os.system("pkg-config --version > /dev/null") + if (x11_error): print("pkg-config not found.. x11 disabled.") return False @@ -31,11 +27,6 @@ def can_build(): print("X11 not found.. x11 disabled.") return False - ssl_error = os.system("pkg-config openssl --modversion > /dev/null ") - if (ssl_error): - print("OpenSSL not found.. x11 disabled.") - return False - x11_error = os.system("pkg-config xcursor --modversion > /dev/null ") if (x11_error): print("xcursor not found.. x11 disabled.") @@ -51,18 +42,18 @@ def can_build(): print("xrandr not found.. x11 disabled.") return False - return True # X11 enabled + return True def get_opts(): return [ - ('use_llvm', 'Use llvm compiler', 'no'), - ('use_static_cpp', 'link stdc++ statically', 'no'), - ('use_sanitizer', 'Use llvm compiler sanitize address', 'no'), - ('use_leak_sanitizer', 'Use llvm compiler sanitize memory leaks', 'no'), + ('use_llvm', 'Use the LLVM compiler', 'no'), + ('use_static_cpp', 'Link stdc++ statically', 'no'), + ('use_sanitizer', 'Use LLVM compiler address sanitizer', 'no'), + ('use_leak_sanitizer', 'Use LLVM compiler memory leaks sanitizer (implies use_sanitizer)', 'no'), ('use_lto', 'Use link time optimization', 'no'), - ('pulseaudio', 'Detect & Use pulseaudio', 'yes'), + ('pulseaudio', 'Detect & use pulseaudio', 'yes'), ('udev', 'Use udev for gamepad connection callbacks', 'no'), ('debug_release', 'Add debug symbols to release version', 'no'), ] @@ -80,66 +71,62 @@ def get_flags(): def configure(env): - is64 = sys.maxsize > 2**32 + ## Build type + + if (env["target"] == "release"): + env.Prepend(CCFLAGS=['-Ofast']) + if (env["debug_release"] == "yes"): + env.Prepend(CCFLAGS=['-g2']) + + elif (env["target"] == "release_debug"): + env.Prepend(CCFLAGS=['-O2', '-ffast-math', '-DDEBUG_ENABLED']) + if (env["debug_release"] == "yes"): + env.Prepend(CCFLAGS=['-g2']) + + elif (env["target"] == "debug"): + env.Prepend(CCFLAGS=['-g2', '-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED']) + + ## Architecture + is64 = sys.maxsize > 2**32 if (env["bits"] == "default"): - if (is64): - env["bits"] = "64" - else: - env["bits"] = "32" + env["bits"] = "64" if is64 else "32" + + ## Compiler configuration - env.Append(CPPPATH=['#platform/x11']) if (env["use_llvm"] == "yes"): - if 'clang++' not in env['CXX']: + if ('clang++' not in env['CXX']): env["CC"] = "clang" env["CXX"] = "clang++" env["LD"] = "clang++" env.Append(CPPFLAGS=['-DTYPED_METHOD_BIND']) - env.extra_suffix = ".llvm" - - if (env["use_sanitizer"] == "yes"): - env.Append(CCFLAGS=['-fsanitize=address', '-fno-omit-frame-pointer']) - env.Append(LINKFLAGS=['-fsanitize=address']) - env.extra_suffix += "s" + env.extra_suffix = ".llvm" + env.extra_suffix - if (env["use_leak_sanitizer"] == "yes"): + # leak sanitizer requires (address) sanitizer + if (env["use_sanitizer"] == "yes" or env["use_leak_sanitizer"] == "yes"): env.Append(CCFLAGS=['-fsanitize=address', '-fno-omit-frame-pointer']) env.Append(LINKFLAGS=['-fsanitize=address']) env.extra_suffix += "s" - - # if (env["tools"]=="no"): - # #no tools suffix - # env['OBJSUFFIX'] = ".nt"+env['OBJSUFFIX'] - # env['LIBSUFFIX'] = ".nt"+env['LIBSUFFIX'] + if (env["use_leak_sanitizer"] == "yes"): + env.Append(CCFLAGS=['-fsanitize=leak']) + env.Append(LINKFLAGS=['-fsanitize=leak']) if (env["use_lto"] == "yes"): env.Append(CCFLAGS=['-flto']) env.Append(LINKFLAGS=['-flto']) - env.Append(CCFLAGS=['-pipe']) env.Append(LINKFLAGS=['-pipe']) - if (env["target"] == "release"): - env.Prepend(CCFLAGS=['-Ofast']) - if (env["debug_release"] == "yes"): - env.Prepend(CCFLAGS=['-g2']) - - elif (env["target"] == "release_debug"): - - env.Prepend(CCFLAGS=['-O2', '-ffast-math', '-DDEBUG_ENABLED']) - if (env["debug_release"] == "yes"): - env.Prepend(CCFLAGS=['-g2']) - - elif (env["target"] == "debug"): - - env.Prepend(CCFLAGS=['-g2', '-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED']) + ## Dependencies env.ParseConfig('pkg-config x11 --cflags --libs') - env.ParseConfig('pkg-config xinerama --cflags --libs') env.ParseConfig('pkg-config xcursor --cflags --libs') + env.ParseConfig('pkg-config xinerama --cflags --libs') env.ParseConfig('pkg-config xrandr --cflags --libs') + # FIXME: Check for existence of the libs before parsing their flags with pkg-config + if (env['builtin_openssl'] == 'no'): # Currently not compatible with OpenSSL 1.1.0+ # https://github.com/godotengine/godot/issues/8624 @@ -196,47 +183,51 @@ def configure(env): if (env['builtin_libogg'] == 'no'): env.ParseConfig('pkg-config ogg --cflags --libs') - env.Append(CPPFLAGS=['-DOPENGL_ENABLED']) + if (env['builtin_libtheora'] != 'no'): + list_of_x86 = ['x86_64', 'x86', 'i386', 'i586'] + if any(platform.machine() in s for s in list_of_x86): + env["x86_libtheora_opt_gcc"] = True + + ## Flags - if os.system("pkg-config --exists alsa") == 0: + if (os.system("pkg-config --exists alsa") == 0): # 0 means found print("Enabling ALSA") env.Append(CPPFLAGS=["-DALSA_ENABLED"]) env.ParseConfig('pkg-config alsa --cflags --libs') else: print("ALSA libraries not found, disabling driver") - if (platform.system() == "Linux"): - env.Append(CPPFLAGS=["-DJOYDEV_ENABLED"]) - if (env["udev"] == "yes"): - # pkg-config returns 0 when the lib exists... - found_udev = not os.system("pkg-config --exists libudev") - - if (found_udev): - print("Enabling udev support") - env.Append(CPPFLAGS=["-DUDEV_ENABLED"]) - env.ParseConfig('pkg-config libudev --cflags --libs') - else: - print("libudev development libraries not found, disabling udev support") - if (env["pulseaudio"] == "yes"): - if not os.system("pkg-config --exists libpulse-simple"): + if (os.system("pkg-config --exists libpulse-simple") == 0): # 0 means found print("Enabling PulseAudio") env.Append(CPPFLAGS=["-DPULSEAUDIO_ENABLED"]) env.ParseConfig('pkg-config --cflags --libs libpulse-simple') else: print("PulseAudio development libraries not found, disabling driver") + if (platform.system() == "Linux"): + env.Append(CPPFLAGS=["-DJOYDEV_ENABLED"]) + + if (env["udev"] == "yes"): + if (os.system("pkg-config --exists libudev") == 0): # 0 means found + print("Enabling udev support") + env.Append(CPPFLAGS=["-DUDEV_ENABLED"]) + env.ParseConfig('pkg-config libudev --cflags --libs') + else: + print("libudev development libraries not found, disabling udev support") + + # Linkflags below this line should typically stay the last ones if (env['builtin_zlib'] == 'no'): env.ParseConfig('pkg-config zlib --cflags --libs') - env.Append(CPPFLAGS=['-DX11_ENABLED', '-DUNIX_ENABLED', '-DGLES2_ENABLED', '-DGLES_OVER_GL']) + env.Append(CPPPATH=['#platform/x11']) + env.Append(CPPFLAGS=['-DX11_ENABLED', '-DUNIX_ENABLED', '-DOPENGL_ENABLED', '-DGLES2_ENABLED', '-DGLES_OVER_GL']) env.Append(LIBS=['GL', 'pthread']) if (platform.system() == "Linux"): env.Append(LIBS=['dl']) - # env.Append(CPPFLAGS=['-DMPC_FIXED_POINT']) - # host compiler is default.. + ## Cross-compilation if (is64 and env["bits"] == "32"): env.Append(CPPFLAGS=['-m32']) @@ -245,17 +236,5 @@ def configure(env): env.Append(CPPFLAGS=['-m64']) env.Append(LINKFLAGS=['-m64', '-L/usr/lib/i686-linux-gnu']) - import methods - - # FIXME: Commented out when moving to gles3 - #env.Append(BUILDERS={'GLSL120': env.Builder(action=methods.build_legacygl_headers, suffix='glsl.h', src_suffix='.glsl')}) - #env.Append(BUILDERS={'GLSL': env.Builder(action=methods.build_glsl_headers, suffix='glsl.h', src_suffix='.glsl')}) - #env.Append(BUILDERS={'GLSL120GLES': env.Builder(action=methods.build_gles2_headers, suffix='glsl.h', src_suffix='.glsl')}) - #env.Append( BUILDERS = { 'HLSL9' : env.Builder(action = methods.build_hlsl_dx9_headers, suffix = 'hlsl.h',src_suffix = '.hlsl') } ) - if (env["use_static_cpp"] == "yes"): env.Append(LINKFLAGS=['-static-libstdc++']) - - list_of_x86 = ['x86_64', 'x86', 'i386', 'i586'] - if any(platform.machine() in s for s in list_of_x86): - env["x86_libtheora_opt_gcc"] = True diff --git a/platform/x11/export/export.cpp b/platform/x11/export/export.cpp index d6bad95e5b..69784a473d 100644 --- a/platform/x11/export/export.cpp +++ b/platform/x11/export/export.cpp @@ -29,7 +29,7 @@ /*************************************************************************/ #include "export.h" #include "editor/editor_export.h" -#include "platform/x11/logo.h" +#include "platform/x11/logo.gen.h" #include "scene/resources/texture.h" void register_x11_exporter() { diff --git a/platform/x11/godot_x11.cpp b/platform/x11/godot_x11.cpp index b293b1bebb..6f418b213f 100644 --- a/platform/x11/godot_x11.cpp +++ b/platform/x11/godot_x11.cpp @@ -28,6 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include <limits.h> +#include <locale.h> #include <stdlib.h> #include <unistd.h> @@ -38,6 +39,8 @@ int main(int argc, char *argv[]) { OS_X11 os; + setlocale(LC_CTYPE, ""); + char *cwd = (char *)malloc(PATH_MAX); getcwd(cwd, PATH_MAX); diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp index 2eebc96d2c..790182794e 100644 --- a/platform/x11/os_x11.cpp +++ b/platform/x11/os_x11.cpp @@ -68,6 +68,8 @@ #undef CursorShape +#include <X11/XKBlib.h> + int OS_X11::get_video_driver_count() const { return 1; } @@ -93,6 +95,7 @@ const char *OS_X11::get_audio_driver_name(int p_driver) const { void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) { + long im_event_mask = 0; last_button_state = 0; xmbstring = NULL; @@ -113,7 +116,32 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au /** XLIB INITIALIZATION **/ x11_display = XOpenDisplay(NULL); - char *modifiers = XSetLocaleModifiers("@im=none"); + Bool xkb_dar = False; + if (x11_display) { + XAutoRepeatOn(x11_display); + xkb_dar = XkbSetDetectableAutoRepeat(x11_display, True, NULL); + } + + char *modifiers = NULL; + + // Try to support IME if detectable auto-repeat is supported + + if (xkb_dar == True) { + +// Xutf8LookupString will be used later instead of XmbLookupString before +// the multibyte sequences can be converted to unicode string. + +#ifdef X_HAVE_UTF8_STRING + modifiers = XSetLocaleModifiers(""); +#endif + } + + if (modifiers == NULL) { + if (is_stdout_verbose()) { + WARN_PRINT("IME is disabled"); + } + modifiers = XSetLocaleModifiers("@im=none"); + } if (modifiers == NULL) { WARN_PRINT("Error setting locale modifiers"); } @@ -153,6 +181,14 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au WARN_PRINT("XOpenIM failed"); xim_style = 0L; } else { + ::XIMCallback im_destroy_callback; + im_destroy_callback.client_data = (::XPointer)(this); + im_destroy_callback.callback = (::XIMProc)(xim_destroy_callback); + if (XSetIMValues(xim, XNDestroyCallback, &im_destroy_callback, + NULL) != NULL) { + WARN_PRINT("Error setting XIM destroy callback"); + } + ::XIMStyles *xim_styles = NULL; xim_style = 0L; char *imvalret = NULL; @@ -242,6 +278,13 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au xev.xclient.data.l[2] = 0; XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureNotifyMask, &xev); + } else if (current_videomode.borderless_window) { + Hints hints; + Atom property; + hints.flags = 2; + hints.decorations = 0; + property = XInternAtom(x11_display, "_MOTIF_WM_HINTS", True); + XChangeProperty(x11_display, x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5); } // disable resizable window @@ -303,7 +346,8 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au StructureNotifyMask | SubstructureNotifyMask | SubstructureRedirectMask | FocusChangeMask | PropertyChangeMask | - ColormapChangeMask | OwnerGrabButtonMask; + ColormapChangeMask | OwnerGrabButtonMask | + im_event_mask; XChangeWindowAttributes(x11_display, x11_window, CWEventMask, &new_attr); @@ -327,6 +371,16 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au if (xim && xim_style) { xic = XCreateIC(xim, XNInputStyle, xim_style, XNClientWindow, x11_window, XNFocusWindow, x11_window, (char *)NULL); + if (XGetICValues(xic, XNFilterEvents, &im_event_mask, NULL) != NULL) { + WARN_PRINT("XGetICValues couldn't obtain XNFilterEvents value"); + XDestroyIC(xic); + xic = NULL; + } + if (xic) { + XSetICFocus(xic); + } else { + WARN_PRINT("XCreateIC couldn't create xic"); + } } else { xic = NULL; @@ -445,6 +499,33 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au _ensure_data_dir(); } +void OS_X11::xim_destroy_callback(::XIM im, ::XPointer client_data, + ::XPointer call_data) { + + WARN_PRINT("Input method stopped"); + OS_X11 *os = reinterpret_cast<OS_X11 *>(client_data); + os->xim = NULL; + os->xic = NULL; +} + +void OS_X11::set_ime_position(short x, short y) { + + if (!xic) { + return; + } + ::XPoint spot; + spot.x = x; + spot.y = y; + XVaNestedList preedit_attr = XVaCreateNestedList(0, + XNSpotLocation, &spot, + NULL); + XSetICValues(xic, + XNPreeditAttributes, preedit_attr, + NULL); + XFree(preedit_attr); + return; +} + void OS_X11::finalize() { if (main_loop) @@ -492,8 +573,12 @@ void OS_X11::finalize() { XcursorImageDestroy(img[i]); }; - XDestroyIC(xic); - XCloseIM(xim); + if (xic) { + XDestroyIC(xic); + } + if (xim) { + XCloseIM(xim); + } XCloseDisplay(x11_display); if (xmbstring) @@ -940,6 +1025,25 @@ bool OS_X11::is_window_maximized() const { return false; } +void OS_X11::set_borderless_window(int p_borderless) { + + if (current_videomode.borderless_window == p_borderless) + return; + + current_videomode.borderless_window = p_borderless; + + Hints hints; + Atom property; + hints.flags = 2; + hints.decorations = current_videomode.borderless_window ? 0 : 1; + property = XInternAtom(x11_display, "_MOTIF_WM_HINTS", True); + XChangeProperty(x11_display, x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5); +} + +bool OS_X11::get_borderless_window() { + return current_videomode.borderless_window; +} + void OS_X11::request_attention() { // Using EWMH -- Extended Window Manager Hints // @@ -1041,9 +1145,61 @@ void OS_X11::handle_key_event(XKeyEvent *p_event, bool p_echo) { xmblen = 8; } + keysym_unicode = keysym_keycode; + if (xkeyevent->type == KeyPress && xic) { Status status; +#ifdef X_HAVE_UTF8_STRING + int utf8len = 8; + char *utf8string = (char *)memalloc(sizeof(char) * utf8len); + int utf8bytes = Xutf8LookupString(xic, xkeyevent, utf8string, + utf8len - 1, &keysym_unicode, &status); + if (status == XBufferOverflow) { + utf8len = utf8bytes + 1; + utf8string = (char *)memrealloc(utf8string, utf8len); + utf8bytes = Xutf8LookupString(xic, xkeyevent, utf8string, + utf8len - 1, &keysym_unicode, &status); + } + utf8string[utf8bytes] = '\0'; + + if (status == XLookupChars) { + bool keypress = xkeyevent->type == KeyPress; + unsigned int keycode = KeyMappingX11::get_keycode(keysym_keycode); + if (keycode >= 'a' && keycode <= 'z') + keycode -= 'a' - 'A'; + + String tmp; + tmp.parse_utf8(utf8string, utf8bytes); + for (int i = 0; i < tmp.length(); i++) { + Ref<InputEventKey> k; + k.instance(); + if (keycode == 0 && tmp[i] == 0) { + continue; + } + + get_key_modifier_state(xkeyevent->state, k); + + k->set_unicode(tmp[i]); + + k->set_pressed(keypress); + + k->set_scancode(keycode); + + k->set_echo(false); + + if (k->get_scancode() == KEY_BACKTAB) { + //make it consistent across platforms. + k->set_scancode(KEY_TAB); + k->set_shift(true); + } + + input->parse_input_event(k); + } + return; + } + memfree(utf8string); +#else do { int mnbytes = XmbLookupString(xic, xkeyevent, xmbstring, xmblen - 1, &keysym_unicode, &status); @@ -1054,6 +1210,7 @@ void OS_X11::handle_key_event(XKeyEvent *p_event, bool p_echo) { xmbstring = (char *)memrealloc(xmbstring, xmblen); } } while (status == XBufferOverflow); +#endif } /* Phase 2, obtain a pigui keycode from the keysym */ @@ -1082,11 +1239,6 @@ void OS_X11::handle_key_event(XKeyEvent *p_event, bool p_echo) { bool keypress = xkeyevent->type == KeyPress; - if (xkeyevent->type == KeyPress && xic) { - if (XFilterEvent((XEvent *)xkeyevent, x11_window)) - return; - } - if (keycode == 0 && unicode == 0) return; @@ -1108,17 +1260,19 @@ void OS_X11::handle_key_event(XKeyEvent *p_event, bool p_echo) { // Echo characters in X11 are a keyrelease and a keypress // one after the other with the (almot) same timestamp. // To detect them, i use XPeekEvent and check that their - // difference in time is below a treshold. + // difference in time is below a threshold. if (xkeyevent->type != KeyPress) { + p_echo = false; + // make sure there are events pending, // so this call won't block. if (XPending(x11_display) > 0) { XEvent peek_event; XPeekEvent(x11_display, &peek_event); - // I'm using a treshold of 5 msecs, + // I'm using a threshold of 5 msecs, // since sometimes there seems to be a little // jitter. I'm still not convinced that all this approach // is correct, but the xorg developers are @@ -1172,6 +1326,18 @@ void OS_X11::handle_key_event(XKeyEvent *p_event, bool p_echo) { k->set_metakey(false); } + bool last_is_pressed = Input::get_singleton()->is_key_pressed(k->get_scancode()); + if (k->is_pressed()) { + if (last_is_pressed) { + k->set_echo(true); + } + } else { + //ignore + if (last_is_pressed == false) { + return; + } + } + //printf("key: %x\n",k->get_scancode()); input->parse_input_event(k); } @@ -1253,6 +1419,10 @@ void OS_X11::process_xevents() { XEvent event; XNextEvent(x11_display, &event); + if (XFilterEvent(&event, None)) { + continue; + } + switch (event.type) { case Expose: Main::force_redraw(); @@ -1295,6 +1465,9 @@ void OS_X11::process_xevents() { ButtonPressMask | ButtonReleaseMask | PointerMotionMask, GrabModeAsync, GrabModeAsync, x11_window, None, CurrentTime); } + if (xic) { + XSetICFocus(xic); + } break; case FocusOut: @@ -1308,9 +1481,16 @@ void OS_X11::process_xevents() { } XUngrabPointer(x11_display, CurrentTime); } + if (xic) { + XUnsetICFocus(xic); + } break; case ConfigureNotify: + if (xic) { + // Not portable. + set_ime_position(0, 1); + } /* call resizeGLScene only if our window-size changed */ if ((event.xconfigure.width == current_videomode.width) && diff --git a/platform/x11/os_x11.h b/platform/x11/os_x11.h index d62186e5bd..39c512b6bd 100644 --- a/platform/x11/os_x11.h +++ b/platform/x11/os_x11.h @@ -113,6 +113,10 @@ class OS_X11 : public OS_Unix { ::XIC xic; ::XIM xim; ::XIMStyle xim_style; + static void xim_destroy_callback(::XIM im, ::XPointer client_data, + ::XPointer call_data); + void set_ime_position(short x, short y); + Point2i last_mouse_pos; bool last_mouse_pos_valid; Point2i last_click_pos; @@ -247,6 +251,9 @@ public: virtual bool is_window_maximized() const; virtual void request_attention(); + virtual void set_borderless_window(int p_borderless); + virtual bool get_borderless_window(); + virtual void move_window_to_foreground(); virtual void alert(const String &p_alert, const String &p_title = "ALERT!"); |