30 Commits

Author SHA1 Message Date
Gerhard Stein
d480cc0484 Bump CG 2021-06-19 18:10:58 +00:00
Gerhard Stein
5b4e368938 CG Update 2021-03-27 18:43:26 +00:00
Gerhard Stein
a2285e949c Updated Commander Genius 2020-10-29 19:10:31 +00:00
Gerhard Stein
c50c43db6f Bump Version 2.6.1 2020-10-16 17:09:57 +00:00
Gerhard Stein
7566e05ee6 Updated Commander Genius 2020-10-15 13:48:35 +00:00
Gerhard Stein
39d55b5d19 code fix 2020-10-11 19:25:53 +00:00
Gerhard Stein
fed2b2469b Updated CG, and added a request permission 2020-10-11 19:22:39 +00:00
Gerhard Stein
d2c77299ff Using static curl and openssl. 2020-10-10 16:48:23 +00:00
Gerhard Stein
57a23c6a56 Adding proper app icon 2020-10-10 07:13:46 +00:00
Gerhard Stein
315dec4b42 Better Template File for SDL2 so the SDL2 can be replaced by a newer version at any time 2020-10-10 06:36:22 +00:00
Gerhard Stein
ec0b9d5ebe Use Virtualpad option added for android builds 2020-10-09 17:23:14 +00:00
Gerhard Stein
61ec755987 More stuff starting to work on CG and SDL 2.0 2020-10-09 17:20:17 +00:00
Gerhard Stein
4a82d315d5 Enabled Commander Genius fully using SDL2. 2020-10-09 14:41:09 +00:00
Gerhard Stein
0ce5f5dee3 SDL 2.0 does not require an icon as external file anymore. So fewer android permission are required for playing that 2020-10-09 14:39:50 +00:00
Gerhard Stein
99393e2dbe SDL2 test application finally, running, but still crashes, for a not found file. Meh. 2020-10-04 19:34:12 +00:00
Gerhard Stein
17c547a43f SDL2 Test updates 2020-10-04 11:52:43 +00:00
Gerhard Stein
d611b7655b Updated javaSDL2 2020-10-04 10:19:21 +00:00
Gerhard Stein
a0bded0cce c++ must be enabled for sdl2, because hid api implementation uses some c++ code. 2020-10-03 12:00:58 +00:00
Gerhard Stein
015fb7ad45 Blacklisting for projects which do not work with SDL2 2020-10-03 11:04:21 +00:00
Gerhard Stein
d0558f22d9 Cleanups 2020-10-03 10:37:24 +00:00
Gerhard Stein
32046e051c More target names changes 2020-10-03 10:28:18 +00:00
Gerhard Stein
487062dd11 Using proper official target name 2020-10-03 10:25:22 +00:00
Gerhard Stein
4741fe77bb Added SDL2_mixer 2020-10-03 09:49:54 +00:00
Gerhard Stein
d9267a1653 Updated Sprite minimal test 2020-10-03 09:42:01 +00:00
Gerhard Stein
9fd75f119e Renaming SDL test code 2020-10-03 09:35:53 +00:00
Gerhard Stein
6962dd59fa Added Blacklist feature for SDL2 stuff 2020-09-29 16:40:03 +00:00
Gerhard Stein
99effe98c4 Setting CG using SDL2 2020-09-28 15:32:01 +00:00
Gerhard Stein
712e3b1624 Added case for SDL2, reduction of base libs 2020-09-28 15:31:27 +00:00
Gerhard Stein
817c0ac596 Updated SDL2_Image 2020-09-28 16:43:02 +02:00
Gerhard Stein
2ecfbd1189 Updated SDL2 2020-09-28 16:41:30 +02:00
15056 changed files with 6104938 additions and 16240 deletions

View File

@@ -1,7 +0,0 @@
root = true
[*]
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = tab
charset = utf-8

View File

@@ -1,156 +0,0 @@
# Copyright (C) 2021-2021 Sergii Pylypenko <x.pelya.x@gmail.com>
#
# This software is provided 'as-is', without any express or implied
# warranty. In no event will the authors be held liable for any damages
# arising from the use of this software.
#
# Permission is granted to anyone to use this software for any purpose,
# including commercial applications, and to alter it and redistribute it
# freely, subject to the following restrictions:
#
# 1. The origin of this software must not be misrepresented; you must not
# claim that you wrote the original software. If you use this software
# in a product, an acknowledgment in the product documentation would be
# appreciated but is not required.
# 2. Altered source versions must be plainly marked as such, and must not be
# misrepresented as being the original software.
# 3. This notice may not be removed or altered from any source distribution.
name: ballfield
on:
push:
branches:
- '*'
tags:
- '*'
pull_request: {}
jobs:
build:
env:
APP_NAME: ballfield
# It takes one hour per one architecture to build Boost and ICU libraries, and Github limits CI script duration to 6 hours
ARCH_LIST: armeabi-v7a arm64-v8a x86 x86_64
runs-on: ubuntu-latest
steps:
- name: Check out the repository
uses: actions/checkout@v2
with:
fetch-depth: 1
submodules: false
- name: Check out submodules
# There are many more submodules in this repo, we don't need them all
run: >
git submodule update --init --recursive --depth=1
project/jni/boost/src project/jni/iconv/src
project/jni/sdl2 project/jni/sdl2_image
project/jni/sdl2_mixer project/jni/sdl2_ttf
- name: Symlink the application dir
run: |
ln -s ${APP_NAME} project/jni/application/src
- name: Set architectures list
run: |
sed -i "s/MultiABI=.*/MultiABI='${ARCH_LIST}'/g" project/jni/application/src/AndroidAppSettings.cfg
# - name: Get Boost revision
# id: boost-rev
# run: echo "::set-output name=BOOST_REV::`git -C project/jni/boost/src rev-parse HEAD`"
#
# - name: Get ICU revision
# id: icu-rev
# run: echo "::set-output name=ICU_REV::`git -C project/jni/iconv/src rev-parse HEAD`"
#
# - name: Copy Boost libraries from cache
# uses: actions/cache@v2
# id: cache-boost
# with:
# # The same SDL revision will produce the same libraries
# key: ${{steps.boost-rev.outputs.BOOST_REV}}
# path: |
# build-android/project/jni/boost/include
# build-android/project/jni/boost/lib
#
# - name: Copy ICU libraries from cache
# uses: actions/cache@v2
# id: cache-icu
# with:
# # The same SDL revision will produce the same libraries
# key: ${{steps.icu-rev.outputs.ICU_REV}}
# path: |
# build-android/project/jni/iconv/include
# build-android/project/jni/iconv/lib
# build-android/project/jni/icuuc/include
# build-android/project/jni/icuuc/lib
#
# - name: Touch cached Boost timestamps
# if: steps.cache-boost.outputs.cache-hit == 'true' || steps.cache-icu.outputs.cache-hit == 'true'
# working-directory: build-android
# run: touch project/jni/boost/lib/*/* || true
#
# - name: Touch cached ICU timestamps
# if: steps.cache-boost.outputs.cache-hit == 'true' || steps.cache-icu.outputs.cache-hit == 'true'
# working-directory: build-android
# run: touch project/jni/iconv/lib/*/* project/jni/icuuc/lib/*/* || true
- name: Patch Java files and build Boost, ICU, and OpenSSL
run: |
export PATH=$ANDROID_NDK_LATEST_HOME:$PATH
./changeAppSettings.sh
- name: Set up Gradle and Android SDK licenses
working-directory: project
run: |
for Y in `seq 20`; do echo y; done | sudo $ANDROID_SDK_ROOT/cmdline-tools/latest/bin/sdkmanager --licenses
./gradlew assembleRelease || true
for Y in `seq 20`; do echo y; done | sudo $ANDROID_SDK_ROOT/cmdline-tools/latest/bin/sdkmanager --licenses --sdk_root=`pwd`
mkdir -p $HOME/.android
keytool -genkey -v -keystore $HOME/.android/debug.keystore -storepass android -alias androiddebugkey -keypass android -keyalg RSA -keysize 2048 -validity 10000 -dname "CN=Debug, OU=Debug, O=Debug, L=Debug, ST=Debug, C=Debug"
echo "sdk.dir=$ANDROID_SDK_ROOT" > local.properties
echo "proguard.config=proguard.cfg;proguard-local.cfg" >> local.properties
- name: Hyper turbo build script GOOOOOOOOOOOO
run: |
export PATH=$ANDROID_NDK_LATEST_HOME:$ANDROID_SDK_ROOT/build-tools/31.0.0:$PATH
./build.sh
- name: App signing keys
run: |
echo "$ANDROID_KEYSTORE_B64" | base64 -d > keystore.jks || true
echo "$ANDROID_UPLOAD_KEYSTORE_B64" | base64 -d > upload_keystore.jks || true
find keystore.jks -empty -delete || true
find upload_keystore.jks -empty -delete || true
env:
ANDROID_KEYSTORE_B64: "${{secrets.ANDROID_KEYSTORE_B64}}"
ANDROID_UPLOAD_KEYSTORE_B64: "${{secrets.ANDROID_UPLOAD_KEYSTORE_B64}}"
- name: Package
run: |
export PATH=$ANDROID_NDK_LATEST_HOME:$ANDROID_SDK_ROOT/build-tools/31.0.0:$PATH
if [ -e keystore.jks ]; then
export ANDROID_KEYSTORE_FILE=`pwd`/keystore.jks
fi
if [ -e upload_keystore.jks ]; then
export ANDROID_UPLOAD_KEYSTORE_FILE=`pwd`/upload_keystore.jks
fi
mkdir -p upload/
./sign.sh
mv *.apk upload/
./signBundle.sh
mv *.aab upload/
env:
ANDROID_KEYSTORE_PASS: "${{secrets.ANDROID_KEYSTORE_PASS}}"
ANDROID_KEYSTORE_ALIAS: "${{secrets.ANDROID_KEYSTORE_ALIAS}}"
ANDROID_UPLOAD_KEYSTORE_PASS: "${{secrets.ANDROID_UPLOAD_KEYSTORE_PASS}}"
ANDROID_UPLOAD_KEYSTORE_ALIAS: "${{secrets.ANDROID_UPLOAD_KEYSTORE_ALIAS}}"
# Github actions is dumb and won't let you download single files from artifacts, so break up the artifacts instead
- uses: actions/upload-artifact@v2
with:
name: ${{env.APP_NAME}}
path: upload
if-no-files-found: error

View File

@@ -1,156 +0,0 @@
# Copyright (C) 2021-2021 Sergii Pylypenko <x.pelya.x@gmail.com>
#
# This software is provided 'as-is', without any express or implied
# warranty. In no event will the authors be held liable for any damages
# arising from the use of this software.
#
# Permission is granted to anyone to use this software for any purpose,
# including commercial applications, and to alter it and redistribute it
# freely, subject to the following restrictions:
#
# 1. The origin of this software must not be misrepresented; you must not
# claim that you wrote the original software. If you use this software
# in a product, an acknowledgment in the product documentation would be
# appreciated but is not required.
# 2. Altered source versions must be plainly marked as such, and must not be
# misrepresented as being the original software.
# 3. This notice may not be removed or altered from any source distribution.
name: sdl2-demo
on:
push:
branches:
- '*'
tags:
- '*'
pull_request: {}
jobs:
build:
env:
APP_NAME: sdl2-demo
# It takes one hour per one architecture to build Boost and ICU libraries, and Github limits CI script duration to 6 hours
ARCH_LIST: armeabi-v7a arm64-v8a x86 x86_64
runs-on: ubuntu-latest
steps:
- name: Check out the repository
uses: actions/checkout@v2
with:
fetch-depth: 1
submodules: false
- name: Check out submodules
# There are many more submodules in this repo, we don't need them all
run: >
git submodule update --init --recursive --depth=1
project/jni/boost/src project/jni/iconv/src
project/jni/sdl2 project/jni/sdl2_image
project/jni/sdl2_mixer project/jni/sdl2_ttf
- name: Symlink the application dir
run: |
ln -s ${APP_NAME} project/jni/application/src
- name: Set architectures list
run: |
sed -i "s/MultiABI=.*/MultiABI='${ARCH_LIST}'/g" project/jni/application/src/AndroidAppSettings.cfg
# - name: Get Boost revision
# id: boost-rev
# run: echo "::set-output name=BOOST_REV::`git -C project/jni/boost/src rev-parse HEAD`"
#
# - name: Get ICU revision
# id: icu-rev
# run: echo "::set-output name=ICU_REV::`git -C project/jni/iconv/src rev-parse HEAD`"
#
# - name: Copy Boost libraries from cache
# uses: actions/cache@v2
# id: cache-boost
# with:
# # The same SDL revision will produce the same libraries
# key: ${{steps.boost-rev.outputs.BOOST_REV}}
# path: |
# build-android/project/jni/boost/include
# build-android/project/jni/boost/lib
#
# - name: Copy ICU libraries from cache
# uses: actions/cache@v2
# id: cache-icu
# with:
# # The same SDL revision will produce the same libraries
# key: ${{steps.icu-rev.outputs.ICU_REV}}
# path: |
# build-android/project/jni/iconv/include
# build-android/project/jni/iconv/lib
# build-android/project/jni/icuuc/include
# build-android/project/jni/icuuc/lib
#
# - name: Touch cached Boost timestamps
# if: steps.cache-boost.outputs.cache-hit == 'true' || steps.cache-icu.outputs.cache-hit == 'true'
# working-directory: build-android
# run: touch project/jni/boost/lib/*/* || true
#
# - name: Touch cached ICU timestamps
# if: steps.cache-boost.outputs.cache-hit == 'true' || steps.cache-icu.outputs.cache-hit == 'true'
# working-directory: build-android
# run: touch project/jni/iconv/lib/*/* project/jni/icuuc/lib/*/* || true
- name: Patch Java files and build Boost, ICU, and OpenSSL
run: |
export PATH=$ANDROID_NDK_LATEST_HOME:$PATH
./changeAppSettings.sh
- name: Set up Gradle and Android SDK licenses
working-directory: project
run: |
for Y in `seq 20`; do echo y; done | sudo $ANDROID_SDK_ROOT/cmdline-tools/latest/bin/sdkmanager --licenses
./gradlew assembleRelease || true
for Y in `seq 20`; do echo y; done | sudo $ANDROID_SDK_ROOT/cmdline-tools/latest/bin/sdkmanager --licenses --sdk_root=`pwd`
mkdir -p $HOME/.android
keytool -genkey -v -keystore $HOME/.android/debug.keystore -storepass android -alias androiddebugkey -keypass android -keyalg RSA -keysize 2048 -validity 10000 -dname "CN=Debug, OU=Debug, O=Debug, L=Debug, ST=Debug, C=Debug"
echo "sdk.dir=$ANDROID_SDK_ROOT" > local.properties
echo "proguard.config=proguard.cfg;proguard-local.cfg" >> local.properties
- name: Hyper turbo build script GOOOOOOOOOOOO
run: |
export PATH=$ANDROID_NDK_LATEST_HOME:$ANDROID_SDK_ROOT/build-tools/31.0.0:$PATH
./build.sh
- name: App signing keys
run: |
echo "$ANDROID_KEYSTORE_B64" | base64 -d > keystore.jks || true
echo "$ANDROID_UPLOAD_KEYSTORE_B64" | base64 -d > upload_keystore.jks || true
find keystore.jks -empty -delete || true
find upload_keystore.jks -empty -delete || true
env:
ANDROID_KEYSTORE_B64: "${{secrets.ANDROID_KEYSTORE_B64}}"
ANDROID_UPLOAD_KEYSTORE_B64: "${{secrets.ANDROID_UPLOAD_KEYSTORE_B64}}"
- name: Package
run: |
export PATH=$ANDROID_NDK_LATEST_HOME:$ANDROID_SDK_ROOT/build-tools/31.0.0:$PATH
if [ -e keystore.jks ]; then
export ANDROID_KEYSTORE_FILE=`pwd`/keystore.jks
fi
if [ -e upload_keystore.jks ]; then
export ANDROID_UPLOAD_KEYSTORE_FILE=`pwd`/upload_keystore.jks
fi
mkdir -p upload/
./sign.sh
mv *.apk upload/
./signBundle.sh
mv *.aab upload/
env:
ANDROID_KEYSTORE_PASS: "${{secrets.ANDROID_KEYSTORE_PASS}}"
ANDROID_KEYSTORE_ALIAS: "${{secrets.ANDROID_KEYSTORE_ALIAS}}"
ANDROID_UPLOAD_KEYSTORE_PASS: "${{secrets.ANDROID_UPLOAD_KEYSTORE_PASS}}"
ANDROID_UPLOAD_KEYSTORE_ALIAS: "${{secrets.ANDROID_UPLOAD_KEYSTORE_ALIAS}}"
# Github actions is dumb and won't let you download single files from artifacts, so break up the artifacts instead
- uses: actions/upload-artifact@v2
with:
name: ${{env.APP_NAME}}
path: upload
if-no-files-found: error

1
.gitignore vendored
View File

@@ -23,4 +23,3 @@
/project/app/build.gradle
/project/app/.gradle
/project/app/build
/project/assetpack/build

95
.gitmodules vendored
View File

@@ -1,3 +1,38 @@
[submodule "project/jni/application/NewRAW"]
path = project/jni/application/NewRAW
url = https://github.com/usineur/android-newraw.git
[submodule "project/jni/boost/src"]
path = project/jni/boost/src
url = https://github.com/moritz-wundke/Boost-for-Android.git
branch = master
update = merge
[submodule "project/jni/application/commandergenius/commandergenius"]
path = project/jni/application/commandergenius/commandergenius
url = https://github.com/gerstrong/Commander-Genius.git
[submodule "project/jni/application/openarena/engine"]
path = project/jni/application/openarena/engine
url = https://github.com/pelya/openarena-engine.git
[submodule "project/jni/application/openarena/vm"]
path = project/jni/application/openarena/vm
url = https://github.com/pelya/openarena-vm
[submodule "project/jni/application/teeworlds/src"]
path = project/jni/application/teeworlds/src
url = https://github.com/pelya/teeworlds.git
[submodule "project/jni/application/xserver/xserver"]
path = project/jni/application/xserver/xserver
url = https://github.com/pelya/xserver.git
branch = xsdl-1.20
update = merge
[submodule "android-shmem"]
path = project/jni/shmem
url = https://github.com/pelya/android-shmem.git
branch = master
update = merge
[submodule "project/jni/application/hid-pc-keyboard/src"]
path = project/jni/application/hid-pc-keyboard/src
url = https://github.com/pelya/android-keyboard-gadget.git
branch = master
update = merge
[submodule "project/jni/iconv/src"]
path = project/jni/iconv/src
url = https://github.com/pelya/libiconv-libicu-android.git
@@ -5,21 +40,47 @@
update = merge
[submodule "project/jni/application/openttd/src"]
path = project/jni/application/openttd/src
url = https://github.com/n-ice-community/openttd-android.git
branch = 12
[submodule "project/jni/sdl2"]
path = project/jni/sdl2
url = https://github.com/libsdl-org/SDL.git
branch = main
[submodule "project/jni/sdl2_image"]
path = project/jni/sdl2_image
url = https://github.com/libsdl-org/SDL_image
branch = main
[submodule "project/jni/sdl2_ttf"]
path = project/jni/sdl2_ttf
url = https://github.com/libsdl-org/SDL_ttf.git
branch = main
[submodule "project/jni/sdl2_mixer"]
path = project/jni/sdl2_mixer
url = https://github.com/libsdl-org/SDL_mixer.git
url = https://github.com/pelya/openttd-android.git
branch = 1.10
[submodule "project/jni/application/uae4all2"]
path = project/jni/application/uae4all2
url = https://github.com/lubomyr/uae4all2.git
[submodule "project/jni/application/basiliskii/basiliskii"]
path = project/jni/application/basiliskii/basiliskii
url = https://github.com/pelya/BasiliskII-android.git
[submodule "project/jni/vncserver/src"]
path = project/jni/vncserver/src
url = https://github.com/LibVNC/libvncserver.git
[submodule "project/jni/application/vice/vice"]
path = project/jni/application/vice/vice
url = https://github.com/lubomyr/vice-2.4.git
[submodule "project/jni/application/xserver/pulseaudio"]
path = project/jni/application/xserver/pulseaudio
url = https://github.com/pelya/pulseaudio-android.git
branch = master
[submodule "project/jni/application/supertux/supertux"]
path = project/jni/application/supertux/supertux
url = https://github.com/pelya/supertux.git
[submodule "project/jni/application/fheroes2/fheroes2"]
path = project/jni/application/fheroes2/fheroes2
url = https://github.com/gerstrong/fheroes2plus.git
[submodule "project/jni/application/ninslash/src"]
path = project/jni/application/ninslash/src
url = https://github.com/pelya/Ninslash.git
branch = master
update = merge
[submodule "project/jni/application/openttd-jgrpp/src"]
path = project/jni/application/openttd-jgrpp/src
url = https://github.com/pelya/OpenTTD-JGR-patchpack.git
branch = android-desktop
[submodule "project/jni/application/liero/src"]
path = project/jni/application/liero/src
url = https://github.com/pelya/liero-android.git
[submodule "project/jni/application/openlierox/src"]
path = project/jni/application/openlierox/src
url = https://github.com/albertz/openlierox.git
branch = half-assed-android-port
[submodule "project/jni/application/xserver-debian/debian-image"]
path = project/jni/application/xserver-debian/debian-image
url = https://github.com/pelya/debian-noroot
branch = master

View File

@@ -1 +0,0 @@
project/app/build/outputs/apk/release/app-release.apk

266
build.sh
View File

@@ -1,45 +1,34 @@
#!/usr/bin/env bash
#!/bin/sh
#set -eu # Bashism, does not work with default shell on Ubuntu 12.04
# Handle any error or die
set -e
THIS_BUILD_DIR=$(dirname "$0")
install_apk=false
run_apk=false
sign_apk=false
sign_bundle=false
build_release=true
do_zipalign=true
quick_rebuild=false
QUICK_REBUILD_ARGS=
# Fix Gradle compilation error
if [ -z "$ANDROID_NDK_HOME" ]; then
export ANDROID_NDK_HOME="$(which ndk-build | sed 's@/ndk-build@@')"
if [ "$#" -gt 0 -a "$1" = "-s" ]; then
shift
sign_apk=true
fi
while getopts "sirqbhz" OPT
do
case $OPT in
s) sign_apk=true;;
i) install_apk=true;;
r) install_apk=true ; run_apk=true;;
q) echo "Quick rebuild does not work anymore with Gradle!";;
b) sign_bundle=true;;
z) do_zipalign=false;;
h)
echo "Usage: $0 [-s] [-i] [-r] [-q] [debug|release] [app-name]"
echo " -s: sign .apk file after building"
echo " -b: sign .aab app bundle file after building"
echo " -i: install APK file to device after building"
echo " -r: run APK file on device after building"
echo " -z: skip zipalign and apksigner"
echo " debug: build debug package"
echo " release: build release package (default)"
echo " app-name: directory under project/jni/application to be compiled"
exit 0
;;
esac
done
shift $(expr $OPTIND - 1)
if [ "$#" -gt 0 -a "$1" = "-i" ]; then
shift
install_apk=true
fi
if [ "$#" -gt 0 -a "$1" = "-r" ]; then
shift
install_apk=true
run_apk=true
fi
if [ "$#" -gt 0 -a "$1" = "-q" ]; then
shift
quick_rebuild=true
QUICK_REBUILD_ARGS=APP_ABI=armeabi-v7a
fi
if [ "$#" -gt 0 -a "$1" = "release" ]; then
shift
@@ -52,7 +41,7 @@ if [ "$#" -gt 0 -a "$1" = "debug" ]; then
export NDK_DEBUG=1
fi
if [ "$#" -gt 0 ]; then
if [ "$#" -gt 0 -a "$1" '!=' "-h" ]; then
echo "Switching build target to $1"
if [ -e project/jni/application/$1 ]; then
rm -f project/jni/application/src
@@ -60,41 +49,51 @@ if [ "$#" -gt 0 ]; then
else
echo "Error: no app $1 under project/jni/application"
echo "Available applications:"
pushd project/jni/application
cd project/jni/application
for f in *; do
if [ -e "$f/AndroidAppSettings.cfg" ]; then
echo "$f"
fi
done
popd
exit 1
fi
shift
fi
if [ ! -e project/local.properties ] || \
! grep -q "package $(grep -Po 'AppFullName\=\K[.[:alnum:]]+' AndroidAppSettings.cfg);" project/src/Globals.java || \
[ "$(readlink AndroidAppSettings.cfg)" -nt "project/src/Globals.java" ] || \
[ -n "$(find project/java/* \
project/javaSDL2/* \
project/jni/sdl2/android-project/app/src/main/java/org/libsdl/app/* \
project/AndroidManifestTemplate.xml \
-cnewer \
project/src/Globals.java \
)" \
];
then
./changeAppSettings.sh -a
if [ "$#" -gt 0 -a "$1" = "-h" ]; then
echo "Usage: $0 [-s] [-i] [-r] [-q] [debug|release] [app-name]"
echo " -s: sign APK file after building"
echo " -i: install APK file to device after building"
echo " -r: run APK file on device after building"
echo " -q: quick-rebuild C code, without rebuilding Java files"
echo " debug: build debug package"
echo " release: build release package (default)"
echo " app-name: directory under project/jni/application to be compiled"
exit 0
fi
NDK_TOOLCHAIN_VERSION=$GCCVER
[ -z "$NDK_TOOLCHAIN_VERSION" ] && NDK_TOOLCHAIN_VERSION=4.9
# Set here your own NDK path if needed
# export PATH=$PATH:~/src/endless_space/android-ndk-r7
NDKBUILDPATH=$PATH
export `grep "AppFullName=" AndroidAppSettings.cfg`
if [ -e project/local.properties ] && \
( grep "package $AppFullName;" project/src/Globals.java > /dev/null 2>&1 && \
[ "`readlink AndroidAppSettings.cfg`" -ot "project/src/Globals.java" ] && \
[ -z "`find project/java/* project/AndroidManifestTemplate.xml -cnewer project/src/Globals.java`" ] ) ; then true ; else
./changeAppSettings.sh -a || exit 1
sleep 1
touch project/src/Globals.java
fi
MYARCH=linux-x86_64
if [ -z "$NCPU" ]; then
NCPU=8
NCPU=4
if uname -s | grep -i "linux" > /dev/null ; then
MYARCH=linux-x86_64
NCPU=$(cat /proc/cpuinfo | grep -c -i processor)
NCPU=`cat /proc/cpuinfo | grep -c -i processor`
fi
if uname -s | grep -i "darwin" > /dev/null ; then
MYARCH=darwin-x86_64
@@ -103,85 +102,92 @@ if [ -z "$NCPU" ]; then
MYARCH=windows-x86_64
fi
fi
export BUILD_NUM_CPUS=$NCPU
$quick_rebuild || rm -r -f project/bin/* # New Android SDK introduced some lame-ass optimizations to the build system which we should take care about
[ -x project/jni/application/src/AndroidPreBuild.sh ] && {
cd project/jni/application/src
./AndroidPreBuild.sh || { echo "AndroidPreBuild.sh returned with error" ; exit 1 ; }
cd ../../../..
}
if [ -x project/jni/application/src/AndroidPreBuild.sh ]; then
pushd project/jni/application/src
./AndroidPreBuild.sh
popd
fi
strip_libs() {
grep "CustomBuildScript=y" ../AndroidAppSettings.cfg > /dev/null && \
grep "MultiABI=" ../AndroidAppSettings.cfg | grep "y\\|all\\|armeabi-v7a" > /dev/null && \
echo Stripping libapplication-armeabi-v7a.so by hand && \
rm obj/local/armeabi-v7a/libapplication.so && \
cp jni/application/src/libapplication-armeabi-v7a.so obj/local/armeabi-v7a/libapplication.so && \
cp jni/application/src/libapplication-armeabi-v7a.so libs/armeabi-v7a/libapplication.so && \
`which ndk-build | sed 's@/ndk-build@@'`/toolchains/arm-linux-androideabi-${NDK_TOOLCHAIN_VERSION}/prebuilt/$MYARCH/bin/arm-linux-androideabi-strip --strip-unneeded libs/armeabi-v7a/libapplication.so
grep "CustomBuildScript=y" ../AndroidAppSettings.cfg > /dev/null && \
grep "MultiABI=" ../AndroidAppSettings.cfg | grep "all\\|x86" > /dev/null && \
echo Stripping libapplication-x86.so by hand && \
rm obj/local/x86/libapplication.so && \
cp jni/application/src/libapplication-x86.so obj/local/x86/libapplication.so && \
cp jni/application/src/libapplication-x86.so libs/x86/libapplication.so && \
`which ndk-build | sed 's@/ndk-build@@'`/toolchains/x86-${NDK_TOOLCHAIN_VERSION}/prebuilt/$MYARCH/bin/i686-linux-android-strip --strip-unneeded libs/x86/libapplication.so
grep "CustomBuildScript=y" ../AndroidAppSettings.cfg > /dev/null && \
grep "MultiABI=" ../AndroidAppSettings.cfg | grep "all\\|x86_64" > /dev/null && \
echo Stripping libapplication-x86_64.so by hand && \
rm obj/local/x86_64/libapplication.so && \
cp jni/application/src/libapplication-x86_64.so obj/local/x86_64/libapplication.so && \
cp jni/application/src/libapplication-x86_64.so libs/x86_64/libapplication.so && \
`which ndk-build | sed 's@/ndk-build@@'`/toolchains/x86_64-${NDK_TOOLCHAIN_VERSION}/prebuilt/$MYARCH/bin/x86_64-linux-android-strip --strip-unneeded libs/x86_64/libapplication.so
grep "CustomBuildScript=y" ../AndroidAppSettings.cfg > /dev/null && \
grep "MultiABI=" ../AndroidAppSettings.cfg | grep "all\\|arm64-v8a" > /dev/null && \
echo Stripping libapplication-arm64-v8a.so by hand && \
rm obj/local/arm64-v8a/libapplication.so && \
cp jni/application/src/libapplication-arm64-v8a.so obj/local/arm64-v8a/libapplication.so && \
cp jni/application/src/libapplication-arm64-v8a.so libs/arm64-v8a/libapplication.so && \
`which ndk-build | sed 's@/ndk-build@@'`/toolchains/aarch64-linux-android-${NDK_TOOLCHAIN_VERSION}/prebuilt/$MYARCH/bin/aarch64-linux-android-strip --strip-unneeded libs/arm64-v8a/libapplication.so
return 0
}
if grep -q 'CustomBuildScript=y' ./AndroidAppSettings.cfg; then
${ANDROID_NDK_HOME}/ndk-build -C project -j$NCPU V=1 CUSTOM_BUILD_SCRIPT_FIRST_PASS=1 NDK_APP_STRIP_MODE=none
make -C project/jni/application -f CustomBuildScript.mk
fi
# Fix Gradle compilation error
[ -z "$ANDROID_NDK_HOME" ] && export ANDROID_NDK_HOME="`which ndk-build | sed 's@/ndk-build@@'`"
${ANDROID_NDK_HOME}/ndk-build -C project -j$NCPU V=1 NDK_APP_STRIP_MODE=none
./copyAssets.sh
pushd project
if $build_release ; then
if [ -x ./gradlew ]; then
./gradlew assembleRelease
else
gradle assembleRelease
fi
if [ -x jni/application/src/AndroidPostBuild.sh ]; then
pushd jni/application/src
./AndroidPostBuild.sh ${THIS_BUILD_DIR}/project/app/build/outputs/apk/release/app-release-unsigned.apk
popd
fi
../copyAssets.sh pack-binaries app/build/outputs/apk/release/app-release-unsigned.apk
rm -f app/build/outputs/apk/release/app-release.apk
if $do_zipalign; then
zipalign -p 4 app/build/outputs/apk/release/app-release-unsigned.apk app/build/outputs/apk/release/app-release.apk
apksigner sign --ks ~/.android/debug.keystore --ks-key-alias androiddebugkey --ks-pass pass:android app/build/outputs/apk/release/app-release.apk
fi
else
if [ -x ./gradlew ]; then
./gradlew assembleDebug
else
gradle assembleDebug
fi
if [ -x jni/application/src/AndroidPostBuild.sh ]; then
pushd jni/application/src
./AndroidPostBuild.sh ${THIS_BUILD_DIR}/project/app/build/outputs/apk/debug/app-debug.apk
popd
fi
mkdir -p app/build/outputs/apk/release
../copyAssets.sh pack-binaries app/build/outputs/apk/debug/app-debug.apk
rm -f app/build/outputs/apk/release/app-release.apk
if $do_zipalign; then
zipalign -p 4 app/build/outputs/apk/debug/app-debug.apk app/build/outputs/apk/release/app-release.apk
apksigner sign --ks ~/.android/debug.keystore --ks-key-alias androiddebugkey --ks-pass pass:android app/build/outputs/apk/release/app-release.apk
fi
fi
if $sign_apk; then
pushd ..
./sign.sh
popd
fi
if $sign_bundle; then
pushd ..
./signBundle.sh
popd
fi
if $install_apk && [ -n "$(adb devices | tail -n +2)" ]; then
if $sign_apk; then
APPNAME=$(grep AppName ../AndroidAppSettings.cfg | sed 's/.*=//' | tr -d '"' | tr " '/" '---')
APPVER=$(grep AppVersionName ../AndroidAppSettings.cfg | sed 's/.*=//' | tr -d '"' | tr " '/" '---')
adb install -r ../$APPNAME-$APPVER.apk ;
else
adb install -r app/build/outputs/apk/release/app-release.apk
fi
fi
if $run_apk; then
ActivityName="$(grep AppFullName ../AndroidAppSettings.cfg | sed 's/.*=//')/.MainActivity"
RUN_APK="adb shell am start -n $ActivityName"
echo "Running $ActivityName on the USB-connected device:"
echo "$RUN_APK"
eval $RUN_APK
fi
cd project && env PATH=$NDKBUILDPATH BUILD_NUM_CPUS=$NCPU ndk-build -j$NCPU V=1 $QUICK_REBUILD_ARGS && \
strip_libs && \
cd .. && ./copyAssets.sh && cd project && \
{ if $build_release ; then \
$quick_rebuild && { \
zip -u -r app/build/outputs/apk/release/app-release-unsigned.apk lib assets || exit 1 ; \
} || ./gradlew assembleRelease || exit 1 ; \
[ '!' -x jni/application/src/AndroidPostBuild.sh ] || {
cd jni/application/src ; \
./AndroidPostBuild.sh `pwd`/../../../app/build/outputs/apk/release/app-release-unsigned.apk || exit 1 ; \
cd ../../.. ; \
} || exit 1 ; \
../copyAssets.sh pack-binaries app/build/outputs/apk/release/app-release-unsigned.apk ; \
rm -f app/build/outputs/apk/release/app-release.apk ; \
zipalign 4 app/build/outputs/apk/release/app-release-unsigned.apk app/build/outputs/apk/release/app-release.apk || exit 1 ; \
apksigner sign --ks ~/.android/debug.keystore --ks-key-alias androiddebugkey --ks-pass pass:android app/build/outputs/apk/release/app-release.apk || exit 1 ; \
else \
./gradlew assembleDebug || exit 1 ; \
[ '!' -x jni/application/src/AndroidPostBuild.sh ] || {
cd jni/application/src ; \
./AndroidPostBuild.sh `pwd`/../../../app/build/outputs/apk/debug/app-debug.apk || exit 1 ; \
cd ../../.. ; \
} || exit 1 ; \
mkdir -p app/build/outputs/apk/release ; \
../copyAssets.sh pack-binaries app/build/outputs/apk/debug/app-debug.apk && \
rm -f app/build/outputs/apk/release/app-release.apk && \
zipalign 4 app/build/outputs/apk/debug/app-debug.apk app/build/outputs/apk/release/app-release.apk &&
apksigner sign --ks ~/.android/debug.keystore --ks-key-alias androiddebugkey --ks-pass pass:android app/build/outputs/apk/release/app-release.apk || exit 1 ; \
fi ; } && \
{ if $sign_apk; then cd .. && ./sign.sh && cd project ; else true ; fi ; } && \
{ $install_apk && [ -n "`adb devices | tail -n +2`" ] && \
{ if $sign_apk; then \
APPNAME=`grep AppName ../AndroidAppSettings.cfg | sed 's/.*=//' | tr -d '"' | tr " '/" '---'` ; \
APPVER=`grep AppVersionName ../AndroidAppSettings.cfg | sed 's/.*=//' | tr -d '"' | tr " '/" '---'` ; \
adb install -r ../$APPNAME-$APPVER.apk ; \
else \
adb install -r app/build/outputs/apk/release/app-release.apk ; \
fi ; } ; \
true ; } && \
{ $run_apk && { \
ActivityName="`grep AppFullName ../AndroidAppSettings.cfg | sed 's/.*=//'`/.MainActivity" ; \
RUN_APK="adb shell am start -n $ActivityName" ; \
echo "Running $ActivityName on the USB-connected device:" ; \
echo "$RUN_APK" ; \
eval $RUN_APK ; } ; \
true ; } || exit 1

File diff suppressed because it is too large Load Diff

View File

@@ -3,38 +3,36 @@
ARCHES="arm64-v8a armeabi-v7a x86 x86_64"
if [ "$1" = "pack-binaries" -o "$1" = "pack-binaries-bundle" ]; then
[ -e jni/application/src/AndroidData/lib ] || exit 0
[ -e jni/application/src/AndroidData/binaries*.zip ] && {
echo "Error: binaries.zip no longer supported in Android 10"
echo "Copy your executable binaries to AndroidData/lib/arm64-v8a"
echo "Then execute them using \$LIBDIR or getenv(\"LIBDIR\")"
exit 0
}
APK="`pwd`/$2"
echo "Copying binaries to .apk file"
cd jni/application/src/AndroidData/ || exit 1
if [ "$1" = "pack-binaries-bundle" ]; then
rm -rf base
mkdir -p base
cp -L -r lib base/
zip -r -D "$APK" base || exit 1
rm -rf base
else
zip -r -D "$APK" lib || exit 1
fi
cd ../../../../
[ -e jni/application/src/AndroidData/lib ] || exit 0
[ -e jni/application/src/AndroidData/binaries*.zip ] && {
echo "Error: binaries.zip no longer supported in Android 10"
echo "Copy your executable binaries to AndroidData/lib/arm64-v8a"
echo "Then execute them using \$LIBDIR or getenv(\"LIBDIR\")"
exit 0
}
APK="`pwd`/$2"
echo "Copying binaries to .apk file"
cd jni/application/src/AndroidData/ || exit 1
if [ "$1" = "pack-binaries-bundle" ]; then
rm -rf base
mkdir -p base
mv lib base/
zip -r "$APK" base || exit 1
mv base/lib ./
rm -rf base
else
zip -r "$APK" lib || exit 1
fi
cd ../../../../
exit 0
fi
echo "Copying app data files from project/jni/application/src/AndroidData to project/assets"
mkdir -p project/assets
rm -f -r project/assets/*
if [ -d "project/jni/application/src/AndroidData" ] ; then
for F in project/jni/application/src/AndroidData/*; do
[ "$F" = "project/jni/application/src/AndroidData/lib" ] && continue
[ "$F" = "project/jni/application/src/AndroidData/assetpack" ] && continue
cp -L -r "$F" project/assets/
done
cp -L -r project/jni/application/src/AndroidData/* project/assets/
rm -rf project/assets/lib
fi
exit 0

View File

@@ -1 +0,0 @@
Initial F-Droid release

View File

@@ -1,11 +0,0 @@
NOTE: This is a fork of https://github.com/pelya/openttd-android since development there is on hold currently.
OpenTTD is an open source reimplementation of the Microprose game Transport Tycoon Deluxe (TTD). As president of a start-up transportation company in (typically) 1950, you have a choice of building rail, road, air and maritime transportation routes to build up your transportation empire. Outsmart your competition by beating them to attractive passenger and commodities routes to become the game's highest-ranking transport company by the year 2050.
OpenTTD is based on Chris Sawyer's Transport Tycoon Deluxe and introduces a whole set of new features, including multiplayer support, better stations and vehicles, larger maps and a host of other options.
Posting a full list of features would be futile as it would mean updating this page almost daily, and even then some things might be forgotten. Play with the game to experience all the features yourself, or take a look at the <a href="https://wiki.openttd.org/en/Manual/">Manual</a> for a more thorough listing and explanation of the features and possibilities available.
Tips:
* Scroll the map with two fingers, when you are building roads or stations.
* Close dialogs by dragging them to the screen edge.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 345 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 224 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 246 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 452 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 315 KiB

View File

@@ -1 +0,0 @@
A simulation game based on the popular game "Transport Tycoon Deluxe"

View File

@@ -14,14 +14,12 @@
android:supportsRtl="true"
android:theme="@style/AppTheme"
>
<activity android:name="MainActivity"
<activity android:name=".MainActivity"
android:label="@string/app_name"
android:alwaysRetainTaskState="true"
android:launchMode="singleTask"
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation|screenSize|smallestScreenSize|layoutDirection"
android:windowSoftInputMode="stateUnspecified"
android:theme="@style/AppTheme"
android:exported="true"
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -45,19 +43,18 @@
<!-- ==OPENFILE== --> </intent-filter>
</activity>
<!-- ==ADMOB== --> <activity android:name="com.google.android.gms.ads.AdActivity" android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation|screenSize|smallestScreenSize|layoutDirection"/>
<!-- ==ADMOB== --> <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" />
<!-- ==ADMOB== --> <meta-data android:name="com.google.android.gms.version" android:value="4323000" /> <!-- Change this value to the actual Google Play SDK version -->
<!-- ==GOOGLEPLAYGAMESERVICES== --> <meta-data android:name="com.google.android.gms.games.APP_ID" android:value="@string/google_play_game_services_app_id" />
<!-- ==GOOGLEPLAYGAMESERVICES== --> <meta-data android:name="com.google.android.gms.appstate.APP_ID" android:value="@string/google_play_game_services_app_id" />
<!-- ==GOOGLEPLAYGAMESERVICES== --> <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version"/>
<meta-data android:name="com.sec.android.support.multiwindow" android:value="true" /> <!-- Samsung's multiwindow -->
<activity android:name="RestartMainActivity"
<activity android:name=".RestartMainActivity"
android:label="@string/app_name"
android:alwaysRetainTaskState="true"
android:launchMode="singleTask"
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation|screenSize|smallestScreenSize|layoutDirection"
android:windowSoftInputMode="stateUnspecified"
android:process=":RestartMainActivity"
android:exported="true"
/>
<service android:name=".DummyService"
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation|screenSize|smallestScreenSize|layoutDirection"
@@ -71,7 +68,7 @@
<!-- ==NOT_EXTERNAL_STORAGE== --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="18" />
<!-- ==NOT_EXTERNAL_STORAGE== --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="18" /> <!-- App has write access to it's own dir on SD card without this permission on Android 4.4 and above -->
<!-- ==READ_OBB== --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="18" />
<!-- ==READ_OBB== --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <!-- OBB file requires explicit permission before Marshmallow -->
<!-- ==READ_OBB== --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="23" /> <!-- OBB file requires explicit permission before Marshmallow -->
<!-- ==RECORD_AUDIO== --> <uses-permission android:name="android.permission.RECORD_AUDIO" />
<!-- ==ADMOB== --> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- ==FOREGROUND_SERVICE== --> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

View File

@@ -0,0 +1,103 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Replace com.test.game with the identifier of your game below, e.g.
com.gamemaker.game
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.libsdl.app"
android:versionCode="1"
android:versionName="1.0"
android:installLocation="auto">
<!-- OpenGL ES 2.0 -->
<uses-feature android:glEsVersion="0x00020000" />
<!-- Touchscreen support -->
<uses-feature
android:name="android.hardware.touchscreen"
android:required="false" />
<!-- Game controller support -->
<uses-feature
android:name="android.hardware.bluetooth"
android:required="false" />
<uses-feature
android:name="android.hardware.gamepad"
android:required="false" />
<uses-feature
android:name="android.hardware.usb.host"
android:required="false" />
<!-- External mouse input events -->
<uses-feature
android:name="android.hardware.type.pc"
android:required="false" />
<!-- Audio recording support -->
<!-- if you want to capture audio, uncomment this. -->
<!-- <uses-feature
android:name="android.hardware.microphone"
android:required="false" /> -->
<!-- Allow writing to external storage -->
<!--
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-->
<!-- Allow access to Bluetooth devices -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<!-- Allow access to the vibrator -->
<uses-permission android:name="android.permission.VIBRATE" />
<!-- ==INTERNET== --> <uses-permission android:name="android.permission.INTERNET" />
<!-- ==EXTERNAL_STORAGE== --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!-- ==NOT_EXTERNAL_STORAGE== --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="18" />
<!-- ==NOT_EXTERNAL_STORAGE== --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="18" /> <!-- App has write access to it's own dir on SD card without this permission on Android 4.4 and above -->
<!-- ==READ_OBB== --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="18" />
<!-- ==READ_OBB== --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="23" /> <!-- OBB file requires explicit permission before Marshmallow -->
<!-- ==RECORD_AUDIO== --> <uses-permission android:name="android.permission.RECORD_AUDIO" />
<!-- ==ADMOB== --> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- ==FOREGROUND_SERVICE== --> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<!-- if you want to capture audio, uncomment this. -->
<!-- <uses-permission android:name="android.permission.RECORD_AUDIO" /> -->
<!-- Create a Java class extending SDLActivity and place it in a
directory under app/src/main/java matching the package, e.g. app/src/main/java/com/gamemaker/game/MyGame.java
then replace "SDLActivity" with the name of your class (e.g. "MyGame")
in the XML below.
An example Java class can be found in README-android.md
-->
<application android:label="@string/app_name"
android:icon="@drawable/icon"
android:allowBackup="true"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
android:hardwareAccelerated="true" >
<!-- Example of setting SDL hints from AndroidManifest.xml:
<meta-data android:name="SDL_ENV.SDL_ACCELEROMETER_AS_JOYSTICK" android:value="0"/>
-->
<activity android:name="SDLActivity"
android:label="@string/app_name"
android:alwaysRetainTaskState="true"
android:launchMode="singleInstance"
android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|keyboard|keyboardHidden|navigation"
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<!-- Drop file event -->
<!--
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="*/*" />
</intent-filter>
-->
</activity>
</application>
</manifest>

View File

@@ -1,39 +1,26 @@
plugins {
id 'com.android.application'
}
apply plugin: 'com.android.application'
android {
compileSdk 31
ndkVersion "23.1.7779620"
compileSdkVersion 29
buildToolsVersion "30.0.0"
defaultConfig {
applicationId "net.olofson.ballfield"
minSdk 16
targetSdk 31
minSdkVersion 16 // Must match version numbers in project/AndroidManifestTemplate.xml
targetSdkVersion 29
}
buildTypes {
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), '../proguard-local.cfg', '../proguard.cfg'
}
releaseWithDebugInfo {
initWith release
ndk {
debugSymbolLevel 'FULL'
}
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
assetPacks = [":assetpack"] // ==ASSETPACK==
dependencies { compile 'com.google.android.gms:play-services-games:19.0.0' } // ==GOOGLEPLAYGAMESERVICES==
dependencies { compile 'com.google.android.gms:play-services-drive:17.0.0' } // ==GOOGLEPLAYGAMESERVICES==
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.3.1'
implementation 'com.google.android.gms:play-services-games:21.0.0' // ==GOOGLEPLAYGAMESERVICES==
implementation 'androidx.appcompat:appcompat:1.1.0'
}

View File

@@ -1,8 +0,0 @@
apply plugin: 'com.android.asset-pack'
assetPack {
packName = "assetpack"
dynamicDelivery {
deliveryType = "install-time"
}
}

View File

@@ -1 +0,0 @@
../../../jni/application/src/AndroidData/assetpack

View File

@@ -1,17 +1,25 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
mavenCentral()
jcenter()
}
dependencies {
classpath "com.android.tools.build:gradle:7.0.3"
classpath "com.android.tools.build:gradle:4.0.0"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
}

View File

@@ -6,7 +6,7 @@
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
org.gradle.jvmargs=-Xmx2048m
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects

Binary file not shown.

View File

@@ -1,6 +1,6 @@
#Sat Nov 27 22:44:43 EET 2021
#Tue Jul 07 20:59:38 EEST 2020
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip

53
project/gradlew vendored
View File

@@ -1,21 +1,5 @@
#!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
##
## Gradle start up script for UN*X
@@ -44,7 +28,7 @@ APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
DEFAULT_JVM_OPTS=""
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
@@ -82,7 +66,6 @@ esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
@@ -126,11 +109,10 @@ if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
@@ -156,19 +138,19 @@ if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
i=$((i+1))
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
@@ -177,9 +159,14 @@ save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
APP_ARGS=$(save "$@")
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"

43
project/gradlew.bat vendored
View File

@@ -1,19 +1,3 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@@ -29,18 +13,15 @@ if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
set DEFAULT_JVM_OPTS=
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -54,7 +35,7 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@@ -64,14 +45,28 @@ echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell

View File

@@ -53,16 +53,10 @@ import java.util.Arrays;
import android.text.SpannedString;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.Manifest;
import android.content.pm.PackageManager;
import android.os.storage.StorageManager;
import android.os.storage.OnObbStateChangeListener;
import android.content.res.AssetManager;
import android.content.pm.PackageManager;
import android.content.pm.ApplicationInfo;
class CountingInputStream extends BufferedInputStream
{
@@ -177,6 +171,7 @@ class DataDownloader extends Thread
{
Parent = _Parent;
Status = new StatusWriter( _Status, _Parent );
//Status.setText( "Connecting to " + Globals.DataDownloadUrl );
outFilesDir = Globals.DataDir;
DownloadComplete = false;
this.start();
@@ -192,6 +187,8 @@ class DataDownloader extends Thread
@Override
public void run()
{
Parent.getVideoLayout().setOnKeyListener(new BackKeyListener(Parent));
String [] downloadFiles = Globals.DataDownloadUrl;
int total = 0;
int count = 0;
@@ -214,16 +211,7 @@ class DataDownloader extends Thread
downloadFiles[i].contains("<ARCH>") &&
! DownloadDataFile(downloadFiles[i].replace("<ARCH>", android.os.Build.CPU_ABI2), DOWNLOAD_FLAG_FILENAME + String.valueOf(i) + ".flag", count+1, total, i) ) )
{
if (!Parent.getFilesDir().getAbsolutePath().equals(Globals.DataDir))
{
Globals.DataDir = Parent.getFilesDir().getAbsolutePath();
Globals.DownloadToSdcard = false;
Log.i("SDL", "Switching download destination directory to internal storage and restarting the app: " + Globals.DataDir);
Settings.Save(Parent);
Intent intent = new Intent(Parent, RestartMainActivity.class);
Parent.startActivity(intent);
System.exit(0);
}
DownloadFailed = true;
return;
}
}
@@ -231,6 +219,7 @@ class DataDownloader extends Thread
}
}
DownloadComplete = true;
Parent.getVideoLayout().setOnKeyListener(null);
initParent();
}
@@ -274,6 +263,20 @@ class DataDownloader extends Thread
if( ! matched )
throw new IOException();
Status.setText( res.getString(R.string.download_unneeded) );
for( int i = 1; i < downloadUrls.length; i++ )
{
if( downloadUrls[i].indexOf("obb:") == 0 ) // APK expansion file provided by Google Play
{
String url = getObbFilePath(downloadUrls[i]);
if (new File(url).length() > 256)
{
Writer writer = new OutputStreamWriter(new FileOutputStream(url), "UTF-8");
writer.write("Extracted and truncated\n");
writer.close();
Log.i("SDL", "Truncated file from expansion: " + url);
}
}
}
return true;
} catch ( IOException e ) {
forceOverwrite = true;
@@ -303,9 +306,6 @@ class DataDownloader extends Thread
boolean DoNotUnzip = false;
boolean FileInAssets = false;
boolean FileInExpansion = false;
boolean MountObb = false;
final boolean[] ObbMounted = new boolean[] { false };
final boolean[] ObbMountedError = new boolean[] { false };
String url = "";
int downloadUrlIndex = 1;
@@ -331,61 +331,31 @@ class DataDownloader extends Thread
partialDownloadLen = partialDownload.length();
}
Status.setText( downloadCount + "/" + downloadTotal + ": " + res.getString(R.string.connecting_to, url) );
if( url.equals("assetpack") )
if( url.indexOf("obb:") == 0 ) // APK expansion file provided by Google Play
{
if( Parent.assetPackPath != null )
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M)
{
Log.i("SDL", "Found asset pack: " + Parent.assetPackPath);
return true;
}
Log.i("SDL", "Asset pack is not installed");
downloadUrlIndex++;
continue;
}
else if( url.indexOf("obb:") == 0 || url.indexOf("mnt:") == 0 ) // APK expansion file provided by Google Play
{
boolean tmpMountObb = ( url.indexOf("mnt:") == 0 );
url = getObbFilePath(url);
InputStream stream1 = null;
try {
stream1 = new FileInputStream(url);
stream1.read();
stream1.close();
Log.i("SDL", "Fetching file from expansion: " + url);
FileInExpansion = true;
MountObb = tmpMountObb;
break;
} catch( IOException ee ) {
Log.i("SDL", "Failed to open file, requesting storage read permission: " + url);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M)
int permissionCheck = Parent.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (permissionCheck != PackageManager.PERMISSION_GRANTED && !Parent.writeExternalStoragePermissionDialogAnswered)
{
int permissionCheck = Parent.checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE);
if (permissionCheck != PackageManager.PERMISSION_GRANTED && !Parent.readExternalStoragePermissionDialogAnswered)
Parent.requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0);
while( !Parent.writeExternalStoragePermissionDialogAnswered )
{
Parent.requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 0);
while( !Parent.readExternalStoragePermissionDialogAnswered )
{
try{ Thread.sleep(300); } catch (InterruptedException e) {}
}
try{ Thread.sleep(300); } catch (InterruptedException e) {}
}
}
} catch( Exception eee ) {
Log.i("SDL", "Failed to open file: " + url);
downloadUrlIndex++;
continue;
}
url = getObbFilePath(url);
InputStream stream1 = null;
try {
stream1 = new FileInputStream(url);
stream1.read();
stream1.close();
Log.i("SDL", "Fetching file from expansion: " + url);
FileInExpansion = true;
MountObb = tmpMountObb;
break;
} catch( Exception eee ) {
} catch( Exception e ) {
Log.i("SDL", "Failed to open file: " + url);
downloadUrlIndex++;
continue;
@@ -454,51 +424,6 @@ class DataDownloader extends Thread
}
}
if( MountObb )
{
Log.i("SDL", "Mounting OBB file: " + url);
StorageManager sm = (StorageManager) Parent.getSystemService(Context.STORAGE_SERVICE);
if( !sm.mountObb(url, null, new OnObbStateChangeListener()
{
public void onObbStateChange(String path, int state)
{
if (state == OnObbStateChangeListener.MOUNTED ||
state == OnObbStateChangeListener.ERROR_ALREADY_MOUNTED)
{
ObbMounted[0] = true;
}
else
{
ObbMountedError[0] = true;
}
}
}) )
{
Log.i("SDL", "Cannot mount OBB file '" + url + "'");
Status.setText( res.getString(R.string.error_dl_from, url) );
return false;
}
while( !ObbMounted[0] )
{
try{ Thread.sleep(300); } catch (InterruptedException e) {}
if( ObbMountedError[0] )
{
Log.i("SDL", "Cannot mount OBB file '" + url + "'");
Status.setText( res.getString(R.string.error_dl_from, url) );
return false;
}
}
Parent.ObbMountPath = sm.getMountedObbPath(url);
if( Parent.ObbMountPath == null )
{
Log.i("SDL", "Cannot mount OBB file '" + url + "'");
Status.setText( res.getString(R.string.error_dl_from, url) );
return false;
}
Log.i("SDL", "Mounted OBB file '" + url + "' to path " + Parent.ObbMountPath);
return true;
}
if( FileInExpansion )
{
Log.i("SDL", "Count file size: '" + url);
@@ -590,7 +515,15 @@ class DataDownloader extends Thread
try {
stream.close();
if( FileInExpansion )
{
Writer writer = new OutputStreamWriter(new FileOutputStream(url), "UTF-8");
writer.write("Extracted and truncated\n");
writer.close();
Log.i("SDL", "Truncated file from expansion: " + url);
}
} catch( java.io.IOException e ) {
Log.i("SDL", "Error truncating file from expansion: " + url);
};
return true;
@@ -850,7 +783,7 @@ class DataDownloader extends Thread
public MainActivity Parent;
public void run()
{
Parent.downloadFinishedInitSDL();
Parent.initSDL();
}
}
Callback cb = new Callback();
@@ -868,13 +801,59 @@ class DataDownloader extends Thread
private String getObbFilePath(final String url)
{
// "obb:" or "mnt:" - same length
return Environment.getExternalStorageDirectory().getAbsolutePath() + "/Android/obb/" +
Parent.getPackageName() + "/" + url.substring("obb:".length()) + "." + Parent.getPackageName() + ".obb";
}
public class BackKeyListener implements View.OnKeyListener
{
MainActivity p;
public BackKeyListener(MainActivity _p)
{
p = _p;
}
@Override
public boolean onKey(View v, int keyCode, KeyEvent event)
{
if( DownloadFailed )
System.exit(1);
AlertDialog.Builder builder = new AlertDialog.Builder(p);
builder.setTitle(p.getResources().getString(R.string.cancel_download));
builder.setMessage(p.getResources().getString(R.string.cancel_download) + (DownloadCanBeResumed ? " " + p.getResources().getString(R.string.cancel_download_resume) : ""));
builder.setPositiveButton(p.getResources().getString(R.string.yes), new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int item)
{
System.exit(1);
dialog.dismiss();
}
});
builder.setNegativeButton(p.getResources().getString(R.string.no), new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int item)
{
dialog.dismiss();
}
});
builder.setOnCancelListener(new DialogInterface.OnCancelListener()
{
public void onCancel(DialogInterface dialog)
{
}
});
AlertDialog alert = builder.create();
alert.setOwnerActivity(p);
alert.show();
return true;
}
}
public StatusWriter Status;
public boolean DownloadComplete = false;
public boolean DownloadFailed = false;
public boolean DownloadCanBeResumed = false;
private MainActivity Parent;
private String outFilesDir = null;

View File

@@ -40,7 +40,6 @@ import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.app.KeyguardManager;
import android.graphics.Rect;
/**
* An implementation of SurfaceView that uses the dedicated surface for

View File

@@ -39,7 +39,8 @@ class Globals
{ "expat", "expat-sdl" },
{ "sqlite3", "sqlite3-sdl" },
}; // Because some libraries are named differently to not clash with system libs
public static final boolean UsingSDL2 = false;
public static final boolean Using_SDL_1_3 = false;
public static final boolean Using_SDL_2_0 = false;
public static String[] DataDownloadUrl = { "Data files are 2 Mb|https://sourceforge.net/projects/libsdl-android/files/CommanderGenius/commandergenius-data.zip/download", "High-quality GFX and music - 40 Mb|https://sourceforge.net/projects/libsdl-android/files/CommanderGenius/commandergenius-hqp.zip/download" };
public static boolean SwVideoMode = false;
public static boolean NeedDepthBuffer = false;
@@ -90,7 +91,6 @@ class Globals
public static boolean HorizontalOrientation = true;
public static boolean AutoDetectOrientation = false;
public static boolean ImmersiveMode = true;
public static boolean DrawInDisplayCutout = false;
public static boolean HideSystemMousePointer = false;
public static boolean DownloadToSdcard = true;
public static boolean PhoneHasArrowKeys = false;
@@ -131,66 +131,12 @@ class Globals
public static boolean KeepAspectRatio = KeepAspectRatioDefaultSetting;
public static boolean TvBorders = true;
public static int RemapHwKeycode[] = new int[SDL_Keys.JAVA_KEYCODE_LAST];
public static int RemapScreenKbKeycode[] = new int[12];
// Values for 800x480 resolution
public static int ScreenKbControlsLayout[][] =
AppUsesThirdJoystick ? new int[][]
{
{ 0, 303, 177, 480 }, // Main joystick/DPAD
{ 0, 0, 48, 48 }, // Text input button
{ 400, 392, 488, 480 }, // Button 0
{ 312, 392, 400, 480 }, // Button 1
{ 400, 304, 488, 392 }, // Button 2
{ 312, 304, 400, 392 }, // Button 3
{ 400, 216, 488, 304 }, // Button 4
{ 312, 216, 400, 304 }, // Button 5
{ 623, 303, 800, 480 }, // Joystick 2
{ 623, 126, 800, 303 }, // Joystick 3
{ 400, 392, 488, 480 }, // Button 6 - copy of button 0, to be redefined in the code
{ 312, 392, 400, 480 }, // Button 7 - copy of button 1, to be redefined in the code
{ 400, 304, 488, 392 }, // Button 8 - copy of button 2, to be redefined in the code
{ 312, 304, 400, 392 }, // Button 9 - copy of button 3, to be redefined in the code
{ 400, 216, 488, 304 }, // Button 10 - copy of button 4, to be redefined in the code
{ 312, 216, 400, 304 }, // Button 11 - copy of button 5, to be redefined in the code
}
: AppUsesSecondJoystick ? new int[][]
{
{ 0, 303, 177, 480 }, // Main joystick/DPAD
{ 0, 0, 48, 48 }, // Text input button
{ 400, 392, 488, 480 }, // Button 0
{ 312, 392, 400, 480 }, // Button 1
{ 400, 304, 488, 392 }, // Button 2
{ 312, 304, 400, 392 }, // Button 3
{ 400, 216, 488, 304 }, // Button 4
{ 312, 216, 400, 304 }, // Button 5
{ 623, 303, 800, 480 }, // Joystick 2
{ 0, 0, 0, 0, }, // Joystick 3
{ 400, 392, 488, 480 }, // Button 6 - copy of button 0, to be redefined in the code
{ 312, 392, 400, 480 }, // Button 7 - copy of button 1, to be redefined in the code
{ 400, 304, 488, 392 }, // Button 8 - copy of button 2, to be redefined in the code
{ 312, 304, 400, 392 }, // Button 9 - copy of button 3, to be redefined in the code
{ 400, 216, 488, 304 }, // Button 10 - copy of button 4, to be redefined in the code
{ 312, 216, 400, 304 }, // Button 11 - copy of button 5, to be redefined in the code
}
: new int[][]
{
{ 0, 303, 177, 480 }, // Main joystick/DPAD
{ 0, 0, 48, 48 }, // Text input button
{ 712, 392, 800, 480 }, // Button 0
{ 624, 392, 712, 480 }, // Button 1
{ 712, 304, 800, 392 }, // Button 2
{ 624, 304, 712, 392 }, // Button 3
{ 712, 216, 800, 304 }, // Button 4
{ 624, 216, 712, 304 }, // Button 5
{ 0, 0, 0, 0, }, // Joystick 2
{ 0, 0, 0, 0, }, // Joystick 3
{ 536, 392, 624, 480 }, // Button 6
{ 448, 392, 536, 480 }, // Button 7
{ 536, 304, 624, 392 }, // Button 8
{ 448, 304, 536, 392 }, // Button 9
{ 536, 216, 624, 304 }, // Button 10
{ 448, 216, 536, 304 }, // Button 11
};
public static int RemapScreenKbKeycode[] = new int[6];
public static int ScreenKbControlsLayout[][] = AppUsesThirdJoystick ? // Values for 800x480 resolution
new int[][] { { 0, 303, 177, 480 }, { 0, 0, 48, 48 }, { 400, 392, 488, 480 }, { 312, 392, 400, 480 }, { 400, 304, 488, 392 }, { 312, 304, 400, 392 }, { 400, 216, 488, 304 }, { 312, 216, 400, 304 }, { 623, 303, 800, 480 }, { 623, 126, 800, 303 } } :
AppUsesSecondJoystick ?
new int[][] { { 0, 303, 177, 480 }, { 0, 0, 48, 48 }, { 400, 392, 488, 480 }, { 312, 392, 400, 480 }, { 400, 304, 488, 392 }, { 312, 304, 400, 392 }, { 400, 216, 488, 304 }, { 312, 216, 400, 304 }, { 623, 303, 800, 480 } } :
new int[][] { { 0, 303, 177, 480 }, { 0, 0, 48, 48 }, { 712, 392, 800, 480 }, { 624, 392, 712, 480 }, { 712, 304, 800, 392 }, { 624, 304, 712, 392 }, { 712, 216, 800, 304 }, { 624, 216, 712, 304 } };
public static boolean ScreenKbControlsShown[] = new boolean[ScreenKbControlsLayout.length]; /* Also joystick and text input button added */
public static int RemapMultitouchGestureKeycode[] = new int[4];
public static boolean MultitouchGesturesUsed[] = new boolean[4];

View File

@@ -278,7 +278,7 @@ class SDL_1_2_Keycodes
// Autogenerated by hand with a command:
// grep 'SDL_SCANCODE_' SDL_scancode.h | sed 's/SDL_SCANCODE_\([a-zA-Z0-9_]\+\).*[=] \([0-9]\+\).*/public static final int SDLK_\1 = \2;/' >> Keycodes.java
class SDL_2_Keycodes
class SDL_1_3_Keycodes
{
public static final int SDLK_UNKNOWN = 0;
public static final int SDLK_A = 4;
@@ -519,10 +519,6 @@ class SDL_2_Keycodes
public static final int SDLK_KBDILLUMUP = 280;
public static final int SDLK_EJECT = 281;
public static final int SDLK_SLEEP = 282;
public static final int SDLK_APP1 = 283;
public static final int SDLK_APP2 = 284;
public static final int SDLK_AUDIOREWIND = 285;
public static final int SDLK_AUDIOFASTFORWARD = 286;
// Mouse buttons can be mapped to on-screen keys
public static final int SDLK_MOUSE_LEFT = 500;
@@ -562,9 +558,9 @@ class SDL_Keys
ArrayList<String> Names = new ArrayList<String> ();
ArrayList<Integer> Values = new ArrayList<Integer> ();
Field [] fields = SDL_1_2_Keycodes.class.getDeclaredFields();
if( Globals.UsingSDL2 )
if( Globals.Using_SDL_1_3 )
{
fields = SDL_2_Keycodes.class.getDeclaredFields();
fields = SDL_1_3_Keycodes.class.getDeclaredFields();
}
try {

View File

@@ -43,7 +43,6 @@ import android.widget.RelativeLayout;
import android.graphics.drawable.Drawable;
import android.graphics.Color;
import android.content.res.Configuration;
import android.content.pm.ApplicationInfo;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
@@ -118,10 +117,6 @@ public class MainActivity extends Activity
getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
// We need to load Globals.DrawInDisplayCutout option to correctly set fullscreen mode, it can only be done from onCreate()
Settings.LoadConfig(this);
DimSystemStatusBar.dim(null, getWindow());
Log.i("SDL", "libSDL: Creating startup screen");
_layout = new LinearLayout(this);
_layout.setOrientation(LinearLayout.VERTICAL);
@@ -187,32 +182,6 @@ public class MainActivity extends Activity
_videoLayout.setFocusable(true);
_videoLayout.setFocusableInTouchMode(true);
_videoLayout.requestFocus();
DimSystemStatusBar.dim(_videoLayout, getWindow());
//Log.i("SDL", "Checking for asset pack");
try
{
if( android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP )
{
ApplicationInfo info = this.getPackageManager().getApplicationInfo(this.getPackageName(), 0);
if( info.splitSourceDirs != null )
{
for( String apk: info.splitSourceDirs )
{
Log.i("SDL", "Package apk: " + apk);
if( apk.endsWith("assetpack.apk") )
{
this.assetPackPath = apk;
Log.i("SDL", "Found asset pack: " + this.assetPackPath);
}
}
}
}
}
catch( Exception eee )
{
Log.i("SDL", "Asset pack exception: " + eee);
}
class Callback implements Runnable
{
@@ -236,9 +205,8 @@ public class MainActivity extends Activity
public MainActivity Parent;
public void run()
{
Settings.ProcessConfig(Parent);
Settings.Load(Parent);
setScreenOrientation();
DimSystemStatusBar.dim(_videoLayout, getWindow());
loaded.release();
loadedLibraries.release();
if( _btn != null )
@@ -346,11 +314,11 @@ public class MainActivity extends Activity
this.runOnUiThread(cb);
}
public void downloadFinishedInitSDL()
public void initSDL()
{
setScreenOrientation();
updateScreenOrientation();
DimSystemStatusBar.dim(_videoLayout, getWindow());
DimSystemStatusBar.get().dim(_videoLayout);
(new Thread(new Runnable()
{
public void run()
@@ -369,7 +337,7 @@ public class MainActivity extends Activity
Log.i("SDL", "libSDL: Application paused, cancelling SDL initialization until it will be brought to foreground");
return;
}
DimSystemStatusBar.dim(_videoLayout, getWindow());
DimSystemStatusBar.get().dim(_videoLayout);
}
runOnUiThread(new Runnable()
{
@@ -383,7 +351,7 @@ public class MainActivity extends Activity
if( android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT && Globals.ImmersiveMode &&
(_videoLayout.getHeight() != dm.widthPixels || _videoLayout.getWidth() != dm.heightPixels) )
{
DimSystemStatusBar.dim(_videoLayout, getWindow());
DimSystemStatusBar.get().dim(_videoLayout);
try {
Thread.sleep(300);
} catch( Exception e ) {}
@@ -402,7 +370,7 @@ public class MainActivity extends Activity
Log.i("SDL", "libSDL: Initializing video and SDL application");
sdlInited = true;
DimSystemStatusBar.dim(_videoLayout, getWindow());
DimSystemStatusBar.get().dim(_videoLayout);
_videoLayout.removeView(_layout);
if( _ad.getView() != null )
_videoLayout.removeView(_ad.getView());
@@ -497,8 +465,8 @@ public class MainActivity extends Activity
_videoLayout.addView(_ad.getView());
_ad.getView().setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.TOP | Gravity.RIGHT));
}
DimSystemStatusBar.dim(_videoLayout, getWindow());
//DimSystemStatusBar.dim(mGLView, getWindow());
DimSystemStatusBar.get().dim(_videoLayout);
//DimSystemStatusBar.get().dim(mGLView);
Rect r = new Rect();
_videoLayout.getWindowVisibleDisplayFrame(r);
@@ -508,40 +476,15 @@ public class MainActivity extends Activity
public void onGlobalLayout()
{
final Rect r = new Rect();
//_videoLayout.getWindowVisibleDisplayFrame(r);
final int xy[] = new int[] { 0, 0 };
_videoLayout.getLocationInWindow(xy);
r.left = xy[0];
r.top = xy[1];
r.right = r.left + _videoLayout.getWidth();
r.bottom = r.top + _videoLayout.getHeight();
//boolean cutoutLeft = false, cutoutTop = false;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P && Globals.ImmersiveMode)
{
if (getWindow().getDecorView() != null && getWindow().getDecorView().getRootWindowInsets() != null &&
getWindow().getDecorView().getRootWindowInsets().getDisplayCutout() != null)
{
android.view.DisplayCutout cutout = getWindow().getDecorView().getRootWindowInsets().getDisplayCutout();
Log.v("SDL", "Detected display cutout");
// TODO: do something with it
//if (cutout.getBoundingRectLeft().width() > 0)
// cutoutLeft = true;
//if (cutout.getBoundingRectTop().height() > 0)
// cutoutTop = true;
}
}
_videoLayout.getWindowVisibleDisplayFrame(r);
final int heightDiff = _videoLayout.getRootView().getHeight() - _videoLayout.getHeight(); // Take system bar into consideration
final int widthDiff = _videoLayout.getRootView().getWidth() - _videoLayout.getWidth(); // Nexus 5 has system bar at the right side
Log.v("SDL", "Main window visible region changed: " + r.left + ":" + r.top + ":" + r.width() + ":" + r.height() + " -> " +
(r.left + widthDiff) + ":" + (r.top + heightDiff) + ":" + r.width() + ":" + r.height());
Log.v("SDL", "videoLayout: " + _videoLayout.getLeft() + ":" + _videoLayout.getTop() + ":" + _videoLayout.getWidth() + ":" + _videoLayout.getHeight() +
" videoLayout.getRootView() " + _videoLayout.getRootView().getLeft() + ":" + _videoLayout.getRootView().getTop() + ":" +
_videoLayout.getRootView().getWidth() + ":" + _videoLayout.getRootView().getHeight());
Log.v("SDL", "Main window visible region changed: " + r.left + ":" + r.top + ":" + r.width() + ":" + r.height() );
_videoLayout.postDelayed( new Runnable()
{
public void run()
{
DimSystemStatusBar.dim(_videoLayout, getWindow());
DimSystemStatusBar.get().dim(_videoLayout);
mGLView.nativeScreenVisibleRect(r.left + widthDiff, r.top + heightDiff, r.width(), r.height());
}
}, 300 );
@@ -549,7 +492,7 @@ public class MainActivity extends Activity
{
public void run()
{
DimSystemStatusBar.dim(_videoLayout, getWindow());
DimSystemStatusBar.get().dim(_videoLayout);
mGLView.nativeScreenVisibleRect(r.left + widthDiff, r.top + heightDiff, r.width(), r.height());
}
}, 600 );
@@ -579,8 +522,8 @@ public class MainActivity extends Activity
super.onResume();
if( mGLView != null )
{
DimSystemStatusBar.dim(_videoLayout, getWindow());
//DimSystemStatusBar.dim(mGLView, getWindow());
DimSystemStatusBar.get().dim(_videoLayout);
//DimSystemStatusBar.get().dim(mGLView);
mGLView.onResume();
}
else
@@ -591,7 +534,7 @@ public class MainActivity extends Activity
downloader.setStatusField(_tv);
if( downloader.DownloadComplete )
{
downloadFinishedInitSDL();
initSDL();
}
}
}
@@ -857,8 +800,8 @@ public class MainActivity extends Activity
}
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
_inputManager.hideSoftInputFromWindow(mGLView.getWindowToken(), 0);
DimSystemStatusBar.dim(_videoLayout, getWindow());
//DimSystemStatusBar.dim(mGLView, getWindow());
DimSystemStatusBar.get().dim(_videoLayout);
//DimSystemStatusBar.get().dim(mGLView);
mGLView.captureMouse(true);
}
});
@@ -995,13 +938,13 @@ public class MainActivity extends Activity
_videoLayout.removeView(_screenKeyboard);
_screenKeyboard = null;
mGLView.captureMouse(true);
DimSystemStatusBar.dim(_videoLayout, getWindow());
DimSystemStatusBar.get().dim(_videoLayout);
_videoLayout.postDelayed( new Runnable()
{
public void run()
{
DimSystemStatusBar.dim(_videoLayout, getWindow());
DimSystemStatusBar.get().dim(_videoLayout);
}
}, 500 );
};
@@ -1300,11 +1243,6 @@ public class MainActivity extends Activity
if( entry.isDirectory() )
{
File outDir = new File( libDir.getAbsolutePath() + "/" + entry.getName() );
if( !outDir.getCanonicalPath().startsWith(libDir.getAbsolutePath() + "/") )
{
Log.i("SDL", "Security exception: " + outDir.getCanonicalPath());
return;
}
if( !(outDir.exists() && outDir.isDirectory()) )
outDir.mkdirs();
continue;
@@ -1315,11 +1253,6 @@ public class MainActivity extends Activity
try
{
File outDir = new File( path.substring(0, path.lastIndexOf("/") ));
if( !outDir.getCanonicalPath().startsWith(libDir.getAbsolutePath() + "/") )
{
Log.i("SDL", "Security exception: " + outDir.getCanonicalPath());
return;
}
if( !(outDir.exists() && outDir.isDirectory()) )
outDir.mkdirs();
}
@@ -1341,11 +1274,6 @@ public class MainActivity extends Activity
} catch( Exception eeeeee ) { }
Log.i("SDL", "Saving to file '" + path + "'");
if( !(new File(path).getCanonicalPath().startsWith(libDir.getAbsolutePath() + "/")) )
{
Log.i("SDL", "Security exception: " + path);
return;
}
out = new FileOutputStream( path );
int len = zip.read(buf);
@@ -1492,11 +1420,6 @@ public class MainActivity extends Activity
{
Log.i("SDL", "libSDL: Record audio permission: " + (grantResults[0] == PackageManager.PERMISSION_GRANTED ? "GRANTED" : "DENIED"));
}
if (Manifest.permission.READ_EXTERNAL_STORAGE.equals(permissions[0]))
{
Log.i("SDL", "libSDL: Read external storage permission: " + (grantResults[0] == PackageManager.PERMISSION_GRANTED ? "GRANTED" : "DENIED"));
readExternalStoragePermissionDialogAnswered = true;
}
if (Manifest.permission.WRITE_EXTERNAL_STORAGE.equals(permissions[0]))
{
Log.i("SDL", "libSDL: Write external storage permission: " + (grantResults[0] == PackageManager.PERMISSION_GRANTED ? "GRANTED" : "DENIED"));
@@ -1538,46 +1461,44 @@ public class MainActivity extends Activity
public LinkedList<Integer> textInput = new LinkedList<Integer> ();
public static MainActivity instance = null;
public boolean readExternalStoragePermissionDialogAnswered = false;
public boolean writeExternalStoragePermissionDialogAnswered = false;
public String ObbMountPath = null;
public String assetPackPath = null; // Not saved to the config file
}
// *** HONEYCOMB / ICS FIX FOR FULLSCREEN MODE, by lmak ***
class DimSystemStatusBar
abstract class DimSystemStatusBar
{
public static void dim(final View view, final Window window)
public static DimSystemStatusBar get()
{
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT && Globals.ImmersiveMode)
{
// Immersive mode, I already hear curses when system bar reappears mid-game from the slightest swipe at the bottom of the screen
//Log.i("SDL", "libSDL: Enabling fullscreen, Android SDK " + android.os.Build.VERSION.SDK_INT + " VERSION_CODES.P " + android.os.Build.VERSION_CODES.P);
if( android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P )
{
//Log.i("SDL", "libSDL: Setting display cutout mode to SHORT_EDGES");
if (Globals.DrawInDisplayCutout)
window.getAttributes().layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
else
window.getAttributes().layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
}
if (view != null)
{
view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
}
}
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB)
return DimSystemStatusBarHoneycomb.Holder.sInstance;
else
return DimSystemStatusBarDummy.Holder.sInstance;
}
public abstract void dim(final View view);
private static class DimSystemStatusBarHoneycomb extends DimSystemStatusBar
{
private static class Holder
{
if (view != null)
{
private static final DimSystemStatusBarHoneycomb sInstance = new DimSystemStatusBarHoneycomb();
}
public void dim(final View view)
{
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT && Globals.ImmersiveMode)
// Immersive mode, I already hear curses when system bar reappears mid-game from the slightest swipe at the bottom of the screen
view.setSystemUiVisibility(android.view.View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | android.view.View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | android.view.View.SYSTEM_UI_FLAG_FULLSCREEN);
else
view.setSystemUiVisibility(android.view.View.SYSTEM_UI_FLAG_LOW_PROFILE);
}
}
}
private static class DimSystemStatusBarDummy extends DimSystemStatusBar
{
private static class Holder
{
private static final DimSystemStatusBarDummy sInstance = new DimSystemStatusBarDummy();
}
public void dim(final View view)
{
}
}
}

View File

@@ -1,56 +0,0 @@
/*
Simple DirectMedia Layer
Java source code (C) 2009-2014 Sergii Pylypenko
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
package net.sourceforge.clonekeenplus;
class Mouse
{
public static final int LEFT_CLICK_NORMAL = 0;
public static final int LEFT_CLICK_NEAR_CURSOR = 1;
public static final int LEFT_CLICK_WITH_MULTITOUCH = 2;
public static final int LEFT_CLICK_WITH_PRESSURE = 3;
public static final int LEFT_CLICK_WITH_KEY = 4;
public static final int LEFT_CLICK_WITH_TIMEOUT = 5;
public static final int LEFT_CLICK_WITH_TAP = 6;
public static final int LEFT_CLICK_WITH_TAP_OR_TIMEOUT = 7;
public static final int RIGHT_CLICK_NONE = 0;
public static final int RIGHT_CLICK_WITH_MULTITOUCH = 1;
public static final int RIGHT_CLICK_WITH_PRESSURE = 2;
public static final int RIGHT_CLICK_WITH_KEY = 3;
public static final int RIGHT_CLICK_WITH_TIMEOUT = 4;
public static final int SDL_FINGER_DOWN = 0;
public static final int SDL_FINGER_UP = 1;
public static final int SDL_FINGER_MOVE = 2;
public static final int SDL_FINGER_HOVER = 3;
public static final int ZOOM_NONE = 0;
public static final int ZOOM_MAGNIFIER = 1;
public static final int MOUSE_HW_INPUT_FINGER = 0;
public static final int MOUSE_HW_INPUT_STYLUS = 1;
public static final int MOUSE_HW_INPUT_MOUSE = 2;
public static final int MAX_HOVER_DISTANCE = 1024;
public static final int HOVER_REDRAW_SCREEN = 1024 * 10;
public static final float MAX_PRESSURE = 1024.0f;
}

View File

@@ -87,7 +87,6 @@ public class Settings
static boolean settingsChanged = false;
static final int SETTINGS_FILE_VERSION = 5;
static boolean convertButtonSizeFromOldSdlVersion = false;
static int settingsAppVersion = 0;
static void Save(final MainActivity p)
{
@@ -192,7 +191,6 @@ public class Settings
out.writeBoolean(Globals.ForceHardwareMouse);
convertButtonSizeFromOldSdlVersion = false;
out.writeBoolean(convertButtonSizeFromOldSdlVersion);
out.writeBoolean(Globals.DrawInDisplayCutout);
out.close();
settingsLoaded = true;
@@ -202,157 +200,13 @@ public class Settings
} catch ( IOException e ) {};
}
static boolean LoadConfig( final MainActivity p )
static void Load( final MainActivity p )
{
Globals.OptionalDataDownload = new boolean[Globals.DataDownloadUrl.length];
for( int i = 0; i < Globals.DataDownloadUrl.length; i++ )
{
if( Globals.DataDownloadUrl[i].indexOf("!") == 0 )
{
Globals.OptionalDataDownload[i] = true;
}
}
try {
ObjectInputStream settingsFile = new ObjectInputStream(new FileInputStream( p.getFilesDir().getAbsolutePath() + "/" + SettingsFileName ));
if( settingsFile.readInt() != SETTINGS_FILE_VERSION )
throw new IOException();
Globals.DownloadToSdcard = settingsFile.readBoolean();
Globals.PhoneHasArrowKeys = settingsFile.readBoolean();
settingsFile.readBoolean();
Globals.UseAccelerometerAsArrowKeys = settingsFile.readBoolean();
Globals.UseTouchscreenKeyboard = settingsFile.readBoolean();
Globals.TouchscreenKeyboardSize = settingsFile.readInt();
convertButtonSizeFromOldSdlVersion = true; // Will be changed to false if we read the remainder of the config file
Globals.AccelerometerSensitivity = settingsFile.readInt();
Globals.AccelerometerCenterPos = settingsFile.readInt();
settingsFile.readInt();
Globals.AudioBufferConfig = settingsFile.readInt();
Globals.TouchscreenKeyboardTheme = settingsFile.readInt();
Globals.RightClickMethod = settingsFile.readInt();
Globals.ShowScreenUnderFinger = settingsFile.readInt();
Globals.LeftClickMethod = settingsFile.readInt();
Globals.MoveMouseWithJoystick = settingsFile.readBoolean();
Globals.ClickMouseWithDpad = settingsFile.readBoolean();
Globals.ClickScreenPressure = settingsFile.readInt();
Globals.ClickScreenTouchspotSize = settingsFile.readInt();
Globals.KeepAspectRatio = settingsFile.readBoolean();
Globals.MoveMouseWithJoystickSpeed = settingsFile.readInt();
Globals.MoveMouseWithJoystickAccel = settingsFile.readInt();
int readKeysSize = settingsFile.readInt();
for( int i = 0; i < readKeysSize; i++ )
{
Globals.RemapHwKeycode[i] = settingsFile.readInt();
}
int readScreenKbRemapKeysSize = settingsFile.readInt();
if( readScreenKbRemapKeysSize > Globals.RemapScreenKbKeycode.length )
throw new IOException();
for( int i = 0; i < readScreenKbRemapKeysSize; i++ )
{
Globals.RemapScreenKbKeycode[i] = settingsFile.readInt();
}
int readScreenKbShownSize = settingsFile.readInt();
if( readScreenKbShownSize > Globals.ScreenKbControlsShown.length )
throw new IOException();
for( int i = 0; i < readScreenKbShownSize; i++ )
{
Globals.ScreenKbControlsShown[i] = settingsFile.readBoolean();
}
Globals.TouchscreenKeyboardTransparency = settingsFile.readInt();
if( settingsFile.readInt() != Globals.RemapMultitouchGestureKeycode.length )
throw new IOException();
for( int i = 0; i < Globals.RemapMultitouchGestureKeycode.length; i++ )
{
Globals.RemapMultitouchGestureKeycode[i] = settingsFile.readInt();
Globals.MultitouchGesturesUsed[i] = settingsFile.readBoolean();
}
Globals.MultitouchGestureSensitivity = settingsFile.readInt();
for( int i = 0; i < Globals.TouchscreenCalibration.length; i++ )
Globals.TouchscreenCalibration[i] = settingsFile.readInt();
StringBuilder b = new StringBuilder();
int len = settingsFile.readInt();
for( int i = 0; i < len; i++ )
b.append( settingsFile.readChar() );
Globals.DataDir = b.toString();
b = new StringBuilder();
len = settingsFile.readInt();
for( int i = 0; i < len; i++ )
b.append( settingsFile.readChar() );
Globals.CommandLine = b.toString();
int screenKbControlsLayoutSize = settingsFile.readInt();
if( screenKbControlsLayoutSize > Globals.ScreenKbControlsLayout.length )
throw new IOException();
for( int i = 0; i < screenKbControlsLayoutSize; i++ )
for( int ii = 0; ii < 4; ii++ )
Globals.ScreenKbControlsLayout[i][ii] = settingsFile.readInt();
Globals.LeftClickKey = settingsFile.readInt();
Globals.RightClickKey = settingsFile.readInt();
Globals.VideoLinearFilter = settingsFile.readBoolean();
Globals.LeftClickTimeout = settingsFile.readInt();
Globals.RightClickTimeout = settingsFile.readInt();
Globals.RelativeMouseMovement = settingsFile.readBoolean();
Globals.RelativeMouseMovementSpeed = settingsFile.readInt();
Globals.RelativeMouseMovementAccel = settingsFile.readInt();
Globals.MultiThreadedVideo = settingsFile.readBoolean();
Globals.OptionalDataDownload = new boolean[settingsFile.readInt()];
for(int i = 0; i < Globals.OptionalDataDownload.length; i++)
Globals.OptionalDataDownload[i] = settingsFile.readBoolean();
settingsFile.readBoolean(); // Unused
Globals.TouchscreenKeyboardDrawSize = settingsFile.readInt();
settingsAppVersion = settingsFile.readInt();
// Gyroscope calibration data, now unused
settingsFile.readFloat();
settingsFile.readFloat();
settingsFile.readFloat();
settingsFile.readFloat();
settingsFile.readFloat();
settingsFile.readFloat();
settingsFile.readFloat();
settingsFile.readFloat();
settingsFile.readFloat();
Globals.OuyaEmulation = settingsFile.readBoolean();
Globals.HoverJitterFilter = settingsFile.readBoolean();
Globals.MoveMouseWithGyroscope = settingsFile.readBoolean();
Globals.MoveMouseWithGyroscopeSpeed = settingsFile.readInt();
Globals.FingerHover = settingsFile.readBoolean();
Globals.FloatingScreenJoystick = settingsFile.readBoolean();
Globals.GenerateSubframeTouchEvents = settingsFile.readBoolean();
Globals.VideoDepthBpp = settingsFile.readInt();
Globals.HorizontalOrientation = settingsFile.readBoolean();
Globals.ImmersiveMode = settingsFile.readBoolean();
Globals.AutoDetectOrientation = settingsFile.readBoolean();
Globals.TvBorders = settingsFile.readBoolean();
Globals.ForceHardwareMouse = settingsFile.readBoolean();
convertButtonSizeFromOldSdlVersion = settingsFile.readBoolean();
Globals.DrawInDisplayCutout = settingsFile.readBoolean();
Log.i("SDL", "libSDL: Settings.LoadConfig(): loaded settings successfully");
settingsFile.close();
return true;
} catch( FileNotFoundException e ) {
Log.i("SDL", "libSDL: settings file not found: " + e);
} catch( SecurityException e ) {
Log.i("SDL", "libSDL: settings file cannot be opened: " + e);
} catch( IOException e ) {
Log.i("SDL", "libSDL: settings file cannot be read: " + e);
}
return false;
}
static void ProcessConfig( final MainActivity p )
{
if( settingsLoaded ) // Prevent starting twice
if(settingsLoaded) // Prevent starting twice
{
return;
}
Log.i("SDL", "libSDL: Settings.ProcessConfig(): enter");
Log.i("SDL", "libSDL: Settings.Load(): enter");
nativeInitKeymap();
for( int i = 0; i < SDL_Keys.JAVA_KEYCODE_LAST; i++ )
{
@@ -374,14 +228,12 @@ public class Settings
}
Globals.ScreenKbControlsShown[0] = (Globals.AppNeedsArrowKeys || Globals.AppUsesJoystick);
Globals.ScreenKbControlsShown[1] = Globals.AppNeedsTextInput;
for( int i = 2; i < 8; i++ )
for( int i = 2; i < Globals.ScreenKbControlsShown.length; i++ )
Globals.ScreenKbControlsShown[i] = ( i - 2 < Globals.AppTouchscreenKeyboardKeysAmount );
if( Globals.AppUsesSecondJoystick )
Globals.ScreenKbControlsShown[8] = true;
if( Globals.AppUsesThirdJoystick )
Globals.ScreenKbControlsShown[9] = true;
for( int i = 10; i < Globals.ScreenKbControlsShown.length; i++ )
Globals.ScreenKbControlsShown[i] = ( i - 4 < Globals.AppTouchscreenKeyboardKeysAmount );
for( int i = 0; i < Globals.RemapMultitouchGestureKeycode.length; i++ )
{
int sdlKey = nativeGetKeymapKeyMultitouchGesture(i);
@@ -424,18 +276,131 @@ public class Settings
}
convertButtonSizeFromOldSdlVersion = false;
settingsLoaded = LoadConfig(p);
try {
ObjectInputStream settingsFile = new ObjectInputStream(new FileInputStream( p.getFilesDir().getAbsolutePath() + "/" + SettingsFileName ));
if( settingsFile.readInt() != SETTINGS_FILE_VERSION )
throw new IOException();
Globals.DownloadToSdcard = settingsFile.readBoolean();
Globals.PhoneHasArrowKeys = settingsFile.readBoolean();
settingsFile.readBoolean();
Globals.UseAccelerometerAsArrowKeys = settingsFile.readBoolean();
Globals.UseTouchscreenKeyboard = settingsFile.readBoolean();
Globals.TouchscreenKeyboardSize = settingsFile.readInt();
convertButtonSizeFromOldSdlVersion = true; // Will be changed to false if we read the remainder of the config file
Globals.AccelerometerSensitivity = settingsFile.readInt();
Globals.AccelerometerCenterPos = settingsFile.readInt();
settingsFile.readInt();
Globals.AudioBufferConfig = settingsFile.readInt();
Globals.TouchscreenKeyboardTheme = settingsFile.readInt();
Globals.RightClickMethod = settingsFile.readInt();
Globals.ShowScreenUnderFinger = settingsFile.readInt();
Globals.LeftClickMethod = settingsFile.readInt();
Globals.MoveMouseWithJoystick = settingsFile.readBoolean();
Globals.ClickMouseWithDpad = settingsFile.readBoolean();
Globals.ClickScreenPressure = settingsFile.readInt();
Globals.ClickScreenTouchspotSize = settingsFile.readInt();
Globals.KeepAspectRatio = settingsFile.readBoolean();
Globals.MoveMouseWithJoystickSpeed = settingsFile.readInt();
Globals.MoveMouseWithJoystickAccel = settingsFile.readInt();
int readKeys = settingsFile.readInt();
for( int i = 0; i < readKeys; i++ )
{
Globals.RemapHwKeycode[i] = settingsFile.readInt();
}
if( settingsFile.readInt() != Globals.RemapScreenKbKeycode.length )
throw new IOException();
for( int i = 0; i < Globals.RemapScreenKbKeycode.length; i++ )
{
Globals.RemapScreenKbKeycode[i] = settingsFile.readInt();
}
if( settingsFile.readInt() != Globals.ScreenKbControlsShown.length )
throw new IOException();
for( int i = 0; i < Globals.ScreenKbControlsShown.length; i++ )
{
Globals.ScreenKbControlsShown[i] = settingsFile.readBoolean();
}
Globals.TouchscreenKeyboardTransparency = settingsFile.readInt();
if( settingsFile.readInt() != Globals.RemapMultitouchGestureKeycode.length )
throw new IOException();
for( int i = 0; i < Globals.RemapMultitouchGestureKeycode.length; i++ )
{
Globals.RemapMultitouchGestureKeycode[i] = settingsFile.readInt();
Globals.MultitouchGesturesUsed[i] = settingsFile.readBoolean();
}
Globals.MultitouchGestureSensitivity = settingsFile.readInt();
for( int i = 0; i < Globals.TouchscreenCalibration.length; i++ )
Globals.TouchscreenCalibration[i] = settingsFile.readInt();
StringBuilder b = new StringBuilder();
int len = settingsFile.readInt();
for( int i = 0; i < len; i++ )
b.append( settingsFile.readChar() );
Globals.DataDir = b.toString();
if (settingsLoaded)
{
Log.i("SDL", "libSDL: Settings.ProcessConfig(): loaded settings successfully");
Log.i("SDL", "libSDL: old app version " + settingsAppVersion + ", new app version " + p.getApplicationVersion());
if( settingsAppVersion != p.getApplicationVersion() )
b = new StringBuilder();
len = settingsFile.readInt();
for( int i = 0; i < len; i++ )
b.append( settingsFile.readChar() );
Globals.CommandLine = b.toString();
if( settingsFile.readInt() != Globals.ScreenKbControlsLayout.length )
throw new IOException();
for( int i = 0; i < Globals.ScreenKbControlsLayout.length; i++ )
for( int ii = 0; ii < 4; ii++ )
Globals.ScreenKbControlsLayout[i][ii] = settingsFile.readInt();
Globals.LeftClickKey = settingsFile.readInt();
Globals.RightClickKey = settingsFile.readInt();
Globals.VideoLinearFilter = settingsFile.readBoolean();
Globals.LeftClickTimeout = settingsFile.readInt();
Globals.RightClickTimeout = settingsFile.readInt();
Globals.RelativeMouseMovement = settingsFile.readBoolean();
Globals.RelativeMouseMovementSpeed = settingsFile.readInt();
Globals.RelativeMouseMovementAccel = settingsFile.readInt();
Globals.MultiThreadedVideo = settingsFile.readBoolean();
Globals.OptionalDataDownload = new boolean[settingsFile.readInt()];
for(int i = 0; i < Globals.OptionalDataDownload.length; i++)
Globals.OptionalDataDownload[i] = settingsFile.readBoolean();
settingsFile.readBoolean(); // Unused
Globals.TouchscreenKeyboardDrawSize = settingsFile.readInt();
int cfgVersion = settingsFile.readInt();
// Gyroscope calibration data, now unused
settingsFile.readFloat();
settingsFile.readFloat();
settingsFile.readFloat();
settingsFile.readFloat();
settingsFile.readFloat();
settingsFile.readFloat();
settingsFile.readFloat();
settingsFile.readFloat();
settingsFile.readFloat();
Globals.OuyaEmulation = settingsFile.readBoolean();
Globals.HoverJitterFilter = settingsFile.readBoolean();
Globals.MoveMouseWithGyroscope = settingsFile.readBoolean();
Globals.MoveMouseWithGyroscopeSpeed = settingsFile.readInt();
Globals.FingerHover = settingsFile.readBoolean();
Globals.FloatingScreenJoystick = settingsFile.readBoolean();
Globals.GenerateSubframeTouchEvents = settingsFile.readBoolean();
Globals.VideoDepthBpp = settingsFile.readInt();
Globals.HorizontalOrientation = settingsFile.readBoolean();
Globals.ImmersiveMode = settingsFile.readBoolean();
Globals.AutoDetectOrientation = settingsFile.readBoolean();
Globals.TvBorders = settingsFile.readBoolean();
Globals.ForceHardwareMouse = settingsFile.readBoolean();
convertButtonSizeFromOldSdlVersion = settingsFile.readBoolean();
settingsLoaded = true;
Log.i("SDL", "libSDL: Settings.Load(): loaded settings successfully");
settingsFile.close();
Log.i("SDL", "libSDL: old cfg version " + cfgVersion + ", our version " + p.getApplicationVersion());
if( cfgVersion != p.getApplicationVersion() )
{
DeleteFilesOnUpgrade(p);
if( Globals.ResetSdlConfigForThisVersion )
{
Log.i("SDL", "libSDL: old app version " + settingsAppVersion + ", new app version " + p.getApplicationVersion() + " and we need to clean up config file");
Log.i("SDL", "libSDL: old cfg version " + cfgVersion + ", our version " + p.getApplicationVersion() + " and we need to clean up config file");
// Delete settings file, and restart the application
DeleteSdlConfigOnUpgradeAndRestart(p);
}
@@ -443,21 +408,26 @@ public class Settings
}
return;
}
Log.i("SDL", "libSDL: settings cannot be loaded");
DeleteFilesOnUpgrade(p);
if (convertButtonSizeFromOldSdlVersion && Globals.TouchscreenKeyboardSize + 1 < Globals.TOUCHSCREEN_KEYBOARD_CUSTOM)
{
Globals.TouchscreenKeyboardSize ++; // New default button size is bigger, but we are keeping old button size for existing installations
//if (Globals.AppTouchscreenKeyboardKeysAmount <= 4 && Globals.TouchscreenKeyboardSize + 1 < Globals.TOUCHSCREEN_KEYBOARD_CUSTOM)
// Globals.TouchscreenKeyboardSize ++; // If there are only 4 buttons they are even bigger
}
if( Globals.ResetSdlConfigForThisVersion && settingsAppVersion != 0 )
{
Log.i("SDL", "libSDL: old cfg version unknown or too old, our version " + p.getApplicationVersion() + " and we need to clean up config file");
DeleteSdlConfigOnUpgradeAndRestart(p);
}
} catch( FileNotFoundException e ) {
Log.i("SDL", "libSDL: settings file not found: " + e);
} catch( SecurityException e ) {
Log.i("SDL", "libSDL: settings file cannot be opened: " + e);
} catch( IOException e ) {
Log.i("SDL", "libSDL: settings file cannot be read: " + e);
DeleteFilesOnUpgrade(p);
if (convertButtonSizeFromOldSdlVersion && Globals.TouchscreenKeyboardSize + 1 < Globals.TOUCHSCREEN_KEYBOARD_CUSTOM)
{
Globals.TouchscreenKeyboardSize ++; // New default button size is bigger, but we are keeping old button size for existing installations
//if (Globals.AppTouchscreenKeyboardKeysAmount <= 4 && Globals.TouchscreenKeyboardSize + 1 < Globals.TOUCHSCREEN_KEYBOARD_CUSTOM)
// Globals.TouchscreenKeyboardSize ++; // If there are only 4 buttons they are even bigger
}
if( Globals.ResetSdlConfigForThisVersion )
{
Log.i("SDL", "libSDL: old cfg version unknown or too old, our version " + p.getApplicationVersion() + " and we need to clean up config file");
DeleteSdlConfigOnUpgradeAndRestart(p);
}
};
if( Globals.DataDir.length() == 0 )
{
@@ -638,7 +608,7 @@ public class Settings
Globals.TouchscreenKeyboardTransparency,
Globals.FloatingScreenJoystick ? 1 : 0,
Globals.AppTouchscreenKeyboardKeysAmount );
DemoGLSurfaceView.SetupTouchscreenKeyboardGraphics(p);
SetupTouchscreenKeyboardGraphics(p);
for( int i = 0; i < Globals.RemapScreenKbKeycode.length; i++ )
nativeSetKeymapKeyScreenKb(i, SDL_Keys.values[Globals.RemapScreenKbKeycode[i]]);
if( Globals.TouchscreenKeyboardSize == Globals.TOUCHSCREEN_KEYBOARD_CUSTOM )
@@ -695,14 +665,6 @@ public class Settings
try {
nativeSetEnv( "ANDROID_OBB_DIR", p.getObbDir().getAbsolutePath() );
} catch (Exception eeeeeee) {}
if( p.ObbMountPath != null )
{
nativeSetEnv( "ANDROID_OBB_MOUNT_DIR", p.ObbMountPath );
}
if( p.assetPackPath != null )
{
nativeSetEnv( "ANDROID_ASSET_PACK_PATH", p.assetPackPath );
}
try {
nativeSetEnv( "ANDROID_APP_NAME", p.getString(p.getApplicationInfo().labelRes) );
} catch (Exception eeeeee) {}
@@ -745,6 +707,63 @@ public class Settings
} catch (Exception eeeee) {}
}
static byte [] loadRaw(Activity p, int res)
{
byte [] buf = new byte[65536 * 2];
byte [] a = new byte[1048576 * 5]; // We need 5Mb buffer for Keen theme, and this Java code is inefficient
int written = 0;
try{
InputStream is = new GZIPInputStream(p.getResources().openRawResource(res));
int readed = 0;
while( (readed = is.read(buf)) >= 0 )
{
if( written + readed > a.length )
{
byte [] b = new byte [written + readed];
System.arraycopy(a, 0, b, 0, written);
a = b;
}
System.arraycopy(buf, 0, a, written, readed);
written += readed;
}
} catch(Exception e) {};
byte [] b = new byte [written];
System.arraycopy(a, 0, b, 0, written);
return b;
}
static void SetupTouchscreenKeyboardGraphics(Activity p)
{
if( Globals.UseTouchscreenKeyboard )
{
if(Globals.TouchscreenKeyboardTheme < 0)
Globals.TouchscreenKeyboardTheme = 0;
if(Globals.TouchscreenKeyboardTheme > 9)
Globals.TouchscreenKeyboardTheme = 9;
if( Globals.TouchscreenKeyboardTheme == 0 )
nativeSetupScreenKeyboardButtons(loadRaw(p, R.raw.ultimatedroid));
if( Globals.TouchscreenKeyboardTheme == 1 )
nativeSetupScreenKeyboardButtons(loadRaw(p, R.raw.simpletheme));
if( Globals.TouchscreenKeyboardTheme == 2 )
nativeSetupScreenKeyboardButtons(loadRaw(p, R.raw.sun));
if( Globals.TouchscreenKeyboardTheme == 3 )
nativeSetupScreenKeyboardButtons(loadRaw(p, R.raw.keen));
if( Globals.TouchscreenKeyboardTheme == 4 )
nativeSetupScreenKeyboardButtons(loadRaw(p, R.raw.retro));
if( Globals.TouchscreenKeyboardTheme == 5 )
nativeSetupScreenKeyboardButtons(loadRaw(p, R.raw.gba));
if( Globals.TouchscreenKeyboardTheme == 6 )
nativeSetupScreenKeyboardButtons(loadRaw(p, R.raw.psx));
if( Globals.TouchscreenKeyboardTheme == 7 )
nativeSetupScreenKeyboardButtons(loadRaw(p, R.raw.snes));
if( Globals.TouchscreenKeyboardTheme == 8 )
nativeSetupScreenKeyboardButtons(loadRaw(p, R.raw.dualshock));
if( Globals.TouchscreenKeyboardTheme == 9 )
nativeSetupScreenKeyboardButtons(loadRaw(p, R.raw.n64));
}
}
abstract static class SdcardAppPath
{
public static SdcardAppPath get()
@@ -953,7 +972,6 @@ public class Settings
Save(MainActivity.instance);
}
// libsdl-1.2.so, does not exist in SDL2
private static native void nativeSetAccelerometerSettings(int sensitivity, int centerPos);
private static native void nativeSetMouseUsed(int RightClickMethod, int ShowScreenUnderFinger, int LeftClickMethod,
int MoveMouseWithJoystick, int ClickMouseWithDpad, int MaxForce, int MaxRadius,
@@ -965,7 +983,7 @@ public class Settings
int HoverJitterFilter, int RightMouseButtonLongPress,
int MoveMouseWithGyroscope, int MoveMouseWithGyroscopeSpeed,
int ForceScreenUpdateMouseClick, int ScreenFollowsMouse);
public static native void nativeSetJoystickUsed(int amount);
private static native void nativeSetJoystickUsed(int amount);
private static native void nativeSetAccelerometerUsed();
private static native void nativeSetMultitouchUsed();
private static native void nativeSetTouchscreenKeyboardUsed();
@@ -975,7 +993,7 @@ public class Settings
private static native void nativeSetVideoMultithreaded();
private static native void nativeSetVideoForceSoftwareMode();
public static native void nativeSetupScreenKeyboard(int size, int drawsize, int theme, int transparency, int floatingScreenJoystick, int buttonAmount);
public static native void nativeSetupScreenKeyboardButtons(byte[] img);
private static native void nativeSetupScreenKeyboardButtons(byte[] img);
private static native void nativeInitKeymap();
private static native int nativeGetKeymapKey(int key);
private static native void nativeSetKeymapKey(int javakey, int key);
@@ -988,7 +1006,6 @@ public class Settings
private static native void nativeSetKeymapKeyMultitouchGesture(int keynum, int key);
private static native void nativeSetMultitouchGestureSensitivity(int sensitivity);
public static native void nativeSetTouchscreenCalibration(int x1, int y1, int x2, int y2);
// libsdl_native_helpers.so, exists in both versions
public static native void nativeSetEnv(final String name, final String value);
public static native int nativeChmod(final String name, int mode);
public static native void nativeChdir(final String dir);

View File

@@ -386,22 +386,26 @@ class SettingsMenuKeyboard extends SettingsMenu
p.getResources().getString(R.string.remap_screenkb_button) + " 4",
p.getResources().getString(R.string.remap_screenkb_button) + " 5",
p.getResources().getString(R.string.remap_screenkb_button) + " 6",
p.getResources().getString(R.string.remap_screenkb_joystick) + " 2",
p.getResources().getString(R.string.remap_screenkb_joystick) + " 3",
p.getResources().getString(R.string.remap_screenkb_button) + " 7",
p.getResources().getString(R.string.remap_screenkb_button) + " 8",
p.getResources().getString(R.string.remap_screenkb_button) + " 9",
p.getResources().getString(R.string.remap_screenkb_button) + " 10",
p.getResources().getString(R.string.remap_screenkb_button) + " 11",
p.getResources().getString(R.string.remap_screenkb_button) + " 12",
};
boolean defaults[] = Arrays.copyOf(Globals.ScreenKbControlsShown, Globals.ScreenKbControlsShown.length);
if( Globals.AppUsesSecondJoystick )
{
items = Arrays.copyOf(items, items.length + 1);
items[items.length - 1] = p.getResources().getString(R.string.remap_screenkb_joystick) + " 2";
defaults = Arrays.copyOf(defaults, defaults.length + 1);
defaults[defaults.length - 1] = true;
}
if( Globals.AppUsesThirdJoystick )
{
items = Arrays.copyOf(items, items.length + 1);
items[items.length - 1] = p.getResources().getString(R.string.remap_screenkb_joystick) + " 3";
defaults = Arrays.copyOf(defaults, defaults.length + 1);
defaults[defaults.length - 1] = true;
}
for( int i = 0; i < Math.min(6, Globals.AppTouchscreenKeyboardKeysNames.length); i++ )
items[i+2] = items[i+2] + " - " + Globals.AppTouchscreenKeyboardKeysNames[i].replace("_", " ");
for( int i = 6; i < Math.min(12, Globals.AppTouchscreenKeyboardKeysNames.length); i++ )
items[i+4] = items[i+4] + " - " + Globals.AppTouchscreenKeyboardKeysNames[i].replace("_", " ");
AlertDialog.Builder builder = new AlertDialog.Builder(p);
builder.setTitle(p.getResources().getString(R.string.remap_screenkb));
@@ -441,15 +445,9 @@ class SettingsMenuKeyboard extends SettingsMenu
p.getResources().getString(R.string.remap_screenkb_button) + " 4",
p.getResources().getString(R.string.remap_screenkb_button) + " 5",
p.getResources().getString(R.string.remap_screenkb_button) + " 6",
p.getResources().getString(R.string.remap_screenkb_button) + " 7",
p.getResources().getString(R.string.remap_screenkb_button) + " 8",
p.getResources().getString(R.string.remap_screenkb_button) + " 9",
p.getResources().getString(R.string.remap_screenkb_button) + " 10",
p.getResources().getString(R.string.remap_screenkb_button) + " 11",
p.getResources().getString(R.string.remap_screenkb_button) + " 12",
};
for( int i = 0; i < Math.min(12, Globals.AppTouchscreenKeyboardKeysNames.length); i++ )
for( int i = 0; i < Math.min(6, Globals.AppTouchscreenKeyboardKeysNames.length); i++ )
items[i] = items[i] + " - " + Globals.AppTouchscreenKeyboardKeysNames[i].replace("_", " ");
if( currentButton >= Globals.RemapScreenKbKeycode.length )
@@ -457,12 +455,7 @@ class SettingsMenuKeyboard extends SettingsMenu
goBack(p);
return;
}
if( currentButton < 6 && ! Globals.ScreenKbControlsShown[currentButton + 2] )
{
showRemapScreenKbConfig2(p, currentButton + 1);
return;
}
if( currentButton >= 6 && ! Globals.ScreenKbControlsShown[currentButton + 4] )
if( ! Globals.ScreenKbControlsShown[currentButton + 2] )
{
showRemapScreenKbConfig2(p, currentButton + 1);
return;
@@ -634,7 +627,7 @@ class SettingsMenuKeyboard extends SettingsMenu
{
p.setText(p.getResources().getString(R.string.screenkb_custom_layout_help));
if (Globals.ImmersiveMode)
DimSystemStatusBar.dim(p.getVideoLayout(), p.getWindow());
DimSystemStatusBar.get().dim(p.getVideoLayout());
p.getVideoLayout().getHandler().postDelayed(new Runnable()
{
public void run()
@@ -664,25 +657,13 @@ class SettingsMenuKeyboard extends SettingsMenu
R.drawable.b5,
R.drawable.b6,
R.drawable.dpad,
R.drawable.dpad,
R.drawable.b1,
R.drawable.b2,
R.drawable.b3,
R.drawable.b4,
R.drawable.b5,
R.drawable.b6,
R.drawable.dpad
};
int oldX = 0, oldY = 0;
boolean resizing = false;
public CustomizeScreenKbLayoutTool(MainActivity _p)
{
if( buttons.length != Globals.ScreenKbControlsLayout.length )
{
Log.i("SDL", "Assertion failed: buttons.length != Globals.ScreenKbControlsLayout.length" );
throw new RuntimeException("Assertion failed: buttons.length != Globals.ScreenKbControlsLayout.length");
}
p = _p;
layout = new FrameLayout(p);
p.getVideoLayout().addView(layout);
@@ -705,7 +686,6 @@ class SettingsMenuKeyboard extends SettingsMenu
if( Globals.TouchscreenKeyboardSize != Globals.TOUCHSCREEN_KEYBOARD_CUSTOM )
{
DemoRenderer.nativeResize(displayX, displayY, 0);
Settings.nativeSetJoystickUsed( Globals.AppUsesThirdJoystick ? 3 : (Globals.AppUsesSecondJoystick ? 2 : (Globals.AppUsesJoystick ? 1 : 0)) );
Settings.nativeSetupScreenKeyboard( Globals.TouchscreenKeyboardSize,
Globals.TouchscreenKeyboardDrawSize,
Globals.TouchscreenKeyboardTheme,
@@ -800,10 +780,6 @@ class SettingsMenuKeyboard extends SettingsMenu
buttonText = "Joystick 2";
if( i == 9 )
buttonText = "Joystick 3";
if( i >= 10 && i <= 15 )
buttonText = p.getResources().getString(R.string.remap_screenkb_button) + (i - 4);
if( i >= 10 && i - 4 < Globals.AppTouchscreenKeyboardKeysNames.length )
buttonText = Globals.AppTouchscreenKeyboardKeysNames[i - 4].replace("_", " ");
p.setText(p.getResources().getString(R.string.screenkb_custom_layout_help) + "\n" + buttonText);
}
@@ -903,7 +879,7 @@ class SettingsMenuKeyboard extends SettingsMenu
p.getResources().getString(R.string.screenkb_floating_joystick),
};
boolean defaults[] = {
boolean defaults[] = {
Globals.FloatingScreenJoystick,
};

View File

@@ -324,7 +324,6 @@ class SettingsMenuMisc extends SettingsMenu
p.getResources().getString(R.string.mouse_keepaspectratio),
p.getResources().getString(R.string.video_smooth),
p.getResources().getString(R.string.video_immersive),
p.getResources().getString(R.string.video_draw_cutout),
p.getResources().getString(R.string.video_orientation_autodetect),
p.getResources().getString(R.string.video_orientation_vertical),
p.getResources().getString(R.string.video_bpp_24),
@@ -334,7 +333,6 @@ class SettingsMenuMisc extends SettingsMenu
Globals.KeepAspectRatio,
Globals.VideoLinearFilter,
Globals.ImmersiveMode,
Globals.DrawInDisplayCutout,
Globals.AutoDetectOrientation,
!Globals.HorizontalOrientation,
Globals.VideoDepthBpp == 24,
@@ -347,7 +345,6 @@ class SettingsMenuMisc extends SettingsMenu
p.getResources().getString(R.string.mouse_keepaspectratio),
p.getResources().getString(R.string.video_smooth),
p.getResources().getString(R.string.video_immersive),
p.getResources().getString(R.string.video_draw_cutout),
p.getResources().getString(R.string.video_orientation_autodetect),
p.getResources().getString(R.string.video_orientation_vertical),
p.getResources().getString(R.string.video_bpp_24),
@@ -358,7 +355,6 @@ class SettingsMenuMisc extends SettingsMenu
Globals.KeepAspectRatio,
Globals.VideoLinearFilter,
Globals.ImmersiveMode,
Globals.DrawInDisplayCutout,
Globals.AutoDetectOrientation,
!Globals.HorizontalOrientation,
Globals.VideoDepthBpp == 24,
@@ -369,7 +365,7 @@ class SettingsMenuMisc extends SettingsMenu
defaults = defaults2;
}
if(Globals.UsingSDL2)
if(Globals.Using_SDL_1_3)
{
CharSequence[] items2 = {
p.getResources().getString(R.string.mouse_keepaspectratio),
@@ -394,16 +390,14 @@ class SettingsMenuMisc extends SettingsMenu
if( item == 2 )
Globals.ImmersiveMode = isChecked;
if( item == 3 )
Globals.DrawInDisplayCutout = isChecked;
if( item == 4 )
Globals.AutoDetectOrientation = isChecked;
if( item == 5 )
if( item == 4 )
Globals.HorizontalOrientation = !isChecked;
if( item == 6 )
if( item == 5 )
Globals.VideoDepthBpp = (isChecked ? 24 : 16);
if( item == 7 )
if( item == 6 )
Globals.TvBorders = isChecked;
if( item == 8 )
if( item == 7 )
Globals.MultiThreadedVideo = isChecked;
}
});

View File

@@ -33,13 +33,11 @@ import javax.microedition.khronos.egl.EGLDisplay;
import javax.microedition.khronos.egl.EGLSurface;
import java.io.File;
import java.io.InputStream;
import java.util.concurrent.locks.ReentrantLock;
import java.lang.reflect.Method;
import java.util.LinkedList;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.zip.GZIPInputStream;
import android.os.Bundle;
import android.os.Build;
@@ -68,9 +66,42 @@ import android.net.Uri;
import android.Manifest;
import android.content.pm.PackageManager;
import android.hardware.input.InputManager;
import android.graphics.Rect;
class Mouse
{
public static final int LEFT_CLICK_NORMAL = 0;
public static final int LEFT_CLICK_NEAR_CURSOR = 1;
public static final int LEFT_CLICK_WITH_MULTITOUCH = 2;
public static final int LEFT_CLICK_WITH_PRESSURE = 3;
public static final int LEFT_CLICK_WITH_KEY = 4;
public static final int LEFT_CLICK_WITH_TIMEOUT = 5;
public static final int LEFT_CLICK_WITH_TAP = 6;
public static final int LEFT_CLICK_WITH_TAP_OR_TIMEOUT = 7;
public static final int RIGHT_CLICK_NONE = 0;
public static final int RIGHT_CLICK_WITH_MULTITOUCH = 1;
public static final int RIGHT_CLICK_WITH_PRESSURE = 2;
public static final int RIGHT_CLICK_WITH_KEY = 3;
public static final int RIGHT_CLICK_WITH_TIMEOUT = 4;
public static final int SDL_FINGER_DOWN = 0;
public static final int SDL_FINGER_UP = 1;
public static final int SDL_FINGER_MOVE = 2;
public static final int SDL_FINGER_HOVER = 3;
public static final int ZOOM_NONE = 0;
public static final int ZOOM_MAGNIFIER = 1;
public static final int MOUSE_HW_INPUT_FINGER = 0;
public static final int MOUSE_HW_INPUT_STYLUS = 1;
public static final int MOUSE_HW_INPUT_MOUSE = 2;
public static final int MAX_HOVER_DISTANCE = 1024;
public static final int HOVER_REDRAW_SCREEN = 1024 * 10;
public static final float MAX_PRESSURE = 1024.0f;
}
abstract class DifferentTouchInput
{
public abstract void process(final MotionEvent event);
@@ -744,7 +775,7 @@ class DemoRenderer extends GLSurfaceView_SDL.Renderer
if(mGlContextLost) {
mGlContextLost = false;
DemoGLSurfaceView.SetupTouchscreenKeyboardGraphics(context); // Reload on-screen buttons graphics
Settings.SetupTouchscreenKeyboardGraphics(context); // Reload on-screen buttons graphics
super.SwapBuffers();
}
@@ -1071,6 +1102,9 @@ class DemoGLSurfaceView extends GLSurfaceView_SDL {
if( nativeKey( keyCode, 0, event.getUnicodeChar(), DifferentTouchInput.processGamepadDeviceId(event.getDevice()) ) == 0 )
return super.onKeyUp(keyCode, event);
//if( keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_MENU )
// DimSystemStatusBar.get().dim(mParent._videoLayout);
return true;
}
@@ -1129,19 +1163,14 @@ class DemoGLSurfaceView extends GLSurfaceView_SDL {
if (DifferentTouchInput.capturedMouseY >= this.getHeight())
DifferentTouchInput.capturedMouseY = this.getHeight() - 1;
//Log.v("SDL", "SDL DemoGLSurfaceView::onCapturedPointerEvent(): X " + DifferentTouchInput.capturedMouseX + " Y " + DifferentTouchInput.capturedMouseY +
//Log.v("SDL", "DemoGLSurfaceView::onCapturedPointerEvent(): X " + DifferentTouchInput.capturedMouseX + " Y " + DifferentTouchInput.capturedMouseY +
// " W " + this.getWidth() + " H " + this.getHeight() + " getX " + event.getX() + " getY " + event.getY() +
// " RelX " + event.getAxisValue(MotionEvent.AXIS_RELATIVE_X) + " RelY " + event.getAxisValue(MotionEvent.AXIS_RELATIVE_Y) );
event.setLocation(DifferentTouchInput.capturedMouseX, DifferentTouchInput.capturedMouseY);
event.setAction(MotionEvent.ACTION_HOVER_MOVE);
int scrollX = Math.round(event.getAxisValue(MotionEvent.AXIS_HSCROLL));
int scrollY = Math.round(event.getAxisValue(MotionEvent.AXIS_VSCROLL));
if (scrollX != 0 || scrollY != 0)
DemoGLSurfaceView.nativeMouseWheel(scrollX, scrollY);
//Log.v("SDL", "DemoGLSurfaceView::onCapturedPointerEvent(): XY " + event.getX() + " " + event.getY() + " action " + event.getAction() + " scroll " + scrollX + " " + scrollY);
//Log.v("SDL", "DemoGLSurfaceView::onCapturedPointerEvent(): XY " + event.getX() + " " + event.getY() + " action " + event.getAction());
return this.onTouchEvent(event);
}
@@ -1224,63 +1253,6 @@ class DemoGLSurfaceView extends GLSurfaceView_SDL {
}
}
static byte [] loadRaw(Activity p, int res)
{
byte [] buf = new byte[65536 * 2];
byte [] a = new byte[1048576 * 5]; // We need 5Mb buffer for Keen theme, and this Java code is inefficient
int written = 0;
try{
InputStream is = new GZIPInputStream(p.getResources().openRawResource(res));
int readed = 0;
while( (readed = is.read(buf)) >= 0 )
{
if( written + readed > a.length )
{
byte [] b = new byte [written + readed];
System.arraycopy(a, 0, b, 0, written);
a = b;
}
System.arraycopy(buf, 0, a, written, readed);
written += readed;
}
} catch(Exception e) {};
byte [] b = new byte [written];
System.arraycopy(a, 0, b, 0, written);
return b;
}
static void SetupTouchscreenKeyboardGraphics(Activity p)
{
if( Globals.UseTouchscreenKeyboard )
{
if(Globals.TouchscreenKeyboardTheme < 0)
Globals.TouchscreenKeyboardTheme = 0;
if(Globals.TouchscreenKeyboardTheme > 9)
Globals.TouchscreenKeyboardTheme = 9;
if( Globals.TouchscreenKeyboardTheme == 0 )
Settings.nativeSetupScreenKeyboardButtons(loadRaw(p, R.raw.ultimatedroid));
if( Globals.TouchscreenKeyboardTheme == 1 )
Settings.nativeSetupScreenKeyboardButtons(loadRaw(p, R.raw.simpletheme));
if( Globals.TouchscreenKeyboardTheme == 2 )
Settings.nativeSetupScreenKeyboardButtons(loadRaw(p, R.raw.sun));
if( Globals.TouchscreenKeyboardTheme == 3 )
Settings.nativeSetupScreenKeyboardButtons(loadRaw(p, R.raw.keen));
if( Globals.TouchscreenKeyboardTheme == 4 )
Settings.nativeSetupScreenKeyboardButtons(loadRaw(p, R.raw.retro));
if( Globals.TouchscreenKeyboardTheme == 5 )
Settings.nativeSetupScreenKeyboardButtons(loadRaw(p, R.raw.gba));
if( Globals.TouchscreenKeyboardTheme == 6 )
Settings.nativeSetupScreenKeyboardButtons(loadRaw(p, R.raw.psx));
if( Globals.TouchscreenKeyboardTheme == 7 )
Settings.nativeSetupScreenKeyboardButtons(loadRaw(p, R.raw.snes));
if( Globals.TouchscreenKeyboardTheme == 8 )
Settings.nativeSetupScreenKeyboardButtons(loadRaw(p, R.raw.dualshock));
if( Globals.TouchscreenKeyboardTheme == 9 )
Settings.nativeSetupScreenKeyboardButtons(loadRaw(p, R.raw.n64));
}
}
DemoRenderer mRenderer;
MainActivity mParent;

View File

@@ -42,6 +42,8 @@ class GameHelperUtils {
return "RESULT_CANCELED";
case GamesActivityResultCodes.RESULT_APP_MISCONFIGURED:
return "RESULT_APP_MISCONFIGURED";
case GamesActivityResultCodes.RESULT_LEFT_ROOM:
return "RESULT_LEFT_ROOM";
case GamesActivityResultCodes.RESULT_LICENSE_FAILED:
return "RESULT_LICENSE_FAILED";
case GamesActivityResultCodes.RESULT_RECONNECT_REQUIRED:

View File

@@ -160,7 +160,6 @@
<string name="video_orientation_autodetect">Auto-detect screen orientation</string>
<string name="video_bpp_24">24 bpp screen color depth</string>
<string name="video_immersive">Hide system navigation buttons / immersive mode</string>
<string name="video_draw_cutout">Draw in display cutout area</string>
<string name="tv_borders">TV borders</string>
<string name="text_edit_click_here">Tap to start typing, press Back when done</string>

View File

@@ -1 +0,0 @@
../java/DataDownloader.java

View File

@@ -1 +0,0 @@
../java/Globals.java

View File

@@ -0,0 +1,22 @@
package org.libsdl.app;
import android.hardware.usb.UsbDevice;
interface HIDDevice
{
public int getId();
public int getVendorId();
public int getProductId();
public String getSerialNumber();
public int getVersion();
public String getManufacturerName();
public String getProductName();
public UsbDevice getDevice();
public boolean open();
public int sendFeatureReport(byte[] report);
public int sendOutputReport(byte[] report);
public boolean getFeatureReport(byte[] report);
public void setFrozen(boolean frozen);
public void close();
public void shutdown();
}

View File

@@ -0,0 +1,650 @@
package org.libsdl.app;
import android.content.Context;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothGattService;
import android.hardware.usb.UsbDevice;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.os.*;
//import com.android.internal.util.HexDump;
import java.lang.Runnable;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.UUID;
class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDevice {
private static final String TAG = "hidapi";
private HIDDeviceManager mManager;
private BluetoothDevice mDevice;
private int mDeviceId;
private BluetoothGatt mGatt;
private boolean mIsRegistered = false;
private boolean mIsConnected = false;
private boolean mIsChromebook = false;
private boolean mIsReconnecting = false;
private boolean mFrozen = false;
private LinkedList<GattOperation> mOperations;
GattOperation mCurrentOperation = null;
private Handler mHandler;
private static final int TRANSPORT_AUTO = 0;
private static final int TRANSPORT_BREDR = 1;
private static final int TRANSPORT_LE = 2;
private static final int CHROMEBOOK_CONNECTION_CHECK_INTERVAL = 10000;
static public final UUID steamControllerService = UUID.fromString("100F6C32-1735-4313-B402-38567131E5F3");
static public final UUID inputCharacteristic = UUID.fromString("100F6C33-1735-4313-B402-38567131E5F3");
static public final UUID reportCharacteristic = UUID.fromString("100F6C34-1735-4313-B402-38567131E5F3");
static private final byte[] enterValveMode = new byte[] { (byte)0xC0, (byte)0x87, 0x03, 0x08, 0x07, 0x00 };
static class GattOperation {
private enum Operation {
CHR_READ,
CHR_WRITE,
ENABLE_NOTIFICATION
}
Operation mOp;
UUID mUuid;
byte[] mValue;
BluetoothGatt mGatt;
boolean mResult = true;
private GattOperation(BluetoothGatt gatt, GattOperation.Operation operation, UUID uuid) {
mGatt = gatt;
mOp = operation;
mUuid = uuid;
}
private GattOperation(BluetoothGatt gatt, GattOperation.Operation operation, UUID uuid, byte[] value) {
mGatt = gatt;
mOp = operation;
mUuid = uuid;
mValue = value;
}
public void run() {
// This is executed in main thread
BluetoothGattCharacteristic chr;
switch (mOp) {
case CHR_READ:
chr = getCharacteristic(mUuid);
//Log.v(TAG, "Reading characteristic " + chr.getUuid());
if (!mGatt.readCharacteristic(chr)) {
Log.e(TAG, "Unable to read characteristic " + mUuid.toString());
mResult = false;
break;
}
mResult = true;
break;
case CHR_WRITE:
chr = getCharacteristic(mUuid);
//Log.v(TAG, "Writing characteristic " + chr.getUuid() + " value=" + HexDump.toHexString(value));
chr.setValue(mValue);
if (!mGatt.writeCharacteristic(chr)) {
Log.e(TAG, "Unable to write characteristic " + mUuid.toString());
mResult = false;
break;
}
mResult = true;
break;
case ENABLE_NOTIFICATION:
chr = getCharacteristic(mUuid);
//Log.v(TAG, "Writing descriptor of " + chr.getUuid());
if (chr != null) {
BluetoothGattDescriptor cccd = chr.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));
if (cccd != null) {
int properties = chr.getProperties();
byte[] value;
if ((properties & BluetoothGattCharacteristic.PROPERTY_NOTIFY) == BluetoothGattCharacteristic.PROPERTY_NOTIFY) {
value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE;
} else if ((properties & BluetoothGattCharacteristic.PROPERTY_INDICATE) == BluetoothGattCharacteristic.PROPERTY_INDICATE) {
value = BluetoothGattDescriptor.ENABLE_INDICATION_VALUE;
} else {
Log.e(TAG, "Unable to start notifications on input characteristic");
mResult = false;
return;
}
mGatt.setCharacteristicNotification(chr, true);
cccd.setValue(value);
if (!mGatt.writeDescriptor(cccd)) {
Log.e(TAG, "Unable to write descriptor " + mUuid.toString());
mResult = false;
return;
}
mResult = true;
}
}
}
}
public boolean finish() {
return mResult;
}
private BluetoothGattCharacteristic getCharacteristic(UUID uuid) {
BluetoothGattService valveService = mGatt.getService(steamControllerService);
if (valveService == null)
return null;
return valveService.getCharacteristic(uuid);
}
static public GattOperation readCharacteristic(BluetoothGatt gatt, UUID uuid) {
return new GattOperation(gatt, Operation.CHR_READ, uuid);
}
static public GattOperation writeCharacteristic(BluetoothGatt gatt, UUID uuid, byte[] value) {
return new GattOperation(gatt, Operation.CHR_WRITE, uuid, value);
}
static public GattOperation enableNotification(BluetoothGatt gatt, UUID uuid) {
return new GattOperation(gatt, Operation.ENABLE_NOTIFICATION, uuid);
}
}
public HIDDeviceBLESteamController(HIDDeviceManager manager, BluetoothDevice device) {
mManager = manager;
mDevice = device;
mDeviceId = mManager.getDeviceIDForIdentifier(getIdentifier());
mIsRegistered = false;
mIsChromebook = mManager.getContext().getPackageManager().hasSystemFeature("org.chromium.arc.device_management");
mOperations = new LinkedList<GattOperation>();
mHandler = new Handler(Looper.getMainLooper());
mGatt = connectGatt();
// final HIDDeviceBLESteamController finalThis = this;
// mHandler.postDelayed(new Runnable() {
// @Override
// public void run() {
// finalThis.checkConnectionForChromebookIssue();
// }
// }, CHROMEBOOK_CONNECTION_CHECK_INTERVAL);
}
public String getIdentifier() {
return String.format("SteamController.%s", mDevice.getAddress());
}
public BluetoothGatt getGatt() {
return mGatt;
}
// Because on Chromebooks we show up as a dual-mode device, it will attempt to connect TRANSPORT_AUTO, which will use TRANSPORT_BREDR instead
// of TRANSPORT_LE. Let's force ourselves to connect low energy.
private BluetoothGatt connectGatt(boolean managed) {
if (Build.VERSION.SDK_INT >= 23) {
try {
return mDevice.connectGatt(mManager.getContext(), managed, this, TRANSPORT_LE);
} catch (Exception e) {
return mDevice.connectGatt(mManager.getContext(), managed, this);
}
} else {
return mDevice.connectGatt(mManager.getContext(), managed, this);
}
}
private BluetoothGatt connectGatt() {
return connectGatt(false);
}
protected int getConnectionState() {
Context context = mManager.getContext();
if (context == null) {
// We are lacking any context to get our Bluetooth information. We'll just assume disconnected.
return BluetoothProfile.STATE_DISCONNECTED;
}
BluetoothManager btManager = (BluetoothManager)context.getSystemService(Context.BLUETOOTH_SERVICE);
if (btManager == null) {
// This device doesn't support Bluetooth. We should never be here, because how did
// we instantiate a device to start with?
return BluetoothProfile.STATE_DISCONNECTED;
}
return btManager.getConnectionState(mDevice, BluetoothProfile.GATT);
}
public void reconnect() {
if (getConnectionState() != BluetoothProfile.STATE_CONNECTED) {
mGatt.disconnect();
mGatt = connectGatt();
}
}
protected void checkConnectionForChromebookIssue() {
if (!mIsChromebook) {
// We only do this on Chromebooks, because otherwise it's really annoying to just attempt
// over and over.
return;
}
int connectionState = getConnectionState();
switch (connectionState) {
case BluetoothProfile.STATE_CONNECTED:
if (!mIsConnected) {
// We are in the Bad Chromebook Place. We can force a disconnect
// to try to recover.
Log.v(TAG, "Chromebook: We are in a very bad state; the controller shows as connected in the underlying Bluetooth layer, but we never received a callback. Forcing a reconnect.");
mIsReconnecting = true;
mGatt.disconnect();
mGatt = connectGatt(false);
break;
}
else if (!isRegistered()) {
if (mGatt.getServices().size() > 0) {
Log.v(TAG, "Chromebook: We are connected to a controller, but never got our registration. Trying to recover.");
probeService(this);
}
else {
Log.v(TAG, "Chromebook: We are connected to a controller, but never discovered services. Trying to recover.");
mIsReconnecting = true;
mGatt.disconnect();
mGatt = connectGatt(false);
break;
}
}
else {
Log.v(TAG, "Chromebook: We are connected, and registered. Everything's good!");
return;
}
break;
case BluetoothProfile.STATE_DISCONNECTED:
Log.v(TAG, "Chromebook: We have either been disconnected, or the Chromebook BtGatt.ContextMap bug has bitten us. Attempting a disconnect/reconnect, but we may not be able to recover.");
mIsReconnecting = true;
mGatt.disconnect();
mGatt = connectGatt(false);
break;
case BluetoothProfile.STATE_CONNECTING:
Log.v(TAG, "Chromebook: We're still trying to connect. Waiting a bit longer.");
break;
}
final HIDDeviceBLESteamController finalThis = this;
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
finalThis.checkConnectionForChromebookIssue();
}
}, CHROMEBOOK_CONNECTION_CHECK_INTERVAL);
}
private boolean isRegistered() {
return mIsRegistered;
}
private void setRegistered() {
mIsRegistered = true;
}
private boolean probeService(HIDDeviceBLESteamController controller) {
if (isRegistered()) {
return true;
}
if (!mIsConnected) {
return false;
}
Log.v(TAG, "probeService controller=" + controller);
for (BluetoothGattService service : mGatt.getServices()) {
if (service.getUuid().equals(steamControllerService)) {
Log.v(TAG, "Found Valve steam controller service " + service.getUuid());
for (BluetoothGattCharacteristic chr : service.getCharacteristics()) {
if (chr.getUuid().equals(inputCharacteristic)) {
Log.v(TAG, "Found input characteristic");
// Start notifications
BluetoothGattDescriptor cccd = chr.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));
if (cccd != null) {
enableNotification(chr.getUuid());
}
}
}
return true;
}
}
if ((mGatt.getServices().size() == 0) && mIsChromebook && !mIsReconnecting) {
Log.e(TAG, "Chromebook: Discovered services were empty; this almost certainly means the BtGatt.ContextMap bug has bitten us.");
mIsConnected = false;
mIsReconnecting = true;
mGatt.disconnect();
mGatt = connectGatt(false);
}
return false;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////
private void finishCurrentGattOperation() {
GattOperation op = null;
synchronized (mOperations) {
if (mCurrentOperation != null) {
op = mCurrentOperation;
mCurrentOperation = null;
}
}
if (op != null) {
boolean result = op.finish(); // TODO: Maybe in main thread as well?
// Our operation failed, let's add it back to the beginning of our queue.
if (!result) {
mOperations.addFirst(op);
}
}
executeNextGattOperation();
}
private void executeNextGattOperation() {
synchronized (mOperations) {
if (mCurrentOperation != null)
return;
if (mOperations.isEmpty())
return;
mCurrentOperation = mOperations.removeFirst();
}
// Run in main thread
mHandler.post(new Runnable() {
@Override
public void run() {
synchronized (mOperations) {
if (mCurrentOperation == null) {
Log.e(TAG, "Current operation null in executor?");
return;
}
mCurrentOperation.run();
// now wait for the GATT callback and when it comes, finish this operation
}
}
});
}
private void queueGattOperation(GattOperation op) {
synchronized (mOperations) {
mOperations.add(op);
}
executeNextGattOperation();
}
private void enableNotification(UUID chrUuid) {
GattOperation op = HIDDeviceBLESteamController.GattOperation.enableNotification(mGatt, chrUuid);
queueGattOperation(op);
}
public void writeCharacteristic(UUID uuid, byte[] value) {
GattOperation op = HIDDeviceBLESteamController.GattOperation.writeCharacteristic(mGatt, uuid, value);
queueGattOperation(op);
}
public void readCharacteristic(UUID uuid) {
GattOperation op = HIDDeviceBLESteamController.GattOperation.readCharacteristic(mGatt, uuid);
queueGattOperation(op);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////
////////////// BluetoothGattCallback overridden methods
//////////////////////////////////////////////////////////////////////////////////////////////////////
public void onConnectionStateChange(BluetoothGatt g, int status, int newState) {
//Log.v(TAG, "onConnectionStateChange status=" + status + " newState=" + newState);
mIsReconnecting = false;
if (newState == 2) {
mIsConnected = true;
// Run directly, without GattOperation
if (!isRegistered()) {
mHandler.post(new Runnable() {
@Override
public void run() {
mGatt.discoverServices();
}
});
}
}
else if (newState == 0) {
mIsConnected = false;
}
// Disconnection is handled in SteamLink using the ACTION_ACL_DISCONNECTED Intent.
}
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
//Log.v(TAG, "onServicesDiscovered status=" + status);
if (status == 0) {
if (gatt.getServices().size() == 0) {
Log.v(TAG, "onServicesDiscovered returned zero services; something has gone horribly wrong down in Android's Bluetooth stack.");
mIsReconnecting = true;
mIsConnected = false;
gatt.disconnect();
mGatt = connectGatt(false);
}
else {
probeService(this);
}
}
}
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
//Log.v(TAG, "onCharacteristicRead status=" + status + " uuid=" + characteristic.getUuid());
if (characteristic.getUuid().equals(reportCharacteristic) && !mFrozen) {
mManager.HIDDeviceFeatureReport(getId(), characteristic.getValue());
}
finishCurrentGattOperation();
}
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
//Log.v(TAG, "onCharacteristicWrite status=" + status + " uuid=" + characteristic.getUuid());
if (characteristic.getUuid().equals(reportCharacteristic)) {
// Only register controller with the native side once it has been fully configured
if (!isRegistered()) {
Log.v(TAG, "Registering Steam Controller with ID: " + getId());
mManager.HIDDeviceConnected(getId(), getIdentifier(), getVendorId(), getProductId(), getSerialNumber(), getVersion(), getManufacturerName(), getProductName(), 0, 0, 0, 0);
setRegistered();
}
}
finishCurrentGattOperation();
}
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
// Enable this for verbose logging of controller input reports
//Log.v(TAG, "onCharacteristicChanged uuid=" + characteristic.getUuid() + " data=" + HexDump.dumpHexString(characteristic.getValue()));
if (characteristic.getUuid().equals(inputCharacteristic) && !mFrozen) {
mManager.HIDDeviceInputReport(getId(), characteristic.getValue());
}
}
public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
//Log.v(TAG, "onDescriptorRead status=" + status);
}
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
BluetoothGattCharacteristic chr = descriptor.getCharacteristic();
//Log.v(TAG, "onDescriptorWrite status=" + status + " uuid=" + chr.getUuid() + " descriptor=" + descriptor.getUuid());
if (chr.getUuid().equals(inputCharacteristic)) {
boolean hasWrittenInputDescriptor = true;
BluetoothGattCharacteristic reportChr = chr.getService().getCharacteristic(reportCharacteristic);
if (reportChr != null) {
Log.v(TAG, "Writing report characteristic to enter valve mode");
reportChr.setValue(enterValveMode);
gatt.writeCharacteristic(reportChr);
}
}
finishCurrentGattOperation();
}
public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
//Log.v(TAG, "onReliableWriteCompleted status=" + status);
}
public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
//Log.v(TAG, "onReadRemoteRssi status=" + status);
}
public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
//Log.v(TAG, "onMtuChanged status=" + status);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////
//////// Public API
//////////////////////////////////////////////////////////////////////////////////////////////////////
@Override
public int getId() {
return mDeviceId;
}
@Override
public int getVendorId() {
// Valve Corporation
final int VALVE_USB_VID = 0x28DE;
return VALVE_USB_VID;
}
@Override
public int getProductId() {
// We don't have an easy way to query from the Bluetooth device, but we know what it is
final int D0G_BLE2_PID = 0x1106;
return D0G_BLE2_PID;
}
@Override
public String getSerialNumber() {
// This will be read later via feature report by Steam
return "12345";
}
@Override
public int getVersion() {
return 0;
}
@Override
public String getManufacturerName() {
return "Valve Corporation";
}
@Override
public String getProductName() {
return "Steam Controller";
}
@Override
public UsbDevice getDevice() {
return null;
}
@Override
public boolean open() {
return true;
}
@Override
public int sendFeatureReport(byte[] report) {
if (!isRegistered()) {
Log.e(TAG, "Attempted sendFeatureReport before Steam Controller is registered!");
if (mIsConnected) {
probeService(this);
}
return -1;
}
// We need to skip the first byte, as that doesn't go over the air
byte[] actual_report = Arrays.copyOfRange(report, 1, report.length - 1);
//Log.v(TAG, "sendFeatureReport " + HexDump.dumpHexString(actual_report));
writeCharacteristic(reportCharacteristic, actual_report);
return report.length;
}
@Override
public int sendOutputReport(byte[] report) {
if (!isRegistered()) {
Log.e(TAG, "Attempted sendOutputReport before Steam Controller is registered!");
if (mIsConnected) {
probeService(this);
}
return -1;
}
//Log.v(TAG, "sendFeatureReport " + HexDump.dumpHexString(report));
writeCharacteristic(reportCharacteristic, report);
return report.length;
}
@Override
public boolean getFeatureReport(byte[] report) {
if (!isRegistered()) {
Log.e(TAG, "Attempted getFeatureReport before Steam Controller is registered!");
if (mIsConnected) {
probeService(this);
}
return false;
}
//Log.v(TAG, "getFeatureReport");
readCharacteristic(reportCharacteristic);
return true;
}
@Override
public void close() {
}
@Override
public void setFrozen(boolean frozen) {
mFrozen = frozen;
}
@Override
public void shutdown() {
close();
BluetoothGatt g = mGatt;
if (g != null) {
g.disconnect();
g.close();
mGatt = null;
}
mManager = null;
mIsRegistered = false;
mIsConnected = false;
mOperations.clear();
}
}

View File

@@ -0,0 +1,685 @@
package org.libsdl.app;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.PendingIntent;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.util.Log;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.hardware.usb.*;
import android.os.Handler;
import android.os.Looper;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
public class HIDDeviceManager {
private static final String TAG = "hidapi";
private static final String ACTION_USB_PERMISSION = "org.libsdl.app.USB_PERMISSION";
private static HIDDeviceManager sManager;
private static int sManagerRefCount = 0;
public static HIDDeviceManager acquire(Context context) {
if (sManagerRefCount == 0) {
sManager = new HIDDeviceManager(context);
}
++sManagerRefCount;
return sManager;
}
public static void release(HIDDeviceManager manager) {
if (manager == sManager) {
--sManagerRefCount;
if (sManagerRefCount == 0) {
sManager.close();
sManager = null;
}
}
}
private Context mContext;
private HashMap<Integer, HIDDevice> mDevicesById = new HashMap<Integer, HIDDevice>();
private HashMap<BluetoothDevice, HIDDeviceBLESteamController> mBluetoothDevices = new HashMap<BluetoothDevice, HIDDeviceBLESteamController>();
private int mNextDeviceId = 0;
private SharedPreferences mSharedPreferences = null;
private boolean mIsChromebook = false;
private UsbManager mUsbManager;
private Handler mHandler;
private BluetoothManager mBluetoothManager;
private List<BluetoothDevice> mLastBluetoothDevices;
private final BroadcastReceiver mUsbBroadcast = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(UsbManager.ACTION_USB_DEVICE_ATTACHED)) {
UsbDevice usbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
handleUsbDeviceAttached(usbDevice);
} else if (action.equals(UsbManager.ACTION_USB_DEVICE_DETACHED)) {
UsbDevice usbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
handleUsbDeviceDetached(usbDevice);
} else if (action.equals(HIDDeviceManager.ACTION_USB_PERMISSION)) {
UsbDevice usbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
handleUsbDevicePermission(usbDevice, intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false));
}
}
};
private final BroadcastReceiver mBluetoothBroadcast = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
// Bluetooth device was connected. If it was a Steam Controller, handle it
if (action.equals(BluetoothDevice.ACTION_ACL_CONNECTED)) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Log.d(TAG, "Bluetooth device connected: " + device);
if (isSteamController(device)) {
connectBluetoothDevice(device);
}
}
// Bluetooth device was disconnected, remove from controller manager (if any)
if (action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Log.d(TAG, "Bluetooth device disconnected: " + device);
disconnectBluetoothDevice(device);
}
}
};
private HIDDeviceManager(final Context context) {
mContext = context;
// Make sure we have the HIDAPI library loaded with the native functions
try {
SDL.loadLibrary("hidapi");
} catch (Throwable e) {
Log.w(TAG, "Couldn't load hidapi: " + e.toString());
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setCancelable(false);
builder.setTitle("SDL HIDAPI Error");
builder.setMessage("Please report the following error to the SDL maintainers: " + e.getMessage());
builder.setNegativeButton("Quit", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
try {
// If our context is an activity, exit rather than crashing when we can't
// call our native functions.
Activity activity = (Activity)context;
activity.finish();
}
catch (ClassCastException cce) {
// Context wasn't an activity, there's nothing we can do. Give up and return.
}
}
});
builder.show();
return;
}
HIDDeviceRegisterCallback();
mSharedPreferences = mContext.getSharedPreferences("hidapi", Context.MODE_PRIVATE);
mIsChromebook = mContext.getPackageManager().hasSystemFeature("org.chromium.arc.device_management");
// if (shouldClear) {
// SharedPreferences.Editor spedit = mSharedPreferences.edit();
// spedit.clear();
// spedit.commit();
// }
// else
{
mNextDeviceId = mSharedPreferences.getInt("next_device_id", 0);
}
initializeUSB();
initializeBluetooth();
}
public Context getContext() {
return mContext;
}
public int getDeviceIDForIdentifier(String identifier) {
SharedPreferences.Editor spedit = mSharedPreferences.edit();
int result = mSharedPreferences.getInt(identifier, 0);
if (result == 0) {
result = mNextDeviceId++;
spedit.putInt("next_device_id", mNextDeviceId);
}
spedit.putInt(identifier, result);
spedit.commit();
return result;
}
private void initializeUSB() {
mUsbManager = (UsbManager)mContext.getSystemService(Context.USB_SERVICE);
/*
// Logging
for (UsbDevice device : mUsbManager.getDeviceList().values()) {
Log.i(TAG,"Path: " + device.getDeviceName());
Log.i(TAG,"Manufacturer: " + device.getManufacturerName());
Log.i(TAG,"Product: " + device.getProductName());
Log.i(TAG,"ID: " + device.getDeviceId());
Log.i(TAG,"Class: " + device.getDeviceClass());
Log.i(TAG,"Protocol: " + device.getDeviceProtocol());
Log.i(TAG,"Vendor ID " + device.getVendorId());
Log.i(TAG,"Product ID: " + device.getProductId());
Log.i(TAG,"Interface count: " + device.getInterfaceCount());
Log.i(TAG,"---------------------------------------");
// Get interface details
for (int index = 0; index < device.getInterfaceCount(); index++) {
UsbInterface mUsbInterface = device.getInterface(index);
Log.i(TAG," ***** *****");
Log.i(TAG," Interface index: " + index);
Log.i(TAG," Interface ID: " + mUsbInterface.getId());
Log.i(TAG," Interface class: " + mUsbInterface.getInterfaceClass());
Log.i(TAG," Interface subclass: " + mUsbInterface.getInterfaceSubclass());
Log.i(TAG," Interface protocol: " + mUsbInterface.getInterfaceProtocol());
Log.i(TAG," Endpoint count: " + mUsbInterface.getEndpointCount());
// Get endpoint details
for (int epi = 0; epi < mUsbInterface.getEndpointCount(); epi++)
{
UsbEndpoint mEndpoint = mUsbInterface.getEndpoint(epi);
Log.i(TAG," ++++ ++++ ++++");
Log.i(TAG," Endpoint index: " + epi);
Log.i(TAG," Attributes: " + mEndpoint.getAttributes());
Log.i(TAG," Direction: " + mEndpoint.getDirection());
Log.i(TAG," Number: " + mEndpoint.getEndpointNumber());
Log.i(TAG," Interval: " + mEndpoint.getInterval());
Log.i(TAG," Packet size: " + mEndpoint.getMaxPacketSize());
Log.i(TAG," Type: " + mEndpoint.getType());
}
}
}
Log.i(TAG," No more devices connected.");
*/
// Register for USB broadcasts and permission completions
IntentFilter filter = new IntentFilter();
filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
filter.addAction(HIDDeviceManager.ACTION_USB_PERMISSION);
mContext.registerReceiver(mUsbBroadcast, filter);
for (UsbDevice usbDevice : mUsbManager.getDeviceList().values()) {
handleUsbDeviceAttached(usbDevice);
}
}
UsbManager getUSBManager() {
return mUsbManager;
}
private void shutdownUSB() {
try {
mContext.unregisterReceiver(mUsbBroadcast);
} catch (Exception e) {
// We may not have registered, that's okay
}
}
private boolean isHIDDeviceInterface(UsbDevice usbDevice, UsbInterface usbInterface) {
if (usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_HID) {
return true;
}
if (isXbox360Controller(usbDevice, usbInterface) || isXboxOneController(usbDevice, usbInterface)) {
return true;
}
return false;
}
private boolean isXbox360Controller(UsbDevice usbDevice, UsbInterface usbInterface) {
final int XB360_IFACE_SUBCLASS = 93;
final int XB360_IFACE_PROTOCOL = 1; // Wired
final int XB360W_IFACE_PROTOCOL = 129; // Wireless
final int[] SUPPORTED_VENDORS = {
0x0079, // GPD Win 2
0x044f, // Thrustmaster
0x045e, // Microsoft
0x046d, // Logitech
0x056e, // Elecom
0x06a3, // Saitek
0x0738, // Mad Catz
0x07ff, // Mad Catz
0x0e6f, // PDP
0x0f0d, // Hori
0x1038, // SteelSeries
0x11c9, // Nacon
0x12ab, // Unknown
0x1430, // RedOctane
0x146b, // BigBen
0x1532, // Razer Sabertooth
0x15e4, // Numark
0x162e, // Joytech
0x1689, // Razer Onza
0x1bad, // Harmonix
0x24c6, // PowerA
};
if (usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_VENDOR_SPEC &&
usbInterface.getInterfaceSubclass() == XB360_IFACE_SUBCLASS &&
(usbInterface.getInterfaceProtocol() == XB360_IFACE_PROTOCOL ||
usbInterface.getInterfaceProtocol() == XB360W_IFACE_PROTOCOL)) {
int vendor_id = usbDevice.getVendorId();
for (int supportedVid : SUPPORTED_VENDORS) {
if (vendor_id == supportedVid) {
return true;
}
}
}
return false;
}
private boolean isXboxOneController(UsbDevice usbDevice, UsbInterface usbInterface) {
final int XB1_IFACE_SUBCLASS = 71;
final int XB1_IFACE_PROTOCOL = 208;
final int[] SUPPORTED_VENDORS = {
0x045e, // Microsoft
0x0738, // Mad Catz
0x0e6f, // PDP
0x0f0d, // Hori
0x1532, // Razer Wildcat
0x24c6, // PowerA
0x2e24, // Hyperkin
};
if (usbInterface.getId() == 0 &&
usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_VENDOR_SPEC &&
usbInterface.getInterfaceSubclass() == XB1_IFACE_SUBCLASS &&
usbInterface.getInterfaceProtocol() == XB1_IFACE_PROTOCOL) {
int vendor_id = usbDevice.getVendorId();
for (int supportedVid : SUPPORTED_VENDORS) {
if (vendor_id == supportedVid) {
return true;
}
}
}
return false;
}
private void handleUsbDeviceAttached(UsbDevice usbDevice) {
connectHIDDeviceUSB(usbDevice);
}
private void handleUsbDeviceDetached(UsbDevice usbDevice) {
List<Integer> devices = new ArrayList<Integer>();
for (HIDDevice device : mDevicesById.values()) {
if (usbDevice.equals(device.getDevice())) {
devices.add(device.getId());
}
}
for (int id : devices) {
HIDDevice device = mDevicesById.get(id);
mDevicesById.remove(id);
device.shutdown();
HIDDeviceDisconnected(id);
}
}
private void handleUsbDevicePermission(UsbDevice usbDevice, boolean permission_granted) {
for (HIDDevice device : mDevicesById.values()) {
if (usbDevice.equals(device.getDevice())) {
boolean opened = false;
if (permission_granted) {
opened = device.open();
}
HIDDeviceOpenResult(device.getId(), opened);
}
}
}
private void connectHIDDeviceUSB(UsbDevice usbDevice) {
synchronized (this) {
for (int interface_index = 0; interface_index < usbDevice.getInterfaceCount(); interface_index++) {
UsbInterface usbInterface = usbDevice.getInterface(interface_index);
if (isHIDDeviceInterface(usbDevice, usbInterface)) {
HIDDeviceUSB device = new HIDDeviceUSB(this, usbDevice, interface_index);
int id = device.getId();
mDevicesById.put(id, device);
if (usbDevice != null && !mUsbManager.hasPermission(usbDevice))
{
HIDDeviceOpenPending(id);
try
{
mUsbManager.requestPermission(usbDevice, PendingIntent.getBroadcast(mContext, 0, new Intent(HIDDeviceManager.ACTION_USB_PERMISSION), 0));
}
catch (Exception e)
{
Log.v(TAG, "Couldn't request permission for USB device " + usbDevice);
HIDDeviceOpenResult(id, false);
return;
}
}
HIDDeviceConnected(id, device.getIdentifier(), device.getVendorId(), device.getProductId(), device.getSerialNumber(), device.getVersion(), device.getManufacturerName(), device.getProductName(), usbInterface.getId(), usbInterface.getInterfaceClass(), usbInterface.getInterfaceSubclass(), usbInterface.getInterfaceProtocol());
}
}
}
}
private void initializeBluetooth() {
Log.d(TAG, "Initializing Bluetooth");
if (mContext.getPackageManager().checkPermission(android.Manifest.permission.BLUETOOTH, mContext.getPackageName()) != PackageManager.PERMISSION_GRANTED) {
Log.d(TAG, "Couldn't initialize Bluetooth, missing android.permission.BLUETOOTH");
return;
}
// Find bonded bluetooth controllers and create SteamControllers for them
mBluetoothManager = (BluetoothManager)mContext.getSystemService(Context.BLUETOOTH_SERVICE);
if (mBluetoothManager == null) {
// This device doesn't support Bluetooth.
return;
}
BluetoothAdapter btAdapter = mBluetoothManager.getAdapter();
if (btAdapter == null) {
// This device has Bluetooth support in the codebase, but has no available adapters.
return;
}
// Get our bonded devices.
for (BluetoothDevice device : btAdapter.getBondedDevices()) {
Log.d(TAG, "Bluetooth device available: " + device);
if (isSteamController(device)) {
connectBluetoothDevice(device);
}
}
// NOTE: These don't work on Chromebooks, to my undying dismay.
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
mContext.registerReceiver(mBluetoothBroadcast, filter);
if (mIsChromebook) {
mHandler = new Handler(Looper.getMainLooper());
mLastBluetoothDevices = new ArrayList<BluetoothDevice>();
// final HIDDeviceManager finalThis = this;
// mHandler.postDelayed(new Runnable() {
// @Override
// public void run() {
// finalThis.chromebookConnectionHandler();
// }
// }, 5000);
}
}
private void shutdownBluetooth() {
try {
mContext.unregisterReceiver(mBluetoothBroadcast);
} catch (Exception e) {
// We may not have registered, that's okay
}
}
// Chromebooks do not pass along ACTION_ACL_CONNECTED / ACTION_ACL_DISCONNECTED properly.
// This function provides a sort of dummy version of that, watching for changes in the
// connected devices and attempting to add controllers as things change.
public void chromebookConnectionHandler() {
if (!mIsChromebook) {
return;
}
ArrayList<BluetoothDevice> disconnected = new ArrayList<BluetoothDevice>();
ArrayList<BluetoothDevice> connected = new ArrayList<BluetoothDevice>();
List<BluetoothDevice> currentConnected = mBluetoothManager.getConnectedDevices(BluetoothProfile.GATT);
for (BluetoothDevice bluetoothDevice : currentConnected) {
if (!mLastBluetoothDevices.contains(bluetoothDevice)) {
connected.add(bluetoothDevice);
}
}
for (BluetoothDevice bluetoothDevice : mLastBluetoothDevices) {
if (!currentConnected.contains(bluetoothDevice)) {
disconnected.add(bluetoothDevice);
}
}
mLastBluetoothDevices = currentConnected;
for (BluetoothDevice bluetoothDevice : disconnected) {
disconnectBluetoothDevice(bluetoothDevice);
}
for (BluetoothDevice bluetoothDevice : connected) {
connectBluetoothDevice(bluetoothDevice);
}
final HIDDeviceManager finalThis = this;
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
finalThis.chromebookConnectionHandler();
}
}, 10000);
}
public boolean connectBluetoothDevice(BluetoothDevice bluetoothDevice) {
Log.v(TAG, "connectBluetoothDevice device=" + bluetoothDevice);
synchronized (this) {
if (mBluetoothDevices.containsKey(bluetoothDevice)) {
Log.v(TAG, "Steam controller with address " + bluetoothDevice + " already exists, attempting reconnect");
HIDDeviceBLESteamController device = mBluetoothDevices.get(bluetoothDevice);
device.reconnect();
return false;
}
HIDDeviceBLESteamController device = new HIDDeviceBLESteamController(this, bluetoothDevice);
int id = device.getId();
mBluetoothDevices.put(bluetoothDevice, device);
mDevicesById.put(id, device);
// The Steam Controller will mark itself connected once initialization is complete
}
return true;
}
public void disconnectBluetoothDevice(BluetoothDevice bluetoothDevice) {
synchronized (this) {
HIDDeviceBLESteamController device = mBluetoothDevices.get(bluetoothDevice);
if (device == null)
return;
int id = device.getId();
mBluetoothDevices.remove(bluetoothDevice);
mDevicesById.remove(id);
device.shutdown();
HIDDeviceDisconnected(id);
}
}
public boolean isSteamController(BluetoothDevice bluetoothDevice) {
// Sanity check. If you pass in a null device, by definition it is never a Steam Controller.
if (bluetoothDevice == null) {
return false;
}
// If the device has no local name, we really don't want to try an equality check against it.
if (bluetoothDevice.getName() == null) {
return false;
}
return bluetoothDevice.getName().equals("SteamController") && ((bluetoothDevice.getType() & BluetoothDevice.DEVICE_TYPE_LE) != 0);
}
private void close() {
shutdownUSB();
shutdownBluetooth();
synchronized (this) {
for (HIDDevice device : mDevicesById.values()) {
device.shutdown();
}
mDevicesById.clear();
mBluetoothDevices.clear();
HIDDeviceReleaseCallback();
}
}
public void setFrozen(boolean frozen) {
synchronized (this) {
for (HIDDevice device : mDevicesById.values()) {
device.setFrozen(frozen);
}
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////
private HIDDevice getDevice(int id) {
synchronized (this) {
HIDDevice result = mDevicesById.get(id);
if (result == null) {
Log.v(TAG, "No device for id: " + id);
Log.v(TAG, "Available devices: " + mDevicesById.keySet());
}
return result;
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////
////////// JNI interface functions
//////////////////////////////////////////////////////////////////////////////////////////////////////
public boolean openDevice(int deviceID) {
Log.v(TAG, "openDevice deviceID=" + deviceID);
HIDDevice device = getDevice(deviceID);
if (device == null) {
HIDDeviceDisconnected(deviceID);
return false;
}
// Look to see if this is a USB device and we have permission to access it
UsbDevice usbDevice = device.getDevice();
if (usbDevice != null && !mUsbManager.hasPermission(usbDevice)) {
HIDDeviceOpenPending(deviceID);
try {
mUsbManager.requestPermission(usbDevice, PendingIntent.getBroadcast(mContext, 0, new Intent(HIDDeviceManager.ACTION_USB_PERMISSION), 0));
} catch (Exception e) {
Log.v(TAG, "Couldn't request permission for USB device " + usbDevice);
HIDDeviceOpenResult(deviceID, false);
}
return false;
}
try {
return device.open();
} catch (Exception e) {
Log.e(TAG, "Got exception: " + Log.getStackTraceString(e));
}
return false;
}
public int sendOutputReport(int deviceID, byte[] report) {
try {
//Log.v(TAG, "sendOutputReport deviceID=" + deviceID + " length=" + report.length);
HIDDevice device;
device = getDevice(deviceID);
if (device == null) {
HIDDeviceDisconnected(deviceID);
return -1;
}
return device.sendOutputReport(report);
} catch (Exception e) {
Log.e(TAG, "Got exception: " + Log.getStackTraceString(e));
}
return -1;
}
public int sendFeatureReport(int deviceID, byte[] report) {
try {
//Log.v(TAG, "sendFeatureReport deviceID=" + deviceID + " length=" + report.length);
HIDDevice device;
device = getDevice(deviceID);
if (device == null) {
HIDDeviceDisconnected(deviceID);
return -1;
}
return device.sendFeatureReport(report);
} catch (Exception e) {
Log.e(TAG, "Got exception: " + Log.getStackTraceString(e));
}
return -1;
}
public boolean getFeatureReport(int deviceID, byte[] report) {
try {
//Log.v(TAG, "getFeatureReport deviceID=" + deviceID);
HIDDevice device;
device = getDevice(deviceID);
if (device == null) {
HIDDeviceDisconnected(deviceID);
return false;
}
return device.getFeatureReport(report);
} catch (Exception e) {
Log.e(TAG, "Got exception: " + Log.getStackTraceString(e));
}
return false;
}
public void closeDevice(int deviceID) {
try {
Log.v(TAG, "closeDevice deviceID=" + deviceID);
HIDDevice device;
device = getDevice(deviceID);
if (device == null) {
HIDDeviceDisconnected(deviceID);
return;
}
device.close();
} catch (Exception e) {
Log.e(TAG, "Got exception: " + Log.getStackTraceString(e));
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////// Native methods
//////////////////////////////////////////////////////////////////////////////////////////////////////
private native void HIDDeviceRegisterCallback();
private native void HIDDeviceReleaseCallback();
native void HIDDeviceConnected(int deviceID, String identifier, int vendorId, int productId, String serial_number, int release_number, String manufacturer_string, String product_string, int interface_number, int interface_class, int interface_subclass, int interface_protocol);
native void HIDDeviceOpenPending(int deviceID);
native void HIDDeviceOpenResult(int deviceID, boolean opened);
native void HIDDeviceDisconnected(int deviceID);
native void HIDDeviceInputReport(int deviceID, byte[] report);
native void HIDDeviceFeatureReport(int deviceID, byte[] report);
}

View File

@@ -0,0 +1,304 @@
package org.libsdl.app;
import android.hardware.usb.*;
import android.os.Build;
import android.util.Log;
import java.util.Arrays;
class HIDDeviceUSB implements HIDDevice {
private static final String TAG = "hidapi";
protected HIDDeviceManager mManager;
protected UsbDevice mDevice;
protected int mInterfaceIndex;
protected int mInterface;
protected int mDeviceId;
protected UsbDeviceConnection mConnection;
protected UsbEndpoint mInputEndpoint;
protected UsbEndpoint mOutputEndpoint;
protected InputThread mInputThread;
protected boolean mRunning;
protected boolean mFrozen;
public HIDDeviceUSB(HIDDeviceManager manager, UsbDevice usbDevice, int interface_index) {
mManager = manager;
mDevice = usbDevice;
mInterfaceIndex = interface_index;
mInterface = mDevice.getInterface(mInterfaceIndex).getId();
mDeviceId = manager.getDeviceIDForIdentifier(getIdentifier());
mRunning = false;
}
public String getIdentifier() {
return String.format("%s/%x/%x/%d", mDevice.getDeviceName(), mDevice.getVendorId(), mDevice.getProductId(), mInterfaceIndex);
}
@Override
public int getId() {
return mDeviceId;
}
@Override
public int getVendorId() {
return mDevice.getVendorId();
}
@Override
public int getProductId() {
return mDevice.getProductId();
}
@Override
public String getSerialNumber() {
String result = null;
if (Build.VERSION.SDK_INT >= 21) {
result = mDevice.getSerialNumber();
}
if (result == null) {
result = "";
}
return result;
}
@Override
public int getVersion() {
return 0;
}
@Override
public String getManufacturerName() {
String result = null;
if (Build.VERSION.SDK_INT >= 21) {
result = mDevice.getManufacturerName();
}
if (result == null) {
result = String.format("%x", getVendorId());
}
return result;
}
@Override
public String getProductName() {
String result = null;
if (Build.VERSION.SDK_INT >= 21) {
result = mDevice.getProductName();
}
if (result == null) {
result = String.format("%x", getProductId());
}
return result;
}
@Override
public UsbDevice getDevice() {
return mDevice;
}
public String getDeviceName() {
return getManufacturerName() + " " + getProductName() + "(0x" + String.format("%x", getVendorId()) + "/0x" + String.format("%x", getProductId()) + ")";
}
@Override
public boolean open() {
mConnection = mManager.getUSBManager().openDevice(mDevice);
if (mConnection == null) {
Log.w(TAG, "Unable to open USB device " + getDeviceName());
return false;
}
// Force claim our interface
UsbInterface iface = mDevice.getInterface(mInterfaceIndex);
if (!mConnection.claimInterface(iface, true)) {
Log.w(TAG, "Failed to claim interfaces on USB device " + getDeviceName());
close();
return false;
}
// Find the endpoints
for (int j = 0; j < iface.getEndpointCount(); j++) {
UsbEndpoint endpt = iface.getEndpoint(j);
switch (endpt.getDirection()) {
case UsbConstants.USB_DIR_IN:
if (mInputEndpoint == null) {
mInputEndpoint = endpt;
}
break;
case UsbConstants.USB_DIR_OUT:
if (mOutputEndpoint == null) {
mOutputEndpoint = endpt;
}
break;
}
}
// Make sure the required endpoints were present
if (mInputEndpoint == null || mOutputEndpoint == null) {
Log.w(TAG, "Missing required endpoint on USB device " + getDeviceName());
close();
return false;
}
// Start listening for input
mRunning = true;
mInputThread = new InputThread();
mInputThread.start();
return true;
}
@Override
public int sendFeatureReport(byte[] report) {
int res = -1;
int offset = 0;
int length = report.length;
boolean skipped_report_id = false;
byte report_number = report[0];
if (report_number == 0x0) {
++offset;
--length;
skipped_report_id = true;
}
res = mConnection.controlTransfer(
UsbConstants.USB_TYPE_CLASS | 0x01 /*RECIPIENT_INTERFACE*/ | UsbConstants.USB_DIR_OUT,
0x09/*HID set_report*/,
(3/*HID feature*/ << 8) | report_number,
mInterface,
report, offset, length,
1000/*timeout millis*/);
if (res < 0) {
Log.w(TAG, "sendFeatureReport() returned " + res + " on device " + getDeviceName());
return -1;
}
if (skipped_report_id) {
++length;
}
return length;
}
@Override
public int sendOutputReport(byte[] report) {
int r = mConnection.bulkTransfer(mOutputEndpoint, report, report.length, 1000);
if (r != report.length) {
Log.w(TAG, "sendOutputReport() returned " + r + " on device " + getDeviceName());
}
return r;
}
@Override
public boolean getFeatureReport(byte[] report) {
int res = -1;
int offset = 0;
int length = report.length;
boolean skipped_report_id = false;
byte report_number = report[0];
if (report_number == 0x0) {
/* Offset the return buffer by 1, so that the report ID
will remain in byte 0. */
++offset;
--length;
skipped_report_id = true;
}
res = mConnection.controlTransfer(
UsbConstants.USB_TYPE_CLASS | 0x01 /*RECIPIENT_INTERFACE*/ | UsbConstants.USB_DIR_IN,
0x01/*HID get_report*/,
(3/*HID feature*/ << 8) | report_number,
mInterface,
report, offset, length,
1000/*timeout millis*/);
if (res < 0) {
Log.w(TAG, "getFeatureReport() returned " + res + " on device " + getDeviceName());
return false;
}
if (skipped_report_id) {
++res;
++length;
}
byte[] data;
if (res == length) {
data = report;
} else {
data = Arrays.copyOfRange(report, 0, res);
}
mManager.HIDDeviceFeatureReport(mDeviceId, data);
return true;
}
@Override
public void close() {
mRunning = false;
if (mInputThread != null) {
while (mInputThread.isAlive()) {
mInputThread.interrupt();
try {
mInputThread.join();
} catch (InterruptedException e) {
// Keep trying until we're done
}
}
mInputThread = null;
}
if (mConnection != null) {
UsbInterface iface = mDevice.getInterface(mInterfaceIndex);
mConnection.releaseInterface(iface);
mConnection.close();
mConnection = null;
}
}
@Override
public void shutdown() {
close();
mManager = null;
}
@Override
public void setFrozen(boolean frozen) {
mFrozen = frozen;
}
protected class InputThread extends Thread {
@Override
public void run() {
int packetSize = mInputEndpoint.getMaxPacketSize();
byte[] packet = new byte[packetSize];
while (mRunning) {
int r;
try
{
r = mConnection.bulkTransfer(mInputEndpoint, packet, packetSize, 1000);
}
catch (Exception e)
{
Log.v(TAG, "Exception in UsbDeviceConnection bulktransfer: " + e);
break;
}
if (r < 0) {
// Could be a timeout or an I/O error
}
if (r > 0) {
byte[] data;
if (r == packetSize) {
data = packet;
} else {
data = Arrays.copyOfRange(packet, 0, r);
}
if (!mFrozen) {
mManager.HIDDeviceInputReport(mDeviceId, data);
}
}
}
}
}
}

View File

@@ -1,209 +0,0 @@
/*
Simple DirectMedia Layer
Java source code (C) 2009-2014 Sergii Pylypenko
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
package net.sourceforge.clonekeenplus;
import android.app.Activity;
import android.app.UiModeManager;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.Configuration;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;
import android.widget.FrameLayout;
import java.util.ArrayList;
import java.util.Arrays;
public class MainActivity extends org.libsdl.app.SDLActivity {
public static MainActivity instance = null;
public String ObbMountPath = null; // Deprecated, always empty
public String assetPackPath = null; // Not saved to the config file
public boolean readExternalStoragePermissionDialogAnswered = false; // Deprecated, always false
public boolean nativeThreadResumeCaptured = false;
public DataDownloader dataDownloader = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
this.instance = this;
super.onCreate(savedInstanceState);
Globals.DataDir = this.getFilesDir().getAbsolutePath();
Settings.settingsLoaded = Settings.LoadConfig(this); // Load Globals.DataDir from SDL 1.2 installation
if (Settings.settingsLoaded) {
Log.i("SDL", "libSDL: Settings.ProcessConfig(): loaded settings successfully");
Log.i("SDL", "libSDL: old app version " + Settings.settingsAppVersion + ", new app version " + this.getApplicationVersion());
if (Settings.settingsAppVersion != this.getApplicationVersion()) {
Settings.DeleteFilesOnUpgrade(this);
if (Globals.ResetSdlConfigForThisVersion) {
Log.i("SDL", "libSDL: old app version " + Settings.settingsAppVersion + ", new app version " + this.getApplicationVersion() + " and we need to clean up config file");
// Delete settings file, and restart the application
Settings.DeleteSdlConfigOnUpgradeAndRestart(this);
}
Settings.Save(this);
}
}
try
{
if( android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP )
{
ApplicationInfo info = this.getPackageManager().getApplicationInfo(this.getPackageName(), 0);
if( info.splitSourceDirs != null )
{
for( String apk: info.splitSourceDirs )
{
Log.i("SDL", "Package apk: " + apk);
if( apk.endsWith("assetpack.apk") )
{
this.assetPackPath = apk;
Log.i("SDL", "Found asset pack: " + this.assetPackPath);
}
}
}
}
}
catch( Exception eee )
{
Log.i("SDL", "Asset pack exception: " + eee);
}
Settings.setEnvVars(this);
Log.v("SDL", "chdir() to: " + Globals.DataDir);
Settings.nativeChdir(Globals.DataDir);
Log.i("SDL", "Starting data download");
this.dataDownloader = new DataDownloader(this, null);
}
public void downloadFinishedInitSDL() {
if (!this.dataDownloader.DownloadComplete)
{
Log.i("SDL", "Data download failed!");
AlertDialog.Builder dlgAlert = new AlertDialog.Builder(this);
dlgAlert.setMessage(this.getResources().getString(R.string.error_dl_from, String.join(" ", Globals.DataDownloadUrl)));
dlgAlert.setTitle("SDL Error");
dlgAlert.setPositiveButton("Exit",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog,int id) {
System.exit(0);
}
});
dlgAlert.setCancelable(false);
dlgAlert.create().show();
return;
}
Log.i("SDL", "Data download finished, starting native thread");
this.dataDownloader = null;
if (this.nativeThreadResumeCaptured)
this.resumeNativeThread();
else
this.pauseNativeThread();
}
@Override
protected void pauseNativeThread() {
Log.i("SDL", "Intercepted pauseNativeThread() from MainActivity");
this.nativeThreadResumeCaptured = false;
if (this.dataDownloader == null) {
super.pauseNativeThread();
}
}
@Override
protected void resumeNativeThread() {
Log.i("SDL", "Intercepted resumeNativeThread() from MainActivity");
this.nativeThreadResumeCaptured = true;
if (this.dataDownloader == null) {
super.resumeNativeThread();
}
}
@Override
protected String[] getLibraries() {
ArrayList<String> ret = new ArrayList<String>();
for (String l: Globals.AppLibraries) {
ret.add(GetMappedLibraryName(l));
}
for (String l: Globals.AppMainLibraries) {
ret.add(GetMappedLibraryName(l));
}
Log.i("SDL", "Loading native libraries: " + String.join(" ", ret));
return ret.toArray(new String[0]);
}
@Override
protected String[] getArguments() {
// Strip the first argument, it will get passed as commandline parameter by SDL2
ArrayList<String> ret = new ArrayList<String>(Arrays.asList(Globals.CommandLine.split(" ")));
if (ret.size() >= 1) {
ret.remove(0);
}
Log.i("SDL", "Commandline arguments: '" + String.join("', '", ret) + "'");
return ret.toArray(new String[0]);
}
private static String GetMappedLibraryName(final String s) {
for (int i = 0; i < Globals.LibraryNamesMap.length; i++) {
if (Globals.LibraryNamesMap[i][0].equals(s))
return Globals.LibraryNamesMap[i][1];
}
return s;
}
public int getApplicationVersion() {
try {
PackageInfo packageInfo = getPackageManager().getPackageInfo(getPackageName(), 0);
return packageInfo.versionCode;
} catch (PackageManager.NameNotFoundException e) {
Log.i("SDL", "libSDL: Cannot get the version of our own package: " + e);
}
return 0;
}
public boolean isRunningOnOUYA() {
try {
PackageInfo packageInfo = getPackageManager().getPackageInfo("tv.ouya", 0);
return true;
} catch (PackageManager.NameNotFoundException e) {
}
UiModeManager uiModeManager = (UiModeManager) getSystemService(UI_MODE_SERVICE);
return (uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION) || Globals.OuyaEmulation;
}
public static void setScreenOrientation() {
// For compatibility with SDL 1.2 code
}
public static void setUpStatusLabel() {
// For compatibility with SDL 1.2 code
}
public static FrameLayout getVideoLayout() {
// For compatibility with SDL 1.2 code
return null;
}
}

View File

@@ -1 +0,0 @@
../java/Mouse.java

84
project/javaSDL2/SDL.java Normal file
View File

@@ -0,0 +1,84 @@
package org.libsdl.app;
import android.content.Context;
import java.lang.reflect.*;
/**
SDL library initialization
*/
public class SDL {
// This function should be called first and sets up the native code
// so it can call into the Java classes
public static void setupJNI() {
SDLActivity.nativeSetupJNI();
SDLAudioManager.nativeSetupJNI();
SDLControllerManager.nativeSetupJNI();
}
// This function should be called each time the activity is started
public static void initialize() {
setContext(null);
SDLActivity.initialize();
SDLAudioManager.initialize();
SDLControllerManager.initialize();
}
// This function stores the current activity (SDL or not)
public static void setContext(Context context) {
mContext = context;
}
public static Context getContext() {
return mContext;
}
public static void loadLibrary(String libraryName) throws UnsatisfiedLinkError, SecurityException, NullPointerException {
if (libraryName == null) {
throw new NullPointerException("No library name provided.");
}
try {
// Let's see if we have ReLinker available in the project. This is necessary for
// some projects that have huge numbers of local libraries bundled, and thus may
// trip a bug in Android's native library loader which ReLinker works around. (If
// loadLibrary works properly, ReLinker will simply use the normal Android method
// internally.)
//
// To use ReLinker, just add it as a dependency. For more information, see
// https://github.com/KeepSafe/ReLinker for ReLinker's repository.
//
Class relinkClass = mContext.getClassLoader().loadClass("com.getkeepsafe.relinker.ReLinker");
Class relinkListenerClass = mContext.getClassLoader().loadClass("com.getkeepsafe.relinker.ReLinker$LoadListener");
Class contextClass = mContext.getClassLoader().loadClass("android.content.Context");
Class stringClass = mContext.getClassLoader().loadClass("java.lang.String");
// Get a 'force' instance of the ReLinker, so we can ensure libraries are reinstalled if
// they've changed during updates.
Method forceMethod = relinkClass.getDeclaredMethod("force");
Object relinkInstance = forceMethod.invoke(null);
Class relinkInstanceClass = relinkInstance.getClass();
// Actually load the library!
Method loadMethod = relinkInstanceClass.getDeclaredMethod("loadLibrary", contextClass, stringClass, stringClass, relinkListenerClass);
loadMethod.invoke(relinkInstance, mContext, libraryName, null, null);
}
catch (final Throwable e) {
// Fall back
try {
System.loadLibrary(libraryName);
}
catch (final UnsatisfiedLinkError ule) {
throw ule;
}
catch (final SecurityException se) {
throw se;
}
}
}
protected static Context mContext;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,387 @@
package org.libsdl.app;
import android.media.*;
import android.os.Build;
import android.util.Log;
public class SDLAudioManager
{
protected static final String TAG = "SDLAudio";
protected static AudioTrack mAudioTrack;
protected static AudioRecord mAudioRecord;
public static void initialize() {
mAudioTrack = null;
mAudioRecord = null;
}
// Audio
protected static String getAudioFormatString(int audioFormat) {
switch (audioFormat) {
case AudioFormat.ENCODING_PCM_8BIT:
return "8-bit";
case AudioFormat.ENCODING_PCM_16BIT:
return "16-bit";
case AudioFormat.ENCODING_PCM_FLOAT:
return "float";
default:
return Integer.toString(audioFormat);
}
}
protected static int[] open(boolean isCapture, int sampleRate, int audioFormat, int desiredChannels, int desiredFrames) {
int channelConfig;
int sampleSize;
int frameSize;
Log.v(TAG, "Opening " + (isCapture ? "capture" : "playback") + ", requested " + desiredFrames + " frames of " + desiredChannels + " channel " + getAudioFormatString(audioFormat) + " audio at " + sampleRate + " Hz");
/* On older devices let's use known good settings */
if (Build.VERSION.SDK_INT < 21) {
if (desiredChannels > 2) {
desiredChannels = 2;
}
if (sampleRate < 8000) {
sampleRate = 8000;
} else if (sampleRate > 48000) {
sampleRate = 48000;
}
}
if (audioFormat == AudioFormat.ENCODING_PCM_FLOAT) {
int minSDKVersion = (isCapture ? 23 : 21);
if (Build.VERSION.SDK_INT < minSDKVersion) {
audioFormat = AudioFormat.ENCODING_PCM_16BIT;
}
}
switch (audioFormat)
{
case AudioFormat.ENCODING_PCM_8BIT:
sampleSize = 1;
break;
case AudioFormat.ENCODING_PCM_16BIT:
sampleSize = 2;
break;
case AudioFormat.ENCODING_PCM_FLOAT:
sampleSize = 4;
break;
default:
Log.v(TAG, "Requested format " + audioFormat + ", getting ENCODING_PCM_16BIT");
audioFormat = AudioFormat.ENCODING_PCM_16BIT;
sampleSize = 2;
break;
}
if (isCapture) {
switch (desiredChannels) {
case 1:
channelConfig = AudioFormat.CHANNEL_IN_MONO;
break;
case 2:
channelConfig = AudioFormat.CHANNEL_IN_STEREO;
break;
default:
Log.v(TAG, "Requested " + desiredChannels + " channels, getting stereo");
desiredChannels = 2;
channelConfig = AudioFormat.CHANNEL_IN_STEREO;
break;
}
} else {
switch (desiredChannels) {
case 1:
channelConfig = AudioFormat.CHANNEL_OUT_MONO;
break;
case 2:
channelConfig = AudioFormat.CHANNEL_OUT_STEREO;
break;
case 3:
channelConfig = AudioFormat.CHANNEL_OUT_STEREO | AudioFormat.CHANNEL_OUT_FRONT_CENTER;
break;
case 4:
channelConfig = AudioFormat.CHANNEL_OUT_QUAD;
break;
case 5:
channelConfig = AudioFormat.CHANNEL_OUT_QUAD | AudioFormat.CHANNEL_OUT_FRONT_CENTER;
break;
case 6:
channelConfig = AudioFormat.CHANNEL_OUT_5POINT1;
break;
case 7:
channelConfig = AudioFormat.CHANNEL_OUT_5POINT1 | AudioFormat.CHANNEL_OUT_BACK_CENTER;
break;
case 8:
if (Build.VERSION.SDK_INT >= 23) {
channelConfig = AudioFormat.CHANNEL_OUT_7POINT1_SURROUND;
} else {
Log.v(TAG, "Requested " + desiredChannels + " channels, getting 5.1 surround");
desiredChannels = 6;
channelConfig = AudioFormat.CHANNEL_OUT_5POINT1;
}
break;
default:
Log.v(TAG, "Requested " + desiredChannels + " channels, getting stereo");
desiredChannels = 2;
channelConfig = AudioFormat.CHANNEL_OUT_STEREO;
break;
}
/*
Log.v(TAG, "Speaker configuration (and order of channels):");
if ((channelConfig & 0x00000004) != 0) {
Log.v(TAG, " CHANNEL_OUT_FRONT_LEFT");
}
if ((channelConfig & 0x00000008) != 0) {
Log.v(TAG, " CHANNEL_OUT_FRONT_RIGHT");
}
if ((channelConfig & 0x00000010) != 0) {
Log.v(TAG, " CHANNEL_OUT_FRONT_CENTER");
}
if ((channelConfig & 0x00000020) != 0) {
Log.v(TAG, " CHANNEL_OUT_LOW_FREQUENCY");
}
if ((channelConfig & 0x00000040) != 0) {
Log.v(TAG, " CHANNEL_OUT_BACK_LEFT");
}
if ((channelConfig & 0x00000080) != 0) {
Log.v(TAG, " CHANNEL_OUT_BACK_RIGHT");
}
if ((channelConfig & 0x00000100) != 0) {
Log.v(TAG, " CHANNEL_OUT_FRONT_LEFT_OF_CENTER");
}
if ((channelConfig & 0x00000200) != 0) {
Log.v(TAG, " CHANNEL_OUT_FRONT_RIGHT_OF_CENTER");
}
if ((channelConfig & 0x00000400) != 0) {
Log.v(TAG, " CHANNEL_OUT_BACK_CENTER");
}
if ((channelConfig & 0x00000800) != 0) {
Log.v(TAG, " CHANNEL_OUT_SIDE_LEFT");
}
if ((channelConfig & 0x00001000) != 0) {
Log.v(TAG, " CHANNEL_OUT_SIDE_RIGHT");
}
*/
}
frameSize = (sampleSize * desiredChannels);
// Let the user pick a larger buffer if they really want -- but ye
// gods they probably shouldn't, the minimums are horrifyingly high
// latency already
int minBufferSize;
if (isCapture) {
minBufferSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat);
} else {
minBufferSize = AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioFormat);
}
desiredFrames = Math.max(desiredFrames, (minBufferSize + frameSize - 1) / frameSize);
int[] results = new int[4];
if (isCapture) {
if (mAudioRecord == null) {
mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, sampleRate,
channelConfig, audioFormat, desiredFrames * frameSize);
// see notes about AudioTrack state in audioOpen(), above. Probably also applies here.
if (mAudioRecord.getState() != AudioRecord.STATE_INITIALIZED) {
Log.e(TAG, "Failed during initialization of AudioRecord");
mAudioRecord.release();
mAudioRecord = null;
return null;
}
mAudioRecord.startRecording();
}
results[0] = mAudioRecord.getSampleRate();
results[1] = mAudioRecord.getAudioFormat();
results[2] = mAudioRecord.getChannelCount();
results[3] = desiredFrames;
} else {
if (mAudioTrack == null) {
mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate, channelConfig, audioFormat, desiredFrames * frameSize, AudioTrack.MODE_STREAM);
// Instantiating AudioTrack can "succeed" without an exception and the track may still be invalid
// Ref: https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/media/java/android/media/AudioTrack.java
// Ref: http://developer.android.com/reference/android/media/AudioTrack.html#getState()
if (mAudioTrack.getState() != AudioTrack.STATE_INITIALIZED) {
/* Try again, with safer values */
Log.e(TAG, "Failed during initialization of Audio Track");
mAudioTrack.release();
mAudioTrack = null;
return null;
}
mAudioTrack.play();
}
results[0] = mAudioTrack.getSampleRate();
results[1] = mAudioTrack.getAudioFormat();
results[2] = mAudioTrack.getChannelCount();
results[3] = desiredFrames;
}
Log.v(TAG, "Opening " + (isCapture ? "capture" : "playback") + ", got " + results[3] + " frames of " + results[2] + " channel " + getAudioFormatString(results[1]) + " audio at " + results[0] + " Hz");
return results;
}
/**
* This method is called by SDL using JNI.
*/
public static int[] audioOpen(int sampleRate, int audioFormat, int desiredChannels, int desiredFrames) {
return open(false, sampleRate, audioFormat, desiredChannels, desiredFrames);
}
/**
* This method is called by SDL using JNI.
*/
public static void audioWriteFloatBuffer(float[] buffer) {
if (mAudioTrack == null) {
Log.e(TAG, "Attempted to make audio call with uninitialized audio!");
return;
}
for (int i = 0; i < buffer.length;) {
int result = mAudioTrack.write(buffer, i, buffer.length - i, AudioTrack.WRITE_BLOCKING);
if (result > 0) {
i += result;
} else if (result == 0) {
try {
Thread.sleep(1);
} catch(InterruptedException e) {
// Nom nom
}
} else {
Log.w(TAG, "SDL audio: error return from write(float)");
return;
}
}
}
/**
* This method is called by SDL using JNI.
*/
public static void audioWriteShortBuffer(short[] buffer) {
if (mAudioTrack == null) {
Log.e(TAG, "Attempted to make audio call with uninitialized audio!");
return;
}
for (int i = 0; i < buffer.length;) {
int result = mAudioTrack.write(buffer, i, buffer.length - i);
if (result > 0) {
i += result;
} else if (result == 0) {
try {
Thread.sleep(1);
} catch(InterruptedException e) {
// Nom nom
}
} else {
Log.w(TAG, "SDL audio: error return from write(short)");
return;
}
}
}
/**
* This method is called by SDL using JNI.
*/
public static void audioWriteByteBuffer(byte[] buffer) {
if (mAudioTrack == null) {
Log.e(TAG, "Attempted to make audio call with uninitialized audio!");
return;
}
for (int i = 0; i < buffer.length; ) {
int result = mAudioTrack.write(buffer, i, buffer.length - i);
if (result > 0) {
i += result;
} else if (result == 0) {
try {
Thread.sleep(1);
} catch(InterruptedException e) {
// Nom nom
}
} else {
Log.w(TAG, "SDL audio: error return from write(byte)");
return;
}
}
}
/**
* This method is called by SDL using JNI.
*/
public static int[] captureOpen(int sampleRate, int audioFormat, int desiredChannels, int desiredFrames) {
return open(true, sampleRate, audioFormat, desiredChannels, desiredFrames);
}
/** This method is called by SDL using JNI. */
public static int captureReadFloatBuffer(float[] buffer, boolean blocking) {
return mAudioRecord.read(buffer, 0, buffer.length, blocking ? AudioRecord.READ_BLOCKING : AudioRecord.READ_NON_BLOCKING);
}
/** This method is called by SDL using JNI. */
public static int captureReadShortBuffer(short[] buffer, boolean blocking) {
if (Build.VERSION.SDK_INT < 23) {
return mAudioRecord.read(buffer, 0, buffer.length);
} else {
return mAudioRecord.read(buffer, 0, buffer.length, blocking ? AudioRecord.READ_BLOCKING : AudioRecord.READ_NON_BLOCKING);
}
}
/** This method is called by SDL using JNI. */
public static int captureReadByteBuffer(byte[] buffer, boolean blocking) {
if (Build.VERSION.SDK_INT < 23) {
return mAudioRecord.read(buffer, 0, buffer.length);
} else {
return mAudioRecord.read(buffer, 0, buffer.length, blocking ? AudioRecord.READ_BLOCKING : AudioRecord.READ_NON_BLOCKING);
}
}
/** This method is called by SDL using JNI. */
public static void audioClose() {
if (mAudioTrack != null) {
mAudioTrack.stop();
mAudioTrack.release();
mAudioTrack = null;
}
}
/** This method is called by SDL using JNI. */
public static void captureClose() {
if (mAudioRecord != null) {
mAudioRecord.stop();
mAudioRecord.release();
mAudioRecord = null;
}
}
/** This method is called by SDL using JNI. */
public static void audioSetThreadPriority(boolean iscapture, int device_id) {
try {
/* Set thread name */
if (iscapture) {
Thread.currentThread().setName("SDLAudioC" + device_id);
} else {
Thread.currentThread().setName("SDLAudioP" + device_id);
}
/* Set thread priority */
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_AUDIO);
} catch (Exception e) {
Log.v(TAG, "modify thread properties failed " + e.toString());
}
}
public static native int nativeSetupJNI();
}

View File

@@ -0,0 +1,788 @@
package org.libsdl.app;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import android.content.Context;
import android.os.*;
import android.view.*;
import android.util.Log;
public class SDLControllerManager
{
public static native int nativeSetupJNI();
public static native int nativeAddJoystick(int device_id, String name, String desc,
int vendor_id, int product_id,
boolean is_accelerometer, int button_mask,
int naxes, int nhats, int nballs);
public static native int nativeRemoveJoystick(int device_id);
public static native int nativeAddHaptic(int device_id, String name);
public static native int nativeRemoveHaptic(int device_id);
public static native int onNativePadDown(int device_id, int keycode);
public static native int onNativePadUp(int device_id, int keycode);
public static native void onNativeJoy(int device_id, int axis,
float value);
public static native void onNativeHat(int device_id, int hat_id,
int x, int y);
protected static SDLJoystickHandler mJoystickHandler;
protected static SDLHapticHandler mHapticHandler;
private static final String TAG = "SDLControllerManager";
public static void initialize() {
if (mJoystickHandler == null) {
if (Build.VERSION.SDK_INT >= 19) {
mJoystickHandler = new SDLJoystickHandler_API19();
} else {
mJoystickHandler = new SDLJoystickHandler_API16();
}
}
if (mHapticHandler == null) {
if (Build.VERSION.SDK_INT >= 26) {
mHapticHandler = new SDLHapticHandler_API26();
} else {
mHapticHandler = new SDLHapticHandler();
}
}
}
// Joystick glue code, just a series of stubs that redirect to the SDLJoystickHandler instance
public static boolean handleJoystickMotionEvent(MotionEvent event) {
return mJoystickHandler.handleMotionEvent(event);
}
/**
* This method is called by SDL using JNI.
*/
public static void pollInputDevices() {
mJoystickHandler.pollInputDevices();
}
/**
* This method is called by SDL using JNI.
*/
public static void pollHapticDevices() {
mHapticHandler.pollHapticDevices();
}
/**
* This method is called by SDL using JNI.
*/
public static void hapticRun(int device_id, float intensity, int length) {
mHapticHandler.run(device_id, intensity, length);
}
/**
* This method is called by SDL using JNI.
*/
public static void hapticStop(int device_id)
{
mHapticHandler.stop(device_id);
}
// Check if a given device is considered a possible SDL joystick
public static boolean isDeviceSDLJoystick(int deviceId) {
InputDevice device = InputDevice.getDevice(deviceId);
// We cannot use InputDevice.isVirtual before API 16, so let's accept
// only nonnegative device ids (VIRTUAL_KEYBOARD equals -1)
if ((device == null) || (deviceId < 0)) {
return false;
}
int sources = device.getSources();
/* This is called for every button press, so let's not spam the logs */
/**
if ((sources & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
Log.v(TAG, "Input device " + device.getName() + " has class joystick.");
}
if ((sources & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD) {
Log.v(TAG, "Input device " + device.getName() + " is a dpad.");
}
if ((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) {
Log.v(TAG, "Input device " + device.getName() + " is a gamepad.");
}
**/
return ((sources & InputDevice.SOURCE_CLASS_JOYSTICK) != 0 ||
((sources & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD) ||
((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD)
);
}
}
class SDLJoystickHandler {
/**
* Handles given MotionEvent.
* @param event the event to be handled.
* @return if given event was processed.
*/
public boolean handleMotionEvent(MotionEvent event) {
return false;
}
/**
* Handles adding and removing of input devices.
*/
public void pollInputDevices() {
}
}
/* Actual joystick functionality available for API >= 12 devices */
class SDLJoystickHandler_API16 extends SDLJoystickHandler {
static class SDLJoystick {
public int device_id;
public String name;
public String desc;
public ArrayList<InputDevice.MotionRange> axes;
public ArrayList<InputDevice.MotionRange> hats;
}
static class RangeComparator implements Comparator<InputDevice.MotionRange> {
@Override
public int compare(InputDevice.MotionRange arg0, InputDevice.MotionRange arg1) {
// Some controllers, like the Moga Pro 2, return AXIS_GAS (22) for right trigger and AXIS_BRAKE (23) for left trigger - swap them so they're sorted in the right order for SDL
int arg0Axis = arg0.getAxis();
int arg1Axis = arg1.getAxis();
if (arg0Axis == MotionEvent.AXIS_GAS) {
arg0Axis = MotionEvent.AXIS_BRAKE;
} else if (arg0Axis == MotionEvent.AXIS_BRAKE) {
arg0Axis = MotionEvent.AXIS_GAS;
}
if (arg1Axis == MotionEvent.AXIS_GAS) {
arg1Axis = MotionEvent.AXIS_BRAKE;
} else if (arg1Axis == MotionEvent.AXIS_BRAKE) {
arg1Axis = MotionEvent.AXIS_GAS;
}
return arg0Axis - arg1Axis;
}
}
private ArrayList<SDLJoystick> mJoysticks;
public SDLJoystickHandler_API16() {
mJoysticks = new ArrayList<SDLJoystick>();
}
@Override
public void pollInputDevices() {
int[] deviceIds = InputDevice.getDeviceIds();
for(int i=0; i < deviceIds.length; ++i) {
SDLJoystick joystick = getJoystick(deviceIds[i]);
if (joystick == null) {
joystick = new SDLJoystick();
InputDevice joystickDevice = InputDevice.getDevice(deviceIds[i]);
if (SDLControllerManager.isDeviceSDLJoystick(deviceIds[i])) {
joystick.device_id = deviceIds[i];
joystick.name = joystickDevice.getName();
joystick.desc = getJoystickDescriptor(joystickDevice);
joystick.axes = new ArrayList<InputDevice.MotionRange>();
joystick.hats = new ArrayList<InputDevice.MotionRange>();
List<InputDevice.MotionRange> ranges = joystickDevice.getMotionRanges();
Collections.sort(ranges, new RangeComparator());
for (InputDevice.MotionRange range : ranges ) {
if ((range.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
if (range.getAxis() == MotionEvent.AXIS_HAT_X ||
range.getAxis() == MotionEvent.AXIS_HAT_Y) {
joystick.hats.add(range);
}
else {
joystick.axes.add(range);
}
}
}
mJoysticks.add(joystick);
SDLControllerManager.nativeAddJoystick(joystick.device_id, joystick.name, joystick.desc, getVendorId(joystickDevice), getProductId(joystickDevice), false, getButtonMask(joystickDevice), joystick.axes.size(), joystick.hats.size()/2, 0);
}
}
}
/* Check removed devices */
ArrayList<Integer> removedDevices = new ArrayList<Integer>();
for(int i=0; i < mJoysticks.size(); i++) {
int device_id = mJoysticks.get(i).device_id;
int j;
for (j=0; j < deviceIds.length; j++) {
if (device_id == deviceIds[j]) break;
}
if (j == deviceIds.length) {
removedDevices.add(Integer.valueOf(device_id));
}
}
for(int i=0; i < removedDevices.size(); i++) {
int device_id = removedDevices.get(i).intValue();
SDLControllerManager.nativeRemoveJoystick(device_id);
for (int j=0; j < mJoysticks.size(); j++) {
if (mJoysticks.get(j).device_id == device_id) {
mJoysticks.remove(j);
break;
}
}
}
}
protected SDLJoystick getJoystick(int device_id) {
for(int i=0; i < mJoysticks.size(); i++) {
if (mJoysticks.get(i).device_id == device_id) {
return mJoysticks.get(i);
}
}
return null;
}
@Override
public boolean handleMotionEvent(MotionEvent event) {
if ((event.getSource() & InputDevice.SOURCE_JOYSTICK) != 0) {
int actionPointerIndex = event.getActionIndex();
int action = event.getActionMasked();
switch(action) {
case MotionEvent.ACTION_MOVE:
SDLJoystick joystick = getJoystick(event.getDeviceId());
if ( joystick != null ) {
for (int i = 0; i < joystick.axes.size(); i++) {
InputDevice.MotionRange range = joystick.axes.get(i);
/* Normalize the value to -1...1 */
float value = ( event.getAxisValue( range.getAxis(), actionPointerIndex) - range.getMin() ) / range.getRange() * 2.0f - 1.0f;
SDLControllerManager.onNativeJoy(joystick.device_id, i, value );
}
for (int i = 0; i < joystick.hats.size(); i+=2) {
int hatX = Math.round(event.getAxisValue( joystick.hats.get(i).getAxis(), actionPointerIndex ) );
int hatY = Math.round(event.getAxisValue( joystick.hats.get(i+1).getAxis(), actionPointerIndex ) );
SDLControllerManager.onNativeHat(joystick.device_id, i/2, hatX, hatY );
}
}
break;
default:
break;
}
}
return true;
}
public String getJoystickDescriptor(InputDevice joystickDevice) {
String desc = joystickDevice.getDescriptor();
if (desc != null && !desc.isEmpty()) {
return desc;
}
return joystickDevice.getName();
}
public int getProductId(InputDevice joystickDevice) {
return 0;
}
public int getVendorId(InputDevice joystickDevice) {
return 0;
}
public int getButtonMask(InputDevice joystickDevice) {
return -1;
}
}
class SDLJoystickHandler_API19 extends SDLJoystickHandler_API16 {
@Override
public int getProductId(InputDevice joystickDevice) {
return joystickDevice.getProductId();
}
@Override
public int getVendorId(InputDevice joystickDevice) {
return joystickDevice.getVendorId();
}
@Override
public int getButtonMask(InputDevice joystickDevice) {
int button_mask = 0;
int[] keys = new int[] {
KeyEvent.KEYCODE_BUTTON_A,
KeyEvent.KEYCODE_BUTTON_B,
KeyEvent.KEYCODE_BUTTON_X,
KeyEvent.KEYCODE_BUTTON_Y,
KeyEvent.KEYCODE_BACK,
KeyEvent.KEYCODE_BUTTON_MODE,
KeyEvent.KEYCODE_BUTTON_START,
KeyEvent.KEYCODE_BUTTON_THUMBL,
KeyEvent.KEYCODE_BUTTON_THUMBR,
KeyEvent.KEYCODE_BUTTON_L1,
KeyEvent.KEYCODE_BUTTON_R1,
KeyEvent.KEYCODE_DPAD_UP,
KeyEvent.KEYCODE_DPAD_DOWN,
KeyEvent.KEYCODE_DPAD_LEFT,
KeyEvent.KEYCODE_DPAD_RIGHT,
KeyEvent.KEYCODE_BUTTON_SELECT,
KeyEvent.KEYCODE_DPAD_CENTER,
// These don't map into any SDL controller buttons directly
KeyEvent.KEYCODE_BUTTON_L2,
KeyEvent.KEYCODE_BUTTON_R2,
KeyEvent.KEYCODE_BUTTON_C,
KeyEvent.KEYCODE_BUTTON_Z,
KeyEvent.KEYCODE_BUTTON_1,
KeyEvent.KEYCODE_BUTTON_2,
KeyEvent.KEYCODE_BUTTON_3,
KeyEvent.KEYCODE_BUTTON_4,
KeyEvent.KEYCODE_BUTTON_5,
KeyEvent.KEYCODE_BUTTON_6,
KeyEvent.KEYCODE_BUTTON_7,
KeyEvent.KEYCODE_BUTTON_8,
KeyEvent.KEYCODE_BUTTON_9,
KeyEvent.KEYCODE_BUTTON_10,
KeyEvent.KEYCODE_BUTTON_11,
KeyEvent.KEYCODE_BUTTON_12,
KeyEvent.KEYCODE_BUTTON_13,
KeyEvent.KEYCODE_BUTTON_14,
KeyEvent.KEYCODE_BUTTON_15,
KeyEvent.KEYCODE_BUTTON_16,
};
int[] masks = new int[] {
(1 << 0), // A -> A
(1 << 1), // B -> B
(1 << 2), // X -> X
(1 << 3), // Y -> Y
(1 << 4), // BACK -> BACK
(1 << 5), // MODE -> GUIDE
(1 << 6), // START -> START
(1 << 7), // THUMBL -> LEFTSTICK
(1 << 8), // THUMBR -> RIGHTSTICK
(1 << 9), // L1 -> LEFTSHOULDER
(1 << 10), // R1 -> RIGHTSHOULDER
(1 << 11), // DPAD_UP -> DPAD_UP
(1 << 12), // DPAD_DOWN -> DPAD_DOWN
(1 << 13), // DPAD_LEFT -> DPAD_LEFT
(1 << 14), // DPAD_RIGHT -> DPAD_RIGHT
(1 << 4), // SELECT -> BACK
(1 << 0), // DPAD_CENTER -> A
(1 << 15), // L2 -> ??
(1 << 16), // R2 -> ??
(1 << 17), // C -> ??
(1 << 18), // Z -> ??
(1 << 20), // 1 -> ??
(1 << 21), // 2 -> ??
(1 << 22), // 3 -> ??
(1 << 23), // 4 -> ??
(1 << 24), // 5 -> ??
(1 << 25), // 6 -> ??
(1 << 26), // 7 -> ??
(1 << 27), // 8 -> ??
(1 << 28), // 9 -> ??
(1 << 29), // 10 -> ??
(1 << 30), // 11 -> ??
(1 << 31), // 12 -> ??
// We're out of room...
0xFFFFFFFF, // 13 -> ??
0xFFFFFFFF, // 14 -> ??
0xFFFFFFFF, // 15 -> ??
0xFFFFFFFF, // 16 -> ??
};
boolean[] has_keys = joystickDevice.hasKeys(keys);
for (int i = 0; i < keys.length; ++i) {
if (has_keys[i]) {
button_mask |= masks[i];
}
}
return button_mask;
}
}
class SDLHapticHandler_API26 extends SDLHapticHandler {
@Override
public void run(int device_id, float intensity, int length) {
SDLHaptic haptic = getHaptic(device_id);
if (haptic != null) {
Log.d("SDL", "Rtest: Vibe with intensity " + intensity + " for " + length);
if (intensity == 0.0f) {
stop(device_id);
return;
}
int vibeValue = Math.round(intensity * 255);
if (vibeValue > 255) {
vibeValue = 255;
}
if (vibeValue < 1) {
stop(device_id);
return;
}
try {
haptic.vib.vibrate(VibrationEffect.createOneShot(length, vibeValue));
}
catch (Exception e) {
// Fall back to the generic method, which uses DEFAULT_AMPLITUDE, but works even if
// something went horribly wrong with the Android 8.0 APIs.
haptic.vib.vibrate(length);
}
}
}
}
class SDLHapticHandler {
class SDLHaptic {
public int device_id;
public String name;
public Vibrator vib;
}
private ArrayList<SDLHaptic> mHaptics;
public SDLHapticHandler() {
mHaptics = new ArrayList<SDLHaptic>();
}
public void run(int device_id, float intensity, int length) {
SDLHaptic haptic = getHaptic(device_id);
if (haptic != null) {
haptic.vib.vibrate(length);
}
}
public void stop(int device_id) {
SDLHaptic haptic = getHaptic(device_id);
if (haptic != null) {
haptic.vib.cancel();
}
}
public void pollHapticDevices() {
final int deviceId_VIBRATOR_SERVICE = 999999;
boolean hasVibratorService = false;
int[] deviceIds = InputDevice.getDeviceIds();
// It helps processing the device ids in reverse order
// For example, in the case of the XBox 360 wireless dongle,
// so the first controller seen by SDL matches what the receiver
// considers to be the first controller
for (int i = deviceIds.length - 1; i > -1; i--) {
SDLHaptic haptic = getHaptic(deviceIds[i]);
if (haptic == null) {
InputDevice device = InputDevice.getDevice(deviceIds[i]);
Vibrator vib = device.getVibrator();
if (vib.hasVibrator()) {
haptic = new SDLHaptic();
haptic.device_id = deviceIds[i];
haptic.name = device.getName();
haptic.vib = vib;
mHaptics.add(haptic);
SDLControllerManager.nativeAddHaptic(haptic.device_id, haptic.name);
}
}
}
/* Check VIBRATOR_SERVICE */
Vibrator vib = (Vibrator) SDL.getContext().getSystemService(Context.VIBRATOR_SERVICE);
if (vib != null) {
hasVibratorService = vib.hasVibrator();
if (hasVibratorService) {
SDLHaptic haptic = getHaptic(deviceId_VIBRATOR_SERVICE);
if (haptic == null) {
haptic = new SDLHaptic();
haptic.device_id = deviceId_VIBRATOR_SERVICE;
haptic.name = "VIBRATOR_SERVICE";
haptic.vib = vib;
mHaptics.add(haptic);
SDLControllerManager.nativeAddHaptic(haptic.device_id, haptic.name);
}
}
}
/* Check removed devices */
ArrayList<Integer> removedDevices = new ArrayList<Integer>();
for(int i=0; i < mHaptics.size(); i++) {
int device_id = mHaptics.get(i).device_id;
int j;
for (j=0; j < deviceIds.length; j++) {
if (device_id == deviceIds[j]) break;
}
if (device_id == deviceId_VIBRATOR_SERVICE && hasVibratorService) {
// don't remove the vibrator if it is still present
} else if (j == deviceIds.length) {
removedDevices.add(device_id);
}
}
for(int i=0; i < removedDevices.size(); i++) {
int device_id = removedDevices.get(i);
SDLControllerManager.nativeRemoveHaptic(device_id);
for (int j=0; j < mHaptics.size(); j++) {
if (mHaptics.get(j).device_id == device_id) {
mHaptics.remove(j);
break;
}
}
}
}
protected SDLHaptic getHaptic(int device_id) {
for(int i=0; i < mHaptics.size(); i++) {
if (mHaptics.get(i).device_id == device_id) {
return mHaptics.get(i);
}
}
return null;
}
}
class SDLGenericMotionListener_API12 implements View.OnGenericMotionListener {
// Generic Motion (mouse hover, joystick...) events go here
@Override
public boolean onGenericMotion(View v, MotionEvent event) {
float x, y;
int action;
switch ( event.getSource() ) {
case InputDevice.SOURCE_JOYSTICK:
case InputDevice.SOURCE_GAMEPAD:
case InputDevice.SOURCE_DPAD:
return SDLControllerManager.handleJoystickMotionEvent(event);
case InputDevice.SOURCE_MOUSE:
action = event.getActionMasked();
switch (action) {
case MotionEvent.ACTION_SCROLL:
x = event.getAxisValue(MotionEvent.AXIS_HSCROLL, 0);
y = event.getAxisValue(MotionEvent.AXIS_VSCROLL, 0);
SDLActivity.onNativeMouse(0, action, x, y, false);
return true;
case MotionEvent.ACTION_HOVER_MOVE:
x = event.getX(0);
y = event.getY(0);
SDLActivity.onNativeMouse(0, action, x, y, false);
return true;
default:
break;
}
break;
default:
break;
}
// Event was not managed
return false;
}
public boolean supportsRelativeMouse() {
return false;
}
public boolean inRelativeMode() {
return false;
}
public boolean setRelativeMouseEnabled(boolean enabled) {
return false;
}
public void reclaimRelativeMouseModeIfNeeded()
{
}
public float getEventX(MotionEvent event) {
return event.getX(0);
}
public float getEventY(MotionEvent event) {
return event.getY(0);
}
}
class SDLGenericMotionListener_API24 extends SDLGenericMotionListener_API12 {
// Generic Motion (mouse hover, joystick...) events go here
private boolean mRelativeModeEnabled;
@Override
public boolean onGenericMotion(View v, MotionEvent event) {
// Handle relative mouse mode
if (mRelativeModeEnabled) {
if (event.getSource() == InputDevice.SOURCE_MOUSE) {
int action = event.getActionMasked();
if (action == MotionEvent.ACTION_HOVER_MOVE) {
float x = event.getAxisValue(MotionEvent.AXIS_RELATIVE_X);
float y = event.getAxisValue(MotionEvent.AXIS_RELATIVE_Y);
SDLActivity.onNativeMouse(0, action, x, y, true);
return true;
}
}
}
// Event was not managed, call SDLGenericMotionListener_API12 method
return super.onGenericMotion(v, event);
}
@Override
public boolean supportsRelativeMouse() {
return true;
}
@Override
public boolean inRelativeMode() {
return mRelativeModeEnabled;
}
@Override
public boolean setRelativeMouseEnabled(boolean enabled) {
mRelativeModeEnabled = enabled;
return true;
}
@Override
public float getEventX(MotionEvent event) {
if (mRelativeModeEnabled) {
return event.getAxisValue(MotionEvent.AXIS_RELATIVE_X);
}
else {
return event.getX(0);
}
}
@Override
public float getEventY(MotionEvent event) {
if (mRelativeModeEnabled) {
return event.getAxisValue(MotionEvent.AXIS_RELATIVE_Y);
}
else {
return event.getY(0);
}
}
}
class SDLGenericMotionListener_API26 extends SDLGenericMotionListener_API24 {
// Generic Motion (mouse hover, joystick...) events go here
private boolean mRelativeModeEnabled;
@Override
public boolean onGenericMotion(View v, MotionEvent event) {
float x, y;
int action;
switch ( event.getSource() ) {
case InputDevice.SOURCE_JOYSTICK:
case InputDevice.SOURCE_GAMEPAD:
case InputDevice.SOURCE_DPAD:
return SDLControllerManager.handleJoystickMotionEvent(event);
case InputDevice.SOURCE_MOUSE:
// DeX desktop mouse cursor is a separate non-standard input type.
case InputDevice.SOURCE_MOUSE | InputDevice.SOURCE_TOUCHSCREEN:
action = event.getActionMasked();
switch (action) {
case MotionEvent.ACTION_SCROLL:
x = event.getAxisValue(MotionEvent.AXIS_HSCROLL, 0);
y = event.getAxisValue(MotionEvent.AXIS_VSCROLL, 0);
SDLActivity.onNativeMouse(0, action, x, y, false);
return true;
case MotionEvent.ACTION_HOVER_MOVE:
x = event.getX(0);
y = event.getY(0);
SDLActivity.onNativeMouse(0, action, x, y, false);
return true;
default:
break;
}
break;
case InputDevice.SOURCE_MOUSE_RELATIVE:
action = event.getActionMasked();
switch (action) {
case MotionEvent.ACTION_SCROLL:
x = event.getAxisValue(MotionEvent.AXIS_HSCROLL, 0);
y = event.getAxisValue(MotionEvent.AXIS_VSCROLL, 0);
SDLActivity.onNativeMouse(0, action, x, y, false);
return true;
case MotionEvent.ACTION_HOVER_MOVE:
x = event.getX(0);
y = event.getY(0);
SDLActivity.onNativeMouse(0, action, x, y, true);
return true;
default:
break;
}
break;
default:
break;
}
// Event was not managed
return false;
}
@Override
public boolean supportsRelativeMouse() {
return (!SDLActivity.isDeXMode() || (Build.VERSION.SDK_INT >= 27));
}
@Override
public boolean inRelativeMode() {
return mRelativeModeEnabled;
}
@Override
public boolean setRelativeMouseEnabled(boolean enabled) {
if (!SDLActivity.isDeXMode() || (Build.VERSION.SDK_INT >= 27)) {
if (enabled) {
SDLActivity.getContentView().requestPointerCapture();
}
else {
SDLActivity.getContentView().releasePointerCapture();
}
mRelativeModeEnabled = enabled;
return true;
}
else
{
return false;
}
}
@Override
public void reclaimRelativeMouseModeIfNeeded()
{
if (mRelativeModeEnabled && !SDLActivity.isDeXMode()) {
SDLActivity.getContentView().requestPointerCapture();
}
}
@Override
public float getEventX(MotionEvent event) {
// Relative mouse in capture mode will only have relative for X/Y
return event.getX(0);
}
@Override
public float getEventY(MotionEvent event) {
// Relative mouse in capture mode will only have relative for X/Y
return event.getY(0);
}
}

View File

@@ -1 +0,0 @@
../java/SDL_Keys.java

View File

@@ -1 +0,0 @@
../java/Settings.java

View File

@@ -1 +0,0 @@
../java/XZInputStream.java

View File

@@ -1 +0,0 @@
../java/translations

View File

@@ -0,0 +1,33 @@
#!/bin/sh
grep '<string name=' values/strings.xml | while read str; do
if echo "$str" | grep 'translatable="false"' ; then continue; fi
var=`echo $str | sed 's/<string name=["]\([^"]*\).*/\1/'`
text=`echo $str | sed 's/<string name=["][^"]*["]>\([^<]*\).*/\1/'`
if [ "$var" = "app_name" ]; then
continue
fi
PRINTEN=true
echo
for dir in values-*; do
lang=`echo $dir | sed 's/[^-]*-\(..\).*/\1/'`
trans=`grep "<string name=\"$var\">" $dir/strings.xml`
transtext=`echo $trans | sed 's/<string name=["][^"]*["]>\([^<]*\).*/\1/'`
if [ -z "$transtext" ] ; then
#transtext=`./translate.py en $lang "$text"`
#echo "$transtext" | grep 'Suspected Terms of Service Abuse' > /dev/null && transtext="$text"
transtext="$text"
grep -v "^[<]/resources[>]\$" $dir/strings.xml > $dir/strings.1.xml
echo "<string name=\"$var\">$transtext</string>" >> $dir/strings.1.xml
echo "</resources>" >> $dir/strings.1.xml
mv -f $dir/strings.1.xml $dir/strings.xml
if $PRINTEN ; then
echo en: $var: $text
PRINTEN=false
fi
echo $lang: $var: $transtext
fi
done
done

View File

@@ -0,0 +1,24 @@
#!/usr/bin/env python
from urllib2 import urlopen
from urllib import urlencode
import sys
# The google translate API can be found here:
# http://code.google.com/apis/ajaxlanguage/documentation/#Examples
lang1=sys.argv[1]
lang2=sys.argv[2]
langpair='%s|%s'%(lang1,lang2)
text=' '.join(sys.argv[3:])
base_url='http://ajax.googleapis.com/ajax/services/language/translate?'
params=urlencode( (('v',1.0),
('q',text),
('langpair',langpair),) )
url=base_url+params
content=urlopen(url).read()
start_idx=content.find('"translatedText":"')+18
translation=content[start_idx:]
end_idx=translation.find('"}, "')
translation=translation[:end_idx]
print translation

View File

@@ -0,0 +1,3 @@
I've tired of using Google Translate to create random gibberish in the languages I don't know,
so from now on the only supported languages are English, Russian, Ukrainian, and French with some community support,
If you wish to maintain a translation - contact me, but I will want a continuous support, not just one-time translation.

View File

@@ -0,0 +1,157 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="init">Initialisiere</string>
<string name="please_wait">Bitte warte, während die Dateien heruntergeladen werden.</string>
<string name="device_config">Gerätekonfiguration</string>
<string name="device_change_cfg">Gerätekonfiguration bearbeiten</string>
<string name="download_unneeded">Download nicht nötig</string>
<string name="connecting_to">Verbinde mit %s</string>
<string name="failed_connecting_to">Verbindung mit %s fehlgeschlagen</string>
<string name="error_connecting_to">Fehler beim Verbinden mit %s</string>
<string name="dl_from">Lade Daten von %s</string>
<string name="error_dl_from">Fehler beim Download von %s</string>
<string name="error_write">Fehler beim schreiben auf %s</string>
<string name="dl_progress">Zu %1$.0f%% abgeschlossen: Datei %2$s</string>
<string name="dl_finished">Abgeschlossen</string>
<string name="storage_phone">Interner Speicher: %d MiB frei</string>
<string name="storage_sd">SD Karte: %d MiB frei</string>
<string name="storage_question">Wohin sollen die Dateien gespeichert werden</string>
<string name="controls_arrows">Pfeiltasten / Joystick / dpad</string>
<string name="controls_trackball">Trackball</string>
<string name="controls_accel">Accelerometer</string>
<string name="controls_question">Welche Arten von Navigationstasten hat das Gerät?</string>
<string name="trackball_no_dampening">Keine Dämpfung</string>
<string name="trackball_fast">Schnell</string>
<string name="trackball_medium">Mittel</string>
<string name="trackball_slow">Langsam</string>
<string name="trackball_question">Dämpfung des Trackball</string>
<string name="accel_fast">Schnell</string>
<string name="accel_medium">Mittel</string>
<string name="accel_slow">Langsam</string>
<string name="accel_question">Empfindlichkeit des Accelerometers</string>
<string name="audiobuf_small">Klein (für schnelle Geräte)</string>
<string name="audiobuf_medium">Mittel</string>
<string name="audiobuf_large">Groß (Wenn Ton "hängt")</string>
<string name="audiobuf_question">Größe des Audiopuffers</string>
<string name="optional_downloads">Optional Downloads</string>
<string name="ok">OK</string>
<string name="controls_touch">Touchscreen nur</string>
<string name="controls_additional">Zusätzliche Kontrollen zu verwenden</string>
<string name="controls_screenkb">On-Screen-Tastatur</string>
<string name="controls_accelnav">Beschleunigungsmesser</string>
<string name="controls_screenkb_size">On-Screen-Tastatur Größe</string>
<string name="controls_screenkb_large">Große</string>
<string name="controls_screenkb_medium">Medium</string>
<string name="controls_screenkb_small">Kleine</string>
<string name="controls_screenkb_tiny">Winzig</string>
<string name="controls_screenkb_theme">On-Screen-Tastatur Thema</string>
<string name="controls_screenkb_by">%1$s von %2$s</string>
<string name="accel_floating">Schwimmend</string>
<string name="accel_fixed_start">Feste, wenn die Anwendung startet</string>
<string name="accel_fixed_horiz">Fixiert auf Tisch Schreibtisch Orientierung</string>
<string name="accel_question_center">Beschleunigungsmesser Mittelstellung</string>
<string name="audiobuf_verysmall">Sehr kleine (schnelle Geräte, weniger Verzögerung)</string>
<string name="rightclick_question">Rechter Mausklick ausgelöst durch</string>
<string name="rightclick_menu">Menütaste</string>
<string name="rightclick_multitouch">Touch-Screen mit dem zweiten Finger</string>
<string name="rightclick_pressure">Touchscreen mit Kraft</string>
<string name="advanced">Erweiterte Funktionen</string>
<string name="mouse_keepaspectratio">Halten 4:3-Bildschirm Seitenverhältnis</string>
<string name="mouse_showcreenunderfinger">Show-Bildschirm unter dem Finger in einem separaten Fenster</string>
<string name="measurepressure_touchplease">Bitte schieben Sie den Finger über den Bildschirm für zwei Sekunden</string>
<string name="rightclick_none">Deaktivieren der rechten Maustaste</string>
<string name="leftclick_question">Linke Maustaste</string>
<string name="leftclick_normal">Normal</string>
<string name="leftclick_near_cursor">Tippen Sie auf nahe Mauszeiger</string>
<string name="leftclick_multitouch">Touch-Screen mit dem zweiten Finger</string>
<string name="leftclick_pressure">Touchscreen mit Kraft</string>
<string name="leftclick_dpadcenter">Trackball klicken Select-Taste</string>
<string name="mouse_joystickmouse">Bewegen Sie die Maus mit Joystick oder Trackball</string>
<string name="measurepressure_response">Pressure %1$03d Radius %2$03d</string>
<string name="click_with_dpadcenter">Linker Mausklick mit Trackball / Joystick Zentrum</string>
<string name="mouse_joystickmousespeed">Bewegen Sie die Maus mit Joystick-Geschwindigkeit</string>
<string name="mouse_joystickmouseaccel">Bewegen Sie die Maus mit Joystick-Beschleunigung</string>
<string name="none">Keine</string>
<string name="controls_screenkb_transparency">On-Screen-Tastatur Transparenz</string>
<string name="controls_screenkb_trans_0">Nicht sichtbar</string>
<string name="controls_screenkb_trans_1">Fast unsichtbar</string>
<string name="controls_screenkb_trans_2">Transparente</string>
<string name="controls_screenkb_trans_3">Semi-transparent</string>
<string name="controls_screenkb_trans_4">Non-transparent</string>
<string name="mouse_emulation">Maus-Emulation</string>
<string name="measurepressure">Kalibrieren Touchscreen Druck</string>
<string name="remap_hwkeys">Remap physischen Tasten</string>
<string name="remap_hwkeys_press">Drücken Sie eine beliebige Taste außer HOME und POWER, können Sie Lautstärke-Tasten</string>
<string name="remap_hwkeys_select">Wählen Sie SDL Schlüsselcode</string>
<string name="remap_screenkb">Remap On-Screen-Steuerung</string>
<string name="remap_screenkb_joystick">On-Screen-Joystick</string>
<string name="remap_screenkb_button">On-Screen-Taste</string>
<string name="remap_screenkb_button_text">On-Screen-Texteingabe-Taste</string>
<string name="remap_screenkb_button_zoomin">Zoom in Zwei-Finger-Geste</string>
<string name="remap_screenkb_button_zoomout">Verkleinern Zwei-Finger-Geste</string>
<string name="remap_screenkb_button_rotateleft">Nach links drehen Zwei-Finger-Geste</string>
<string name="remap_screenkb_button_rotateright">Nach rechts drehen Zwei-Finger-Geste</string>
<string name="remap_screenkb_button_gestures">Zwei-Finger-Gesten</string>
<string name="accel_veryfast">Sehr schnell</string>
<string name="remap_screenkb_button_gestures_sensitivity">Zwei-Finger-Gesten Bildschirm Empfindlichkeit</string>
<string name="storage_custom">Geben Sie direkt</string>
<string name="storage_commandline">Geben Kommandozeilenparameter</string>
<string name="calibrate_touchscreen">Kalibrieren Touchscreen</string>
<string name="calibrate_touchscreen_touch">Touch allen vier Rändern des Bildschirms, drücken Sie Menü, wenn Sie fertig</string>
<string name="screenkb_custom_layout">Passen Sie auf dem Bildschirm Tastatur-Layout</string>
<string name="screenkb_custom_layout_help">Slide-Bildschirm hinzufügen Taste, drücken Sie Menü zum letzten Knopf rückgängig machen</string>
<string name="rightclick_key">Physikalische Schlüssel</string>
<string name="mouse_showcreenunderfinger2">On-Screen-Lupe</string>
<string name="video">Video-Einstellungen</string>
<string name="video_smooth">Glatte Video</string>
<string name="accel_veryslow">Sehr langsam</string>
<string name="leftclick_timeout">Halten Sie an der gleichen Stelle</string>
<string name="leftclick_tap">Tippen Sie auf</string>
<string name="leftclick_tap_or_timeout">Tippen Sie auf oder halten</string>
<string name="leftclick_timeout_time">Holding-Timeout</string>
<string name="leftclick_timeout_time_0">0,3 Sek.</string>
<string name="leftclick_timeout_time_1">0,5 Sek.</string>
<string name="leftclick_timeout_time_2">0,7 Sek.</string>
<string name="leftclick_timeout_time_3">1 Sek.</string>
<string name="leftclick_timeout_time_4">1,5 Sek.</string>
<string name="mouse_relative">Relative Bewegung der Maus (Laptop-Modus)</string>
<string name="mouse_relative_speed">Relative Maus Bewegungsgeschwindigkeit</string>
<string name="mouse_relative_accel">Relative Bewegung der Maus Beschleunigung</string>
<string name="downloads">Downloads</string>
<string name="video_separatethread">Separaten Thread für Video, FPS bei einigen Geräten zu erhöhen</string>
<string name="text_edit_click_here">Tippen Sie auf der Eingabe beginnen, drücken Sie Zurück, wenn Sie fertig</string>
<string name="display_size_mouse">Konfigurieren der Maus je nach Display-Größe</string>
<string name="display_size">Wählen Sie Ihre Display-Größe</string>
<string name="display_size_large">Groß (Tablette)</string>
<string name="display_size_small">Klein (Telefon)</string>
<string name="display_size_tiny">Uberklein (Xperia Mini)</string>
<string name="show_more_options">Weitere Optionen</string>
<string name="controls_screenkb_drawsize">Größe der Schaltfläche Bilder</string>
<string name="cancel">Cancel</string>
<string name="controls_screenkb_custom">Custom</string>
<string name="mouse_hover_jitter_filter">Filter jitter for stylus/finger hover</string>
<string name="remap_hwkeys_select_simple">Select action</string>
<string name="remap_hwkeys_select_more_keys">Show all keycodes</string>
<string name="display_size_small_touchpad">Small, touchpad mode</string>
<string name="display_size_tiny_touchpad">Tiny, touchpad mode</string>
<string name="hardware_mouse_detected">Hardware mouse detected, disabling mouse emulation</string>
<string name="not_enough_ram">Not enough RAM</string>
<string name="not_enough_ram_size">This app needs %1$d Mb RAM, your device has %2$d Mb</string>
<string name="ignore">Ignore</string>
<string name="calibrate_gyroscope">Calibrate gyroscope</string>
<string name="calibrate_gyroscope_text">Put your device on a flat surface</string>
<string name="calibrate_gyroscope_not_supported">Your device does not have gyroscope</string>
<string name="reset_config">Reset config to defaults</string>
<string name="reset_config_ask">Reset all options to default values?</string>
<string name="cancel_download">Cancel data downloading?</string>
<string name="cancel_download_resume">You can resume it later, the data will not be downloaded twice.</string>
<string name="yes">Yes</string>
<string name="no">No</string>
</resources>

View File

@@ -0,0 +1,157 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="init">Käynnistetään</string>
<string name="please_wait">Odota kun tietoja ladataan</string>
<string name="device_config">Laiteasetukset</string>
<string name="device_change_cfg">Muuta laiteasetuksia</string>
<string name="download_unneeded">Ei tarvitse ladata</string>
<string name="connecting_to">Yhdistetään %s</string>
<string name="failed_connecting_to">Yhdistäminen epäonnistui %s</string>
<string name="error_connecting_to">Virhe yhdistettäessä %s</string>
<string name="dl_from">Ladataan kohteesta %s</string>
<string name="error_dl_from">Virhe ladattaessa kohteesta %s</string>
<string name="error_write">Virhe kirjoittaessa %s</string>
<string name="dl_progress">%1$.0f%% valmis: tiedosto %2$s</string>
<string name="dl_finished">Valmis</string>
<string name="storage_phone">Sisäinen muisti - %d Mt vapaana</string>
<string name="storage_sd">SD kortti - %d Mt vapaana</string>
<string name="storage_question">Minne sovelluksen data ladataan</string>
<string name="controls_arrows">Nuolinapit / joystick / dpad</string>
<string name="controls_trackball">Pallohiiri</string>
<string name="controls_accel">Kiihtyvyysanturi</string>
<string name="controls_question">Millaiset navigointinapit laittessasi on?</string>
<string name="trackball_no_dampening">Ei vaimennusta</string>
<string name="trackball_fast">Nopea</string>
<string name="trackball_medium">Kohtalainen</string>
<string name="trackball_slow">Hidas</string>
<string name="trackball_question">Pallohiiren vaimennus</string>
<string name="accel_fast">Nopea</string>
<string name="accel_medium">Kohtalainen</string>
<string name="accel_slow">Hidas</string>
<string name="accel_question">Kiihtyvyysanturin herkkyys</string>
<string name="audiobuf_small">Pieni (nopeat laitteet)</string>
<string name="audiobuf_medium">Keskisuuri</string>
<string name="audiobuf_large">Suuri (jos ääni pätkii)</string>
<string name="audiobuf_question">Äänipuskurin koko</string>
<string name="optional_downloads">Vapaaehtoinen lataukset</string>
<string name="ok">OK</string>
<string name="controls_touch">Kosketusnäyttö vain</string>
<string name="controls_additional">Muita ohjausobjekteja käyttää</string>
<string name="controls_screenkb">Näyttönäppäimistöllä</string>
<string name="controls_accelnav">Kiihtyvyysmittari</string>
<string name="controls_screenkb_size">Näyttönäppäimistöllä koko</string>
<string name="controls_screenkb_large">Suuri</string>
<string name="controls_screenkb_medium">Medium</string>
<string name="controls_screenkb_small">Pienet</string>
<string name="controls_screenkb_tiny">Tiny</string>
<string name="controls_screenkb_theme">Näyttönäppäimistöllä teema</string>
<string name="controls_screenkb_by">%1$s %2$s</string>
<string name="accel_floating">Kelluva</string>
<string name="accel_fixed_start">Kiinteät kun sovellus käynnistyy</string>
<string name="accel_fixed_horiz">Korjattu taulukko työpöytä suuntautumiseen</string>
<string name="accel_question_center">Kiihtyvyysmittari keskiasentoon</string>
<string name="audiobuf_verysmall">Hyvin pieni (nopea laitteita, vähemmän lag)</string>
<string name="rightclick_question">Napsauta hiiren kakkospainikkeella alkunsa</string>
<string name="rightclick_menu">Valikkonäppäin</string>
<string name="rightclick_multitouch">Kosketusnäyttö on toinen sormi</string>
<string name="rightclick_pressure">Kosketusnäyttö voimalla</string>
<string name="advanced">Lisäominaisuudet</string>
<string name="mouse_keepaspectratio">Pidä 04:03 kuvasuhde</string>
<string name="mouse_showcreenunderfinger">Näytä näytön alle sormi erillisessä ikkunassa</string>
<string name="measurepressure_touchplease">Ole hyvä ja liu\u0026#39;uttamalla sormea näytöllä kaksi sekuntia</string>
<string name="rightclick_none">Poista oikealla hiiren klikkauksella</string>
<string name="leftclick_question">Vasen hiiren nappi</string>
<string name="leftclick_normal">Normaali</string>
<string name="leftclick_near_cursor">Touch lähellä hiiren kursori</string>
<string name="leftclick_multitouch">Kosketusnäyttö on toinen sormi</string>
<string name="leftclick_pressure">Kosketusnäyttö voimalla</string>
<string name="leftclick_dpadcenter">Trackball Valitse / Select-näppäintä</string>
<string name="mouse_joystickmouse">Siirrä hiiren ohjaimella tai trackball</string>
<string name="measurepressure_response">Paine %1$03d säde %2$03d</string>
<string name="click_with_dpadcenter">Vasen hiiren klikkaus trackball-ohjaimella keskusta</string>
<string name="mouse_joystickmousespeed">Siirrä hiiri ohjainta nopeasti</string>
<string name="mouse_joystickmouseaccel">Siirrä hiiri ohjainta kiihtyvyys</string>
<string name="none">Ei</string>
<string name="controls_screenkb_transparency">Näyttönäppäimistöllä avoimuutta</string>
<string name="controls_screenkb_trans_0">Näkymätön</string>
<string name="controls_screenkb_trans_1">Lähes näkymätön</string>
<string name="controls_screenkb_trans_2">Läpinäkyvä</string>
<string name="controls_screenkb_trans_3">Semi-avoimet</string>
<string name="controls_screenkb_trans_4">Ei-läpinäkyvä</string>
<string name="mouse_emulation">Hiiren emulointi</string>
<string name="measurepressure">Kalibroi kosketusnäyttö paine</string>
<string name="remap_hwkeys">Remap fyysiset näppäimet</string>
<string name="remap_hwkeys_press">Paina mitä tahansa näppäintä paitsi koti-ja POWER, voit käyttää äänenvoimakkuusnäppäimiä</string>
<string name="remap_hwkeys_select">Valitse SDL näppäinkoodien</string>
<string name="remap_screenkb">Remap näytön valvonnan</string>
<string name="remap_screenkb_joystick">Näytöllä ohjainta</string>
<string name="remap_screenkb_button">Ruutunäyttöpainike</string>
<string name="remap_screenkb_button_text">Näytön tekstin tulopainiketta</string>
<string name="remap_screenkb_button_zoomin">Suurenna kahden sormen elettä</string>
<string name="remap_screenkb_button_zoomout">Pienennä kahden sormen elettä</string>
<string name="remap_screenkb_button_rotateleft">Kierrä vasemmalle kahden sormen elettä</string>
<string name="remap_screenkb_button_rotateright">Kierrä oikealle kahden sormen elettä</string>
<string name="remap_screenkb_button_gestures">Kahden sormen eleitä</string>
<string name="accel_veryfast">Erittäin nopea</string>
<string name="remap_screenkb_button_gestures_sensitivity">Kahden sormen näytön eleet herkkyys</string>
<string name="storage_custom">Määritä hakemisto</string>
<string name="storage_commandline">Määritä komentoriviparametrit</string>
<string name="calibrate_touchscreen">Kalibroi kosketusnäyttö</string>
<string name="calibrate_touchscreen_touch">Touch kaikki neljä reunaa näytön, paina Valikko, kun olet valmis</string>
<string name="screenkb_custom_layout">Mukauta-ruudun näppäimistö</string>
<string name="screenkb_custom_layout_help">Työnnä näytön lisätä painikkeen, paina Menu kumota viimeksi painike</string>
<string name="rightclick_key">Fyysinen avain</string>
<string name="mouse_showcreenunderfinger2">Näytöllä suurennuslasi</string>
<string name="video">Videon asetukset</string>
<string name="video_smooth">Tasainen video</string>
<string name="accel_veryslow">Erittäin hidas</string>
<string name="leftclick_timeout">Pidä samalla paikalla</string>
<string name="leftclick_tap">Hana</string>
<string name="leftclick_tap_or_timeout">Napauta tai pidä</string>
<string name="leftclick_timeout_time">Holding aikakatkaisu</string>
<string name="leftclick_timeout_time_0">0,3 sekuntia</string>
<string name="leftclick_timeout_time_1">0,5 sekuntia</string>
<string name="leftclick_timeout_time_2">0,7 sekuntia</string>
<string name="leftclick_timeout_time_3">1 sek</string>
<string name="leftclick_timeout_time_4">1,5 sek</string>
<string name="mouse_relative">Suhteellinen hiiren liikkeet (kannettavan tietokoneen tilassa)</string>
<string name="mouse_relative_speed">Suhteellinen hiiren liikkeen nopeus</string>
<string name="mouse_relative_accel">Suhteellinen hiiren liikkeen kiihtyvyys</string>
<string name="downloads">Downloads</string>
<string name="video_separatethread">Erillisessä säikeessä video, kasvaa FPS joissakin laitteissa</string>
<string name="text_edit_click_here">Napauta aloittaa kirjoittamisen, paina Takaisin, kun olet valmis</string>
<string name="display_size_mouse">Määritä hiiren riippuen näytön koosta</string>
<string name="display_size">Valitse näytön koko</string>
<string name="display_size_large">Suuri (tabletti)</string>
<string name="display_size_small">Pieni (puhelin)</string>
<string name="display_size_tiny">Tiny (Xperia Mini)</string>
<string name="show_more_options">Näytä enemmän vaihtoehtoja</string>
<string name="controls_screenkb_drawsize">Koko painike kuvia</string>
<string name="cancel">Cancel</string>
<string name="controls_screenkb_custom">Custom</string>
<string name="mouse_hover_jitter_filter">Filter jitter for stylus/finger hover</string>
<string name="remap_hwkeys_select_simple">Select action</string>
<string name="remap_hwkeys_select_more_keys">Show all keycodes</string>
<string name="display_size_small_touchpad">Small, touchpad mode</string>
<string name="display_size_tiny_touchpad">Tiny, touchpad mode</string>
<string name="hardware_mouse_detected">Hardware mouse detected, disabling mouse emulation</string>
<string name="not_enough_ram">Not enough RAM</string>
<string name="not_enough_ram_size">This app needs %1$d Mb RAM, your device has %2$d Mb</string>
<string name="ignore">Ignore</string>
<string name="calibrate_gyroscope">Calibrate gyroscope</string>
<string name="calibrate_gyroscope_text">Put your device on a flat surface</string>
<string name="calibrate_gyroscope_not_supported">Your device does not have gyroscope</string>
<string name="reset_config">Reset config to defaults</string>
<string name="reset_config_ask">Reset all options to default values?</string>
<string name="cancel_download">Cancel data downloading?</string>
<string name="cancel_download_resume">You can resume it later, the data will not be downloaded twice.</string>
<string name="yes">Yes</string>
<string name="no">No</string>
</resources>

View File

@@ -0,0 +1,196 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- values-es/string.xml string resource in spanish languaje -->
<resources>
<string name="init">Inicializando</string>
<string name="please_wait">Por favor espere mientras se descargan los datos</string>
<string name="device_config">Configuración del dispositivo</string>
<string name="device_change_cfg">Cambiar la configuración del dispositivo</string>
<string name="download_unneeded">No se necesita descarga</string>
<string name="connecting_to">Conectándose a %s</string>
<string name="failed_connecting_to">Fallo al conectarse a %s</string>
<string name="error_connecting_to">Error al conectarse a %s</string>
<string name="dl_from">Descargándose datos desde %s</string>
<string name="error_dl_from">Error al descargarse los datos desde %s</string>
<string name="error_write">Error al escribir en %s</string>
<string name="dl_progress">%1$.0f%% hecho: archivo %2$s</string>
<string name="dl_finished">Finalizado</string>
<string name="storage_phone">Almacenamiento interno - %d MB libres</string>
<string name="storage_sd">Almacenamiento SD card - %d MB libres</string>
<string name="storage_custom">Especifique el directorio</string>
<string name="storage_commandline">Especifique los parámetros de la línea de comandos, one argument per line</string>
<string name="storage_question">Lugar donde guardar los datos de la instalación</string>
<string name="optional_downloads">Descargas</string>
<string name="downloads">Descargas</string>
<string name="ok">Aceptar</string>
<string name="cancel">Cancelar</string>
<string name="controls_arrows">Flechas / Joystick / Cruceta mando video consola</string>
<string name="controls_trackball">Bola de control (Trackball)</string>
<string name="controls_accel">Acelerómetro</string>
<string name="controls_touch">Sólo Tocando la pantalla</string>
<string name="controls_question">¿ Qué clase de teclas de navegación tiene su dispositivo ?</string>
<string name="controls_additional">Controles adicionales</string>
<string name="controls_screenkb">Teclado virtual en pantalla</string>
<string name="controls_accelnav">Acelerómetro</string>
<string name="controls_screenkb_size">Tamaño del teclado virtual en pantalla</string>
<string name="controls_screenkb_drawsize">Tamaño de las imágenes de los botones</string>
<string name="controls_screenkb_large">Grande</string>
<string name="controls_screenkb_medium">Mediano</string>
<string name="controls_screenkb_small">Pequeño</string>
<string name="controls_screenkb_tiny">Diminuto</string>
<string name="controls_screenkb_custom">Personalizado</string>
<string name="controls_screenkb_theme">Tema del teclado virtual en pantalla</string>
<string name="controls_screenkb_by">%1$s x %2$s</string>
<string name="controls_screenkb_transparency">Teclado virtual en pantalla transparente</string>
<string name="controls_screenkb_trans_0">Invisible</string>
<string name="controls_screenkb_trans_1">Semi invisible</string>
<string name="controls_screenkb_trans_2">Transparente</string>
<string name="controls_screenkb_trans_3">Semi transparente</string>
<string name="controls_screenkb_trans_4">Opaco</string>
<string name="trackball_no_dampening">Sin retardo (muy rápido)</string>
<string name="trackball_fast">Rápido</string>
<string name="trackball_medium">Mediano</string>
<string name="trackball_slow">Lento</string>
<string name="trackball_question">Retardo de la Bola control(Trackball)</string>
<string name="accel_veryfast">Muy rápido</string>
<string name="accel_fast">Rápido</string>
<string name="accel_medium">Mediano</string>
<string name="accel_slow">Lento</string>
<string name="accel_veryslow">Muy lento</string>
<string name="accel_question">Determinar velocidad accelerómetro</string>
<string name="accel_floating">Flotante</string>
<string name="accel_fixed_start">Fijo cuando la aplicación comienza</string>
<string name="accel_fixed_horiz">Fijar la orientación de la tablet</string>
<string name="accel_question_center">Centrar la posición del acelerómetro</string>
<string name="mouse_emulation">Emulación del ratón</string>
<string name="rightclick_question">Botón derecho del ratón</string>
<string name="rightclick_menu">Tecla de menú</string>
<string name="rightclick_key">Tecla física</string>
<string name="rightclick_multitouch">Tocar la pantalla con un segundo dedo</string>
<string name="rightclick_pressure">Tocar la pantalla durante un tiempo prolongado</string>
<string name="rightclick_none">Desabilitar el botón derecho del ratón</string>
<string name="leftclick_question">Botón izquierdo del ratón</string>
<string name="leftclick_normal">Normal</string>
<string name="leftclick_near_cursor">Tocar cerca del cursor del ratón</string>
<string name="leftclick_multitouch">Tocar la pantalla con un segundo dedo</string>
<string name="leftclick_pressure">Tocar la pantalla durante un tiempo prolongado</string>
<string name="leftclick_dpadcenter">Botón del Trackball / centrar joystick</string>
<string name="leftclick_timeout">Dejar de tocar y tocar la pantalla durante ...</string>
<string name="leftclick_tap">Un toque rápido (no tocar, tocar, y no tocar)</string>
<string name="leftclick_tap_or_timeout">Tocar o dejar de tocar</string>
<string name="leftclick_timeout_time">Mantener toque durante ...</string>
<string name="leftclick_timeout_time_0">0.3 sec</string>
<string name="leftclick_timeout_time_1">0.5 sec</string>
<string name="leftclick_timeout_time_2">0.7 sec</string>
<string name="leftclick_timeout_time_3">1 sec</string>
<string name="leftclick_timeout_time_4">1.5 sec</string>
<string name="click_with_dpadcenter">Botón izquierdo del ratón mediante: Bola(trackball)/centrar joystick</string>
<string name="advanced">Características avanzadas</string>
<string name="mouse_keepaspectratio">Mantenr proporción de la pantalla 4:3</string>
<string name="mouse_showcreenunderfinger">Mostrar la pantalla debajo del dedo en una ventana por separado</string>
<string name="mouse_showcreenunderfinger2">Mostrar lente de aumento sobre la pantalla</string>
<string name="mouse_joystickmouse">Mover el ratón mediante joystick o bola(trackball)</string>
<string name="mouse_joystickmousespeed">Mover el ratón mediante un joystick de velocidad</string>
<string name="mouse_joystickmouseaccel">Mover el ratón mediante un joystick de aceleración</string>
<string name="mouse_relative">Movimiento relativo del ratón (laptop mode)</string>
<string name="mouse_relative_speed">Velocidad relativa del movimiento del ratón</string>
<string name="mouse_relative_accel">Aceleración relativa del movimiento del ratón</string>
<string name="mouse_hover_jitter_filter">Filtro elimina nerviosismo al escribir/dedo flotante</string>
<string name="mouse_gyroscope_mouse">Controlar el ratón mediante el giroscopio</string>
<string name="mouse_gyroscope_mouse_sensitivity">Sensibilidad del giroscopio</string>
<string name="mouse_finger_hover">Dedo flotante deslizante</string>
<string name="mouse_subframe_touch_events">Múltiples eventos de toque por fotograma</string>
<string name="none">Nada</string>
<string name="measurepressure">Calibrar la presión del toque</string>
<string name="measurepressure_touchplease">Por favor deslice el dedo por la pantalla durante dos segundos</string>
<string name="measurepressure_response">Presión %1$03d radio %2$03d</string>
<string name="audiobuf_verysmall">Muy pequeña (dispositivos rápidos, menos retraso)</string>
<string name="audiobuf_small">Pequeña</string>
<string name="audiobuf_medium">Media</string>
<string name="audiobuf_large">Grande (dispositivos antiguos, si el sonido se entrecorta)</string>
<string name="audiobuf_question">Tamaño de la memoria de almacenamiento de audio</string>
<string name="remap_hwkeys">Cambiar teclas físicas</string>
<string name="remap_hwkeys_press">Presione una tecla excepto Botón central(HOME) y Botón encendido, puede usar las teclas de volumen</string>
<string name="remap_hwkeys_select">Seleccionar código de la tecla SDL</string>
<string name="remap_hwkeys_select_simple">Seleccionar acción</string>
<string name="remap_hwkeys_select_more_keys">Mostrar todos los códigos de teclas</string>
<string name="remap_screenkb">Cambiar controles de pulsación pantalla</string>
<string name="remap_screenkb_joystick">Joystick</string>
<string name="remap_screenkb_button">Botón</string>
<string name="remap_screenkb_button_text">Bótón para introducir texto</string>
<string name="remap_screenkb_button_gestures">Gestos con dos dedos</string>
<string name="remap_screenkb_button_gestures_sensitivity">Sensibilidad de gestos con dos dedos</string>
<string name="remap_screenkb_button_zoomin">Gesto para Zoom de aumento con dos dedos</string>
<string name="remap_screenkb_button_zoomout">Gesto prara Zoom de disminución con dos dedos</string>
<string name="remap_screenkb_button_rotateleft">Gesto para rotar a la izquierda con dos dedos</string>
<string name="remap_screenkb_button_rotateright">Gesto para rotar a la derecha con dos dedos</string>
<string name="screenkb_custom_layout">Pesonalizar la presentación del teclado virtual en pantalla</string>
<string name="screenkb_custom_layout_help">Presione botón Atras para finalizar. Cambiar tamaño botones deslizando sobre el espacio vacío.</string>
<string name="screenkb_floating_joystick">Joystick flotante</string>
<string name="calibrate_touchscreen">Calibrar el toque sobre la pantalla</string>
<string name="calibrate_touchscreen_touch">Toque todas las esquinas de la pantalla, puse botón Atras para finalizar</string>
<string name="video">Configuración de Video</string>
<string name="video_smooth">Filtro de lineas</string>
<string name="video_separatethread">Hebra/proceso separado para video, puede incrementar FPS, puede colgar la APP</string>
<string name="video_orientation_vertical">Orientación Horizontal/Vertical de la pantalla</string>
<string name="video_bpp_24">24 bits profundidad del color</string>
<string name="video_immersive">Ocultar botones de navegación(botones pantalla) / modo inmersión</string>
<string name="text_edit_click_here">Toque y suelte para empezar a teclear, presione botón Atras para finalizar</string>
<string name="display_size_mouse">Modo de emulación del ratón</string>
<string name="display_size">Tamaño de la pantalla para la emulación del ratón</string>
<string name="display_size_large">Grande (tablets)</string>
<string name="display_size_small">Pequeña, lupa de aumento</string>
<string name="display_size_small_touchpad">Pequeña, modo touchpad</string>
<string name="display_size_tiny">Diminuta</string>
<string name="display_size_tiny_touchpad">Diminuta, modo touchpad</string>
<string name="show_more_options">Mostrar más opciones</string>
<string name="hardware_mouse_detected">Detección del ratón real, desabilita emulación del ratón</string>
<string name="not_enough_ram">No hay suficiente memoria RAM</string>
<string name="not_enough_ram_size">Esta APP necesita %1$d Mb RAM, su dispositivo tiene %2$d Mb</string>
<string name="ignore">Ignorar</string>
<string name="calibrate_gyroscope">Calibrar giroscopio</string>
<string name="calibrate_gyroscope_text">Mantenga quieta la pantalla en una superficie plana, que no vibre</string>
<string name="calibrate_gyroscope_not_supported">Su dispositivo no tiene giroscopio</string>
<string name="reset_config">Resetear configuración a valores por defecto</string>
<string name="reset_config_ask">¿ Resetear todas las opciones a valores por defecto ?</string>
<string name="cancel_download">¿ Cancelar descarga de datos ?</string>
<string name="cancel_download_resume">Usted puede continuar después, los datos ya guardados no se descargarán otra vez.</string>
<string name="yes">Si</string>
<string name="no">No</string>
<!-- Play Game Services strings -->
<string name="gamehelper_sign_in_failed">Fallo al conectarse a la cuenta. Por favor chequee la conexión de la red e inténtelo de nuevo.</string>
<string name="gamehelper_app_misconfigured">La aplicacion esta incorrectamente configurada. Chequee que el nombre del paquete y certificado coincide con el ID de cliente creado en la Consola de Desarrollo. También, si la aplicación no esta todavía publicada, chequee que la cuenta que usted esta intentando acceder esta listada como cuenta de testeador. Vea registro de errores(logs) para más información.</string>
<string name="gamehelper_license_failed">Chequeo de licencia fallido.</string>
<string name="gamehelper_unknown_error">Error desconocido.</string>
<string name="accessing_network">Accediendo a la red, por favor espere</string>
</resources>

View File

@@ -0,0 +1,192 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="init">Démarrage</string>
<string name="please_wait">Veuillez patienter pendant que les données sont téléchargées</string>
<string name="device_config">Configuration de l\'appareil</string>
<string name="device_change_cfg">Changer la configuration</string>
<string name="download_unneeded">Téléchargement non nécessaire</string>
<string name="connecting_to">Connexion à %s</string>
<string name="failed_connecting_to">Echec de la connexion à %s</string>
<string name="error_connecting_to">Erreur durant la connexion à %s</string>
<string name="dl_from">Téléchargement à partir de %s</string>
<string name="error_dl_from">Erreur lors du téléchargement à partir de %s</string>
<string name="error_write">Erreur d\'écriture dans %s</string>
<string name="dl_progress">%1$.0f%% fait : fichier %2$s</string>
<string name="dl_finished">Fini</string>
<string name="storage_phone">Stockage interne - %d Mo de libre</string>
<string name="storage_sd">Carte SD - %d Mo de libre</string>
<string name="storage_custom">Choisir le répertoire</string>
<string name="storage_commandline">Choisir les paramètres de la ligne de commande, one argument per line</string>
<string name="storage_question">Où télécharger les données</string>
<string name="optional_downloads">Téléchargements</string>
<string name="downloads">Téléchargements</string>
<string name="ok">OK</string>
<string name="controls_arrows">Flèches / joystick / dpad</string>
<string name="controls_trackball">Trackball</string>
<string name="controls_accel">Accéléromètre</string>
<string name="controls_touch">Ecran tactile seul</string>
<string name="controls_question">Quel type de touches votre appareil a-t-il?</string>
<string name="controls_additional">Contrôles supplémentaires</string>
<string name="controls_screenkb">Clavier à l\'écran</string>
<string name="controls_accelnav">Accéléromètre</string>
<string name="controls_screenkb_size">Taille du clavier à l\'écran</string>
<string name="controls_screenkb_drawsize">Taille des images des boutons</string>
<string name="controls_screenkb_large">Grande</string>
<string name="controls_screenkb_medium">Moyenne</string>
<string name="controls_screenkb_small">Petite</string>
<string name="controls_screenkb_tiny">Minuscule</string>
<string name="controls_screenkb_theme">Thème du clavier à l\'écran</string>
<string name="controls_screenkb_by">%1$s par %2$s</string>
<string name="controls_screenkb_transparency">Transparence du clavier</string>
<string name="controls_screenkb_trans_0">Invisible</string>
<string name="controls_screenkb_trans_1">Presque invisible</string>
<string name="controls_screenkb_trans_2">Transparent</string>
<string name="controls_screenkb_trans_3">Semi-transparent</string>
<string name="controls_screenkb_trans_4">Non-transparent</string>
<string name="trackball_no_dampening">Sans limite</string>
<string name="trackball_fast">Rapide</string>
<string name="trackball_medium">Moyenne</string>
<string name="trackball_slow">Lente</string>
<string name="trackball_question">Limitation du trackball</string>
<string name="accel_veryfast">Très rapide</string>
<string name="accel_fast">Rapide</string>
<string name="accel_medium">Moyenne</string>
<string name="accel_slow">Lente</string>
<string name="accel_veryslow">Très lente</string>
<string name="accel_question">Sensibilité de l\'accéléromètre</string>
<string name="accel_floating">Flottante</string>
<string name="accel_fixed_start">Déterminée au démarrage de l\'application</string>
<string name="accel_fixed_horiz">Orientaton de la table</string>
<string name="accel_question_center">Position du centre de l\'accéléromètre</string>
<string name="mouse_emulation">Emulation de la souris</string>
<string name="rightclick_question">Clic droit de la souris</string>
<string name="rightclick_menu">Touche Menu</string>
<string name="rightclick_key">Touche Physique</string>
<string name="rightclick_multitouch">Ecran tactile avec le deuxième doigt</string>
<string name="rightclick_pressure">Ecran tactile avec force</string>
<string name="rightclick_none">Désactiver le clic droit de la souris</string>
<string name="leftclick_question">Clic gauche de la souris</string>
<string name="leftclick_normal">Normal</string>
<string name="leftclick_near_cursor">Curseur de la souris près Touch</string>
<string name="leftclick_multitouch">Ecran tactile avec le deuxième doigt</string>
<string name="leftclick_pressure">Ecran tactile avec force</string>
<string name="leftclick_dpadcenter">Trackball clic / Joystick au centre</string>
<string name="leftclick_timeout">Tenir au même endroit</string>
<string name="leftclick_tap">Appuyez sur</string>
<string name="leftclick_tap_or_timeout">Appuyez sur, ou maintenez</string>
<string name="leftclick_timeout_time">timeout Holding</string>
<string name="leftclick_timeout_time_0">0,3 s</string>
<string name="leftclick_timeout_time_1">0,5 sec</string>
<string name="leftclick_timeout_time_2">0,7 sec</string>
<string name="leftclick_timeout_time_3">1 sec</string>
<string name="leftclick_timeout_time_4">1,5 sec</string>
<string name="click_with_dpadcenter">Cliquez gauche de la souris avec le Trackball / centre du joystick </string>
<string name="advanced">Fonctionnalités avancées</string>
<string name="mouse_keepaspectratio">Gardez le format 4:3 écran</string>
<string name="mouse_showcreenunderfinger">Afficher l\'écran sous le doigt dans une fenêtre séparée</string>
<string name="mouse_showcreenunderfinger2">Loupe à l\'écran</string>
<string name="mouse_joystickmouse">Déplacez la souris avec un trackball ou le joystick</string>
<string name="mouse_joystickmousespeed">Déplacez la souris avec la vitesse du joystick</string>
<string name="mouse_joystickmouseaccel">Déplacez la souris avec l\'accélération du joystick</string>
<string name="mouse_relative">Mouvement relatif de la souris (mode portable)</string>
<string name="mouse_relative_speed">Vitesse relative de la souris</string>
<string name="mouse_relative_accel">Accélération relative de la souris</string>
<string name="none">Aucun</string>
<string name="measurepressure">Calibrer la pression de l\'écran tactile</string>
<string name="measurepressure_touchplease">Glisser les doigts sur l\'écran pendant deux secondes</string>
<string name="measurepressure_response">Pression %1$03d rayon %2$03d</string>
<string name="audiobuf_verysmall">Très petite (appareils rapides, plus de réactivité)</string>
<string name="audiobuf_small">Petite (appareils rapides)</string>
<string name="audiobuf_medium">Moyenne</string>
<string name="audiobuf_large">Grande (appareils anciens, si le son est saccadé)</string>
<string name="audiobuf_question">Taille du tampon audio</string>
<string name="remap_hwkeys">Reconfigurer les touches physiques</string>
<string name="remap_hwkeys_press">Appuyez sur n\'importe quelle touche sauf HOME et POWER, vous pouvez utiliser les touches de volume</string>
<string name="remap_hwkeys_select">Sélectionnez le keycode SDL</string>
<string name="remap_screenkb">Reconfigurer les contrôles via l\'écran</string>
<string name="remap_screenkb_joystick">Joystick à l\'écran</string>
<string name="remap_screenkb_button">Bouton à l\'écran</string>
<string name="remap_screenkb_button_text">Saisie de texte à l\'écran</string>
<string name="remap_screenkb_button_gestures">Gestes avec deux doigts</string>
<string name="remap_screenkb_button_gestures_sensitivity">Sensibilité des gestes</string>
<string name="remap_screenkb_button_zoomin">Geste de +Zoom avec deux doigts</string>
<string name="remap_screenkb_button_zoomout">Geste de -Zoom avec deux doigts</string>
<string name="remap_screenkb_button_rotateleft">Geste de rotation à gauche avec deux doigts</string>
<string name="remap_screenkb_button_rotateright">Geste de rotation à droite avec deux doigts</string>
<string name="screenkb_custom_layout">Personnalisation de la présentation du clavier à l\'écran</string>
<string name="calibrate_touchscreen">Calibrer l\'écran tactile</string>
<string name="calibrate_touchscreen_touch">Touchez les bords de l\'écran, appuyez sur Retour/BACK lorsque vous avez terminé</string>
<string name="video">Paramètres vidéo</string>
<string name="video_smooth">Fluidité de la vidéo</string>
<string name="video_separatethread">Thread séparé pour la vidéo : permet paroifs d\'augmenter FPS</string>
<string name="text_edit_click_here">Appuyez pour commencer à taper, appuyez sur Retour/BACK lorsque vous avez terminé</string>
<string name="display_size_mouse">Mode d\'émulation de la souris</string>
<string name="display_size">Sélectionnez votre taille d\'affichage</string>
<string name="display_size_large">Large (tablet)</string>
<string name="display_size_small">Petit (téléphone)</string>
<string name="display_size_small_touchpad">Petit, mode touchpad</string>
<string name="display_size_tiny">Très petit</string>
<string name="display_size_tiny_touchpad">Très petit, mode touchpad</string>
<string name="show_more_options">Afficher plus d\'options</string>
<string name="hardware_mouse_detected">Hardware mouse detected, disabling mouse emulation</string>
<string name="not_enough_ram">Not enough RAM</string>
<string name="not_enough_ram_size">This app needs %1$d Mb RAM, your device has %2$d Mb</string>
<string name="ignore">Ignore</string>
<string name="calibrate_gyroscope">Calibrate gyroscope</string>
<string name="calibrate_gyroscope_text">Put your phone on a flat surface</string>
<string name="reset_config">Reset config to defaults</string>
<string name="cancel">Cancel</string>
<string name="calibrate_gyroscope_not_supported">Your device does not have gyroscope</string>
<string name="reset_config_ask">Reset all options to default values?</string>
<string name="cancel_download">Cancel data downloading?</string>
<string name="cancel_download_resume">You can resume it later, the data will not be downloaded twice.</string>
<string name="yes">Yes</string>
<string name="no">No</string>
<string name="screenkb_custom_layout_help">Press BACK when done. Resize buttons by sliding on empty space.</string>
<string name="controls_screenkb_custom">Custom</string>
<string name="mouse_hover_jitter_filter">Filter jitter for stylus/finger hover</string>
<string name="remap_hwkeys_select_simple">Select action</string>
<string name="remap_hwkeys_select_more_keys">Show all keycodes</string>
<string name="mouse_gyroscope_mouse">Control mouse with gyroscope</string>
<string name="mouse_gyroscope_mouse_sensitivity">Gyroscope sensitivity</string>
<string name="mouse_finger_hover">Finger hover</string>
<string name="mouse_subframe_touch_events">Multiple touch events per video frame</string>
<string name="screenkb_floating_joystick">Floating joystick</string>
<string name="video_orientation_vertical">Portrait/vertical screen orientation</string>
<string name="video_bpp_24">24 bpp screen color depth</string>
<string name="video_immersive">Hide system navigation buttons / immersive mode</string>
<string name="gamehelper_sign_in_failed">Failed to sign in. Please check your network connection and try again.</string>
<string name="gamehelper_app_misconfigured">The application is incorrectly configured. Check that the package name and signing certificate match the client ID created in Developer Console. Also, if the application is not yet published, check that the account you are trying to sign in with is listed as a tester account. See logs for more information.</string>
<string name="gamehelper_license_failed">License check failed.</string>
<string name="gamehelper_unknown_error">Unknown error.</string>
<string name="accessing_network">Accessing network, please wait</string>
</resources>

View File

@@ -0,0 +1,166 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="init">Инициализация</string>
<string name="please_wait">Пожалуйста, подождите, пока данные загружаются</string>
<string name="device_config">Конфигурация устройства</string>
<string name="device_change_cfg">Изменение конфигурации устройства</string>
<string name="download_unneeded">Нет необходимости скачивать</string>
<string name="connecting_to">Подключение к %s</string>
<string name="failed_connecting_to">Ошибка подключения к %s</string>
<string name="error_connecting_to">Ошибка подключения к %s</string>
<string name="dl_from">Загрузка данных с %s</string>
<string name="error_dl_from">Ошибка при загрузке данных с %s</string>
<string name="error_write">Ошибка записи в %s</string>
<string name="dl_progress">%1$.0f%% готово: файл %2$s</string>
<string name="dl_finished">Завершенный</string>
<string name="storage_phone">Внутреннее хранение - %d Мб</string>
<string name="storage_sd">SD карта - %d Мб</string>
<string name="storage_question">Куда сохранять данные приложения</string>
<string name="storage_access">Разрешение на запись на SD карту</string>
<string name="optional_downloads">Дополнительные загрузки</string>
<string name="ok">Продолжить</string>
<string name="controls_arrows">Стрелки / джойстик / Dpad</string>
<string name="controls_trackball">Трекбол</string>
<string name="controls_accel">Акселерометр</string>
<string name="controls_touch">Только сенсорный экран</string>
<string name="controls_question">Какие на телефоне кнопки навигации?</string>
<string name="controls_additional">Дополнительные элементы управления</string>
<string name="controls_screenkb">Экранная клавиатура</string>
<string name="controls_accelnav">Акселерометр</string>
<string name="controls_screenkb_size">Размер экранной клавиатуры</string>
<string name="controls_screenkb_large">Большой</string>
<string name="controls_screenkb_medium">Средний</string>
<string name="controls_screenkb_small">Маленький</string>
<string name="controls_screenkb_tiny">Крошечный</string>
<string name="controls_screenkb_theme">Тема клавиатуры</string>
<string name="controls_screenkb_by">%1$s от %2$s</string>
<string name="trackball_no_dampening">Нет</string>
<string name="trackball_fast">Быстрое</string>
<string name="trackball_medium">Среднее</string>
<string name="trackball_slow">Медленное</string>
<string name="trackball_question">Замедление трекбола</string>
<string name="accel_fast">Быстрая</string>
<string name="accel_medium">Средний</string>
<string name="accel_slow">Медленно</string>
<string name="accel_question">Чувствительность акселерометра</string>
<string name="rightclick_question">Правая кнопка мыши</string>
<string name="rightclick_menu">Кнопка меню</string>
<string name="rightclick_multitouch">Касание экрана вторым пальцем</string>
<string name="rightclick_pressure">Нажатие на экран с силой</string>
<string name="advanced">Расширенные функции</string>
<string name="mouse_keepaspectratio">Сохранять соотношение сторон 4:3 на экране</string>
<string name="mouse_showcreenunderfinger">Экранная лупа</string>
<string name="measurepressure_touchplease">Пожалуйста, проведите пальцем по экрану в течение двух секунд</string>
<string name="measurepressure_response">Давление %1$03d радиус %2$03d </string>
<string name="audiobuf_verysmall">Очень мало (быстрые устройства)</string>
<string name="audiobuf_small">Малый</string>
<string name="audiobuf_medium">Средний</string>
<string name="audiobuf_large">Большой (для старых устройств, если звук прерывается)</string>
<string name="audiobuf_question">Размер буфера аудио</string>
<string name="accel_floating">Плавающее</string>
<string name="accel_fixed_start">Фиксировано при запуске приложения</string>
<string name="accel_fixed_horiz">Фиксировано на горизонт</string>
<string name="accel_question_center">Центральное положение акселерометра</string>
<string name="rightclick_none">Правая кнопка мыши отключена</string>
<string name="leftclick_question">Левая кнопка мыши</string>
<string name="leftclick_normal">Нормальный</string>
<string name="leftclick_near_cursor">Касание возле курсора мыши</string>
<string name="leftclick_multitouch">Касание двумя пальцами</string>
<string name="leftclick_pressure">Нажатие с силой</string>
<string name="leftclick_dpadcenter">Нажатие на трекбол / центр джойстика</string>
<string name="mouse_joystickmouse">Перемещение мыши при помощи джойстика или трекбола</string>
<string name="click_with_dpadcenter">Левый клик мыши при помощи трекбола / центра джойстика</string>
<string name="mouse_joystickmousespeed">Перемещение мыши джойстиком - скорость</string>
<string name="mouse_joystickmouseaccel">Перемещение мыши джойстиком - ускорение</string>
<string name="none">Нет</string>
<string name="controls_screenkb_transparency">Прозрачность клавиатуры</string>
<string name="controls_screenkb_trans_0">Невидимый</string>
<string name="controls_screenkb_trans_1">Почти невидимый</string>
<string name="controls_screenkb_trans_2">Прозрачный</string>
<string name="controls_screenkb_trans_3">Полупрозрачные</string>
<string name="controls_screenkb_trans_4">Непрозрачные</string>
<string name="mouse_emulation">Эмуляции мыши</string>
<string name="measurepressure">Калибровка сенсорного давления</string>
<string name="remap_hwkeys">Переназначение физических кнопок</string>
<string name="remap_hwkeys_press">Нажмите любую клавишу, кроме HOME и POWER, вы можете использовать кнопки регулировки громкости</string>
<string name="remap_hwkeys_select">Выберите код кнопки SDL</string>
<string name="remap_screenkb">Переназначение экранных кнопок</string>
<string name="remap_screenkb_joystick">Экранный джойстик</string>
<string name="remap_screenkb_button">Экранные кнопки</string>
<string name="remap_screenkb_button_text">Экранная кнопка ввода текста</string>
<string name="remap_screenkb_button_zoomin">Увеличить двумя пальцами</string>
<string name="remap_screenkb_button_zoomout">Уменьшить двумя пальцами</string>
<string name="remap_screenkb_button_rotateleft">Повернуть налево двумя пальцами</string>
<string name="remap_screenkb_button_rotateright">Повернуть вправо двумя пальцами</string>
<string name="remap_screenkb_button_gestures">Жест двумя пальцами по экрану</string>
<string name="accel_veryfast">Очень быстро</string>
<string name="remap_screenkb_button_gestures_sensitivity">Чувствительность жеста двумя пальцами по экрану</string>
<string name="storage_custom">Укажите каталог</string>
<string name="storage_commandline">Параметры командной строки, каждый аргумент на отдельной строке</string>
<string name="calibrate_touchscreen">Калибровка сенсорного экрана</string>
<string name="calibrate_touchscreen_touch">Дотроньтесь до всех краев экрана, потом нажмите Назад/BACK</string>
<string name="screenkb_custom_layout">Настройка расположения кнопок</string>
<string name="screenkb_custom_layout_help">Нажмите кнопку Назад/BACK для завершения. Проведите по пустому месту, чтобы изменить размер кнопки</string>
<string name="rightclick_key">Физическая кнопка</string>
<string name="mouse_showcreenunderfinger2">Наэкранная лупа</string>
<string name="video">Настройки видео</string>
<string name="video_smooth">Линейное сглаживание видео</string>
<string name="accel_veryslow">Очень медленно</string>
<string name="leftclick_timeout">Нажатие с задержкой</string>
<string name="leftclick_tap">Быстрое нажатие</string>
<string name="leftclick_tap_or_timeout">Быстрое нажатие либо с задержкой</string>
<string name="leftclick_timeout_time">Время нажатия</string>
<string name="leftclick_timeout_time_0">0,3 сек</string>
<string name="leftclick_timeout_time_1">0,5 сек</string>
<string name="leftclick_timeout_time_2">0,7 сек</string>
<string name="leftclick_timeout_time_3">1 сек</string>
<string name="leftclick_timeout_time_4">1,5 сек</string>
<string name="mouse_relative">Относительное движение мыши (режим ноутбука)</string>
<string name="mouse_relative_speed">Скорость движения мыши</string>
<string name="mouse_relative_accel">Ускорение движения мыши</string>
<string name="downloads">Загрузки</string>
<string name="video_separatethread">Отдельный поток для видео, увеличит FPS на некоторых устройствах</string>
<string name="text_edit_click_here">Нажмите, чтобы ввести текст, нажмите Назад, когда закончите</string>
<string name="display_size_mouse">Настройка размера дисплея</string>
<string name="display_size">Размер дисплея</string>
<string name="display_size_large">Большой (таблетка)</string>
<string name="display_size_small">Маленький (телефон)</string>
<string name="display_size_tiny">Крохотный</string>
<string name="show_more_options">Показать больше параметров</string>
<string name="controls_screenkb_drawsize">Размер изображения кнопок</string>
<string name="display_size_small_touchpad">Маленький, режим тачпада</string>
<string name="display_size_tiny_touchpad">Крохотный, режим тачпада</string>
<string name="hardware_mouse_detected">Обнаружена внешняя мышь, эмуляция мыши выключена</string>
<string name="not_enough_ram">Недостаточно оперативной памяти</string>
<string name="not_enough_ram_size">Для запуска приложения нужно %1$d Мб оперативной памяти, на этом устройстве есть %2$d Мб</string>
<string name="ignore">Игнорировать</string>
<string name="calibrate_gyroscope">Калибровать гироскоп</string>
<string name="calibrate_gyroscope_text">Положите устройство на ровную поверхность</string>
<string name="reset_config">Сбросить все настройки</string>
<string name="cancel">Отменить</string>
<string name="calibrate_gyroscope_not_supported">Гироскоп отсутствует</string>
<string name="reset_config_ask">Сбросить все настройки в значения по умолчанию?</string>
<string name="cancel_download">Остановить загрузку?</string>
<string name="cancel_download_resume">Загрузка может быть продолжена позднее.</string>
<string name="yes">Да</string>
<string name="no">Нет</string>
<string name="controls_screenkb_custom">Пользовательские настройки</string>
<string name="mouse_hover_jitter_filter">Фильтровать дрожание при поднесении стилуса/пальца к экрану</string>
<string name="remap_hwkeys_select_simple">Выберите действие</string>
<string name="remap_hwkeys_select_more_keys">Показать все коды кнопок</string>
<string name="mouse_gyroscope_mouse">Control mouse with gyroscope</string>
<string name="mouse_gyroscope_mouse_sensitivity">Gyroscope sensitivity</string>
<string name="mouse_finger_hover">Finger hover</string>
<string name="mouse_subframe_touch_events">Multiple touch events per video frame</string>
<string name="screenkb_floating_joystick">Floating joystick</string>
<string name="video_orientation_vertical">Portrait/vertical screen orientation</string>
<string name="video_bpp_24">24 bpp screen color depth</string>
<string name="video_immersive">Hide system navigation buttons / immersive mode</string>
<string name="gamehelper_sign_in_failed">Failed to sign in. Please check your network connection and try again.</string>
<string name="gamehelper_app_misconfigured">The application is incorrectly configured. Check that the package name and signing certificate match the client ID created in Developer Console. Also, if the application is not yet published, check that the account you are trying to sign in with is listed as a tester account. See logs for more information.</string>
<string name="gamehelper_license_failed">License check failed.</string>
<string name="gamehelper_unknown_error">Unknown error.</string>
<string name="accessing_network">Accessing network, please wait</string>
</resources>

View File

@@ -0,0 +1,165 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="init">Ініціалізація</string>
<string name="please_wait">Будь-ласка, зачекайте, поки завантажуться дані</string>
<string name="device_config">Конфігурація пристрою</string>
<string name="device_change_cfg">Зміна конфігурації пристрою</string>
<string name="download_unneeded">Немає необхідності викачувати</string>
<string name="connecting_to">Підключенння до %s</string>
<string name="failed_connecting_to">Помилка підключення до %s</string>
<string name="error_connecting_to">помилка підключення до %s</string>
<string name="dl_from">Завантаження даних з %s</string>
<string name="error_dl_from">Помилка при завантаженні даних з %s</string>
<string name="error_write">Помилка запису в %s</string>
<string name="dl_progress">%1$.0f%% готово: файл %2$s</string>
<string name="dl_finished">Завершений</string>
<string name="storage_phone">Внутрішнє зберігання - %d Мб</string>
<string name="storage_sd">SD карта - %d Мб</string>
<string name="storage_question">Куди зберігати дані програми</string>
<string name="storage_access">Дозвіл на запис на SD карту</string>
<string name="optional_downloads">Додаткові завантаження</string>
<string name="ok">ОК</string>
<string name="controls_arrows">Стрілки / джойстік / Dpad</string>
<string name="controls_trackball">Трекбол</string>
<string name="controls_accel">Акселерометр</string>
<string name="controls_touch">Тільки сенсорний екран</string>
<string name="controls_question">Які на телефоні кнопки навігації?</string>
<string name="controls_additional">Додаткові элементи керування</string>
<string name="controls_screenkb">Наекранні кнопки</string>
<string name="controls_accelnav">Акселерометр</string>
<string name="controls_screenkb_size">Розмір наекранних кнопок</string>
<string name="controls_screenkb_large">Великий</string>
<string name="controls_screenkb_medium">Середній</string>
<string name="controls_screenkb_small">Малий</string>
<string name="controls_screenkb_tiny">Дрібний</string>
<string name="controls_screenkb_theme">Тема кнопок</string>
<string name="controls_screenkb_by">%1$s від %2$s</string>
<string name="trackball_no_dampening">Немає</string>
<string name="trackball_fast">Швидке</string>
<string name="trackball_medium">Середнє</string>
<string name="trackball_slow">Повільне</string>
<string name="trackball_question">Сповільнення трекболу</string>
<string name="accel_fast">Швидко</string>
<string name="accel_medium">середньо</string>
<string name="accel_slow">повільно</string>
<string name="accel_question">Чутливість акселерометру</string>
<string name="rightclick_question">Права кнопка миші</string>
<string name="rightclick_menu">Кнопка меню</string>
<string name="rightclick_multitouch">Торкання екрана другим пальцем</string>
<string name="rightclick_pressure">Натиск на екран силою</string>
<string name="advanced">Розширені функції</string>
<string name="mouse_keepaspectratio">Зберігати співвідношення сторін 4:3 на екрані</string>
<string name="mouse_showcreenunderfinger">Наекранна лупа</string>
<string name="measurepressure_touchplease">Будь-ласка, проведіть пальцем по екрану на протязі двох секунд</string>
<string name="measurepressure_response">Тиск %1$03d радіус %2$03d </string>
<string name="audiobuf_verysmall">Дуже мало (швидкі пристрої)</string>
<string name="audiobuf_small">Малий</string>
<string name="audiobuf_medium">Середній</string>
<string name="audiobuf_large">Великий (для старих пристроїв, якщо звук переривається)</string>
<string name="audiobuf_question">Розмір буферу аудіо</string>
<string name="accel_floating">Плаваюче</string>
<string name="accel_fixed_start">Фiксоване під час запуску програми</string>
<string name="accel_fixed_horiz">Фiксоване до горизонту</string>
<string name="accel_question_center">Центральне положення акселерометра</string>
<string name="rightclick_none">Вiдключена</string>
<string name="leftclick_question">Ліва кнопка миші</string>
<string name="leftclick_normal">Нормальна</string>
<string name="leftclick_near_cursor">Дотик біля курсору миші</string>
<string name="leftclick_multitouch">Натиск на екран другим пальцем</string>
<string name="leftclick_pressure">>Натиск на екран з силою</string>
<string name="leftclick_dpadcenter">Натиск на трекбол / центр джойстику</string>
<string name="mouse_joystickmouse">Переміщення миші за допомогою джойстика або трекбола</string>
<string name="click_with_dpadcenter">Лівий клік миші за допомогою трекбола / центра джойстика</string>
<string name="mouse_joystickmousespeed">Переміщення миші джойстиком - швидкiсть</string>
<string name="mouse_joystickmouseaccel">Переміщення миші джойстиком - прискорення</string>
<string name="none">Немає</string>
<string name="controls_screenkb_transparency">Прозорість клавіатури</string>
<string name="controls_screenkb_trans_0">Невидимий</string>
<string name="controls_screenkb_trans_1">Майже невидимий</string>
<string name="controls_screenkb_trans_2">Прозорий</string>
<string name="controls_screenkb_trans_3">Напівпрозорі</string>
<string name="controls_screenkb_trans_4">Непрозорі</string>
<string name="mouse_emulation">Емуляція миші</string>
<string name="measurepressure">Калібрування сенсорного натискання</string>
<string name="remap_hwkeys">Перепризначення фізичних кнопок</string>
<string name="remap_hwkeys_press">Натисніть будь-яку клавішу, крім HOME і POWER, ви можете використовувати клавіші регулювання гучності</string>
<string name="remap_hwkeys_select">Виберіть код кнопки SDL</string>
<string name="remap_screenkb">Перепризначення наекранних кнопок</string>
<string name="remap_screenkb_joystick">Наекранний джойстік</string>
<string name="remap_screenkb_button">Наекранні кнопки</string>
<string name="remap_screenkb_button_text">Наекранна кнопка вводу тексту</string>
<string name="remap_screenkb_button_zoomin">Збільшити двома пальцями</string>
<string name="remap_screenkb_button_zoomout">Зменшити двома пальцями</string>
<string name="remap_screenkb_button_rotateleft">Повернути наліво двома пальцями</string>
<string name="remap_screenkb_button_rotateright">Повернути праворуч двома пальцями</string>
<string name="remap_screenkb_button_gestures">Жест двома пальцями по екрану</string>
<string name="accel_veryfast">Дуже швидко</string>
<string name="remap_screenkb_button_gestures_sensitivity">Чутливість жесту двома пальцями по екрану</string>
<string name="storage_custom">Вкажіть каталог</string>
<string name="storage_commandline">Вкажіть параметри командного рядка, кожен аргумент на окремому рядку</string>
<string name="calibrate_touchscreen">Калібрування сенсорного екрану</string>
<string name="calibrate_touchscreen_touch">Доторкнiться до всіх країв екрану, потiм натисніть Назад/BACK</string>
<string name="screenkb_custom_layout">Налаштування положення кнопок</string>
<string name="screenkb_custom_layout_help">Натисніть Назад/BACK для завершення. Проведiть по екрану, щоб змінити розмір кнопки</string>
<string name="rightclick_key">Фізична кнопка</string>
<string name="mouse_showcreenunderfinger2">Наекранна лупа</string>
<string name="video">Налаштування відео</string>
<string name="video_smooth">Лінійне сглажування відео</string>
<string name="accel_veryslow">Дуже повільно</string>
<string name="leftclick_timeout">Натискання з затримкою</string>
<string name="leftclick_tap">Швидке натискання</string>
<string name="leftclick_tap_or_timeout">Швидке натискання або з затримкою</string>
<string name="leftclick_timeout_time">Час натискання</string>
<string name="leftclick_timeout_time_0">0,3 сек</string>
<string name="leftclick_timeout_time_1">0,5 сек</string>
<string name="leftclick_timeout_time_2">0,7 секунд</string>
<string name="leftclick_timeout_time_3">1 сек</string>
<string name="leftclick_timeout_time_4">1,5 сек</string>
<string name="mouse_relative">Відносний рух миші (режим ноутбука)</string>
<string name="mouse_relative_speed">Швидкість руху миші</string>
<string name="mouse_relative_accel">Прискорення руху миші</string>
<string name="downloads">Завантаження</string>
<string name="video_separatethread">Окремий потік для відео, збільшить FPS на деяких пристроях</string>
<string name="text_edit_click_here">Натисніть, щоб ввести текст, натисніть Назад, коли закiнчете</string>
<string name="display_size_mouse">Налаштування розміру дисплея</string>
<string name="display_size">Виберіть розмір дисплея</string>
<string name="display_size_large">Великий (таблетка)</string>
<string name="display_size_small">Маленький</string>
<string name="display_size_tiny">Крихiтний</string>
<string name="show_more_options">Показати більше параметрів</string>
<string name="controls_screenkb_drawsize">Розмір зображення кнопок</string>
<string name="display_size_small_touchpad">Маленький, режим тачпаду</string>
<string name="display_size_tiny_touchpad">Крихiтний, режим тачпаду</string>
<string name="hardware_mouse_detected">Виявлена зовнiшня миша, емуляція миші вимкнена</string>
<string name="not_enough_ram">Недостатньо пам’яті</string>
<string name="not_enough_ram_size">Потрібно %1$d Mb пам’яті, доступно лише %2$d Mb</string>
<string name="ignore">Ігнорувати</string>
<string name="calibrate_gyroscope">Калібрувати гіроскоп</string>
<string name="calibrate_gyroscope_text">Покладіть телефон на рівну поверхню</string>
<string name="reset_config">Скинути всі налаштування</string>
<string name="cancel">Відмінити</string>
<string name="calibrate_gyroscope_not_supported">Гіроскоп відсутній</string>
<string name="reset_config_ask">Скинути всі налаштування у значення за замовчуванням?</string>
<string name="cancel_download">Припинити завантаження?</string>
<string name="cancel_download_resume">Завантаження може бути відновлено пізніше.</string>
<string name="yes">Так</string>
<string name="no">Ні</string>
<string name="controls_screenkb_custom">Налаштування користувача</string>
<string name="mouse_hover_jitter_filter">Фільтрувати тремтіння при піднесенні стилуса/пальця до екрану</string>
<string name="remap_hwkeys_select_simple">Виберіть дію</string>
<string name="remap_hwkeys_select_more_keys">Показати всі коди кнопок</string>
<string name="mouse_gyroscope_mouse">Control mouse with gyroscope</string>
<string name="mouse_gyroscope_mouse_sensitivity">Gyroscope sensitivity</string>
<string name="mouse_finger_hover">Finger hover</string>
<string name="mouse_subframe_touch_events">Multiple touch events per video frame</string>
<string name="screenkb_floating_joystick">Floating joystick</string>
<string name="video_orientation_vertical">Portrait/vertical screen orientation</string>
<string name="video_bpp_24">24 bpp screen color depth</string>
<string name="video_immersive">Hide system navigation buttons / immersive mode</string>
<string name="gamehelper_sign_in_failed">Failed to sign in. Please check your network connection and try again.</string>
<string name="gamehelper_app_misconfigured">The application is incorrectly configured. Check that the package name and signing certificate match the client ID created in Developer Console. Also, if the application is not yet published, check that the account you are trying to sign in with is listed as a tester account. See logs for more information.</string>
<string name="gamehelper_license_failed">License check failed.</string>
<string name="gamehelper_unknown_error">Unknown error.</string>
<string name="accessing_network">Accessing network, please wait</string>
</resources>

View File

@@ -0,0 +1,205 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Commander Genius</string>
<string name="init">初始化中</string>
<string name="please_wait">正在下载数据,请稍候</string>
<string name="device_config">设备配置</string>
<string name="device_change_cfg">更改设备配置</string>
<string name="download_unneeded">没有需要下载的内容</string>
<string name="connecting_to">正在连接到 %s</string>
<string name="failed_connecting_to">连接到 %s 失败</string>
<string name="error_connecting_to"> %s 连接出错</string>
<string name="dl_from">正在从 %s 下载数据</string>
<string name="error_dl_from">从 %s 下载数据时出错</string>
<string name="error_write">写入到 %s 时出错</string>
<string name="dl_progress">%1$.0f%% 已完成: 文件 %2$s</string>
<string name="dl_finished">已完成</string>
<string name="storage_phone">内部储存 - %d MB 空闲</string>
<string name="storage_sd">SD卡储存 - %d MB 空闲</string>
<string name="storage_custom">自定义目录</string>
<string name="storage_commandline">命令行参数,每行一个参数</string>
<string name="storage_question">数据文件安装位置</string>
<string name="optional_downloads">下载</string>
<string name="downloads">下载</string>
<string name="ok">完成</string>
<string name="cancel">取消</string>
<string name="controls_arrows">箭头 / 操纵杆 / 方向键</string>
<string name="controls_trackball">轨迹球</string>
<string name="controls_accel">加速度计</string>
<string name="controls_touch">只使用触屏</string>
<string name="controls_question">您的设备有哪些导航键?</string>
<string name="controls_additional">附加控制</string>
<string name="controls_screenkb">屏幕键盘</string>
<string name="controls_accelnav">加速度计</string>
<string name="controls_screenkb_size">屏幕键盘大小</string>
<string name="controls_screenkb_drawsize">按钮大小</string>
<string name="controls_screenkb_large"></string>
<string name="controls_screenkb_medium"></string>
<string name="controls_screenkb_small"></string>
<string name="controls_screenkb_tiny">微小</string>
<string name="controls_screenkb_custom">自定义</string>
<string name="controls_screenkb_theme">屏幕键盘主题</string>
<string name="controls_screenkb_by">%1$s by %2$s</string>
<string name="controls_screenkb_transparency">屏幕键盘透明度</string>
<string name="controls_screenkb_trans_0">隐形</string>
<string name="controls_screenkb_trans_1">半隐形</string>
<string name="controls_screenkb_trans_2">透明</string>
<string name="controls_screenkb_trans_3">半透明</string>
<string name="controls_screenkb_trans_4">不透明</string>
<string name="trackball_no_dampening">无阻碍</string>
<string name="trackball_fast"></string>
<string name="trackball_medium"></string>
<string name="trackball_slow"></string>
<string name="trackball_question">轨迹球阻碍</string>
<string name="accel_veryfast">非常快</string>
<string name="accel_fast"></string>
<string name="accel_medium"></string>
<string name="accel_slow"></string>
<string name="accel_veryslow">非常慢</string>
<string name="accel_question">加速度计灵敏度</string>
<string name="accel_floating">Floating</string>
<string name="accel_fixed_start">在应用程序启动时修复</string>
<string name="accel_fixed_horiz">Fixed to table desk orientation</string>
<string name="accel_question_center">加速度计中心位置</string>
<string name="mouse_emulation">鼠标模拟</string>
<string name="rightclick_question">单击鼠标右键</string>
<string name="rightclick_menu">菜单键</string>
<string name="rightclick_key">物理按键</string>
<string name="rightclick_multitouch">双指触摸</string>
<string name="rightclick_pressure">使用按压力度</string>
<string name="rightclick_none">禁用鼠标右键</string>
<string name="leftclick_question">鼠标左键单击</string>
<string name="leftclick_normal">正常</string>
<string name="leftclick_near_cursor">触摸靠近鼠标光标</string>
<string name="leftclick_multitouch">双指触摸</string>
<string name="leftclick_pressure">使用按压力度</string>
<string name="leftclick_dpadcenter">轨迹球点击 / 操纵杆中心</string>
<string name="leftclick_timeout">长按一个点</string>
<string name="leftclick_tap">点击</string>
<string name="leftclick_tap_or_timeout">点击或长按</string>
<string name="leftclick_timeout_time">长按超时</string>
<string name="leftclick_timeout_time_0">0.3 秒</string>
<string name="leftclick_timeout_time_1">0.5 秒</string>
<string name="leftclick_timeout_time_2">0.7 秒</string>
<string name="leftclick_timeout_time_3">1 秒</string>
<string name="leftclick_timeout_time_4">1.5 秒</string>
<string name="click_with_dpadcenter">左键点击和轨迹球点击 / 操纵杆中心</string>
<string name="advanced">高级功能</string>
<string name="mouse_keepaspectratio">保持4:3的屏幕宽高比</string>
<string name="mouse_showcreenunderfinger">在单独的窗口中显示屏幕</string>
<string name="mouse_showcreenunderfinger2">屏幕放大镜</string>
<string name="mouse_joystickmouse">使用操纵杆或轨迹球移动鼠标</string>
<string name="mouse_joystickmousespeed">使用操纵杆移动鼠标时的速度</string>
<string name="mouse_joystickmouseaccel">使用操纵杆加速移动鼠标</string>
<string name="mouse_relative">鼠标相对移动(笔记本模式)</string>
<string name="mouse_relative_speed">鼠标相对移动速度</string>
<string name="mouse_relative_accel">鼠标相对移动加速</string>
<string name="mouse_hover_jitter_filter">过滤指针/手指的抖动</string>
<string name="mouse_gyroscope_mouse">用陀螺仪控制鼠标移动</string>
<string name="mouse_gyroscope_mouse_sensitivity">陀螺仪灵敏度</string>
<string name="mouse_finger_hover">手指抖动</string>
<string name="mouse_subframe_touch_events">每一帧的多点触摸事件</string>
<string name="none"></string>
<string name="measurepressure">校准触摸屏压力</string>
<string name="measurepressure_touchplease">请将手指滑过屏幕两秒钟</string>
<string name="measurepressure_response">压力 %1$03d 半径 %2$03d</string>
<string name="audiobuf_verysmall">非常小(较新的设备,延迟低)</string>
<string name="audiobuf_small"></string>
<string name="audiobuf_medium">中等</string>
<string name="audiobuf_large">大(较老的设备,如果声音不稳定请选此项)</string>
<string name="audiobuf_question">音频缓冲大小</string>
<string name="remap_hwkeys">映射物理按键</string>
<string name="remap_hwkeys_press">按下任意按键 除了HOME键和POWER键如音量键</string>
<string name="remap_hwkeys_select">选择SDL按键</string>
<string name="remap_hwkeys_select_simple">选择动作</string>
<string name="remap_hwkeys_select_more_keys">显示所有按键</string>
<string name="remap_screenkb">映射屏幕控件</string>
<string name="remap_screenkb_joystick">手柄</string>
<string name="remap_screenkb_button">按钮</string>
<string name="remap_screenkb_button_text">文本输入按钮</string>
<string name="remap_screenkb_button_gestures">双指手势</string>
<string name="remap_screenkb_button_gestures_sensitivity">双指手势灵敏度</string>
<string name="remap_screenkb_button_zoomin">双指放大</string>
<string name="remap_screenkb_button_zoomout">双指缩小</string>
<string name="remap_screenkb_button_rotateleft">双指向左旋转</string>
<string name="remap_screenkb_button_rotateright">双指向右旋转</string>
<string name="screenkb_custom_layout">自定义屏幕键盘布局</string>
<string name="screenkb_custom_layout_help">按返回键结束,在空白区域滑动调整按钮大小</string>
<string name="screenkb_floating_joystick">浮动操纵杆</string>
<string name="calibrate_touchscreen">校准触摸屏</string>
<string name="calibrate_touchscreen_touch">触摸屏幕的所有边缘,按返回键结束</string>
<string name="video">视频选项</string>
<string name="video_smooth">线性过滤</string>
<string name="video_separatethread">用单线程处理视频可能会提高FPS也可能使程序崩溃</string>
<string name="video_orientation_vertical">切换横屏/竖屏</string>
<string name="video_orientation_autodetect">自动检测屏幕方向</string>
<string name="video_bpp_24">24 bpp颜色深度</string>
<string name="video_immersive">隐藏系统导航按钮/沉浸模式</string>
<string name="tv_borders">电视边框</string>
<string name="text_edit_click_here">点击开始输入,按返回键结束</string>
<string name="display_size_mouse">鼠标仿真模式</string>
<string name="display_size">显示仿真鼠标的大小</string>
<string name="display_size_desktop">桌面版,无仿真</string>
<string name="display_size_large">大(适用于平板电脑)</string>
<string name="display_size_small">小,放大镜</string>
<string name="display_size_small_touchpad">小,触摸模式</string>
<string name="display_size_tiny">很小</string>
<string name="display_size_tiny_touchpad">很小,触摸模式</string>
<string name="show_more_options">显示更多选项</string>
<string name="hardware_mouse_detected">检测到鼠标硬件,禁用鼠标仿真</string>
<string name="not_enough_ram">没有足够的 RAM</string>
<string name="not_enough_ram_size">本程序需要 %1$d Mb 的RAM您的设备有 %2$d Mb</string>
<string name="ignore">忽略</string>
<string name="calibrate_gyroscope">校准陀螺仪</string>
<string name="calibrate_gyroscope_text">将您的设备放在水平表面上</string>
<string name="calibrate_gyroscope_not_supported">您的设备没有陀螺仪</string>
<string name="reset_config">将所有配置重置为默认值</string>
<string name="reset_config_ask">是否将所有选项重置为默认值?</string>
<string name="cancel_download">是否取消数据下载?</string>
<string name="cancel_download_resume">您可以稍后恢复它,数据不会被下载两次。</string>
<string name="yes"></string>
<string name="no"></string>
<!-- Play Game Services strings -->
<string name="gamehelper_sign_in_failed">无法登录,请检查您的网络连接,然后重试。</string>
<string name="gamehelper_app_misconfigured">应用程序配置不正确。请检查包名和签名证书是否与开发者控制台中创建的客户端ID一致。此外如果应用程序尚未发布请检查您的帐户是否为测试人员帐户。详细信息请参阅日志。</string>
<string name="gamehelper_license_failed">许可证检查失败。</string>
<string name="gamehelper_unknown_error">未知错误。</string>
<string name="accessing_network">正在访问网络,请稍候</string>
<string name="restarting_please_wait">重新启动中,请稍候。</string>
<string name="notification_app_is_running">%s 正在运行中</string>
<string name="notification_stop">停止</string>
</resources>

View File

@@ -0,0 +1,210 @@
<?xml version="1.0" encoding="utf-8"?>
<resources
xmlns:tools="http://schemas.android.com/tools"
tools:ignore="MissingTranslation">
<string name="app_name">Commander Genius</string>
<string name="init">Initializing</string>
<string name="please_wait">Please wait while data is being downloaded</string>
<string name="device_config">Device configuration</string>
<string name="device_change_cfg">Change device configuration</string>
<string name="download_unneeded">No need to download</string>
<string name="connecting_to">Connecting to %s</string>
<string name="failed_connecting_to">Failed connecting to %s</string>
<string name="error_connecting_to">Error connecting to %s</string>
<string name="dl_from">Downloading data from %s</string>
<string name="error_dl_from">Error downloading data from %s</string>
<string name="error_write">Error writing to %s</string>
<string name="dl_progress">%1$.0f%% done: file %2$s</string>
<string name="dl_finished">Finished</string>
<string name="storage_phone">Internal storage - %d MB free</string>
<string name="storage_sd">SD card storage - %d MB free</string>
<string name="storage_custom">Specify directory</string>
<string name="storage_commandline">Command line parameters, one argument per line</string>
<string name="storage_question">Data installation location</string>
<string name="storage_access">Permission to write to SD card</string>
<string name="optional_downloads">Downloads</string>
<string name="downloads">Downloads</string>
<string name="ok">OK</string>
<string name="cancel">Cancel</string>
<string name="controls_arrows">Arrows / joystick / dpad</string>
<string name="controls_trackball">Trackball</string>
<string name="controls_accel">Accelerometer</string>
<string name="controls_touch">Touchscreen only</string>
<string name="controls_question">What kind of navigation keys does your device have?</string>
<string name="controls_additional">Additional controls</string>
<string name="controls_screenkb">On-screen keyboard</string>
<string name="controls_accelnav">Accelerometer</string>
<string name="controls_screenkb_size">On-screen keyboard size</string>
<string name="controls_screenkb_drawsize">Size of button images</string>
<string name="controls_screenkb_large">Large</string>
<string name="controls_screenkb_medium">Medium</string>
<string name="controls_screenkb_small">Small</string>
<string name="controls_screenkb_tiny">Tiny</string>
<string name="controls_screenkb_custom">Custom</string>
<string name="controls_screenkb_theme">On-screen keyboard theme</string>
<string name="controls_screenkb_by">%1$s by %2$s</string>
<string name="controls_screenkb_transparency">On-screen keyboard transparency</string>
<string name="controls_screenkb_trans_0">Invisible</string>
<string name="controls_screenkb_trans_1">Almost invisible</string>
<string name="controls_screenkb_trans_2">Transparent</string>
<string name="controls_screenkb_trans_3">Semi-transparent</string>
<string name="controls_screenkb_trans_4">Non-transparent</string>
<string name="trackball_no_dampening">No dampening</string>
<string name="trackball_fast">Fast</string>
<string name="trackball_medium">Medium</string>
<string name="trackball_slow">Slow</string>
<string name="trackball_question">Trackball dampening</string>
<string name="accel_veryfast">Very fast</string>
<string name="accel_fast">Fast</string>
<string name="accel_medium">Medium</string>
<string name="accel_slow">Slow</string>
<string name="accel_veryslow">Very slow</string>
<string name="accel_question">Accelerometer sensitivity</string>
<string name="accel_floating">Floating</string>
<string name="accel_fixed_start">Fixed when application starts</string>
<string name="accel_fixed_horiz">Fixed to table desk orientation</string>
<string name="accel_question_center">Accelerometer center position</string>
<string name="mouse_emulation">Mouse emulation</string>
<string name="rightclick_question">Right mouse click</string>
<string name="rightclick_menu">Menu key</string>
<string name="rightclick_key">Physical key</string>
<string name="rightclick_multitouch">Touch screen with second finger</string>
<string name="rightclick_pressure">Touch screen with force</string>
<string name="rightclick_none">Disable right mouse click</string>
<string name="leftclick_question">Left mouse click</string>
<string name="leftclick_normal">Normal</string>
<string name="leftclick_near_cursor">Touch near mouse cursor</string>
<string name="leftclick_multitouch">Touch screen with second finger</string>
<string name="leftclick_pressure">Touch screen with force</string>
<string name="leftclick_dpadcenter">Trackball click / joystick center</string>
<string name="leftclick_timeout">Hold at the same spot</string>
<string name="leftclick_tap">Tap</string>
<string name="leftclick_tap_or_timeout">Tap or hold</string>
<string name="leftclick_timeout_time">Holding timeout</string>
<string name="leftclick_timeout_time_0">0.3 sec</string>
<string name="leftclick_timeout_time_1">0.5 sec</string>
<string name="leftclick_timeout_time_2">0.7 sec</string>
<string name="leftclick_timeout_time_3">1 sec</string>
<string name="leftclick_timeout_time_4">1.5 sec</string>
<string name="click_with_dpadcenter">Left mouse click with trackball / joystick center</string>
<string name="advanced">Advanced features</string>
<string name="mouse_keepaspectratio">Keep 4:3 screen aspect ratio</string>
<string name="mouse_showcreenunderfinger">Show screen under finger in separate window</string>
<string name="mouse_showcreenunderfinger2">On-screen magnifying glass</string>
<string name="mouse_joystickmouse">Move mouse with joystick or trackball</string>
<string name="mouse_joystickmousespeed">Move mouse with joystick speed</string>
<string name="mouse_joystickmouseaccel">Move mouse with joystick acceleration</string>
<string name="mouse_relative">Relative mouse movement (laptop mode)</string>
<string name="mouse_relative_speed">Relative mouse movement speed</string>
<string name="mouse_relative_accel">Relative mouse movement acceleration</string>
<string name="mouse_hover_jitter_filter">Filter jitter for stylus/finger hover</string>
<string name="mouse_gyroscope_mouse">Control mouse with gyroscope</string>
<string name="mouse_gyroscope_mouse_sensitivity">Gyroscope sensitivity</string>
<string name="mouse_finger_hover">Finger hover</string>
<string name="mouse_subframe_touch_events">Multiple touch events per video frame</string>
<string name="none">None</string>
<string name="measurepressure">Calibrate touchscreen pressure</string>
<string name="measurepressure_touchplease">Please slide finger across the screen for two seconds</string>
<string name="measurepressure_response">Pressure %1$03d radius %2$03d</string>
<string name="audiobuf_verysmall">Very small (fast devices, less lag)</string>
<string name="audiobuf_small">Small</string>
<string name="audiobuf_medium">Medium</string>
<string name="audiobuf_large">Large (older devices, if sound is choppy)</string>
<string name="audiobuf_question">Size of audio buffer</string>
<string name="remap_hwkeys">Remap physical keys</string>
<string name="remap_hwkeys_press">Press any key except HOME and POWER, you may use volume keys</string>
<string name="remap_hwkeys_select">Select SDL keycode</string>
<string name="remap_hwkeys_select_simple">Select action</string>
<string name="remap_hwkeys_select_more_keys">Show all keycodes</string>
<string name="remap_screenkb">Remap on-screen controls</string>
<string name="remap_screenkb_joystick">Joystick</string>
<string name="remap_screenkb_button">Button</string>
<string name="remap_screenkb_button_text">Text input button</string>
<string name="remap_screenkb_button_gestures">Two-finger screen gestures</string>
<string name="remap_screenkb_button_gestures_sensitivity">Two-finger screen gestures sensitivity</string>
<string name="remap_screenkb_button_zoomin">Zoom in two-finger gesture</string>
<string name="remap_screenkb_button_zoomout">Zoom out two-finger gesture</string>
<string name="remap_screenkb_button_rotateleft">Rotate left two-finger gesture</string>
<string name="remap_screenkb_button_rotateright">Rotate right two-finger gesture</string>
<string name="screenkb_custom_layout">Customize on-screen keyboard layout</string>
<string name="screenkb_custom_layout_help">Press BACK when done. Resize buttons by sliding on empty space.</string>
<string name="screenkb_floating_joystick">Floating joystick</string>
<string name="calibrate_touchscreen">Calibrate touchscreen</string>
<string name="calibrate_touchscreen_touch">Touch all edges of the screen, press BACK when done</string>
<string name="video">Video settings</string>
<string name="video_smooth">Linear video filtering</string>
<string name="video_separatethread">Separate thread for video, it can increase FPS, it also can crash the app</string>
<string name="video_orientation_vertical">Portrait/vertical screen orientation</string>
<string name="video_orientation_autodetect">Auto-detect screen orientation</string>
<string name="video_bpp_24">24 bpp screen color depth</string>
<string name="video_immersive">Hide system navigation buttons / immersive mode</string>
<string name="tv_borders">TV borders</string>
<string name="text_edit_click_here">Tap to start typing, press Back when done</string>
<string name="display_size_mouse">Mouse emulation mode</string>
<string name="display_size">Display size for mouse emulation</string>
<string name="display_size_desktop">Desktop, no emulation</string>
<string name="display_size_large">Large (tablets)</string>
<string name="display_size_small">Small, magnifying glass</string>
<string name="display_size_small_touchpad">Small, touchpad mode</string>
<string name="display_size_tiny">Tiny</string>
<string name="display_size_tiny_touchpad">Tiny, touchpad mode</string>
<string name="show_more_options">Show more options</string>
<string name="hardware_mouse_detected">Hardware mouse detected, disabling mouse emulation</string>
<string name="not_enough_ram">Not enough RAM</string>
<string name="not_enough_ram_size">This app needs %1$d Mb RAM, your device has %2$d Mb</string>
<string name="ignore">Ignore</string>
<string name="calibrate_gyroscope">Calibrate gyroscope</string>
<string name="calibrate_gyroscope_text">Put your device on a flat surface</string>
<string name="calibrate_gyroscope_not_supported">Your device does not have gyroscope</string>
<string name="reset_config">Reset config to defaults</string>
<string name="reset_config_ask">Reset all options to default values?</string>
<string name="cancel_download">Cancel data downloading?</string>
<string name="cancel_download_resume">You can resume it later, the data will not be downloaded twice.</string>
<string name="yes">Yes</string>
<string name="no">No</string>
<!-- Play Game Services strings -->
<string name="gamehelper_sign_in_failed">Failed to sign in. Please check your network connection and try again.</string>
<string name="gamehelper_app_misconfigured">The application is incorrectly configured. Check that the package name and signing certificate match the client ID created in Developer Console. Also, if the application is not yet published, check that the account you are trying to sign in with is listed as a tester account. See logs for more information.</string>
<string name="gamehelper_license_failed">License check failed.</string>
<string name="gamehelper_unknown_error">Unknown error.</string>
<string name="accessing_network">Accessing network, please wait</string>
<string name="google_play_game_services_app_id" translatable="false">==GOOGLEPLAYGAMESERVICES_APP_ID==</string>
<string name="restarting_please_wait">Restarting, please wait.</string>
<string name="notification_app_is_running">%s is running</string>
<string name="notification_stop">Stop</string>
</resources>

View File

@@ -4,19 +4,27 @@ ifneq ($(strip $(filter mad, $(COMPILED_LIBRARIES))),)
SDL_MIXER_USE_LIBMAD := 1
endif
# Disable timidity library inside sdl2_mixer, we have our own version of timidity used by OpenTTD
SUPPORT_MID_TIMIDITY := 0
NDK_VERSION := $(strip $(patsubst android-ndk-%,%,$(filter android-ndk-%, $(subst /, ,$(dir $(TARGET_CC))))))
#$(info NDK version $(NDK_VERSION)) # This warning puzzles ndk-gdb
ifneq ($(filter r1 r2 r3 r4 r5 r6 r7 r8,$(NDK_VERSION)),)
$(error Your NDK $(NDK_VERSION) is too old, please download NDK from http://developer.android.com)
endif
ifdef ANDROID_NDK_HOME
NDK_PATH := $(ANDROID_NDK_HOME)
else
NDK_PATH := $(shell dirname $(shell which ndk-build))
NDK_SUBDIR_MAKEFILES_FULL := $(call all-subdir-makefiles)
# If you want to exclude certain subprojects from the build process.
# v.g.: SDL2_image already brings it's own implementation of png, so we exclude the bundled one
ifeq ($(SDL_VERSION),2.0)
BLACKLISTED_SUBPROJECTS := jpeg png ogg mpg123 timidity fluidsynth faad openal sdl_blitpool sdl_gfx sdl_image sdl_main sdl_mixer sdl_net sdl_sound sdl_ttf zzip freetype
else
BLACKLISTED_SUBPROJECTS := sdl2_image
endif
include $(call all-subdir-makefiles)
BLACKLISTED_MAKEFILES := $(addprefix jni/../jni/,$(BLACKLISTED_SUBPROJECTS))
BLACKLISTED_MAKEFILES := $(addsuffix /Android.mk,$(BLACKLISTED_MAKEFILES))
NDK_SUBDIR_MAKEFILES := $(filter-out $(BLACKLISTED_MAKEFILES), $(NDK_SUBDIR_MAKEFILES_FULL))
include $(NDK_SUBDIR_MAKEFILES)

View File

@@ -1,17 +1,44 @@
# Makefile to build precompiled libraries, which cannot be built using standard NDK makefiles
# TODO: libffmpeg, libpython (used only in GemRB)
# TODO: libboost, libffmpeg, libpython (used only in GemRB)
ARCH_LIST ?= arm64-v8a x86_64 armeabi-v7a x86
ifeq ($(strip $(ARCH_LIST)),all)
ARCH_LIST := arm64-v8a x86_64 armeabi-v7a x86
endif
ARCHES32 := armeabi-v7a x86
ARCHES64 := arm64-v8a x86_64
ICONV := $(foreach ARCH, $(ARCH_LIST), iconv/lib/$(ARCH)/libiconv.so iconv/lib/$(ARCH)/libcharset.so)
ICONV := $(foreach ARCH, $(ARCHES32) $(ARCHES64), iconv/lib/$(ARCH)/libiconv.so iconv/lib/$(ARCH)/libcharset.so)
ICU_LIBS := icudata icui18n icuio icutest icutu icuuc iculx icu-le-hb
ICU := $(foreach ARCH, $(ARCH_LIST), $(foreach NAME, $(ICU_LIBS), icuuc/lib/$(ARCH)/lib$(NAME).a))
ICU_LIBS := icudata icui18n icuio icutest icutu icuuc iculx icu-le-hb harfbuzz
ICU := $(foreach ARCH, $(ARCHES32) $(ARCHES64), $(foreach NAME, $(ICU_LIBS), icuuc/lib/$(ARCH)/lib$(NAME).a))
OPENSSL := $(foreach ARCH, $(ARCH_LIST), openssl/lib/$(ARCH)/libcrypto.so.sdl.1.so openssl/lib/$(ARCH)/libssl.so.sdl.1.so)
OPENSSL := $(foreach ARCH, $(ARCHES32) $(ARCHES64), openssl/lib-$(ARCH)/libcrypto.so.sdl.1.so openssl/lib-$(ARCH)/libssl.so.sdl.1.so)
LIBS := $(ICONV) $(ICU) $(OPENSSL)
.PHONY: all boost openssl icu
all: $(LIBS)
openssl: $(OPENSSL)
icu: $(ICONV) $(ICU)
#.NOTPARALLEL: $(LIBS) $(BOOST)
$(ICONV) $(ICU): iconv/src/build.sh
cd iconv/src && \
./build.sh && \
for ARCH in $(ARCHES32) $(ARCHES64); do \
mkdir -p ../lib/$$ARCH ../include ; \
cp -f $$ARCH/libiconv.so $$ARCH/libcharset.so ../lib/$$ARCH/ ; \
cp -f $$ARCH/include/*.h ../include/ ; \
mkdir -p ../../icuuc/lib/$$ARCH ../../icuuc/include/unicode ../../icuuc/include/layout ; \
cp -f $$ARCH/libicu*.a $$ARCH/libharfbuzz.a ../../icuuc/lib/$$ARCH/ ; \
cp -f $$ARCH/include/unicode/*.h ../../icuuc/include/unicode/ ; \
cp -f $$ARCH/include/layout/*.h ../../icuuc/include/layout/ ; \
cp -f $$ARCH/include/icu-le-hb/layout/*.h ../../icuuc/include/layout/ ; \
done && \
git clean -f -d -x
$(OPENSSL): openssl/compile.sh
cd openssl && ./compile.sh
BOOST_LIBS := \
atomic \
@@ -22,10 +49,10 @@ BOOST_LIBS := \
coroutine \
date_time \
exception \
fiber \
filesystem \
graph \
iostreams \
json \
locale \
log \
log_setup \
@@ -35,12 +62,13 @@ BOOST_LIBS := \
math_tr1 \
math_tr1f \
math_tr1l \
nowide \
prg_exec_monitor \
program_options \
random \
regex \
serialization \
stacktrace_basic \
stacktrace_noop \
system \
test_exec_monitor \
thread \
@@ -51,69 +79,22 @@ BOOST_LIBS := \
wserialization \
BOOST := $(foreach ARCH, $(ARCH_LIST), $(foreach NAME, $(strip $(BOOST_LIBS)), boost/lib/$(ARCH)/libboost_$(NAME).a))
.PHONY: all boost icu openssl
all: $(ICONV) $(ICU) $(OPENSSL) $(BOOST)
boost: $(BOOST) $(foreach NAME, $(strip $(BOOST_LIBS)), boost_$(NAME))
icu: $(ICONV) $(ICU)
openssl: $(OPENSSL)
$(ICONV) $(ICU): iconv/src/build.sh
cd iconv/src && \
for ARCH in $(ARCH_LIST); do \
$(shell echo "#=Compiling iconv for $$ARCH") \
env ARCHS=$$ARCH PATH=$(PATH):${ANDROID_NDK_HOME} ./build.sh && \
mkdir -p ../lib/$$ARCH ../include ; \
cp -f $$ARCH/libiconv.so $$ARCH/libcharset.so ../lib/$$ARCH/ ; \
cp -f $$ARCH/include/*.h ../include/ ; \
mkdir -p ../../icuuc/lib/$$ARCH ../../icuuc/include/unicode ../../icuuc/include/layout ; \
cp -f $$ARCH/libicu*.a ../../icuuc/lib/$$ARCH/ ; \
cp -f $$ARCH/include/unicode/*.h ../../icuuc/include/unicode/ ; \
cp -f $$ARCH/include/layout/*.h ../../icuuc/include/layout/ ; \
cp -f $$ARCH/include/icu-le-hb/layout/*.h ../../icuuc/include/layout/ ; \
done
$(OPENSSL): openssl/compile.sh
cd openssl && env ARCH_LIST="$(ARCH_LIST)" ./compile.sh
BOOST := $(foreach ARCH, $(ARCHES32) $(ARCHES64), $(foreach NAME, $(BOOST_LIBS), boost/lib/$(ARCH)/libboost_$(NAME).a))
$(BOOST): boost/src/build-android.sh
rm -rf boost/include boost/lib ; \
cd boost/src && \
./build-android.sh --boost=1.78.0 --with-iconv --target-version=16 --arch=$(shell echo $(foreach ARCH, $(ARCH_LIST),$(ARCH),) | tr -d ' ') && \
for ARCH in $(ARCH_LIST); do \
./build-android.sh --boost=1.69.0 --with-iconv --arch=$(shell echo $(foreach ARCH, $(ARCHES32) $(ARCHES64),$(ARCH),) | tr -d ' ') && \
for ARCH in $(ARCHES32) $(ARCHES64); do \
mkdir -p ../lib/$$ARCH ../include ; \
$(foreach NAME, $(strip $(BOOST_LIBS)), cp -f build/out/$$ARCH/lib/libboost_$(NAME)-clang-mt-*.a ../lib/$$ARCH/libboost_$(NAME).a || exit 1 ;) \
$(foreach NAME, $(BOOST_LIBS), cp -f build/out/$$ARCH/lib/libboost_$(NAME)-clang-mt-*.a ../lib/$$ARCH/libboost_$(NAME).a || exit 1 ;) \
cp -r -f build/out/$$ARCH/include/boost-*/* ../include/ || exit 1 ; \
done || exit 1
done || exit 1 ; \
git clean -f -d -x ; \
$(foreach NAME, $(BOOST_LIBS), ln -sf boost ../../boost_$(NAME) ;)
$(foreach NAME, $(strip $(BOOST_LIBS)), boost_$(NAME)):
ln -sf boost $@
boost: $(BOOST)
iconv/src/build.sh boost/src/build-android.sh:
git submodule update --init --recursive
# Dependencies for CustomBuildScript.mk
define COPY_TO_OBJ =
ARCH := $(1)
SRCDIR := $(2)
FILENAME := $(3)
../obj/local/$$(ARCH)/$$(FILENAME) $$(abspath ../obj/local/$$(ARCH)/$$(FILENAME)): $$(SRCDIR)/$$(FILENAME)
cp -f $$< $$@
#$$(warning === ARCH = $(1) SRCDIR = $(2) FILENAME = $(3) ../obj/local/$$(ARCH)/$$(FILENAME) $$(abspath ../obj/local/$$(ARCH)/$$(FILENAME)): $$(SRCDIR)/$$(FILENAME))
endef # COPY_TO_OBJ
$(foreach ARCH, $(ARCH_LIST), $(foreach NAME, libiconv.so libcharset.so, $(eval $(call COPY_TO_OBJ,$(ARCH),iconv/lib/$(ARCH),$(NAME)))))
$(foreach ARCH, $(ARCH_LIST), $(foreach NAME, $(ICU_LIBS), $(eval $(call COPY_TO_OBJ,$(ARCH),icuuc/lib/$(ARCH),lib$(NAME).a))))
$(foreach ARCH, $(ARCH_LIST), $(foreach NAME, libcrypto.so.sdl.1.so libssl.so.sdl.1.so, $(eval $(call COPY_TO_OBJ,$(ARCH),openssl/lib/$(ARCH),$(NAME)))))

View File

@@ -1 +0,0 @@
../sdl2/include

View File

@@ -1 +0,0 @@
../sdl2_image

View File

@@ -1 +0,0 @@
../sdl2_mixer/include

View File

@@ -1 +0,0 @@
../sdl2_ttf

View File

@@ -1,24 +1,18 @@
SDL_VERSION := 1.2
# To filter out static libs from all libs in makefile
APP_AVAILABLE_STATIC_LIBS := jpeg png webp freetype fontconfig xerces ogg vorbis tremor flac \
boost_atomic boost_chrono boost_container boost_context boost_contract boost_coroutine boost_date_time boost_exception boost_filesystem \
boost_graph boost_iostreams boost_json boost_locale boost_log boost_log_setup boost_math_c99 boost_math_c99f boost_math_c99l boost_math_tr1 \
boost_math_tr1f boost_math_tr1l boost_nowide boost_prg_exec_monitor boost_program_options boost_random boost_regex boost_serialization \
APP_AVAILABLE_STATIC_LIBS := jpeg png freetype fontconfig xerces ogg vorbis flac \
boost_atomic boost_chrono boost_container boost_context boost_coroutine boost_date_time boost_exception boost_filesystem \
boost_graph boost_iostreams boost_locale boost_log boost_log_setup boost_prg_exec_monitor boost_program_options boost_random \
boost_regex boost_serialization boost_signals boost_stacktrace_basic boost_stacktrace_noop \
boost_system boost_test_exec_monitor boost_thread boost_timer boost_type_erasure boost_unit_test_framework boost_wave boost_wserialization \
glu icudata icutest icui18n icuio icule iculx icutu icuuc icu-le-hb harfbuzz sdl_savepng android_support \
gl4es nanogl gd guichan glm
gl4es nanogl gd guichan
# Available libraries: mad (GPL-ed!) sdl_mixer sdl_image sdl_ttf sdl_net sdl_blitpool sdl_gfx sdl_sound intl xml2 lua jpeg png ogg flac tremor vorbis freetype xerces curl theora fluidsynth lzma lzo2 mikmod openal timidity zzip bzip2 yaml-cpp python boost_date_time boost_filesystem boost_iostreams boost_program_options boost_regex boost_signals boost_system boost_thread glu avcodec avdevice avfilter avformat avresample avutil swscale swresample bzip2
APP_MODULES := application sdl-1.2 sdl_native_helpers jpeg png ogg flac vorbis freetype tremor ogg
ifeq ($(CUSTOM_BUILD_SCRIPT_FIRST_PASS),)
APP_MODULES += application $(if $(filter 1.2, $(SDL_VERSION)), sdl_main)
endif
APP_MODULES := application sdl-1.2 sdl_main sdl_native_helpers jpeg png ogg flac vorbis freetype tremor ogg
ifeq ($(APP_ABI),)
APP_ABI := arm64-v8a armeabi-v7a x86 x86_64
APP_ABI := armeabi-v7a
endif
# The namespace in Java file, with dots replaced with underscores
@@ -64,6 +58,8 @@ USE_GL4ES :=
SDL_ADDITIONAL_CFLAGS := -DSDL_ANDROID_KEYCODE_MOUSE=UNKNOWN -DSDL_ANDROID_KEYCODE_0=LCTRL -DSDL_ANDROID_KEYCODE_1=LALT -DSDL_ANDROID_KEYCODE_2=SPACE -DSDL_ANDROID_KEYCODE_3=RETURN -DSDL_ANDROID_KEYCODE_4=RETURN
SDL_VERSION := 1.2
NDK_TOOLCHAIN_VERSION := clang
APP_PLATFORM := android-16

View File

@@ -3,21 +3,8 @@ LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := application
APPDIR := $(shell readlink $(LOCAL_PATH)/src)
LOCAL_SHARED_LIBRARIES := $(if $(filter 1.2, $(SDL_VERSION)), sdl-1.2, SDL2) $(filter-out $(APP_AVAILABLE_STATIC_LIBS), $(COMPILED_LIBRARIES))
LOCAL_STATIC_LIBRARIES := $(filter $(APP_AVAILABLE_STATIC_LIBS), $(COMPILED_LIBRARIES))
LOCAL_LDLIBS := $(APPLICATION_GLES_LIBRARY) -ldl -llog -lz
LOCAL_LDFLAGS := -Lobj/local/$(TARGET_ARCH_ABI)
LOCAL_LDFLAGS += $(APPLICATION_ADDITIONAL_LDFLAGS)
ifeq ($(APPLICATION_CUSTOM_BUILD_SCRIPT),)
APP_SUBDIRS := $(patsubst $(LOCAL_PATH)/%, %, $(shell find $(LOCAL_PATH)/$(APPDIR) -path '*/.svn' -prune -o -type d -print))
ifneq ($(APPLICATION_SUBDIRS_BUILD),)
APPLICATION_SUBDIRS_BUILD_NONRECURSIVE := $(addprefix $(APPDIR)/, $(filter-out %/*, $(APPLICATION_SUBDIRS_BUILD)))
@@ -27,10 +14,9 @@ APPLICATION_SUBDIRS_BUILD_RECURSIVE := $(patsubst $(LOCAL_PATH)/%, %, $(APPLICAT
APP_SUBDIRS := $(APPLICATION_SUBDIRS_BUILD_NONRECURSIVE) $(APPLICATION_SUBDIRS_BUILD_RECURSIVE)
endif
LOCAL_SRC_FILES := $(filter %.c %.cpp %.cc, $(APP_SUBDIRS))
APP_SUBDIRS := $(filter-out %.c %.cpp %.cc, $(APP_SUBDIRS))
LOCAL_SRC_FILES := $(filter %.c %.cpp, $(APP_SUBDIRS))
APP_SUBDIRS := $(filter-out %.c %.cpp, $(APP_SUBDIRS))
LOCAL_SRC_FILES += $(foreach F, $(APP_SUBDIRS), $(addprefix $(F)/,$(notdir $(wildcard $(LOCAL_PATH)/$(F)/*.cpp))))
LOCAL_SRC_FILES += $(foreach F, $(APP_SUBDIRS), $(addprefix $(F)/,$(notdir $(wildcard $(LOCAL_PATH)/$(F)/*.cc))))
LOCAL_SRC_FILES += $(foreach F, $(APP_SUBDIRS), $(addprefix $(F)/,$(notdir $(wildcard $(LOCAL_PATH)/$(F)/*.c))))
LOCAL_SRC_FILES := $(filter-out $(addprefix $(APPDIR)/, $(APPLICATION_BUILD_EXCLUDE)), $(LOCAL_SRC_FILES))
@@ -46,7 +32,7 @@ LOCAL_CFLAGS += $(foreach D, $(LOCAL_C_INCLUDES), -iquote$(D))
LOCAL_C_INCLUDES :=
endif
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../$(strip $(if $(filter 1.2, $(SDL_VERSION)), sdl-1.2, SDL2))/include
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../sdl-$(SDL_VERSION)/include
LOCAL_C_INCLUDES += $(foreach L, $(COMPILED_LIBRARIES), $(LOCAL_PATH)/../$(L)/include)
LOCAL_CFLAGS += $(APPLICATION_ADDITIONAL_CFLAGS)
@@ -55,13 +41,78 @@ LOCAL_CPPFLAGS += $(APPLICATION_ADDITIONAL_CPPFLAGS)
# Change C++ file extension as appropriate
LOCAL_CPP_EXTENSION := .cpp .cxx .cc
ifneq ($(APPLICATION_CUSTOM_BUILD_SCRIPT),)
LOCAL_SRC_FILES := dummy.c
endif
ifeq ($(SDL_VERSION),2.0)
LOCAL_SHARED_LIBRARIES := SDL2 $(filter-out $(APP_AVAILABLE_STATIC_LIBS), $(COMPILED_LIBRARIES))
else
LOCAL_SHARED_LIBRARIES := sdl-$(SDL_VERSION) $(filter-out $(APP_AVAILABLE_STATIC_LIBS), $(COMPILED_LIBRARIES))
endif
LOCAL_STATIC_LIBRARIES := $(filter $(APP_AVAILABLE_STATIC_LIBS), $(COMPILED_LIBRARIES))
LOCAL_LDLIBS := $(APPLICATION_GLES_LIBRARY) -ldl -llog -lz
LOCAL_LDFLAGS := -Lobj/local/$(TARGET_ARCH_ABI)
LOCAL_LDFLAGS += $(APPLICATION_ADDITIONAL_LDFLAGS)
LOCAL_CPP_EXTENSION := .cpp .cxx .cc
SDL_APP_LIB_DEPENDS-$(TARGET_ARCH_ABI) := $(LOCAL_PATH)/src/AndroidBuild.sh $(LOCAL_PATH)/src/AndroidAppSettings.cfg
SDL_APP_LIB_DEPENDS-$(TARGET_ARCH_ABI) += $(foreach LIB, $(LOCAL_SHARED_LIBRARIES), obj/local/$(TARGET_ARCH_ABI)/lib$(LIB).so)
SDL_APP_LIB_DEPENDS-$(TARGET_ARCH_ABI) += $(foreach LIB, $(LOCAL_STATIC_LIBRARIES), obj/local/$(TARGET_ARCH_ABI)/lib$(LIB).a)
.PHONY: obj/local/$(TARGET_ARCH_ABI)/libcrypto.so obj/local/$(TARGET_ARCH_ABI)/libssl.so obj/local/$(TARGET_ARCH_ABI)/libcurl.so
obj/local/$(TARGET_ARCH_ABI)/libcrypto.so: obj/local/$(TARGET_ARCH_ABI)/libcrypto.so.sdl.0.so
obj/local/$(TARGET_ARCH_ABI)/libssl.so: obj/local/$(TARGET_ARCH_ABI)/libssl.so.sdl.0.so
obj/local/$(TARGET_ARCH_ABI)/libcurl.so: obj/local/$(TARGET_ARCH_ABI)/libcurl-sdl.so
obj/local/$(TARGET_ARCH_ABI)/libexpat.so: obj/local/$(TARGET_ARCH_ABI)/libexpat-sdl.so
include $(BUILD_SHARED_LIBRARY)
else ifeq ($(CUSTOM_BUILD_SCRIPT_FIRST_PASS),) # APPLICATION_CUSTOM_BUILD_SCRIPT and not CUSTOM_BUILD_SCRIPT_FIRST_PASS
ifneq ($(APPLICATION_CUSTOM_BUILD_SCRIPT),)
LOCAL_SRC_FILES := $(APPDIR)/libapplication-$(TARGET_ARCH_ABI).so
LOCAL_MODULE_FILENAME := libapplication
# TODO: here we're digging inside NDK internal build system, that's not portable
# NDK r5b provided the $(PREBUILT_SHARED_LIBRARY) target, however it requires .so file to be already present on disk
# Also I cannot just launch AndroidBuild.sh from makefile because other libraries are not rebuilt and linking will fail
.PHONY: OVERRIDE_CUSTOM_LIB
OVERRIDE_CUSTOM_LIB:
# Prevent ./AndroidBuild.sh to be invoked in parallel for different architectures, it may do things like downloading files which work poorly when launched in parallel
# .NOTPARALLEL prevents other sources from building in parallel, so we're using flock shell command here
# There is flock command on Linux, but it fails to lock a file, and mkdir is more portable
PARALLEL_LOCK := until mkdir .lock >/dev/null 2>&1; do sleep 1; done
PARALLEL_UNLOCK := rmdir .lock >/dev/null 2>&1
include $(PREBUILT_SHARED_LIBRARY)
LOCAL_PATH_SDL_APPLICATION := $(LOCAL_PATH)
endif
$(shell cd $(LOCAL_PATH_SDL_APPLICATION)/src && $(PARALLEL_UNLOCK))
obj/local/armeabi-v7a/libapplication.so: $(LOCAL_PATH)/src/libapplication-armeabi-v7a.so
$(LOCAL_PATH)/src/libapplication-armeabi-v7a.so: $(SDL_APP_LIB_DEPENDS-armeabi-v7a) OVERRIDE_CUSTOM_LIB
cd $(LOCAL_PATH_SDL_APPLICATION)/src && $(PARALLEL_LOCK) && \
./AndroidBuild.sh armeabi-v7a arm-linux-androideabi && $(PARALLEL_UNLOCK)
obj/local/x86/libapplication.so: $(LOCAL_PATH)/src/libapplication-x86.so
$(LOCAL_PATH)/src/libapplication-x86.so: $(SDL_APP_LIB_DEPENDS-x86) OVERRIDE_CUSTOM_LIB
cd $(LOCAL_PATH_SDL_APPLICATION)/src && $(PARALLEL_LOCK) && \
./AndroidBuild.sh x86 i686-linux-android && $(PARALLEL_UNLOCK)
obj/local/arm64-v8a/libapplication.so: $(LOCAL_PATH)/src/libapplication-arm64-v8a.so
$(LOCAL_PATH)/src/libapplication-arm64-v8a.so: $(SDL_APP_LIB_DEPENDS-arm64-v8a) OVERRIDE_CUSTOM_LIB
cd $(LOCAL_PATH_SDL_APPLICATION)/src && $(PARALLEL_LOCK) && \
./AndroidBuild.sh arm64-v8a aarch64-linux-android && $(PARALLEL_UNLOCK)
obj/local/x86_64/libapplication.so: $(LOCAL_PATH)/src/libapplication-x86_64.so
$(LOCAL_PATH)/src/libapplication-x86_64.so: $(SDL_APP_LIB_DEPENDS-x86_64) OVERRIDE_CUSTOM_LIB
cd $(LOCAL_PATH_SDL_APPLICATION)/src && $(PARALLEL_LOCK) && \
./AndroidBuild.sh x86_64 x86_64-linux-android && $(PARALLEL_UNLOCK)
endif # $(APPLICATION_CUSTOM_BUILD_SCRIPT)

View File

@@ -1,54 +0,0 @@
include ../Settings.mk
APPDIR := $(shell readlink src)
all: $(foreach ARCH, $(APP_ABI), $(APPDIR)/libapplication-$(ARCH).so)
.PHONY: all $(foreach ARCH, $(APP_ABI), $(APPDIR)/libapplication-$(ARCH).so)
TARGET_GCC_PREFIX_armeabi-v7a := arm-linux-androideabi
TARGET_GCC_PREFIX_x86 := i686-linux-android
TARGET_GCC_PREFIX_arm64-v8a := aarch64-linux-android
TARGET_GCC_PREFIX_x86_64 := x86_64-linux-android
LOCAL_STATIC_LIBRARIES := $(filter $(APP_AVAILABLE_STATIC_LIBS), $(COMPILED_LIBRARIES))
LOCAL_SHARED_LIBRARIES := sdl-$(SDL_VERSION) $(filter-out $(APP_AVAILABLE_STATIC_LIBS), $(COMPILED_LIBRARIES))
LOCAL_SHARED_LIBRARIES := $(patsubst crypto, crypto.so.sdl.1, $(LOCAL_SHARED_LIBRARIES))
LOCAL_SHARED_LIBRARIES := $(patsubst ssl, ssl.so.sdl.1, $(LOCAL_SHARED_LIBRARIES))
LOCAL_SHARED_LIBRARIES := $(patsubst curl, curl-sdl, $(LOCAL_SHARED_LIBRARIES))
LOCAL_SHARED_LIBRARIES := $(patsubst expat, expat-sdl, $(LOCAL_SHARED_LIBRARIES))
define DEPENDS_FOR_ARCH =
../../obj/local/$(1)/$(2):
make -C .. -f Makefile.prebuilt $$(abspath $$@)
SDL_APP_LIB_DEPENDS_$(1) += ../../obj/local/$(1)/$(2)
#$$(warning === ../../obj/local/$(1)/$(2):)
endef
$(foreach ARCH, $(APP_ABI), $(foreach LIB, $(LOCAL_SHARED_LIBRARIES), $(eval $(call DEPENDS_FOR_ARCH,$(ARCH),lib$(LIB).so))))
$(foreach ARCH, $(APP_ABI), $(foreach LIB, $(LOCAL_STATIC_LIBRARIES), $(eval $(call DEPENDS_FOR_ARCH,$(ARCH),lib$(LIB).a))))
define BUILD_FOR_ARCH =
SDL_APP_LIB_DEPENDS_$(1) += $$(APPDIR)/AndroidBuild.sh $$(APPDIR)/AndroidAppSettings.cfg
$$(APPDIR)/libapplication-$(1).so: $$(SDL_APP_LIB_DEPENDS_$(1))
cd $$(APPDIR) && ./AndroidBuild.sh $(1) $$(TARGET_GCC_PREFIX_$(1))
@objdump -p $$@ | grep 'SONAME' && { \
objdump -p $$@ | grep 'SONAME *libapplication.so' || { \
rm $$@ ; echo 'Error: $$@ must have SONAME set to "libapplication.so", add option -Wl,-soname=libapplication.so to your linker flags' ; \
} ; \
}
#$$(warning ====== $$(APPDIR)/libapplication-$(1).so: ==> $$(SDL_APP_LIB_DEPENDS_$(1)))
endef
$(foreach ARCH, $(APP_ABI), $(eval $(call BUILD_FOR_ARCH,$(ARCH))))

View File

@@ -0,0 +1,34 @@
# The application settings for Android libSDL port
AppSettingVersion=16
LibSdlVersion=1.2
AppName="REminiscence"
AppFullName=fr.freecyxdown.sdl
ScreenOrientation=h
InhibitSuspend=n
AppDataDownloadUrl="Data files size is 1 Mb|http://anddev.at.ua/data/reminiscence-data.zip?attredirects=0&d=1"
SdlVideoResize=y
SdlVideoResizeKeepAspect=n
NeedDepthBuffer=n
AppUsesMouse=n
AppNeedsTwoButtonMouse=n
AppNeedsArrowKeys=y
AppNeedsTextInput=y
AppUsesJoystick=n
AppHandlesJoystickSensitivity=n
AppUsesMultitouch=n
NonBlockingSwapBuffers=n
RedefinedKeys="RSHIFT RETURN BACKSPACE RETURN SPACE"
AppTouchscreenKeyboardKeysAmount=3
AppTouchscreenKeyboardKeysAmountAutoFire=0
RedefinedKeysScreenKb="RSHIFT RETURN BACKSPACE RETURN SPACE"
MultiABI=n
AppVersionCode=01901
AppVersionName="0.1.9"
CompiledLibraries="jpeg png"
CustomBuildScript=n
AppCflags='-Dmain=SDL_main -DBYPASS_PROTECTION'
AppLdflags=''
AppSubdirsBuild=''
AppUseCrystaXToolchain=n
AppCmdline=''
ReadmeText='^You may press "Home" now - the data will be downloaded in background'

View File

@@ -0,0 +1,20 @@
#!/bin/sh
LOCAL_PATH=`dirname $0`
LOCAL_PATH=`cd $LOCAL_PATH && pwd`
# Hacks for broken configure scripts
#rm -rf $LOCAL_PATH/../../obj/local/armeabi/libSDL_*.so
#rm -rf $LOCAL_PATH/../../obj/local/armeabi/libsdl_main.so
# Uncomment if your configure expects SDL libraries in form "libSDL_name.so"
#if [ -e $LOCAL_PATH/../../obj/local/armeabi/libsdl_mixer.so ] ; then
# ln -sf libsdl_mixer.so $LOCAL_PATH/../../obj/local/armeabi/libSDL_Mixer.so
#fi
#for F in $LOCAL_PATH/../../obj/local/armeabi/libsdl_*.so; do
# LIBNAME=`echo $F | sed "s@$LOCAL_PATH/../../obj/local/armeabi/libsdl_\(.*\)[.]so@\1@"`
# ln -sf libsdl_$LIBNAME.so $LOCAL_PATH/../../obj/local/armeabi/libSDL_$LIBNAME.so
#done
../setEnvironment.sh make -C REminiscence-0.1.9 -j2 && cp -f REminiscence-0.1.9/rs libapplication.so

View File

@@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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 2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

View File

@@ -0,0 +1,29 @@
SDL_CFLAGS = `sdl-config --cflags` -Dmain=SDL_main -fpic -mthumb-interwork -ffunction-sections -funwind-tables -fstack-protector -fno-short-enums -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -DANDROID -Wno-psabi -march=armv5te -mtune=xscale -msoft-float -fno-exceptions -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64 -I/home/lubomyr/src/endless_space/android-ndk-r4-crystax/build/platforms/android-8/arch-arm/usr/include -I/home/lubomyr/project/jni/sdl-1.2/include
SDL_LIBS = `sdl-config --libs` -nostdlib -Wl,-soname,libapplication.so -Wl,-shared,-Bsymbolic -Wl,--whole-archive -Wl,--no-whole-archive /home/lubomyr/src/endless_space/android-ndk-r4-crystax/build/prebuilt/linux-x86/arm-eabi-4.4.0/arm-eabi/lib/libstdc++.a /home/lubomyr/src/endless_space/android-ndk-r4-crystax/build/platforms/android-8/arch-arm/usr/lib/libc.a -L/home/lubomyr/project/obj/local/armeabi -lsdl-1.2 -lm -llog -lgcc -L/home/lubomyr/src/endless_space/android-ndk-r4-crystax/build/platforms/android-8/arch-arm/usr/lib
DEFINES = -DBYPASS_PROTECTION
#DEFINES = -DBYPASS_PROTECTION -DNDEBUG
CXX = arm-eabi-g++
CXXFLAGS:= -g -Wall -Wuninitialized -Wno-unknown-pragmas -Wshadow -Wimplicit
CXXFLAGS+= -Wundef -Wreorder -Wwrite-strings -Wnon-virtual-dtor -Wno-multichar
CXXFLAGS+= $(SDL_CFLAGS) $(DEFINES)
SRCS = collision.cpp cutscene.cpp file.cpp game.cpp graphics.cpp main.cpp menu.cpp \
mixer.cpp mod_player.cpp piege.cpp resource.cpp scaler.cpp sfx_player.cpp \
staticres.cpp systemstub_sdl.cpp unpack.cpp util.cpp video.cpp
OBJS = $(SRCS:.cpp=.o)
DEPS = $(SRCS:.cpp=.d)
rs: $(OBJS)
$(CXX) $(LDFLAGS) -o $@ $(OBJS) $(SDL_LIBS) -lz
.cpp.o:
$(CXX) $(CXXFLAGS) -MMD -c $< -o $*.o
clean:
rm -f *.o *.d
-include $(DEPS)

View File

@@ -0,0 +1,138 @@
REminiscence README
Release version: 0.1.9 (Mar 16 2007)
-------------------------------------------------------------------------------
About:
------
REminiscence is a re-implementation of the engine used in the game Flashback
made by Delphine Software and released in 1992. More informations about the
game can be found at [1], [2] and [3].
Supported Versions:
-------------------
Only the PC DOS versions are supported. The engine has been reported to work
with english, french, german and spanish versions of the game.
Compiling:
----------
Tweak the Makefile if needed and type make (only gcc3 has been tested so far).
The SDL and zlib libraries are required.
Data Files:
-----------
You will need the original files, here is the required list :
FB_TXT.FNT
GLOBAL.ICN
GLOBAL.FIB
GLOBAL.SPC
*.OFF
*.SPR
*.MAP
*.PAL
*.ANI
*.CT
*.MBK
*.OBJ
*.PGE
*.RP
*.TBN
*.CMD
*.POL
*CINE.*
If you have a version distributed by SSI, you'll have to rename some files :
logosssi.cmd -> logos.cmd
logosssi.pol -> logos.pol
menu1ssi.map -> menu1.map
menu1ssi.pal -> menu1.pal
In order to hear music, you'll need the original music files (.mod) of the
amiga version. Copy them to the DATA directory and rename them like this :
mod.flashback-ascenseur
mod.flashback-ceinturea
mod.flashback-chute
mod.flashback-desintegr
mod.flashback-donneobjt
mod.flashback-fin
mod.flashback-fin2
mod.flashback-game_over
mod.flashback-holocube
mod.flashback-introb
mod.flashback-jungle
mod.flashback-logo
mod.flashback-memoire
mod.flashback-missionca
mod.flashback-options1
mod.flashback-options2
mod.flashback-reunion
mod.flashback-taxi
mod.flashback-teleport2
mod.flashback-teleporta
mod.flashback-voyage
Running:
--------
By default, the engine will try to load the game data files from the 'DATA'
directory (as the original game did). The savestates are saved in the current
directory. These paths can be changed using command line switches :
Usage: rs [OPTIONS]...
--datapath=PATH Path to data files (default 'DATA')
--savepath=PATH Path to save files (default '.')
In-game hotkeys :
Arrow Keys move Conrad
Enter use the current inventory object
Shift talk / use / run / shoot
Escape display the options
Backspace display the inventory
Alt Enter toggle windowed/fullscreen mode
Alt + and - change video scaler
Ctrl S save game state
Ctrl L load game state
Ctrl + and - change game state slot
Ctrl R toggle input keys record
Ctrl P toggle input keys replay
Debug hotkeys :
Ctrl F toggle fast mode
Ctrl I set Conrad life counter to 32767
Ctrl B toggle display of updated dirty blocks
Ctrl M mirror mode (just a hack, really)
Credits:
--------
Delphine Software, obviously, for making another great game.
Yaz0r, Pixel and gawd for sharing information they gathered on the game.
Contact:
--------
Gregory Montoir, cyx@users.sourceforge.net
URLs:
-----
[1] http://www.mobygames.com/game/flashback-the-quest-for-identity
[2] http://en.wikipedia.org/wiki/Flashback:_The_Quest_for_Identity
[3] http://ramal.free.fr/fb_en.htm

View File

@@ -0,0 +1,523 @@
/* REminiscence - Flashback interpreter
* Copyright (C) 2005-2007 Gregory Montoir
*
* 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 2
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "game.h"
#include "resource.h"
void Game::col_prepareRoomState() {
memset(_col_activeCollisionSlots, 0xFF, sizeof(_col_activeCollisionSlots));
_col_currentLeftRoom = _res._ctData[CT_LEFT_ROOM + _currentRoom];
_col_currentRightRoom = _res._ctData[CT_RIGHT_ROOM + _currentRoom];
for (int i = 0; i != _col_curPos; ++i) {
CollisionSlot *_di = _col_slotsTable[i];
uint8 room = _di->ct_pos / 64;
if (room == _currentRoom) {
_col_activeCollisionSlots[0x30 + (_di->ct_pos & 0x3F)] = i;
} else if (room == _col_currentLeftRoom) {
_col_activeCollisionSlots[0x00 + (_di->ct_pos & 0x3F)] = i;
} else if (room == _col_currentRightRoom) {
_col_activeCollisionSlots[0x60 + (_di->ct_pos & 0x3F)] = i;
}
}
#ifdef DEBUG_COLLISION
printf("---\n");
for (int y = 0; y < 7; ++y) {
for (int x = 0; x < 16; ++x) {
printf("%d", _res._ctData[0x100 + _currentRoom * 0x70 + y * 16 + x]);
}
printf("\n");
}
#endif
}
void Game::col_clearState() {
_col_curPos = 0;
_col_curSlot = _col_slots;
}
void Game::col_preparePiegeState(LivePGE *pge) {
debug(DBG_COL, "Game::col_preparePiegeState() pge_num=%d", pge - &_pgeLive[0]);
CollisionSlot *ct_slot1, *ct_slot2;
if (pge->init_PGE->unk1C == 0) {
pge->collision_slot = 0xFF;
return;
}
int i = 0;
ct_slot1 = 0;
for (int c = 0; c < pge->init_PGE->unk1C; ++c) {
ct_slot2 = _col_curSlot;
if (ct_slot2 + 1 > &_col_slots[255])
return;
_col_curSlot = ct_slot2 + 1;
int16 pos = col_getGridPos(pge, i);
if (pos < 0) {
if (ct_slot1 == 0) {
pge->collision_slot = 0xFF;
} else {
ct_slot1->index = 0xFFFF;
}
return;
}
ct_slot2->ct_pos = pos;
ct_slot2->live_pge = pge;
ct_slot2->index = 0xFFFF;
int16 _ax = col_findSlot(pos);
if (_ax >= 0) {
ct_slot2->prev_slot = _col_slotsTable[_ax];
_col_slotsTable[_ax] = ct_slot2;
if (ct_slot1 == 0) {
pge->collision_slot = _ax;
} else {
ct_slot1->index = _ax;
}
LivePGE *temp_pge = ct_slot2->live_pge;
if (temp_pge->flags & 0x80) {
_pge_liveTable2[temp_pge->index] = temp_pge;
temp_pge->flags |= 4;
}
if (ct_slot2->prev_slot) {
temp_pge = ct_slot2->prev_slot->live_pge;
if (temp_pge->flags & 0x80) {
_pge_liveTable2[temp_pge->index] = temp_pge;
temp_pge->flags |= 4;
}
}
} else {
ct_slot2->prev_slot = 0;
_col_slotsTable[_col_curPos] = ct_slot2;
if (ct_slot1 == 0) {
pge->collision_slot = _col_curPos;
} else {
ct_slot1->index = _col_curPos;
}
_col_curPos++;
}
ct_slot1 = ct_slot2;
i += 0x10;
}
}
uint16 Game::col_getGridPos(LivePGE *pge, int16 dx) {
int16 x = pge->pos_x + dx;
int16 y = pge->pos_y;
int8 c = pge->room_location;
if (c < 0) return 0xFFFF;
if (x < 0) {
c = _res._ctData[CT_LEFT_ROOM + c];
if (c < 0) return 0xFFFF;
x += 256;
} else if (x >= 256) {
c = _res._ctData[CT_RIGHT_ROOM + c];
if (c < 0) return 0xFFFF;
x -= 256;
} else if (y < 0) {
c = _res._ctData[CT_UP_ROOM + c];
if (c < 0) return 0xFFFF;
y += 216;
} else if (y >= 216) {
c = _res._ctData[CT_DOWN_ROOM + c];
if (c < 0) return 0xFFFF;
y -= 216;
}
x = (x + 8) >> 4;
y = (y - 8) / 72;
if (x < 0 || x > 15 || y < 0 || y > 2) {
return 0xFFFF;
} else {
return y * 16 + x + c * 64;
}
}
int16 Game::col_findSlot(int16 pos) {
for (uint16 i = 0; i < _col_curPos; ++i) {
if (_col_slotsTable[i]->ct_pos == pos)
return i;
}
return -1;
}
int16 Game::col_getGridData(LivePGE *pge, int16 dy, int16 dx) {
if (_pge_currentPiegeFacingDir) {
dx = -dx;
}
const int16 pge_grid_y = _col_currentPiegeGridPosY + dy;
const int16 pge_grid_x = _col_currentPiegeGridPosX + dx;
const int8 *room_ct_data;
int8 next_room;
if (pge_grid_x < 0) {
room_ct_data = &_res._ctData[CT_LEFT_ROOM];
next_room = room_ct_data[pge->room_location];
if (next_room < 0) return 1;
room_ct_data += pge_grid_x + 16 + pge_grid_y * 16 + next_room * 0x70;
return (int16)room_ct_data[0x40];
} else if (pge_grid_x >= 16) {
room_ct_data = &_res._ctData[CT_RIGHT_ROOM];
next_room = room_ct_data[pge->room_location];
if (next_room < 0) return 1;
room_ct_data += pge_grid_x - 16 + pge_grid_y * 16 + next_room * 0x70;
return (int16)room_ct_data[0x80];
} else if (pge_grid_y < 1) {
room_ct_data = &_res._ctData[CT_UP_ROOM];
next_room = room_ct_data[pge->room_location];
if (next_room < 0) return 1;
room_ct_data += pge_grid_x + (pge_grid_y + 6) * 16 + next_room * 0x70;
return (int16)room_ct_data[0x100];
} else if (pge_grid_y >= 7) {
room_ct_data = &_res._ctData[CT_DOWN_ROOM];
next_room = room_ct_data[pge->room_location];
if (next_room < 0) return 1;
room_ct_data += pge_grid_x + (pge_grid_y - 6) * 16 + next_room * 0x70;
return (int16)room_ct_data[0xC0];
} else {
room_ct_data = &_res._ctData[0x100];
room_ct_data += pge_grid_x + pge_grid_y * 16 + pge->room_location * 0x70;
return (int16)room_ct_data[0];
}
}
LivePGE *Game::col_findPiege(LivePGE *pge, uint16 arg2) {
if (pge->collision_slot != 0xFF) {
CollisionSlot *slot = _col_slotsTable[pge->collision_slot];
while (slot) {
if (slot->live_pge == pge) {
slot = slot->prev_slot;
} else {
if (arg2 == 0xFFFF || arg2 == slot->live_pge->init_PGE->object_type) {
return slot->live_pge;
} else {
slot = slot->prev_slot;
}
}
}
}
return 0;
}
uint8 Game::col_findCurrentCollidingObject(LivePGE *pge, uint8 n1, uint8 n2, uint8 n3, LivePGE **pge_out) {
if (pge_out) {
*pge_out = pge;
}
if (pge->collision_slot != 0xFF) {
CollisionSlot *cs = _col_slotsTable[pge->collision_slot];
while (cs) {
LivePGE *col_pge = cs->live_pge;
if (pge_out) {
*pge_out = col_pge;
}
if (col_pge->init_PGE->object_type == n1 ||
col_pge->init_PGE->object_type == n2 ||
col_pge->init_PGE->object_type == n3) {
return col_pge->init_PGE->colliding_icon_num;
} else {
cs = cs->prev_slot;
}
}
}
return 0;
}
int16 Game::col_detectHit(LivePGE *pge, int16 arg2, int16 arg4, col_Callback1 callback1, col_Callback2 callback2, int16 argA, int16 argC) {
debug(DBG_COL, "col_detectHit()");
int16 pos_dx, pos_dy, var8, varA;
int16 collision_score = 0;
int8 pge_room = pge->room_location;
if (pge_room < 0 || pge_room >= 0x40) {
return 0;
}
int16 thr = pge->init_PGE->counter_values[0];
if (thr > 0) {
pos_dx = -1;
pos_dy = -1;
} else {
pos_dx = 1;
pos_dy = 1;
thr = -thr;
}
if (_pge_currentPiegeFacingDir) {
pos_dx = -pos_dx;
}
int16 grid_pos_x = (pge->pos_x + 8) >> 4;
int16 grid_pos_y = (pge->pos_y / 72);
if (grid_pos_y >= 0 && grid_pos_y <= 2) {
grid_pos_y *= 16;
collision_score = 0;
var8 = 0;
varA = 0;
if (argA != 0) {
var8 = pos_dy;
grid_pos_x += pos_dx;
varA = 1;
}
while (varA <= thr) {
if (grid_pos_x < 0) {
pge_room = _res._ctData[CT_LEFT_ROOM + pge_room];
if (pge_room < 0) break;
grid_pos_x += 16;
}
if (grid_pos_x >= 16) {
pge_room = _res._ctData[CT_RIGHT_ROOM + pge_room];
if (pge_room < 0) break;
grid_pos_x -= 16;
}
int16 slot = col_findSlot(grid_pos_y + grid_pos_x + pge_room * 64);
if (slot >= 0) {
CollisionSlot *cs = _col_slotsTable[slot];
while (cs) {
collision_score += (this->*callback1)(cs->live_pge, pge, arg2, arg4);
cs = cs->prev_slot;
}
}
if ((this->*callback2)(pge, var8, varA, arg2) != 0) {
break;
}
grid_pos_x += pos_dx;
++varA;
var8 += pos_dy;
}
}
if (argC == -1) {
return collision_score;
} else {
return 0;
}
}
int Game::col_detectHitCallback1(LivePGE *pge, int16 dy, int16 unk1, int16 unk2) {
if (col_getGridData(pge, 1, dy) != 0) {
return 1;
} else {
return 0;
}
}
int Game::col_detectHitCallback6(LivePGE *pge, int16 dy, int16 unk1, int16 unk2) {
return 0;
}
int Game::col_detectHitCallback2(LivePGE *pge1, LivePGE *pge2, int16 unk1, int16 unk2) {
if (pge1 != pge2 && (pge1->flags & 4)) {
if (pge1->init_PGE->object_type == unk2) {
if ((pge1->flags & 1) == (pge2->flags & 1)) {
if (col_detectHitCallbackHelper(pge1, unk1) == 0) {
return 1;
}
}
}
}
return 0;
}
int Game::col_detectHitCallback3(LivePGE *pge1, LivePGE *pge2, int16 unk1, int16 unk2) {
if (pge1 != pge2 && (pge1->flags & 4)) {
if (pge1->init_PGE->object_type == unk2) {
if ((pge1->flags & 1) != (pge2->flags & 1)) {
if (col_detectHitCallbackHelper(pge1, unk1) == 0) {
return 1;
}
}
}
}
return 0;
}
int Game::col_detectHitCallback4(LivePGE *pge1, LivePGE *pge2, int16 unk1, int16 unk2) {
if (pge1 != pge2 && (pge1->flags & 4)) {
if (pge1->init_PGE->object_type == unk2) {
if ((pge1->flags & 1) != (pge2->flags & 1)) {
if (col_detectHitCallbackHelper(pge1, unk1) == 0) {
pge_updateGroup(pge2->index, pge1->index, unk1);
return 1;
}
}
}
}
return 0;
}
int Game::col_detectHitCallback5(LivePGE *pge1, LivePGE *pge2, int16 unk1, int16 unk2) {
if (pge1 != pge2 && (pge1->flags & 4)) {
if (pge1->init_PGE->object_type == unk2) {
if ((pge1->flags & 1) == (pge2->flags & 1)) {
if (col_detectHitCallbackHelper(pge1, unk1) == 0) {
pge_updateGroup(pge2->index, pge1->index, unk1);
return 1;
}
}
}
}
return 0;
}
int Game::col_detectHitCallbackHelper(LivePGE *pge, int16 groupId) {
InitPGE *init_pge = pge->init_PGE;
assert(init_pge->obj_node_number < _res._numObjectNodes);
ObjectNode *on = _res._objectNodesMap[init_pge->obj_node_number];
Object *obj = &on->objects[pge->first_obj_number];
int i = pge->first_obj_number;
while (pge->obj_type == obj->type && on->last_obj_number > i) {
if (obj->opcode2 == 0x6B) { // pge_op_isInGroupSlice
if (obj->opcode_arg2 == 0) {
if (groupId == 1 || groupId == 2) return 0xFFFF;
}
if (obj->opcode_arg2 == 1) {
if (groupId == 3 || groupId == 4) return 0xFFFF;
}
} else if (obj->opcode2 == 0x22) { // pge_op_isInGroup
if (obj->opcode_arg2 == groupId) return 0xFFFF;
}
if (obj->opcode1 == 0x6B) { // pge_op_isInGroupSlice
if (obj->opcode_arg1 == 0) {
if (groupId == 1 || groupId == 2) return 0xFFFF;
}
if (obj->opcode_arg1 == 1) {
if (groupId == 3 || groupId == 4) return 0xFFFF;
}
} else if (obj->opcode1 == 0x22) { // pge_op_isInGroup
if (obj->opcode_arg1 == groupId) return 0xFFFF;
}
++obj;
++i;
}
return 0;
}
int Game::col_detectGunHitCallback1(LivePGE *pge, int16 arg2, int16 arg4, int16 arg6) {
int16 _ax = col_getGridData(pge, 1, arg2);
if (_ax != 0) {
if (!(_ax & 2) || (arg6 != 1)) {
return _ax;
}
}
return 0;
}
int Game::col_detectGunHitCallback2(LivePGE *pge1, LivePGE *pge2, int16 arg4, int16) {
if (pge1 != pge2 && (pge1->flags & 4)) {
if (pge1->init_PGE->object_type == 1 || pge1->init_PGE->object_type == 10) {
uint8 id;
if ((pge1->flags & 1) != (pge2->flags & 1)) {
id = 4;
if (arg4 == 0) {
id = 3;
}
} else {
id = 2;
if (arg4 == 0) {
id = 1;
}
}
if (col_detectHitCallbackHelper(pge1, id) != 0) {
pge_updateGroup(pge2->index, pge1->index, id);
return 1;
}
}
}
return 0;
}
int Game::col_detectGunHitCallback3(LivePGE *pge1, LivePGE *pge2, int16 arg4, int16) {
if (pge1 != pge2 && (pge1->flags & 4)) {
if (pge1->init_PGE->object_type == 1 || pge1->init_PGE->object_type == 12 || pge1->init_PGE->object_type == 10) {
uint8 id;
if ((pge1->flags & 1) != (pge2->flags & 1)) {
id = 4;
if (arg4 == 0) {
id = 3;
}
} else {
id = 2;
if (arg4 == 0) {
id = 1;
}
}
if (col_detectHitCallbackHelper(pge1, id) != 0) {
pge_updateGroup(pge2->index, pge1->index, id);
return 1;
}
}
}
return 0;
}
int Game::col_detectGunHit(LivePGE *pge, int16 arg2, int16 arg4, col_Callback1 callback1, col_Callback2 callback2, int16 argA, int16 argC) {
int8 pge_room = pge->room_location;
if (pge_room < 0 || pge_room >= 0x40) return 0;
int16 thr, pos_dx, pos_dy;
if (argC == -1) {
thr = pge->init_PGE->counter_values[0];
} else {
thr = pge->init_PGE->counter_values[3];
}
if (thr > 0) {
pos_dx = -1;
pos_dy = -1;
} else {
pos_dx = 1;
pos_dy = 1;
thr = -thr;
}
if (_pge_currentPiegeFacingDir) {
pos_dx = -pos_dx;
}
int16 grid_pos_x = (pge->pos_x + 8) >> 4;
int16 grid_pos_y = (pge->pos_y - 8) / 72;
if (grid_pos_y >= 0 && grid_pos_y <= 2) {
grid_pos_y *= 16;
int16 var8 = 0;
int16 varA = 0;
if (argA != 0) {
var8 = pos_dy;
grid_pos_x += pos_dx;
varA = 1;
}
while (varA <= thr) {
if (grid_pos_x < 0) {
pge_room = _res._ctData[CT_LEFT_ROOM + pge_room];
if (pge_room < 0) return 0;
grid_pos_x += 0x10;
}
if (grid_pos_x >= 0x10) {
pge_room = _res._ctData[CT_RIGHT_ROOM + pge_room];
if (pge_room < 0) return 0;
grid_pos_x -= 0x10;
}
int16 slot = col_findSlot(pge_room * 64 + grid_pos_x + grid_pos_y);
if (slot >= 0) {
CollisionSlot *cs = _col_slotsTable[slot];
while (cs) {
int r = (this->*callback1)(cs->live_pge, pge, arg2, arg4);
if (r != 0) return r;
cs = cs->prev_slot;
}
}
if ((this->*callback2)(pge, var8, varA, arg2) != 0) {
break;
}
grid_pos_x += pos_dx;
++varA;
var8 += pos_dy;
}
}
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,138 @@
/* REminiscence - Flashback interpreter
* Copyright (C) 2005-2007 Gregory Montoir
*
* 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 2
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __CUTSCENE_H__
#define __CUTSCENE_H__
#include "intern.h"
#include "graphics.h"
struct ModPlayer;
struct Resource;
struct SystemStub;
struct Video;
struct Cutscene {
typedef void (Cutscene::*OpcodeStub)();
enum {
NUM_OPCODES = 15,
TIMER_SLICE = 15
};
static const OpcodeStub _opcodeTable[];
static const char *_namesTable[];
static const uint16 _offsetsTable[];
static const uint16 _cosTable[];
static const uint16 _sinTable[];
static const uint8 _creditsData[];
static const uint16 _creditsCutSeq[];
static const uint8 _musicTable[];
static const uint8 _protectionShapeData[];
Graphics _gfx;
ModPlayer *_ply;
Resource *_res;
SystemStub *_stub;
Video *_vid;
Version _ver;
uint16 _id;
uint16 _deathCutsceneId;
bool _interrupted;
bool _stop;
uint8 *_polPtr;
uint8 *_cmdPtr;
uint8 *_cmdPtrBak;
uint32 _tstamp;
uint8 _frameDelay;
bool _newPal;
uint8 _palBuf[0x20 * 2];
uint16 _startOffset;
bool _creditsSequence;
uint32 _rotData[4];
uint8 _primitiveColor;
uint8 _clearScreen;
Point _vertices[0x80];
bool _hasAlphaColor;
uint8 _varText;
uint8 _varKey;
int16 _shape_ix;
int16 _shape_iy;
int16 _shape_ox;
int16 _shape_oy;
int16 _shape_cur_x;
int16 _shape_cur_y;
int16 _shape_prev_x;
int16 _shape_prev_y;
uint16 _shape_count;
uint32 _shape_cur_x16;
uint32 _shape_cur_y16;
uint32 _shape_prev_x16;
uint32 _shape_prev_y16;
uint8 _textSep[0x14];
uint8 _textBuf[500];
const uint8 *_textCurPtr;
uint8 *_textCurBuf;
uint8 _textUnk2;
uint8 _creditsTextPosX;
uint8 _creditsTextPosY;
int16 _creditsTextCounter;
uint8 *_page0, *_page1, *_pageC;
Cutscene(ModPlayer *player, Resource *res, SystemStub *stub, Video *vid, Version ver);
void sync();
void copyPalette(const uint8 *pal, uint16 num);
void updatePalette();
void setPalette();
void initRotationData(uint16 a, uint16 b, uint16 c);
uint16 findTextSeparators(const uint8 *p);
void drawText(int16 x, int16 y, const uint8 *p, uint16 color, uint8 *page, uint8 n);
void swapLayers();
void drawCreditsText();
void drawProtectionShape(uint8 shapeNum, int16 zoom);
void drawShape(const uint8 *data, int16 x, int16 y);
void drawShapeScale(const uint8 *data, int16 zoom, int16 b, int16 c, int16 d, int16 e, int16 f, int16 g);
void drawShapeScaleRotate(const uint8 *data, int16 zoom, int16 b, int16 c, int16 d, int16 e, int16 f, int16 g);
void op_markCurPos();
void op_refreshScreen();
void op_waitForSync();
void op_drawShape();
void op_setPalette();
void op_drawStringAtBottom();
void op_nop();
void op_skip3();
void op_refreshAll();
void op_drawShapeScale();
void op_drawShapeScaleRotate();
void op_drawCreditsText();
void op_drawStringAtPos();
void op_handleKeys();
uint8 fetchNextCmdByte();
uint16 fetchNextCmdWord();
void mainLoop(uint16 offset);
void load(uint16 cutName);
void prepare();
void startCredits();
void play();
};
#endif // __CUTSCENE_H__

View File

@@ -0,0 +1,222 @@
/* REminiscence - Flashback interpreter
* Copyright (C) 2005-2007 Gregory Montoir
*
* 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 2
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "zlib.h"
#include "file.h"
struct File_impl {
bool _ioErr;
File_impl() : _ioErr(false) {}
virtual bool open(const char *path, const char *mode) = 0;
virtual void close() = 0;
virtual uint32 size() = 0;
virtual void seek(int32 off) = 0;
virtual void read(void *ptr, uint32 len) = 0;
virtual void write(void *ptr, uint32 len) = 0;
};
struct stdFile : File_impl {
FILE *_fp;
stdFile() : _fp(0) {}
bool open(const char *path, const char *mode) {
_ioErr = false;
_fp = fopen(path, mode);
return (_fp != 0);
}
void close() {
if (_fp) {
fclose(_fp);
_fp = 0;
}
}
uint32 size() {
uint32 sz = 0;
if (_fp) {
int pos = ftell(_fp);
fseek(_fp, 0, SEEK_END);
sz = ftell(_fp);
fseek(_fp, pos, SEEK_SET);
}
return sz;
}
void seek(int32 off) {
if (_fp) {
fseek(_fp, off, SEEK_SET);
}
}
void read(void *ptr, uint32 len) {
if (_fp) {
uint32 r = fread(ptr, 1, len, _fp);
if (r != len) {
_ioErr = true;
}
}
}
void write(void *ptr, uint32 len) {
if (_fp) {
uint32 r = fwrite(ptr, 1, len, _fp);
if (r != len) {
_ioErr = true;
}
}
}
};
struct zlibFile : File_impl {
gzFile _fp;
zlibFile() : _fp(0) {}
bool open(const char *path, const char *mode) {
_ioErr = false;
_fp = gzopen(path, mode);
return (_fp != 0);
}
void close() {
if (_fp) {
gzclose(_fp);
_fp = 0;
}
}
uint32 size() {
uint32 sz = 0;
if (_fp) {
int pos = gztell(_fp);
gzseek(_fp, 0, SEEK_END);
sz = gztell(_fp);
gzseek(_fp, pos, SEEK_SET);
}
return sz;
}
void seek(int32 off) {
if (_fp) {
gzseek(_fp, off, SEEK_SET);
}
}
void read(void *ptr, uint32 len) {
if (_fp) {
uint32 r = gzread(_fp, ptr, len);
if (r != len) {
_ioErr = true;
}
}
}
void write(void *ptr, uint32 len) {
if (_fp) {
uint32 r = gzwrite(_fp, ptr, len);
if (r != len) {
_ioErr = true;
}
}
}
};
File::File(bool gzipped) {
if (gzipped) {
_impl = new zlibFile;
} else {
_impl = new stdFile;
}
}
File::~File() {
_impl->close();
delete _impl;
}
bool File::open(const char *filename, const char *directory, const char *mode) {
_impl->close();
char buf[512];
sprintf(buf, "%s/%s", directory, filename);
char *p = buf + strlen(directory) + 1;
string_lower(p);
bool opened = _impl->open(buf, mode);
if (!opened) { // let's try uppercase
string_upper(p);
opened = _impl->open(buf, mode);
}
return opened;
}
void File::close() {
_impl->close();
}
bool File::ioErr() const {
return _impl->_ioErr;
}
uint32 File::size() {
return _impl->size();
}
void File::seek(int32 off) {
_impl->seek(off);
}
void File::read(void *ptr, uint32 len) {
_impl->read(ptr, len);
}
uint8 File::readByte() {
uint8 b;
read(&b, 1);
return b;
}
uint16 File::readUint16LE() {
uint8 lo = readByte();
uint8 hi = readByte();
return (hi << 8) | lo;
}
uint32 File::readUint32LE() {
uint16 lo = readUint16LE();
uint16 hi = readUint16LE();
return (hi << 16) | lo;
}
uint16 File::readUint16BE() {
uint8 hi = readByte();
uint8 lo = readByte();
return (hi << 8) | lo;
}
uint32 File::readUint32BE() {
uint16 hi = readUint16BE();
uint16 lo = readUint16BE();
return (hi << 16) | lo;
}
void File::write(void *ptr, uint32 len) {
_impl->write(ptr, len);
}
void File::writeByte(uint8 b) {
write(&b, 1);
}
void File::writeUint16BE(uint16 n) {
writeByte(n >> 8);
writeByte(n & 0xFF);
}
void File::writeUint32BE(uint32 n) {
writeUint16BE(n >> 16);
writeUint16BE(n & 0xFFFF);
}

View File

@@ -0,0 +1,49 @@
/* REminiscence - Flashback interpreter
* Copyright (C) 2005-2007 Gregory Montoir
*
* 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 2
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __FILE_H__
#define __FILE_H__
#include "intern.h"
struct File_impl;
struct File {
File(bool gzipped = false);
~File();
File_impl *_impl;
bool open(const char *filename, const char *directory, const char *mode);
void close();
bool ioErr() const;
uint32 size();
void seek(int32 off);
void read(void *ptr, uint32 len);
uint8 readByte();
uint16 readUint16LE();
uint32 readUint32LE();
uint16 readUint16BE();
uint32 readUint32BE();
void write(void *ptr, uint32 size);
void writeByte(uint8 b);
void writeUint16BE(uint16 n);
void writeUint32BE(uint32 n);
};
#endif // __FILE_H__

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,391 @@
/* REminiscence - Flashback interpreter
* Copyright (C) 2005-2007 Gregory Montoir
*
* 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 2
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __GAME_H__
#define __GAME_H__
#include "intern.h"
#include "cutscene.h"
#include "menu.h"
#include "mixer.h"
#include "mod_player.h"
#include "resource.h"
#include "sfx_player.h"
#include "video.h"
struct File;
struct SystemStub;
struct Game {
typedef int (Game::*pge_OpcodeProc)(ObjectOpcodeArgs *args);
typedef int (Game::*pge_ZOrderCallback)(LivePGE *, LivePGE *, uint8, uint8);
typedef int (Game::*col_Callback1)(LivePGE *, LivePGE *, int16, int16);
typedef int (Game::*col_Callback2)(LivePGE *, int16, int16, int16);
enum {
CT_UP_ROOM = 0x00,
CT_DOWN_ROOM = 0x40,
CT_RIGHT_ROOM = 0x80,
CT_LEFT_ROOM = 0xC0
};
static const Level _gameLevels[];
static const uint16 _scoreTable[];
static const uint8 _monsterListLevel1[];
static const uint8 _monsterListLevel2[];
static const uint8 _monsterListLevel3[];
static const uint8 _monsterListLevel4_1[];
static const uint8 _monsterListLevel4_2[];
static const uint8 _monsterListLevel5_1[];
static const uint8 _monsterListLevel5_2[];
static const uint8 *_monsterListLevels[];
static const uint8 _monsterPals[4][32];
static const char *_monsterNames[];
static const pge_OpcodeProc _pge_opcodeTable[];
static const uint8 _pge_modKeysTable[];
static const uint8 _protectionCodeData[];
static const uint8 _protectionPal[];
Cutscene _cut;
Menu _menu;
Mixer _mix;
ModPlayer _modPly;
Resource _res;
SfxPlayer _sfxPly;
Video _vid;
SystemStub *_stub;
const char *_savePath;
const uint8 *_stringsTable;
const char **_textsTable;
uint8 _currentLevel;
uint8 _skillLevel;
uint32 _score;
uint8 _currentRoom;
uint8 _currentIcon;
bool _loadMap;
uint8 _printLevelCodeCounter;
uint32 _randSeed;
uint16 _currentInventoryIconNum;
uint16 _curMonsterFrame;
uint16 _curMonsterNum;
uint8 _blinkingConradCounter;
uint16 _textToDisplay;
bool _eraseBackground;
AnimBufferState _animBuffer0State[41];
AnimBufferState _animBuffer1State[6]; // Conrad
AnimBufferState _animBuffer2State[42];
AnimBufferState _animBuffer3State[12];
AnimBuffers _animBuffers;
uint8 _bankData[0x7000];
uint8 *_firstBankData;
uint8 *_lastBankData;
BankSlot _bankSlots[49];
BankSlot *_curBankSlot;
const uint8 *_bankDataPtrs;
uint16 _deathCutsceneCounter;
bool _saveStateCompleted;
Game(SystemStub *, const char *dataPath, const char *savePath, Version ver);
void run();
void resetGameState();
void mainLoop();
void updateTiming();
void playCutscene(int id = -1);
void loadLevelMap();
void loadLevelData();
void start();
void drawIcon(uint8 iconNum, int16 x, int16 y, uint8 colMask);
void drawCurrentInventoryItem();
void printLevelCode();
void showFinalScore();
bool handleConfigPanel();
bool handleContinueAbort();
bool handleProtectionScreen();
void printSaveStateCompleted();
void drawLevelTexts();
void drawStoryTexts();
void prepareAnims();
void prepareAnimsHelper(LivePGE *pge, int16 dx, int16 dy);
void drawAnims();
void drawAnimBuffer(uint8 stateNum, AnimBufferState *state);
void drawObject(const uint8 *dataPtr, int16 x, int16 y, uint8 flags);
void drawObjectFrame(const uint8 *dataPtr, int16 x, int16 y, uint8 flags);
void decodeCharacterFrame(const uint8 *dataPtr, uint8 *dstPtr);
void drawCharacter(const uint8 *dataPtr, int16 x, int16 y, uint8 a, uint8 b, uint8 flags);
uint8 *loadBankData(uint16 MbkEntryNum);
int loadMonsterSprites(LivePGE *pge);
void playSound(uint8 sfxId, uint8 softVol);
uint16 getRandomNumber();
void changeLevel();
uint16 getLineLength(const uint8 *str) const;
void handleInventory();
uint8 *findBankData(uint16 entryNum);
// pieges
bool _pge_playAnimSound;
GroupPGE _pge_groups[256];
GroupPGE *_pge_groupsTable[256];
GroupPGE *_pge_nextFreeGroup;
LivePGE *_pge_liveTable2[256]; // active pieges list (index = pge number)
LivePGE *_pge_liveTable1[256]; // pieges list by room (index = room)
LivePGE _pgeLive[256];
uint8 _pge_currentPiegeRoom;
bool _pge_currentPiegeFacingDir; // (false == left)
bool _pge_processOBJ;
uint8 _pge_inpKeysMask;
uint16 _pge_opTempVar1;
uint16 _pge_opTempVar2;
uint16 _pge_compareVar1;
uint16 _pge_compareVar2;
void pge_resetGroups();
void pge_removeFromGroup(uint8 idx);
int pge_isInGroup(LivePGE *pge_dst, uint16 group_id, uint16 counter);
void pge_loadForCurrentLevel(uint16 idx);
void pge_process(LivePGE *pge);
void pge_setupNextAnimFrame(LivePGE *pge, GroupPGE *le);
void pge_playAnimSound(LivePGE *pge, uint16 arg2);
void pge_setupAnim(LivePGE *pge);
int pge_execute(LivePGE *live_pge, InitPGE *init_pge, const Object *obj);
void pge_prepare();
void pge_setupDefaultAnim(LivePGE *pge);
uint16 pge_processOBJ(LivePGE *pge);
void pge_setupOtherPieges(LivePGE *pge, InitPGE *init_pge);
void pge_addToCurrentRoomList(LivePGE *pge, uint8 room);
void pge_getInput();
int pge_op_isInpUp(ObjectOpcodeArgs *args);
int pge_op_isInpBackward(ObjectOpcodeArgs *args);
int pge_op_isInpDown(ObjectOpcodeArgs *args);
int pge_op_isInpForward(ObjectOpcodeArgs *args);
int pge_op_isInpUpMod(ObjectOpcodeArgs *args);
int pge_op_isInpBackwardMod(ObjectOpcodeArgs *args);
int pge_op_isInpDownMod(ObjectOpcodeArgs *args);
int pge_op_isInpForwardMod(ObjectOpcodeArgs *args);
int pge_op_isInpIdle(ObjectOpcodeArgs *args);
int pge_op_isInpNoMod(ObjectOpcodeArgs *args);
int pge_op_getCollision0u(ObjectOpcodeArgs *args);
int pge_op_getCollision00(ObjectOpcodeArgs *args);
int pge_op_getCollision0d(ObjectOpcodeArgs *args);
int pge_op_getCollision1u(ObjectOpcodeArgs *args);
int pge_op_getCollision10(ObjectOpcodeArgs *args);
int pge_op_getCollision1d(ObjectOpcodeArgs *args);
int pge_op_getCollision2u(ObjectOpcodeArgs *args);
int pge_op_getCollision20(ObjectOpcodeArgs *args);
int pge_op_getCollision2d(ObjectOpcodeArgs *args);
int pge_op_doesNotCollide0u(ObjectOpcodeArgs *args);
int pge_op_doesNotCollide00(ObjectOpcodeArgs *args);
int pge_op_doesNotCollide0d(ObjectOpcodeArgs *args);
int pge_op_doesNotCollide1u(ObjectOpcodeArgs *args);
int pge_op_doesNotCollide10(ObjectOpcodeArgs *args);
int pge_op_doesNotCollide1d(ObjectOpcodeArgs *args);
int pge_op_doesNotCollide2u(ObjectOpcodeArgs *args);
int pge_op_doesNotCollide20(ObjectOpcodeArgs *args);
int pge_op_doesNotCollide2d(ObjectOpcodeArgs *args);
int pge_op_collides0o0d(ObjectOpcodeArgs *args);
int pge_op_collides2o2d(ObjectOpcodeArgs *args);
int pge_op_collides0o0u(ObjectOpcodeArgs *args);
int pge_op_collides2o2u(ObjectOpcodeArgs *args);
int pge_op_collides2u2o(ObjectOpcodeArgs *args);
int pge_op_isInGroup(ObjectOpcodeArgs *args);
int pge_op_updateGroup0(ObjectOpcodeArgs *args);
int pge_op_updateGroup1(ObjectOpcodeArgs *args);
int pge_op_updateGroup2(ObjectOpcodeArgs *args);
int pge_op_updateGroup3(ObjectOpcodeArgs *args);
int pge_op_isPiegeDead(ObjectOpcodeArgs *args);
int pge_op_collides1u2o(ObjectOpcodeArgs *args);
int pge_op_collides1u1o(ObjectOpcodeArgs *args);
int pge_op_collides1o1u(ObjectOpcodeArgs *args);
int pge_o_unk0x2B(ObjectOpcodeArgs *args);
int pge_o_unk0x2C(ObjectOpcodeArgs *args);
int pge_o_unk0x2D(ObjectOpcodeArgs *args);
int pge_op_nop(ObjectOpcodeArgs *args);
int pge_op_pickupObject(ObjectOpcodeArgs *args);
int pge_op_addItemToInventory(ObjectOpcodeArgs *args);
int pge_op_copyPiege(ObjectOpcodeArgs *args);
int pge_op_canUseCurrentInventoryItem(ObjectOpcodeArgs *args);
int pge_op_removeItemFromInventory(ObjectOpcodeArgs *args);
int pge_o_unk0x34(ObjectOpcodeArgs *args);
int pge_op_isInpMod(ObjectOpcodeArgs *args);
int pge_op_setCollisionState1(ObjectOpcodeArgs *args);
int pge_op_setCollisionState0(ObjectOpcodeArgs *args);
int pge_op_isInGroup1(ObjectOpcodeArgs *args);
int pge_op_isInGroup2(ObjectOpcodeArgs *args);
int pge_op_isInGroup3(ObjectOpcodeArgs *args);
int pge_op_isInGroup4(ObjectOpcodeArgs *args);
int pge_o_unk0x3C(ObjectOpcodeArgs *args);
int pge_o_unk0x3D(ObjectOpcodeArgs *args);
int pge_op_setPiegeCounter(ObjectOpcodeArgs *args);
int pge_op_decPiegeCounter(ObjectOpcodeArgs *args);
int pge_o_unk0x40(ObjectOpcodeArgs *args);
int pge_op_wakeUpPiege(ObjectOpcodeArgs *args);
int pge_op_removePiege(ObjectOpcodeArgs *args);
int pge_op_removePiegeIfNotNear(ObjectOpcodeArgs *args);
int pge_op_loadPiegeCounter(ObjectOpcodeArgs *args);
int pge_o_unk0x45(ObjectOpcodeArgs *args);
int pge_o_unk0x46(ObjectOpcodeArgs *args);
int pge_o_unk0x47(ObjectOpcodeArgs *args);
int pge_o_unk0x48(ObjectOpcodeArgs *args);
int pge_o_unk0x49(ObjectOpcodeArgs *args);
int pge_o_unk0x4A(ObjectOpcodeArgs *args);
int pge_op_killPiege(ObjectOpcodeArgs *args);
int pge_op_isInCurrentRoom(ObjectOpcodeArgs *args);
int pge_op_isNotInCurrentRoom(ObjectOpcodeArgs *args);
int pge_op_scrollPosY(ObjectOpcodeArgs *args);
int pge_op_playDefaultDeathCutscene(ObjectOpcodeArgs *args);
int pge_o_unk0x50(ObjectOpcodeArgs *args);
int pge_o_unk0x52(ObjectOpcodeArgs *args);
int pge_o_unk0x53(ObjectOpcodeArgs *args);
int pge_op_isPiegeNear(ObjectOpcodeArgs *args);
int pge_op_setLife(ObjectOpcodeArgs *args);
int pge_op_incLife(ObjectOpcodeArgs *args);
int pge_op_setPiegeDefaultAnim(ObjectOpcodeArgs *args);
int pge_op_setLifeCounter(ObjectOpcodeArgs *args);
int pge_op_decLifeCounter(ObjectOpcodeArgs *args);
int pge_op_playCutscene(ObjectOpcodeArgs *args);
int pge_op_isTempVar2Set(ObjectOpcodeArgs *args);
int pge_op_playDeathCutscene(ObjectOpcodeArgs *args);
int pge_o_unk0x5D(ObjectOpcodeArgs *args);
int pge_o_unk0x5E(ObjectOpcodeArgs *args);
int pge_o_unk0x5F(ObjectOpcodeArgs *args);
int pge_op_findAndCopyPiege(ObjectOpcodeArgs *args);
int pge_op_isInRandomRange(ObjectOpcodeArgs *args);
int pge_o_unk0x62(ObjectOpcodeArgs *args);
int pge_o_unk0x63(ObjectOpcodeArgs *args);
int pge_o_unk0x64(ObjectOpcodeArgs *args);
int pge_op_addToCredits(ObjectOpcodeArgs *args);
int pge_op_subFromCredits(ObjectOpcodeArgs *args);
int pge_o_unk0x67(ObjectOpcodeArgs *args);
int pge_op_setCollisionState2(ObjectOpcodeArgs *args);
int pge_op_saveState(ObjectOpcodeArgs *args);
int pge_o_unk0x6A(ObjectOpcodeArgs *args);
int pge_op_isInGroupSlice(ObjectOpcodeArgs *args);
int pge_o_unk0x6C(ObjectOpcodeArgs *args);
int pge_op_isCollidingObject(ObjectOpcodeArgs *args);
int pge_o_unk0x6E(ObjectOpcodeArgs *args);
int pge_o_unk0x6F(ObjectOpcodeArgs *args);
int pge_o_unk0x70(ObjectOpcodeArgs *args);
int pge_o_unk0x71(ObjectOpcodeArgs *args);
int pge_o_unk0x72(ObjectOpcodeArgs *args);
int pge_o_unk0x73(ObjectOpcodeArgs *args);
int pge_op_collides4u(ObjectOpcodeArgs *args);
int pge_op_doesNotCollide4u(ObjectOpcodeArgs *args);
int pge_op_isBelowConrad(ObjectOpcodeArgs *args);
int pge_op_isAboveConrad(ObjectOpcodeArgs *args);
int pge_op_isNotFacingConrad(ObjectOpcodeArgs *args);
int pge_op_isFacingConrad(ObjectOpcodeArgs *args);
int pge_op_collides2u1u(ObjectOpcodeArgs *args);
int pge_op_displayText(ObjectOpcodeArgs *args);
int pge_o_unk0x7C(ObjectOpcodeArgs *args);
int pge_op_playSound(ObjectOpcodeArgs *args);
int pge_o_unk0x7E(ObjectOpcodeArgs *args);
int pge_o_unk0x7F(ObjectOpcodeArgs *args);
int pge_op_setPiegePosX(ObjectOpcodeArgs *args);
int pge_op_setPiegePosModX(ObjectOpcodeArgs *args);
int pge_op_changeRoom(ObjectOpcodeArgs *args);
int pge_op_hasInventoryItem(ObjectOpcodeArgs *args);
int pge_op_changeLevel(ObjectOpcodeArgs *args);
int pge_op_shakeScreen(ObjectOpcodeArgs *args);
int pge_o_unk0x86(ObjectOpcodeArgs *args);
int pge_op_playSoundGroup(ObjectOpcodeArgs *args);
int pge_op_adjustPos(ObjectOpcodeArgs *args);
int pge_op_setTempVar1(ObjectOpcodeArgs *args);
int pge_op_isTempVar1Set(ObjectOpcodeArgs *args);
int pge_setCurrentInventoryObject(LivePGE *pge);
void pge_updateInventory(LivePGE *pge1, LivePGE *pge2);
void pge_reorderInventory(LivePGE *pge);
LivePGE *pge_getInventoryItemBefore(LivePGE *pge, LivePGE *last_pge);
void pge_addToInventory(LivePGE *pge1, LivePGE *pge2, LivePGE *pge3);
int pge_updateCollisionState(LivePGE *pge, int16 pge_dy, uint8 var8);
int pge_ZOrder(LivePGE *pge, int16 num, pge_ZOrderCallback compare, uint16 unk);
void pge_updateGroup(uint8 idx, uint8 unk1, int16 unk2);
void pge_removeFromInventory(LivePGE *pge1, LivePGE *pge2, LivePGE *pge3);
int pge_ZOrderByAnimY(LivePGE *pge1, LivePGE *pge2, uint8 comp, uint8 comp2);
int pge_ZOrderByAnimYIfType(LivePGE *pge1, LivePGE *pge2, uint8 comp, uint8 comp2);
int pge_ZOrderIfIndex(LivePGE *pge1, LivePGE *pge2, uint8 comp, uint8 comp2);
int pge_ZOrderByIndex(LivePGE *pge1, LivePGE *pge2, uint8 comp, uint8 comp2);
int pge_ZOrderByObj(LivePGE *pge1, LivePGE *pge2, uint8 comp, uint8 comp2);
int pge_ZOrderIfDifferentDirection(LivePGE *pge1, LivePGE *pge2, uint8 comp, uint8 comp2);
int pge_ZOrderIfSameDirection(LivePGE *pge1, LivePGE *pge2, uint8 comp, uint8 comp2);
int pge_ZOrderIfTypeAndSameDirection(LivePGE *pge1, LivePGE *pge2, uint8 comp, uint8 comp2);
int pge_ZOrderIfTypeAndDifferentDirection(LivePGE *pge1, LivePGE *pge2, uint8 comp, uint8 comp2);
int pge_ZOrderByNumber(LivePGE *pge1, LivePGE *pge2, uint8 comp, uint8 comp2);
// collision
CollisionSlot _col_slots[256];
uint8 _col_curPos;
CollisionSlot *_col_slotsTable[256];
CollisionSlot *_col_curSlot;
CollisionSlot2 _col_slots2[256];
CollisionSlot2 *_col_slots2Cur;
CollisionSlot2 *_col_slots2Next;
uint8 _col_activeCollisionSlots[0x30 * 3]; // left, current, right
uint8 _col_currentLeftRoom;
uint8 _col_currentRightRoom;
int16 _col_currentPiegeGridPosX;
int16 _col_currentPiegeGridPosY;
void col_prepareRoomState();
void col_clearState();
LivePGE *col_findPiege(LivePGE *pge, uint16 arg2);
int16 col_findSlot(int16 pos);
void col_preparePiegeState(LivePGE *dst_pge);
uint16 col_getGridPos(LivePGE *pge, int16 dx);
int16 col_getGridData(LivePGE *pge, int16 dy, int16 dx);
uint8 col_findCurrentCollidingObject(LivePGE *pge, uint8 n1, uint8 n2, uint8 n3, LivePGE **pge_out);
int16 col_detectHit(LivePGE *pge, int16 arg2, int16 arg4, col_Callback1 callback1, col_Callback2 callback2, int16 argA, int16 argC);
int col_detectHitCallback2(LivePGE *pge1, LivePGE *pge2, int16 unk1, int16 unk2);
int col_detectHitCallback3(LivePGE *pge1, LivePGE *pge2, int16 unk1, int16 unk2);
int col_detectHitCallback4(LivePGE *pge1, LivePGE *pge2, int16 unk1, int16 unk2);
int col_detectHitCallback5(LivePGE *pge1, LivePGE *pge2, int16 unk1, int16 unk2);
int col_detectHitCallback1(LivePGE *pge, int16 dy, int16 unk1, int16 unk2);
int col_detectHitCallback6(LivePGE *pge, int16 dy, int16 unk1, int16 unk2);
int col_detectHitCallbackHelper(LivePGE *pge, int16 unk1);
int col_detectGunHitCallback1(LivePGE *pge, int16 arg2, int16 arg4, int16 arg6);
int col_detectGunHitCallback2(LivePGE *pge1, LivePGE *pge2, int16 arg4, int16);
int col_detectGunHitCallback3(LivePGE *pge1, LivePGE *pge2, int16 arg4, int16);
int col_detectGunHit(LivePGE *pge, int16 arg2, int16 arg4, col_Callback1 callback1, col_Callback2 callback2, int16 argA, int16 argC);
// input
uint8 _inp_lastKeysHit;
uint8 _inp_lastKeysHitLeftRight;
bool _inp_replay;
bool _inp_record;
File *_inp_demo;
void inp_handleSpecialKeys();
void inp_update();
// save/load state
uint8 _stateSlot;
bool _validSaveState;
void makeGameDemoName(char *buf);
void makeGameStateName(uint8 slot, char *buf);
bool saveGameState(uint8 slot);
bool loadGameState(uint8 slot);
void saveState(File *f);
void loadState(File *f);
};
#endif // __GAME_H__

View File

@@ -0,0 +1,718 @@
/* REminiscence - Flashback interpreter
* Copyright (C) 2005-2007 Gregory Montoir
*
* 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 2
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "graphics.h"
void Graphics::setClippingRect(int16 rx, int16 ry, int16 rw, int16 rh) {
debug(DBG_VIDEO, "Graphics::setClippingRect(%d, %d, %d, %d)", rx, ry, rw, rh);
_crx = rx;
_cry = ry;
_crw = rw;
_crh = rh;
}
void Graphics::drawPoint(uint8 color, const Point *pt) {
debug(DBG_VIDEO, "Graphics::drawPoint() col=0x%X x=%d, y=%d", color, pt->x, pt->y);
if (pt->x >= 0 && pt->x < _crw && pt->y >= 0 && pt->y < _crh) {
*(_layer + (pt->y + _cry) * 256 + pt->x + _crx) = color;
}
}
void Graphics::drawLine(uint8 color, const Point *pt1, const Point *pt2) {
debug(DBG_VIDEO, "Graphics::drawLine()");
int16 dxincr1 = 1;
int16 dyincr1 = 1;
int16 dx = pt2->x - pt1->x;
if (dx < 0) {
dxincr1 = -1;
dx = -dx;
}
int16 dy = pt2->y - pt1->y;
if (dy < 0) {
dyincr1 = -1;
dy = -dy;
}
int16 dxincr2, dyincr2, delta1, delta2;
if (dx < dy) {
dxincr2 = 0;
dyincr2 = 1;
delta1 = dx;
delta2 = dy;
if (dyincr1 < 0) {
dyincr2 = -1;
}
} else {
dxincr2 = 1;
dyincr2 = 0;
delta1 = dy;
delta2 = dx;
if (dxincr1 < 0) {
dxincr2 = -1;
}
}
Point pt;
pt.x = pt1->x;
pt.y = pt1->y;
int16 octincr1 = delta1 * 2 - delta2 * 2;
int16 octincr2 = delta1 * 2;
int16 oct = delta1 * 2 - delta2;
if (delta2 >= 0) {
drawPoint(color, &pt);
while (--delta2 >= 0) {
if (oct >= 0) {
pt.x += dxincr1;
pt.y += dyincr1;
oct += octincr1;
} else {
pt.x += dxincr2;
pt.y += dyincr2;
oct += octincr2;
}
drawPoint(color, &pt);
}
}
}
void Graphics::addEllipseRadius(int16 y, int16 x1, int16 x2) {
debug(DBG_VIDEO, "Graphics::addEllipseRadius()");
if (y >= 0 && y <= _crh) {
y = (y - _areaPoints[0]) * 2;
if (x1 < 0) {
x1 = 0;
}
if (x2 >= _crw) {
x2 = _crw - 1;
}
_areaPoints[y + 1] = x1;
_areaPoints[y + 2] = x2;
}
}
void Graphics::drawEllipse(uint8 color, bool hasAlpha, const Point *pt, int16 rx, int16 ry) {
debug(DBG_VIDEO, "Graphics::drawEllipse()");
bool flag = false;
int16 y = pt->y - ry;
if (y < 0) {
y = 0;
}
if (y < _crh) {
if (pt->y + ry >= 0) {
_areaPoints[0] = y;
int32 dy = 0;
int32 rxsq = rx * rx;
int32 rxsq2 = rx * rx * 2;
int32 rxsq4 = rx * rx * 4;
int32 rysq = ry * ry;
int32 rysq2 = ry * ry * 2;
int32 rysq4 = ry * ry * 4;
int32 dx = 0;
int32 b = rx * ((rysq2 & 0xFFFF) + (rysq2 >> 16));
int32 a = 2 * b;
int32 ny1, ny2, nx1, nx2;
ny1 = ny2 = rysq4 / 2 - a + rxsq;
nx1 = nx2 = rxsq2 - b + rysq;
while (ny2 < 0) {
int16 x2 = pt->x + rx;
int16 x1 = pt->x - rx;
int16 by = pt->y + dy;
int16 ty = pt->y - dy;
if (x1 != x2) {
addEllipseRadius(by, x1, x2);
if (ty < by) {
addEllipseRadius(ty, x1, x2);
}
}
dy += 1;
dx += rxsq4;
nx1 = dx;
if (nx2 < 0) {
nx2 += nx1 + rxsq2;
ny2 += nx1;
} else {
--rx;
a -= rysq4;
ny1 = a;
nx2 += nx1 + rxsq2 - ny1;
ny2 += nx1 + rysq2 - ny1;
}
}
while (rx >= 0) {
bool flag2 = false;
int16 x2 = pt->x + rx;
int16 x1 = pt->x - rx;
int16 by = pt->y + dy;
int16 ty = pt->y - dy;
if (!flag && x1 != x2) {
flag2 = true;
addEllipseRadius(by, x1, x2);
if (ty < by) {
addEllipseRadius(ty, x1, x2);
}
}
if (flag2) {
flag = true;
}
--rx;
a -= rysq4;
nx1 = a;
if (ny2 < 0) {
++dy;
flag = false;
dx += rxsq4;
ny2 += dx - nx1 + rysq2;
ny1 = dx - nx1 + rysq2;
} else {
ny2 += rysq2 - nx1;
ny1 = rysq2 - nx1;
}
}
if (flag) {
++dy;
}
while (dy <= ry) {
int16 ty = pt->y - dy;
int16 by = pt->y + dy;
if (ty < by) {
addEllipseRadius(ty, pt->x, pt->x);
}
addEllipseRadius(by, pt->x, pt->x);
++dy;
}
y = pt->y + ry + 1;
if (y > _crh) {
y = _crh;
}
y = (y - _areaPoints[0]) * 2;
_areaPoints[y + 1] = -1;
fillArea(color, hasAlpha);
}
}
}
void Graphics::fillArea(uint8 color, bool hasAlpha) {
debug(DBG_VIDEO, "Graphics::fillArea()");
int16 *pts = _areaPoints;
uint8 *dst = _layer + (_cry + *pts++) * 256 + _crx;
int16 x1 = *pts++;
if (x1 >= 0) {
if (hasAlpha && color > 0xC7) {
do {
int16 x2 = *pts++;
if (x2 < _crw && x2 >= x1) {
int len = x2 - x1 + 1;
for (int i = 0; i < len; ++i) {
*(dst + x1 + i) |= color & 8; // XXX 0x88
}
}
dst += 256;
x1 = *pts++;
} while (x1 >= 0);
} else {
do {
int16 x2 = *pts++;
if (x2 < _crw && x2 >= x1) {
int len = x2 - x1 + 1;
memset(dst + x1, color, len);
}
dst += 256;
x1 = *pts++;
} while (x1 >= 0);
}
}
}
void Graphics::drawSegment(uint8 color, bool hasAlpha, int16 ys, const Point *pts, uint8 numPts) {
debug(DBG_VIDEO, "Graphics::drawSegment()");
int16 xmin, xmax, ymin, ymax;
xmin = xmax = pts[0].x;
ymin = ymax = pts[0].y;
for (int i = 1; i < numPts; ++i) {
int16 x = pts[i].x;
int16 y = pts[i].y;
if ((xmin << 16) + ymin > (x << 16) + y) {
xmin = x;
ymin = y;
}
if ((xmax << 16) + ymax < (x << 16) + y) {
xmax = x;
ymax = y;
}
}
if (xmin < 0) {
xmin = 0;
}
if (xmax >= _crw) {
xmax = _crw - 1;
}
_areaPoints[0] = ys;
_areaPoints[1] = xmin;
_areaPoints[2] = xmax;
_areaPoints[3] = -1;
fillArea(color, hasAlpha);
}
void Graphics::drawPolygonOutline(uint8 color, const Point *pts, uint8 numPts) {
debug(DBG_VIDEO, "Graphics::drawPolygonOutline()");
assert(numPts >= 2);
int i;
for (i = 0; i < numPts - 1; ++i) {
drawLine(color, &pts[i], &pts[i + 1]);
}
drawLine(color, &pts[i], &pts[0]);
}
static int32 calcPolyStep1(int16 dx, int16 dy) {
debug(DBG_VIDEO, "Graphics::calcPolyStep1()");
assert(dy != 0);
int32 a = dx * 256;
if ((a >> 16) < dy) {
a = ((int16)(a / dy)) * 256;
} else {
a = ((a / 256) / dy) & 0xFFFF0000;
}
return a;
}
static int32 calcPolyStep2(int16 dx, int16 dy) {
debug(DBG_VIDEO, "Graphics::calcPolyStep2()");
assert(dy != 0);
int32 a = dx * 256;
if ((a >> 16) < dy) {
a = ((int16)(a / dy)) * 256;
} else {
a = ((a / 256) / dy) << 16;
}
return a;
}
static void drawPolygonHelper1(int32 &x, int16 &y, int32 &step, int16 *&pts, int16 *&start) {
bool first = true;
x = pts[0];
y = pts[1];
int16 dy, dx;
do {
if (first) {
first = false;
} else {
x = *pts;
}
--pts;
dy = *pts - y;
--pts;
dx = *pts - x;
} while (dy <= 0 && start < pts);
x <<= 16;
if (dy > 0) {
step = calcPolyStep1(dx, dy);
}
}
static void drawPolygonHelper2(int32 &x, int16 &y, int32 &step, int16 *&pts, int16 *&start) {
bool first = true;
x = *start++;
y = *start++;
int16 dy, dx;
do {
if (first) {
first = false;
} else {
x = *start;
start += 2;
}
dy = start[1] - y;
dx = start[0] - x;
} while (dy <= 0 && start < pts);
x <<= 16;
if (dy > 0) {
step = calcPolyStep2(dx, dy);
}
}
void Graphics::drawPolygon(uint8 color, bool hasAlpha, const Point *pts, uint8 numPts) {
debug(DBG_VIDEO, "Graphics::drawPolygon()");
assert(numPts * 4 < 0x100);
int16 *apts1 = &_areaPoints[0x100];
int16 *apts2 = &_areaPoints[0x100 + numPts * 2];
int16 xmin, xmax, ymin, ymax;
xmin = xmax = pts[0].x;
ymin = ymax = pts[0].y;
int16 *spts = apts1;
*apts1++ = *apts2++ = pts[0].x;
*apts1++ = *apts2++ = pts[0].y;
for (int p = 1; p < numPts; ++p) {
int16 x = pts[p].x;
int16 y = pts[p].y;
if (ymin > y) {
ymin = y;
spts = apts1;
}
if (ymax < y) {
ymax = y;
}
*apts1++ = *apts2++ = x;
*apts1++ = *apts2++ = y;
if (xmin > x) {
xmin = x;
}
if (xmax < x) {
xmax = x;
}
}
int16 *rpts = _areaPoints;
if (xmax < 0 || xmin >= _crw || ymax < 0 || ymin >= _crh) {
return;
}
if (numPts == 2) {
drawLine(color, &pts[0], &pts[1]);
return;
}
if (ymax == ymin) {
drawSegment(color, hasAlpha, ymax, pts, numPts);
return;
}
int16 x, dx, y, dy;
int32 a, b, d, f;
int32 xstep1 = 0;
int32 xstep2 = 0;
apts1 = &spts[numPts * 2];
xmax = _crw - 1;
ymax = _crh - 1;
int32 l1 = 65536;
int32 l2 = -65536;
if (ymin < 0) {
int16 x0, y0;
do {
--apts1;
y0 = *apts1;
--apts1;
x0 = *apts1;
} while (y0 < 0);
x = apts1[2];
y = apts1[3];
dy = y0 - y;
dx = x0 - x;
xstep1 = (dy << 16) | dx;
assert(dy != 0);
a = y * dx / dy;
b = (x - a) << 16;
d = xstep1 = calcPolyStep1(dx, dy);
if (d < 0) {
d = -d;
}
if (d < l1) {
d = l2;
}
d /= 2;
b -= d;
do {
x0 = *spts++;
y0 = *spts++;
} while (*(spts + 1) < 0);
dy = spts[1] - y0;
dx = spts[0] - x0;
xstep2 = (dy << 16) | dx;
assert(dy != 0);
a = y0 * dx / dy;
f = (x0 - a) << 16;
d = xstep2 = calcPolyStep2(dx, dy);
if (d < 0) {
d = -d;
}
if (d < l1) {
d = l1;
}
d /= 2;
f += d;
ymin = 0;
*rpts++ = 0;
goto gfx_startLine;
}
*rpts++ = ymin;
gfx_startNewLine:
drawPolygonHelper2(f, ymin, xstep2, apts1, spts);
if (spts >= apts1) {
b = apts1[0] << 16;
dy = apts1[1];
if (dy <= ymax) goto gfx_endLine;
goto gfx_fillArea;
}
drawPolygonHelper1(b, ymin, xstep1, apts1, spts);
d = xstep1;
if (d < 0) {
if (d >= l2) {
d = l1;
}
d /= 2;
b += d;
}
d = xstep2;
if (d >= 0) {
if (d <= l1) {
d = l1;
}
d /= 2;
f += d;
}
d = b;
if (d < 0) {
d = 0;
}
x = f >> 16;
if (x > xmax) {
x = xmax;
}
*rpts++ = d >> 16;
*rpts++ = x;
++ymin;
d = xstep1;
if (d >= 0) {
if (d <= l1) {
d = l1;
}
d /= 2;
}
b += d;
d = xstep2;
if (d < 0) {
if (d >= l2) {
d = l1;
}
d /= 2;
}
f += d;
gfx_startLine:
while (1) {
dy = apts1[1];
if (spts >= apts1) {
break;
} else if (dy > spts[1]) {
dy = spts[1];
if (dy > ymax) {
goto gfx_drawPolygonEnd;
}
dy -= ymin;
if (dy > 0) {
--dy;
do {
a = b;
if (a < 0) {
a = 0;
}
x = f >> 16;
if (x > xmax) {
x = xmax;
}
*rpts++ = a >> 16;
*rpts++ = x;
b += xstep1;
f += xstep2;
--dy;
} while (dy >= 0);
}
drawPolygonHelper2(f, ymin, xstep2, apts1, spts);
d = xstep2;
if (d >= 0) {
if (d <= l1) {
d = l1;
}
d /= 2;
f += d;
} else {
d = b;
if (d < 0) {
d = 0;
}
x = f >> 16;
if (x > xmax) {
x = xmax;
}
*rpts++ = d >> 16;
*rpts++ = x;
++ymin;
d = xstep2;
if (d >= l2) {
d = l1;
}
d /= 2;
f += d;
b += xstep1;
}
} else if (dy == spts[1]) {
if (dy > ymax) goto gfx_drawPolygonEnd;
dy -= ymin;
if (dy > 0) {
--dy;
do {
a = b;
if (a < 0) {
a = 0;
}
x = f >> 16;
if (x > xmax) {
x = xmax;
}
*rpts++ = a >> 16;
*rpts++ = x;
b += xstep1;
f += xstep2;
--dy;
} while (dy >= 0);
}
goto gfx_startNewLine;
} else if (dy > ymax) {
goto gfx_drawPolygonEnd;
} else {
dy -= ymin;
if (dy > 0) {
--dy;
do {
a = b;
if (a < 0) {
a = 0;
}
x = f >> 16;
if (x > xmax) {
x = xmax;
}
*rpts++ = a >> 16;
*rpts++ = x;
b += xstep1;
f += xstep2;
--dy;
} while (dy >= 0);
}
drawPolygonHelper1(b, ymin, xstep1, apts1, spts);
d = xstep1;
if (d < 0) {
if (d >= l2) {
d = l1;
}
d /= 2;
b += d;
} else {
d = b;
if (d < 0) {
d = 0;
}
x = f >> 16;
if (x > xmax) {
x = xmax;
}
*rpts++ = d >> 16;
*rpts++ = x;
++ymin;
d = xstep1;
if (d <= l1) {
d = l1;
}
d /= 2;
b += d;
f += xstep2;
}
}
}
if (dy > ymax) goto gfx_drawPolygonEnd;
dy -= ymin;
if (dy < 0) goto gfx_fillArea;
if (dy > 0) {
--dy;
do {
a = b;
if (a < 0) {
a = 0;
}
x = f >> 16;
if (x > xmax) {
x = xmax;
}
*rpts++ = a >> 16;
*rpts++ = x;
b += xstep1;
f += xstep2;
--dy;
} while (dy >= 0);
}
b = f = (apts1[0] << 16) | apts1[1];
gfx_endLine:
d = xstep1;
if (d >= 0) {
if (d >= l1) {
d /= 2;
b -= d;
}
}
d = xstep2;
if (d < 0) {
d /= 2;
f -= d;
}
a = b;
if (a < 0) {
a = 0;
}
x = f >> 16;
if (x > xmax) {
x = xmax;
}
*rpts++ = a >> 16;
*rpts++ = x;
goto gfx_fillArea;
gfx_drawPolygonEnd:
dy = ymax - ymin;
if (dy >= 0) {
do {
a = b;
if (a < 0) {
a = 0;
}
x = f >> 16;
if (x > xmax) {
x = xmax;
}
*rpts++ = a >> 16;
*rpts++ = x;
b += xstep1;
f += xstep2;
--dy;
} while (dy >= 0);
}
gfx_fillArea:
*rpts++ = -1;
fillArea(color, hasAlpha);
}

View File

@@ -0,0 +1,40 @@
/* REminiscence - Flashback interpreter
* Copyright (C) 2005-2007 Gregory Montoir
*
* 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 2
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __GRAPHICS_H__
#define __GRAPHICS_H__
#include "intern.h"
struct Graphics {
uint8 *_layer;
int16 _areaPoints[0x200];
int16 _crx, _cry, _crw, _crh;
void setClippingRect(int16 vx, int16 vy, int16 vw, int16 vh);
void drawPoint(uint8 color, const Point *pt);
void drawLine(uint8 color, const Point *pt1, const Point *pt2);
void addEllipseRadius(int16 y, int16 x1, int16 x2);
void drawEllipse(uint8 color, bool hasAlpha, const Point *pt, int16 rx, int16 ry);
void fillArea(uint8 color, bool hasAlpha);
void drawSegment(uint8 color, bool hasAlpha, int16 ys, const Point *pts, uint8 numPts);
void drawPolygonOutline(uint8 color, const Point *pts, uint8 numPts);
void drawPolygon(uint8 color, bool hasAlpha, const Point *pts, uint8 numPts);
};
#endif // __GRAPHICS_H__

View File

@@ -0,0 +1,193 @@
/* REminiscence - Flashback interpreter
* Copyright (C) 2005-2007 Gregory Montoir
*
* 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 2
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __INTERN_H__
#define __INTERN_H__
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cassert>
#include "sys.h"
#include "util.h"
#define MAX(x,y) ((x)>(y)?(x):(y))
#define MIN(x,y) ((x)<(y)?(x):(y))
#define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
template<typename T>
inline void SWAP(T &a, T &b) {
T tmp = a;
a = b;
b = tmp;
}
enum Version {
VER_FR,
VER_EN,
VER_DE,
VER_SP
};
struct Color {
uint8 r;
uint8 g;
uint8 b;
};
struct Point {
int16 x;
int16 y;
};
struct Level {
const char *name;
const char *name2;
uint16 cutscene_id;
};
struct InitPGE {
uint16 type;
int16 pos_x;
int16 pos_y;
uint16 obj_node_number;
uint16 life;
int16 counter_values[4];
uint8 object_type;
uint8 init_room;
uint8 room_location;
uint8 init_flags;
uint8 colliding_icon_num;
uint8 icon_num;
uint8 object_id;
uint8 skill;
uint8 mirror_x;
uint8 flags;
uint8 unk1C; // collidable, collision_data_len
uint8 text_num;
};
struct LivePGE {
uint16 obj_type;
int16 pos_x;
int16 pos_y;
uint8 anim_seq;
uint8 room_location;
int16 life;
int16 counter_value;
uint8 collision_slot;
uint8 next_inventory_PGE;
uint8 current_inventory_PGE;
uint8 unkF; // unk_inventory_PGE
uint16 anim_number;
uint8 flags;
uint8 index;
uint16 first_obj_number;
LivePGE *next_PGE_in_room;
InitPGE *init_PGE;
};
struct GroupPGE {
GroupPGE *next_entry;
uint16 index;
uint16 group_id;
};
struct Object {
uint16 type;
int8 dx;
int8 dy;
uint16 init_obj_type;
uint8 opcode2;
uint8 opcode1;
uint8 flags;
uint8 opcode3;
uint16 init_obj_number;
int16 opcode_arg1;
int16 opcode_arg2;
int16 opcode_arg3;
};
struct ObjectNode {
uint16 last_obj_number;
Object *objects;
uint16 num_objects;
};
struct ObjectOpcodeArgs {
LivePGE *pge; // arg0
int16 a; // arg2
int16 b; // arg4
};
struct AnimBufferState {
int16 x;
int16 y;
const uint8 *dataPtr;
LivePGE *pge;
};
struct AnimBuffers {
AnimBufferState *_states[4];
uint8 _curPos[4];
void addState(uint8 stateNum, int16 x, int16 y, const uint8 *dataPtr, LivePGE *pge);
};
struct CollisionSlot {
int16 ct_pos;
CollisionSlot *prev_slot;
LivePGE *live_pge;
uint16 index;
};
struct MbkEntry {
uint16 offset;
uint16 len;
};
struct BankSlot {
uint16 entryNum;
uint8 *ptr;
};
struct CollisionSlot2 {
CollisionSlot2 *next_slot;
int8 *unk2;
uint8 data_size;
uint8 data_buf[0x10]; // XXX check size
};
struct InventoryItem {
uint8 icon_num;
InitPGE *init_pge;
LivePGE *live_pge;
};
struct SoundFx {
uint32 offset;
uint16 len;
uint8 *data;
};
#endif // __INTERN_H__

View File

@@ -0,0 +1,50 @@
/* REminiscence - Flashback interpreter
* Copyright (C) 2005-2006 Gregory Montoir
*
* 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 2
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "locale.h"
Locale::Locale(Version ver)
: _ver(ver) {
switch (_ver) {
case VER_FR:
_stringsTable = _stringsTableFR;
_textsTable = _textsTableFR;
break;
case VER_EN:
_stringsTable = _stringsTableEN;
_textsTable = _textsTableEN;
break;
case VER_DE:
_stringsTable = _stringsTableDE;
_textsTable = _textsTableDE;
break;
case VER_SP:
_stringsTable = _stringsTableSP;
_textsTable = _textsTableSP;
break;
}
}
const char *Locale::get(int id) const {
const char *text = 0;
if (id >= 0 && id < LI_NUM) {
text = _textsTable[id];
}
return text;
}

View File

@@ -0,0 +1,69 @@
/* REminiscence - Flashback interpreter
* Copyright (C) 2005-2006 Gregory Montoir
*
* 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 2
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __LOCALE_H__
#define __LOCALE_H__
#include "intern.h"
struct Locale {
enum Id {
LI_01_CONTINUE_OR_ABORT = 0,
LI_02_TIME,
LI_03_CONTINUE,
LI_04_ABORT,
LI_05_COMPLETED,
LI_06_LEVEL,
LI_07_START,
LI_08_SKILL,
LI_09_PASSWORD,
LI_10_INFO,
LI_11_QUIT,
LI_12_SKILL_LEVEL,
LI_13_EASY,
LI_14_NORMAL,
LI_15_EXPERT,
LI_16_ENTER_PASSWORD1,
LI_17_ENTER_PASSWORD2,
LI_18_RESUME_GAME,
LI_19_ABORT_GAME,
LI_20_LOAD_GAME,
LI_21_SAVE_GAME,
LI_22_SAVE_SLOT,
LI_NUM
};
static const char *_textsTableFR[];
static const char *_textsTableEN[];
static const char *_textsTableDE[];
static const char *_textsTableSP[];
static const uint8 _stringsTableFR[];
static const uint8 _stringsTableEN[];
static const uint8 _stringsTableDE[];
static const uint8 _stringsTableSP[];
Version _ver;
const char **_textsTable;
const uint8 *_stringsTable;
Locale(Version ver);
const char *get(int id) const;
};
#endif // __LOCALE_H__

View File

@@ -0,0 +1,85 @@
/* REminiscence - Flashback interpreter
* Copyright (C) 2005-2007 Gregory Montoir
*
* 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 2
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "file.h"
#include "game.h"
#include "systemstub.h"
static const char *USAGE =
"REminiscence - Flashback Interpreter\n"
"Usage: rs [OPTIONS]...\n"
" --datapath=PATH Path to data files (default 'DATA')\n"
" --savepath=PATH Path to save files (default '.')";
static bool parseOption(const char *arg, const char *longCmd, const char **opt) {
bool handled = false;
if (arg[0] == '-' && arg[1] == '-') {
if (strncmp(arg + 2, longCmd, strlen(longCmd)) == 0) {
*opt = arg + 2 + strlen(longCmd);
handled = true;
}
}
return handled;
}
static Version detectVersion(const char *dataPath) {
static struct {
const char *filename;
Version ver;
} checkTable[] = {
{ "ENGCINE.BIN", VER_EN },
{ "FR_CINE.BIN", VER_FR },
{ "GERCINE.BIN", VER_DE },
{ "SPACINE.BIN", VER_SP }
};
for (uint8 i = 0; i < ARRAYSIZE(checkTable); ++i) {
File f;
if (f.open(checkTable[i].filename, dataPath, "rb")) {
return checkTable[i].ver;
}
}
error("Unable to find data files, check that all required files are present");
return VER_EN;
}
#undef main
#include <SDL.h>
int main(int argc, char *argv[]) {
const char *dataPath = "DATA";
const char *savePath = ".";
for (int i = 1; i < argc; ++i) {
bool opt = false;
if (strlen(argv[i]) >= 2) {
opt |= parseOption(argv[i], "datapath=", &dataPath);
opt |= parseOption(argv[i], "savepath=", &savePath);
}
if (!opt) {
printf(USAGE);
return 0;
}
}
Version ver = detectVersion(dataPath);
g_debugMask = DBG_INFO; // DBG_CUT | DBG_VIDEO | DBG_RES | DBG_MENU | DBG_PGE | DBG_GAME | DBG_UNPACK | DBG_COL | DBG_MOD | DBG_SFX;
SystemStub *stub = SystemStub_SDL_create();
Game *g = new Game(stub, dataPath, savePath, ver);
g->run();
delete g;
delete stub;
return 0;
}

View File

@@ -0,0 +1,316 @@
/* REminiscence - Flashback interpreter
* Copyright (C) 2005-2007 Gregory Montoir
*
* 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 2
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "game.h"
#include "mod_player.h"
#include "resource.h"
#include "systemstub.h"
#include "video.h"
#include "menu.h"
Menu::Menu(ModPlayer *ply, Resource *res, SystemStub *stub, Video *vid)
: _ply(ply), _res(res), _stub(stub), _vid(vid) {
}
void Menu::drawString(const char *str, int16 y, int16 x, uint8 color) {
debug(DBG_MENU, "Menu::drawString()");
uint8 v1b = _vid->_charFrontColor;
uint8 v2b = _vid->_charTransparentColor;
uint8 v3b = _vid->_charShadowColor;
switch (color) {
case 0:
_vid->_charFrontColor = _charVar1;
_vid->_charTransparentColor = _charVar2;
_vid->_charShadowColor = _charVar2;
break;
case 1:
_vid->_charFrontColor = _charVar2;
_vid->_charTransparentColor = _charVar1;
_vid->_charShadowColor = _charVar1;
break;
case 2:
_vid->_charFrontColor = _charVar3;
_vid->_charTransparentColor = 0xFF;
_vid->_charShadowColor = _charVar1;
break;
case 3:
_vid->_charFrontColor = _charVar4;
_vid->_charTransparentColor = 0xFF;
_vid->_charShadowColor = _charVar1;
break;
case 4:
_vid->_charFrontColor = _charVar2;
_vid->_charTransparentColor = 0xFF;
_vid->_charShadowColor = _charVar1;
break;
case 5:
_vid->_charFrontColor = _charVar2;
_vid->_charTransparentColor = 0xFF;
_vid->_charShadowColor = _charVar5;
break;
}
drawString2(str, y, x);
_vid->_charFrontColor = v1b;
_vid->_charTransparentColor = v2b;
_vid->_charShadowColor = v3b;
}
void Menu::drawString2(const char *str, int16 y, int16 x) {
debug(DBG_MENU, "Menu::drawString2()");
int len = 0;
while (*str) {
_vid->drawChar((uint8)*str, y, x + len);
++str;
++len;
}
_vid->markBlockAsDirty(x * 8, y * 8, len * 8, 8);
}
void Menu::loadPicture(const char *prefix) {
debug(DBG_MENU, "Menu::loadPicture('%s')", prefix);
_res->load_MAP_menu(prefix, _res->_memBuf);
for (int i = 0; i < 4; ++i) {
for (int y = 0; y < 224; ++y) {
for (int x = 0; x < 64; ++x) {
_vid->_frontLayer[i + x * 4 + 256 * y] = _res->_memBuf[0x3800 * i + x + 64 * y];
}
}
}
_res->load_PAL_menu(prefix, _res->_memBuf);
_stub->setPalette(_res->_memBuf, 256);
}
void Menu::handleInfoScreen() {
debug(DBG_MENU, "Menu::handleInfoScreen()");
_vid->fadeOut();
switch (_res->_ver) {
case VER_FR:
loadPicture("instru_f");
break;
case VER_EN:
case VER_DE:
case VER_SP:
loadPicture("instru_e");
break;
}
_vid->fullRefresh();
_vid->updateScreen();
do {
_stub->sleep(EVENTS_DELAY);
_stub->processEvents();
if (_stub->_pi.enter) {
_stub->_pi.enter = false;
break;
}
} while (!_stub->_pi.quit);
}
void Menu::handleSkillScreen(uint8 &new_skill) {
debug(DBG_MENU, "Menu::handleSkillScreen()");
static const uint8 option_colors[3][3] = { { 2, 3, 3 }, { 3, 2, 3}, { 3, 3, 2 } };
_vid->fadeOut();
loadPicture("menu3");
_vid->fullRefresh();
drawString(_res->getMenuString(LocaleData::LI_12_SKILL_LEVEL), 12, 4, 3);
int skill_level = new_skill;
do {
drawString(_res->getMenuString(LocaleData::LI_13_EASY), 15, 14, option_colors[skill_level][0]);
drawString(_res->getMenuString(LocaleData::LI_14_NORMAL), 17, 14, option_colors[skill_level][1]);
drawString(_res->getMenuString(LocaleData::LI_15_EXPERT), 19, 14, option_colors[skill_level][2]);
_vid->updateScreen();
_stub->sleep(EVENTS_DELAY);
_stub->processEvents();
if (_stub->_pi.dirMask & PlayerInput::DIR_UP) {
_stub->_pi.dirMask &= ~PlayerInput::DIR_UP;
if (skill_level != 0) {
--skill_level;
} else {
skill_level = 2;
}
}
if (_stub->_pi.dirMask & PlayerInput::DIR_DOWN) {
_stub->_pi.dirMask &= ~PlayerInput::DIR_DOWN;
if (skill_level != 2) {
++skill_level;
} else {
skill_level = 0;
}
}
if (_stub->_pi.enter) {
_stub->_pi.enter = false;
new_skill = skill_level;
return;
}
} while (!_stub->_pi.quit);
new_skill = 1;
}
bool Menu::handlePasswordScreen(uint8 &new_skill, uint8 &new_level) {
debug(DBG_MENU, "Menu::handlePasswordScreen()");
_vid->fadeOut();
_vid->_charShadowColor = _charVar1;
_vid->_charTransparentColor = 0xFF;
_vid->_charFrontColor = _charVar4;
_vid->fullRefresh();
char password[7];
int len = 0;
do {
loadPicture("menu2");
drawString2(_res->getMenuString(LocaleData::LI_16_ENTER_PASSWORD1), 15, 3);
drawString2(_res->getMenuString(LocaleData::LI_17_ENTER_PASSWORD2), 17, 3);
for (int i = 0; i < len; ++i) {
_vid->drawChar((uint8)password[i], 21, i + 15);
}
_vid->drawChar(0x20, 21, len + 15);
_vid->markBlockAsDirty(15 * 8, 21 * 8, (len + 1) * 8, 8);
_vid->updateScreen();
_stub->sleep(EVENTS_DELAY);
_stub->processEvents();
char c = _stub->_pi.lastChar;
if (c != 0) {
_stub->_pi.lastChar = 0;
if (len < 6) {
if (c >= 'a' && c <= 'z') {
c &= ~0x20;
}
if ((c >= 'A' && c <= 'Z') || (c == 0x20)) {
password[len] = c;
++len;
}
}
}
if (_stub->_pi.backspace) {
_stub->_pi.backspace = false;
if (len > 0) {
--len;
}
}
if (_stub->_pi.enter) {
_stub->_pi.enter = false;
password[len] = '\0';
for (int level = 0; level < 8; ++level) {
for (int skill = 0; skill < 3; ++skill) {
if (strcmp(_passwords[level][skill], password) == 0) {
new_level = level;
new_skill = skill;
return true;
}
}
}
return false;
}
} while (!_stub->_pi.quit);
return false;
}
bool Menu::handleTitleScreen(uint8 &new_skill, uint8 &new_level) {
debug(DBG_MENU, "Menu::handleTitleScreen()");
bool quit_loop = false;
int menu_entry = 0;
bool reinit_screen = true;
bool continue_game = true;
_charVar1 = 0;
_charVar2 = 0;
_charVar3 = 0;
_charVar4 = 0;
_charVar5 = 0;
_ply->play(1);
while (!quit_loop) {
if (reinit_screen) {
_vid->fadeOut();
loadPicture("menu1");
_vid->fullRefresh();
_charVar3 = 1;
_charVar4 = 2;
menu_entry = 0;
reinit_screen = false;
}
int selected_menu_entry = -1;
for (int i = 0; i < 5; ++i) {
int color = (i == menu_entry) ? 2 : 3;
drawString(_res->getMenuString(LocaleData::LI_07_START + i), 16 + i * 2, 20, color);
}
_vid->updateScreen();
_stub->sleep(EVENTS_DELAY);
_stub->processEvents();
if (_stub->_pi.dirMask & PlayerInput::DIR_UP) {
_stub->_pi.dirMask &= ~PlayerInput::DIR_UP;
if (menu_entry != 0) {
--menu_entry;
} else {
menu_entry = 4;
}
}
if (_stub->_pi.dirMask & PlayerInput::DIR_DOWN) {
_stub->_pi.dirMask &= ~PlayerInput::DIR_DOWN;
if (menu_entry != 4) {
++menu_entry;
} else {
menu_entry = 0;
}
}
if (_stub->_pi.enter) {
_stub->_pi.enter = false;
selected_menu_entry = menu_entry;
}
if (selected_menu_entry != -1) {
switch (selected_menu_entry) {
case MENU_OPTION_ITEM_START:
new_level = 0;
quit_loop = true;
break;
case MENU_OPTION_ITEM_SKILL:
handleSkillScreen(new_skill);
reinit_screen = true;
break;
case MENU_OPTION_ITEM_PASSWORD:
if (handlePasswordScreen(new_skill, new_level)) {
quit_loop = true;
} else {
reinit_screen = true;
}
break;
case MENU_OPTION_ITEM_INFO:
handleInfoScreen();
reinit_screen = true;
break;
case MENU_OPTION_ITEM_QUIT:
continue_game = false;
quit_loop = true;
break;
}
}
if (_stub->_pi.quit) {
continue_game = false;
quit_loop = true;
break;
}
}
_ply->stop();
return continue_game;
}

View File

@@ -0,0 +1,67 @@
/* REminiscence - Flashback interpreter
* Copyright (C) 2005-2007 Gregory Montoir
*
* 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 2
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __MENU_H__
#define __MENU_H__
#include "intern.h"
struct ModPlayer;
struct Resource;
struct SystemStub;
struct Video;
struct Menu {
enum {
MENU_OPTION_ITEM_START = 0,
MENU_OPTION_ITEM_SKILL,
MENU_OPTION_ITEM_PASSWORD,
MENU_OPTION_ITEM_INFO,
MENU_OPTION_ITEM_QUIT
};
enum {
EVENTS_DELAY = 80
};
static const char *_passwords[8][3];
ModPlayer *_ply;
Resource *_res;
SystemStub *_stub;
Video *_vid;
const char **_textOptions;
uint8 _charVar1;
uint8 _charVar2;
uint8 _charVar3;
uint8 _charVar4;
uint8 _charVar5;
Menu(ModPlayer *ply, Resource *res, SystemStub *stub, Video *vid);
void drawString(const char *str, int16 y, int16 x, uint8 color);
void drawString2(const char *str, int16 y, int16 x);
void loadPicture(const char *prefix);
void handleInfoScreen();
void handleSkillScreen(uint8 &new_skill);
bool handlePasswordScreen(uint8 &new_skill, uint8 &new_level);
bool handleTitleScreen(uint8 &new_skill, uint8 &new_level);
};
#endif // __MENU_H__

View File

@@ -0,0 +1,124 @@
/* REminiscence - Flashback interpreter
* Copyright (C) 2005-2007 Gregory Montoir
*
* 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 2
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "mixer.h"
#include "systemstub.h"
Mixer::Mixer(SystemStub *stub)
: _stub(stub) {
}
void Mixer::init() {
memset(_channels, 0, sizeof(_channels));
_premixHook = 0;
_mutex = _stub->createMutex();
_stub->startAudio(Mixer::mixCallback, this);
}
void Mixer::free() {
stopAll();
_stub->stopAudio();
_stub->destroyMutex(_mutex);
}
void Mixer::setPremixHook(PremixHook premixHook, void *userData) {
debug(DBG_SND, "Mixer::setPremixHook()");
MutexStack(_stub, _mutex);
_premixHook = premixHook;
_premixHookData = userData;
}
void Mixer::play(const MixerChunk *mc, uint16 freq, uint8 volume) {
debug(DBG_SND, "Mixer::play(%d, %d)", freq, volume);
MutexStack(_stub, _mutex);
MixerChannel *ch = 0;
for (int i = 0; i < NUM_CHANNELS; ++i) {
MixerChannel *cur = &_channels[i];
if (cur->active) {
if (cur->chunk.data == mc->data) {
cur->chunkPos = 0;
return;
}
} else {
ch = cur;
break;
}
}
if (ch) {
ch->active = true;
ch->volume = volume;
ch->chunk = *mc;
ch->chunkPos = 0;
ch->chunkInc = (freq << FRAC_BITS) / _stub->getOutputSampleRate();
}
}
uint32 Mixer::getSampleRate() const {
return _stub->getOutputSampleRate();
}
void Mixer::stopAll() {
debug(DBG_SND, "Mixer::stopAll()");
MutexStack(_stub, _mutex);
for (uint8 i = 0; i < NUM_CHANNELS; ++i) {
_channels[i].active = false;
}
}
inline void addclamp(int16& a, int b) {
int add = a + b;
if (add < -32767) {
add = -32767;
} else if (add > 32767) {
add = 32767;
}
a = add;
}
void Mixer::mix(int8 *buf1, int len) {
int16 *buf = (int16 *)buf1;
MutexStack(_stub, _mutex);
memset(buf, 0, len);
len /= 2;
if (_premixHook) {
if (!_premixHook(_premixHookData, buf, len)) {
_premixHook = 0;
_premixHookData = 0;
}
}
for (uint8 i = 0; i < NUM_CHANNELS; ++i) {
MixerChannel *ch = &_channels[i];
if (ch->active) {
for (int pos = 0; pos < len; ++pos) {
if ((ch->chunkPos >> FRAC_BITS) >= (ch->chunk.len - 1)) {
ch->active = false;
break;
}
int out = resampleLinear(&ch->chunk, ch->chunkPos, ch->chunkInc, FRAC_BITS);
addclamp(buf[pos], out * Mixer::MIX_AMPLIFICATIION * ch->volume / Mixer::MAX_VOLUME );
ch->chunkPos += ch->chunkInc;
}
}
}
}
void Mixer::mixCallback(void *param, uint8 *buf, int len) {
((Mixer *)param)->mix((int8 *)buf, len);
}

View File

@@ -0,0 +1,96 @@
/* REminiscence - Flashback interpreter
* Copyright (C) 2005-2007 Gregory Montoir
*
* 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 2
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __MIXER_H__
#define __MIXER_H__
#include "intern.h"
struct MixerChunk {
uint8 *data;
uint32 len;
int8 getPCM(int offset) const {
if (offset < 0) {
offset = 0;
} else if (offset >= (int)len) {
offset = len - 1;
}
return (int8)data[offset];
}
};
struct MixerChannel {
uint8 active;
uint8 volume;
MixerChunk chunk;
uint32 chunkPos;
uint32 chunkInc;
};
struct SystemStub;
struct Mixer {
typedef bool (*PremixHook)(void *userData, int16 *buf, int len);
enum {
NUM_CHANNELS = 4,
FRAC_BITS = 12,
MAX_VOLUME = 64,
MIX_AMPLIFICATIION = 64 // TODO: edit here to tweak sound
};
void *_mutex;
SystemStub *_stub;
MixerChannel _channels[NUM_CHANNELS];
PremixHook _premixHook;
void *_premixHookData;
Mixer(SystemStub *stub);
void init();
void free();
void setPremixHook(PremixHook premixHook, void *userData);
void play(const MixerChunk *mc, uint16 freq, uint8 volume);
void stopAll();
uint32 getSampleRate() const;
void mix(int8 *buf, int len);
//static void addclamp(int16 &a, int b);
static void mixCallback(void *param, uint8 *buf, int len);
};
template <class T>
int resampleLinear(T *sample, int pos, int step, int fracBits) {
const int inputPos = pos >> fracBits;
const int inputFrac = (1 << fracBits) - 1;
int out = sample->getPCM(inputPos);
out += (sample->getPCM(inputPos + 1) - out) * inputFrac >> fracBits;
return out;
}
template <class T>
int resample3Pt(T *sample, int pos, int step, int fracBits) {
const int inputPos = pos >> fracBits;
const int inputFrac = (1 << fracBits) - 1;
int out = sample->getPCM(inputPos) >> 1;
out += sample->getPCM(inputPos + ((inputFrac - (step >> 1)) >> fracBits)) >> 2;
out += sample->getPCM(inputPos + ((inputFrac + (step >> 1)) >> fracBits)) >> 2;
return out;
}
#endif // __MIXER_H__

Some files were not shown because too many files have changed in this diff Show More