diff --git a/license.txt b/license.txt index 4ab53606d..322fc60ed 100644 --- a/license.txt +++ b/license.txt @@ -25,7 +25,7 @@ distribution. This software uses LuaJIT: -LuaJIT is Copyright (c) 2005-2014 Mike Pall +LuaJIT is Copyright (c) 2005-2015 Mike Pall Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -123,7 +123,8 @@ DEALINGS IN THE SOFTWARE. --------- -This software uses the following LGPL libraries on Windows, Mac OS X, and Linux: +This software uses the following LGPL libraries on Windows, Mac OS X, Linux, +and Android: - libmpg123 Website: http://www.mpg123.de/ diff --git a/platform/xcode/liblove.xcodeproj/project.pbxproj b/platform/xcode/liblove.xcodeproj/project.pbxproj index 8ecfc18bd..8e902f02e 100644 --- a/platform/xcode/liblove.xcodeproj/project.pbxproj +++ b/platform/xcode/liblove.xcodeproj/project.pbxproj @@ -848,6 +848,9 @@ FA8951A31AA2EDF300EC385A /* wrap_Event.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA8951A01AA2EDF300EC385A /* wrap_Event.cpp */; }; FA8951A41AA2EDF300EC385A /* wrap_Event.h in Headers */ = {isa = PBXBuildFile; fileRef = FA8951A11AA2EDF300EC385A /* wrap_Event.h */; }; FA9B4A0816E1578300074F42 /* SDL2.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA9B4A0716E1578300074F42 /* SDL2.framework */; }; + FAA3A9AE1B7D465A00CED060 /* android.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAA3A9AC1B7D465A00CED060 /* android.cpp */; }; + FAA3A9AF1B7D465A00CED060 /* android.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAA3A9AC1B7D465A00CED060 /* android.cpp */; }; + FAA3A9B01B7D465A00CED060 /* android.h in Headers */ = {isa = PBXBuildFile; fileRef = FAA3A9AD1B7D465A00CED060 /* android.h */; }; FAA627CE18E7E1560080752D /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FAA627CD18E7E1560080752D /* CoreServices.framework */; }; FAAFF04416CB11C700CCDE45 /* OpenAL-Soft.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FAAFF04316CB11C700CCDE45 /* OpenAL-Soft.framework */; }; FAB17BE01ABFAA2000F9BA27 /* Compressor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAB17BDE1ABFAA2000F9BA27 /* Compressor.cpp */; }; @@ -1498,6 +1501,8 @@ FA8951A01AA2EDF300EC385A /* wrap_Event.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Event.cpp; sourceTree = ""; }; FA8951A11AA2EDF300EC385A /* wrap_Event.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Event.h; sourceTree = ""; }; FA9B4A0716E1578300074F42 /* SDL2.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDL2.framework; path = /Library/Frameworks/SDL2.framework; sourceTree = ""; }; + FAA3A9AC1B7D465A00CED060 /* android.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = android.cpp; sourceTree = ""; }; + FAA3A9AD1B7D465A00CED060 /* android.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = android.h; sourceTree = ""; }; FAA627CD18E7E1560080752D /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = System/Library/Frameworks/CoreServices.framework; sourceTree = SDKROOT; }; FAAFF04316CB11C700CCDE45 /* OpenAL-Soft.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = "OpenAL-Soft.framework"; path = "/Library/Frameworks/OpenAL-Soft.framework"; sourceTree = ""; }; FAB17BDE1ABFAA2000F9BA27 /* Compressor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Compressor.cpp; sourceTree = ""; }; @@ -1601,6 +1606,8 @@ FA0B78F61A958E3B000E1D17 /* common */ = { isa = PBXGroup; children = ( + FAA3A9AC1B7D465A00CED060 /* android.cpp */, + FAA3A9AD1B7D465A00CED060 /* android.h */, FA0B78F71A958E3B000E1D17 /* b64.cpp */, FA0B78F81A958E3B000E1D17 /* b64.h */, FA0B78F91A958E3B000E1D17 /* config.h */, @@ -3054,6 +3061,7 @@ FA0B7DDE1A95902C000E1D17 /* wrap_BezierCurve.h in Headers */, FA0B7DED1A95902C000E1D17 /* Cursor.h in Headers */, FA0B7E501A95902C000E1D17 /* wrap_Fixture.h in Headers */, + FAA3A9B01B7D465A00CED060 /* android.h in Headers */, FA0B7A491A958EA3000E1D17 /* b2PolygonShape.h in Headers */, FA0B79281A958E3B000E1D17 /* math.h in Headers */, FA0B7A9A1A958EA3000E1D17 /* b2MotorJoint.h in Headers */, @@ -3312,6 +3320,7 @@ FA0B7DC21A95902C000E1D17 /* wrap_Joystick.cpp in Sources */, FA0B7CD41A95902C000E1D17 /* Source.cpp in Sources */, FA0B7AEF1A958EA3000E1D17 /* inet.c in Sources */, + FAA3A9AF1B7D465A00CED060 /* android.cpp in Sources */, FA0B7CD11A95902C000E1D17 /* Audio.cpp in Sources */, FA0B7D131A95902C000E1D17 /* Font.cpp in Sources */, FA0B7EC91A95902C000E1D17 /* threads.cpp in Sources */, @@ -3596,6 +3605,7 @@ FA0B7CD31A95902C000E1D17 /* Source.cpp in Sources */, FA0B7A411A958EA3000E1D17 /* b2CircleShape.cpp in Sources */, FA0B7CD01A95902C000E1D17 /* Audio.cpp in Sources */, + FAA3A9AE1B7D465A00CED060 /* android.cpp in Sources */, FA0B7D121A95902C000E1D17 /* Font.cpp in Sources */, FA0B7EC81A95902C000E1D17 /* threads.cpp in Sources */, FA0B7A6B1A958EA3000E1D17 /* b2World.cpp in Sources */, diff --git a/src/common/android.cpp b/src/common/android.cpp new file mode 100644 index 000000000..530535625 --- /dev/null +++ b/src/common/android.cpp @@ -0,0 +1,231 @@ +/** + * Copyright (c) 2006-2014 LOVE Development Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + **/ + +#include "android.h" + +#ifdef LOVE_ANDROID + +#include "SDL.h" +#include "jni.h" + +#include +#include +#include +#include + +namespace love +{ +namespace android +{ + +void setImmersive(bool immersive_active) +{ + JNIEnv *env = (JNIEnv*) SDL_AndroidGetJNIEnv(); + + jobject activity = (jobject) SDL_AndroidGetActivity(); + + jclass clazz(env->GetObjectClass(activity)); + jmethodID method_id = env->GetMethodID(clazz, "setImmersiveMode", "(Z)V"); + + env->CallVoidMethod(activity, method_id, immersive_active); + + env->DeleteLocalRef(activity); + env->DeleteLocalRef(clazz); +} + +bool getImmersive() +{ + JNIEnv *env = (JNIEnv*) SDL_AndroidGetJNIEnv(); + + jobject activity = (jobject) SDL_AndroidGetActivity(); + + jclass clazz(env->GetObjectClass(activity)); + jmethodID method_id = env->GetMethodID(clazz, "getImmersiveMode", "()Z"); + + jboolean immersive_active = env->CallBooleanMethod(activity, method_id); + + env->DeleteLocalRef(activity); + env->DeleteLocalRef(clazz); + + return immersive_active; +} + +double getScreenScale() +{ + static double result = -1.; + + if (result == -1.) + { + JNIEnv *env = (JNIEnv*) SDL_AndroidGetJNIEnv(); + jclass activity = env->FindClass("org/love2d/android/GameActivity"); + + jmethodID getMetrics = env->GetStaticMethodID(activity, "getMetrics", "()Landroid/util/DisplayMetrics;"); + jobject metrics = env->CallStaticObjectMethod(activity, getMetrics); + jclass metricsClass = env->GetObjectClass(metrics); + + result = env->GetFloatField(metrics, env->GetFieldID(metricsClass, "density", "F")); + + env->DeleteLocalRef(metricsClass); + env->DeleteLocalRef(metrics); + env->DeleteLocalRef(activity); + } + + return result; +} + +const char *getSelectedGameFile() +{ + static const char *path = NULL; + + if (path) + { + delete path; + path = NULL; + } + + JNIEnv *env = (JNIEnv*) SDL_AndroidGetJNIEnv(); + jclass activity = env->FindClass("org/love2d/android/GameActivity"); + + jmethodID getGamePath = env->GetStaticMethodID(activity, "getGamePath", "()Ljava/lang/String;"); + jstring gamePath = (jstring) env->CallStaticObjectMethod(activity, getGamePath); + const char *utf = env->GetStringUTFChars(gamePath, 0); + if (utf) + { + path = SDL_strdup(utf); + env->ReleaseStringUTFChars(gamePath, utf); + } + + env->DeleteLocalRef(gamePath); + env->DeleteLocalRef(activity); + + return path; +} + +bool openURL(const std::string &url) +{ + JNIEnv *env = (JNIEnv*) SDL_AndroidGetJNIEnv(); + jclass activity = env->FindClass("org/love2d/android/GameActivity"); + + jmethodID openURL= env->GetStaticMethodID(activity, "openURL", "(Ljava/lang/String;)V"); + jstring url_jstring = (jstring) env->NewStringUTF(url.c_str()); + + env->CallStaticVoidMethod(activity, openURL, url_jstring); + + env->DeleteLocalRef(url_jstring); + env->DeleteLocalRef(activity); + return true; +} + +void vibrate(double seconds) +{ + JNIEnv *env = (JNIEnv*) SDL_AndroidGetJNIEnv(); + jclass activity = env->FindClass("org/love2d/android/GameActivity"); + + jmethodID vibrate_method = env->GetStaticMethodID(activity, "vibrate", "(D)V"); + env->CallStaticVoidMethod(activity, vibrate_method, seconds); + + env->DeleteLocalRef(activity); +} + +/* + * Helper functions for the filesystem module + */ +void freeGameArchiveMemory(void *ptr) +{ + char *game_love_data = static_cast(ptr); + delete[] game_love_data; +} + +bool loadGameArchiveToMemory(const char* filename, char **ptr, size_t *size) +{ + SDL_RWops *asset_game_file = SDL_RWFromFile(filename, "rb"); + if (!asset_game_file) { + SDL_Log("Could not find %s", filename); + return false; + } + + Sint64 file_size = asset_game_file->size(asset_game_file); + if (file_size <= 0) { + SDL_Log("Could not load game from %s. File has invalid file size: %d.", filename, (int) file_size); + return false; + } + + *ptr = new char[file_size]; + if (!*ptr) { + SDL_Log("Could not allocate memory for in-memory game archive"); + return false; + } + + size_t bytes_copied = asset_game_file->read(asset_game_file, (void*) *ptr, sizeof(char), (size_t) file_size); + if (bytes_copied != file_size) { + SDL_Log("Incomplete copy of in-memory game archive!"); + delete[] *ptr; + return false; + } + + *size = (size_t) file_size; + return true; +} + +bool directoryExists(const char *path) +{ + struct stat s; + int err = stat(path, &s); + if (err == -1) + { + if (errno != ENOENT) + SDL_Log("Error checking for directory %s errno = %d: %s", path, errno, strerror(errno)); + return false; + } + + return S_ISDIR(s.st_mode); +} + +bool mkdir(const char *path) +{ + int err = ::mkdir(path, 0770); + if (err == -1) + { + SDL_Log("Error: Could not create directory %s", path); + return false; + } + + return true; +} + +bool createStorageDirectories() +{ + std::string internal_storage_path = SDL_AndroidGetInternalStoragePath(); + + std::string save_directory = internal_storage_path + "/save"; + if (!directoryExists(save_directory.c_str()) && !mkdir(save_directory.c_str())) + return false; + + std::string game_directory = internal_storage_path + "/game"; + if (!directoryExists (game_directory.c_str()) && !mkdir(game_directory.c_str())) + return false; + + return true; +} + +} // android +} // love + +#endif // LOVE_ANDROID diff --git a/src/common/android.h b/src/common/android.h new file mode 100644 index 000000000..b0e051bc0 --- /dev/null +++ b/src/common/android.h @@ -0,0 +1,73 @@ +/** + * Copyright (c) 2006-2014 LOVE Development Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + **/ + +#ifndef LOVE_ANDROID_H +#define LOVE_ANDROID_H + +#include "config.h" + +#ifdef LOVE_ANDROID + +#include + +namespace love +{ +namespace android +{ + +/** + * Enables or disables immersive mode where the navigation bar is hidden. + **/ +void setImmersive(bool immersive_active); +bool getImmersive(); + +/** + * Gets the scale factor of the window's screen, e.g. on Retina displays this + * will return 2.0. + **/ +double getScreenScale(); + +/** + * Gets the selected love file in the device filesystem. + **/ +const char *getSelectedGameFile(); + +bool openURL(const std::string &url); + +void vibrate(double seconds); + +/* + * Helper functions for the filesystem module + */ +void freeGameArchiveMemory(void *ptr); + +bool loadGameArchiveToMemory(const char *filename, char **ptr, size_t *size); + +bool directoryExists(const char *path); + +bool mkdir(const char *path); + +bool createStorageDirectories(); + +} // android +} // love + +#endif // LOVE_ANDROID +#endif // LOVE_ANDROID_H diff --git a/src/common/config.h b/src/common/config.h index 18f37ac4c..4e13a1bc6 100644 --- a/src/common/config.h +++ b/src/common/config.h @@ -26,7 +26,10 @@ # define LOVE_WINDOWS 1 #endif #if defined(linux) || defined(__linux) || defined(__linux__) -# define LOVE_LINUX 1 +# define LOVE_LINUX 1 +#endif +#if defined(__ANDROID__) +# define LOVE_ANDROID 1 #endif #if defined(__APPLE__) # include