Merge branch 'master' of github.com:supertuxkart/stk-code
17
.gitignore
vendored
@ -51,3 +51,20 @@ packets_log.txt
|
||||
history.dat
|
||||
README.dependencies
|
||||
xx
|
||||
|
||||
android/android-ndk*
|
||||
android/android-sdk*
|
||||
android/assets
|
||||
android/bin
|
||||
android/obj
|
||||
android/libs
|
||||
android-*
|
||||
*.apk
|
||||
|
||||
lib/curl
|
||||
lib/freetype
|
||||
lib/ifaddrs
|
||||
lib/libogg
|
||||
lib/libvorbis
|
||||
lib/openal
|
||||
lib/openssl
|
||||
|
174
android/Android.mk
Normal file
@ -0,0 +1,174 @@
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
|
||||
# OpenAL
|
||||
LOCAL_MODULE := openal
|
||||
LOCAL_SRC_FILES := obj/openal/libopenal.a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
|
||||
# OGG
|
||||
LOCAL_MODULE := ogg
|
||||
LOCAL_SRC_FILES := obj/libogg/src/.libs/libogg.a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
|
||||
# Vorbis
|
||||
LOCAL_MODULE := vorbis
|
||||
LOCAL_SRC_FILES := obj/libvorbis/lib/.libs/libvorbis.a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
|
||||
# Vorbisfile
|
||||
LOCAL_MODULE := vorbisfile
|
||||
LOCAL_SRC_FILES := obj/libvorbis/lib/.libs/libvorbisfile.a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
|
||||
# CURL
|
||||
LOCAL_MODULE := curl
|
||||
LOCAL_SRC_FILES := obj/curl/lib/.libs/libcurl.a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
|
||||
# libcrypto
|
||||
LOCAL_MODULE := libcrypto
|
||||
LOCAL_SRC_FILES := obj/openssl/libcrypto.a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
|
||||
# libssl
|
||||
LOCAL_MODULE := libssl
|
||||
LOCAL_SRC_FILES := obj/openssl/libssl.a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
|
||||
# JPEG
|
||||
LOCAL_MODULE := jpeglib
|
||||
LOCAL_SRC_FILES := obj/jpeglib/libjpeglib.a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
|
||||
# Freetype
|
||||
LOCAL_MODULE := freetype
|
||||
LOCAL_SRC_FILES := obj/freetype/objs/.libs/libfreetype.a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
|
||||
# zlib
|
||||
LOCAL_MODULE := zlib
|
||||
LOCAL_SRC_FILES := obj/zlib/libz.a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
|
||||
# PNG
|
||||
LOCAL_MODULE := png
|
||||
LOCAL_SRC_FILES := obj/libpng/libpng.a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
|
||||
# ifaddrs
|
||||
LOCAL_MODULE := ifaddrs
|
||||
LOCAL_PATH := .
|
||||
LOCAL_SRC_FILES := ../lib/ifaddrs/ifaddrs.c
|
||||
LOCAL_CFLAGS := -I../lib/ifaddrs
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
|
||||
# AngelScript
|
||||
LOCAL_MODULE := angelscript
|
||||
LOCAL_PATH := .
|
||||
LOCAL_CPP_FEATURES += rtti exceptions
|
||||
LOCAL_SRC_FILES := $(wildcard ../lib/angelscript/source/*.S) \
|
||||
$(wildcard ../lib/angelscript/source/*.cpp)
|
||||
LOCAL_CFLAGS := -I../lib/angelscript/source/
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
|
||||
# ENET
|
||||
LOCAL_MODULE := enet
|
||||
LOCAL_PATH := .
|
||||
LOCAL_CPP_FEATURES += rtti
|
||||
LOCAL_SRC_FILES := $(wildcard ../lib/enet/*.c)
|
||||
LOCAL_CFLAGS := -I../lib/enet/include/ -DHAS_SOCKLEN_T
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
|
||||
# Bullet
|
||||
LOCAL_MODULE := bullet
|
||||
LOCAL_PATH := .
|
||||
LOCAL_CPP_FEATURES += rtti
|
||||
LOCAL_SRC_FILES := $(wildcard ../lib/bullet/src/*/*.cpp) \
|
||||
$(wildcard ../lib/bullet/src/*/*/*.cpp)
|
||||
LOCAL_CFLAGS := -I../lib/bullet/src/
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
|
||||
# Irrlicht
|
||||
LOCAL_MODULE := irrlicht
|
||||
LOCAL_PATH := .
|
||||
LOCAL_CPP_FEATURES += rtti
|
||||
LOCAL_SRC_FILES := $(wildcard ../lib/irrlicht/source/Irrlicht/*.cpp) \
|
||||
$(wildcard ../lib/irrlicht/source/Irrlicht/Android/*.cpp)
|
||||
LOCAL_CFLAGS := -I../lib/irrlicht/source/Irrlicht/ \
|
||||
-I../lib/irrlicht/include/ \
|
||||
-Iobj/jpeglib/ \
|
||||
-Iobj/libpng/ \
|
||||
-Iobj/zlib/ \
|
||||
-I$(call my-dir)/../../sources/android/native_app_glue
|
||||
-std=gnu++0x
|
||||
LOCAL_STATIC_LIBRARIES := jpeglib png zlib
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
|
||||
# STK
|
||||
LOCAL_MODULE := main
|
||||
LOCAL_PATH := .
|
||||
LOCAL_CPP_FEATURES += rtti exceptions
|
||||
LOCAL_SRC_FILES := $(wildcard ../src/*.cpp) \
|
||||
$(wildcard ../src/*/*.cpp) \
|
||||
$(wildcard ../src/*/*/*.cpp)
|
||||
LOCAL_LDLIBS := -llog -landroid -lEGL -lGLESv3 -lOpenSLES
|
||||
LOCAL_CFLAGS := -I../lib/angelscript/include \
|
||||
-I../lib/bullet/src \
|
||||
-I../lib/enet/include \
|
||||
-I../lib/ifaddrs \
|
||||
-I../lib/irrlicht/include \
|
||||
-I../lib/irrlicht/source/Irrlicht \
|
||||
-I../src \
|
||||
-Iobj/curl/include \
|
||||
-Iobj/freetype/include \
|
||||
-Iobj/libogg/include \
|
||||
-Iobj/libvorbis/include \
|
||||
-Iobj/openal/include \
|
||||
-I$(call my-dir)/../../sources/android/native_app_glue \
|
||||
-DUSE_GLES2 \
|
||||
-DHAVE_OGGVORBIS \
|
||||
-DNDEBUG \
|
||||
-std=gnu++0x
|
||||
|
||||
LOCAL_STATIC_LIBRARIES := irrlicht bullet enet freetype ifaddrs angelscript \
|
||||
vorbisfile vorbis ogg openal curl libssl libcrypto \
|
||||
gnustl_static android_native_app_glue
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
$(call import-module,android/native_app_glue)
|
38
android/AndroidManifest.xml
Normal file
@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.supertuxkart.stk"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0">
|
||||
|
||||
<!-- This .apk has no Java code itself, so set hasCode to false. -->
|
||||
<application android:debuggable="true"
|
||||
android:label="@string/app_name"
|
||||
android:icon="@drawable/icon"
|
||||
android:hasCode="false"
|
||||
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
|
||||
android:hardwareAccelerated="true">
|
||||
|
||||
<activity android:name="android.app.NativeActivity"
|
||||
android:label="@string/app_name"
|
||||
android:configChanges="keyboardHidden|orientation"
|
||||
android:screenOrientation="sensorLandscape">
|
||||
|
||||
<!-- Tell NativeActivity the name of or .so -->
|
||||
<meta-data android:name="android.app.lib_name"
|
||||
android:value="main" />
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
<uses-sdk android:minSdkVersion="19" />
|
||||
<uses-feature android:glEsVersion="0x00020000" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.READ_MEDIA_STORAGE" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.WRITE_MEDIA_STORAGE" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
</manifest>
|
126
android/README.ANDROID
Normal file
@ -0,0 +1,126 @@
|
||||
================================================================================
|
||||
|
||||
SUPERTUXKART
|
||||
|
||||
================================================================================
|
||||
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
SYSTEM REQUIREMENTS
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
To run SuperTuxKart on Android, you need a device that meets following
|
||||
requirements:
|
||||
|
||||
- Android 4.4 or later
|
||||
- Processor compatible with armv7 or x86
|
||||
- GPU that supports OpenGL ES 3.0
|
||||
- 1 GB RAM (STK uses ~150 MB in minimal configuration)
|
||||
- 300 MB of free space on internal storage
|
||||
- Touch screen or external keyboard
|
||||
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
COMPILATION
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
The build scripts are designed to run under linux. They may work under cygwin
|
||||
after some tweaks, but atm. only linux is supported.
|
||||
|
||||
Dependencies list (may be incomplete):
|
||||
|
||||
autoconf, automake, make, python, ant, imagemagick, cmake, vorbis-tools
|
||||
|
||||
Additionally some dependencies for optimize_data script:
|
||||
|
||||
advancecomp, libjpeg-progs, optipng
|
||||
|
||||
Before compilation you must download the package with dependencies from:
|
||||
https://github.com/supertuxkart/dependencies
|
||||
and extract it to stk-code/lib. It contains sources of libraries that are used
|
||||
in STK, but are not availiable in stk-code repository (curl, freetype, openal).
|
||||
|
||||
You need also Android SDK for android-19 platform (the API for Android 4.4) and
|
||||
Android NDK (versions r12b and r13b have been tested).
|
||||
|
||||
You need to create proper "android-sdk" and "android-ndk" symlinks in the
|
||||
directory with Android project, so that the compilation script will have access
|
||||
to the SDK and NDK.
|
||||
|
||||
These paths can be also set in SDK_PATH and NDK_PATH environmental variables.
|
||||
|
||||
Before running the compilation, run the generate_assets script, so that
|
||||
selected assets will be copied to "assets" directory, and then included in the
|
||||
apk file.
|
||||
|
||||
You can select different karts and tracks by setting KARTS and TRACKS variables
|
||||
in the generate_assets.sh script at the beginning of file.
|
||||
|
||||
When you are creating the assets directory manually, note that the
|
||||
directories.txt file is urgently needed and it is used by the application for
|
||||
extracting assets.
|
||||
|
||||
If the assets directory is already prepared, you can run "./make.sh" command to
|
||||
build the project and create an apk file. Note that all arguments are passed to
|
||||
the make command, so that you can run "./make.sh -j5" for multi-threaded build.
|
||||
|
||||
If you want to prepare a package for particular architecture, you can choose it
|
||||
by setting the COMPILE_ARCH environmental variable. At this stage, supported
|
||||
architectures are "armv7", "x86" and "aarch64". The default is "armv7".
|
||||
|
||||
Basically if all dependencies are installed in the system, it should be enough
|
||||
to just run:
|
||||
|
||||
export SDK_PATH=/path/to/your/android/sdk
|
||||
export NDK_PATH=/path/to/your/android/ndk
|
||||
./generate_assets.sh
|
||||
./make.sh -j5
|
||||
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
KNOWN ISSUES
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
1. At this stage only shader-based (OpenGL ES 3.0) pipeline works. The fixed
|
||||
pipeline (GLES 2.0) could work (it works under linux), but it doesn't look
|
||||
good and is generally broken. It means that it's not possible to run STK on
|
||||
Android 4.2 or older. It is technically possible to do - check GLES context
|
||||
version, load OpenGL functions dynamically using EGL, and if they are not
|
||||
loaded properly, then fallback to GLES 2.0. But these devices may be too
|
||||
slow to run STK anyway.
|
||||
|
||||
2. It never ocurred for me, but it's possible that EGL context is lost in some
|
||||
cases. SuperTuxKart is not designed to re-create all textures at any moment,
|
||||
so this is a "Wontfix", at least for now.
|
||||
|
||||
3. Some bright tracks (Farm, Gran Paradiso) seem to be a bit darker in GLES
|
||||
renderer than in original OpenGL 3.x renderer. It can be easily hacked by
|
||||
adding few lines to object pass shader, but we should rather try to find the
|
||||
real reason.
|
||||
|
||||
4. We use "exit(0)" at the end of main function. We shouldn't do it and we
|
||||
should just return from the main function. But STK uses some global
|
||||
variables and their values are remembered when the game is restarted. We
|
||||
should properly clear them or re-initialize on startup. Using the "exit(0)"
|
||||
is not-that-bad workaround, but it may cause a crash on exit sometimes.
|
||||
It seems to affect only Android 5.0. More information about the crash:
|
||||
https://code.google.com/p/android/issues/detail?id=160824
|
||||
|
||||
5. STK crashes on Qualcomm with Adreno 305 when trying to draw menu interface.
|
||||
Backtrace shows glDrawElements function, and internally crashed in vbo
|
||||
allocation.
|
||||
|
||||
6. STK crashes on startup on some devices when aarch64 build is made using
|
||||
Android r13 NDK. The r13 version has rather big modifications (it uses clang
|
||||
instead of gcc by default). This is probably a bug in NDK/compiler/OS, but
|
||||
for this reason using NDK r12 for 64-bit arm compilation is preferred.
|
||||
|
||||
7. Angelscript doesn't have full support for aarch64 builds, so that scripting
|
||||
won't work on this platform.
|
||||
|
||||
8. Turning left/right using accelerometer is available, but at this stage the
|
||||
default screen orientation is not automatically detected and user must
|
||||
manually choose if he needs "phone" or "tablet" accelerometer.
|
6
android/build.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project name="SuperTuxKart" default="help">
|
||||
|
||||
<import file="${sdk.dir}/tools/ant/build.xml" />
|
||||
|
||||
</project>
|
240
android/generate_assets.sh
Executable file
@ -0,0 +1,240 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# (C) 2016-2017 Dawid Gan, under the GPLv3
|
||||
#
|
||||
# A script that generates data files for Android apk
|
||||
|
||||
|
||||
# Below are simple configuration variables
|
||||
# It's allowed to set "all" for KARTS and TRACKS if it's intended to create
|
||||
# package with full data.
|
||||
# The karts and tracks directories shouldn't exist in ASSETS_DIRS variable
|
||||
# because they are handled separately
|
||||
# The TEXTURE_SIZE and SOUND_QUALITY take effect only if DECREASE_QUALITY has
|
||||
# value greater than 0
|
||||
# The script needs imagemagick and ogg utils installed to use DECREASE_QUALITY
|
||||
# feature
|
||||
|
||||
################################################################################
|
||||
|
||||
export KARTS="tux nolok xue"
|
||||
export TRACKS="battleisland cornfield_crossing featunlocked gplose gpwin \
|
||||
hacienda introcutscene introcutscene2 lighthouse olivermath \
|
||||
overworld snowmountain snowtuxpeak soccer_field tutorial"
|
||||
|
||||
export ASSETS_PATHS="../data \
|
||||
../../stk-assets \
|
||||
../../supertuxkart-assets"
|
||||
|
||||
export ASSETS_DIRS="library models music sfx textures"
|
||||
|
||||
export TEXTURE_SIZE=256
|
||||
export SOUND_QUALITY=64
|
||||
|
||||
export RUN_OPTIMIZE_SCRIPT=0
|
||||
export DECREASE_QUALITY=1
|
||||
|
||||
################################################################################
|
||||
|
||||
|
||||
cd "`dirname "$0"`"
|
||||
|
||||
# Find assets path
|
||||
for ASSETS_PATH in $ASSETS_PATHS; do
|
||||
if [ -d $ASSETS_PATH ] && [ `ls $ASSETS_PATH | grep -c tracks` -gt 0 ]; then
|
||||
echo "Assets found in $ASSETS_PATH"
|
||||
ASSETS_PATH_FOUND=1
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -z $ASSETS_PATH_FOUND ]; then
|
||||
echo "Couldn't find assets path"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -d "../data" ]; then
|
||||
echo "Couldn't find data directory"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
# Clear previous assets directory
|
||||
echo "Clear previous assets directory"
|
||||
rm -rf assets
|
||||
|
||||
|
||||
# Copy all assets
|
||||
echo "Copy all assets"
|
||||
|
||||
mkdir -p assets/data
|
||||
|
||||
for DIR in `ls $ASSETS_PATH`; do
|
||||
CAN_BE_COPIED=0
|
||||
|
||||
for ASSETS_DIR in $ASSETS_DIRS; do
|
||||
if [ $DIR = $ASSETS_DIR ]; then
|
||||
CAN_BE_COPIED=1
|
||||
break
|
||||
fi
|
||||
done;
|
||||
|
||||
# Don't copy karts and tracks. It will be handled later
|
||||
BLACKLIST_ASSETS="karts tracks"
|
||||
for ASSETS_DIR in $BLACKLIST_ASSETS; do
|
||||
if [ $DIR = $ASSETS_DIR ]; then
|
||||
CAN_BE_COPIED=0
|
||||
break
|
||||
fi
|
||||
done;
|
||||
|
||||
if [ $CAN_BE_COPIED -gt 0 ]; then
|
||||
cp -a "$ASSETS_PATH/$DIR" assets/data/
|
||||
fi
|
||||
done;
|
||||
|
||||
|
||||
# Copy selected tracks
|
||||
echo "Copy selected tracks"
|
||||
|
||||
mkdir -p assets/data/tracks
|
||||
|
||||
for DIR in `ls $ASSETS_PATH/tracks`; do
|
||||
CAN_BE_COPIED=0
|
||||
|
||||
if [ "$TRACKS" != "all" ]; then
|
||||
for TRACK in $TRACKS; do
|
||||
if [ $DIR = $TRACK ]; then
|
||||
CAN_BE_COPIED=1
|
||||
break
|
||||
fi
|
||||
done;
|
||||
else
|
||||
CAN_BE_COPIED=1
|
||||
fi
|
||||
|
||||
if [ $CAN_BE_COPIED -gt 0 ]; then
|
||||
cp -a "$ASSETS_PATH/tracks/$DIR" assets/data/tracks/
|
||||
fi
|
||||
done
|
||||
|
||||
|
||||
# Copy selected karts
|
||||
echo "Copy selected karts"
|
||||
|
||||
mkdir -p assets/data/karts
|
||||
|
||||
for DIR in `ls $ASSETS_PATH/karts`; do
|
||||
CAN_BE_COPIED=0
|
||||
|
||||
if [ "$KARTS" != "all" ]; then
|
||||
for KART in $KARTS; do
|
||||
if [ $DIR = $KART ]; then
|
||||
CAN_BE_COPIED=1
|
||||
break
|
||||
fi
|
||||
done;
|
||||
else
|
||||
CAN_BE_COPIED=1
|
||||
fi
|
||||
|
||||
if [ $CAN_BE_COPIED -gt 0 ]; then
|
||||
cp -a "$ASSETS_PATH/karts/$DIR" assets/data/karts/
|
||||
fi
|
||||
done
|
||||
|
||||
|
||||
# Decrease assets quality in order to save some disk space and RAM
|
||||
echo "Decrease assets quality"
|
||||
|
||||
convert_image()
|
||||
{
|
||||
if [ -z "$1" ]; then
|
||||
echo "No file to convert"
|
||||
return
|
||||
fi
|
||||
|
||||
FILE="$1"
|
||||
|
||||
W=`identify -format "%[fx:w]" "$FILE"`
|
||||
H=`identify -format "%[fx:h]" "$FILE"`
|
||||
|
||||
if [ -z $W ] || [ -z $H ]; then
|
||||
echo "Couldn't convert $FILE file"
|
||||
return
|
||||
fi
|
||||
|
||||
if [ $W -le $TEXTURE_SIZE ] && [ $H -le $TEXTURE_SIZE ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
if [ $W -gt $H ]; then
|
||||
SCALED_W=$TEXTURE_SIZE
|
||||
SCALED_H=$(($TEXTURE_SIZE * $H / $W))
|
||||
else
|
||||
SCALED_W=$(($TEXTURE_SIZE * $W / $H))
|
||||
SCALED_H=$TEXTURE_SIZE
|
||||
fi
|
||||
|
||||
convert -scale $SCALED_WE\x$SCALED_H "$FILE" "$FILE"
|
||||
}
|
||||
|
||||
convert_sound()
|
||||
{
|
||||
if [ -z "$1" ]; then
|
||||
echo "No file to convert"
|
||||
return
|
||||
fi
|
||||
|
||||
FILE="$1"
|
||||
|
||||
oggdec "$FILE" -o tmp.wav
|
||||
|
||||
if [ -s tmp.wav ]; then
|
||||
oggenc --downmix -b $SOUND_QUALITY tmp.wav -o tmp.ogg
|
||||
fi
|
||||
|
||||
if [ -s tmp.ogg ]; then
|
||||
SIZE_OLD=`du -k "$FILE" | cut -f1`
|
||||
SIZE_NEW=`du -k "tmp.ogg" | cut -f1`
|
||||
|
||||
if [ $SIZE_NEW -lt $SIZE_OLD ]; then
|
||||
mv tmp.ogg "$FILE"
|
||||
fi
|
||||
fi
|
||||
|
||||
rm -f tmp.wav tmp.ogg
|
||||
}
|
||||
|
||||
if [ $DECREASE_QUALITY -gt 0 ]; then
|
||||
find assets/data -iname "*.png" | while read f; do convert_image "$f"; done
|
||||
find assets/data -iname "*.jpg" | while read f; do convert_image "$f"; done
|
||||
find assets/data -iname "*.ogg" | while read f; do convert_sound "$f"; done
|
||||
fi
|
||||
|
||||
|
||||
# Copy data directory
|
||||
echo "Copy data directory"
|
||||
cp -a ../data/* assets/data/
|
||||
|
||||
|
||||
# Run optimize_data.sh script
|
||||
if [ $RUN_OPTIMIZE_SCRIPT -gt 0 ]; then
|
||||
echo "Run optimize_data.sh script"
|
||||
sh -c 'cd assets/data; ../../../data/optimize_data.sh'
|
||||
fi
|
||||
|
||||
|
||||
# Generate directories list
|
||||
echo "Generate directories list"
|
||||
find assets/* -type d > assets/directories.txt
|
||||
sed -i s/'.\/assets\/'// assets/directories.txt
|
||||
sed -i s/'assets\/'// assets/directories.txt
|
||||
|
||||
|
||||
# It will be probably ignored by ant, but create it anyway...
|
||||
touch assets/.nomedia
|
||||
|
||||
|
||||
echo "Done."
|
||||
exit 0
|
288
android/make.sh
Executable file
@ -0,0 +1,288 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# (C) 2016-2017 Dawid Gan, under the GPLv3
|
||||
#
|
||||
# A script that creates the apk build
|
||||
|
||||
|
||||
export DIRNAME=$(realpath "$(dirname "$0")")
|
||||
|
||||
export NDK_PATH_DEFAULT="$DIRNAME/android-ndk"
|
||||
export SDK_PATH_DEFAULT="$DIRNAME/android-sdk"
|
||||
|
||||
export NDK_TOOLCHAIN_PATH="$DIRNAME/obj/bin"
|
||||
export NDK_BUILD_SCRIPT="$DIRNAME/Android.mk"
|
||||
export PATH="$DIRNAME/obj/bin:$PATH"
|
||||
export CROSS_SYSROOT="$DIRNAME/obj/sysroot"
|
||||
|
||||
#export NDK_CCACHE=ccache
|
||||
export NDK_CPPFLAGS="-O3 -g"
|
||||
|
||||
export NDK_ABI_ARMV7=armeabi-v7a
|
||||
export ARCH_ARMV7=arm
|
||||
export HOST_ARMV7=arm-linux-androideabi
|
||||
export NDK_PLATFORM_ARMV7=android-19
|
||||
|
||||
export NDK_ABI_X86=x86
|
||||
export ARCH_X86=x86
|
||||
export HOST_X86=i686-linux-android
|
||||
export NDK_PLATFORM_X86=android-19
|
||||
|
||||
export NDK_ABI_AARCH64=arm64-v8a
|
||||
export ARCH_AARCH64=arm64
|
||||
export HOST_AARCH64=aarch64-linux-android
|
||||
export NDK_PLATFORM_AARCH64=android-21
|
||||
|
||||
|
||||
# A helper function that checks if error ocurred
|
||||
check_error()
|
||||
{
|
||||
if [ $? -gt 0 ]; then
|
||||
echo "Error ocurred."
|
||||
exit
|
||||
fi
|
||||
}
|
||||
|
||||
# Handle clean command
|
||||
if [ ! -z "$1" ] && [ "$1" = "clean" ]; then
|
||||
rm -rf bin
|
||||
rm -rf libs
|
||||
rm -rf obj
|
||||
exit
|
||||
fi
|
||||
|
||||
# Check if compilation for different platform has been started before
|
||||
if [ -f "$DIRNAME/obj/compile_arch" ]; then
|
||||
PROJECT_ARCH=$(cat "$DIRNAME/obj/compile_arch")
|
||||
|
||||
if [ -z "$COMPILE_ARCH" ]; then
|
||||
COMPILE_ARCH="$PROJECT_ARCH"
|
||||
elif [ "$PROJECT_ARCH" != "$COMPILE_ARCH" ]; then
|
||||
echo "Error: Compilation for different platform has been already made."
|
||||
echo "Run './make.sh clean' first or set COMPILE_ARCH variable" \
|
||||
"to '$PROJECT_ARCH.'"
|
||||
exit
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$COMPILE_ARCH" ]; then
|
||||
COMPILE_ARCH="armv7"
|
||||
fi
|
||||
|
||||
# Update variables for selected architecture
|
||||
if [ "$COMPILE_ARCH" = "armv7" ]; then
|
||||
export NDK_PLATFORM=$NDK_PLATFORM_ARMV7
|
||||
export NDK_ABI=$NDK_ABI_ARMV7
|
||||
export ARCH=$ARCH_ARMV7
|
||||
export HOST=$HOST_ARMV7
|
||||
elif [ "$COMPILE_ARCH" = "x86" ]; then
|
||||
export NDK_PLATFORM=$NDK_PLATFORM_X86
|
||||
export NDK_ABI=$NDK_ABI_X86
|
||||
export ARCH=$ARCH_X86
|
||||
export HOST=$HOST_X86
|
||||
elif [ "$COMPILE_ARCH" = "aarch64" ]; then
|
||||
export NDK_PLATFORM=$NDK_PLATFORM_AARCH64
|
||||
export NDK_ABI=$NDK_ABI_AARCH64
|
||||
export ARCH=$ARCH_AARCH64
|
||||
export HOST=$HOST_AARCH64
|
||||
else
|
||||
echo "Unknow COMPILE_ARCH: $COMPILE_ARCH. Possible values are: " \
|
||||
"armv7, aarch64, x86"
|
||||
exit
|
||||
fi
|
||||
|
||||
# Check if we have access to the Android NDK and SDK
|
||||
if [ -z "$NDK_PATH" ]; then
|
||||
export NDK_PATH="$NDK_PATH_DEFAULT"
|
||||
fi
|
||||
|
||||
if [ -z "$SDK_PATH" ]; then
|
||||
export SDK_PATH="$SDK_PATH_DEFAULT"
|
||||
fi
|
||||
|
||||
NDK_PATH=$(realpath "$NDK_PATH")
|
||||
SDK_PATH=$(realpath "$SDK_PATH")
|
||||
|
||||
if [ ! -d "$NDK_PATH" ]; then
|
||||
echo "Error: Couldn't find $NDK_PATH directory. Please create a symlink" \
|
||||
"to your Android NDK installation in the $NDK_PATH_DEFAULT or set" \
|
||||
"proper path in the NDK_PATH variable"
|
||||
exit
|
||||
fi
|
||||
|
||||
if [ ! -d "$SDK_PATH" ]; then
|
||||
echo "Error: Couldn't find $SDK_PATH directory. Please create a symlink" \
|
||||
"to your Android SDK installation in the $SDK_PATH_DEFAULT or set" \
|
||||
"proper path in the SDK_PATH variable"
|
||||
exit
|
||||
fi
|
||||
|
||||
# Standalone toolchain
|
||||
if [ ! -f "$DIRNAME/obj/make_standalone_toolchain.stamp" ]; then
|
||||
echo "Creating standalone toolchain"
|
||||
rm -rf "$DIRNAME/obj"
|
||||
${NDK_PATH}/build/tools/make-standalone-toolchain.sh \
|
||||
--platform=$NDK_PLATFORM \
|
||||
--install-dir="$DIRNAME/obj/" \
|
||||
--arch=$ARCH
|
||||
check_error
|
||||
touch "$DIRNAME/obj/make_standalone_toolchain.stamp"
|
||||
echo $COMPILE_ARCH > "$DIRNAME/obj/compile_arch"
|
||||
fi
|
||||
|
||||
# Freetype
|
||||
if [ ! -f "$DIRNAME/obj/freetype.stamp" ]; then
|
||||
echo "Compiling freetype"
|
||||
mkdir -p "$DIRNAME/obj/freetype"
|
||||
cp -a -f "$DIRNAME/../lib/freetype/"* "$DIRNAME/obj/freetype"
|
||||
|
||||
cd "$DIRNAME/obj/freetype"
|
||||
./configure --host=$HOST \
|
||||
--without-zlib \
|
||||
--without-png \
|
||||
--without-harfbuzz &&
|
||||
make $@
|
||||
check_error
|
||||
touch "$DIRNAME/obj/freetype.stamp"
|
||||
fi
|
||||
|
||||
# Zlib
|
||||
if [ ! -f "$DIRNAME/obj/zlib.stamp" ]; then
|
||||
echo "Compiling zlib"
|
||||
mkdir -p "$DIRNAME/obj/zlib"
|
||||
cp -a -f "$DIRNAME/../lib/zlib/"* "$DIRNAME/obj/zlib"
|
||||
|
||||
cd "$DIRNAME/obj/zlib"
|
||||
cmake . -DCMAKE_TOOLCHAIN_FILE=../../../cmake/Toolchain-android.cmake \
|
||||
-DHOST=$HOST &&
|
||||
make $@
|
||||
check_error
|
||||
touch "$DIRNAME/obj/zlib.stamp"
|
||||
fi
|
||||
|
||||
# Libpng
|
||||
if [ ! -f "$DIRNAME/obj/libpng.stamp" ]; then
|
||||
echo "Compiling libpng"
|
||||
mkdir -p "$DIRNAME/obj/libpng"
|
||||
mkdir -p "$DIRNAME/obj/libpng/lib"
|
||||
cp -a -f "$DIRNAME/../lib/libpng/"* "$DIRNAME/obj/libpng"
|
||||
|
||||
cd "$DIRNAME/obj/libpng"
|
||||
cmake . -DCMAKE_TOOLCHAIN_FILE=../../../cmake/Toolchain-android.cmake \
|
||||
-DHOST=$HOST \
|
||||
-DZLIB_LIBRARY="$DIRNAME/obj/zlib/libz.a" \
|
||||
-DZLIB_INCLUDE_DIR="$DIRNAME/obj/zlib/" \
|
||||
-DPNG_TESTS=0 &&
|
||||
make $@
|
||||
check_error
|
||||
touch "$DIRNAME/obj/libpng.stamp"
|
||||
fi
|
||||
|
||||
# Openal
|
||||
if [ ! -f "$DIRNAME/obj/openal.stamp" ]; then
|
||||
echo "Compiling openal"
|
||||
mkdir -p "$DIRNAME/obj/openal"
|
||||
cp -a -f "$DIRNAME/../lib/openal/"* "$DIRNAME/obj/openal"
|
||||
|
||||
cd "$DIRNAME/obj/openal"
|
||||
cmake . -DCMAKE_TOOLCHAIN_FILE=../../../cmake/Toolchain-android.cmake \
|
||||
-DHOST=$HOST \
|
||||
-DALSOFT_UTILS=0 \
|
||||
-DALSOFT_EXAMPLES=0 \
|
||||
-DALSOFT_TESTS=0 \
|
||||
-DLIBTYPE=STATIC &&
|
||||
make $@
|
||||
check_error
|
||||
touch "$DIRNAME/obj/openal.stamp"
|
||||
fi
|
||||
|
||||
# OpenSSL
|
||||
if [ ! -f "$DIRNAME/obj/openssl.stamp" ]; then
|
||||
echo "Compiling openssl"
|
||||
mkdir -p "$DIRNAME/obj/openssl"
|
||||
cp -a -f "$DIRNAME/../lib/openssl/"* "$DIRNAME/obj/openssl"
|
||||
|
||||
cd "$DIRNAME/obj/openssl"
|
||||
./Configure android --cross-compile-prefix="$HOST-"
|
||||
make $@
|
||||
check_error
|
||||
touch "$DIRNAME/obj/openssl.stamp"
|
||||
fi
|
||||
|
||||
# Curl
|
||||
if [ ! -f "$DIRNAME/obj/curl.stamp" ]; then
|
||||
echo "Compiling curl"
|
||||
mkdir -p "$DIRNAME/obj/curl"
|
||||
cp -a -f "$DIRNAME/../lib/curl/"* "$DIRNAME/obj/curl"
|
||||
|
||||
cd "$DIRNAME/obj/curl"
|
||||
CPPFLAGS="-I$DIRNAME/obj/openssl/include $CPPFLAGS" \
|
||||
LDFLAGS="-L$DIRNAME/obj/openssl/ $LDFLAGS" \
|
||||
./configure --host=$HOST \
|
||||
--with-ssl \
|
||||
--disable-shared \
|
||||
--enable-static \
|
||||
--enable-threaded-resolver &&
|
||||
make $@
|
||||
check_error
|
||||
touch "$DIRNAME/obj/curl.stamp"
|
||||
fi
|
||||
|
||||
# Jpeglib
|
||||
if [ ! -f "$DIRNAME/obj/jpeglib.stamp" ]; then
|
||||
echo "Compiling jpeglib"
|
||||
mkdir -p "$DIRNAME/obj/jpeglib"
|
||||
cp -a -f "$DIRNAME/../lib/jpeglib/"* "$DIRNAME/obj/jpeglib"
|
||||
|
||||
cd "$DIRNAME/obj/jpeglib"
|
||||
cmake . -DCMAKE_TOOLCHAIN_FILE=../../../cmake/Toolchain-android.cmake \
|
||||
-DHOST=$HOST &&
|
||||
make $@
|
||||
check_error
|
||||
touch "$DIRNAME/obj/jpeglib.stamp"
|
||||
fi
|
||||
|
||||
# Libogg
|
||||
if [ ! -f "$DIRNAME/obj/libogg.stamp" ]; then
|
||||
echo "Compiling libogg"
|
||||
mkdir -p "$DIRNAME/obj/libogg"
|
||||
cp -a -f "$DIRNAME/../lib/libogg/"* "$DIRNAME/obj/libogg"
|
||||
|
||||
cd "$DIRNAME/obj/libogg"
|
||||
./configure --host=$HOST &&
|
||||
make $@
|
||||
check_error
|
||||
touch "$DIRNAME/obj/libogg.stamp"
|
||||
fi
|
||||
|
||||
# Libvorbis
|
||||
if [ ! -f "$DIRNAME/obj/libvorbis.stamp" ]; then
|
||||
echo "Compiling libvorbis"
|
||||
mkdir -p "$DIRNAME/obj/libvorbis"
|
||||
cp -a -f "$DIRNAME/../lib/libvorbis/"* "$DIRNAME/obj/libvorbis"
|
||||
|
||||
cd "$DIRNAME/obj/libvorbis"
|
||||
CPPFLAGS="-I$DIRNAME/obj/libogg/include $CPPFLAGS" \
|
||||
LDFLAGS="-L$DIRNAME/obj/libogg/src/.libs $LDFLAGS" \
|
||||
./configure --host=$HOST &&
|
||||
make $@
|
||||
check_error
|
||||
touch "$DIRNAME/obj/libvorbis.stamp"
|
||||
fi
|
||||
|
||||
# STK
|
||||
echo "Compiling STK"
|
||||
cd "$DIRNAME"
|
||||
${NDK_PATH}/ndk-build $@ \
|
||||
APP_BUILD_SCRIPT="$NDK_BUILD_SCRIPT" \
|
||||
APP_ABI="$NDK_ABI" \
|
||||
APP_PLATFORM="$NDK_PLATFORM" \
|
||||
APP_CPPFLAGS="$NDK_CPPFLAGS" \
|
||||
APP_STL=gnustl_static
|
||||
|
||||
check_error
|
||||
|
||||
# Build apk
|
||||
echo "Building APK"
|
||||
ant debug -Dsdk.dir="$SDK_PATH" -Dtarget=$NDK_PLATFORM
|
||||
check_error
|
BIN
android/res/drawable-hdpi/icon.png
Normal file
After Width: | Height: | Size: 5.7 KiB |
BIN
android/res/drawable-mdpi/icon.png
Normal file
After Width: | Height: | Size: 3.1 KiB |
BIN
android/res/drawable-xhdpi/icon.png
Normal file
After Width: | Height: | Size: 8.9 KiB |
BIN
android/res/drawable-xxhdpi/icon.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
android/res/drawable/icon.png
Normal file
After Width: | Height: | Size: 37 KiB |
4
android/res/values/strings.xml
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">SuperTuxKart</string>
|
||||
</resources>
|
32
cmake/Toolchain-android.cmake
Normal file
@ -0,0 +1,32 @@
|
||||
# Cross-compiling requires CMake 2.6 or newer. Example:
|
||||
# cmake .. -DCMAKE_TOOLCHAIN_FILE=../XCompile-Android.txt -DHOST=arm-linux-androideabi
|
||||
# Where 'arm-linux-androideabi' is the host prefix for the cross-compiler. If
|
||||
# you already have a toolchain file setup, you may use that instead of this
|
||||
# file. Make sure to set CMAKE_FIND_ROOT_PATH to where the NDK toolchain was
|
||||
# installed (e.g. "$ENV{HOME}/toolchains/arm-linux-androideabi-r10c-21").
|
||||
|
||||
# the name of the target operating system
|
||||
SET(CMAKE_SYSTEM_NAME Linux)
|
||||
|
||||
# which compilers to use for C and C++
|
||||
SET(CMAKE_C_COMPILER "${HOST}-gcc")
|
||||
SET(CMAKE_CXX_COMPILER "${HOST}-g++")
|
||||
SET(CMAKE_RC_COMPILER "${HOST}-windres")
|
||||
|
||||
# here is the target environment located
|
||||
SET(CMAKE_FIND_ROOT_PATH $ENV{NDK_TOOLCHAIN_PATH})
|
||||
|
||||
# here is where stuff gets installed to
|
||||
SET(CMAKE_INSTALL_PREFIX "${CMAKE_FIND_ROOT_PATH}" CACHE STRING "Install path prefix, prepended onto install directories." FORCE)
|
||||
|
||||
# adjust the default behaviour of the FIND_XXX() commands:
|
||||
# search headers and libraries in the target environment, search
|
||||
# programs in the host environment
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
|
||||
# set env vars so that pkg-config will look in the appropriate directory for
|
||||
# .pc files (as there seems to be no way to force using ${HOST}-pkg-config)
|
||||
set(ENV{PKG_CONFIG_LIBDIR} "${CMAKE_INSTALL_PREFIX}/lib/pkgconfig")
|
||||
set(ENV{PKG_CONFIG_PATH} "")
|
@ -119,6 +119,9 @@ Karts
|
||||
Objects
|
||||
- GeekPenguinBR, TuxKartDriver : Models from Las Dunas Stadium
|
||||
|
||||
Jymis
|
||||
- Karts and icons
|
||||
|
||||
Minibjorn
|
||||
- Powerups and baddies (models + icons)
|
||||
- Explosion and smoke particles
|
||||
|
@ -10,8 +10,8 @@
|
||||
<material file="explode.png" />
|
||||
|
||||
<!-- Amount of particles emitted per second -->
|
||||
<rate min="500"
|
||||
max="800" />
|
||||
<rate min="400"
|
||||
max="600" />
|
||||
|
||||
<!-- Minimal and maximal lifetime of a particle, in milliseconds. -->
|
||||
<lifetime min="1000"
|
||||
|
@ -10,8 +10,8 @@
|
||||
<material file="explode.png" />
|
||||
|
||||
<!-- Amount of particles emitted per second -->
|
||||
<rate min="500"
|
||||
max="800" />
|
||||
<rate min="400"
|
||||
max="600" />
|
||||
|
||||
<!-- Minimal and maximal lifetime of a particle, in milliseconds. -->
|
||||
<lifetime min="1000"
|
||||
|
@ -10,8 +10,8 @@
|
||||
<material file="explode.png" />
|
||||
|
||||
<!-- Amount of particles emitted per second -->
|
||||
<rate min="500"
|
||||
max="800" />
|
||||
<rate min="400"
|
||||
max="600" />
|
||||
|
||||
<!-- Minimal and maximal lifetime of a particle, in milliseconds. -->
|
||||
<lifetime min="1000"
|
||||
|
@ -1,9 +1,16 @@
|
||||
<?xml version="1.0"?>
|
||||
<graphical-restrictions>
|
||||
<card is="Intel(R) HD Graphics" os="windows" version="<9.0" disable="ForceLegacyDevice"/>
|
||||
<card is="Intel(R) HD Graphics" os="windows" version="<9.0" disable="HighDefinitionTextures"/>
|
||||
<card is="Intel(R) HD Graphics 2000" os="windows" disable="UniformBufferObject"/>
|
||||
<card is="Intel(R) HD Graphics 2000" os="windows" disable="AdvancedPipeline"/>
|
||||
<card is="Intel(R) HD Graphics 2000" os="windows" disable="FramebufferSRGBWorking"/>
|
||||
<card is="Intel(R) HD Graphics 2000" os="windows" disable="HighDefinitionTextures"/>
|
||||
<card is="Intel(R) HD Graphics 3000" os="windows" disable="UniformBufferObject"/>
|
||||
<card is="Intel(R) HD Graphics 3000" os="windows" disable="AdvancedPipeline"/>
|
||||
<card is="Intel(R) HD Graphics 3000" os="windows" disable="FramebufferSRGBWorking"/>
|
||||
<card is="Intel(R) HD Graphics" os="windows" disable="ForceLegacyDevice"/>
|
||||
<card is="Intel(R) HD Graphics 3000" os="windows" disable="HighDefinitionTextures"/>
|
||||
<card is="Intel(R) HD Graphics 4600" os="windows" disable="ComputeShader"/>
|
||||
<card contains="Intel" os="osx" disable="GI"/>
|
||||
<card contains="Intel" os="linux" version="<11.2" disable="ComputeShader"/>
|
||||
<card contains="Intel" os="linux" version="<11.2" disable="GeometryShader"/>
|
||||
@ -11,7 +18,6 @@
|
||||
<card contains="Intel" os="linux" version="<11.2" disable="TextureCompressionS3TC"/>
|
||||
<card contains="Intel" os="windows" disable="TextureCompressionS3TC"/>
|
||||
<card contains="Intel" os="osx" disable="TextureCompressionS3TC"/>
|
||||
<card contains="Intel" os="windows" disable="HighDefinitionTextures"/>
|
||||
<card contains="NVIDIA" os="windows" version="<344.65" disable="BufferStorage"/>
|
||||
<card contains="NVIDIA" os="linux" version="<343.22" disable="BufferStorage"/>
|
||||
<card contains="NVIDIA" disable="ShaderAtomicCounters"/>
|
||||
|
BIN
data/gui/android/blur_bg_button.png
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
data/gui/android/blur_bg_button_focus.png
Normal file
After Width: | Height: | Size: 5.2 KiB |
BIN
data/gui/android/directionnal_wheel.png
Normal file
After Width: | Height: | Size: 144 KiB |
BIN
data/gui/android/drift.png
Normal file
After Width: | Height: | Size: 41 KiB |
12
data/gui/android/license.txt
Normal file
@ -0,0 +1,12 @@
|
||||
# Licensing work
|
||||
|
||||
Icons firstly made for SuperTuxKart UI on Android.
|
||||
|
||||
Files: blur_bg_button ; blur_bg_button_focus ; directionnal_wheel ; drift ; nitro ; nitro_empty ; pause ; thunderbird_reset ; wing_mirror
|
||||
- CC BY-SA 4.0 / author: Néd J. Édoire
|
||||
|
||||
# License information:
|
||||
|
||||
- Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)
|
||||
Visit the following link for detailed informations:
|
||||
https://creativecommons.org/licenses/by-sa/4.0/
|
BIN
data/gui/android/nitro.png
Normal file
After Width: | Height: | Size: 27 KiB |
BIN
data/gui/android/nitro_empty.png
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
data/gui/android/pause.png
Normal file
After Width: | Height: | Size: 9.8 KiB |
BIN
data/gui/android/thunderbird_reset.png
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
data/gui/android/wing_mirror.png
Normal file
After Width: | Height: | Size: 16 KiB |
@ -3,12 +3,18 @@
|
||||
<div x="2%" y="1%" width="96%" height="98%" layout="vertical-row" >
|
||||
<header id="title" width="100%" height="fit" text_align="center" word_wrap="true" text="Touch Device Settings" />
|
||||
|
||||
<spacer height="30" width="10" />
|
||||
<spacer height="35" width="10" />
|
||||
|
||||
<label width="100%" I18N="In the multitouch settings screen" text="General"/>
|
||||
|
||||
<spacer height="15" width="10"/>
|
||||
|
||||
<div width="75%" height="fit" layout="horizontal-row" >
|
||||
<label proportion="1" height="100%" text_align="right" I18N="In the multitouch settings screen" text="Device enabled"/>
|
||||
<div proportion="1" height="fit" layout="horizontal-row" >
|
||||
<spacer width="40" height="100%" />
|
||||
<checkbox id="buttons_enabled"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div width="75%" height="fit" layout="horizontal-row" >
|
||||
<label proportion="1" height="100%" text_align="right" I18N="In the multitouch settings screen" text="Buttons scale"/>
|
||||
<div proportion="1" height="fit" layout="horizontal-row" >
|
||||
@ -16,13 +22,35 @@
|
||||
<gauge id="scale" proportion="1" min_value="50" max_value="150"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<label width="100%" I18N="In the multitouch settings screen" text="Accelerometer"/>
|
||||
|
||||
<spacer height="45" width="10"/>
|
||||
<div width="75%" height="fit" layout="horizontal-row" >
|
||||
<label proportion="1" height="100%" text_align="right" I18N="In the multitouch settings screen" text="Disabled"/>
|
||||
<div proportion="1" height="fit" layout="horizontal-row" >
|
||||
<spacer width="40" height="100%" />
|
||||
<checkbox id="accelerometer_disabled"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div width="75%" height="fit" layout="horizontal-row" >
|
||||
<label proportion="1" height="100%" text_align="right" I18N="In the multitouch settings screen" text="Phone"/>
|
||||
<div proportion="1" height="fit" layout="horizontal-row" >
|
||||
<spacer width="40" height="100%" />
|
||||
<checkbox id="accelerometer_phone"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div width="75%" height="fit" layout="horizontal-row" >
|
||||
<label proportion="1" height="100%" text_align="right" I18N="In the multitouch settings screen" text="Tablet"/>
|
||||
<div proportion="1" height="fit" layout="horizontal-row" >
|
||||
<spacer width="40" height="100%" />
|
||||
<checkbox id="accelerometer_tablet"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<label width="100%" I18N="In the multitouch settings screen" text="Advanced"/>
|
||||
|
||||
<spacer height="15" width="10"/>
|
||||
|
||||
<div width="75%" height="fit" layout="horizontal-row" >
|
||||
<label proportion="1" height="100%" text_align="right" I18N="In the multitouch settings screen" text="Deadzone center"/>
|
||||
<div proportion="1" height="fit" layout="horizontal-row" >
|
||||
@ -31,8 +59,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<spacer height="15" width="10"/>
|
||||
|
||||
<div width="75%" height="fit" layout="horizontal-row" >
|
||||
<label proportion="1" height="100%" text_align="right" I18N="In the multitouch settings screen" text="Deadzone edge"/>
|
||||
<div proportion="1" height="fit" layout="horizontal-row" >
|
||||
@ -41,12 +67,13 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<spacer height="45" width="10"/>
|
||||
<spacer height="35" width="10"/>
|
||||
|
||||
<button id="restore" text="Restore defaults" align="center"/>
|
||||
|
||||
<spacer height="15" width="10"/>
|
||||
|
||||
<button id="close" text="Apply" align="center"/>
|
||||
<div width="fit" height="fit" layout="horizontal-row" align="center">
|
||||
<button id="restore" text="Restore defaults"/>
|
||||
<spacer width="40" height="100%" />
|
||||
<button id="close" text="Apply"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</stkgui>
|
||||
|
@ -202,16 +202,21 @@
|
||||
friction: The friction increase when a parachute is attached.
|
||||
duration: The time an attached parachute is active
|
||||
duration-other: The time a parachute attached from other kart works
|
||||
duration-rank-mult: The multiplier applied to the duration of the
|
||||
parachute on the 1st kart when affected by the item. Scale for
|
||||
intermediary ranks to 1.0 for the last affected.
|
||||
duration-speed-mult: Applied in all cases, multitplier to duration
|
||||
of the parachute at max-speed. Scale to 1.0 at 0 speed.
|
||||
lbound-fraction: The lower bound fraction of speed when lost will
|
||||
detach parachute. E.g. at nearly 0 speed, only 5% of speed
|
||||
detach parachute. E.g. at nearly 0 speed, only 20% of speed
|
||||
need to be lost.
|
||||
ubound-fraction: The upper bound fraction of speed when lost will
|
||||
detach parachute. E.g. at max-speed 30% of speed must be lost.
|
||||
detach parachute. E.g. at max-speed 50% of speed must be lost.
|
||||
max-speed: A factor that decides the impact of rate of speed
|
||||
(distance between bounds) -->
|
||||
<parachute friction="2.0" duration="4.0" duration-other="8.0"
|
||||
lbound-fraction="0.95" ubound-fraction="0.7" max-speed="23" />
|
||||
|
||||
<parachute friction="2.0" duration="2.0" duration-other="2.6"
|
||||
duration-rank-mult="1.35" duration-speed-mult="2.0"
|
||||
lbound-fraction="0.8" ubound-fraction="0.5" max-speed="23" />
|
||||
<!-- Bubblegum
|
||||
duration: How long the bubblegum lasts.
|
||||
speed-fraction: To what fraction of top-speed the speed is reduced.
|
||||
|
@ -2,7 +2,7 @@ uniform mat4 ModelViewMatrix;
|
||||
uniform vec3 Position;
|
||||
uniform vec2 Size;
|
||||
|
||||
#if __VERSION__ >= 330
|
||||
#ifdef Explicit_Attrib_Location_Usable
|
||||
layout(location = 0) in vec2 Corner;
|
||||
layout(location = 3) in vec2 Texcoord;
|
||||
#else
|
||||
|
@ -1,7 +1,7 @@
|
||||
uniform vec2 center;
|
||||
uniform vec2 size;
|
||||
|
||||
#if __VERSION__ >= 330
|
||||
#ifdef Explicit_Attrib_Location_Usable
|
||||
layout(location = 0) in vec2 Position;
|
||||
#else
|
||||
in vec2 Position;
|
||||
@ -11,4 +11,4 @@ in vec2 Position;
|
||||
void main()
|
||||
{
|
||||
gl_Position = vec4(Position * size + center, 0., 1.);
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ uniform vec2 size;
|
||||
uniform vec2 texcenter;
|
||||
uniform vec2 texsize;
|
||||
|
||||
#if __VERSION__ >= 330
|
||||
#ifdef Explicit_Attrib_Location_Usable
|
||||
layout(location=0) in vec2 Position;
|
||||
layout(location=3) in vec2 Texcoord;
|
||||
layout(location=2) in uvec4 Color;
|
||||
|
@ -23,7 +23,6 @@ void main(void)
|
||||
#endif
|
||||
#endif
|
||||
vec4 detail = texture(Detail, uv_bis);
|
||||
detail.xyz = pow(detail.xyz, vec3(2.2));
|
||||
detail.rgb = detail.a * detail.rgb;
|
||||
color.rgb = detail.rgb + color.rgb * (1. - detail.a);
|
||||
float specmap = texture(SpecMap, uv).g;
|
||||
|
@ -1,6 +1,6 @@
|
||||
uniform mat4 ModelMatrix;
|
||||
|
||||
#if __VERSION__ >= 330
|
||||
#ifdef Explicit_Attrib_Location_Usable
|
||||
layout(location = 0) in vec3 Position;
|
||||
layout(location = 3) in vec2 Texcoord;
|
||||
layout(location = 4) in vec2 SecondTexcoord;
|
||||
|
@ -1,4 +1,4 @@
|
||||
#if __VERSION__ >= 330
|
||||
#ifdef Explicit_Attrib_Location_Usable
|
||||
layout(location=0) in vec3 Position;
|
||||
layout(location = 1) in float lifetime;
|
||||
layout(location = 2) in float size;
|
||||
|
@ -1,4 +1,4 @@
|
||||
#if __VERSION__ >= 330
|
||||
#ifdef Explicit_Attrib_Location_Usable
|
||||
layout(location = 0) in vec3 Position;
|
||||
layout(location = 7) in vec3 Origin;
|
||||
layout(location = 8) in vec3 Orientation;
|
||||
|
@ -2,7 +2,7 @@ uniform vec3 windDir;
|
||||
uniform mat4 ModelMatrix;
|
||||
uniform mat4 InverseModelMatrix;
|
||||
|
||||
#if __VERSION__ >= 330
|
||||
#ifdef Explicit_Attrib_Location_Usable
|
||||
layout(location = 0) in vec3 Position;
|
||||
layout(location = 1) in vec3 Normal;
|
||||
layout(location = 2) in vec4 Color;
|
||||
|
@ -29,7 +29,6 @@ void main(void)
|
||||
vec4 detail = texture(Detail, uv_bis);
|
||||
float specmap = texture(SpecMap, uv).g;
|
||||
#endif
|
||||
detail.xyz = pow(detail.xyz, vec3(2.2));
|
||||
detail.rgb = detail.a * detail.rgb;
|
||||
color.rgb = detail.rgb + color.rgb * (1. - detail.a);
|
||||
FragColor = vec4(getLightFactor(color.xyz, vec3(1.), specmap, 0.), 1.);
|
||||
|
@ -1,6 +1,6 @@
|
||||
uniform vec3 windDir;
|
||||
|
||||
#if __VERSION__ >= 330
|
||||
#ifdef Explicit_Attrib_Location_Usable
|
||||
layout(location = 0) in vec3 Position;
|
||||
layout(location = 1) in vec3 Normal;
|
||||
layout(location = 2) in vec4 Color;
|
||||
|
@ -1,7 +1,7 @@
|
||||
uniform int layer;
|
||||
|
||||
uniform vec3 windDir;
|
||||
#if __VERSION__ >= 330
|
||||
#ifdef Explicit_Attrib_Location_Usable
|
||||
layout(location = 0) in vec3 Position;
|
||||
layout(location = 2) in vec4 Color;
|
||||
layout(location = 3) in vec2 Texcoord;
|
||||
|
@ -1,4 +1,4 @@
|
||||
#if __VERSION__ >= 330
|
||||
#ifdef Explicit_Attrib_Location_Usable
|
||||
layout(location = 0) in vec3 Position;
|
||||
layout(location = 1) in vec3 Normal;
|
||||
layout(location = 2) in vec4 Color;
|
||||
|
@ -1,6 +1,6 @@
|
||||
uniform int layer;
|
||||
|
||||
#if __VERSION__ >= 330
|
||||
#ifdef Explicit_Attrib_Location_Usable
|
||||
layout(location = 0) in vec3 Position;
|
||||
layout(location = 3) in vec2 Texcoord;
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
#if __VERSION__ >= 330
|
||||
#ifdef Explicit_Attrib_Location_Usable
|
||||
layout(location = 0) in vec3 Position;
|
||||
layout(location = 1) in vec3 Normal;
|
||||
layout(location = 2) in vec4 Color;
|
||||
|
@ -1,6 +1,6 @@
|
||||
uniform int layer;
|
||||
|
||||
#if __VERSION__ >= 330
|
||||
#ifdef Explicit_Attrib_Location_Usable
|
||||
layout(location = 0) in vec3 Position;
|
||||
layout(location = 3) in vec4 Data1;
|
||||
layout(location = 5) in ivec4 Joint;
|
||||
|
@ -17,7 +17,7 @@ uniform mat4 InverseModelMatrix =
|
||||
uniform vec2 texture_trans = vec2(0., 0.);
|
||||
#endif
|
||||
|
||||
#if __VERSION__ >= 330
|
||||
#ifdef Explicit_Attrib_Location_Usable
|
||||
layout(location = 0) in vec3 Position;
|
||||
layout(location = 1) in vec3 Normal;
|
||||
layout(location = 2) in vec4 Color;
|
||||
|
@ -40,7 +40,11 @@ void main(void)
|
||||
col = vec4(new_color.r, new_color.g, new_color.b, col.a);
|
||||
}
|
||||
|
||||
#ifdef GL_ES
|
||||
col.xyz *= color.xyz;
|
||||
#else
|
||||
col.xyz *= pow(color.xyz, vec3(2.2));
|
||||
#endif
|
||||
float specmap = texture(SpecMap, uv).g;
|
||||
float emitmap = texture(SpecMap, uv).b;
|
||||
FragColor = vec4(getLightFactor(col.xyz, vec3(1.), specmap, emitmap), 1.);
|
||||
|
@ -1,7 +1,7 @@
|
||||
uniform vec3 color_from;
|
||||
uniform vec3 color_to;
|
||||
|
||||
#if __VERSION__ >= 330
|
||||
#ifdef Explicit_Attrib_Location_Usable
|
||||
layout(location=0) in vec3 Position;
|
||||
layout(location = 1) in float lifetime;
|
||||
layout(location = 2) in float size;
|
||||
|
@ -9,7 +9,7 @@ uniform float track_x_len;
|
||||
uniform float track_z_len;
|
||||
uniform samplerBuffer heightmap;
|
||||
|
||||
#if __VERSION__ >= 330
|
||||
#ifdef Explicit_Attrib_Location_Usable
|
||||
layout (location = 4) in vec3 particle_position_initial;
|
||||
layout (location = 5) in float lifetime_initial;
|
||||
layout (location = 6) in vec3 particle_velocity_initial;
|
||||
|
@ -4,7 +4,7 @@ uniform mat4 sourcematrix;
|
||||
uniform int level;
|
||||
uniform float size_increase_factor;
|
||||
|
||||
#if __VERSION__ >= 330
|
||||
#ifdef Explicit_Attrib_Location_Usable
|
||||
layout (location = 4) in vec3 particle_position_initial;
|
||||
layout (location = 5) in float lifetime_initial;
|
||||
layout (location = 6) in vec3 particle_velocity_initial;
|
||||
@ -40,14 +40,14 @@ void main(void)
|
||||
{
|
||||
float dt_from_last_frame = fract(updated_lifetime) * lifetime_initial;
|
||||
float coeff = dt_from_last_frame / float(dt);
|
||||
|
||||
|
||||
vec4 previous_frame_position = previous_frame_sourcematrix * vec4(particle_position_initial, 1.0);
|
||||
vec4 current_frame_position = sourcematrix * vec4(particle_position_initial, 1.0);
|
||||
|
||||
|
||||
vec4 updated_initialposition = mix(current_frame_position,
|
||||
previous_frame_position,
|
||||
coeff);
|
||||
|
||||
|
||||
vec4 updated_initial_velocity = mix(sourcematrix * vec4(particle_velocity_initial, 0.0),
|
||||
previous_frame_sourcematrix * vec4(particle_velocity_initial, 0.0),
|
||||
coeff);
|
||||
@ -56,12 +56,12 @@ void main(void)
|
||||
//But the simple formula ( (current_frame_position - previous_frame_position) / dt ) with a constant speed
|
||||
//between 2 frames creates visual artifacts when the framerate is low, and a more accurate formula would need
|
||||
//more complex computations.
|
||||
|
||||
|
||||
new_particle_position = updated_initialposition.xyz + dt_from_last_frame * updated_initial_velocity.xyz;
|
||||
new_particle_velocity = updated_initial_velocity.xyz;
|
||||
|
||||
|
||||
new_lifetime = fract(updated_lifetime);
|
||||
new_size = mix(size_initial, size_initial * size_increase_factor, fract(updated_lifetime));
|
||||
new_size = mix(size_initial, size_initial * size_increase_factor, fract(updated_lifetime));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1,4 +1,4 @@
|
||||
#if __VERSION__ >= 330
|
||||
#ifdef Explicit_Attrib_Location_Usable
|
||||
layout(location = 0) in vec3 Position;
|
||||
layout(location = 1) in vec3 Normal;
|
||||
layout(location = 2) in vec4 Color;
|
||||
|
@ -2,7 +2,7 @@ uniform mat4 ModelMatrix;
|
||||
uniform mat4 RSMMatrix;
|
||||
uniform vec2 texture_trans = vec2(0., 0.);
|
||||
|
||||
#if __VERSION__ >= 330
|
||||
#ifdef Explicit_Attrib_Location_Usable
|
||||
layout(location = 0) in vec3 Position;
|
||||
layout(location = 1) in vec3 Normal;
|
||||
layout(location = 2) in vec4 Color;
|
||||
|
@ -1,4 +1,4 @@
|
||||
#if __VERSION__ >= 330
|
||||
#ifdef Explicit_Attrib_Location_Usable
|
||||
layout(location = 0) in vec2 Position;
|
||||
layout(location = 3) in vec2 Texcoord;
|
||||
#else
|
||||
|
@ -1,7 +1,7 @@
|
||||
uniform int layer;
|
||||
uniform mat4 ModelMatrix;
|
||||
|
||||
#if __VERSION__ >= 330
|
||||
#ifdef Explicit_Attrib_Location_Usable
|
||||
layout(location = 0) in vec3 Position;
|
||||
layout(location = 3) in vec2 Texcoord;
|
||||
#else
|
||||
|
@ -2,7 +2,7 @@ uniform int layer;
|
||||
uniform mat4 ModelMatrix;
|
||||
uniform vec3 windDir;
|
||||
|
||||
#if __VERSION__ >= 330
|
||||
#ifdef Explicit_Attrib_Location_Usable
|
||||
layout(location = 0) in vec3 Position;
|
||||
layout(location = 2) in vec4 Color;
|
||||
layout(location = 3) in vec2 Texcoord;
|
||||
|
@ -18,7 +18,7 @@ uniform vec2 texture_trans = vec2(0., 0.);
|
||||
#endif
|
||||
uniform int skinning_offset;
|
||||
|
||||
#if __VERSION__ >= 330
|
||||
#ifdef Explicit_Attrib_Location_Usable
|
||||
layout(location = 0) in vec3 Position;
|
||||
layout(location = 1) in vec3 Normal;
|
||||
layout(location = 2) in vec4 Color;
|
||||
|
@ -2,7 +2,7 @@ uniform mat4 ModelMatrix;
|
||||
uniform int skinning_offset;
|
||||
uniform int layer;
|
||||
|
||||
#if __VERSION__ >= 330
|
||||
#ifdef Explicit_Attrib_Location_Usable
|
||||
layout(location = 0) in vec3 Position;
|
||||
layout(location = 3) in vec4 Data1;
|
||||
layout(location = 5) in ivec4 Joint;
|
||||
|
@ -1,4 +1,4 @@
|
||||
#if __VERSION__ >= 330
|
||||
#ifdef Explicit_Attrib_Location_Usable
|
||||
layout(location = 0) in vec3 Position;
|
||||
#else
|
||||
in vec3 Position;
|
||||
|
@ -35,7 +35,11 @@ float getShadowFactor(vec3 pos, int index)
|
||||
for (float i = -1.; i <= 1.; i += 1.)
|
||||
{
|
||||
for (float j = -1.; j <= 1.; j += 1.)
|
||||
result += texture(shadowtex, vec4(shadowtexcoord + vec2(i,j) / shadow_res, float(index), d));
|
||||
{
|
||||
// result += texture(shadowtex, vec4(shadowtexcoord + vec2(i,j) / shadow_res, float(index), d));
|
||||
// Added a hack with j+1. to avoid ugly lines
|
||||
result += texture(shadowtex, vec4(shadowtexcoord + vec2(i,j+1.) / shadow_res, float(index), d));
|
||||
}
|
||||
}
|
||||
|
||||
return result / 9.;
|
||||
|
@ -3,7 +3,7 @@ uniform vec2 size;
|
||||
uniform vec2 texcenter;
|
||||
uniform vec2 texsize;
|
||||
|
||||
#if __VERSION__ >= 330
|
||||
#ifdef Explicit_Attrib_Location_Usable
|
||||
layout(location=0) in vec2 Position;
|
||||
layout(location=3) in vec2 Texcoord;
|
||||
#else
|
||||
@ -17,4 +17,4 @@ void main()
|
||||
{
|
||||
uv = Texcoord * texsize + texcenter;
|
||||
gl_Position = vec4(Position * size + center, 0., 1.);
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,10 @@ vec3 getLightFactor(vec3 diffuseMatColor, vec3 specularMatColor, float specMapVa
|
||||
vec3 DiffuseComponent = texture(DiffuseMap, tc).xyz;
|
||||
vec3 SpecularComponent = texture(SpecularMap, tc).xyz;
|
||||
float ao = texture(SSAO, tc).x;
|
||||
#ifdef GL_ES
|
||||
DiffuseComponent = pow(DiffuseComponent, vec3(1. / 2.2));
|
||||
SpecularComponent = pow(SpecularComponent, vec3(1. / 2.2));
|
||||
#endif
|
||||
vec3 tmp = diffuseMatColor * DiffuseComponent * (1. - specMapValue) + specularMatColor * SpecularComponent * specMapValue;
|
||||
vec3 emitCol = diffuseMatColor.xyz * diffuseMatColor.xyz * diffuseMatColor.xyz * 15.;
|
||||
return tmp * ao + (emitMapValue * emitCol);
|
||||
|
@ -16,12 +16,51 @@
|
||||
|
||||
<!-- Scores are the number of points given when the race ends. -->
|
||||
<grand-prix>
|
||||
<!-- Karts on position 1 and 2 will have 3 more points than the next kart;
|
||||
a kart on position 3 and 4 will have two more points than the next;
|
||||
and all remaining karts will have one more point than the next. -->
|
||||
<points from="1" to="2" points="3"/>
|
||||
<points from="3" to="4" points="2"/>
|
||||
<points from="5" points="1"/>
|
||||
<!-- Establish the distribution of points in GP.
|
||||
|
||||
For a race of N karts ; the N-first point values are taken.
|
||||
Then, they are sorted. E.g. ; 0 1 2 1 3 2 becomes 0 1 1 2 2 3.
|
||||
Then these numbers are used to establish the DIFFERENCE of points
|
||||
between consecutive karts.
|
||||
|
||||
The smaller of the numbers is used to establish the score for the
|
||||
last kart and not the difference between 2 karts.
|
||||
|
||||
In the above example, the last kart will have 0 point, the one before
|
||||
before 1 (0+1) ; the one before 2 (0+1+1), the one before 4 (0+1+1+2),
|
||||
etc. until the 1st which have 9 (0+1+1+2+2+3)
|
||||
|
||||
There shall be at least as much points nodes as max-numbers kart -->
|
||||
<points points="0" /> <!-- added with 1 kart, score for the last kart -->
|
||||
<points points="1" /> <!-- added with 2 karts -->
|
||||
<points points="1" /> <!-- added with 3 karts -->
|
||||
<points points="2" /> <!-- added with 4 karts -->
|
||||
<points points="2" /> <!-- added with 5 karts -->
|
||||
<points points="1" /> <!-- added with 6 karts -->
|
||||
<points points="3" /> <!-- added with 7 karts -->
|
||||
<points points="2" /> <!-- added with 8 karts -->
|
||||
<points points="3" /> <!-- added with 9 karts -->
|
||||
<points points="1" /> <!-- added with 10 karts -->
|
||||
<points points="4" /> <!-- added with 11 karts -->
|
||||
<points points="2" /> <!-- added with 12 karts -->
|
||||
<points points="1" /> <!-- added with 13 karts -->
|
||||
<points points="3" /> <!-- added with 14 karts -->
|
||||
<points points="2" /> <!-- added with 15 karts -->
|
||||
<points points="1" /> <!-- added with 16 karts -->
|
||||
<points points="4" /> <!-- added with 17 karts -->
|
||||
<points points="2" /> <!-- added with 18 karts -->
|
||||
<points points="3" /> <!-- added with 19 karts -->
|
||||
<points points="1" /> <!-- added with 20 karts -->
|
||||
<points points="5" /> <!-- added with 21 karts -->
|
||||
<points points="2" /> <!-- added with 22 karts -->
|
||||
<points points="1" /> <!-- added with 23 karts -->
|
||||
<points points="3" /> <!-- added with 24 karts -->
|
||||
<points points="4" /> <!-- added with 25 karts -->
|
||||
<points points="1" /> <!-- added with 26 karts -->
|
||||
<points points="2" /> <!-- added with 27 karts -->
|
||||
<points points="1" /> <!-- added with 28 karts -->
|
||||
<points points="3" /> <!-- added with 29 karts -->
|
||||
<points points="5" /> <!-- added with 30 karts -->
|
||||
</grand-prix>
|
||||
|
||||
<!-- Time in follow-the-leader after which karts are removed.
|
||||
@ -353,7 +392,7 @@
|
||||
outside of the chassis and results in more stable physical
|
||||
behaviour of the karts. -->
|
||||
<collision impulse-type="normal"
|
||||
impulse="3000" impulse-time="0.1" terrain-impulse="1600"
|
||||
impulse="3000" impulse-time="0.1" terrain-impulse="160"
|
||||
restitution="1.0" bevel-factor="0.5 0.0 0.7"
|
||||
physical-wheel-position="-1" />
|
||||
|
||||
|
@ -112,6 +112,7 @@ source/Irrlicht/CImageLoaderPNG.cpp
|
||||
source/Irrlicht/CImageWriterBMP.cpp
|
||||
source/Irrlicht/CImageWriterJPG.cpp
|
||||
source/Irrlicht/CImageWriterPNG.cpp
|
||||
source/Irrlicht/CIrrDeviceAndroid.cpp
|
||||
source/Irrlicht/CIrrDeviceConsole.cpp
|
||||
source/Irrlicht/CIrrDeviceFB.cpp
|
||||
source/Irrlicht/CIrrDeviceLinux.cpp
|
||||
@ -243,6 +244,7 @@ source/Irrlicht/CImageLoaderPNG.h
|
||||
source/Irrlicht/CImageWriterBMP.h
|
||||
source/Irrlicht/CImageWriterJPG.h
|
||||
source/Irrlicht/CImageWriterPNG.h
|
||||
source/Irrlicht/CIrrDeviceAndroid.h
|
||||
source/Irrlicht/CIrrDeviceConsole.h
|
||||
source/Irrlicht/CIrrDeviceFB.h
|
||||
source/Irrlicht/CIrrDeviceLinux.h
|
||||
|
963
lib/irrlicht/source/Irrlicht/CIrrDeviceAndroid.cpp
Normal file
@ -0,0 +1,963 @@
|
||||
// Copyright (C) 2002-2007 Nikolaus Gebhardt
|
||||
// Copyright (C) 2007-2011 Christian Stehno
|
||||
// Copyright (C) 2016-2017 Dawid Gan
|
||||
// This file is part of the "Irrlicht Engine".
|
||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
||||
|
||||
#include "CIrrDeviceAndroid.h"
|
||||
|
||||
#ifdef _IRR_COMPILE_WITH_ANDROID_DEVICE_
|
||||
|
||||
#include <assert.h>
|
||||
#include "os.h"
|
||||
#include "CFileSystem.h"
|
||||
#include "COGLES2Driver.h"
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace video
|
||||
{
|
||||
IVideoDriver* createOGLES1Driver(const SIrrlichtCreationParameters& params,
|
||||
video::SExposedVideoData& data, io::IFileSystem* io);
|
||||
|
||||
IVideoDriver* createOGLES2Driver(const SIrrlichtCreationParameters& params,
|
||||
video::SExposedVideoData& data, io::IFileSystem* io);
|
||||
}
|
||||
}
|
||||
|
||||
namespace irr
|
||||
{
|
||||
|
||||
// These variables must be global. Otherwise initialization will reach infinite
|
||||
// loop after creating the device second time (i.e. the NULL driver and then
|
||||
// GLES2 driver). We get initialization events from Android only once.
|
||||
bool CIrrDeviceAndroid::IsPaused = true;
|
||||
bool CIrrDeviceAndroid::IsFocused = false;
|
||||
bool CIrrDeviceAndroid::IsStarted = false;
|
||||
bool CIrrDeviceAndroid::IsClosing = false;
|
||||
|
||||
//! constructor
|
||||
CIrrDeviceAndroid::CIrrDeviceAndroid(const SIrrlichtCreationParameters& param)
|
||||
: CIrrDeviceStub(param),
|
||||
Accelerometer(0),
|
||||
Gyroscope(0),
|
||||
IsMousePressed(false)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CIrrDeviceAndroid");
|
||||
#endif
|
||||
|
||||
Android = (android_app *)(param.PrivateData);
|
||||
|
||||
IsClosing = Android->destroyRequested;
|
||||
|
||||
Android->userData = this;
|
||||
Android->onAppCmd = handleAndroidCommand;
|
||||
Android->onInputEvent = handleInput;
|
||||
|
||||
SensorManager = ASensorManager_getInstance();
|
||||
SensorEventQueue = ASensorManager_createEventQueue(SensorManager,
|
||||
Android->looper, LOOPER_ID_USER, NULL, NULL);
|
||||
|
||||
ANativeActivity_setWindowFlags(Android->activity,
|
||||
AWINDOW_FLAG_KEEP_SCREEN_ON |
|
||||
AWINDOW_FLAG_FULLSCREEN, 0);
|
||||
|
||||
createKeyMap();
|
||||
|
||||
// Create cursor control
|
||||
CursorControl = new CCursorControl();
|
||||
|
||||
os::Printer::log("Waiting for Android activity window to be created.", ELL_DEBUG);
|
||||
|
||||
while ((!IsStarted || !IsFocused || IsPaused) && !IsClosing)
|
||||
{
|
||||
s32 events = 0;
|
||||
android_poll_source* source = 0;
|
||||
|
||||
s32 id = ALooper_pollAll(-1, NULL, &events, (void**)&source);
|
||||
|
||||
if (id >=0 && source != NULL)
|
||||
{
|
||||
source->process(Android, source);
|
||||
}
|
||||
}
|
||||
|
||||
assert(Android->window);
|
||||
os::Printer::log("Done", ELL_DEBUG);
|
||||
|
||||
ExposedVideoData.OGLESAndroid.Window = Android->window;
|
||||
|
||||
getVideoModeList();
|
||||
|
||||
createDriver();
|
||||
|
||||
if (VideoDriver)
|
||||
createGUIAndScene();
|
||||
}
|
||||
|
||||
|
||||
CIrrDeviceAndroid::~CIrrDeviceAndroid()
|
||||
{
|
||||
Android->userData = NULL;
|
||||
}
|
||||
|
||||
video::IVideoModeList* CIrrDeviceAndroid::getVideoModeList()
|
||||
{
|
||||
if (Android == NULL || Android->window == NULL)
|
||||
return NULL;
|
||||
|
||||
core::dimension2d<u32> size = core::dimension2d<u32>(
|
||||
ANativeWindow_getWidth(Android->window),
|
||||
ANativeWindow_getHeight(Android->window));
|
||||
|
||||
CreationParams.WindowSize.Width = size.Width;
|
||||
CreationParams.WindowSize.Height = size.Height;
|
||||
|
||||
if (!VideoModeList.getVideoModeCount())
|
||||
{
|
||||
VideoModeList.addMode(size, 32);
|
||||
VideoModeList.setDesktop(32, size);
|
||||
}
|
||||
|
||||
return &VideoModeList;
|
||||
}
|
||||
|
||||
void CIrrDeviceAndroid::createDriver()
|
||||
{
|
||||
// Create the driver.
|
||||
switch(CreationParams.DriverType)
|
||||
{
|
||||
case video::EDT_OGLES1:
|
||||
#ifdef _IRR_COMPILE_WITH_OGLES1_
|
||||
VideoDriver = video::createOGLES1Driver(CreationParams, ExposedVideoData, FileSystem);
|
||||
#else
|
||||
os::Printer::log("No OpenGL ES 1.0 support compiled in.", ELL_ERROR);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case video::EDT_OGLES2:
|
||||
#ifdef _IRR_COMPILE_WITH_OGLES2_
|
||||
VideoDriver = video::createOGLES2Driver(CreationParams, ExposedVideoData, FileSystem);
|
||||
#else
|
||||
os::Printer::log("No OpenGL ES 2.0 support compiled in.", ELL_ERROR);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case video::EDT_NULL:
|
||||
VideoDriver = video::createNullDriver(FileSystem, CreationParams.WindowSize);
|
||||
break;
|
||||
|
||||
default:
|
||||
os::Printer::log("Unable to create video driver of unknown type.", ELL_ERROR);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool CIrrDeviceAndroid::run()
|
||||
{
|
||||
os::Timer::tick();
|
||||
|
||||
while (!IsClosing)
|
||||
{
|
||||
s32 Events = 0;
|
||||
android_poll_source* Source = 0;
|
||||
bool should_run = (IsStarted && IsFocused && !IsPaused) || IsClosing;
|
||||
s32 id = ALooper_pollAll(should_run ? 0 : -1, NULL, &Events,
|
||||
(void**)&Source);
|
||||
|
||||
if (id < 0)
|
||||
break;
|
||||
|
||||
if (Source)
|
||||
{
|
||||
Source->process(Android, Source);
|
||||
}
|
||||
|
||||
// if a sensor has data, we'll process it now.
|
||||
if (id == LOOPER_ID_USER)
|
||||
{
|
||||
ASensorEvent event;
|
||||
while (ASensorEventQueue_getEvents(SensorEventQueue, &event, 1) > 0)
|
||||
{
|
||||
switch (event.type)
|
||||
{
|
||||
case ASENSOR_TYPE_ACCELEROMETER:
|
||||
SEvent accEvent;
|
||||
accEvent.EventType = EET_ACCELEROMETER_EVENT;
|
||||
accEvent.AccelerometerEvent.X = event.acceleration.x;
|
||||
accEvent.AccelerometerEvent.Y = event.acceleration.y;
|
||||
accEvent.AccelerometerEvent.Z = event.acceleration.z;
|
||||
|
||||
postEventFromUser(accEvent);
|
||||
break;
|
||||
|
||||
case ASENSOR_TYPE_GYROSCOPE:
|
||||
SEvent gyroEvent;
|
||||
gyroEvent.EventType = EET_GYROSCOPE_EVENT;
|
||||
gyroEvent.GyroscopeEvent.X = event.vector.x;
|
||||
gyroEvent.GyroscopeEvent.Y = event.vector.y;
|
||||
gyroEvent.GyroscopeEvent.Z = event.vector.z;
|
||||
|
||||
postEventFromUser(gyroEvent);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return !IsClosing;
|
||||
}
|
||||
|
||||
void CIrrDeviceAndroid::yield()
|
||||
{
|
||||
struct timespec ts = {0,1};
|
||||
nanosleep(&ts, NULL);
|
||||
}
|
||||
|
||||
void CIrrDeviceAndroid::sleep(u32 timeMs, bool pauseTimer)
|
||||
{
|
||||
const bool wasStopped = Timer ? Timer->isStopped() : true;
|
||||
|
||||
struct timespec ts;
|
||||
ts.tv_sec = (time_t) (timeMs / 1000);
|
||||
ts.tv_nsec = (long) (timeMs % 1000) * 1000000;
|
||||
|
||||
if (pauseTimer && !wasStopped)
|
||||
Timer->stop();
|
||||
|
||||
nanosleep(&ts, NULL);
|
||||
|
||||
if (pauseTimer && !wasStopped)
|
||||
Timer->start();
|
||||
}
|
||||
|
||||
void CIrrDeviceAndroid::setWindowCaption(const wchar_t* text)
|
||||
{
|
||||
}
|
||||
|
||||
bool CIrrDeviceAndroid::present(video::IImage* surface, void* windowId,
|
||||
core::rect<s32>* srcClip)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CIrrDeviceAndroid::isWindowActive() const
|
||||
{
|
||||
return (IsFocused && !IsPaused);
|
||||
}
|
||||
|
||||
bool CIrrDeviceAndroid::isWindowFocused() const
|
||||
{
|
||||
return IsFocused;
|
||||
}
|
||||
|
||||
bool CIrrDeviceAndroid::isWindowMinimized() const
|
||||
{
|
||||
return IsPaused;
|
||||
}
|
||||
|
||||
void CIrrDeviceAndroid::closeDevice()
|
||||
{
|
||||
}
|
||||
|
||||
void CIrrDeviceAndroid::setResizable(bool resize)
|
||||
{
|
||||
}
|
||||
|
||||
void CIrrDeviceAndroid::minimizeWindow()
|
||||
{
|
||||
}
|
||||
|
||||
void CIrrDeviceAndroid::maximizeWindow()
|
||||
{
|
||||
}
|
||||
|
||||
void CIrrDeviceAndroid::restoreWindow()
|
||||
{
|
||||
}
|
||||
|
||||
E_DEVICE_TYPE CIrrDeviceAndroid::getType() const
|
||||
{
|
||||
return EIDT_ANDROID;
|
||||
}
|
||||
|
||||
void CIrrDeviceAndroid::handleAndroidCommand(android_app* app, int32_t cmd)
|
||||
{
|
||||
CIrrDeviceAndroid* device = (CIrrDeviceAndroid *)app->userData;
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case APP_CMD_SAVE_STATE:
|
||||
os::Printer::log("Android command APP_CMD_SAVE_STATE", ELL_DEBUG);
|
||||
break;
|
||||
case APP_CMD_INIT_WINDOW:
|
||||
os::Printer::log("Android command APP_CMD_INIT_WINDOW", ELL_DEBUG);
|
||||
|
||||
if (device != NULL)
|
||||
{
|
||||
device->getExposedVideoData().OGLESAndroid.Window = app->window;
|
||||
|
||||
// If the Android app is resumed, we need to re-create EGL surface
|
||||
// to allow to draw something on it again.
|
||||
if (device->VideoDriver != NULL &&
|
||||
device->CreationParams.DriverType == video::EDT_OGLES2)
|
||||
{
|
||||
video::COGLES2Driver* driver = (video::COGLES2Driver*)(device->VideoDriver);
|
||||
driver->reloadEGLSurface(app->window);
|
||||
}
|
||||
}
|
||||
|
||||
IsStarted = true;
|
||||
break;
|
||||
case APP_CMD_TERM_WINDOW:
|
||||
os::Printer::log("Android command APP_CMD_TERM_WINDOW", ELL_DEBUG);
|
||||
IsStarted = false;
|
||||
break;
|
||||
case APP_CMD_GAINED_FOCUS:
|
||||
os::Printer::log("Android command APP_CMD_GAINED_FOCUS", ELL_DEBUG);
|
||||
IsFocused = true;
|
||||
break;
|
||||
case APP_CMD_LOST_FOCUS:
|
||||
os::Printer::log("Android command APP_CMD_LOST_FOCUS", ELL_DEBUG);
|
||||
IsFocused = false;
|
||||
break;
|
||||
case APP_CMD_DESTROY:
|
||||
os::Printer::log("Android command APP_CMD_DESTROY", ELL_DEBUG);
|
||||
IsClosing = true;
|
||||
// Make sure that state variables are set to the default state
|
||||
// when the app is destroyed
|
||||
IsPaused = true;
|
||||
IsFocused = false;
|
||||
IsStarted = false;
|
||||
break;
|
||||
case APP_CMD_PAUSE:
|
||||
os::Printer::log("Android command APP_CMD_PAUSE", ELL_DEBUG);
|
||||
IsPaused = true;
|
||||
break;
|
||||
case APP_CMD_RESUME:
|
||||
os::Printer::log("Android command APP_CMD_RESUME", ELL_DEBUG);
|
||||
IsPaused = false;
|
||||
break;
|
||||
case APP_CMD_START:
|
||||
os::Printer::log("Android command APP_CMD_START", ELL_DEBUG);
|
||||
break;
|
||||
case APP_CMD_STOP:
|
||||
os::Printer::log("Android command APP_CMD_STOP", ELL_DEBUG);
|
||||
break;
|
||||
case APP_CMD_WINDOW_RESIZED:
|
||||
os::Printer::log("Android command APP_CMD_WINDOW_RESIZED", ELL_DEBUG);
|
||||
break;
|
||||
case APP_CMD_CONFIG_CHANGED:
|
||||
os::Printer::log("Android command APP_CMD_CONFIG_CHANGED", ELL_DEBUG);
|
||||
break;
|
||||
case APP_CMD_LOW_MEMORY:
|
||||
os::Printer::log("Android command APP_CMD_LOW_MEMORY", ELL_DEBUG);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (device != NULL)
|
||||
{
|
||||
SEvent event;
|
||||
event.EventType = EET_SYSTEM_EVENT;
|
||||
event.SystemEvent.EventType = ESET_ANDROID_CMD;
|
||||
event.SystemEvent.AndroidCmd.Cmd = cmd;
|
||||
device->postEventFromUser(event);
|
||||
}
|
||||
}
|
||||
|
||||
s32 CIrrDeviceAndroid::handleInput(android_app* app, AInputEvent* androidEvent)
|
||||
{
|
||||
CIrrDeviceAndroid* device = (CIrrDeviceAndroid*)app->userData;
|
||||
s32 status = 0;
|
||||
|
||||
if (device == NULL)
|
||||
return status;
|
||||
|
||||
|
||||
switch (AInputEvent_getType(androidEvent))
|
||||
{
|
||||
case AINPUT_EVENT_TYPE_MOTION:
|
||||
{
|
||||
SEvent event;
|
||||
event.EventType = EET_TOUCH_INPUT_EVENT;
|
||||
|
||||
s32 eventAction = AMotionEvent_getAction(androidEvent);
|
||||
|
||||
#if 0
|
||||
// Useful for debugging. We might have to pass some of those infos on at some point.
|
||||
// but preferably device independent (so iphone can use same irrlicht flags).
|
||||
int32_t flags = AMotionEvent_getFlags(androidEvent);
|
||||
os::Printer::log("flags: ", core::stringc(flags).c_str(), ELL_DEBUG);
|
||||
int32_t metaState = AMotionEvent_getMetaState(androidEvent);
|
||||
os::Printer::log("metaState: ", core::stringc(metaState).c_str(), ELL_DEBUG);
|
||||
int32_t edgeFlags = AMotionEvent_getEdgeFlags(androidEvent);
|
||||
os::Printer::log("edgeFlags: ", core::stringc(flags).c_str(), ELL_DEBUG);
|
||||
#endif
|
||||
|
||||
bool touchReceived = true;
|
||||
bool simulate_mouse = false;
|
||||
core::position2d<s32> mouse_pos = core::position2d<s32>(0, 0);
|
||||
|
||||
switch (eventAction & AMOTION_EVENT_ACTION_MASK)
|
||||
{
|
||||
case AMOTION_EVENT_ACTION_DOWN:
|
||||
case AMOTION_EVENT_ACTION_POINTER_DOWN:
|
||||
event.TouchInput.Event = ETIE_PRESSED_DOWN;
|
||||
break;
|
||||
case AMOTION_EVENT_ACTION_MOVE:
|
||||
event.TouchInput.Event = ETIE_MOVED;
|
||||
break;
|
||||
case AMOTION_EVENT_ACTION_UP:
|
||||
case AMOTION_EVENT_ACTION_POINTER_UP:
|
||||
case AMOTION_EVENT_ACTION_CANCEL:
|
||||
event.TouchInput.Event = ETIE_LEFT_UP;
|
||||
break;
|
||||
default:
|
||||
touchReceived = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (touchReceived)
|
||||
{
|
||||
s32 count = 1;
|
||||
s32 idx = (eventAction & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >>
|
||||
AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
|
||||
|
||||
// Process all touches for move action.
|
||||
if (event.TouchInput.Event == ETIE_MOVED)
|
||||
{
|
||||
count = AMotionEvent_getPointerCount(androidEvent);
|
||||
idx = 0;
|
||||
}
|
||||
|
||||
for (s32 i = 0; i < count; ++i)
|
||||
{
|
||||
event.TouchInput.ID = AMotionEvent_getPointerId(androidEvent, i + idx);
|
||||
event.TouchInput.X = AMotionEvent_getX(androidEvent, i + idx);
|
||||
event.TouchInput.Y = AMotionEvent_getY(androidEvent, i + idx);
|
||||
|
||||
device->postEventFromUser(event);
|
||||
|
||||
if (event.TouchInput.ID == 0)
|
||||
{
|
||||
simulate_mouse = true;
|
||||
mouse_pos.X = event.TouchInput.X;
|
||||
mouse_pos.Y = event.TouchInput.Y;
|
||||
}
|
||||
}
|
||||
|
||||
status = 1;
|
||||
}
|
||||
|
||||
// Simulate mouse event for first finger on multitouch device.
|
||||
// This allows to click on GUI elements.
|
||||
if (simulate_mouse)
|
||||
{
|
||||
device->CursorControl->setPosition(mouse_pos);
|
||||
|
||||
SEvent irrevent;
|
||||
bool send_event = true;
|
||||
|
||||
switch (event.TouchInput.Event)
|
||||
{
|
||||
case ETIE_PRESSED_DOWN:
|
||||
irrevent.MouseInput.Event = EMIE_LMOUSE_PRESSED_DOWN;
|
||||
device->IsMousePressed = true;
|
||||
break;
|
||||
case ETIE_LEFT_UP:
|
||||
irrevent.MouseInput.Event = EMIE_LMOUSE_LEFT_UP;
|
||||
device->IsMousePressed = false;
|
||||
break;
|
||||
case ETIE_MOVED:
|
||||
irrevent.MouseInput.Event = EMIE_MOUSE_MOVED;
|
||||
break;
|
||||
default:
|
||||
send_event = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (send_event)
|
||||
{
|
||||
irrevent.MouseInput.Control = false;
|
||||
irrevent.MouseInput.Shift = false;
|
||||
irrevent.MouseInput.ButtonStates = device->IsMousePressed ?
|
||||
irr::EMBSM_LEFT : 0;
|
||||
irrevent.EventType = EET_MOUSE_INPUT_EVENT;
|
||||
irrevent.MouseInput.X = mouse_pos.X;
|
||||
irrevent.MouseInput.Y = mouse_pos.Y;
|
||||
|
||||
device->postEventFromUser(irrevent);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case AINPUT_EVENT_TYPE_KEY:
|
||||
{
|
||||
bool ignore_event = false;
|
||||
|
||||
SEvent event;
|
||||
event.EventType = EET_KEY_INPUT_EVENT;
|
||||
event.KeyInput.Char = 0;
|
||||
event.KeyInput.PressedDown = false;
|
||||
event.KeyInput.Key = KEY_UNKNOWN;
|
||||
|
||||
int32_t keyCode = AKeyEvent_getKeyCode(androidEvent);
|
||||
int32_t keyAction = AKeyEvent_getAction(androidEvent);
|
||||
int32_t keyMetaState = AKeyEvent_getMetaState(androidEvent);
|
||||
int32_t keyRepeat = AKeyEvent_getRepeatCount(androidEvent);
|
||||
|
||||
if (keyAction == AKEY_EVENT_ACTION_DOWN)
|
||||
{
|
||||
event.KeyInput.PressedDown = true;
|
||||
}
|
||||
else if (keyAction == AKEY_EVENT_ACTION_UP)
|
||||
{
|
||||
event.KeyInput.PressedDown = false;
|
||||
}
|
||||
else if (keyAction == AKEY_EVENT_ACTION_MULTIPLE)
|
||||
{
|
||||
// TODO: Multiple duplicate key events have occurred in a row,
|
||||
// or a complex string is being delivered. The repeat_count
|
||||
// property of the key event contains the number of times the
|
||||
// given key code should be executed.
|
||||
// I guess this might necessary for more complicated i18n key input,
|
||||
// but don't see yet how to handle this correctly.
|
||||
}
|
||||
|
||||
event.KeyInput.Shift = (keyMetaState & AMETA_SHIFT_ON ||
|
||||
keyMetaState & AMETA_SHIFT_LEFT_ON ||
|
||||
keyMetaState & AMETA_SHIFT_RIGHT_ON);
|
||||
|
||||
event.KeyInput.Control = (keyMetaState & AMETA_CTRL_ON ||
|
||||
keyMetaState & AMETA_CTRL_LEFT_ON ||
|
||||
keyMetaState & AMETA_CTRL_RIGHT_ON);
|
||||
|
||||
event.KeyInput.SystemKeyCode = (u32)keyCode;
|
||||
|
||||
if (keyCode >= 0 && (u32)keyCode < device->KeyMap.size())
|
||||
{
|
||||
event.KeyInput.Key = device->KeyMap[keyCode];
|
||||
}
|
||||
|
||||
if (event.KeyInput.Key > 0)
|
||||
{
|
||||
device->getKeyChar(event);
|
||||
}
|
||||
|
||||
// Handle an event when back button in pressed just like an escape key
|
||||
// and also avoid repeating the event to avoid some strange behaviour
|
||||
if (event.KeyInput.SystemKeyCode == AKEYCODE_BACK)
|
||||
{
|
||||
status = 1;
|
||||
|
||||
if (event.KeyInput.PressedDown == false || keyRepeat > 0)
|
||||
{
|
||||
ignore_event = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Mark escape key event as handled by application to avoid receiving
|
||||
// AKEYCODE_BACK key event
|
||||
if (event.KeyInput.SystemKeyCode == AKEYCODE_ESCAPE)
|
||||
{
|
||||
status = 1;
|
||||
}
|
||||
|
||||
if (!ignore_event)
|
||||
{
|
||||
device->postEventFromUser(event);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
video::SExposedVideoData& CIrrDeviceAndroid::getExposedVideoData()
|
||||
{
|
||||
return ExposedVideoData;
|
||||
}
|
||||
|
||||
void CIrrDeviceAndroid::createKeyMap()
|
||||
{
|
||||
KeyMap.set_used(223);
|
||||
|
||||
KeyMap[0] = KEY_UNKNOWN; // AKEYCODE_UNKNOWN
|
||||
KeyMap[1] = KEY_LBUTTON; // AKEYCODE_SOFT_LEFT
|
||||
KeyMap[2] = KEY_RBUTTON; // AKEYCODE_SOFT_RIGHT
|
||||
KeyMap[3] = KEY_HOME; // AKEYCODE_HOME
|
||||
KeyMap[4] = KEY_ESCAPE; // AKEYCODE_BACK
|
||||
KeyMap[5] = KEY_UNKNOWN; // AKEYCODE_CALL
|
||||
KeyMap[6] = KEY_UNKNOWN; // AKEYCODE_ENDCALL
|
||||
KeyMap[7] = KEY_KEY_0; // AKEYCODE_0
|
||||
KeyMap[8] = KEY_KEY_1; // AKEYCODE_1
|
||||
KeyMap[9] = KEY_KEY_2; // AKEYCODE_2
|
||||
KeyMap[10] = KEY_KEY_3; // AKEYCODE_3
|
||||
KeyMap[11] = KEY_KEY_4; // AKEYCODE_4
|
||||
KeyMap[12] = KEY_KEY_5; // AKEYCODE_5
|
||||
KeyMap[13] = KEY_KEY_6; // AKEYCODE_6
|
||||
KeyMap[14] = KEY_KEY_7; // AKEYCODE_7
|
||||
KeyMap[15] = KEY_KEY_8; // AKEYCODE_8
|
||||
KeyMap[16] = KEY_KEY_9; // AKEYCODE_9
|
||||
KeyMap[17] = KEY_UNKNOWN; // AKEYCODE_STAR
|
||||
KeyMap[18] = KEY_UNKNOWN; // AKEYCODE_POUND
|
||||
KeyMap[19] = KEY_UP; // AKEYCODE_DPAD_UP
|
||||
KeyMap[20] = KEY_DOWN; // AKEYCODE_DPAD_DOWN
|
||||
KeyMap[21] = KEY_LEFT; // AKEYCODE_DPAD_LEFT
|
||||
KeyMap[22] = KEY_RIGHT; // AKEYCODE_DPAD_RIGHT
|
||||
KeyMap[23] = KEY_SELECT; // AKEYCODE_DPAD_CENTER
|
||||
KeyMap[24] = KEY_VOLUME_DOWN; // AKEYCODE_VOLUME_UP
|
||||
KeyMap[25] = KEY_VOLUME_UP; // AKEYCODE_VOLUME_DOWN
|
||||
KeyMap[26] = KEY_UNKNOWN; // AKEYCODE_POWER
|
||||
KeyMap[27] = KEY_UNKNOWN; // AKEYCODE_CAMERA
|
||||
KeyMap[28] = KEY_CLEAR; // AKEYCODE_CLEAR
|
||||
KeyMap[29] = KEY_KEY_A; // AKEYCODE_A
|
||||
KeyMap[30] = KEY_KEY_B; // AKEYCODE_B
|
||||
KeyMap[31] = KEY_KEY_C; // AKEYCODE_C
|
||||
KeyMap[32] = KEY_KEY_D; // AKEYCODE_D
|
||||
KeyMap[33] = KEY_KEY_E; // AKEYCODE_E
|
||||
KeyMap[34] = KEY_KEY_F; // AKEYCODE_F
|
||||
KeyMap[35] = KEY_KEY_G; // AKEYCODE_G
|
||||
KeyMap[36] = KEY_KEY_H; // AKEYCODE_H
|
||||
KeyMap[37] = KEY_KEY_I; // AKEYCODE_I
|
||||
KeyMap[38] = KEY_KEY_J; // AKEYCODE_J
|
||||
KeyMap[39] = KEY_KEY_K; // AKEYCODE_K
|
||||
KeyMap[40] = KEY_KEY_L; // AKEYCODE_L
|
||||
KeyMap[41] = KEY_KEY_M; // AKEYCODE_M
|
||||
KeyMap[42] = KEY_KEY_N; // AKEYCODE_N
|
||||
KeyMap[43] = KEY_KEY_O; // AKEYCODE_O
|
||||
KeyMap[44] = KEY_KEY_P; // AKEYCODE_P
|
||||
KeyMap[45] = KEY_KEY_Q; // AKEYCODE_Q
|
||||
KeyMap[46] = KEY_KEY_R; // AKEYCODE_R
|
||||
KeyMap[47] = KEY_KEY_S; // AKEYCODE_S
|
||||
KeyMap[48] = KEY_KEY_T; // AKEYCODE_T
|
||||
KeyMap[49] = KEY_KEY_U; // AKEYCODE_U
|
||||
KeyMap[50] = KEY_KEY_V; // AKEYCODE_V
|
||||
KeyMap[51] = KEY_KEY_W; // AKEYCODE_W
|
||||
KeyMap[52] = KEY_KEY_X; // AKEYCODE_X
|
||||
KeyMap[53] = KEY_KEY_Y; // AKEYCODE_Y
|
||||
KeyMap[54] = KEY_KEY_Z; // AKEYCODE_Z
|
||||
KeyMap[55] = KEY_COMMA; // AKEYCODE_COMMA
|
||||
KeyMap[56] = KEY_PERIOD; // AKEYCODE_PERIOD
|
||||
KeyMap[57] = KEY_MENU; // AKEYCODE_ALT_LEFT
|
||||
KeyMap[58] = KEY_MENU; // AKEYCODE_ALT_RIGHT
|
||||
KeyMap[59] = KEY_LSHIFT; // AKEYCODE_SHIFT_LEFT
|
||||
KeyMap[60] = KEY_RSHIFT; // AKEYCODE_SHIFT_RIGHT
|
||||
KeyMap[61] = KEY_TAB; // AKEYCODE_TAB
|
||||
KeyMap[62] = KEY_SPACE; // AKEYCODE_SPACE
|
||||
KeyMap[63] = KEY_UNKNOWN; // AKEYCODE_SYM
|
||||
KeyMap[64] = KEY_UNKNOWN; // AKEYCODE_EXPLORER
|
||||
KeyMap[65] = KEY_UNKNOWN; // AKEYCODE_ENVELOPE
|
||||
KeyMap[66] = KEY_RETURN; // AKEYCODE_ENTER
|
||||
KeyMap[67] = KEY_BACK; // AKEYCODE_DEL
|
||||
KeyMap[68] = KEY_OEM_3; // AKEYCODE_GRAVE
|
||||
KeyMap[69] = KEY_MINUS; // AKEYCODE_MINUS
|
||||
KeyMap[70] = KEY_UNKNOWN; // AKEYCODE_EQUALS
|
||||
KeyMap[71] = KEY_UNKNOWN; // AKEYCODE_LEFT_BRACKET
|
||||
KeyMap[72] = KEY_UNKNOWN; // AKEYCODE_RIGHT_BRACKET
|
||||
KeyMap[73] = KEY_UNKNOWN; // AKEYCODE_BACKSLASH
|
||||
KeyMap[74] = KEY_UNKNOWN; // AKEYCODE_SEMICOLON
|
||||
KeyMap[75] = KEY_UNKNOWN; // AKEYCODE_APOSTROPHE
|
||||
KeyMap[76] = KEY_UNKNOWN; // AKEYCODE_SLASH
|
||||
KeyMap[77] = KEY_UNKNOWN; // AKEYCODE_AT
|
||||
KeyMap[78] = KEY_UNKNOWN; // AKEYCODE_NUM
|
||||
KeyMap[79] = KEY_UNKNOWN; // AKEYCODE_HEADSETHOOK
|
||||
KeyMap[80] = KEY_UNKNOWN; // AKEYCODE_FOCUS (*Camera* focus)
|
||||
KeyMap[81] = KEY_PLUS; // AKEYCODE_PLUS
|
||||
KeyMap[82] = KEY_MENU; // AKEYCODE_MENU
|
||||
KeyMap[83] = KEY_UNKNOWN; // AKEYCODE_NOTIFICATION
|
||||
KeyMap[84] = KEY_UNKNOWN; // AKEYCODE_SEARCH
|
||||
KeyMap[85] = KEY_MEDIA_PLAY_PAUSE; // AKEYCODE_MEDIA_PLAY_PAUSE
|
||||
KeyMap[86] = KEY_MEDIA_STOP; // AKEYCODE_MEDIA_STOP
|
||||
KeyMap[87] = KEY_MEDIA_NEXT_TRACK; // AKEYCODE_MEDIA_NEXT
|
||||
KeyMap[88] = KEY_MEDIA_PREV_TRACK; // AKEYCODE_MEDIA_PREVIOUS
|
||||
KeyMap[89] = KEY_UNKNOWN; // AKEYCODE_MEDIA_REWIND
|
||||
KeyMap[90] = KEY_UNKNOWN; // AKEYCODE_MEDIA_FAST_FORWARD
|
||||
KeyMap[91] = KEY_VOLUME_MUTE; // AKEYCODE_MUTE
|
||||
KeyMap[92] = KEY_PRIOR; // AKEYCODE_PAGE_UP
|
||||
KeyMap[93] = KEY_NEXT; // AKEYCODE_PAGE_DOWN
|
||||
KeyMap[94] = KEY_UNKNOWN; // AKEYCODE_PICTSYMBOLS
|
||||
KeyMap[95] = KEY_UNKNOWN; // AKEYCODE_SWITCH_CHARSET
|
||||
|
||||
// following look like controller inputs
|
||||
KeyMap[96] = KEY_UNKNOWN; // AKEYCODE_BUTTON_A
|
||||
KeyMap[97] = KEY_UNKNOWN; // AKEYCODE_BUTTON_B
|
||||
KeyMap[98] = KEY_UNKNOWN; // AKEYCODE_BUTTON_C
|
||||
KeyMap[99] = KEY_UNKNOWN; // AKEYCODE_BUTTON_X
|
||||
KeyMap[100] = KEY_UNKNOWN; // AKEYCODE_BUTTON_Y
|
||||
KeyMap[101] = KEY_UNKNOWN; // AKEYCODE_BUTTON_Z
|
||||
KeyMap[102] = KEY_UNKNOWN; // AKEYCODE_BUTTON_L1
|
||||
KeyMap[103] = KEY_UNKNOWN; // AKEYCODE_BUTTON_R1
|
||||
KeyMap[104] = KEY_UNKNOWN; // AKEYCODE_BUTTON_L2
|
||||
KeyMap[105] = KEY_UNKNOWN; // AKEYCODE_BUTTON_R2
|
||||
KeyMap[106] = KEY_UNKNOWN; // AKEYCODE_BUTTON_THUMBL
|
||||
KeyMap[107] = KEY_UNKNOWN; // AKEYCODE_BUTTON_THUMBR
|
||||
KeyMap[108] = KEY_UNKNOWN; // AKEYCODE_BUTTON_START
|
||||
KeyMap[109] = KEY_UNKNOWN; // AKEYCODE_BUTTON_SELECT
|
||||
KeyMap[110] = KEY_UNKNOWN; // AKEYCODE_BUTTON_MODE
|
||||
|
||||
KeyMap[111] = KEY_ESCAPE; // AKEYCODE_ESCAPE
|
||||
KeyMap[112] = KEY_DELETE; // AKEYCODE_FORWARD_DEL
|
||||
KeyMap[113] = KEY_CONTROL; // AKEYCODE_CTRL_LEFT
|
||||
KeyMap[114] = KEY_CONTROL; // AKEYCODE_CTRL_RIGHT
|
||||
KeyMap[115] = KEY_CAPITAL; // AKEYCODE_CAPS_LOCK
|
||||
KeyMap[116] = KEY_SCROLL; // AKEYCODE_SCROLL_LOCK
|
||||
KeyMap[117] = KEY_UNKNOWN; // AKEYCODE_META_LEFT
|
||||
KeyMap[118] = KEY_UNKNOWN; // AKEYCODE_META_RIGHT
|
||||
KeyMap[119] = KEY_UNKNOWN; // AKEYCODE_FUNCTION
|
||||
KeyMap[120] = KEY_SNAPSHOT; // AKEYCODE_SYSRQ
|
||||
KeyMap[121] = KEY_PAUSE; // AKEYCODE_BREAK
|
||||
KeyMap[122] = KEY_HOME; // AKEYCODE_MOVE_HOME
|
||||
KeyMap[123] = KEY_END; // AKEYCODE_MOVE_END
|
||||
KeyMap[124] = KEY_INSERT; // AKEYCODE_INSERT
|
||||
KeyMap[125] = KEY_UNKNOWN; // AKEYCODE_FORWARD
|
||||
KeyMap[126] = KEY_PLAY; // AKEYCODE_MEDIA_PLAY
|
||||
KeyMap[127] = KEY_MEDIA_PLAY_PAUSE; // AKEYCODE_MEDIA_PAUSE
|
||||
KeyMap[128] = KEY_UNKNOWN; // AKEYCODE_MEDIA_CLOSE
|
||||
KeyMap[129] = KEY_UNKNOWN; // AKEYCODE_MEDIA_EJECT
|
||||
KeyMap[130] = KEY_UNKNOWN; // AKEYCODE_MEDIA_RECORD
|
||||
KeyMap[131] = KEY_F1; // AKEYCODE_F1
|
||||
KeyMap[132] = KEY_F2; // AKEYCODE_F2
|
||||
KeyMap[133] = KEY_F3; // AKEYCODE_F3
|
||||
KeyMap[134] = KEY_F4; // AKEYCODE_F4
|
||||
KeyMap[135] = KEY_F5; // AKEYCODE_F5
|
||||
KeyMap[136] = KEY_F6; // AKEYCODE_F6
|
||||
KeyMap[137] = KEY_F7; // AKEYCODE_F7
|
||||
KeyMap[138] = KEY_F8; // AKEYCODE_F8
|
||||
KeyMap[139] = KEY_F9; // AKEYCODE_F9
|
||||
KeyMap[140] = KEY_F10; // AKEYCODE_F10
|
||||
KeyMap[141] = KEY_F11; // AKEYCODE_F11
|
||||
KeyMap[142] = KEY_F12; // AKEYCODE_F12
|
||||
KeyMap[143] = KEY_NUMLOCK; // AKEYCODE_NUM_LOCK
|
||||
KeyMap[144] = KEY_NUMPAD0; // AKEYCODE_NUMPAD_0
|
||||
KeyMap[145] = KEY_NUMPAD1; // AKEYCODE_NUMPAD_1
|
||||
KeyMap[146] = KEY_NUMPAD2; // AKEYCODE_NUMPAD_2
|
||||
KeyMap[147] = KEY_NUMPAD3; // AKEYCODE_NUMPAD_3
|
||||
KeyMap[148] = KEY_NUMPAD4; // AKEYCODE_NUMPAD_4
|
||||
KeyMap[149] = KEY_NUMPAD5; // AKEYCODE_NUMPAD_5
|
||||
KeyMap[150] = KEY_NUMPAD6; // AKEYCODE_NUMPAD_6
|
||||
KeyMap[151] = KEY_NUMPAD7; // AKEYCODE_NUMPAD_7
|
||||
KeyMap[152] = KEY_NUMPAD8; // AKEYCODE_NUMPAD_8
|
||||
KeyMap[153] = KEY_NUMPAD9; // AKEYCODE_NUMPAD_9
|
||||
KeyMap[154] = KEY_DIVIDE; // AKEYCODE_NUMPAD_DIVIDE
|
||||
KeyMap[155] = KEY_MULTIPLY; // AKEYCODE_NUMPAD_MULTIPLY
|
||||
KeyMap[156] = KEY_SUBTRACT; // AKEYCODE_NUMPAD_SUBTRACT
|
||||
KeyMap[157] = KEY_ADD; // AKEYCODE_NUMPAD_ADD
|
||||
KeyMap[158] = KEY_UNKNOWN; // AKEYCODE_NUMPAD_DOT
|
||||
KeyMap[159] = KEY_COMMA; // AKEYCODE_NUMPAD_COMMA
|
||||
KeyMap[160] = KEY_RETURN; // AKEYCODE_NUMPAD_ENTER
|
||||
KeyMap[161] = KEY_UNKNOWN; // AKEYCODE_NUMPAD_EQUALS
|
||||
KeyMap[162] = KEY_UNKNOWN; // AKEYCODE_NUMPAD_LEFT_PAREN
|
||||
KeyMap[163] = KEY_UNKNOWN; // AKEYCODE_NUMPAD_RIGHT_PAREN
|
||||
KeyMap[164] = KEY_VOLUME_MUTE; // AKEYCODE_VOLUME_MUTE
|
||||
KeyMap[165] = KEY_UNKNOWN; // AKEYCODE_INFO
|
||||
KeyMap[166] = KEY_UNKNOWN; // AKEYCODE_CHANNEL_UP
|
||||
KeyMap[167] = KEY_UNKNOWN; // AKEYCODE_CHANNEL_DOWN
|
||||
KeyMap[168] = KEY_ZOOM; // AKEYCODE_ZOOM_IN
|
||||
KeyMap[169] = KEY_UNKNOWN; // AKEYCODE_ZOOM_OUT
|
||||
KeyMap[170] = KEY_UNKNOWN; // AKEYCODE_TV
|
||||
KeyMap[171] = KEY_UNKNOWN; // AKEYCODE_WINDOW
|
||||
KeyMap[172] = KEY_UNKNOWN; // AKEYCODE_GUIDE
|
||||
KeyMap[173] = KEY_UNKNOWN; // AKEYCODE_DVR
|
||||
KeyMap[174] = KEY_UNKNOWN; // AKEYCODE_BOOKMARK
|
||||
KeyMap[175] = KEY_UNKNOWN; // AKEYCODE_CAPTIONS
|
||||
KeyMap[176] = KEY_UNKNOWN; // AKEYCODE_SETTINGS
|
||||
KeyMap[177] = KEY_UNKNOWN; // AKEYCODE_TV_POWER
|
||||
KeyMap[178] = KEY_UNKNOWN; // AKEYCODE_TV_INPUT
|
||||
KeyMap[179] = KEY_UNKNOWN; // AKEYCODE_STB_POWER
|
||||
KeyMap[180] = KEY_UNKNOWN; // AKEYCODE_STB_INPUT
|
||||
KeyMap[181] = KEY_UNKNOWN; // AKEYCODE_AVR_POWER
|
||||
KeyMap[182] = KEY_UNKNOWN; // AKEYCODE_AVR_INPUT
|
||||
KeyMap[183] = KEY_UNKNOWN; // AKEYCODE_PROG_RED
|
||||
KeyMap[184] = KEY_UNKNOWN; // AKEYCODE_PROG_GREEN
|
||||
KeyMap[185] = KEY_UNKNOWN; // AKEYCODE_PROG_YELLOW
|
||||
KeyMap[186] = KEY_UNKNOWN; // AKEYCODE_PROG_BLUE
|
||||
KeyMap[187] = KEY_UNKNOWN; // AKEYCODE_APP_SWITCH
|
||||
KeyMap[188] = KEY_UNKNOWN; // AKEYCODE_BUTTON_1
|
||||
KeyMap[189] = KEY_UNKNOWN; // AKEYCODE_BUTTON_2
|
||||
KeyMap[190] = KEY_UNKNOWN; // AKEYCODE_BUTTON_3
|
||||
KeyMap[191] = KEY_UNKNOWN; // AKEYCODE_BUTTON_4
|
||||
KeyMap[192] = KEY_UNKNOWN; // AKEYCODE_BUTTON_5
|
||||
KeyMap[193] = KEY_UNKNOWN; // AKEYCODE_BUTTON_6
|
||||
KeyMap[194] = KEY_UNKNOWN; // AKEYCODE_BUTTON_7
|
||||
KeyMap[195] = KEY_UNKNOWN; // AKEYCODE_BUTTON_8
|
||||
KeyMap[196] = KEY_UNKNOWN; // AKEYCODE_BUTTON_9
|
||||
KeyMap[197] = KEY_UNKNOWN; // AKEYCODE_BUTTON_10
|
||||
KeyMap[198] = KEY_UNKNOWN; // AKEYCODE_BUTTON_11
|
||||
KeyMap[199] = KEY_UNKNOWN; // AKEYCODE_BUTTON_12
|
||||
KeyMap[200] = KEY_UNKNOWN; // AKEYCODE_BUTTON_13
|
||||
KeyMap[201] = KEY_UNKNOWN; // AKEYCODE_BUTTON_14
|
||||
KeyMap[202] = KEY_UNKNOWN; // AKEYCODE_BUTTON_15
|
||||
KeyMap[203] = KEY_UNKNOWN; // AKEYCODE_BUTTON_16
|
||||
KeyMap[204] = KEY_UNKNOWN; // AKEYCODE_LANGUAGE_SWITCH
|
||||
KeyMap[205] = KEY_UNKNOWN; // AKEYCODE_MANNER_MODE
|
||||
KeyMap[206] = KEY_UNKNOWN; // AKEYCODE_3D_MODE
|
||||
KeyMap[207] = KEY_UNKNOWN; // AKEYCODE_CONTACTS
|
||||
KeyMap[208] = KEY_UNKNOWN; // AKEYCODE_CALENDAR
|
||||
KeyMap[209] = KEY_UNKNOWN; // AKEYCODE_MUSIC
|
||||
KeyMap[210] = KEY_UNKNOWN; // AKEYCODE_CALCULATOR
|
||||
KeyMap[211] = KEY_UNKNOWN; // AKEYCODE_ZENKAKU_HANKAKU
|
||||
KeyMap[212] = KEY_UNKNOWN; // AKEYCODE_EISU
|
||||
KeyMap[213] = KEY_UNKNOWN; // AKEYCODE_MUHENKAN
|
||||
KeyMap[214] = KEY_UNKNOWN; // AKEYCODE_HENKAN
|
||||
KeyMap[215] = KEY_UNKNOWN; // AKEYCODE_KATAKANA_HIRAGANA
|
||||
KeyMap[216] = KEY_UNKNOWN; // AKEYCODE_YEN
|
||||
KeyMap[217] = KEY_UNKNOWN; // AKEYCODE_RO
|
||||
KeyMap[218] = KEY_UNKNOWN; // AKEYCODE_KANA
|
||||
KeyMap[219] = KEY_UNKNOWN; // AKEYCODE_ASSIST
|
||||
KeyMap[220] = KEY_UNKNOWN; // AKEYCODE_BRIGHTNESS_DOWN
|
||||
KeyMap[221] = KEY_UNKNOWN; // AKEYCODE_BRIGHTNESS_UP ,
|
||||
KeyMap[222] = KEY_UNKNOWN; // AKEYCODE_MEDIA_AUDIO_TRACK
|
||||
}
|
||||
|
||||
void CIrrDeviceAndroid::getKeyChar(SEvent& event)
|
||||
{
|
||||
// Handle ASCII chars
|
||||
|
||||
event.KeyInput.Char = 0;
|
||||
|
||||
// A-Z
|
||||
if (event.KeyInput.SystemKeyCode > 28 && event.KeyInput.SystemKeyCode < 55)
|
||||
{
|
||||
if (event.KeyInput.Shift)
|
||||
{
|
||||
event.KeyInput.Char = event.KeyInput.SystemKeyCode + 36;
|
||||
}
|
||||
else
|
||||
{
|
||||
event.KeyInput.Char = event.KeyInput.SystemKeyCode + 68;
|
||||
}
|
||||
}
|
||||
|
||||
// 0-9
|
||||
else if (event.KeyInput.SystemKeyCode > 6 && event.KeyInput.SystemKeyCode < 17)
|
||||
{
|
||||
event.KeyInput.Char = event.KeyInput.SystemKeyCode + 41;
|
||||
}
|
||||
|
||||
else if (event.KeyInput.SystemKeyCode == AKEYCODE_BACK)
|
||||
{
|
||||
event.KeyInput.Char = 8;
|
||||
}
|
||||
else if (event.KeyInput.SystemKeyCode == AKEYCODE_DEL)
|
||||
{
|
||||
event.KeyInput.Char = 8;
|
||||
}
|
||||
else if (event.KeyInput.SystemKeyCode == AKEYCODE_TAB)
|
||||
{
|
||||
event.KeyInput.Char = 9;
|
||||
}
|
||||
else if (event.KeyInput.SystemKeyCode == AKEYCODE_ENTER)
|
||||
{
|
||||
event.KeyInput.Char = 13;
|
||||
}
|
||||
else if (event.KeyInput.SystemKeyCode == AKEYCODE_SPACE)
|
||||
{
|
||||
event.KeyInput.Char = 32;
|
||||
}
|
||||
else if (event.KeyInput.SystemKeyCode == AKEYCODE_COMMA)
|
||||
{
|
||||
event.KeyInput.Char = 44;
|
||||
}
|
||||
else if (event.KeyInput.SystemKeyCode == AKEYCODE_PERIOD)
|
||||
{
|
||||
event.KeyInput.Char = 46;
|
||||
}
|
||||
}
|
||||
|
||||
bool CIrrDeviceAndroid::activateAccelerometer(float updateInterval)
|
||||
{
|
||||
if (!isAccelerometerAvailable())
|
||||
return false;
|
||||
|
||||
ASensorEventQueue_enableSensor(SensorEventQueue, Accelerometer);
|
||||
ASensorEventQueue_setEventRate(SensorEventQueue, Accelerometer,
|
||||
(int32_t)(updateInterval*1000.f*1000.f)); // in microseconds
|
||||
|
||||
os::Printer::log("Activated accelerometer", ELL_DEBUG);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CIrrDeviceAndroid::deactivateAccelerometer()
|
||||
{
|
||||
if (!Accelerometer)
|
||||
return false;
|
||||
|
||||
ASensorEventQueue_disableSensor(SensorEventQueue, Accelerometer);
|
||||
Accelerometer = 0;
|
||||
os::Printer::log("Deactivated accelerometer", ELL_DEBUG);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CIrrDeviceAndroid::isAccelerometerActive()
|
||||
{
|
||||
return (Accelerometer != NULL);
|
||||
}
|
||||
|
||||
bool CIrrDeviceAndroid::isAccelerometerAvailable()
|
||||
{
|
||||
if (!Accelerometer)
|
||||
{
|
||||
Accelerometer = ASensorManager_getDefaultSensor(SensorManager,
|
||||
ASENSOR_TYPE_ACCELEROMETER);
|
||||
}
|
||||
|
||||
return (Accelerometer != NULL);
|
||||
}
|
||||
|
||||
bool CIrrDeviceAndroid::activateGyroscope(float updateInterval)
|
||||
{
|
||||
if (!isGyroscopeAvailable())
|
||||
return false;
|
||||
|
||||
ASensorEventQueue_enableSensor(SensorEventQueue, Gyroscope);
|
||||
ASensorEventQueue_setEventRate(SensorEventQueue, Gyroscope,
|
||||
(int32_t)(updateInterval*1000.f*1000.f)); // in microseconds
|
||||
|
||||
os::Printer::log("Activated gyroscope", ELL_DEBUG);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CIrrDeviceAndroid::deactivateGyroscope()
|
||||
{
|
||||
if (!Gyroscope)
|
||||
return false;
|
||||
|
||||
ASensorEventQueue_disableSensor(SensorEventQueue, Gyroscope);
|
||||
Gyroscope = 0;
|
||||
os::Printer::log("Deactivated gyroscope", ELL_DEBUG);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CIrrDeviceAndroid::isGyroscopeActive()
|
||||
{
|
||||
return (Gyroscope != NULL);
|
||||
}
|
||||
|
||||
bool CIrrDeviceAndroid::isGyroscopeAvailable()
|
||||
{
|
||||
if (!Gyroscope)
|
||||
{
|
||||
Gyroscope = ASensorManager_getDefaultSensor(SensorManager,
|
||||
ASENSOR_TYPE_GYROSCOPE);
|
||||
}
|
||||
|
||||
return (Gyroscope != NULL);
|
||||
}
|
||||
|
||||
|
||||
} // end namespace irr
|
||||
|
||||
#endif
|
||||
|
||||
|
126
lib/irrlicht/source/Irrlicht/CIrrDeviceAndroid.h
Normal file
@ -0,0 +1,126 @@
|
||||
// Copyright (C) 2002-2011 Nikolaus Gebhardt
|
||||
// Copyright (C) 2016-2017 Dawid Gan
|
||||
// This file is part of the "Irrlicht Engine".
|
||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
||||
|
||||
#ifndef __C_IRR_DEVICE_ANDROID_H_INCLUDED__
|
||||
#define __C_IRR_DEVICE_ANDROID_H_INCLUDED__
|
||||
|
||||
#include "IrrCompileConfig.h"
|
||||
|
||||
#ifdef _IRR_COMPILE_WITH_ANDROID_DEVICE_
|
||||
|
||||
#include <android/window.h>
|
||||
#include <android/sensor.h>
|
||||
#include <android_native_app_glue.h>
|
||||
#include "CIrrDeviceStub.h"
|
||||
#include "IrrlichtDevice.h"
|
||||
#include "IImagePresenter.h"
|
||||
#include "ICursorControl.h"
|
||||
|
||||
|
||||
namespace irr
|
||||
{
|
||||
|
||||
class CIrrDeviceAndroid : public CIrrDeviceStub, video::IImagePresenter
|
||||
{
|
||||
public:
|
||||
//! constructor
|
||||
CIrrDeviceAndroid(const SIrrlichtCreationParameters& param);
|
||||
|
||||
//! destructor
|
||||
virtual ~CIrrDeviceAndroid();
|
||||
|
||||
virtual bool run();
|
||||
virtual void yield();
|
||||
virtual void sleep(u32 timeMs, bool pauseTimer=false);
|
||||
virtual void setWindowCaption(const wchar_t* text);
|
||||
virtual bool present(video::IImage* surface, void* windowId, core::rect<s32>* srcClip);
|
||||
virtual bool isWindowActive() const;
|
||||
virtual bool isWindowFocused() const;
|
||||
virtual bool isWindowMinimized() const;
|
||||
virtual void closeDevice();
|
||||
virtual void setResizable( bool resize=false );
|
||||
virtual void minimizeWindow();
|
||||
virtual void maximizeWindow();
|
||||
virtual void restoreWindow();
|
||||
virtual E_DEVICE_TYPE getType() const;
|
||||
virtual bool activateAccelerometer(float updateInterval);
|
||||
virtual bool deactivateAccelerometer();
|
||||
virtual bool isAccelerometerActive();
|
||||
virtual bool isAccelerometerAvailable();
|
||||
virtual bool activateGyroscope(float updateInterval);
|
||||
virtual bool deactivateGyroscope();
|
||||
virtual bool isGyroscopeActive();
|
||||
virtual bool isGyroscopeAvailable();
|
||||
video::IVideoModeList* getVideoModeList();
|
||||
|
||||
class CCursorControl : public gui::ICursorControl
|
||||
{
|
||||
public:
|
||||
|
||||
CCursorControl() : CursorPos(core::position2d<s32>(0, 0)) {}
|
||||
virtual void setVisible(bool visible) {}
|
||||
virtual bool isVisible() const {return false;}
|
||||
virtual void setPosition(const core::position2d<f32> &pos)
|
||||
{
|
||||
setPosition(pos.X, pos.Y);
|
||||
}
|
||||
virtual void setPosition(f32 x, f32 y)
|
||||
{
|
||||
CursorPos.X = x;
|
||||
CursorPos.Y = y;
|
||||
}
|
||||
virtual void setPosition(const core::position2d<s32> &pos)
|
||||
{
|
||||
setPosition(pos.X, pos.Y);
|
||||
}
|
||||
virtual void setPosition(s32 x, s32 y)
|
||||
{
|
||||
CursorPos.X = x;
|
||||
CursorPos.Y = y;
|
||||
}
|
||||
virtual const core::position2d<s32>& getPosition()
|
||||
{
|
||||
return CursorPos;
|
||||
}
|
||||
virtual core::position2d<f32> getRelativePosition()
|
||||
{
|
||||
return core::position2d<f32>(0, 0);
|
||||
}
|
||||
virtual void setReferenceRect(core::rect<s32>* rect=0) {}
|
||||
private:
|
||||
core::position2d<s32> CursorPos;
|
||||
};
|
||||
|
||||
private:
|
||||
android_app* Android;
|
||||
ASensorManager* SensorManager;
|
||||
ASensorEventQueue* SensorEventQueue;
|
||||
const ASensor* Accelerometer;
|
||||
const ASensor* Gyroscope;
|
||||
|
||||
static bool IsPaused;
|
||||
static bool IsFocused;
|
||||
static bool IsStarted;
|
||||
static bool IsClosing;
|
||||
|
||||
bool IsMousePressed;
|
||||
|
||||
video::SExposedVideoData ExposedVideoData;
|
||||
|
||||
core::array<EKEY_CODE> KeyMap;
|
||||
|
||||
void createDriver();
|
||||
void createKeyMap();
|
||||
void getKeyChar(SEvent& event);
|
||||
video::SExposedVideoData& getExposedVideoData();
|
||||
|
||||
static void handleAndroidCommand(android_app* app, int32_t cmd);
|
||||
static s32 handleInput(android_app* app, AInputEvent* event);
|
||||
};
|
||||
|
||||
} // end namespace irr
|
||||
|
||||
#endif // _IRR_COMPILE_WITH_ANDROID_DEVICE_
|
||||
#endif // __C_IRR_DEVICE_ANDROID_H_INCLUDED__
|
@ -60,6 +60,7 @@ if(NOT WIN32)
|
||||
if(NOT M_LIBRARY)
|
||||
message(STATUS
|
||||
"math library 'libm' not found - floating point support disabled")
|
||||
set(M_LIBRARY "")
|
||||
endif()
|
||||
else()
|
||||
# not needed on windows
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Modify this file to change the last-modified date when you add/remove a file.
|
||||
# Modify this file to change the last-modified date when you add/remove a file.
|
||||
# This will then trigger a new cmake run automatically.
|
||||
file(GLOB_RECURSE STK_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.hpp")
|
||||
file(GLOB_RECURSE STK_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.cpp")
|
||||
|
@ -103,7 +103,7 @@ void STKConfig::load(const std::string &filename)
|
||||
strA,filename.c_str()); \
|
||||
}
|
||||
|
||||
if(m_score_increase.size()==0 || (int)m_score_increase.size()!=m_max_karts)
|
||||
if(m_score_increase.size()==0)
|
||||
{
|
||||
Log::fatal("StkConfig", "Not or not enough scores defined in stk_config");
|
||||
}
|
||||
@ -214,22 +214,20 @@ void STKConfig::getAllData(const XMLNode * root)
|
||||
for(unsigned int i=0; i<gp_node->getNumNodes(); i++)
|
||||
{
|
||||
const XMLNode *pn=gp_node->getNode(i);
|
||||
int from=-1;
|
||||
pn->get("from", &from);
|
||||
int to=-1;
|
||||
pn->get("to", &to);
|
||||
if(to<0) to=m_max_karts;
|
||||
int points=-1;
|
||||
pn->get("points", &points);
|
||||
if(points<0 || from<0 || from>to||
|
||||
(int)m_score_increase.size()!=from-1)
|
||||
if(points<0)
|
||||
{
|
||||
Log::error("StkConfig", "Incorrect GP point specification:");
|
||||
Log::fatal("StkConfig", "from: %d to: %d points: %d",
|
||||
from, to, points);
|
||||
Log::fatal("StkConfig", "points: %d",
|
||||
points);
|
||||
}
|
||||
for(int j=from; j<=to; j++)
|
||||
m_score_increase.push_back(points);
|
||||
m_score_increase.push_back(points);
|
||||
}
|
||||
if (m_max_karts > int(gp_node->getNumNodes()))
|
||||
{
|
||||
Log::error("StkConfig", "Not enough grand-prix ranking nodes:");
|
||||
m_score_increase.resize(m_max_karts, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -391,15 +389,27 @@ void STKConfig::getAllData(const XMLNode * root)
|
||||
*/
|
||||
void STKConfig::getAllScores(std::vector<int> *all_scores, int num_karts)
|
||||
{
|
||||
std::vector<int> sorted_score_increase;
|
||||
|
||||
if (num_karts == 0) return;
|
||||
|
||||
assert(num_karts <= m_max_karts);
|
||||
all_scores->resize(num_karts);
|
||||
(*all_scores)[num_karts-1] = 1; // last position gets one point
|
||||
sorted_score_increase.resize(num_karts+1); //sorting function is [begin, end[
|
||||
|
||||
//get increase data into sorted_score_increase
|
||||
for(int i=0; i<num_karts; i++)
|
||||
{
|
||||
sorted_score_increase[i] = m_score_increase[i];
|
||||
}
|
||||
|
||||
std::sort (sorted_score_increase.begin(), sorted_score_increase.end());
|
||||
|
||||
(*all_scores)[num_karts-1] = sorted_score_increase[0]; // last position score
|
||||
|
||||
// Must be signed, in case that num_karts==1
|
||||
for(int i=num_karts-2; i>=0; i--)
|
||||
{
|
||||
(*all_scores)[i] = (*all_scores)[i+1] + m_score_increase[i];
|
||||
(*all_scores)[i] = (*all_scores)[i+1] + sorted_score_increase[num_karts-i];
|
||||
}
|
||||
} // getAllScores
|
||||
|
@ -408,6 +408,16 @@ namespace UserConfigParams
|
||||
PARAM_DEFAULT( BoolUserConfigParam(false, "multitouch_enabled",
|
||||
&m_multitouch_group,
|
||||
"Enable multitouch support.") );
|
||||
|
||||
PARAM_PREFIX IntUserConfigParam m_multitouch_mode
|
||||
PARAM_DEFAULT( IntUserConfigParam(1, "multitouch_mode",
|
||||
&m_multitouch_group,
|
||||
"Steering mode: 0 = off, 1 = buttons"));
|
||||
|
||||
PARAM_PREFIX IntUserConfigParam m_multitouch_accelerometer
|
||||
PARAM_DEFAULT( IntUserConfigParam(0, "multitouch_accelerometer",
|
||||
&m_multitouch_group,
|
||||
"Accelerometer mode: 0 = off, 1 = tablet, 2 = phone"));
|
||||
|
||||
PARAM_PREFIX FloatUserConfigParam m_multitouch_deadzone_center
|
||||
PARAM_DEFAULT( FloatUserConfigParam(0.1f, "multitouch_deadzone_center",
|
||||
|
@ -206,28 +206,33 @@ void FontWithFace::insertGlyph(wchar_t c, const GlyphInfo& gi)
|
||||
|
||||
const unsigned int cur_tex = m_spritebank->getTextureCount() -1;
|
||||
#ifndef SERVER_ONLY
|
||||
video::ITexture* tex = m_spritebank->getTexture(cur_tex);
|
||||
glBindTexture(GL_TEXTURE_2D, tex->getOpenGLTextureName());
|
||||
assert(bits->pixel_mode == FT_PIXEL_MODE_GRAY);
|
||||
if (CVS->isARBTextureSwizzleUsable())
|
||||
if (bits->buffer != NULL)
|
||||
{
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, m_used_width, m_used_height,
|
||||
bits->width, bits->rows, GL_RED, GL_UNSIGNED_BYTE, bits->buffer);
|
||||
video::ITexture* tex = m_spritebank->getTexture(cur_tex);
|
||||
glBindTexture(GL_TEXTURE_2D, tex->getOpenGLTextureName());
|
||||
assert(bits->pixel_mode == FT_PIXEL_MODE_GRAY);
|
||||
if (CVS->isARBTextureSwizzleUsable())
|
||||
{
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, m_used_width, m_used_height,
|
||||
bits->width, bits->rows, GL_RED, GL_UNSIGNED_BYTE,
|
||||
bits->buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
const unsigned int size = bits->width * bits->rows;
|
||||
uint8_t* image_data = new uint8_t[size * 4];
|
||||
memset(image_data, 255, size * 4);
|
||||
for (unsigned int i = 0; i < size; i++)
|
||||
image_data[4 * i + 3] = bits->buffer[i];
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, m_used_width, m_used_height,
|
||||
bits->width, bits->rows, GL_BGRA, GL_UNSIGNED_BYTE,
|
||||
image_data);
|
||||
delete[] image_data;
|
||||
}
|
||||
if (tex->hasMipMaps())
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
const unsigned int size = bits->width * bits->rows;
|
||||
uint8_t* image_data = new uint8_t[size * 4];
|
||||
memset(image_data, 255, size * 4);
|
||||
for (unsigned int i = 0; i < size; i++)
|
||||
image_data[4 * i + 3] = bits->buffer[i];
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, m_used_width, m_used_height,
|
||||
bits->width, bits->rows, GL_BGRA, GL_UNSIGNED_BYTE, image_data);
|
||||
delete[] image_data;
|
||||
}
|
||||
if (tex->hasMipMaps())
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
#endif
|
||||
|
||||
// Store the rectangle of current glyph
|
||||
|
@ -38,11 +38,10 @@
|
||||
*/
|
||||
CameraNormal::CameraNormal(Camera::CameraType type, int camera_index,
|
||||
AbstractKart* kart)
|
||||
: Camera(type, camera_index, kart)
|
||||
: Camera(type, camera_index, kart), m_camera_offset(0, 0, -15.0f)
|
||||
{
|
||||
m_distance = kart ? kart->getKartProperties()->getCameraDistance() : 1000.0f;
|
||||
m_ambient_light = Track::getCurrentTrack()->getDefaultAmbientColor();
|
||||
m_smooth_dt = 0.0f;
|
||||
|
||||
// TODO: Put these values into a config file
|
||||
// Global or per split screen zone?
|
||||
@ -53,8 +52,17 @@ CameraNormal::CameraNormal(Camera::CameraType type, int camera_index,
|
||||
m_target_speed = 10.0f;
|
||||
m_rotation_range = 0.4f;
|
||||
m_rotation_range = 0.0f;
|
||||
m_kart_position = btVector3(0, 0, 0);
|
||||
m_kart_rotation = btQuaternion(0, 0, 0, 0);
|
||||
reset();
|
||||
m_camera->setNearValue(1.0f);
|
||||
|
||||
if (kart)
|
||||
{
|
||||
btTransform btt = kart->getTrans();
|
||||
m_kart_position = btt.getOrigin();
|
||||
m_kart_rotation = btt.getRotation();
|
||||
}
|
||||
} // Camera
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -65,22 +73,23 @@ CameraNormal::CameraNormal(Camera::CameraType type, int camera_index,
|
||||
*/
|
||||
void CameraNormal::smoothMoveCamera(float dt)
|
||||
{
|
||||
if(!m_kart) return;
|
||||
|
||||
Kart *kart = dynamic_cast<Kart*>(m_kart);
|
||||
if (kart->isFlying())
|
||||
{
|
||||
Vec3 vec3 = m_kart->getXYZ() + Vec3(sin(m_kart->getHeading()) * -4.0f,
|
||||
0.5f,
|
||||
cos(m_kart->getHeading()) * -4.0f);
|
||||
0.5f,
|
||||
cos(m_kart->getHeading()) * -4.0f);
|
||||
m_camera->setTarget(m_kart->getXYZ().toIrrVector());
|
||||
m_camera->setPosition(vec3.toIrrVector());
|
||||
return;
|
||||
} // kart is flying
|
||||
|
||||
|
||||
core::vector3df current_position = m_camera->getPosition();
|
||||
core::vector3df current_position = m_camera->getPosition();
|
||||
// Smoothly interpolate towards the position and target
|
||||
const KartProperties *kp = m_kart->getKartProperties();
|
||||
float max_increase_with_zipper = kp->getZipperMaxSpeedIncrease();
|
||||
float max_speed_without_zipper = kp->getEngineMaxSpeed();
|
||||
float current_speed = m_kart->getSmoothedSpeed();
|
||||
|
||||
@ -88,44 +97,54 @@ void CameraNormal::smoothMoveCamera(float dt)
|
||||
float skid_factor = ks->getVisualSkidRotation();
|
||||
|
||||
float skid_angle = asin(skid_factor);
|
||||
float ratio = (current_speed - max_speed_without_zipper) / max_increase_with_zipper;
|
||||
float ratio = current_speed / max_speed_without_zipper;
|
||||
|
||||
ratio = ratio > -0.12f ? ratio : -0.12f;
|
||||
|
||||
// distance of camera from kart in x and z plane
|
||||
float camera_distance = -3 * (0.5f + ratio);
|
||||
if (camera_distance > -2.0f) camera_distance = -2.0f;
|
||||
float camera_distance = -1.25f - 2.5f * ratio;
|
||||
if (camera_distance > -2.0f) camera_distance = -2.0f; // don't get too close to the kart
|
||||
|
||||
// Defines how far camera should be from player kart.
|
||||
Vec3 camera_offset(camera_distance * sin(skid_angle / 2),
|
||||
1.1f * (1 + ratio / 2),
|
||||
camera_distance * cos(skid_angle / 2));
|
||||
Vec3 m_kart_camera_position_with_offset = m_kart->getTrans()(camera_offset);
|
||||
Vec3 wanted_camera_offset(camera_distance * sin(skid_angle / 2),
|
||||
(0.85f + ratio / 2.5f),
|
||||
camera_distance * cos(skid_angle / 2));
|
||||
|
||||
|
||||
//m_smooth_dt = 0.3f * dt + 0.7f * m_smooth_dt;
|
||||
float delta = (dt*5.0f);
|
||||
if (delta < 0.0f)
|
||||
delta = 0.0f;
|
||||
else if (delta > 1.0f)
|
||||
delta = 1.0f;
|
||||
|
||||
m_camera_offset += (wanted_camera_offset - m_camera_offset) * delta;
|
||||
|
||||
float delta2 = dt * 8.0f;
|
||||
if (delta2 < 0)
|
||||
delta2 = 0;
|
||||
else if (delta2 > 1)
|
||||
delta2 = 1;
|
||||
|
||||
btTransform btt = m_kart->getTrans();
|
||||
m_kart_position = btt.getOrigin();// m_kart_position + (btt.getOrigin() - m_kart_position) * delta2;
|
||||
m_kart_rotation = m_kart_rotation.normalized().slerp(btt.getRotation().normalized(), delta2);
|
||||
|
||||
btt.setOrigin(m_kart_position);
|
||||
btt.setRotation(m_kart_rotation);
|
||||
|
||||
Vec3 m_kart_camera_position_with_offset = btt(m_camera_offset);
|
||||
// next target
|
||||
Vec3 current_target = m_kart->getTrans()(Vec3(0, 0.5f, 0));
|
||||
Vec3 current_target = btt(Vec3(0, 0.5f, 0));
|
||||
// new required position of camera
|
||||
core::vector3df wanted_position = m_kart_camera_position_with_offset.toIrrVector();
|
||||
current_position = m_kart_camera_position_with_offset.toIrrVector();
|
||||
|
||||
float f = 5.0f;
|
||||
if ((current_speed > 5 ) || (current_speed < 0 ))
|
||||
{
|
||||
f = current_speed >0 ? current_speed/3 + 1.0f
|
||||
: -1.5f * current_speed + 2.0f;
|
||||
}
|
||||
m_smooth_dt = 0.3f * dt + 0.7f * m_smooth_dt;
|
||||
current_position += (wanted_position - current_position) * (m_smooth_dt*f);
|
||||
|
||||
// Avoid camera crash: if the speed is negative, the current_position
|
||||
// can oscillate between plus and minus, getting bigger and bigger. If
|
||||
// this happens often enough, floating point overflow happens (large
|
||||
// negative speeds can happen when the kart is tumbling/falling)
|
||||
// To avoid this, we just move the camera to the wanted position if
|
||||
// the distance becomes too large (see #1356).
|
||||
if( (current_position - wanted_position).getLengthSQ() > 100)
|
||||
{
|
||||
Log::debug("camera", "Resetting camera position to avoid crash");
|
||||
current_position = wanted_position;
|
||||
}
|
||||
//Log::info("CAM_DEBUG", "OFFSET: %f %f %f TRANSFORMED %f %f %f TARGET %f %f %f",
|
||||
// wanted_camera_offset.x(), wanted_camera_offset.y(), wanted_camera_offset.z(),
|
||||
// m_kart_camera_position_with_offset.x(), m_kart_camera_position_with_offset.y(),
|
||||
// m_kart_camera_position_with_offset.z(), current_target.x(), current_target.y(),
|
||||
// current_target.z());
|
||||
|
||||
if(getMode()!=CM_FALLING)
|
||||
m_camera->setPosition(current_position);
|
||||
|
@ -49,8 +49,8 @@ private:
|
||||
/** Factor of the effects of steering in camera aim. */
|
||||
float m_rotation_range;
|
||||
|
||||
/** Used to smoothly move the camera. */
|
||||
float m_smooth_dt;
|
||||
Vec3 m_camera_offset;
|
||||
|
||||
void smoothMoveCamera(float dt);
|
||||
void handleEndCamera(float dt);
|
||||
void getCameraSettings(float *above_kart, float *cam_angle,
|
||||
@ -59,6 +59,9 @@ private:
|
||||
void positionCamera(float dt, float above_kart, float cam_angle,
|
||||
float side_way, float distance, float smoothing);
|
||||
|
||||
btVector3 m_kart_position;
|
||||
btQuaternion m_kart_rotation;
|
||||
|
||||
// Give a few classes access to the constructor (mostly for inheritance)
|
||||
friend class Camera;
|
||||
friend class CameraDebug;
|
||||
|
@ -91,7 +91,7 @@ void CentralVideoSettings::init()
|
||||
std::string driver((char*)(glGetString(GL_VERSION)));
|
||||
std::string card((char*)(glGetString(GL_RENDERER)));
|
||||
GraphicsRestrictions::init(driver, card);
|
||||
|
||||
|
||||
if (GraphicsRestrictions::isDisabled(GraphicsRestrictions::GR_FORCE_LEGACY_DEVICE))
|
||||
{
|
||||
m_glsl = false;
|
||||
@ -238,6 +238,13 @@ void CentralVideoSettings::init()
|
||||
hasTextureStorage = true;
|
||||
hasTextureSwizzle = true;
|
||||
}
|
||||
|
||||
if (!GraphicsRestrictions::isDisabled(GraphicsRestrictions::GR_EXPLICIT_ATTRIB_LOCATION) &&
|
||||
m_glsl == true)
|
||||
{
|
||||
Log::info("GLDriver", "Explicit Attrib Location Present");
|
||||
hasExplicitAttribLocation = true;
|
||||
}
|
||||
|
||||
if (!GraphicsRestrictions::isDisabled(GraphicsRestrictions::GR_TEXTURE_FORMAT_BGRA8888) &&
|
||||
(hasGLExtension("GL_IMG_texture_format_BGRA8888") ||
|
||||
@ -259,12 +266,19 @@ void CentralVideoSettings::init()
|
||||
|
||||
unsigned CentralVideoSettings::getGLSLVersion() const
|
||||
{
|
||||
#if defined(USE_GLES2)
|
||||
if (m_gl_major_version >= 3)
|
||||
return 300;
|
||||
else
|
||||
return 100;
|
||||
#else
|
||||
if (m_gl_major_version > 3 || (m_gl_major_version == 3 && m_gl_minor_version == 3))
|
||||
return m_gl_major_version * 100 + m_gl_minor_version * 10;
|
||||
else if (m_gl_major_version == 3)
|
||||
return 100 + (m_gl_minor_version + 3) * 10;
|
||||
else
|
||||
return 120;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool CentralVideoSettings::isGLSL() const
|
||||
|
@ -91,13 +91,14 @@ public:
|
||||
|
||||
// ============================================================================
|
||||
/** */
|
||||
class HeightmapSimulationShader : public Shader <HeightmapSimulationShader,
|
||||
core::matrix4, int, int,
|
||||
float,float,float,float,float>
|
||||
#if !defined(USE_GLES2)
|
||||
class HeightmapSimulationShader :
|
||||
public TextureShader<HeightmapSimulationShader, 1,
|
||||
core::matrix4, int, int,
|
||||
float, float, float, float,
|
||||
float>
|
||||
{
|
||||
public:
|
||||
GLuint m_TU_heightmap;
|
||||
|
||||
HeightmapSimulationShader()
|
||||
{
|
||||
const char *varyings[] = {"new_particle_position", "new_lifetime",
|
||||
@ -105,12 +106,12 @@ public:
|
||||
loadTFBProgram("particlesimheightmap.vert", varyings, 4);
|
||||
assignUniforms("sourcematrix", "dt", "level", "size_increase_factor",
|
||||
"track_x", "track_x_len", "track_z", "track_z_len");
|
||||
m_TU_heightmap = 2;
|
||||
assignTextureUnit(m_TU_heightmap, "heightmap");
|
||||
assignSamplerNames(0, "heightmap", ST_TEXTURE_BUFFER);
|
||||
} // HeightmapSimulationShader
|
||||
|
||||
|
||||
}; // class HeightmapSimulationShader
|
||||
#endif
|
||||
|
||||
// ============================================================================
|
||||
|
||||
@ -203,6 +204,7 @@ void ParticleSystemProxy::setHeightmap(const std::vector<std::vector<float> > &h
|
||||
glBindTexture(GL_TEXTURE_BUFFER, heightmaptexture);
|
||||
glTexBuffer(GL_TEXTURE_BUFFER, GL_R32F, heighmapbuffer);
|
||||
glBindBuffer(GL_TEXTURE_BUFFER, 0);
|
||||
glBindTexture(GL_TEXTURE_BUFFER, 0);
|
||||
|
||||
delete[] hm_array;
|
||||
#endif
|
||||
@ -475,10 +477,9 @@ void ParticleSystemProxy::simulate()
|
||||
{
|
||||
#if !defined(USE_GLES2)
|
||||
HeightmapSimulationShader::getInstance()->use();
|
||||
glActiveTexture(GL_TEXTURE0 + HeightmapSimulationShader::getInstance()->m_TU_heightmap);
|
||||
glBindTexture(GL_TEXTURE_BUFFER, heightmaptexture);
|
||||
HeightmapSimulationShader::getInstance()->setTextureUnits(heightmaptexture);
|
||||
HeightmapSimulationShader::getInstance()->setUniforms(matrix, timediff, active_count, size_increase_factor, track_x, track_x_len, track_z, track_z_len);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -76,7 +76,7 @@ Material::Material(const XMLNode *node, bool deprecated)
|
||||
init();
|
||||
|
||||
bool b = false;
|
||||
|
||||
|
||||
node->get("clampu", &b); if (b) m_clamp_tex |= UCLAMP; //blender 2.4 style
|
||||
node->get("clampU", &b); if (b) m_clamp_tex |= UCLAMP; //blender 2.5 style
|
||||
b = false;
|
||||
@ -745,7 +745,7 @@ void Material::setMaterialProperties(video::SMaterial *m, scene::IMeshBuffer* m
|
||||
ITexture *tex;
|
||||
ITexture *glossytex;
|
||||
STKTexManager* stm = STKTexManager::getInstance();
|
||||
if (m_gloss_map.size() > 0 && UserConfigParams::m_dynamic_lights)
|
||||
if (m_gloss_map.size() > 0 && CVS->isDefferedEnabled())
|
||||
{
|
||||
glossytex = stm->getTexture(m_gloss_map, false/*srgb*/,
|
||||
false/*premul_alpha*/, false/*set_material*/,
|
||||
@ -886,7 +886,7 @@ void Material::setMaterialProperties(video::SMaterial *m, scene::IMeshBuffer* m
|
||||
|
||||
if (m_normal_map_tex.size() > 0)
|
||||
{
|
||||
if (UserConfigParams::m_dynamic_lights)
|
||||
if (CVS->isDefferedEnabled())
|
||||
{
|
||||
tex = stm->getTexture(m_normal_map_tex, false/*srgb*/,
|
||||
false/*premul_alpha*/, false/*set_material*/,
|
||||
|
@ -709,7 +709,6 @@ void ParticleEmitter::setParticleType(const ParticleKind* type)
|
||||
|
||||
void ParticleEmitter::addHeightMapAffector(Track* t)
|
||||
{
|
||||
|
||||
if (m_is_glsl)
|
||||
{
|
||||
const Vec3* aabb_min;
|
||||
|
@ -354,16 +354,16 @@ public:
|
||||
} // render
|
||||
}; // BloomShader
|
||||
|
||||
static video::ITexture *lensDustTex = 0;
|
||||
|
||||
// ============================================================================
|
||||
class BloomBlendShader : public TextureShader<BloomBlendShader, 4>
|
||||
{
|
||||
private:
|
||||
video::ITexture* m_lens_dust_tex;
|
||||
public:
|
||||
BloomBlendShader()
|
||||
{
|
||||
if (!lensDustTex)
|
||||
lensDustTex = irr_driver->getTexture(FileManager::TEXTURE, "gfx_lensDust_a.png");
|
||||
m_lens_dust_tex =
|
||||
irr_driver->getTexture(FileManager::TEXTURE, "gfx_lensDust_a.png");
|
||||
|
||||
loadProgram(OBJECT, GL_VERTEX_SHADER, "screenquad.vert",
|
||||
GL_FRAGMENT_SHADER, "bloomblend.frag");
|
||||
@ -381,7 +381,7 @@ public:
|
||||
setTextureUnits(render_target_bloom_128,
|
||||
render_target_bloom_256,
|
||||
render_target_bloom_512,
|
||||
lensDustTex->getOpenGLTextureName());
|
||||
m_lens_dust_tex->getOpenGLTextureName());
|
||||
drawFullScreenEffect();
|
||||
} // render
|
||||
}; // BloomBlendShader
|
||||
|
@ -237,7 +237,7 @@ void Referee::selectReadySetGo(int rsg)
|
||||
return;
|
||||
video::SMaterial &m = m_scene_node->getMaterial(m_st_traffic_buffer); // m_scene_node->getMesh()->getMeshBuffer(m_st_traffic_buffer)->getMaterial();
|
||||
|
||||
//if (irr_driver->isGLSL() && UserConfigParams::m_dynamic_lights)
|
||||
//if (irr_driver->isGLSL() && CVS->isDefferedEnabled())
|
||||
// m.MaterialType = irr_driver->getShader(ES_OBJECT_UNLIT);
|
||||
|
||||
core::matrix4* matrix = &m.getTextureMatrix(0);
|
||||
|
@ -42,7 +42,7 @@ int ShaderBase::loadTFBProgram(const std::string &shader_name,
|
||||
#ifdef USE_GLES2
|
||||
loadAndAttachShader(GL_FRAGMENT_SHADER, "tfb_dummy.frag");
|
||||
#endif
|
||||
if (CVS->getGLSLVersion() < 330)
|
||||
if (!CVS->isARBExplicitAttribLocationUsable())
|
||||
setAttribute(PARTICLES_SIM);
|
||||
|
||||
glTransformFeedbackVaryings(m_program, varying_count, varyings,
|
||||
@ -74,7 +74,7 @@ void ShaderBase::bypassUBO() const
|
||||
|
||||
GLint PM = glGetUniformLocation(m_program, "ProjectionMatrix");
|
||||
glUniformMatrix4fv(PM, 1, GL_FALSE, irr_driver->getProjMatrix().pointer());
|
||||
|
||||
|
||||
GLint PVM = glGetUniformLocation(m_program, "ProjectionViewMatrix");
|
||||
glUniformMatrix4fv(PVM, 1, GL_FALSE, irr_driver->getProjViewMatrix().pointer());
|
||||
|
||||
|
@ -33,7 +33,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
/** A simple non-templated base class. It is used to store some enums used in
|
||||
/** A simple non-templated base class. It is used to store some enums used in
|
||||
* templates, the actual header for a shader, and a statis list of all kill
|
||||
* functions (which delete all singletons, and therefore forces a reload of all
|
||||
* shaders).
|
||||
@ -301,7 +301,7 @@ public:
|
||||
* \param index Index of the texture.
|
||||
* \param uniform Uniform name.
|
||||
*/
|
||||
template<typename... T1>
|
||||
template<typename... T1>
|
||||
void assignTextureUnit(GLuint index, const char* uniform, T1... rest)
|
||||
{
|
||||
glUseProgram(m_program);
|
||||
@ -349,7 +349,7 @@ public:
|
||||
{
|
||||
m_program = glCreateProgram();
|
||||
loadAndAttachShader(args...);
|
||||
if (CVS->getGLSLVersion() < 330)
|
||||
if (!CVS->isARBExplicitAttribLocationUsable())
|
||||
setAttribute(type);
|
||||
glLinkProgram(m_program);
|
||||
|
||||
|
@ -787,7 +787,9 @@ void ShaderBasedRenderer::render(float dt)
|
||||
RaceGUIBase *rg = world->getRaceGUI();
|
||||
if (rg) rg->update(dt);
|
||||
|
||||
if (!CVS->isDefferedEnabled())
|
||||
bool force_rtt = UserConfigParams::m_scale_rtts_factor != 1.0f;
|
||||
|
||||
if (!CVS->isDefferedEnabled() && !force_rtt)
|
||||
{
|
||||
prepareForwardRenderer();
|
||||
}
|
||||
@ -801,7 +803,7 @@ void ShaderBasedRenderer::render(float dt)
|
||||
oss << "drawAll() for kart " << cam;
|
||||
PROFILER_PUSH_CPU_MARKER(oss.str().c_str(), (cam+1)*60,
|
||||
0x00, 0x00);
|
||||
camera->activate(!CVS->isDefferedEnabled());
|
||||
camera->activate(!CVS->isDefferedEnabled() && !force_rtt);
|
||||
rg->preRenderCallback(camera); // adjusts start referee
|
||||
irr_driver->getSceneManager()->setActiveCamera(camnode);
|
||||
|
||||
@ -819,7 +821,7 @@ void ShaderBasedRenderer::render(float dt)
|
||||
if(CVS->isARBUniformBufferObjectUsable())
|
||||
uploadLightingData();
|
||||
PROFILER_POP_CPU_MARKER();
|
||||
renderScene(camnode, dt, track->hasShadows(), false);
|
||||
renderScene(camnode, dt, track->hasShadows(), force_rtt);
|
||||
|
||||
if (irr_driver->getBoundingBoxesViz())
|
||||
{
|
||||
@ -828,7 +830,7 @@ void ShaderBasedRenderer::render(float dt)
|
||||
|
||||
debugPhysics();
|
||||
|
||||
if (CVS->isDefferedEnabled())
|
||||
if (CVS->isDefferedEnabled() || force_rtt)
|
||||
{
|
||||
renderPostProcessing(camera);
|
||||
}
|
||||
@ -942,6 +944,7 @@ void ShaderBasedRenderer::renderToTexture(GL3RenderTarget *render_target,
|
||||
// ----------------------------------------------------------------------------
|
||||
void ShaderBasedRenderer::preloadShaderFiles()
|
||||
{
|
||||
SharedGPUObjects::init();
|
||||
ShaderFilesManager* sfm = ShaderFilesManager::getInstance();
|
||||
|
||||
sfm->addShaderFile("object_pass.vert", GL_VERTEX_SHADER);
|
||||
|
@ -89,7 +89,10 @@ GLuint ShaderFilesManager::loadShader(const std::string &file, unsigned type)
|
||||
code << "#extension GL_AMD_vertex_shader_layer : enable\n";
|
||||
|
||||
if (CVS->isARBExplicitAttribLocationUsable())
|
||||
{
|
||||
code << "#extension GL_ARB_explicit_attrib_location : enable\n";
|
||||
code << "#define Explicit_Attrib_Location_Usable\n";
|
||||
}
|
||||
|
||||
if (CVS->isAZDOEnabled())
|
||||
{
|
||||
|
@ -259,7 +259,6 @@ void Shaders::loadShaders()
|
||||
}
|
||||
|
||||
initGL();
|
||||
SharedGPUObjects::init();
|
||||
} // loadShaders
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -56,24 +56,21 @@ public:
|
||||
} // bindVertexArray
|
||||
}; // SkyboxShader
|
||||
|
||||
|
||||
class SpecularIBLGenerator : public TextureShader<SpecularIBLGenerator, 1,
|
||||
#if !defined(USE_GLES2)
|
||||
class SpecularIBLGenerator : public TextureShader<SpecularIBLGenerator, 2,
|
||||
core::matrix4, float >
|
||||
{
|
||||
public:
|
||||
GLuint m_tu_samples;
|
||||
SpecularIBLGenerator()
|
||||
{
|
||||
loadProgram(OBJECT, GL_VERTEX_SHADER, "screenquad.vert",
|
||||
GL_FRAGMENT_SHADER, "importance_sampling_specular.frag");
|
||||
assignUniforms("PermutationMatrix", "ViewportSize");
|
||||
m_tu_samples = 1;
|
||||
assignSamplerNames(0, "tex", ST_TRILINEAR_CUBEMAP);
|
||||
assignTextureUnit(m_tu_samples, "samples");
|
||||
assignSamplerNames(0, "tex", ST_TRILINEAR_CUBEMAP,
|
||||
1, "samples", ST_TEXTURE_BUFFER);
|
||||
}
|
||||
|
||||
}; // SpecularIBLGenerator
|
||||
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -277,16 +274,15 @@ void Skybox::generateSpecularCubemap()
|
||||
}
|
||||
|
||||
glBindVertexArray(0);
|
||||
glActiveTexture(GL_TEXTURE0 +
|
||||
SpecularIBLGenerator::getInstance()->m_tu_samples);
|
||||
GLuint sampleTex, sampleBuffer;
|
||||
glGenBuffers(1, &sampleBuffer);
|
||||
glBindBuffer(GL_TEXTURE_BUFFER, sampleBuffer);
|
||||
GLuint sample_texture, sample_buffer;
|
||||
glGenBuffers(1, &sample_buffer);
|
||||
glBindBuffer(GL_TEXTURE_BUFFER, sample_buffer);
|
||||
glBufferData(GL_TEXTURE_BUFFER, 2048 * sizeof(float), tmp,
|
||||
GL_STATIC_DRAW);
|
||||
glGenTextures(1, &sampleTex);
|
||||
glBindTexture(GL_TEXTURE_BUFFER, sampleTex);
|
||||
glTexBuffer(GL_TEXTURE_BUFFER, GL_RG32F, sampleBuffer);
|
||||
glGenTextures(1, &sample_texture);
|
||||
glBindTexture(GL_TEXTURE_BUFFER, sample_texture);
|
||||
glTexBuffer(GL_TEXTURE_BUFFER, GL_RG32F, sample_buffer);
|
||||
glBindTexture(GL_TEXTURE_BUFFER, 0);
|
||||
glBindVertexArray(SharedGPUObjects::getFullScreenQuadVAO());
|
||||
|
||||
for (unsigned face = 0; face < 6; face++)
|
||||
@ -298,20 +294,19 @@ void Skybox::generateSpecularCubemap()
|
||||
GLuint status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
assert(status == GL_FRAMEBUFFER_COMPLETE);
|
||||
|
||||
SpecularIBLGenerator::getInstance()->setTextureUnits(m_cube_map);
|
||||
SpecularIBLGenerator::getInstance()
|
||||
->setTextureUnits(m_cube_map, sample_texture);
|
||||
SpecularIBLGenerator::getInstance()->setUniforms(M[face],
|
||||
viewportSize);
|
||||
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
}
|
||||
glActiveTexture( GL_TEXTURE0
|
||||
+ SpecularIBLGenerator::getInstance()->m_tu_samples);
|
||||
glBindBuffer(GL_TEXTURE_BUFFER, 0);
|
||||
glBindTexture(GL_TEXTURE_BUFFER, 0);
|
||||
|
||||
delete[] tmp;
|
||||
glDeleteTextures(1, &sampleTex);
|
||||
glDeleteBuffers(1, &sampleBuffer);
|
||||
glDeleteTextures(1, &sample_texture);
|
||||
glDeleteBuffers(1, &sample_buffer);
|
||||
}
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
glDeleteFramebuffers(1, &fbo);
|
||||
|
@ -1,19 +1,6 @@
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 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.
|
||||
// Copyright (C) 2002-2012 Nikolaus Gebhardt
|
||||
// This file is part of the "Irrlicht Engine".
|
||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
||||
|
||||
#include "graphics/stk_mesh_loader.hpp"
|
||||
#include "graphics/stk_tex_manager.hpp"
|
||||
@ -1059,7 +1046,7 @@ void STKMeshLoader::loadTextures(SB3dMaterial& material) const
|
||||
|
||||
video::ITexture* tex =
|
||||
STKTexManager::getInstance()->getTexture(full_path.c_str(),
|
||||
i == 0 ? true : false/*is_srgb*/, false/*premul_alpha*/,
|
||||
i <= 1 ? true : false/*is_srgb*/, false/*premul_alpha*/,
|
||||
true/*set_material*/);
|
||||
|
||||
material.Material.setTexture(i, tex);
|
||||
|
@ -1,19 +1,6 @@
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 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.
|
||||
// Copyright (C) 2002-2012 Nikolaus Gebhardt
|
||||
// This file is part of the "Irrlicht Engine".
|
||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
||||
|
||||
#ifndef HEADER_STK_MESH_LOADER_HPP
|
||||
#define HEADER_STK_MESH_LOADER_HPP
|
||||
|
@ -33,7 +33,8 @@ TextureShaderBase::BindFunction TextureShaderBase::m_all_bind_functions[] =
|
||||
/* ST_VOLUME_LINEAR_FILTERED */ &TextureShaderBase::bindTextureVolume,
|
||||
/* ST_NEARED_CLAMPED_FILTERED */ &TextureShaderBase::bindTextureNearestClamped,
|
||||
/* ST_BILINEAR_CLAMPED_FILTERED */ &TextureShaderBase::bindTextureBilinearClamped,
|
||||
/* ST_SEMI_TRILINEAR */ &TextureShaderBase::bindTextureSemiTrilinear
|
||||
/* ST_SEMI_TRILINEAR */ &TextureShaderBase::bindTextureSemiTrilinear,
|
||||
/* ST_TEXTURE_BUFFER */ &TextureShaderBase::bindTextureBuffer
|
||||
};
|
||||
|
||||
GLuint TextureShaderBase::m_all_texture_types[] =
|
||||
@ -47,6 +48,10 @@ GLuint TextureShaderBase::m_all_texture_types[] =
|
||||
/* ST_NEARED_CLAMPED_FILTERED */ GL_TEXTURE_2D,
|
||||
/* ST_BILINEAR_CLAMPED_FILTERED */ GL_TEXTURE_2D,
|
||||
/* ST_SEMI_TRILINEAR */ GL_TEXTURE_2D
|
||||
#ifndef USE_GLES2
|
||||
/* ST_TEXTURE_BUFFER */, GL_TEXTURE_BUFFER
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -116,6 +121,13 @@ void TextureShaderBase::bindTextureNearestClamped(GLuint texture_unit,
|
||||
} // bindTextureNearestClamped
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void TextureShaderBase::bindTextureBuffer(GLuint texture_unit, GLuint tex_id)
|
||||
{
|
||||
#ifndef USE_GLES2
|
||||
glActiveTexture(GL_TEXTURE0 + texture_unit);
|
||||
glBindTexture(GL_TEXTURE_BUFFER, tex_id);
|
||||
#endif
|
||||
} // bindTextureBuffer
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void TextureShaderBase::bindTextureBilinear(GLuint texture_unit, GLuint tex)
|
||||
@ -239,6 +251,10 @@ GLuint TextureShaderBase::createSamplers(SamplerTypeNew sampler_type)
|
||||
return createBilinearClampedSampler();
|
||||
case ST_SEMI_TRILINEAR:
|
||||
return createSemiTrilinearSampler();
|
||||
#ifndef USE_GLES2
|
||||
case ST_TEXTURE_BUFFER:
|
||||
return 0;
|
||||
#endif
|
||||
default:
|
||||
assert(false);
|
||||
return 0;
|
||||
@ -248,7 +264,6 @@ GLuint TextureShaderBase::createSamplers(SamplerTypeNew sampler_type)
|
||||
// ----------------------------------------------------------------------------
|
||||
GLuint TextureShaderBase::createNearestSampler()
|
||||
{
|
||||
#ifdef GL_VERSION_3_3
|
||||
unsigned id;
|
||||
glGenSamplers(1, &id);
|
||||
glSamplerParameteri(id, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
@ -258,13 +273,11 @@ GLuint TextureShaderBase::createNearestSampler()
|
||||
if (CVS->isEXTTextureFilterAnisotropicUsable())
|
||||
glSamplerParameterf(id, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.);
|
||||
return id;
|
||||
#endif
|
||||
} // createNearestSampler
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
GLuint TextureShaderBase::createTrilinearSampler()
|
||||
{
|
||||
#ifdef GL_VERSION_3_3
|
||||
unsigned id;
|
||||
glGenSamplers(1, &id);
|
||||
glSamplerParameteri(id, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
@ -279,13 +292,11 @@ GLuint TextureShaderBase::createTrilinearSampler()
|
||||
glSamplerParameterf(id, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float)aniso);
|
||||
}
|
||||
return id;
|
||||
#endif
|
||||
} // createTrilinearSampler
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
GLuint TextureShaderBase::createBilinearSampler()
|
||||
{
|
||||
#ifdef GL_VERSION_3_3
|
||||
unsigned id;
|
||||
glGenSamplers(1, &id);
|
||||
glSamplerParameteri(id, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
@ -295,12 +306,10 @@ GLuint TextureShaderBase::createBilinearSampler()
|
||||
if (CVS->isEXTTextureFilterAnisotropicUsable())
|
||||
glSamplerParameterf(id, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.);
|
||||
return id;
|
||||
#endif
|
||||
} // createBilinearSampler
|
||||
// ----------------------------------------------------------------------------
|
||||
GLuint TextureShaderBase::createShadowSampler()
|
||||
{
|
||||
#ifdef GL_VERSION_3_3
|
||||
unsigned id;
|
||||
glGenSamplers(1, &id);
|
||||
glSamplerParameteri(id, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
@ -310,13 +319,11 @@ GLuint TextureShaderBase::createShadowSampler()
|
||||
glSamplerParameterf(id, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
|
||||
glSamplerParameterf(id, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
|
||||
return id;
|
||||
#endif
|
||||
} // createShadowSampler
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
GLuint TextureShaderBase::createBilinearClampedSampler()
|
||||
{
|
||||
#ifdef GL_VERSION_3_3
|
||||
unsigned id;
|
||||
glGenSamplers(1, &id);
|
||||
glSamplerParameteri(id, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
@ -326,14 +333,12 @@ GLuint TextureShaderBase::createBilinearClampedSampler()
|
||||
if (CVS->isEXTTextureFilterAnisotropicUsable())
|
||||
glSamplerParameterf(id, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.);
|
||||
return id;
|
||||
#endif
|
||||
} // createBilinearClampedSampler
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
GLuint TextureShaderBase::createTrilinearClampedArray()
|
||||
{
|
||||
#ifdef GL_VERSION_3_3
|
||||
unsigned id;
|
||||
glGenSamplers(1, &id);
|
||||
glSamplerParameteri(id, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
@ -348,12 +353,10 @@ GLuint TextureShaderBase::createTrilinearClampedArray()
|
||||
glSamplerParameterf(id, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float)aniso);
|
||||
}
|
||||
return id;
|
||||
#endif
|
||||
} // createTrilinearClampedArray
|
||||
// ----------------------------------------------------------------------------
|
||||
GLuint TextureShaderBase::createSemiTrilinearSampler()
|
||||
{
|
||||
#ifdef GL_VERSION_3_3
|
||||
unsigned id;
|
||||
glGenSamplers(1, &id);
|
||||
glSamplerParameteri(id, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
@ -363,7 +366,6 @@ GLuint TextureShaderBase::createSemiTrilinearSampler()
|
||||
if (CVS->isEXTTextureFilterAnisotropicUsable())
|
||||
glSamplerParameterf(id, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.);
|
||||
return id;
|
||||
#endif
|
||||
} // createSemiTrilinearSampler
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -43,13 +43,18 @@ enum SamplerTypeNew
|
||||
ST_NEARED_CLAMPED_FILTERED,
|
||||
ST_BILINEAR_CLAMPED_FILTERED,
|
||||
ST_SEMI_TRILINEAR,
|
||||
#ifdef USE_GLES2
|
||||
ST_MAX = ST_SEMI_TRILINEAR
|
||||
#else
|
||||
ST_TEXTURE_BUFFER,
|
||||
ST_MAX = ST_TEXTURE_BUFFER
|
||||
#endif
|
||||
}; // SamplerTypeNew
|
||||
|
||||
// ============================================================================
|
||||
/** A simple non-templated base class for a shader that uses textures. A non
|
||||
* templated base class is necessary to easily handle static objects (like
|
||||
* list of all bind functions to call) - with templates each instance is a
|
||||
* templated base class is necessary to easily handle static objects (like
|
||||
* list of all bind functions to call) - with templates each instance is a
|
||||
* different class (with different static values).
|
||||
*/
|
||||
class TextureShaderBase
|
||||
@ -68,7 +73,8 @@ protected:
|
||||
static void bindTextureShadow(GLuint tex_unit, GLuint tex_id);
|
||||
static void bindTrilinearClampedArrayTexture(GLuint tex_unit, GLuint tex_id);
|
||||
static void bindTextureVolume(GLuint tex_unit, GLuint tex_id);
|
||||
|
||||
static void bindTextureBuffer(GLuint tex_unit, GLuint tex_id);
|
||||
|
||||
GLuint createSamplers(SamplerTypeNew sampler_type);
|
||||
private:
|
||||
|
||||
@ -88,7 +94,7 @@ protected:
|
||||
// ========================================================================
|
||||
/** Class C needs to be the newly declared shaders class (necessary for
|
||||
* the instance template). NUM_TEXTURES is the number of texture units
|
||||
* used in this shader. It is used to test at compile time that the
|
||||
* used in this shader. It is used to test at compile time that the
|
||||
* right number of arguments are supplied to the variadic functions.
|
||||
*/
|
||||
template<class C, int NUM_TEXTURES, typename...tp>
|
||||
@ -171,13 +177,15 @@ public:
|
||||
template<int N, typename... TexIds>
|
||||
void setTextureUnitsImpl(GLuint tex_id, TexIds... args)
|
||||
{
|
||||
#if defined(USE_GLES2)
|
||||
if (CVS->getGLSLVersion() >= 300)
|
||||
#else
|
||||
if (CVS->getGLSLVersion() >= 330)
|
||||
#endif
|
||||
{
|
||||
#ifdef GL_VERSION_3_3
|
||||
glActiveTexture(GL_TEXTURE0 + m_texture_units[N]);
|
||||
glBindTexture(m_texture_type[N], tex_id);
|
||||
glBindSampler(m_texture_units[N], m_sampler_ids[N]);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -199,7 +199,8 @@ bool EventHandler::OnEvent (const SEvent &event)
|
||||
else if (event.EventType == EET_MOUSE_INPUT_EVENT ||
|
||||
event.EventType == EET_TOUCH_INPUT_EVENT ||
|
||||
event.EventType == EET_KEY_INPUT_EVENT ||
|
||||
event.EventType == EET_JOYSTICK_INPUT_EVENT)
|
||||
event.EventType == EET_JOYSTICK_INPUT_EVENT ||
|
||||
event.EventType == EET_ACCELEROMETER_EVENT)
|
||||
{
|
||||
// Remember the mouse position
|
||||
if (event.EventType == EET_MOUSE_INPUT_EVENT &&
|
||||
|
@ -1129,30 +1129,26 @@ EventPropagation InputManager::input(const SEvent& event)
|
||||
|
||||
// Simulate touch event on non-android devices
|
||||
#if !defined(ANDROID)
|
||||
if (UserConfigParams::m_multitouch_enabled == true &&
|
||||
(type == EMIE_LMOUSE_PRESSED_DOWN || type == EMIE_LMOUSE_LEFT_UP ||
|
||||
type == EMIE_MOUSE_MOVED))
|
||||
MultitouchDevice* device = m_device_manager->getMultitouchDevice();
|
||||
|
||||
if (device != NULL && (type == EMIE_LMOUSE_PRESSED_DOWN ||
|
||||
type == EMIE_LMOUSE_LEFT_UP || type == EMIE_MOUSE_MOVED))
|
||||
{
|
||||
MultitouchDevice* device = m_device_manager->getMultitouchDevice();
|
||||
device->m_events[0].id = 0;
|
||||
device->m_events[0].x = event.MouseInput.X;
|
||||
device->m_events[0].y = event.MouseInput.Y;
|
||||
|
||||
if (device != NULL)
|
||||
if (type == EMIE_LMOUSE_PRESSED_DOWN)
|
||||
{
|
||||
device->m_events[0].id = 0;
|
||||
device->m_events[0].x = event.MouseInput.X;
|
||||
device->m_events[0].y = event.MouseInput.Y;
|
||||
|
||||
if (type == EMIE_LMOUSE_PRESSED_DOWN)
|
||||
{
|
||||
device->m_events[0].touched = true;
|
||||
}
|
||||
else if (type == EMIE_LMOUSE_LEFT_UP)
|
||||
{
|
||||
device->m_events[0].touched = false;
|
||||
}
|
||||
|
||||
m_device_manager->updateMultitouchDevice();
|
||||
device->updateDeviceState(0);
|
||||
device->m_events[0].touched = true;
|
||||
}
|
||||
else if (type == EMIE_LMOUSE_LEFT_UP)
|
||||
{
|
||||
device->m_events[0].touched = false;
|
||||
}
|
||||
|
||||
m_device_manager->updateMultitouchDevice();
|
||||
device->updateDeviceState(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1169,6 +1165,32 @@ EventPropagation InputManager::input(const SEvent& event)
|
||||
how fast.
|
||||
*/
|
||||
}
|
||||
else if (event.EventType == EET_ACCELEROMETER_EVENT)
|
||||
{
|
||||
MultitouchDevice* device = m_device_manager->getMultitouchDevice();
|
||||
|
||||
if (device)
|
||||
{
|
||||
for (unsigned int i = 0; i < device->getButtonsCount(); i++)
|
||||
{
|
||||
MultitouchButton* button = device->getButton(i);
|
||||
|
||||
if (button->type != BUTTON_STEERING)
|
||||
continue;
|
||||
|
||||
if (UserConfigParams::m_multitouch_accelerometer == 1)
|
||||
{
|
||||
button->axis_x = -event.AccelerometerEvent.X / 5.0f;
|
||||
device->handleControls(button);
|
||||
}
|
||||
else if (UserConfigParams::m_multitouch_accelerometer == 2)
|
||||
{
|
||||
button->axis_x = event.AccelerometerEvent.Y / 5.0f;
|
||||
device->handleControls(button);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// block events in all modes but initial menus (except in text boxes to
|
||||
// allow typing, and except in modal dialogs in-game)
|
||||
|
@ -36,6 +36,11 @@ MultitouchDevice::MultitouchDevice()
|
||||
m_type = DT_MULTITOUCH;
|
||||
m_name = "Multitouch";
|
||||
m_player = NULL;
|
||||
#ifdef ANDROID
|
||||
m_android_device = dynamic_cast<CIrrDeviceAndroid*>(
|
||||
irr_driver->getDevice());
|
||||
assert(m_android_device != NULL);
|
||||
#endif
|
||||
|
||||
for (MultitouchEvent& event : m_events)
|
||||
{
|
||||
@ -53,6 +58,13 @@ MultitouchDevice::MultitouchDevice()
|
||||
*/
|
||||
MultitouchDevice::~MultitouchDevice()
|
||||
{
|
||||
#ifdef ANDROID
|
||||
if (m_android_device->isAccelerometerActive())
|
||||
{
|
||||
m_android_device->deactivateAccelerometer();
|
||||
}
|
||||
#endif
|
||||
|
||||
clearButtons();
|
||||
}
|
||||
|
||||
@ -177,8 +189,7 @@ void MultitouchDevice::updateDeviceState(unsigned int event_id)
|
||||
{
|
||||
button->pressed = false;
|
||||
button->event_id = 0;
|
||||
button->axis_x = 0.0f;
|
||||
button->axis_y = 0.0f;
|
||||
updateButtonAxes(button, 0.0f, 0.0f);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -190,15 +201,13 @@ void MultitouchDevice::updateDeviceState(unsigned int event_id)
|
||||
{
|
||||
if (button->pressed == true)
|
||||
{
|
||||
button->axis_x = (float)(event.x - button->x) /
|
||||
(button->width/2) - 1;
|
||||
button->axis_y = (float)(event.y - button->y) /
|
||||
(button->height/2) - 1;
|
||||
updateButtonAxes(button,
|
||||
(float)(event.x - button->x) / (button->width/2) - 1,
|
||||
(float)(event.y - button->y) / (button->height/2) - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
button->axis_x = 0.0f;
|
||||
button->axis_y = 0.0f;
|
||||
updateButtonAxes(button, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
if (prev_axis_x != button->axis_x ||
|
||||
@ -232,6 +241,25 @@ void MultitouchDevice::updateConfigParams()
|
||||
|
||||
m_deadzone_edge = UserConfigParams::m_multitouch_deadzone_edge;
|
||||
m_deadzone_edge = std::min(std::max(m_deadzone_edge, 0.0f), 0.5f);
|
||||
|
||||
#ifdef ANDROID
|
||||
if (UserConfigParams::m_multitouch_accelerometer > 0 &&
|
||||
!m_android_device->isAccelerometerActive())
|
||||
{
|
||||
m_android_device->activateAccelerometer(1.0f / 30);
|
||||
|
||||
// Disable accelerometer if it couldn't be activated
|
||||
if (!m_android_device->isAccelerometerActive())
|
||||
{
|
||||
UserConfigParams::m_multitouch_accelerometer = 0;
|
||||
}
|
||||
}
|
||||
else if (UserConfigParams::m_multitouch_accelerometer == 0 &&
|
||||
m_android_device->isAccelerometerActive())
|
||||
{
|
||||
m_android_device->deactivateAccelerometer();
|
||||
}
|
||||
#endif
|
||||
} // updateConfigParams
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -249,6 +277,26 @@ float MultitouchDevice::getSteeringFactor(float value)
|
||||
m_deadzone_center), 1.0f);
|
||||
}
|
||||
|
||||
/** Updates the button axes. It leaves X axis untouched if the accelerometer is
|
||||
* used for turning left/right
|
||||
* \param button A button that should be updated
|
||||
* \param x A value from 0 to 1
|
||||
* \param y A value from 0 to 1
|
||||
*/
|
||||
void MultitouchDevice::updateButtonAxes(MultitouchButton* button, float x,
|
||||
float y)
|
||||
{
|
||||
if (UserConfigParams::m_multitouch_accelerometer == 0)
|
||||
{
|
||||
button->axis_x = x;
|
||||
}
|
||||
|
||||
button->axis_y = y;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Sends proper action for player controller depending on the button type
|
||||
* and state.
|
||||
|
@ -25,6 +25,10 @@
|
||||
#include "input/input_device.hpp"
|
||||
#include "IEventReceiver.h"
|
||||
|
||||
#ifdef ANDROID
|
||||
#include "../../../lib/irrlicht/source/Irrlicht/CIrrDeviceAndroid.h"
|
||||
#endif
|
||||
|
||||
#define NUMBER_OF_MULTI_TOUCHES 10
|
||||
|
||||
enum MultitouchButtonType
|
||||
@ -77,8 +81,14 @@ private:
|
||||
/** The parameter that is used for steering button and determines dead area
|
||||
* at the edge of button */
|
||||
float m_deadzone_edge;
|
||||
|
||||
#ifdef ANDROID
|
||||
/** Pointer to the Android irrlicht device */
|
||||
CIrrDeviceAndroid* m_android_device;
|
||||
#endif
|
||||
|
||||
float getSteeringFactor(float value);
|
||||
void updateButtonAxes(MultitouchButton* button, float x, float y);
|
||||
|
||||
public:
|
||||
/** The array that contains data for all multitouch input events */
|
||||
|
498
src/io/assets_android.cpp
Normal file
@ -0,0 +1,498 @@
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2014-2015 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.
|
||||
|
||||
#include "graphics/irr_driver.hpp"
|
||||
#include "io/assets_android.hpp"
|
||||
#include "io/file_manager.hpp"
|
||||
#include "utils/log.hpp"
|
||||
#include "utils/progress_bar_android.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
|
||||
#ifdef ANDROID
|
||||
#include <android/asset_manager.h>
|
||||
#include <sys/statfs.h>
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Assets Android constructor
|
||||
*/
|
||||
AssetsAndroid::AssetsAndroid(FileManager* file_manager)
|
||||
{
|
||||
m_file_manager = file_manager;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** A function that detects a path where data directory is placed and that
|
||||
* sets some environment variables that are used for finding data and
|
||||
* home directory in a common code.
|
||||
*/
|
||||
void AssetsAndroid::init()
|
||||
{
|
||||
#ifdef ANDROID
|
||||
if (m_file_manager == NULL)
|
||||
return;
|
||||
|
||||
bool needs_extract_data = false;
|
||||
const std::string version = std::string("supertuxkart.") + STK_VERSION;
|
||||
|
||||
// Add some paths to check
|
||||
std::vector<std::string> paths;
|
||||
|
||||
if (getenv("SUPERTUXKART_DATADIR"))
|
||||
paths.push_back(getenv("SUPERTUXKART_DATADIR"));
|
||||
|
||||
if (getenv("EXTERNAL_STORAGE"))
|
||||
paths.push_back(getenv("EXTERNAL_STORAGE"));
|
||||
|
||||
if (getenv("SECONDARY_STORAGE"))
|
||||
paths.push_back(getenv("SECONDARY_STORAGE"));
|
||||
|
||||
if (global_android_app->activity->externalDataPath)
|
||||
paths.push_back(global_android_app->activity->externalDataPath);
|
||||
|
||||
if (global_android_app->activity->internalDataPath)
|
||||
paths.push_back(global_android_app->activity->internalDataPath);
|
||||
|
||||
paths.push_back("/sdcard/");
|
||||
paths.push_back("/storage/sdcard0/");
|
||||
paths.push_back("/storage/sdcard1/");
|
||||
paths.push_back("/data/data/org.supertuxkart.stk/files/");
|
||||
|
||||
// Check if STK data is available somewhere
|
||||
for (std::string path : paths)
|
||||
{
|
||||
Log::info("AssetsAndroid", "Check data files in: %s", path.c_str());
|
||||
|
||||
if (m_file_manager->fileExists(path + "/stk/data/" + version))
|
||||
{
|
||||
Log::info("AssetsAndroid", "Data files found in: %s", path.c_str());
|
||||
m_stk_dir = path + "/stk";
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_file_manager->fileExists(path + "/supertuxkart/data/" + version))
|
||||
{
|
||||
Log::info("AssetsAndroid", "Data files found in: %s", path.c_str());
|
||||
m_stk_dir = path + "/supertuxkart";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Create data dir if it's not available anywhere
|
||||
if (m_stk_dir.size() == 0)
|
||||
{
|
||||
std::string preferred_path = getPreferredPath(paths);
|
||||
|
||||
if (preferred_path.length() > 0)
|
||||
{
|
||||
if (m_file_manager->checkAndCreateDirectoryP(preferred_path +
|
||||
"/stk/data"))
|
||||
{
|
||||
Log::info("AssetsAndroid", "Data directory created in: %s",
|
||||
preferred_path.c_str());
|
||||
m_stk_dir = preferred_path + "/stk";
|
||||
needs_extract_data = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If getPreferredPath failed for some reason, then try to use the first
|
||||
// available path
|
||||
if (m_stk_dir.size() == 0)
|
||||
{
|
||||
for (std::string path : paths)
|
||||
{
|
||||
if (m_file_manager->checkAndCreateDirectoryP(path + "/stk/data"))
|
||||
{
|
||||
Log::info("AssetsAndroid", "Data directory created in: %s",
|
||||
path.c_str());
|
||||
m_stk_dir = path + "/stk";
|
||||
needs_extract_data = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We can't continue if STK dir has not been found
|
||||
if (m_stk_dir.size() == 0)
|
||||
{
|
||||
Log::fatal("AssetsAndroid", "Fatal error: Couldn't find Supertuxkart "
|
||||
"data directory");
|
||||
}
|
||||
|
||||
// Check if assets were extracted properly
|
||||
if (!m_file_manager->fileExists(m_stk_dir + "/.extracted") &&
|
||||
!needs_extract_data)
|
||||
{
|
||||
needs_extract_data = true;
|
||||
Log::warn("AssetsAndroid", "Assets seem to be not extracted properly, "
|
||||
"because the .extracted file doesn't exist. Force "
|
||||
"extracting assets...");
|
||||
}
|
||||
|
||||
if (!m_file_manager->checkAndCreateDirectoryP(m_stk_dir + "/home"))
|
||||
{
|
||||
Log::warn("AssetsAndroid", "Couldn't create home directory");
|
||||
}
|
||||
|
||||
// Set some useful variables
|
||||
setenv("SUPERTUXKART_DATADIR", m_stk_dir.c_str(), 1);
|
||||
setenv("HOME", (m_stk_dir + "/home").c_str(), 1);
|
||||
setenv("XDG_CONFIG_HOME", (m_stk_dir + "/home").c_str(), 1);
|
||||
|
||||
// Extract data directory from apk if it's needed
|
||||
if (needs_extract_data)
|
||||
{
|
||||
removeData();
|
||||
extractData();
|
||||
|
||||
if (!m_file_manager->fileExists(m_stk_dir + "/.extracted"))
|
||||
{
|
||||
Log::fatal("AssetsAndroid", "Fatal error: Assets were not "
|
||||
"extracted properly");
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** A function that extracts whole data directory from apk file to a real
|
||||
* path in the filesystem
|
||||
*/
|
||||
void AssetsAndroid::extractData()
|
||||
{
|
||||
#ifdef ANDROID
|
||||
const std::string dirs_list = "directories.txt";
|
||||
|
||||
bool success = true;
|
||||
|
||||
// Create .nomedia file
|
||||
touchFile(m_stk_dir + "/.nomedia");
|
||||
|
||||
// Extract base directory first, so that we will be able to open the file
|
||||
// with dir names
|
||||
success = extractDir("");
|
||||
|
||||
if (!success)
|
||||
{
|
||||
Log::error("AssetsAndroid", "Error: Couldn't extract main directory.");
|
||||
return;
|
||||
}
|
||||
|
||||
std::fstream file(m_stk_dir + "/" + dirs_list, std::ios::in);
|
||||
|
||||
if (file.good())
|
||||
{
|
||||
unsigned int lines_count = 0;
|
||||
|
||||
while (!file.eof())
|
||||
{
|
||||
std::string dir_name;
|
||||
getline(file, dir_name);
|
||||
|
||||
if (dir_name.length() == 0 || dir_name.at(0) == '#')
|
||||
continue;
|
||||
|
||||
lines_count++;
|
||||
}
|
||||
|
||||
if (lines_count > 0)
|
||||
{
|
||||
file.clear();
|
||||
file.seekg(0, std::ios::beg);
|
||||
|
||||
ProgressBarAndroid* progress_bar = new ProgressBarAndroid();
|
||||
progress_bar->draw(0.0f);
|
||||
unsigned int current_line = 1;
|
||||
|
||||
while (!file.eof())
|
||||
{
|
||||
std::string dir_name;
|
||||
getline(file, dir_name);
|
||||
|
||||
if (dir_name.length() == 0 || dir_name.at(0) == '#')
|
||||
continue;
|
||||
|
||||
success = extractDir(dir_name);
|
||||
|
||||
assert(lines_count > 0);
|
||||
progress_bar->draw((float)(current_line) / lines_count);
|
||||
current_line++;
|
||||
|
||||
if (progress_bar->closeEventReceived())
|
||||
{
|
||||
success = false;
|
||||
}
|
||||
|
||||
if (!success)
|
||||
break;
|
||||
}
|
||||
|
||||
delete progress_bar;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::warn("AssetsAndroid", "Warning: Cannot open %s file. Ignoring "
|
||||
"extraction of other directories.", dirs_list.c_str());
|
||||
}
|
||||
|
||||
file.close();
|
||||
|
||||
// Mark the extraction as successful if everything is ok
|
||||
if (success)
|
||||
{
|
||||
touchFile(m_stk_dir + "/.extracted");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** A function that extracts selected directory from apk file
|
||||
* \param dir_name Directory to extract from assets
|
||||
* \return True if successfully extracted
|
||||
*/
|
||||
bool AssetsAndroid::extractDir(std::string dir_name)
|
||||
{
|
||||
#ifdef ANDROID
|
||||
AAssetManager* amgr = global_android_app->activity->assetManager;
|
||||
|
||||
Log::info("AssetsAndroid", "Extracting %s directory",
|
||||
dir_name.length() > 0 ? dir_name.c_str() : "main");
|
||||
|
||||
std::string output_dir = dir_name;
|
||||
|
||||
if (m_stk_dir.length() > 0)
|
||||
{
|
||||
output_dir = m_stk_dir + "/" + dir_name;
|
||||
}
|
||||
|
||||
AAssetDir* asset_dir = AAssetManager_openDir(amgr, dir_name.c_str());
|
||||
|
||||
if (asset_dir == NULL)
|
||||
{
|
||||
Log::warn("AssetsAndroid", "Couldn't get asset dir: %s",
|
||||
dir_name.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!m_file_manager->checkAndCreateDirectoryP(output_dir))
|
||||
{
|
||||
Log::warn("AssetsAndroid", "Couldn't create %s directory",
|
||||
output_dir.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
const int buf_size = 65536;
|
||||
char* buf = new char[buf_size]();
|
||||
bool extraction_failed = false;
|
||||
|
||||
while (!extraction_failed)
|
||||
{
|
||||
const char* filename = AAssetDir_getNextFileName(asset_dir);
|
||||
|
||||
// Check if finished
|
||||
if (filename == NULL)
|
||||
break;
|
||||
|
||||
if (strlen(filename) == 0)
|
||||
continue;
|
||||
|
||||
std::string file_path = std::string(filename);
|
||||
|
||||
if (dir_name.length() > 0)
|
||||
{
|
||||
file_path = dir_name + "/" + std::string(filename);
|
||||
}
|
||||
|
||||
AAsset* asset = AAssetManager_open(amgr, file_path.c_str(),
|
||||
AASSET_MODE_STREAMING);
|
||||
|
||||
if (asset == NULL)
|
||||
{
|
||||
Log::warn("AssetsAndroid", "Asset is null: %s", filename);
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string output_path = output_dir + "/" + std::string(filename);
|
||||
std::fstream out_file(output_path, std::ios::out | std::ios::binary);
|
||||
|
||||
if (!out_file.good())
|
||||
{
|
||||
extraction_failed = true;
|
||||
Log::error("AssetsAndroid", "Couldn't create a file: %s", filename);
|
||||
AAsset_close(asset);
|
||||
break;
|
||||
}
|
||||
|
||||
int nb_read = 0;
|
||||
while ((nb_read = AAsset_read(asset, buf, buf_size)) > 0)
|
||||
{
|
||||
out_file.write(buf, nb_read);
|
||||
|
||||
if (out_file.fail())
|
||||
{
|
||||
extraction_failed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
out_file.close();
|
||||
|
||||
if (out_file.fail() || extraction_failed)
|
||||
{
|
||||
extraction_failed = true;
|
||||
Log::error("AssetsAndroid", "Extraction failed for file: %s",
|
||||
filename);
|
||||
}
|
||||
|
||||
AAsset_close(asset);
|
||||
}
|
||||
|
||||
delete[] buf;
|
||||
|
||||
AAssetDir_close(asset_dir);
|
||||
|
||||
return !extraction_failed;
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** A function that removes whole STK data directory
|
||||
*/
|
||||
void AssetsAndroid::removeData()
|
||||
{
|
||||
#ifdef ANDROID
|
||||
if (m_stk_dir.length() == 0)
|
||||
return;
|
||||
|
||||
// Make sure that we are not accidentally removing wrong directory
|
||||
if (m_stk_dir.find("/stk") == std::string::npos &&
|
||||
m_stk_dir.find("/supertuxkart") == std::string::npos)
|
||||
{
|
||||
Log::error("AssetsAndroid", "Invalid data directory: %s",
|
||||
m_stk_dir.c_str());
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
std::set<std::string> files;
|
||||
m_file_manager->listFiles(files, m_stk_dir, true);
|
||||
|
||||
for (std::string file : files)
|
||||
{
|
||||
if (file == m_stk_dir + "/." || file == m_stk_dir + "/..")
|
||||
continue;
|
||||
|
||||
// Don't delete home directory that contains configuration files
|
||||
// and add-ons
|
||||
if (file == m_stk_dir + "/home")
|
||||
continue;
|
||||
|
||||
// Don't delete .nomedia file. It has a sense to keep it for home
|
||||
// directory, i.e. for textures of add-on karts etc.
|
||||
if (file == m_stk_dir + "/.nomedia")
|
||||
continue;
|
||||
|
||||
Log::info("AssetsAndroid", "Deleting file: %s\n", file.c_str());
|
||||
|
||||
if (m_file_manager->isDirectory(file))
|
||||
{
|
||||
m_file_manager->removeDirectory(file);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_file_manager->removeFile(file);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** A function that creates empty file
|
||||
* \param path A path to the file that should be created
|
||||
*/
|
||||
void AssetsAndroid::touchFile(std::string path)
|
||||
{
|
||||
#ifdef ANDROID
|
||||
if (m_file_manager->fileExists(path))
|
||||
return;
|
||||
|
||||
std::fstream file(path, std::ios::out | std::ios::binary);
|
||||
|
||||
if (!file.good())
|
||||
{
|
||||
Log::warn("AssetsAndroid", "Error: Cannot create %s file.",
|
||||
path.c_str());
|
||||
}
|
||||
|
||||
file.close();
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Determines best path for extracting assets, depending on available disk
|
||||
* space.
|
||||
* \param paths A list of paths that should be checked
|
||||
* \return Best path or empty string in case of error
|
||||
*/
|
||||
std::string AssetsAndroid::getPreferredPath(const std::vector<std::string>&
|
||||
paths)
|
||||
{
|
||||
#ifdef ANDROID
|
||||
std::string preferred_path;
|
||||
int prev_available_space = 0;
|
||||
|
||||
for (std::string path : paths)
|
||||
{
|
||||
// Paths that start with /data should be used only as a fallback if
|
||||
// everything other doesn't work, because typical user doesn't have
|
||||
// access to these directories and i.e. can't manually delete the files
|
||||
// to clean up device
|
||||
if (path.find("/data") == 0)
|
||||
continue;
|
||||
|
||||
struct statfs stat;
|
||||
|
||||
if (statfs(path.c_str(), &stat) != 0)
|
||||
continue;
|
||||
|
||||
int available_space = (int)((stat.f_bavail * stat.f_bsize) / 1000000);
|
||||
|
||||
Log::info("AssetsAndroid", "Available space in '%s': %i MB",
|
||||
path.c_str(), available_space);
|
||||
|
||||
if (available_space > prev_available_space)
|
||||
{
|
||||
preferred_path = path;
|
||||
prev_available_space = available_space;
|
||||
}
|
||||
}
|
||||
|
||||
return preferred_path;
|
||||
#endif
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
45
src/io/assets_android.hpp
Normal file
@ -0,0 +1,45 @@
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2014-2015 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.
|
||||
|
||||
#ifndef HEADER_ASSETS_ANDROID_HPP
|
||||
#define HEADER_ASSETS_ANDROID_HPP
|
||||
|
||||
#include <string>
|
||||
|
||||
class FileManager;
|
||||
|
||||
class AssetsAndroid
|
||||
{
|
||||
private:
|
||||
FileManager* m_file_manager;
|
||||
std::string m_stk_dir;
|
||||
|
||||
void extractData();
|
||||
bool extractDir(std::string dir_name);
|
||||
void removeData();
|
||||
void touchFile(std::string path);
|
||||
std::string getPreferredPath(const std::vector<std::string>& paths);
|
||||
|
||||
public:
|
||||
AssetsAndroid(FileManager* file_manager);
|
||||
~AssetsAndroid() {};
|
||||
|
||||
void init();
|
||||
};
|
||||
|
||||
|
||||
#endif
|
@ -171,10 +171,25 @@ void Attachment::set(AttachmentType type, float time,
|
||||
// by slowing down.
|
||||
if(m_type==ATTACH_PARACHUTE)
|
||||
{
|
||||
const KartProperties *kp = m_kart->getKartProperties();
|
||||
float speed_mult;
|
||||
|
||||
m_initial_speed = m_kart->getSpeed();
|
||||
// if going very slowly or backwards, braking won't remove parachute
|
||||
if(m_initial_speed <= 1.5) m_initial_speed = 1.5;
|
||||
|
||||
float f = m_initial_speed / kp->getParachuteMaxSpeed();
|
||||
float temp_mult = kp->getParachuteDurationSpeedMult();
|
||||
|
||||
// duration can't be reduced by higher speed
|
||||
if (temp_mult < 1.0f) temp_mult = 1.0f;
|
||||
|
||||
if (f > 1.0f) f = 1.0f; // cap fraction
|
||||
|
||||
speed_mult = 1.0f + (f * (temp_mult - 1.0f));
|
||||
|
||||
m_time_left = m_time_left * speed_mult;
|
||||
|
||||
if (UserConfigParams::m_graphical_effects)
|
||||
{
|
||||
// .blend was created @25 (<10 real, slow computer), make it faster
|
||||
|
@ -368,9 +368,9 @@ void Powerup::use()
|
||||
case PowerupManager::POWERUP_PARACHUTE:
|
||||
{
|
||||
AbstractKart* player_kart = NULL;
|
||||
//Attach a parachutte(that last twice as long as the
|
||||
//one from the bananas) to all the karts that
|
||||
//are in front of this one.
|
||||
//Attach a parachute(that last 1,3 time as long as the
|
||||
//one from the bananas and is affected by the rank multiplier)
|
||||
//to all the karts that are in front of this one.
|
||||
for(unsigned int i = 0 ; i < world->getNumKarts(); ++i)
|
||||
{
|
||||
AbstractKart *kart=world->getKart(i);
|
||||
@ -382,8 +382,24 @@ void Powerup::use()
|
||||
}
|
||||
if(m_kart->getPosition() > kart->getPosition())
|
||||
{
|
||||
float rank_mult, position_factor;
|
||||
//0 if the one before the item user ; 1 if first ; scaled inbetween
|
||||
if (kart->getPosition() == 1)
|
||||
{
|
||||
position_factor = 1.0f;
|
||||
}
|
||||
else //m_kart position is always >= 3
|
||||
{
|
||||
float rank_factor;
|
||||
|
||||
rank_factor = (float)(kart->getPosition() - 1) / (float)(m_kart->getPosition() - 2);
|
||||
position_factor = 1.0f - rank_factor;
|
||||
}
|
||||
|
||||
rank_mult = 1 + (position_factor * (kp->getParachuteDurationRankMult() - 1));
|
||||
|
||||
kart->getAttachment()->set(Attachment::ATTACH_PARACHUTE,
|
||||
kp->getParachuteDurationOther());
|
||||
(kp->getParachuteDurationOther() * rank_mult));
|
||||
|
||||
if(kart->getController()->isLocalPlayerController())
|
||||
player_kart = kart;
|
||||
|
@ -126,6 +126,10 @@ AbstractCharacteristic::ValueType AbstractCharacteristic::getType(
|
||||
return TYPE_FLOAT;
|
||||
case PARACHUTE_DURATION_OTHER:
|
||||
return TYPE_FLOAT;
|
||||
case PARACHUTE_DURATION_RANK_MULT:
|
||||
return TYPE_FLOAT;
|
||||
case PARACHUTE_DURATION_SPEED_MULT:
|
||||
return TYPE_FLOAT;
|
||||
case PARACHUTE_LBOUND_FRACTION:
|
||||
return TYPE_FLOAT;
|
||||
case PARACHUTE_UBOUND_FRACTION:
|
||||
@ -350,6 +354,10 @@ std::string AbstractCharacteristic::getName(CharacteristicType type)
|
||||
return "PARACHUTE_DURATION";
|
||||
case PARACHUTE_DURATION_OTHER:
|
||||
return "PARACHUTE_DURATION_OTHER";
|
||||
case PARACHUTE_DURATION_RANK_MULT:
|
||||
return "PARACHUTE_DURATION_RANK_MULT";
|
||||
case PARACHUTE_DURATION_SPEED_MULT:
|
||||
return "PARACHUTE_DURATION_SPEED_MULT";
|
||||
case PARACHUTE_LBOUND_FRACTION:
|
||||
return "PARACHUTE_LBOUND_FRACTION";
|
||||
case PARACHUTE_UBOUND_FRACTION:
|
||||
@ -926,6 +934,30 @@ float AbstractCharacteristic::getParachuteDurationOther() const
|
||||
return result;
|
||||
} // getParachuteDurationOther
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
float AbstractCharacteristic::getParachuteDurationRankMult() const
|
||||
{
|
||||
float result;
|
||||
bool is_set = false;
|
||||
process(PARACHUTE_DURATION_RANK_MULT, &result, &is_set);
|
||||
if (!is_set)
|
||||
Log::fatal("AbstractCharacteristic", "Can't get characteristic %s",
|
||||
getName(PARACHUTE_DURATION_RANK_MULT).c_str());
|
||||
return result;
|
||||
} // getParachuteDurationRankMult
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
float AbstractCharacteristic::getParachuteDurationSpeedMult() const
|
||||
{
|
||||
float result;
|
||||
bool is_set = false;
|
||||
process(PARACHUTE_DURATION_SPEED_MULT, &result, &is_set);
|
||||
if (!is_set)
|
||||
Log::fatal("AbstractCharacteristic", "Can't get characteristic %s",
|
||||
getName(PARACHUTE_DURATION_SPEED_MULT).c_str());
|
||||
return result;
|
||||
} // getParachuteDurationSpeedMult
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
float AbstractCharacteristic::getParachuteLboundFraction() const
|
||||
{
|
||||
|
@ -130,6 +130,8 @@ public:
|
||||
PARACHUTE_FRICTION,
|
||||
PARACHUTE_DURATION,
|
||||
PARACHUTE_DURATION_OTHER,
|
||||
PARACHUTE_DURATION_RANK_MULT,
|
||||
PARACHUTE_DURATION_SPEED_MULT,
|
||||
PARACHUTE_LBOUND_FRACTION,
|
||||
PARACHUTE_UBOUND_FRACTION,
|
||||
PARACHUTE_MAX_SPEED,
|
||||
@ -300,6 +302,8 @@ public:
|
||||
float getParachuteFriction() const;
|
||||
float getParachuteDuration() const;
|
||||
float getParachuteDurationOther() const;
|
||||
float getParachuteDurationRankMult() const;
|
||||
float getParachuteDurationSpeedMult() const;
|
||||
float getParachuteLboundFraction() const;
|
||||
float getParachuteUboundFraction() const;
|
||||
float getParachuteMaxSpeed() const;
|
||||
|
@ -753,6 +753,18 @@ float KartProperties::getParachuteDurationOther() const
|
||||
return m_cached_characteristic->getParachuteDurationOther();
|
||||
} // getParachuteDurationOther
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
float KartProperties::getParachuteDurationRankMult() const
|
||||
{
|
||||
return m_cached_characteristic->getParachuteDurationRankMult();
|
||||
} // getParachuteDurationRankMult
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
float KartProperties::getParachuteDurationSpeedMult() const
|
||||
{
|
||||
return m_cached_characteristic->getParachuteDurationSpeedMult();
|
||||
} // getParachuteDurationSpeedMult
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
float KartProperties::getParachuteLboundFraction() const
|
||||
{
|
||||
|