Fixed typo

This commit is contained in:
Deve 2017-01-27 22:43:49 +01:00
parent 62bcf52f9c
commit 803eba5d5c
24 changed files with 2825 additions and 1 deletions

17
.gitignore vendored
View File

@ -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
View 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)

View 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>

134
android/README.ANDROID Normal file
View File

@ -0,0 +1,134 @@
================================================================================
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. Explosion effect has poor performance and causes fps drop for a while.
Though it can be easily tweaked, so that less particles per second is
generated.
5. Touch steering needs nice button icons.
6. 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
7. STK crashes on Qualcomm with Adreno 305 when trying to draw menu interface.
Backtrace shows glDrawElements function, and internally crashed in vbo
allocation.
8. 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.
9. Angelscript doesn't have full support for aarch64 builds, so that scripting
won't work on this platform.
10. Steering with accelerometer is not available yet. It needs some work to do
it properly because tablets have different screen orientation than phones,
so that they receive events from different axies during rotating the device.
As far as I see it's not possible to read default screen orientation using
NDK functions.

6
android/build.xml Normal file
View 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
View 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
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">SuperTuxKart</string>
</resources>

View 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} "")

View File

@ -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

View 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

View 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__

View File

@ -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

View File

@ -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")

433
src/io/assets_android.cpp Normal file
View File

@ -0,0 +1,433 @@
// 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>
#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)
{
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
}
//-----------------------------------------------------------------------------

44
src/io/assets_android.hpp Normal file
View File

@ -0,0 +1,44 @@
// 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);
public:
AssetsAndroid(FileManager* file_manager);
~AssetsAndroid() {};
void init();
};
#endif

62
src/main_android.cpp Normal file
View File

@ -0,0 +1,62 @@
#ifdef ANDROID
#include "config/user_config.hpp"
#include "graphics/irr_driver.hpp"
#include "utils/log.hpp"
extern int main(int argc, char *argv[]);
void override_default_params()
{
// It has an effect only on the first run, when config file is created.
// So that we can still modify these params in STK options and user's
// choice will be then remembered.
// Set smaller texture size to avoid high RAM usage
UserConfigParams::m_max_texture_size = 256;
UserConfigParams::m_high_definition_textures = false;
// Disable advanced lighting by default to make the game playable
UserConfigParams::m_dynamic_lights = false;
// Enable touch steering and screen keyboard
UserConfigParams::m_multitouch_enabled = true;
UserConfigParams::m_screen_keyboard = true;
// It shouldn't matter, but STK is always run in fullscreen on android
UserConfigParams::m_fullscreen = true;
// Make sure that user can play every track even if there are installed
// only few tracks and it's impossible to finish overworld challenges
UserConfigParams::m_everything_unlocked = true;
// Create default user istead of showing login screen to make life easier
UserConfigParams::m_enforce_current_player = true;
// Just for debugging
UserConfigParams::m_log_errors_to_console = true;
}
void android_main(struct android_app* app)
{
Log::info("AndroidMain", "Loading application...");
app_dummy();
override_default_params();
global_android_app = app;
main(0, {});
Log::info("AndroidMain", "Closing STK...");
// TODO: Irrlicht device is properly waiting for destroy event, but
// some global variables are not initialized/cleared in functions and thus
// its state is remembered when the window is restored. We will use exit
// call to make sure that all variables are cleared until a proper fix will
// be done.
exit(0);
}
#endif

View File

@ -0,0 +1,205 @@
// 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 "config/user_config.hpp"
#include "graphics/irr_driver.hpp"
#include "utils/log.hpp"
#include "utils/progress_bar_android.hpp"
#ifdef ANDROID
ProgressBarAndroid::ProgressBarAndroid()
{
m_program = 0;
m_vertex_shader = 0;
m_fragment_shader = 0;
m_position = 0;
m_progress = 0;
m_vbo = 0;
m_device = NULL;
m_initialized = false;
m_close_event_received = false;
init();
}
ProgressBarAndroid::~ProgressBarAndroid()
{
close();
}
bool ProgressBarAndroid::compileShaders()
{
const GLchar* vsh =
"precision mediump float;"
"attribute vec2 position;"
"uniform float progress;"
"void main(void)"
"{"
" float pos_x = (position.x + 1.0) * progress - 1.0;"
" float pos_y = position.y * 0.1 - 0.6;"
" gl_Position = vec4(pos_x, pos_y, 0.0, 1.0);"
"}";
const GLchar* fsh =
"precision mediump float;"
"void main(void)"
"{"
" gl_FragColor = vec4(0.5, 0.5, 0.5, 1.0);"
"}";
m_vertex_shader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(m_vertex_shader, 1, &vsh, NULL);
glCompileShader(m_vertex_shader);
GLint success;
glGetShaderiv(m_vertex_shader, GL_COMPILE_STATUS, &success);
if (!success)
{
Log::error("ProgressBarAndroid", "Failed to compile vertex shader.");
return false;
}
m_fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(m_fragment_shader, 1, &fsh, NULL);
glCompileShader(m_fragment_shader);
glGetShaderiv(m_fragment_shader, GL_COMPILE_STATUS, &success);
if (!success)
{
Log::error("ProgressBarAndroid", "Failed to compile fragment shader.");
return false;
}
m_program = glCreateProgram();
glAttachShader(m_program, m_vertex_shader);
glAttachShader(m_program, m_fragment_shader);
glLinkProgram(m_program);
glGetProgramiv(m_program, GL_LINK_STATUS, &success);
if (!success)
{
Log::error("ProgressBarAndroid", "Failed to link program.");
return false;
}
m_position = glGetAttribLocation(m_program, "position");
if (m_position == -1)
{
Log::error("ProgressBarAndroid", "Failed to get attrib location.");
return false;
}
m_progress = glGetUniformLocation(m_program, "progress");
if (m_progress == -1)
{
Log::error("ProgressBarAndroid", "Failed to get uniform location.");
return false;
}
return true;
}
void ProgressBarAndroid::deleteShaders()
{
glDeleteShader(m_vertex_shader);
glDeleteShader(m_fragment_shader);
glDeleteProgram(m_program);
}
void ProgressBarAndroid::init()
{
SIrrlichtCreationParameters params;
params.DriverType = video::EDT_OGLES2;
params.Bits = 32;
params.Fullscreen = UserConfigParams::m_fullscreen;
params.WindowSize = core::dimension2du(640, 480);
#if defined(ANDROID)
params.PrivateData = (void*)global_android_app;
#endif
m_device = createDeviceEx(params);
if (!m_device)
return;
bool success = compileShaders();
if (!success)
return;
const GLfloat vertices[] =
{
-1, 1, 1, -1, -1, -1,
1, -1, -1, 1, 1, 1
};
glGenBuffers(1, &m_vbo);
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glUseProgram(m_program);
glEnableVertexAttribArray(m_position);
glVertexAttribPointer(m_position, 2, GL_FLOAT, GL_FALSE, 0, 0);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
m_initialized = true;
}
void ProgressBarAndroid::close()
{
glDisableVertexAttribArray(m_position);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glUseProgram(0);
deleteShaders();
if (m_device != NULL)
{
m_device->closeDevice();
m_device->clearSystemMessages();
m_device->run();
m_device->drop();
m_device = NULL;
}
m_initialized = false;
}
void ProgressBarAndroid::draw(float value)
{
if (!m_initialized || m_close_event_received)
return;
value = value > 1.0f ? 1.0f : value;
m_close_event_received = !m_device->run();
m_device->getVideoDriver()->beginScene(true, true);
glClear(GL_COLOR_BUFFER_BIT);
glUniform1f(m_progress, value);
glDrawArrays(GL_TRIANGLES, 0, 6);
m_device->getVideoDriver()->endScene();
}
#endif

View File

@ -0,0 +1,55 @@
// 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_PROGRESS_BAR_ANDROID_HPP
#define HEADER_PROGRESS_BAR_ANDROID_HPP
#ifdef ANDROID
#include "IrrlichtDevice.h"
#include "graphics/gl_headers.hpp"
class ProgressBarAndroid
{
private:
GLuint m_program;
GLuint m_vertex_shader;
GLuint m_fragment_shader;
GLint m_position;
GLint m_progress;
GLuint m_vbo;
irr::IrrlichtDevice* m_device;
bool m_initialized;
bool m_close_event_received;
bool compileShaders();
void deleteShaders();
void init();
void close();
public:
ProgressBarAndroid();
~ProgressBarAndroid();
void draw(float value);
bool closeEventReceived() {return m_close_event_received;}
};
#endif
#endif