supertuxkart-serenity/src/main_android.cpp
2023-06-11 01:44:58 +02:00

319 lines
12 KiB
C++

// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2016-2017 SuperTuxKart-Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifdef MOBILE_STK
#include "config/user_config.hpp"
#include "graphics/irr_driver.hpp"
#include "utils/log.hpp"
#include "utils/string_utils.hpp"
#ifdef ANDROID
#include "SDL_stdinc.h"
#include "SDL_system.h"
#include <jni.h>
std::string g_android_main_user_agent;
extern int android_main(int argc, char *argv[]);
extern "C" JNIEXPORT void JNICALL debugMsg(JNIEnv* env, jclass cls, jstring msg);
extern "C" JNIEXPORT void JNICALL handlePadding(JNIEnv* env, jclass cls, jboolean val);
extern "C" JNIEXPORT void JNICALL addDNSSrvRecords(JNIEnv* env, jclass cls, jstring name, jint weight);
extern "C" JNIEXPORT void JNICALL pauseRenderingJNI(JNIEnv* env, jclass cls);
extern "C" JNIEXPORT void JNICALL editText2STKEditbox(JNIEnv* env, jclass cls, jint widget_id, jstring text, jint start, jint end, jint composing_start, jint composing_end);
extern "C" JNIEXPORT void JNICALL handleActionNext(JNIEnv* env, jclass cls, jint widget_id);
extern "C" JNIEXPORT void JNICALL handleLeftRight(JNIEnv* env, jclass cls, jboolean left, jint widget_id);
#if !defined(ANDROID_PACKAGE_CLASS_NAME)
#error
#endif
void registering_natives()
{
JNINativeMethod stkactivity_tab[] =
{
{ "debugMsg", "(Ljava/lang/String;)V", (void*)&debugMsg },
{ "handlePadding", "(Z)V", (void*)&handlePadding },
{ "addDNSSrvRecords", "(Ljava/lang/String;I)V", (void*)&addDNSSrvRecords },
{ "pauseRenderingJNI", "()V", (void*)&pauseRenderingJNI }
};
JNIEnv* env = (JNIEnv*)SDL_AndroidGetJNIEnv();
assert(env);
const char* stkactivity_class = ANDROID_PACKAGE_CLASS_NAME "/SuperTuxKartActivity";
jclass clazz = env->FindClass(stkactivity_class);
if (clazz == NULL)
{
Log::error("MainAndroid", "Failed to find class %s.",
stkactivity_class);
return;
}
if (env->RegisterNatives(
clazz, stkactivity_tab, (int)SDL_arraysize(stkactivity_tab)) < 0)
{
Log::error("MainAndroid", "Failed to register methods of %s.",
stkactivity_class);
}
JNINativeMethod stkeditbox_tab[] =
{
{ "editText2STKEditbox", "(ILjava/lang/String;IIII)V", (void*)&editText2STKEditbox },
{ "handleActionNext", "(I)V", (void*)&handleActionNext },
{ "handleLeftRight", "(ZI)V", (void*)&handleLeftRight }
};
const char* stkeditbox_class = ANDROID_PACKAGE_CLASS_NAME "/STKEditText";
clazz = env->FindClass(stkeditbox_class);
if (clazz == NULL)
{
Log::error("MainAndroid", "Failed to find class %s.",
stkeditbox_class);
return;
}
if (env->RegisterNatives(
clazz, stkeditbox_tab, (int)SDL_arraysize(stkeditbox_tab)) < 0)
{
Log::error("MainAndroid", "Failed to register methods of %s.",
stkeditbox_class);
}
}
void override_default_params_for_mobile();
extern "C" int SDL_main(int argc, char *argv[])
{
registering_natives();
override_default_params_for_mobile();
return android_main(argc, argv);
}
#endif
void override_default_params_for_mobile()
{
// It has an effect only on the first run, when config file is created.
// So that we can still modify these params in STK options and user's
// choice will be then remembered.
// Set smaller texture size to avoid high RAM usage
UserConfigParams::m_max_texture_size = 256;
UserConfigParams::m_high_definition_textures = false;
// Enable advanced lighting only for android >= 8
#ifdef ANDROID
UserConfigParams::m_dynamic_lights = (SDL_GetAndroidSDKVersion() >= 26);
#endif
// Disable light scattering for better performance
UserConfigParams::m_light_scatter = false;
// Enable multitouch race GUI
UserConfigParams::m_multitouch_draw_gui = true;
#ifdef ANDROID
// For usage in StringUtils::getUserAgentString
if (SDL_IsAndroidTV())
{
// For some android tv sdl returns a touch screen device even it doesn't
// have
UserConfigParams::m_multitouch_draw_gui = false;
g_android_main_user_agent = " (AndroidTV)";
}
else if (SDL_IsChromebook())
g_android_main_user_agent = " (ChromeOS)";
else
g_android_main_user_agent = " (Android)";
// Get some info about display
const int SCREENLAYOUT_SIZE_SMALL = 1;
const int SCREENLAYOUT_SIZE_NORMAL = 2;
const int SCREENLAYOUT_SIZE_LARGE = 3;
const int SCREENLAYOUT_SIZE_XLARGE = 4;
int32_t screen_size = 0;
int ddpi = 0;
JNIEnv* env = (JNIEnv*)SDL_AndroidGetJNIEnv();
assert(env);
jobject activity = (jobject)SDL_AndroidGetActivity();
if (activity != NULL)
{
jclass clazz = env->GetObjectClass(activity);
if (clazz != NULL)
{
jmethodID method_id = env->GetMethodID(clazz, "getScreenSize",
"()I");
if (method_id != NULL)
screen_size = env->CallIntMethod(activity, method_id);
jmethodID display_dpi_id = env->GetStaticMethodID(clazz,
"getDisplayDPI", "()Landroid/util/DisplayMetrics;");
if (display_dpi_id != NULL)
{
jobject display_dpi_obj = env->CallStaticObjectMethod(clazz,
display_dpi_id);
jclass display_dpi_class = env->GetObjectClass(display_dpi_obj);
jfieldID ddpi_field = env->GetFieldID(display_dpi_class,
"densityDpi", "I");
ddpi = env->GetIntField(display_dpi_obj, ddpi_field);
env->DeleteLocalRef(display_dpi_obj);
env->DeleteLocalRef(display_dpi_class);
}
env->DeleteLocalRef(activity);
env->DeleteLocalRef(clazz);
}
}
// Set multitouch device scale depending on actual screen size
switch (screen_size)
{
case SCREENLAYOUT_SIZE_SMALL:
case SCREENLAYOUT_SIZE_NORMAL:
UserConfigParams::m_multitouch_scale.setDefaultValue(1.3f);
UserConfigParams::m_multitouch_sensitivity_x.setDefaultValue(0.1f);
UserConfigParams::m_font_size = 5.0f;
break;
case SCREENLAYOUT_SIZE_LARGE:
UserConfigParams::m_multitouch_scale.setDefaultValue(1.2f);
UserConfigParams::m_multitouch_sensitivity_x.setDefaultValue(0.15f);
UserConfigParams::m_font_size = 5.0f;
break;
case SCREENLAYOUT_SIZE_XLARGE:
UserConfigParams::m_multitouch_scale.setDefaultValue(1.1f);
UserConfigParams::m_multitouch_sensitivity_x.setDefaultValue(0.2f);
UserConfigParams::m_font_size = 4.0f;
break;
default:
break;
}
// Update rtts scale based on display DPI
if (ddpi < 1)
{
Log::warn("MainAndroid", "Failed to get display DPI.");
UserConfigParams::m_scale_rtts_factor = 0.7f;
}
else
{
if (ddpi > 400)
UserConfigParams::m_scale_rtts_factor = 0.6f;
else if (ddpi > 300)
UserConfigParams::m_scale_rtts_factor = 0.65f;
else if (ddpi > 200)
UserConfigParams::m_scale_rtts_factor = 0.7f;
else if (ddpi > 150)
UserConfigParams::m_scale_rtts_factor = 0.75f;
else
UserConfigParams::m_scale_rtts_factor = 0.8f;
Log::info("MainAndroid", "Display DPI: %i", ddpi);
Log::info("MainAndroid", "Render scale: %f",
(float)UserConfigParams::m_scale_rtts_factor);
}
#endif
// Enable screen keyboard
UserConfigParams::m_screen_keyboard = 1;
// It shouldn't matter, but STK is always run in fullscreen on android
UserConfigParams::m_fullscreen = true;
// Make sure that user can play every track even if there are installed
// only few tracks and it's impossible to finish overworld challenges
UserConfigParams::m_unlock_everything = 1;
// Create default user istead of showing login screen to make life easier
UserConfigParams::m_enforce_current_player = true;
}
#ifdef IOS_STK
void getConfigForDevice(const char* dev)
{
// Check browser.geekbench.com/ios-benchmarks metal benchmark
// https://gist.github.com/adamawolf/3048717 for device name mapping
std::string device = dev;
if (device.find("iPhone") != std::string::npos)
{
// Normal configuration default
UserConfigParams::m_multitouch_scale.setDefaultValue(1.3f);
UserConfigParams::m_multitouch_sensitivity_x.setDefaultValue(0.1f);
UserConfigParams::m_font_size = 5.0f;
device.erase(0, 6);
auto versions = StringUtils::splitToUInt(device, ',');
if (versions.size() == 2)
{
// A9 GPU
if (versions[0] >= 8)
{
UserConfigParams::m_dynamic_lights = true;
UserConfigParams::m_high_definition_textures = 1;
}
if (versions[0] < 7 || // iPhone 5s
(versions[0] == 7 && versions[1] == 2) || // iPhone 6
(versions[0] == 8 && versions[1] == 1) || // iPhone 6S
(versions[0] == 8 && versions[1] == 4) || // iPhone SE
(versions[0] == 9 && versions[1] == 1) || // iPhone 7
(versions[0] == 9 && versions[1] == 3) || // iPhone 7
(versions[0] == 10 && versions[1] == 1) || // iPhone 8
(versions[0] == 10 && versions[1] == 4) // iPhone 8
)
{
// Those phones have small screen
UserConfigParams::m_multitouch_scale.setDefaultValue(1.45f);
}
}
}
else if (device.find("iPad") != std::string::npos)
{
// Normal configuration default
UserConfigParams::m_multitouch_scale.setDefaultValue(0.95f);
UserConfigParams::m_multitouch_sensitivity_x.setDefaultValue(0.2f);
UserConfigParams::m_font_size = 3.0f;
device.erase(0, 4);
auto versions = StringUtils::splitToUInt(device, ',');
if (versions.size() == 2)
{
if (versions[0] >= 7)
{
UserConfigParams::m_dynamic_lights = true;
UserConfigParams::m_high_definition_textures = 1;
}
}
}
else if (device.find("iPod") != std::string::npos)
{
// All iPod touch has small screen
UserConfigParams::m_font_size = 5.0f;
UserConfigParams::m_multitouch_scale.setDefaultValue(1.45f);
UserConfigParams::m_multitouch_sensitivity_x.setDefaultValue(0.1f);
device.erase(0, 4);
auto versions = StringUtils::splitToUInt(device, ',');
if (versions.size() == 2)
{
// iPod Touch 7th Generation (A10)
if (versions[0] >= 9)
{
UserConfigParams::m_dynamic_lights = true;
UserConfigParams::m_high_definition_textures = 1;
}
}
}
}
#endif
#endif