From 47a8620d9742a7a63eb1dd664e5a3a67062aa55f Mon Sep 17 00:00:00 2001 From: Paul Hunkin Date: Mon, 17 May 2010 15:14:34 +1200 Subject: [PATCH 01/34] Initial commit, adding __ANDROID__ to the platform list --- include/SDL_platform.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/SDL_platform.h b/include/SDL_platform.h index f9429bdec..a41f56309 100644 --- a/include/SDL_platform.h +++ b/include/SDL_platform.h @@ -65,6 +65,13 @@ #undef __LINUX__ #define __LINUX__ 1 #endif +#if defined(ANDROID) +#undef __ANDROID__ +#undef __LINUX__ //do we need to do this? +#define __ANDROID__ 1 +#endif + + #if defined(__APPLE__) /* lets us know what version of Mac OS X we're compiling on */ From 1c62b779c7959c44c66751bb40c700e2b7eeead1 Mon Sep 17 00:00:00 2001 From: Paul Hunkin Date: Sun, 23 May 2010 15:08:30 +1200 Subject: [PATCH 02/34] Fixed comment style --- include/SDL_platform.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/include/SDL_platform.h b/include/SDL_platform.h index a41f56309..90eed561c 100644 --- a/include/SDL_platform.h +++ b/include/SDL_platform.h @@ -67,12 +67,10 @@ #endif #if defined(ANDROID) #undef __ANDROID__ -#undef __LINUX__ //do we need to do this? +#undef __LINUX__ /*do we need to do this?*/ #define __ANDROID__ 1 #endif - - #if defined(__APPLE__) /* lets us know what version of Mac OS X we're compiling on */ #include "AvailabilityMacros.h" From 8706b8163d61c15dd9079eb6f74a9afb3678fb8f Mon Sep 17 00:00:00 2001 From: Paul Hunkin Date: Sun, 23 May 2010 15:10:18 +1200 Subject: [PATCH 03/34] Fix compile errors under Android toolchain. Seems to have the same issue as the NDS. --- include/SDL_stdinc.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/include/SDL_stdinc.h b/include/SDL_stdinc.h index c7e7edd57..504ff32c4 100644 --- a/include/SDL_stdinc.h +++ b/include/SDL_stdinc.h @@ -167,9 +167,10 @@ SDL_COMPILE_TIME_ASSERT(uint16, sizeof(Uint16) == 2); SDL_COMPILE_TIME_ASSERT(sint16, sizeof(Sint16) == 2); SDL_COMPILE_TIME_ASSERT(uint32, sizeof(Uint32) == 4); SDL_COMPILE_TIME_ASSERT(sint32, sizeof(Sint32) == 4); -#ifndef __NINTENDODS__ /* TODO: figure out why the following happens: - include/SDL_stdinc.h:150: error: size of array 'SDL_dummy_uint64' is negative - include/SDL_stdinc.h:151: error: size of array 'SDL_dummy_sint64' is negative */ +#if !defined(__NINTENDODS__) && !defined(__ANDROID__) +/* TODO: figure out why the following happens: + include/SDL_stdinc.h:150: error: size of array 'SDL_dummy_uint64' is negative + include/SDL_stdinc.h:151: error: size of array 'SDL_dummy_sint64' is negative */ SDL_COMPILE_TIME_ASSERT(uint64, sizeof(Uint64) == 8); SDL_COMPILE_TIME_ASSERT(sint64, sizeof(Sint64) == 8); #endif @@ -188,7 +189,8 @@ SDL_COMPILE_TIME_ASSERT(sint64, sizeof(Sint64) == 8); /** \cond */ #ifndef DOXYGEN_SHOULD_IGNORE_THIS -#ifndef __NINTENDODS__ /* TODO: include/SDL_stdinc.h:174: error: size of array 'SDL_dummy_enum' is negative */ +#if !defined(__NINTENDODS__) && !defined(__ANDROID__) + /* TODO: include/SDL_stdinc.h:174: error: size of array 'SDL_dummy_enum' is negative */ typedef enum { DUMMY_ENUM_VALUE From 0781a76fafb0698a3826ec7e0ac6a7deddce514d Mon Sep 17 00:00:00 2001 From: Paul Hunkin Date: Sun, 23 May 2010 15:12:41 +1200 Subject: [PATCH 04/34] Fix a compile error when SDL_JOYSTICK_DISABLED is set --- src/events/SDL_events.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/events/SDL_events.c b/src/events/SDL_events.c index e99a55d93..5fb5f075b 100644 --- a/src/events/SDL_events.c +++ b/src/events/SDL_events.c @@ -92,11 +92,13 @@ SDL_Unlock_EventThread(void) static __inline__ SDL_bool SDL_ShouldPollJoystick() { +#if !SDL_JOYSTICK_DISABLED if (SDL_numjoysticks && (!SDL_disabled_events[SDL_JOYAXISMOTION >> 8] || SDL_JoystickEventState(SDL_QUERY))) { return SDL_TRUE; } +#endif return SDL_FALSE; } From adfffe82b1e4ea1d729d24a07055b71b3fbc438a Mon Sep 17 00:00:00 2001 From: Paul Hunkin Date: Sun, 23 May 2010 15:13:39 +1200 Subject: [PATCH 05/34] Added some wrapper shell scripts to make android compiling easier --- build-scripts/acc.sh | 15 +++++++++++++++ build-scripts/ald.sh | 18 ++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100755 build-scripts/acc.sh create mode 100755 build-scripts/ald.sh diff --git a/build-scripts/acc.sh b/build-scripts/acc.sh new file mode 100755 index 000000000..e4be71c75 --- /dev/null +++ b/build-scripts/acc.sh @@ -0,0 +1,15 @@ +#!/bin/bash +ANDROID_NDK="/home/paul/Projects/gsoc/sdk/android-ndk-r4" +TOOLS_PATH="$ANDROID_NDK/build/prebuilt/linux-x86/arm-eabi-4.2.1/bin" + +export PATH=$TOOLS_PATH:$PATH + +CC="arm-eabi-gcc" + +#cflags +ACC_C=" -I$ANDROID_NDK/build/platforms/android-4/common/include \ + -I$ANDROID_NDK/build/platforms/android-4/arch-arm/usr/include \ + -DANDROID -c" + + +$CC $CFLAGS $ACC_C $@ diff --git a/build-scripts/ald.sh b/build-scripts/ald.sh new file mode 100755 index 000000000..4aa6c3a4a --- /dev/null +++ b/build-scripts/ald.sh @@ -0,0 +1,18 @@ +#!/bin/bash +ANDROID_NDK="/home/paul/Projects/gsoc/sdk/android-ndk-r4" +TOOLS_PATH="$ANDROID_NDK/build/prebuilt/linux-x86/arm-eabi-4.2.1/bin" + +export PATH=$TOOLS_PATH:$PATH + +LD="arm-eabi-ld" + +#ldflags +ACC_L=" -rpath-link=$ANDROID_NDK/build/platforms/android-4/arch-arm/usr/lib/ \ + -dynamic-linker=/system/bin/linker \ + -L$ANDROID_NDK/build/platforms/android-3/arch-arm/usr/lib/ -lc -nostdlib \ + $ANDROID_NDK/build/platforms/android-4/arch-arm/usr/lib/crtbegin_static.o \ + -L$ANDROID_NDK/build/prebuilt/linux-x86/arm-eabi-4.2.1/lib/gcc/arm-eabi/4.2.1 " + +$LD $ACC_L $LDFLAGS $@ -lgcc + + From e9e78ea46e02f4e3577d07cdb1c3740fcd576ae6 Mon Sep 17 00:00:00 2001 From: Paul Hunkin Date: Sun, 23 May 2010 15:18:16 +1200 Subject: [PATCH 06/34] Added some android build stuff --- Makefile.android | 51 +++++++++++++++++++++++++ include/SDL_config_android.h | 72 ++++++++++++++++++++++++++++++++++++ 2 files changed, 123 insertions(+) create mode 100755 Makefile.android create mode 100755 include/SDL_config_android.h diff --git a/Makefile.android b/Makefile.android new file mode 100755 index 000000000..e60d4abab --- /dev/null +++ b/Makefile.android @@ -0,0 +1,51 @@ +# Makefile to build the SDL library + +ANDROID_NDK=/home/paul/Projects/gsoc/sdk/android-ndk-r4 +TOOLS_PATH=$(ANDROID_NDK)/build/prebuilt/linux-x86/arm-eabi-4.2.1/bin +ANDROID_INCLUDES = -I$(ANDROID_NDK)/build/platforms/android-4/common/include \ + -I$(ANDROID_NDK)/build/platforms/android-4/arch-arm/usr/include +INCLUDE = -I./include +CFLAGS = -g -O2 $(INCLUDE) $(ANDROID_INCLUDES) -DANDROID -static + +AR = $(TOOLS_PATH)/arm-eabi-ar +RANLIB = $(TOOLS_PATH)/arm-eabi-ranlib +CC = $(TOOLS_PATH)/arm-eabi-gcc + + +CONFIG_H = include/SDL_config.h +TARGET = libSDL.a +SOURCES = \ + src/*.c \ + src/audio/*.c \ + src/cpuinfo/*.c \ + src/events/*.c \ + src/file/*.c \ + src/joystick/*.c \ + src/haptic/*.c \ + src/stdlib/*.c \ + src/thread/*.c \ + src/timer/*.c \ + src/video/*.c \ + src/power/*.c \ + src/audio/dummy/*.c \ + src/video/dummy/*.c \ + src/joystick/dummy/*.c \ + src/haptic/dummy/*.c \ + src/atomic/dummy/*.c \ + src/thread/generic/*.c \ + src/timer/dummy/*.c \ + src/loadso/dummy/*.c \ + +OBJECTS = $(shell echo $(SOURCES) | sed -e 's,\.c,\.o,g') + +all: $(TARGET) + +$(TARGET): $(CONFIG_H) $(OBJECTS) + $(AR) crv $@ $^ + $(RANLIB) $@ + +$(CONFIG_H): + cp $(CONFIG_H).default $(CONFIG_H) + +clean: + rm -f $(TARGET) $(OBJECTS) diff --git a/include/SDL_config_android.h b/include/SDL_config_android.h new file mode 100755 index 000000000..c5877c49f --- /dev/null +++ b/include/SDL_config_android.h @@ -0,0 +1,72 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2010 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ + +#ifndef _SDL_config_android_h +#define _SDL_config_android_h + +#include "SDL_platform.h" + +/** + * \file SDL_config_android.h + * + * This is a configuration that can be used to build SDL for Android + */ + +#include + +/* +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef signed short int16_t; +typedef unsigned short uint16_t; +typedef signed int int32_t; +typedef unsigned int uint32_t; +*/ + +#define SIZEOF_VOIDP 4 + +typedef unsigned int size_t; +//typedef unsigned long uintptr_t; + +#define SDL_AUDIO_DRIVER_DUMMY 1 + +#define SDL_CDROM_DISABLED 1 + +#define SDL_HAPTIC_DISABLED 1 + +#define SDL_JOYSTICK_DISABLED 1 + +#define SDL_LOADSO_DISABLED 1 + +#define SDL_THREADS_DISABLED 1 + +#define SDL_TIMERS_DISABLED 1 + +#define SDL_TIMER_UNIX 1 + +#define SDL_VIDEO_DRIVER_DUMMY 1 + +#define HAVE_STDIO_H 1 +#define HAVE_SYS_TYPES_H 1 + +#endif /* _SDL_config_minimal_h */ + From 395db5c4a23c269a0224537427118dcb23dd20cb Mon Sep 17 00:00:00 2001 From: Paul Hunkin Date: Thu, 10 Jun 2010 18:54:23 +1200 Subject: [PATCH 07/34] Added (partially implemented) android video backend and associated files needed to build --- Makefile.android | 4 +- build-scripts/acc.sh | 6 +- build-scripts/ald.sh | 12 +- build-scripts/android_libs/libEGL.so | Bin 0 -> 36100 bytes build-scripts/android_libs/libcutils.so | Bin 0 -> 55252 bytes build-scripts/android_libs/libutils.so | Bin 0 -> 172344 bytes include/SDL_config_android.h | 6 +- src/SDL_compat.c | 11 + src/video/SDL_sysvideo.h | 3 + src/video/SDL_video.c | 3 + src/video/android/SDL_androidevents.c | 52 ++++ src/video/android/SDL_androidevents_c.h | 28 ++ src/video/android/SDL_androidgl.c | 158 +++++++++++ src/video/android/SDL_androidrender.c | 344 ++++++++++++++++++++++++ src/video/android/SDL_androidrender_c.h | 28 ++ src/video/android/SDL_androidvideo.c | 152 +++++++++++ src/video/android/SDL_androidvideo.h | 31 +++ src/video/android/egl.h | 330 +++++++++++++++++++++++ src/video/android/eglext.h | 162 +++++++++++ src/video/android/eglplatform.h | 118 ++++++++ 20 files changed, 1437 insertions(+), 11 deletions(-) create mode 100644 build-scripts/android_libs/libEGL.so create mode 100644 build-scripts/android_libs/libcutils.so create mode 100644 build-scripts/android_libs/libutils.so create mode 100644 src/video/android/SDL_androidevents.c create mode 100644 src/video/android/SDL_androidevents_c.h create mode 100644 src/video/android/SDL_androidgl.c create mode 100644 src/video/android/SDL_androidrender.c create mode 100644 src/video/android/SDL_androidrender_c.h create mode 100644 src/video/android/SDL_androidvideo.c create mode 100644 src/video/android/SDL_androidvideo.h create mode 100644 src/video/android/egl.h create mode 100644 src/video/android/eglext.h create mode 100644 src/video/android/eglplatform.h diff --git a/Makefile.android b/Makefile.android index e60d4abab..bf6b2838e 100755 --- a/Makefile.android +++ b/Makefile.android @@ -5,7 +5,7 @@ TOOLS_PATH=$(ANDROID_NDK)/build/prebuilt/linux-x86/arm-eabi-4.2.1/bin ANDROID_INCLUDES = -I$(ANDROID_NDK)/build/platforms/android-4/common/include \ -I$(ANDROID_NDK)/build/platforms/android-4/arch-arm/usr/include INCLUDE = -I./include -CFLAGS = -g -O2 $(INCLUDE) $(ANDROID_INCLUDES) -DANDROID -static +CFLAGS = -g -O2 $(INCLUDE) $(ANDROID_INCLUDES) -DANDROID -DANDROID_NDK -static AR = $(TOOLS_PATH)/arm-eabi-ar RANLIB = $(TOOLS_PATH)/arm-eabi-ranlib @@ -28,7 +28,7 @@ SOURCES = \ src/video/*.c \ src/power/*.c \ src/audio/dummy/*.c \ - src/video/dummy/*.c \ + src/video/android/*.c \ src/joystick/dummy/*.c \ src/haptic/dummy/*.c \ src/atomic/dummy/*.c \ diff --git a/build-scripts/acc.sh b/build-scripts/acc.sh index e4be71c75..e66d5f8fc 100755 --- a/build-scripts/acc.sh +++ b/build-scripts/acc.sh @@ -7,9 +7,9 @@ export PATH=$TOOLS_PATH:$PATH CC="arm-eabi-gcc" #cflags -ACC_C=" -I$ANDROID_NDK/build/platforms/android-4/common/include \ - -I$ANDROID_NDK/build/platforms/android-4/arch-arm/usr/include \ - -DANDROID -c" +ACC_C=" -I$ANDROID_NDK/build/platforms/android-8/common/include \ + -I$ANDROID_NDK/build/platforms/android-8/arch-arm/usr/include \ + -DANDROID -DANDROID_NDK -c" $CC $CFLAGS $ACC_C $@ diff --git a/build-scripts/ald.sh b/build-scripts/ald.sh index 4aa6c3a4a..9ac41fa66 100755 --- a/build-scripts/ald.sh +++ b/build-scripts/ald.sh @@ -1,18 +1,20 @@ #!/bin/bash ANDROID_NDK="/home/paul/Projects/gsoc/sdk/android-ndk-r4" TOOLS_PATH="$ANDROID_NDK/build/prebuilt/linux-x86/arm-eabi-4.2.1/bin" +ADDITIONAL_LIBS=`dirname "$0"`/android_libs/ export PATH=$TOOLS_PATH:$PATH LD="arm-eabi-ld" #ldflags -ACC_L=" -rpath-link=$ANDROID_NDK/build/platforms/android-4/arch-arm/usr/lib/ \ +ACC_L=" -rpath-link=$ANDROID_NDK/build/platforms/android-8/arch-arm/usr/lib/ \ -dynamic-linker=/system/bin/linker \ - -L$ANDROID_NDK/build/platforms/android-3/arch-arm/usr/lib/ -lc -nostdlib \ - $ANDROID_NDK/build/platforms/android-4/arch-arm/usr/lib/crtbegin_static.o \ - -L$ANDROID_NDK/build/prebuilt/linux-x86/arm-eabi-4.2.1/lib/gcc/arm-eabi/4.2.1 " + -lc -nostdlib \ + $ANDROID_NDK/build/platforms/android-8/arch-arm/usr/lib/crtbegin_static.o \ + -L$ANDROID_NDK/build/platforms/android-8/arch-arm/usr/lib/ \ + -L$ANDROID_NDK/build/prebuilt/linux-x86/arm-eabi-4.2.1/lib/gcc/arm-eabi/4.2.1 \ + -L$ADDITIONAL_LIBS " $LD $ACC_L $LDFLAGS $@ -lgcc - diff --git a/build-scripts/android_libs/libEGL.so b/build-scripts/android_libs/libEGL.so new file mode 100644 index 0000000000000000000000000000000000000000..03a18b39fd95da0102567ed3a7102d72961f2b9c GIT binary patch literal 36100 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 PaM5_ks=s=5iS_>hkCIXr literal 0 HcmV?d00001 diff --git a/build-scripts/android_libs/libcutils.so b/build-scripts/android_libs/libcutils.so new file mode 100644 index 0000000000000000000000000000000000000000..825852b607d70437a8da5cfa236be119b8de1d16 GIT binary patch literal 55252 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 literal 0 HcmV?d00001 diff --git a/build-scripts/android_libs/libutils.so b/build-scripts/android_libs/libutils.so new file mode 100644 index 0000000000000000000000000000000000000000..c09e96fdc29d719abdc45278c80e2b62a55cdeab GIT binary patch literal 172344 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 Date: Tue, 17 Aug 2010 17:28:14 +1200 Subject: [PATCH 33/34] Updated the readme --- README.android | 41 +++++++++++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/README.android b/README.android index 10d2061b0..ae10e0125 100644 --- a/README.android +++ b/README.android @@ -1,16 +1,45 @@ -============================================================================== +================================================================================ Simple DirectMedia Layer for Android -============================================================================== +================================================================================ Requirements: Android NDK r4 or later +================================================================================ + How the port works +================================================================================ + +- Android applications are Java-based, optionally with parts written in C +- As SDL apps are C-based, we use a small Java shim that uses JNI to talk to +the SDL library +- This means that your application C code must be placed inside an android +Java project, along with some C support code that communicates with Java +- This eventually produces a standard Android .apk package + + + + + + +================================================================================ + Building an app +================================================================================ + Instructions: 1. Edit android/config.cfg to point to the location of the NDK 2. Run 'make -f Makefile.android'. If all goes well, libsdl.a should be created -3. Place your application source files in android/testproject/jni -4. Run 'ndk-build' (a script provided by the NDK). This compiles the C source -4. Run 'ant' in android/testproject. This compiles the .java and eventually +3. Place your application source files in android/project/jni +4. Edit the Android.mk to include your source files +5. Run 'ndk-build' (a script provided by the NDK). This compiles the C source +6. Run 'ant' in android/testproject. This compiles the .java and eventually creates a .apk with the C source embedded -6. 'ant install' will push the apk to the device or emulator (if connected) +7. 'ant install' will push the apk to the device or emulator (if connected) + + + +================================================================================ + Known issues +================================================================================ +- SDL audio (although it's mostly written, just not working properly yet) +- TODO. I'm sure there's a bunch more stuff I haven't thought of From 7f9373756c1721d25cab9acc6fb4b9153d9dc800 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Thu, 19 Aug 2010 00:21:20 -0700 Subject: [PATCH 34/34] Removed obsolete test project --- android/testproject/AndroidManifest.xml | 15 - android/testproject/build.properties | 17 - android/testproject/build.xml | 67 -- android/testproject/default.properties | 11 - android/testproject/jni/Android.mk | 20 - android/testproject/jni/app-android.cpp | 236 ------- android/testproject/jni/egl.h | 269 -------- android/testproject/jni/eglnatives.h | 277 --------- android/testproject/jni/egltypes.h | 48 -- android/testproject/jni/importgl.cpp | 168 ----- android/testproject/jni/importgl.h | 172 ------ android/testproject/jni/lesson05.c | 574 ------------------ android/testproject/local.properties | 10 - .../testproject/res/drawable-hdpi/icon.png | Bin 4147 -> 0 bytes .../testproject/res/drawable-ldpi/icon.png | Bin 1723 -> 0 bytes .../testproject/res/drawable-mdpi/icon.png | Bin 2574 -> 0 bytes android/testproject/res/layout/main.xml | 13 - android/testproject/res/values/strings.xml | 4 - .../src/org/libsdl/android/SDLActivity.java | 388 ------------ 19 files changed, 2289 deletions(-) delete mode 100644 android/testproject/AndroidManifest.xml delete mode 100644 android/testproject/build.properties delete mode 100644 android/testproject/build.xml delete mode 100644 android/testproject/default.properties delete mode 100644 android/testproject/jni/Android.mk delete mode 100644 android/testproject/jni/app-android.cpp delete mode 100644 android/testproject/jni/egl.h delete mode 100644 android/testproject/jni/eglnatives.h delete mode 100644 android/testproject/jni/egltypes.h delete mode 100644 android/testproject/jni/importgl.cpp delete mode 100644 android/testproject/jni/importgl.h delete mode 100644 android/testproject/jni/lesson05.c delete mode 100644 android/testproject/local.properties delete mode 100644 android/testproject/res/drawable-hdpi/icon.png delete mode 100644 android/testproject/res/drawable-ldpi/icon.png delete mode 100644 android/testproject/res/drawable-mdpi/icon.png delete mode 100644 android/testproject/res/layout/main.xml delete mode 100644 android/testproject/res/values/strings.xml delete mode 100644 android/testproject/src/org/libsdl/android/SDLActivity.java diff --git a/android/testproject/AndroidManifest.xml b/android/testproject/AndroidManifest.xml deleted file mode 100644 index bb98659f2..000000000 --- a/android/testproject/AndroidManifest.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - diff --git a/android/testproject/build.properties b/android/testproject/build.properties deleted file mode 100644 index edc7f2305..000000000 --- a/android/testproject/build.properties +++ /dev/null @@ -1,17 +0,0 @@ -# This file is used to override default values used by the Ant build system. -# -# This file must be checked in Version Control Systems, as it is -# integral to the build system of your project. - -# This file is only used by the Ant script. - -# You can use this to override default values such as -# 'source.dir' for the location of your java source folder and -# 'out.dir' for the location of your output folder. - -# You can also use it define how the release builds are signed by declaring -# the following properties: -# 'key.store' for the location of your keystore and -# 'key.alias' for the name of the key to use. -# The password will be asked during the build when you use the 'release' target. - diff --git a/android/testproject/build.xml b/android/testproject/build.xml deleted file mode 100644 index cd16dcbea..000000000 --- a/android/testproject/build.xml +++ /dev/null @@ -1,67 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/android/testproject/default.properties b/android/testproject/default.properties deleted file mode 100644 index 459f2ac68..000000000 --- a/android/testproject/default.properties +++ /dev/null @@ -1,11 +0,0 @@ -# This file is automatically generated by Android Tools. -# Do not modify this file -- YOUR CHANGES WILL BE ERASED! -# -# This file must be checked in Version Control Systems. -# -# To customize properties used by the Ant build system use, -# "build.properties", and override values to adapt the script to your -# project structure. - -# Project target. -target=Google Inc.:Google APIs:7 diff --git a/android/testproject/jni/Android.mk b/android/testproject/jni/Android.mk deleted file mode 100644 index bf1e39e9f..000000000 --- a/android/testproject/jni/Android.mk +++ /dev/null @@ -1,20 +0,0 @@ -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_MODULE := sdltest - -SDL := /home/paul/Projects/gsoc/SDL-gsoc2010_android/ - -LOCAL_CFLAGS := -DANDROID_NDK \ - -DDISABLE_IMPORTGL \ - -I$(SDL)/include - -LOCAL_SRC_FILES := \ - importgl.cpp \ - app-android.cpp \ - lesson05.c \ - -LOCAL_LDLIBS := -lGLESv1_CM -ldl -llog -lSDL -lEGL -lgcc -L$(SDL) -L$(SDL)/build-scripts/android_libs/ - -include $(BUILD_SHARED_LIBRARY) diff --git a/android/testproject/jni/app-android.cpp b/android/testproject/jni/app-android.cpp deleted file mode 100644 index e3dc8f773..000000000 --- a/android/testproject/jni/app-android.cpp +++ /dev/null @@ -1,236 +0,0 @@ -/******************************************************************************* - Headers -*******************************************************************************/ -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -//#include "importgl.h" -//#include "egl.h" - -/******************************************************************************* - Globals -*******************************************************************************/ -static long _getTime(void){ - struct timeval now; - gettimeofday(&now, NULL); - return (long)(now.tv_sec*1000 + now.tv_usec/1000); -} - -JNIEnv* mEnv = NULL; -JNIEnv* mAudioThreadEnv = NULL; //See the note below for why this is necessary -JavaVM* mVM = NULL; - -//Main activity -jclass mActivityInstance; - -//method signatures -jmethodID midCreateGLContext; -jmethodID midFlipBuffers; -jmethodID midEnableFeature; -jmethodID midUpdateAudio; - -extern "C" int SDL_main(); -extern "C" int Android_OnKeyDown(int keycode); -extern "C" int Android_OnKeyUp(int keycode); -extern "C" void Android_SetScreenResolution(int width, int height); -extern "C" void Android_OnResize(int width, int height, int format); -extern "C" int SDL_SendQuit(); -extern "C" void Android_EnableFeature(int featureid, bool enabled); - -//If we're not the active app, don't try to render -bool bRenderingEnabled = false; - -//Feature IDs -static const int FEATURE_AUDIO = 1; -static const int FEATURE_ACCEL = 2; - -//Accelerometer data storage -float fLastAccelerometer[3]; - - -/******************************************************************************* - Functions called by JNI -*******************************************************************************/ - -//Library init -extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved){ - - JNIEnv* env = NULL; - jint result = -1; - - if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { - return result; - } - - mEnv = env; - - __android_log_print(ANDROID_LOG_INFO, "SDL", "JNI: OnLoad"); - - jclass cls = mEnv->FindClass ("org/libsdl/android/SDLActivity"); - mActivityInstance = cls; - midCreateGLContext = mEnv->GetStaticMethodID(cls,"createGLContext","()V"); - midFlipBuffers = mEnv->GetStaticMethodID(cls,"flipBuffers","()V"); - midEnableFeature = mEnv->GetStaticMethodID(cls,"enableFeature","(II)V"); - midUpdateAudio = mEnv->GetStaticMethodID(cls,"updateAudio","([B)V"); - - if(!midCreateGLContext || !midFlipBuffers || !midEnableFeature || - !midUpdateAudio){ - __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: Bad mids\n"); - }else{ - __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: Good mids\n"); - } - - return JNI_VERSION_1_4; -} - -//Start up the SDL app -extern "C" void Java_org_libsdl_android_SDLActivity_nativeInit( JNIEnv* env, - jobject obj ){ - - __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: Native Init"); - - mEnv = env; - bRenderingEnabled = true; - - Android_EnableFeature(FEATURE_ACCEL, true); - - SDL_main(); -} - -//Keydown -extern "C" void Java_org_libsdl_android_SDLActivity_onNativeKeyDown(JNIEnv* env, - jobject obj, jint keycode){ - - int r = Android_OnKeyDown(keycode); - __android_log_print(ANDROID_LOG_INFO, "SDL", - "SDL: native key down %d, %d\n", keycode, r); - -} - -//Keyup -extern "C" void Java_org_libsdl_android_SDLActivity_onNativeKeyUp(JNIEnv* env, - jobject obj, jint keycode){ - - int r = Android_OnKeyUp(keycode); - __android_log_print(ANDROID_LOG_INFO, "SDL", - "SDL: native key up %d, %d\n", keycode, r); - -} - -//Touch -extern "C" void Java_org_libsdl_android_SDLActivity_onNativeTouch(JNIEnv* env, - jobject obj, jint action, jfloat x, jfloat y, jfloat p){ - - __android_log_print(ANDROID_LOG_INFO, "SDL", - "SDL: native touch event %d @ %f/%f, pressure %f\n", - action, x, y, p); - - //TODO: Pass this off to the SDL multitouch stuff - -} - -//Quit -extern "C" void Java_org_libsdl_android_SDLActivity_nativeQuit( JNIEnv* env, - jobject obj ){ - - //Stop rendering as we're no longer in the foreground - bRenderingEnabled = false; - - //Inject a SDL_QUIT event - int r = SDL_SendQuit(); - - __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: Native quit %d", r); -} - -//Screen size -extern "C" void Java_org_libsdl_android_SDLActivity_nativeSetScreenSize( - JNIEnv* env, jobject obj, jint width, jint height){ - - __android_log_print(ANDROID_LOG_INFO, "SDL", - "SDL: Set screen size on init: %d/%d\n", width, height); - Android_SetScreenResolution(width, height); - -} - -//Resize -extern "C" void Java_org_libsdl_android_SDLActivity_onNativeResize( - JNIEnv* env, jobject obj, jint width, - jint height, jint format){ - Android_OnResize(width, height, format); -} - -extern "C" void Java_org_libsdl_android_SDLActivity_onNativeAccel( - JNIEnv* env, jobject obj, - jfloat x, jfloat y, jfloat z){ - fLastAccelerometer[0] = x; - fLastAccelerometer[1] = y; - fLastAccelerometer[2] = z; -} - - - -/******************************************************************************* - Functions called by SDL into Java -*******************************************************************************/ -extern "C" void Android_CreateContext(){ - __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: sdl_create_context()\n"); - - bRenderingEnabled = true; - - mEnv->CallStaticVoidMethod(mActivityInstance, midCreateGLContext ); -} - -extern "C" void Android_Render(){ - - if(!bRenderingEnabled){ - return; - } - - //When we get here, we've accumulated a full frame - mEnv->CallStaticVoidMethod(mActivityInstance, midFlipBuffers ); -} - -extern "C" void Android_EnableFeature(int featureid, bool enabled){ - - mEnv->CallStaticVoidMethod(mActivityInstance, midEnableFeature, - featureid, (int)enabled); -} - -extern "C" void Android_UpdateAudioBuffer(unsigned char *buf, int len){ - - //Annoyingly we can't just call into Java from any thread. Because the audio - //callback is dispatched from the SDL audio thread (that wasn't made from - //java, we have to do some magic here to let the JVM know about the thread. - //Because everything it touches on the Java side is static anyway, it's - //not a big deal, just annoying. - if(!mAudioThreadEnv){ - __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: Need to set up audio thread env\n"); - - mJVM->AttachCurrentThread(&mAudioThreadEnv, NULL); - - __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: ok\n"); - } - - jbyteArray arr = mAudioThreadEnv->NewByteArray(len); - - //blah. We probably should rework this so we avoid the copy. - mAudioThreadEnv->SetByteArrayRegion(arr, 0, len, (jbyte *)buf); - - __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: copied\n"); - - mAudioThreadEnv->CallStaticVoidMethod( mActivityInstance, - midUpdateAudio, arr ); - - __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: invoked\n"); - -} - diff --git a/android/testproject/jni/egl.h b/android/testproject/jni/egl.h deleted file mode 100644 index 3efa93cb7..000000000 --- a/android/testproject/jni/egl.h +++ /dev/null @@ -1,269 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * 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 - * - * http://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. - */ - -#ifndef ANDROID_EGL_H -#define ANDROID_EGL_H - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define EGL_VERSION_1_0 1 -#define EGL_VERSION_1_1 1 -#define EGL_VERSION_1_2 1 - -#define EGL_FALSE 0 -#define EGL_TRUE 1 - -/* Errors */ -#define EGL_SUCCESS 0x3000 -#define EGL_NOT_INITIALIZED 0x3001 -#define EGL_BAD_ACCESS 0x3002 -#define EGL_BAD_ALLOC 0x3003 -#define EGL_BAD_ATTRIBUTE 0x3004 -#define EGL_BAD_CONFIG 0x3005 -#define EGL_BAD_CONTEXT 0x3006 -#define EGL_BAD_CURRENT_SURFACE 0x3007 -#define EGL_BAD_DISPLAY 0x3008 -#define EGL_BAD_MATCH 0x3009 -#define EGL_BAD_NATIVE_PIXMAP 0x300A -#define EGL_BAD_NATIVE_WINDOW 0x300B -#define EGL_BAD_PARAMETER 0x300C -#define EGL_BAD_SURFACE 0x300D -#define EGL_CONTEXT_LOST 0x300E - -/* Config attributes */ -#define EGL_BUFFER_SIZE 0x3020 -#define EGL_ALPHA_SIZE 0x3021 -#define EGL_BLUE_SIZE 0x3022 -#define EGL_GREEN_SIZE 0x3023 -#define EGL_RED_SIZE 0x3024 -#define EGL_DEPTH_SIZE 0x3025 -#define EGL_STENCIL_SIZE 0x3026 -#define EGL_CONFIG_CAVEAT 0x3027 -#define EGL_CONFIG_ID 0x3028 -#define EGL_LEVEL 0x3029 -#define EGL_MAX_PBUFFER_HEIGHT 0x302A -#define EGL_MAX_PBUFFER_PIXELS 0x302B -#define EGL_MAX_PBUFFER_WIDTH 0x302C -#define EGL_NATIVE_RENDERABLE 0x302D -#define EGL_NATIVE_VISUAL_ID 0x302E -#define EGL_NATIVE_VISUAL_TYPE 0x302F -#define EGL_SAMPLES 0x3031 -#define EGL_SAMPLE_BUFFERS 0x3032 -#define EGL_SURFACE_TYPE 0x3033 -#define EGL_TRANSPARENT_TYPE 0x3034 -#define EGL_TRANSPARENT_BLUE_VALUE 0x3035 -#define EGL_TRANSPARENT_GREEN_VALUE 0x3036 -#define EGL_TRANSPARENT_RED_VALUE 0x3037 -#define EGL_NONE 0x3038 -#define EGL_BIND_TO_TEXTURE_RGB 0x3039 -#define EGL_BIND_TO_TEXTURE_RGBA 0x303A -#define EGL_MIN_SWAP_INTERVAL 0x303B -#define EGL_MAX_SWAP_INTERVAL 0x303C -#define EGL_LUMINANCE_SIZE 0x303D -#define EGL_ALPHA_MASK_SIZE 0x303E -#define EGL_COLOR_BUFFER_TYPE 0x303F -#define EGL_RENDERABLE_TYPE 0x3040 - -/* Config values */ -#define EGL_DONT_CARE ((EGLint)-1) - -#define EGL_SLOW_CONFIG 0x3050 -#define EGL_NON_CONFORMANT_CONFIG 0x3051 -#define EGL_TRANSPARENT_RGB 0x3052 -#define EGL_NO_TEXTURE 0x305C -#define EGL_TEXTURE_RGB 0x305D -#define EGL_TEXTURE_RGBA 0x305E -#define EGL_TEXTURE_2D 0x305F -#define EGL_RGB_BUFFER 0x308E -#define EGL_LUMINANCE_BUFFER 0x308F - -/* Config attribute mask bits */ -#define EGL_PBUFFER_BIT 0x01 -#define EGL_PIXMAP_BIT 0x02 -#define EGL_WINDOW_BIT 0x04 -#define EGL_OPENGL_ES_BIT 0x01 -#define EGL_OPENVG_BIT 0x02 - -/* String names */ -#define EGL_VENDOR 0x3053 -#define EGL_VERSION 0x3054 -#define EGL_EXTENSIONS 0x3055 -#define EGL_CLIENT_APIS 0x308D - -/* Surface attributes */ -#define EGL_HEIGHT 0x3056 -#define EGL_WIDTH 0x3057 -#define EGL_LARGEST_PBUFFER 0x3058 -#define EGL_TEXTURE_FORMAT 0x3080 -#define EGL_TEXTURE_TARGET 0x3081 -#define EGL_MIPMAP_TEXTURE 0x3082 -#define EGL_MIPMAP_LEVEL 0x3083 -#define EGL_RENDER_BUFFER 0x3086 -#define EGL_COLORSPACE 0x3087 -#define EGL_ALPHA_FORMAT 0x3088 -#define EGL_HORIZONTAL_RESOLUTION 0x3090 -#define EGL_VERTICAL_RESOLUTION 0x3091 -#define EGL_PIXEL_ASPECT_RATIO 0x3092 -#define EGL_SWAP_BEHAVIOR 0x3093 - -#define EGL_BACK_BUFFER 0x3084 -#define EGL_SINGLE_BUFFER 0x3085 - -#define EGL_DISPLAY_SCALING 10000 - -#define EGL_UNKNOWN ((EGLint)-1) - -/* Back buffer swap behaviors */ -#define EGL_BUFFER_PRESERVED 0x3094 -#define EGL_BUFFER_DESTROYED 0x3095 - -/* CreatePbufferFromClientBuffer buffer types */ -#define EGL_OPENVG_IMAGE 0x3096 - -/* QueryContext targets */ -#define EGL_CONTEXT_CLIENT_TYPE 0x3097 - -/* BindAPI/QueryAPI targets */ -#define EGL_OPENGL_ES_API 0x30A0 -#define EGL_OPENVG_API 0x30A1 - -/* WaitNative engines */ -#define EGL_CORE_NATIVE_ENGINE 0x305B - -/* Current surfaces */ -#define EGL_DRAW 0x3059 -#define EGL_READ 0x305A - - -EGLDisplay eglGetDisplay(NativeDisplayType display); -EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor); -EGLBoolean eglTerminate(EGLDisplay dpy); - -EGLBoolean eglGetConfigs( EGLDisplay dpy, - EGLConfig *configs, - EGLint config_size, EGLint *num_config); - -EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list, - EGLConfig *configs, EGLint config_size, - EGLint *num_config); - -EGLBoolean eglGetConfigAttrib( EGLDisplay dpy, EGLConfig config, - EGLint attribute, EGLint *value); - -EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, - NativeWindowType window, - const EGLint *attrib_list); - -EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config, - NativePixmapType pixmap, - const EGLint *attrib_list); - -EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config, - const EGLint *attrib_list); - -EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface); - -EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface, - EGLint attribute, EGLint *value); - -EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, - EGLContext share_list, const EGLint *attrib_list); - -EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx); - -EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw, - EGLSurface read, EGLContext ctx); - -EGLContext eglGetCurrentContext(void); -EGLSurface eglGetCurrentSurface(EGLint readdraw); -EGLDisplay eglGetCurrentDisplay(void); -EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx, - EGLint attribute, EGLint *value); - -EGLBoolean eglWaitGL(void); -EGLBoolean eglWaitNative(EGLint engine); -EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw); -EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface, - NativePixmapType target); - -EGLint eglGetError(void); -const char* eglQueryString(EGLDisplay dpy, EGLint name); -void (*eglGetProcAddress (const char *procname))(); - -/* ---------------------------------------------------------------------------- - * EGL 1.1 - * ---------------------------------------------------------------------------- - */ - -EGLBoolean eglSurfaceAttrib( - EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value); -EGLBoolean eglBindTexImage( - EGLDisplay dpy, EGLSurface surface, EGLint buffer); -EGLBoolean eglReleaseTexImage( - EGLDisplay dpy, EGLSurface surface, EGLint buffer); - -EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval); - -/* ---------------------------------------------------------------------------- - * EGL 1.2 - * ---------------------------------------------------------------------------- - */ - -EGLBoolean eglBindAPI(EGLenum api); -EGLenum eglQueryAPI(void); -EGLBoolean eglWaitClient(void); -EGLBoolean eglReleaseThread(void); -EGLSurface eglCreatePbufferFromClientBuffer( - EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, - EGLConfig config, const EGLint *attrib_list); - -/* ---------------------------------------------------------------------------- - * Android extentions - * ---------------------------------------------------------------------------- - */ - -EGLBoolean eglSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw, - EGLint l, EGLint t, EGLint w, EGLint h); - -EGLBoolean eglCopyFrontToBackANDROID(EGLDisplay dpy, - EGLSurface surface, - EGLint l, EGLint t, EGLint w, EGLint h); - -const char* eglQueryStringConfigANDROID( - EGLDisplay dpy, EGLConfig config, EGLint name); - -void* eglGetRenderBufferAddressANDROID(EGLDisplay dpy, EGLSurface surface); - -EGLBoolean eglCopyBitsANDROID(EGLDisplay dpy, - NativeWindowType draw, EGLint x, EGLint y, - NativeWindowType read, - EGLint crop_x, EGLint crop_y, EGLint crop_w, EGLint crop_h, - EGLint flags); - - -#ifdef __cplusplus -} -#endif - - -#endif /*ANDROID_EGL_H*/ - diff --git a/android/testproject/jni/eglnatives.h b/android/testproject/jni/eglnatives.h deleted file mode 100644 index 9d72be84e..000000000 --- a/android/testproject/jni/eglnatives.h +++ /dev/null @@ -1,277 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * 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 - * - * http://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. - */ - -#ifndef ANDROID_EGLNATIVES_H -#define ANDROID_EGLNATIVES_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif -/*****************************************************************************/ - -struct egl_native_window_t; -struct egl_native_pixmap_t; - - -typedef struct egl_native_window_t* NativeWindowType; -typedef struct egl_native_pixmap_t* NativePixmapType; -typedef void* NativeDisplayType; - -/* - * This a conveniance function to create a NativeWindowType surface - * that maps to the whole screen - * This function is actually implemented in libui.so - */ - -NativeWindowType android_createDisplaySurface(); - -/* flags returned from swapBuffer */ -#define EGL_NATIVES_FLAG_SIZE_CHANGED 0x00000001 - -/* surface flags */ -#define EGL_NATIVES_FLAG_DESTROY_BACKBUFFER 0x00000001 - -enum native_pixel_format_t -{ - NATIVE_PIXEL_FORMAT_RGBA_8888 = 1, - NATIVE_PIXEL_FORMAT_RGB_565 = 4, - NATIVE_PIXEL_FORMAT_RGBA_5551 = 6, - NATIVE_PIXEL_FORMAT_RGBA_4444 = 7, - NATIVE_PIXEL_FORMAT_YCbCr_422_SP= 0x10, - NATIVE_PIXEL_FORMAT_YCbCr_420_SP= 0x11, -}; - -enum native_memory_type_t -{ - NATIVE_MEMORY_TYPE_PMEM = 0, - NATIVE_MEMORY_TYPE_GPU = 1, - NATIVE_MEMORY_TYPE_FB = 2, - NATIVE_MEMORY_TYPE_HEAP = 128 -}; - - -struct egl_native_window_t -{ - /* - * magic must be set to 0x600913 - */ - uint32_t magic; - - /* - * must be sizeof(egl_native_window_t) - */ - uint32_t version; - - /* - * ident is reserved for the Android platform - */ - uint32_t ident; - - /* - * width, height and stride of the window in pixels - * Any of these value can be nul in which case GL commands are - * accepted and processed as usual, but not rendering occurs. - */ - int width; // w=h=0 is legal - int height; - int stride; - - /* - * format of the native window (see ui/PixelFormat.h) - */ - int format; - - /* - * Offset of the bits in the VRAM - */ - intptr_t offset; - - /* - * flags describing some attributes of this surface - * EGL_NATIVES_FLAG_DESTROY_BACKBUFFER: backbuffer not preserved after - * eglSwapBuffers - */ - uint32_t flags; - - /* - * horizontal and vertical resolution in DPI - */ - float xdpi; - float ydpi; - - /* - * refresh rate in frames per second (Hz) - */ - float fps; - - - /* - * Base memory virtual address of the surface in the CPU side - */ - intptr_t base; - - /* - * Heap the offset above is based from - */ - int fd; - - /* - * Memory type the surface resides into - */ - uint8_t memory_type; - - /* - * Reserved for future use. MUST BE ZERO. - */ - uint8_t reserved_pad[3]; - int reserved[8]; - - /* - * Vertical stride (only relevant with planar formats) - */ - - int vstride; - - /* - * Hook called by EGL to hold a reference on this structure - */ - void (*incRef)(NativeWindowType window); - - /* - * Hook called by EGL to release a reference on this structure - */ - void (*decRef)(NativeWindowType window); - - /* - * Hook called by EGL to perform a page flip. This function - * may update the size attributes above, in which case it returns - * the EGL_NATIVES_FLAG_SIZE_CHANGED bit set. - */ - uint32_t (*swapBuffers)(NativeWindowType window); - - /* - * Hook called by EGL to set the swap rectangle. this hook can be - * null (operation not supported) - */ - void (*setSwapRectangle)(NativeWindowType window, int l, int t, int w, int h); - - /* - * Reserved for future use. MUST BE ZERO. - */ - void (*reserved_proc_0)(void); - - - /* - * Hook called by EGL to retrieve the next buffer to render into. - * This call updates this structure. - */ - uint32_t (*nextBuffer)(NativeWindowType window); - - /* - * Hook called by EGL when the native surface is associated to EGL - * (eglCreateWindowSurface). Can be NULL. - */ - void (*connect)(NativeWindowType window); - - /* - * Hook called by EGL when eglDestroySurface is called. Can be NULL. - */ - void (*disconnect)(NativeWindowType window); - - /* - * Reserved for future use. MUST BE ZERO. - */ - void (*reserved_proc[11])(void); - - /* - * Some storage reserved for the oem driver. - */ - intptr_t oem[4]; -}; - - -struct egl_native_pixmap_t -{ - int32_t version; /* must be 32 */ - int32_t width; - int32_t height; - int32_t stride; - uint8_t* data; - uint8_t format; - uint8_t rfu[3]; - union { - uint32_t compressedFormat; - int32_t vstride; - }; - int32_t reserved; -}; - -/*****************************************************************************/ - -/* - * OEM's egl's library (libhgl.so) must imlement these hooks to allocate - * the GPU memory they need - */ - - -typedef struct -{ - // for internal use - void* user; - // virtual address of this area - void* base; - // size of this area in bytes - size_t size; - // physical address of this area - void* phys; - // offset in this area available to the GPU - size_t offset; - // fd of this area - int fd; -} gpu_area_t; - -typedef struct -{ - // area where GPU registers are mapped - gpu_area_t regs; - // number of extra areas (currently limited to 2) - int32_t count; - // extra GPU areas (currently limited to 2) - gpu_area_t gpu[2]; -} request_gpu_t; - - -typedef request_gpu_t* (*OEM_EGL_acquire_gpu_t)(void* user); -typedef int (*OEM_EGL_release_gpu_t)(void* user, request_gpu_t* handle); -typedef void (*register_gpu_t) - (void* user, OEM_EGL_acquire_gpu_t, OEM_EGL_release_gpu_t); - -void oem_register_gpu( - void* user, - OEM_EGL_acquire_gpu_t acquire, - OEM_EGL_release_gpu_t release); - - -/*****************************************************************************/ - -#ifdef __cplusplus -} -#endif - -#endif /* ANDROID_EGLNATIVES_H */ - diff --git a/android/testproject/jni/egltypes.h b/android/testproject/jni/egltypes.h deleted file mode 100644 index fd68fa351..000000000 --- a/android/testproject/jni/egltypes.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * 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 - * - * http://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. - */ - -#ifndef ANDROID_EGL_TYPES_H -#define ANDROID_EGL_TYPES_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef unsigned int EGLBoolean; -typedef int32_t EGLint; -typedef int EGLenum; -typedef void *EGLDisplay; -typedef void *EGLConfig; -typedef void *EGLSurface; -typedef void *EGLContext; -typedef void *EGLClientBuffer; - -#define EGL_DEFAULT_DISPLAY ((NativeDisplayType)0) - -#define EGL_NO_CONTEXT ((EGLContext)0) -#define EGL_NO_DISPLAY ((EGLDisplay)0) -#define EGL_NO_SURFACE ((EGLSurface)0) - - -#ifdef __cplusplus -} -#endif - - -#endif /* ANDROID_EGL_TYPES_H */ - diff --git a/android/testproject/jni/importgl.cpp b/android/testproject/jni/importgl.cpp deleted file mode 100644 index f501636c7..000000000 --- a/android/testproject/jni/importgl.cpp +++ /dev/null @@ -1,168 +0,0 @@ -/* San Angeles Observation OpenGL ES version example - * Copyright 2004-2005 Jetro Lauha - * All rights reserved. - * Web: http://iki.fi/jetro/ - * - * This source is free software; you can redistribute it and/or - * modify it under the terms of EITHER: - * (1) The GNU Lesser General Public License as published by the Free - * Software Foundation; either version 2.1 of the License, or (at - * your option) any later version. The text of the GNU Lesser - * General Public License is included with this source in the - * file LICENSE-LGPL.txt. - * (2) The BSD-style license that is included with this source in - * the file LICENSE-BSD.txt. - * - * This source 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 files - * LICENSE-LGPL.txt and LICENSE-BSD.txt for more details. - * - * $Id: importgl.c,v 1.4 2005/02/08 18:42:55 tonic Exp $ - * $Revision: 1.4 $ - */ - -#undef WIN32 -#undef LINUX -#ifdef _MSC_VER -// Desktop or mobile Win32 environment: -#define WIN32 -#else -// Linux environment: -#define LINUX -#endif - -#ifndef DISABLE_IMPORTGL - -#if defined(WIN32) -#define WIN32_LEAN_AND_MEAN -#include -#include -static HMODULE sGLESDLL = NULL; -#endif // WIN32 - -#ifdef LINUX -#include -#include -static void *sGLESSO = NULL; -#endif // LINUX - -#endif /* DISABLE_IMPORTGL */ - -#define IMPORTGL_NO_FNPTR_DEFS -#define IMPORTGL_API -#define IMPORTGL_FNPTRINIT = NULL -#include "importgl.h" - - -/* Imports function pointers to selected function calls in OpenGL ES Common - * or Common Lite profile DLL or shared object. The function pointers are - * stored as global symbols with equivalent function name but prefixed with - * "funcPtr_". Standard gl/egl calls are redirected to the function pointers - * with preprocessor macros (see importgl.h). - */ -int importGLInit() -{ - int result = 1; - -#ifndef DISABLE_IMPORTGL - -#undef IMPORT_FUNC - -#ifdef WIN32 - sGLESDLL = LoadLibrary(_T("libGLES_CM.dll")); - if (sGLESDLL == NULL) - sGLESDLL = LoadLibrary(_T("libGLES_CL.dll")); - if (sGLESDLL == NULL) - return 0; // Cannot find OpenGL ES Common or Common Lite DLL. - - /* The following fetches address to each egl & gl function call - * and stores it to the related function pointer. Casting through - * void * results in warnings with VC warning level 4, which - * could be fixed by casting to the true type for each fetch. - */ -#define IMPORT_FUNC(funcName) do { \ - void *procAddress = (void *)GetProcAddress(sGLESDLL, _T(#funcName)); \ - if (procAddress == NULL) result = 0; \ - *((void **)&FNPTR(funcName)) = procAddress; } while (0) -#endif // WIN32 - -#ifdef LINUX -#ifdef ANDROID_NDK - sGLESSO = dlopen("libGLESv1_CM.so", RTLD_NOW); -#else /* !ANDROID_NDK */ - sGLESSO = dlopen("libGLES_CM.so", RTLD_NOW); - if (sGLESSO == NULL) - sGLESSO = dlopen("libGLES_CL.so", RTLD_NOW); -#endif /* !ANDROID_NDK */ - if (sGLESSO == NULL) - return 0; // Cannot find OpenGL ES Common or Common Lite SO. - -#define IMPORT_FUNC(funcName) do { \ - void *procAddress = (void *)dlsym(sGLESSO, #funcName); \ - if (procAddress == NULL) result = 0; \ - *((void **)&FNPTR(funcName)) = procAddress; } while (0) -#endif // LINUX - -#ifndef ANDROID_NDK - IMPORT_FUNC(eglChooseConfig); - IMPORT_FUNC(eglCreateContext); - IMPORT_FUNC(eglCreateWindowSurface); - IMPORT_FUNC(eglDestroyContext); - IMPORT_FUNC(eglDestroySurface); - IMPORT_FUNC(eglGetConfigAttrib); - IMPORT_FUNC(eglGetConfigs); - IMPORT_FUNC(eglGetDisplay); - IMPORT_FUNC(eglGetError); - IMPORT_FUNC(eglInitialize); - IMPORT_FUNC(eglMakeCurrent); - IMPORT_FUNC(eglSwapBuffers); - IMPORT_FUNC(eglTerminate); -#endif /* !ANDROID_NDK */ - - IMPORT_FUNC(glBlendFunc); - IMPORT_FUNC(glClear); - IMPORT_FUNC(glClearColorx); - IMPORT_FUNC(glColor4x); - IMPORT_FUNC(glColorPointer); - IMPORT_FUNC(glDisable); - IMPORT_FUNC(glDisableClientState); - IMPORT_FUNC(glDrawArrays); - IMPORT_FUNC(glEnable); - IMPORT_FUNC(glEnableClientState); - IMPORT_FUNC(glFrustumx); - IMPORT_FUNC(glGetError); - IMPORT_FUNC(glLightxv); - IMPORT_FUNC(glLoadIdentity); - IMPORT_FUNC(glMaterialx); - IMPORT_FUNC(glMaterialxv); - IMPORT_FUNC(glMatrixMode); - IMPORT_FUNC(glMultMatrixx); - IMPORT_FUNC(glNormalPointer); - IMPORT_FUNC(glPopMatrix); - IMPORT_FUNC(glPushMatrix); - IMPORT_FUNC(glRotatex); - IMPORT_FUNC(glScalex); - IMPORT_FUNC(glShadeModel); - IMPORT_FUNC(glTranslatex); - IMPORT_FUNC(glVertexPointer); - IMPORT_FUNC(glViewport); - -#endif /* DISABLE_IMPORTGL */ - - return result; -} - - -void importGLDeinit() -{ -#ifndef DISABLE_IMPORTGL -#ifdef WIN32 - FreeLibrary(sGLESDLL); -#endif - -#ifdef LINUX - dlclose(sGLESSO); -#endif -#endif /* DISABLE_IMPORTGL */ -} diff --git a/android/testproject/jni/importgl.h b/android/testproject/jni/importgl.h deleted file mode 100644 index b05e0c84f..000000000 --- a/android/testproject/jni/importgl.h +++ /dev/null @@ -1,172 +0,0 @@ -/* San Angeles Observation OpenGL ES version example - * Copyright 2004-2005 Jetro Lauha - * All rights reserved. - * Web: http://iki.fi/jetro/ - * - * This source is free software; you can redistribute it and/or - * modify it under the terms of EITHER: - * (1) The GNU Lesser General Public License as published by the Free - * Software Foundation; either version 2.1 of the License, or (at - * your option) any later version. The text of the GNU Lesser - * General Public License is included with this source in the - * file LICENSE-LGPL.txt. - * (2) The BSD-style license that is included with this source in - * the file LICENSE-BSD.txt. - * - * This source 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 files - * LICENSE-LGPL.txt and LICENSE-BSD.txt for more details. - * - * $Id: importgl.h,v 1.4 2005/02/24 20:29:33 tonic Exp $ - * $Revision: 1.4 $ - */ - -#ifndef IMPORTGL_H_INCLUDED -#define IMPORTGL_H_INCLUDED - - -#ifdef __cplusplus -extern "C" { -#endif - - -#include -#ifndef ANDROID_NDK -#include -#endif /* !ANDROID_NDK */ - -/* Use DISABLE_IMPORTGL if you want to link the OpenGL ES at - * compile/link time and not import it dynamically runtime. - */ -#ifndef DISABLE_IMPORTGL - - -/* Dynamically fetches pointers to the egl & gl functions. - * Should be called once on application initialization. - * Returns non-zero on success and 0 on failure. - */ -extern int importGLInit(); - -/* Frees the handle to egl & gl functions library. - */ -extern void importGLDeinit(); - - -#ifndef IMPORTGL_API -#define IMPORTGL_API extern -#endif -#ifndef IMPORTGL_FNPTRINIT -#define IMPORTGL_FNPTRINIT -#endif - -#define FNDEF(retType, funcName, args) IMPORTGL_API retType (*funcPtr_##funcName) args IMPORTGL_FNPTRINIT - -#ifndef ANDROID_NDK -FNDEF(EGLBoolean, eglChooseConfig, (EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config)); -FNDEF(EGLContext, eglCreateContext, (EGLDisplay dpy, EGLConfig config, EGLContext share_list, const EGLint *attrib_list)); -FNDEF(EGLSurface, eglCreateWindowSurface, (EGLDisplay dpy, EGLConfig config, NativeWindowType window, const EGLint *attrib_list)); -FNDEF(EGLBoolean, eglDestroyContext, (EGLDisplay dpy, EGLContext ctx)); -FNDEF(EGLBoolean, eglDestroySurface, (EGLDisplay dpy, EGLSurface surface)); -FNDEF(EGLBoolean, eglGetConfigAttrib, (EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value)); -FNDEF(EGLBoolean, eglGetConfigs, (EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config)); -FNDEF(EGLDisplay, eglGetDisplay, (NativeDisplayType display)); -FNDEF(EGLint, eglGetError, (void)); -FNDEF(EGLBoolean, eglInitialize, (EGLDisplay dpy, EGLint *major, EGLint *minor)); -FNDEF(EGLBoolean, eglMakeCurrent, (EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx)); -FNDEF(EGLBoolean, eglSwapBuffers, (EGLDisplay dpy, EGLSurface draw)); -FNDEF(EGLBoolean, eglTerminate, (EGLDisplay dpy)); -#endif /* !ANDROID_NDK */ - -FNDEF(void, glBlendFunc, (GLenum sfactor, GLenum dfactor)); -FNDEF(void, glClear, (GLbitfield mask)); -FNDEF(void, glClearColorx, (GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha)); -FNDEF(void, glColor4x, (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha)); -FNDEF(void, glColorPointer, (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)); -FNDEF(void, glDisable, (GLenum cap)); -FNDEF(void, glDisableClientState, (GLenum array)); -FNDEF(void, glDrawArrays, (GLenum mode, GLint first, GLsizei count)); -FNDEF(void, glEnable, (GLenum cap)); -FNDEF(void, glEnableClientState, (GLenum array)); -FNDEF(void, glFrustumx, (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar)); -FNDEF(GLenum, glGetError, (void)); -FNDEF(void, glLightxv, (GLenum light, GLenum pname, const GLfixed *params)); -FNDEF(void, glLoadIdentity, (void)); -FNDEF(void, glMaterialx, (GLenum face, GLenum pname, GLfixed param)); -FNDEF(void, glMaterialxv, (GLenum face, GLenum pname, const GLfixed *params)); -FNDEF(void, glMatrixMode, (GLenum mode)); -FNDEF(void, glMultMatrixx, (const GLfixed *m)); -FNDEF(void, glNormalPointer, (GLenum type, GLsizei stride, const GLvoid *pointer)); -FNDEF(void, glPopMatrix, (void)); -FNDEF(void, glPushMatrix, (void)); -FNDEF(void, glRotatex, (GLfixed angle, GLfixed x, GLfixed y, GLfixed z)); -FNDEF(void, glScalex, (GLfixed x, GLfixed y, GLfixed z)); -FNDEF(void, glShadeModel, (GLenum mode)); -FNDEF(void, glTranslatex, (GLfixed x, GLfixed y, GLfixed z)); -FNDEF(void, glVertexPointer, (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)); -FNDEF(void, glViewport, (GLint x, GLint y, GLsizei width, GLsizei height)); - - -#undef FN -#define FNPTR(name) funcPtr_##name - -#ifndef IMPORTGL_NO_FNPTR_DEFS - -// Redirect egl* and gl* function calls to funcPtr_egl* and funcPtr_gl*. - -#ifndef ANDROID_NDK -#define eglChooseConfig FNPTR(eglChooseConfig) -#define eglCreateContext FNPTR(eglCreateContext) -#define eglCreateWindowSurface FNPTR(eglCreateWindowSurface) -#define eglDestroyContext FNPTR(eglDestroyContext) -#define eglDestroySurface FNPTR(eglDestroySurface) -#define eglGetConfigAttrib FNPTR(eglGetConfigAttrib) -#define eglGetConfigs FNPTR(eglGetConfigs) -#define eglGetDisplay FNPTR(eglGetDisplay) -#define eglGetError FNPTR(eglGetError) -#define eglInitialize FNPTR(eglInitialize) -#define eglMakeCurrent FNPTR(eglMakeCurrent) -#define eglSwapBuffers FNPTR(eglSwapBuffers) -#define eglTerminate FNPTR(eglTerminate) -#endif /* !ANDROID_NDK */ - -#define glBlendFunc FNPTR(glBlendFunc) -#define glClear FNPTR(glClear) -#define glClearColorx FNPTR(glClearColorx) -#define glColor4x FNPTR(glColor4x) -#define glColorPointer FNPTR(glColorPointer) -#define glDisable FNPTR(glDisable) -#define glDisableClientState FNPTR(glDisableClientState) -#define glDrawArrays FNPTR(glDrawArrays) -#define glEnable FNPTR(glEnable) -#define glEnableClientState FNPTR(glEnableClientState) -#define glFrustumx FNPTR(glFrustumx) -#define glGetError FNPTR(glGetError) -#define glLightxv FNPTR(glLightxv) -#define glLoadIdentity FNPTR(glLoadIdentity) -#define glMaterialx FNPTR(glMaterialx) -#define glMaterialxv FNPTR(glMaterialxv) -#define glMatrixMode FNPTR(glMatrixMode) -#define glMultMatrixx FNPTR(glMultMatrixx) -#define glNormalPointer FNPTR(glNormalPointer) -#define glPopMatrix FNPTR(glPopMatrix) -#define glPushMatrix FNPTR(glPushMatrix) -#define glRotatex FNPTR(glRotatex) -#define glScalex FNPTR(glScalex) -#define glShadeModel FNPTR(glShadeModel) -#define glTranslatex FNPTR(glTranslatex) -#define glVertexPointer FNPTR(glVertexPointer) -#define glViewport FNPTR(glViewport) - -#endif // !IMPORTGL_NO_FNPTR_DEFS - - -#endif // !DISABLE_IMPORTGL - - -#ifdef __cplusplus -} -#endif - - -#endif // !IMPORTGL_H_INCLUDED diff --git a/android/testproject/jni/lesson05.c b/android/testproject/jni/lesson05.c deleted file mode 100644 index 92bb07153..000000000 --- a/android/testproject/jni/lesson05.c +++ /dev/null @@ -1,574 +0,0 @@ -/* - * This code was created by Jeff Molofee '99 - * (ported to Linux/SDL by Ti Leggett '01) - * - * If you've found this code useful, please let me know. - * - * Visit Jeff at http://nehe.gamedev.net/ - * - * or for port-specific comments, questions, bugreports etc. - * email to leggett@eecs.tulane.edu - */ - -#include -#include -#include - -#include - -#include - - -#ifdef ANDROID -#include -#else -#include -#include -#endif -#include "SDL.h" - -/* screen width, height, and bit depth */ -#define SCREEN_WIDTH 320 -#define SCREEN_HEIGHT 430 -#define SCREEN_BPP 16 - -/* Define our booleans */ -#define TRUE 1 -#define FALSE 0 - -/* This is our SDL surface */ -SDL_Surface *surface; - -int rotation = 0; - - -/************************************** - gluperspective implementation -**************************************/ -void gluPerspective(double fovy, double aspect, double zNear, double zFar){ - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - double xmin, xmax, ymin, ymax; - ymax = zNear * tan(fovy * M_PI / 360.0); - ymin = -ymax; - xmin = ymin * aspect; - xmax = ymax * aspect; - glFrustumf(xmin, xmax, ymin, ymax, zNear, zFar); -} - - -/************************************** - glulookat implementation -**************************************/ -void gluLookAt(GLfloat eyex, GLfloat eyey, GLfloat eyez, - GLfloat centerx, GLfloat centery, GLfloat centerz, - GLfloat upx, GLfloat upy, GLfloat upz) -{ - GLfloat m[16]; - GLfloat x[3], y[3], z[3]; - GLfloat mag; - - /* Make rotation matrix */ - - /* Z vector */ - z[0] = eyex - centerx; - z[1] = eyey - centery; - z[2] = eyez - centerz; - mag = sqrt(z[0] * z[0] + z[1] * z[1] + z[2] * z[2]); - if (mag) { /* mpichler, 19950515 */ - z[0] /= mag; - z[1] /= mag; - z[2] /= mag; - } - - /* Y vector */ - y[0] = upx; - y[1] = upy; - y[2] = upz; - - /* X vector = Y cross Z */ - x[0] = y[1] * z[2] - y[2] * z[1]; - x[1] = -y[0] * z[2] + y[2] * z[0]; - x[2] = y[0] * z[1] - y[1] * z[0]; - - /* Recompute Y = Z cross X */ - y[0] = z[1] * x[2] - z[2] * x[1]; - y[1] = -z[0] * x[2] + z[2] * x[0]; - y[2] = z[0] * x[1] - z[1] * x[0]; - - /* mpichler, 19950515 */ - /* cross product gives area of parallelogram, which is < 1.0 for - * non-perpendicular unit-length vectors; so normalize x, y here - */ - - mag = sqrt(x[0] * x[0] + x[1] * x[1] + x[2] * x[2]); - if (mag) { - x[0] /= mag; - x[1] /= mag; - x[2] /= mag; - } - - mag = sqrt(y[0] * y[0] + y[1] * y[1] + y[2] * y[2]); - if (mag) { - y[0] /= mag; - y[1] /= mag; - y[2] /= mag; - } - -#define M(row,col) m[col*4+row] - M(0, 0) = x[0]; - M(0, 1) = x[1]; - M(0, 2) = x[2]; - M(0, 3) = 0.0; - M(1, 0) = y[0]; - M(1, 1) = y[1]; - M(1, 2) = y[2]; - M(1, 3) = 0.0; - M(2, 0) = z[0]; - M(2, 1) = z[1]; - M(2, 2) = z[2]; - M(2, 3) = 0.0; - M(3, 0) = 0.0; - M(3, 1) = 0.0; - M(3, 2) = 0.0; - M(3, 3) = 1.0; -#undef M - glMultMatrixf(m); - - /* Translate Eye to Origin */ - glTranslatef(-eyex, -eyey, -eyez); - -} - - - - - -/* function to release/destroy our resources and restoring the old desktop */ -void Quit( int returnCode ) -{ - /* clean up the window */ - SDL_Quit( ); - - /* and exit appropriately */ - exit( returnCode ); -} - -/* function to reset our viewport after a window resize */ -int resizeWindow( int width, int height ) -{ - /* Height / width ration */ - GLfloat ratio; - - /* Protect against a divide by zero */ - if ( height == 0 ) - height = 1; - - ratio = ( GLfloat )width / ( GLfloat )height; - - /* Setup our viewport. */ - glViewport( 0, 0, ( GLsizei )width, ( GLsizei )height ); - - /* change to the projection matrix and set our viewing volume. */ - glMatrixMode( GL_PROJECTION ); - glLoadIdentity( ); - - /* Set our perspective */ - gluPerspective( 45.0f, ratio, 0.1f, 100.0f ); - - /* Make sure we're chaning the model view and not the projection */ - glMatrixMode( GL_MODELVIEW ); - - /* Reset The View */ - glLoadIdentity( ); - - return( TRUE ); -} - -/* function to handle key press events */ -void handleKeyPress( SDL_keysym *keysym ) -{ - switch ( keysym->sym ) - { - case SDLK_ESCAPE: - /* ESC key was pressed */ - Quit( 0 ); - break; - case SDLK_F1: - /* F1 key was pressed - * this toggles fullscreen mode - */ - SDL_WM_ToggleFullScreen( surface ); - break; - case SDLK_LEFT: - rotation -= 30; - break; - - case SDLK_RIGHT: - rotation += 30; - break; - - default: - break; - } - - __android_log_print(ANDROID_LOG_INFO, "SDL","Keycode: %d, %d, %d\n", keysym->sym, SDLK_LEFT, SDLK_RIGHT); - - return; -} - -/* general OpenGL initialization function */ -int initGL( GLvoid ) -{ - - /* Enable smooth shading */ - glShadeModel( GL_SMOOTH ); - - /* Set the background black */ - glClearColor( 0.0f, 0.0f, 0.0f, 0.0f ); - - /* Depth buffer setup */ - //glClearDepth( 1.0f ); - - /* Enables Depth Testing */ - glEnable( GL_DEPTH_TEST ); - - /* The Type Of Depth Test To Do */ - glDepthFunc( GL_LEQUAL ); - - /* Really Nice Perspective Calculations */ - glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST ); - - return( TRUE ); -} - -/* Here goes our drawing code */ -int drawGLScene( GLvoid ) -{ - - static int Frames = 0; - static int T0 = 0; - - glViewport(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); - - glClearColorx(0,0,0,255); - glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - gluPerspective(45, (float)SCREEN_WIDTH / SCREEN_HEIGHT, 0.5f, 150); - - glMatrixMode(GL_MODELVIEW); - - glLoadIdentity(); - - //Camera - gluLookAt(0,0,5, 0,0,0, 0,1,0); - - //Draw a triangle - //glRotatef(iRot, 0, 1, 0); - - glRotatef( rotation, 0.0f, 1.0f, 0.0f ); - - - glEnableClientState (GL_VERTEX_ARRAY); - glEnableClientState (GL_COLOR_ARRAY); - - /* Rotate The Triangle On The Y axis ( NEW ) */ - //glRotatef( Frames % 360, 0.0f, 1.0f, 0.0f ); - - /* GLES variant of drawing a triangle */ - const GLfloat triVertices[][9] = { - { /* Front Triangle */ - 0.0f, 1.0f, 0.0f, /* Top Of Triangle */ - -1.0f, -1.0f, 1.0f, /* Left Of Triangle */ - 1.0f, -1.0f, 1.0f /* Right Of Triangle */ - }, { /* Right Triangle */ - 0.0f, 1.0f, 0.0f, /* Top Of Triangle */ - 1.0f, -1.0f, 1.0f, /* Left Of Triangle */ - 1.0f, -1.0f, -1.0f /* Right Of Triangle */ - }, { /* Back Triangle */ - 0.0f, 1.0f, 0.0f, /* Top Of Triangle */ - 1.0f, -1.0f, -1.0f, /* Left Of Triangle */ - -1.0f, -1.0f, -1.0f /* Right Of Triangle */ - }, { /* Left Triangle */ - 0.0f, 1.0f, 0.0f, /* Top Of Triangle */ - -1.0f, -1.0f, -1.0f, /* Left Of Triangle */ - -1.0f, -1.0f, 1.0f /* Right Of Triangle */ - } - }; - - /* unlike GL, GLES does not support RGB. We have to use RGBA instead */ - const GLfloat triColors[][12] = { - { /* Front triangle */ - 1.0f, 0.0f, 0.0f, 1.0f, /* Red */ - 0.0f, 1.0f, 0.0f, 1.0f, /* Green */ - 0.0f, 0.0f, 1.0f, 1.0f /* Blue */ - }, { /* Right triangle */ - 1.0f, 0.0f, 0.0f, 1.0f, /* Red */ - 0.0f, 0.0f, 1.0f, 1.0f, /* Blue */ - 0.0f, 1.0f, 0.0f, 1.0f /* Green */ - }, { /* Back triangle */ - 1.0f, 0.0f, 0.0f, 1.0f, /* Red */ - 0.0f, 1.0f, 0.0f, 1.0f, /* Green */ - 0.0f, 0.0f, 1.0f, 1.0f /* Blue */ - }, { /* Left triangle */ - 1.0f, 0.0f, 0.0f, 1.0f, /* Red */ - 0.0f, 0.0f, 1.0f, 1.0f, /* Blue */ - 0.0f, 1.0f, 0.0f, 1.0f /* Green */ - } - }; - - glEnableClientState(GL_COLOR_ARRAY); - - int tri=0; - - /* Loop through all Triangles */ - for(tri=0;tri= 5000) { - GLfloat seconds = (t - T0) / 1000.0; - GLfloat fps = Frames / seconds; - __android_log_print(ANDROID_LOG_INFO, "SDL","%d frames in %g seconds = %g FPS\n", Frames, seconds, fps); - T0 = t; - Frames = 0; - } - } - - rotation++; - - return( TRUE ); -} - - -struct -{ - SDL_AudioSpec spec; - Uint8 *sound; /* Pointer to wave data */ - Uint32 soundlen; /* Length of wave data */ - int soundpos; /* Current play position */ -} wave; - -void SDLCALL -fillerup(void *unused, Uint8 * stream, int len) -{ - __android_log_print(ANDROID_LOG_INFO, "SDL","FILLERUP\n"); - - Uint8 *waveptr; - int waveleft; - - /* Set up the pointers */ - waveptr = wave.sound + wave.soundpos; - waveleft = wave.soundlen - wave.soundpos; - - /* Go! */ - while (waveleft <= len) { - SDL_memcpy(stream, waveptr, waveleft); - stream += waveleft; - len -= waveleft; - waveptr = wave.sound; - waveleft = wave.soundlen; - wave.soundpos = 0; - } - SDL_memcpy(stream, waveptr, len); - wave.soundpos += len; -} - -void testAudio(){ - - const char *file = "/sdcard/sample.wav"; - - /* Load the SDL library */ - if (SDL_Init(SDL_INIT_AUDIO) < 0) { - __android_log_print(ANDROID_LOG_INFO, "SDL","Couldn't initialize SDL Audio: %s\n", SDL_GetError()); - return; - }else{ - __android_log_print(ANDROID_LOG_INFO, "SDL","Init audio ok\n"); - } - - /* Load the wave file into memory */ - if (SDL_LoadWAV(file, &wave.spec, &wave.sound, &wave.soundlen) == NULL) { - __android_log_print(ANDROID_LOG_INFO, "SDL", "Couldn't load %s: %s\n", file, SDL_GetError()); - return; - } - - wave.spec.callback = fillerup; - - __android_log_print(ANDROID_LOG_INFO, "SDL","Loaded: %d\n", wave.soundlen); - - - /* Initialize fillerup() variables */ - if (SDL_OpenAudio(&wave.spec, NULL) < 0) { - __android_log_print(ANDROID_LOG_INFO, "SDL", "Couldn't open audio: %s\n", SDL_GetError()); - SDL_FreeWAV(wave.sound); - return; - } - - __android_log_print(ANDROID_LOG_INFO, "SDL","Using audio driver: %s\n", SDL_GetCurrentAudioDriver()); - - /* Let the audio run */ - SDL_PauseAudio(0); - - __android_log_print(ANDROID_LOG_INFO, "SDL","Playing\n"); - - while (SDL_GetAudioStatus() == SDL_AUDIO_PLAYING){ - //__android_log_print(ANDROID_LOG_INFO, "SDL","Still playing\n"); - SDL_Delay(100); - } - - __android_log_print(ANDROID_LOG_INFO, "SDL","Closing down\n"); - - /* Clean up on signal */ - SDL_CloseAudio(); - SDL_FreeWAV(wave.sound); -} - -int SDL_main( int argc, char **argv ) -{ - - __android_log_print(ANDROID_LOG_INFO, "SDL","entry\n"); - - /* Flags to pass to SDL_SetVideoMode */ - int videoFlags; - /* main loop variable */ - int done = FALSE; - /* used to collect events */ - SDL_Event event; - /* this holds some info about our display */ - const SDL_VideoInfo *videoInfo; - /* whether or not the window is active */ - int isActive = TRUE; - - /* initialize SDL */ - if ( SDL_Init( SDL_INIT_VIDEO ) < 0 ) - { - __android_log_print(ANDROID_LOG_INFO, "SDL", "Video initialization failed: %s\n", - SDL_GetError( ) ); - Quit( 1 ); - } - - /* Fetch the video info */ - videoInfo = SDL_GetVideoInfo( ); - - if ( !videoInfo ) - { - __android_log_print(ANDROID_LOG_INFO, "SDL", "Video query failed: %s\n", - SDL_GetError( ) ); - Quit( 1 ); - } - - /* the flags to pass to SDL_SetVideoMode */ - videoFlags = SDL_OPENGL; /* Enable OpenGL in SDL */ - videoFlags |= SDL_GL_DOUBLEBUFFER; /* Enable double buffering */ - videoFlags |= SDL_HWPALETTE; /* Store the palette in hardware */ - videoFlags |= SDL_RESIZABLE; /* Enable window resizing */ - - /* This checks to see if surfaces can be stored in memory */ - if ( videoInfo->hw_available ) - videoFlags |= SDL_HWSURFACE; - else - videoFlags |= SDL_SWSURFACE; - - /* This checks if hardware blits can be done */ - if ( videoInfo->blit_hw ) - videoFlags |= SDL_HWACCEL; - - /* Sets up OpenGL double buffering */ - SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); - - /* get a SDL surface */ - surface = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, - videoFlags ); - - /* Verify there is a surface */ - if ( !surface ) - { - __android_log_print(ANDROID_LOG_INFO, "SDL", "Video mode set failed: %s\n", SDL_GetError( ) ); - Quit( 1 ); - } - - __android_log_print(ANDROID_LOG_INFO, "SDL","Made a video mode!\n"); - - /* initialize OpenGL */ - initGL( ); - - /* resize the initial window */ - resizeWindow( SCREEN_WIDTH, SCREEN_HEIGHT ); - - - testAudio(); - - - /* wait for events */ - while ( !done ) - { - /* handle the events in the queue */ - - while ( SDL_PollEvent( &event ) ) - { - switch( event.type ) - { - case SDL_ACTIVEEVENT: - /* Something's happend with our focus - * If we lost focus or we are iconified, we - * shouldn't draw the screen - */ - if ( event.active.gain == 0 ) - isActive = FALSE; - else - isActive = TRUE; - break; - case SDL_VIDEORESIZE: - /* handle resize event */ - surface = SDL_SetVideoMode( event.resize.w, - event.resize.h, - 16, videoFlags ); - if ( !surface ) - { - __android_log_print(ANDROID_LOG_INFO, "SDL","Could not get a surface after resize: %s\n", SDL_GetError( ) ); - Quit( 1 ); - } - resizeWindow( event.resize.w, event.resize.h ); - break; - case SDL_KEYDOWN: - /* handle key presses */ - handleKeyPress( &event.key.keysym ); - break; - case SDL_QUIT: - /* handle quit requests */ - done = TRUE; - __android_log_print(ANDROID_LOG_INFO, "SDL","App is shutting down\n"); - break; - default: - break; - } - } - - /* draw the scene */ - if ( isActive ) - drawGLScene( ); - } - - /* clean ourselves up and exit */ - Quit( 0 ); - - /* Should never get here */ - return( 0 ); -} - - diff --git a/android/testproject/local.properties b/android/testproject/local.properties deleted file mode 100644 index 27accedc4..000000000 --- a/android/testproject/local.properties +++ /dev/null @@ -1,10 +0,0 @@ -# This file is automatically generated by Android Tools. -# Do not modify this file -- YOUR CHANGES WILL BE ERASED! -# -# This file must *NOT* be checked in Version Control Systems, -# as it contains information specific to your local configuration. - -# location of the SDK. This is only used by Ant -# For customization when using a Version Control System, please read the -# header note. -sdk.dir=/home/paul/Projects/gsoc/sdk/android-sdk-linux_86 diff --git a/android/testproject/res/drawable-hdpi/icon.png b/android/testproject/res/drawable-hdpi/icon.png deleted file mode 100644 index 8074c4c571b8cd19e27f4ee5545df367420686d7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4147 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 diff --git a/android/testproject/res/drawable-ldpi/icon.png b/android/testproject/res/drawable-ldpi/icon.png deleted file mode 100644 index 1095584ec21f71cd0afc9e0993aa2209671b590c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1723 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 - - - - diff --git a/android/testproject/res/values/strings.xml b/android/testproject/res/values/strings.xml deleted file mode 100644 index 060fae8f8..000000000 --- a/android/testproject/res/values/strings.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - TestActivity - diff --git a/android/testproject/src/org/libsdl/android/SDLActivity.java b/android/testproject/src/org/libsdl/android/SDLActivity.java deleted file mode 100644 index de2a1850b..000000000 --- a/android/testproject/src/org/libsdl/android/SDLActivity.java +++ /dev/null @@ -1,388 +0,0 @@ -package org.libsdl.android; - -import javax.microedition.khronos.egl.EGLConfig; -import javax.microedition.khronos.opengles.GL10; -import javax.microedition.khronos.egl.*; - -import android.app.*; -import android.content.*; -import android.view.*; -import android.os.*; -import android.util.Log; -import android.graphics.*; -import android.text.method.*; -import android.text.*; -import android.media.*; -import android.hardware.*; -import android.content.*; - -import java.lang.*; - - -/** - SDL Activity -*/ -public class SDLActivity extends Activity { - - //Main components - private static SDLActivity mSingleton; - private static SDLSurface mSurface; - - //Audio - private static AudioTrack mAudioTrack; - private static boolean bAudioIsEnabled; - - //Sensors - private static boolean bAccelIsEnabled; - - //feature IDs. Must match up on the C side as well. - private static int FEATURE_AUDIO = 1; - private static int FEATURE_ACCEL = 2; - - //Load the .so - static { - System.loadLibrary("sdltest"); - } - - //Setup - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - //So we can call stuff from static callbacks - mSingleton = this; - - //Set up the surface - mSurface = new SDLSurface(getApplication()); - setContentView(mSurface); - SurfaceHolder holder = mSurface.getHolder(); - holder.setType(SurfaceHolder.SURFACE_TYPE_GPU); - - } - - //Audio - public static boolean initAudio(){ - - //blah. Hardcoded things are bad. FIXME when we have more sound stuff - //working properly. - mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, - 11025, - AudioFormat.CHANNEL_CONFIGURATION_MONO, - AudioFormat.ENCODING_PCM_8BIT, - 2048, - AudioTrack.MODE_STREAM); - bAudioIsEnabled = true; - return true; - } - - //Accel - public static boolean initAccel(){ - mSurface.enableSensor(Sensor.TYPE_ACCELEROMETER, true); - bAccelIsEnabled = true; - return true; - } - - public static boolean closeAccel(){ - mSurface.enableSensor(Sensor.TYPE_ACCELEROMETER, false); - bAccelIsEnabled = false; - return true; - } - - - //Events - protected void onPause() { - super.onPause(); - } - - protected void onResume() { - super.onResume(); - } - - - - - - //C functions we call - public static native void nativeInit(); - public static native void nativeQuit(); - public static native void nativeSetScreenSize(int width, int height); - public static native void onNativeKeyDown(int keycode); - public static native void onNativeKeyUp(int keycode); - public static native void onNativeTouch(int action, float x, - float y, float p); - public static native void onNativeResize(int x, int y, int format); - public static native void onNativeAccel(float x, float y, float z); - - - - //Java functions called from C - private static void createGLContext(){ - mSurface.initEGL(); - } - - public static void flipBuffers(){ - mSurface.flipEGL(); - } - - public static void updateAudio(byte [] buf){ - - if(mAudioTrack == null){ - return; - } - - mAudioTrack.write(buf, 0, buf.length); - mAudioTrack.play(); - - Log.v("SDL","Played some audio"); - } - - public static void enableFeature(int featureid, int enabled){ - Log.v("SDL","Feature " + featureid + " = " + enabled); - - //Yuck. This is all horribly inelegent. If it gets to more than a few - //'features' I'll rip this out and make something nicer, I promise :) - if(featureid == FEATURE_AUDIO){ - if(enabled == 1){ - initAudio(); - }else{ - //We don't have one of these yet... - //closeAudio(); - } - } - - else if(featureid == FEATURE_ACCEL){ - if(enabled == 1){ - initAccel(); - }else{ - closeAccel(); - } - } - } - - - - - - - -} - -/** - Simple nativeInit() runnable -*/ -class SDLRunner implements Runnable{ - public void run(){ - //SDLActivity.initAudio(); - - //Runs SDL_main() - SDLActivity.nativeInit(); - - Log.v("SDL","SDL thread terminated"); - } -} - - -/** - SDLSurface. This is what we draw on, so we need to know when it's created - in order to do anything useful. - - Because of this, that's where we set up the SDL thread -*/ -class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, - View.OnKeyListener, View.OnTouchListener, SensorEventListener { - - //This is what SDL runs in. It invokes SDL_main(), eventually - private Thread mSDLThread; - - //EGL private objects - private EGLContext mEGLContext; - private EGLSurface mEGLSurface; - private EGLDisplay mEGLDisplay; - - //Sensors - private static SensorManager mSensorManager; - - //Startup - public SDLSurface(Context context) { - super(context); - getHolder().addCallback(this); - - setFocusable(true); - setFocusableInTouchMode(true); - requestFocus(); - setOnKeyListener(this); - setOnTouchListener(this); - - mSensorManager = (SensorManager)context.getSystemService("sensor"); - } - - //Called when we have a valid drawing surface - public void surfaceCreated(SurfaceHolder holder) { - Log.v("SDL","Surface created"); - - int width = getWidth(); - int height = getHeight(); - - //Set the width and height variables in C before we start SDL so we have - //it available on init - SDLActivity.nativeSetScreenSize(width, height); - - //Now start up the C app thread - mSDLThread = new Thread(new SDLRunner(), "SDLThread"); - mSDLThread.start(); - } - - //Called when we lose the surface - public void surfaceDestroyed(SurfaceHolder holder) { - Log.v("SDL","Surface destroyed"); - - SDLActivity.nativeQuit(); - - //Now wait for the SDL thread to quit - try{ - mSDLThread.wait(); - }catch(Exception e){ - Log.v("SDL","Problem stopping thread: " + e); - } - } - - //Called when the surface is resized - public void surfaceChanged(SurfaceHolder holder, int format, - int width, int height) { - Log.v("SDL","Surface resized"); - - SDLActivity.onNativeResize(width, height, format); - } - - //unused - public void onDraw(Canvas canvas) {} - - - //EGL functions - public boolean initEGL(){ - Log.v("SDL","Starting up"); - - try{ - - EGL10 egl = (EGL10)EGLContext.getEGL(); - - EGLDisplay dpy = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); - - int[] version = new int[2]; - egl.eglInitialize(dpy, version); - - int[] configSpec = { - //EGL10.EGL_DEPTH_SIZE, 16, - EGL10.EGL_NONE - }; - EGLConfig[] configs = new EGLConfig[1]; - int[] num_config = new int[1]; - egl.eglChooseConfig(dpy, configSpec, configs, 1, num_config); - EGLConfig config = configs[0]; - - EGLContext ctx = egl.eglCreateContext(dpy, config, EGL10.EGL_NO_CONTEXT, null); - - EGLSurface surface = egl.eglCreateWindowSurface(dpy, config, this, null); - - egl.eglMakeCurrent(dpy, surface, surface, ctx); - - mEGLContext = ctx; - mEGLDisplay = dpy; - mEGLSurface = surface; - - - }catch(Exception e){ - Log.v("SDL", e + ""); - for(StackTraceElement s : e.getStackTrace()){ - Log.v("SDL", s.toString()); - } - } - Log.v("SDL","Done making!"); - - return true; - } - - //EGL buffer flip - public void flipEGL(){ - try{ - - EGL10 egl = (EGL10)EGLContext.getEGL(); - GL10 gl = (GL10)mEGLContext.getGL(); - - egl.eglWaitNative(EGL10.EGL_NATIVE_RENDERABLE, null); - - //drawing here - - egl.eglWaitGL(); - - egl.eglSwapBuffers(mEGLDisplay, mEGLSurface); - - - }catch(Exception e){ - Log.v("SDL", "flipEGL(): " + e); - - for(StackTraceElement s : e.getStackTrace()){ - Log.v("SDL", s.toString()); - } - } - } - - - - //Key events - public boolean onKey(View v, int keyCode, KeyEvent event){ - - if(event.getAction() == KeyEvent.ACTION_DOWN){ - SDLActivity.onNativeKeyDown(keyCode); - return true; - } - - else if(event.getAction() == KeyEvent.ACTION_UP){ - SDLActivity.onNativeKeyUp(keyCode); - return true; - } - - return false; - } - - //Touch events - public boolean onTouch(View v, MotionEvent event){ - - int action = event.getAction(); - float x = event.getX(); - float y = event.getY(); - float p = event.getPressure(); - - //TODO: Anything else we need to pass? - SDLActivity.onNativeTouch(action, x, y, p); - return true; - } - - //Sensor events - public void enableSensor(int sensortype, boolean enabled){ - //TODO: This uses getDefaultSensor - what if we have >1 accels? - if(enabled){ - mSensorManager.registerListener(this, - mSensorManager.getDefaultSensor(sensortype), - SensorManager.SENSOR_DELAY_GAME, null); - }else{ - mSensorManager.unregisterListener(this, - mSensorManager.getDefaultSensor(sensortype)); - } - } - - public void onAccuracyChanged(Sensor sensor, int accuracy){ - //TODO - } - - public void onSensorChanged(SensorEvent event){ - if(event.sensor.getType() == Sensor.TYPE_ACCELEROMETER){ - SDLActivity.onNativeAccel( event.values[0], - event.values[1], - event.values[2] ); - } - } - - -} - -

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 |= surface_flags; SDL_PublicSurface = SDL_VideoSurface; return SDL_PublicSurface; diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h index bc2991287..54f96cb1e 100644 --- a/src/video/SDL_sysvideo.h +++ b/src/video/SDL_sysvideo.h @@ -414,6 +414,9 @@ extern VideoBootStrap NDS_bootstrap; #if SDL_VIDEO_DRIVER_PANDORA extern VideoBootStrap PND_bootstrap; #endif +#if SDL_VIDEO_DRIVER_ANDROID +extern VideoBootStrap Android_bootstrap; +#endif #define SDL_CurrentDisplay (&_this->displays[_this->current_display]) #define SDL_CurrentRenderer (SDL_CurrentDisplay->current_renderer) diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index 8ac0d1d4c..67c5ff0b2 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -99,6 +99,9 @@ static VideoBootStrap *bootstrap[] = { #endif #if SDL_VIDEO_DRIVER_PANDORA &PND_bootstrap, +#endif +#if SDL_VIDEO_DRIVER_ANDROID + &Android_bootstrap, #endif NULL }; diff --git a/src/video/android/SDL_androidevents.c b/src/video/android/SDL_androidevents.c new file mode 100644 index 000000000..2ca26e1eb --- /dev/null +++ b/src/video/android/SDL_androidevents.c @@ -0,0 +1,52 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2010 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +/* Being a null driver, there's no event stream. We just define stubs for + most of the API. */ + +#include +#include + +#include "../../events/SDL_sysevents.h" +#include "../../events/SDL_events_c.h" + +void +Android_PumpEvents(_THIS) +{ + + //scanKeys(); + /* TODO: defer click-age */ + /* + if (keysDown() & KEY_TOUCH) { + SDL_SendMouseButton(0, SDL_PRESSED, 0); + } else if (keysUp() & KEY_TOUCH) { + SDL_SendMouseButton(0, SDL_RELEASED, 0); + } + if (keysHeld() & KEY_TOUCH) { + touchPosition t = touchReadXY(); + SDL_SendMouseMotion(0, 0, t.px, t.py, 1); + } + */ +} + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/android/SDL_androidevents_c.h b/src/video/android/SDL_androidevents_c.h new file mode 100644 index 000000000..b53b74ebe --- /dev/null +++ b/src/video/android/SDL_androidevents_c.h @@ -0,0 +1,28 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2010 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +#include "SDL_androidvideo.h" + +extern void Android_PumpEvents(_THIS); + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/android/SDL_androidgl.c b/src/video/android/SDL_androidgl.c new file mode 100644 index 000000000..d0df06890 --- /dev/null +++ b/src/video/android/SDL_androidgl.c @@ -0,0 +1,158 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2010 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +/* Android SDL video driver implementation +*/ + +#include "SDL_video.h" +#include "SDL_mouse.h" +#include "../SDL_sysvideo.h" +#include "../SDL_pixels_c.h" +#include "../../events/SDL_events_c.h" + +#include "SDL_androidvideo.h" +#include "SDL_androidevents_c.h" +#include "SDL_androidrender_c.h" + +/* Android header */ +#include "egl.h" + + +//EGL globals +static EGLDisplay iEglDisplay; +static EGLConfig iEglConfig; +static EGLContext iEglContext; +static EGLSurface iEglSurface; + +EGLint attribList [] = +{ + EGL_BUFFER_SIZE, 16, //16 bit color + EGL_DEPTH_SIZE, 15, + EGL_NONE +}; + + + + +/* GL functions */ +int Android_GL_LoadLibrary(_THIS, const char *path){ + printf("[STUB] GL_LoadLibrary\n"); + return 0; +} + +void *Android_GL_GetProcAddress(_THIS, const char *proc){ + printf("[STUB] GL_GetProcAddress\n"); + return 0; +} + +void Android_GL_UnloadLibrary(_THIS){ + printf("[STUB] GL_UnloadLibrary\n"); +} + +/* +int *Android_GL_GetVisual(_THIS, Display * display, int screen){ + printf("[STUB] GL_GetVisual\n"); + return 0; +} +*/ + +SDL_GLContext Android_GL_CreateContext(_THIS, SDL_Window * window){ + printf("[STUB] GL_CreateContext\n"); + + //Start up the display + iEglDisplay = eglGetDisplay (EGL_DEFAULT_DISPLAY); + if(iEglDisplay == EGL_NO_DISPLAY){ + printf("Unable to find a suitable EGLDisplay\n"); + return NULL; + } + + printf("1\n"); + + if(!eglInitialize(iEglDisplay, 0, 0)){ + printf("Couldn't init display\n"); + return NULL; + } + + printf("2\n"); + + EGLint numConfigs; + + if(!eglChooseConfig(iEglDisplay, attribList, &iEglConfig, 1, &numConfigs)){ + printf("Couldn't choose config\n"); + return NULL; + } + + printf("3\n"); + + iEglContext = eglCreateContext(iEglDisplay, iEglConfig, EGL_NO_CONTEXT, 0); + + if(iEglContext == 0){ + printf("Couldn't create context\n"); + return NULL; + } + + printf("4\n"); + + NativeWindowType iWindow = 1; //android_createDisplaySurface(); + + iEglSurface = eglCreateWindowSurface(iEglDisplay, iEglConfig, iWindow, 0); + + printf("5\n"); + + if(iEglSurface == NULL){ + printf("Couldn't create surface\n"); + return NULL; + } + + printf("6\n"); + + eglMakeCurrent(iEglDisplay, iEglSurface, iEglSurface, iEglContext); + + printf("fininshed making context\n"); + + return iEglSurface; +} + +int Android_GL_MakeCurrent(_THIS, SDL_Window * window, + SDL_GLContext context){ + printf("[STUB] GL_MakeCurrent\n"); + return 0; +} + +int Android_GL_SetSwapInterval(_THIS, int interval){ + printf("[STUB] GL_SetSwapInterval\n"); + return 0; +} + +int Android_GL_GetSwapInterval(_THIS){ + printf("[STUB] GL_GetSwapInterval\n"); + return 0; +} + +void Android_GL_SwapWindow(_THIS, SDL_Window * window){ + printf("[STUB] GL_SwapWindow\n"); +} + +void Android_GL_DeleteContext(_THIS, SDL_GLContext context){ + printf("[STUB] GL_DeleteContext\n"); +} diff --git a/src/video/android/SDL_androidrender.c b/src/video/android/SDL_androidrender.c new file mode 100644 index 000000000..58ef5e43f --- /dev/null +++ b/src/video/android/SDL_androidrender.c @@ -0,0 +1,344 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2010 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +#include "SDL_video.h" +#include "../SDL_sysvideo.h" +#include "../SDL_yuv_sw_c.h" +#include "../SDL_renderer_sw.h" + + +/* SDL surface based renderer implementation */ + +static SDL_Renderer *Android_CreateRenderer(SDL_Window * window, + Uint32 flags); +static int Android_RenderDrawPoints(SDL_Renderer * renderer, + const SDL_Point * points, int count); +static int Android_RenderDrawLines(SDL_Renderer * renderer, + const SDL_Point * points, int count); +static int Android_RenderDrawRects(SDL_Renderer * renderer, + const SDL_Rect ** rects, int count); +static int Android_RenderFillRects(SDL_Renderer * renderer, + const SDL_Rect ** rects, int count); +static int Android_RenderCopy(SDL_Renderer * renderer, + SDL_Texture * texture, + const SDL_Rect * srcrect, + const SDL_Rect * dstrect); +static int Android_RenderReadPixels(SDL_Renderer * renderer, + const SDL_Rect * rect, + Uint32 format, + void * pixels, int pitch); +static int Android_RenderWritePixels(SDL_Renderer * renderer, + const SDL_Rect * rect, + Uint32 format, + const void * pixels, int pitch); +static void Android_RenderPresent(SDL_Renderer * renderer); +static void Android_DestroyRenderer(SDL_Renderer * renderer); + + +SDL_RenderDriver Android_RenderDriver = { + Android_CreateRenderer, + { + "dummy", + (SDL_RENDERER_SINGLEBUFFER | SDL_RENDERER_PRESENTCOPY | + SDL_RENDERER_PRESENTFLIP2 | SDL_RENDERER_PRESENTFLIP3 | + SDL_RENDERER_PRESENTDISCARD), + } +}; + +typedef struct +{ + int current_screen; + SDL_Surface *screens[3]; +} Android_RenderData; + +SDL_Renderer * +Android_CreateRenderer(SDL_Window * window, Uint32 flags) +{ + SDL_VideoDisplay *display = window->display; + SDL_DisplayMode *displayMode = &display->current_mode; + SDL_Renderer *renderer; + Android_RenderData *data; + int i, n; + int bpp; + Uint32 Rmask, Gmask, Bmask, Amask; + + if (!SDL_PixelFormatEnumToMasks + (displayMode->format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) { + SDL_SetError("Unknown display format"); + return NULL; + } + + renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer)); + if (!renderer) { + SDL_OutOfMemory(); + return NULL; + } + + data = (Android_RenderData *) SDL_malloc(sizeof(*data)); + if (!data) { + Android_DestroyRenderer(renderer); + SDL_OutOfMemory(); + return NULL; + } + SDL_zerop(data); + + renderer->RenderDrawPoints = Android_RenderDrawPoints; + renderer->RenderDrawLines = Android_RenderDrawLines; + renderer->RenderDrawRects = Android_RenderDrawRects; + renderer->RenderFillRects = Android_RenderFillRects; + renderer->RenderCopy = Android_RenderCopy; + renderer->RenderReadPixels = Android_RenderReadPixels; + renderer->RenderWritePixels = Android_RenderWritePixels; + renderer->RenderPresent = Android_RenderPresent; + renderer->DestroyRenderer = Android_DestroyRenderer; + renderer->info.name = Android_RenderDriver.info.name; + renderer->info.flags = 0; + renderer->window = window; + renderer->driverdata = data; + Setup_SoftwareRenderer(renderer); + + if (flags & SDL_RENDERER_PRESENTFLIP2) { + renderer->info.flags |= SDL_RENDERER_PRESENTFLIP2; + n = 2; + } else if (flags & SDL_RENDERER_PRESENTFLIP3) { + renderer->info.flags |= SDL_RENDERER_PRESENTFLIP3; + n = 3; + } else { + renderer->info.flags |= SDL_RENDERER_PRESENTCOPY; + n = 1; + } + for (i = 0; i < n; ++i) { + data->screens[i] = + SDL_CreateRGBSurface(0, window->w, window->h, bpp, Rmask, Gmask, + Bmask, Amask); + if (!data->screens[i]) { + Android_DestroyRenderer(renderer); + return NULL; + } + SDL_SetSurfacePalette(data->screens[i], display->palette); + } + data->current_screen = 0; + + return renderer; +} + +static int +Android_RenderDrawPoints(SDL_Renderer * renderer, + const SDL_Point * points, int count) +{ + Android_RenderData *data = + (Android_RenderData *) renderer->driverdata; + SDL_Surface *target = data->screens[data->current_screen]; + + if (renderer->blendMode == SDL_BLENDMODE_NONE || + renderer->blendMode == SDL_BLENDMODE_MASK) { + Uint32 color = SDL_MapRGBA(target->format, + renderer->r, renderer->g, renderer->b, + renderer->a); + + return SDL_DrawPoints(target, points, count, color); + } else { + return SDL_BlendPoints(target, points, count, renderer->blendMode, + renderer->r, renderer->g, renderer->b, + renderer->a); + } +} + +static int +Android_RenderDrawLines(SDL_Renderer * renderer, + const SDL_Point * points, int count) +{ + Android_RenderData *data = + (Android_RenderData *) renderer->driverdata; + SDL_Surface *target = data->screens[data->current_screen]; + + if (renderer->blendMode == SDL_BLENDMODE_NONE || + renderer->blendMode == SDL_BLENDMODE_MASK) { + Uint32 color = SDL_MapRGBA(target->format, + renderer->r, renderer->g, renderer->b, + renderer->a); + + return SDL_DrawLines(target, points, count, color); + } else { + return SDL_BlendLines(target, points, count, renderer->blendMode, + renderer->r, renderer->g, renderer->b, + renderer->a); + } +} + +static int +Android_RenderDrawRects(SDL_Renderer * renderer, const SDL_Rect ** rects, + int count) +{ + Android_RenderData *data = + (Android_RenderData *) renderer->driverdata; + SDL_Surface *target = data->screens[data->current_screen]; + + if (renderer->blendMode == SDL_BLENDMODE_NONE || + renderer->blendMode == SDL_BLENDMODE_MASK) { + Uint32 color = SDL_MapRGBA(target->format, + renderer->r, renderer->g, renderer->b, + renderer->a); + + return SDL_DrawRects(target, rects, count, color); + } else { + return SDL_BlendRects(target, rects, count, + renderer->blendMode, + renderer->r, renderer->g, renderer->b, + renderer->a); + } +} + +static int +Android_RenderFillRects(SDL_Renderer * renderer, const SDL_Rect ** rects, + int count) +{ + Android_RenderData *data = + (Android_RenderData *) renderer->driverdata; + SDL_Surface *target = data->screens[data->current_screen]; + + if (renderer->blendMode == SDL_BLENDMODE_NONE || + renderer->blendMode == SDL_BLENDMODE_MASK) { + Uint32 color = SDL_MapRGBA(target->format, + renderer->r, renderer->g, renderer->b, + renderer->a); + + return SDL_FillRects(target, rects, count, color); + } else { + return SDL_BlendFillRects(target, rects, count, + renderer->blendMode, + renderer->r, renderer->g, renderer->b, + renderer->a); + } +} + +static int +Android_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, + const SDL_Rect * srcrect, const SDL_Rect * dstrect) +{ + Android_RenderData *data = + (Android_RenderData *) renderer->driverdata; + SDL_Window *window = renderer->window; + SDL_VideoDisplay *display = window->display; + + if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) { + SDL_Surface *target = data->screens[data->current_screen]; + void *pixels = + (Uint8 *) target->pixels + dstrect->y * target->pitch + + dstrect->x * target->format->BytesPerPixel; + return SDL_SW_CopyYUVToRGB((SDL_SW_YUVTexture *) texture->driverdata, + srcrect, display->current_mode.format, + dstrect->w, dstrect->h, pixels, + target->pitch); + } else { + SDL_Surface *surface = (SDL_Surface *) texture->driverdata; + SDL_Surface *target = data->screens[data->current_screen]; + SDL_Rect real_srcrect = *srcrect; + SDL_Rect real_dstrect = *dstrect; + + return SDL_LowerBlit(surface, &real_srcrect, target, &real_dstrect); + } +} + +static int +Android_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, + Uint32 format, void * pixels, int pitch) +{ + Android_RenderData *data = + (Android_RenderData *) renderer->driverdata; + SDL_Window *window = renderer->window; + SDL_VideoDisplay *display = window->display; + SDL_Surface *screen = data->screens[data->current_screen]; + Uint32 screen_format = display->current_mode.format; + Uint8 *screen_pixels = (Uint8 *) screen->pixels + + rect->y * screen->pitch + + rect->x * screen->format->BytesPerPixel; + int screen_pitch = screen->pitch; + + return SDL_ConvertPixels(rect->w, rect->h, + screen_format, screen_pixels, screen_pitch, + format, pixels, pitch); +} + +static int +Android_RenderWritePixels(SDL_Renderer * renderer, const SDL_Rect * rect, + Uint32 format, const void * pixels, int pitch) +{ + Android_RenderData *data = + (Android_RenderData *) renderer->driverdata; + SDL_Window *window = renderer->window; + SDL_VideoDisplay *display = window->display; + SDL_Surface *screen = data->screens[data->current_screen]; + Uint32 screen_format = display->current_mode.format; + Uint8 *screen_pixels = (Uint8 *) screen->pixels + + rect->y * screen->pitch + + rect->x * screen->format->BytesPerPixel; + int screen_pitch = screen->pitch; + + return SDL_ConvertPixels(rect->w, rect->h, + format, pixels, pitch, + screen_format, screen_pixels, screen_pitch); +} + +static void +Android_RenderPresent(SDL_Renderer * renderer) +{ + static int frame_number; + Android_RenderData *data = + (Android_RenderData *) renderer->driverdata; + + /* Send the data to the display */ + if (SDL_getenv("SDL_VIDEO_DUMMY_SAVE_FRAMES")) { + char file[128]; + SDL_snprintf(file, sizeof(file), "SDL_window%d-%8.8d.bmp", + renderer->window->id, ++frame_number); + SDL_SaveBMP(data->screens[data->current_screen], file); + } + + /* Update the flipping chain, if any */ + if (renderer->info.flags & SDL_RENDERER_PRESENTFLIP2) { + data->current_screen = (data->current_screen + 1) % 2; + } else if (renderer->info.flags & SDL_RENDERER_PRESENTFLIP3) { + data->current_screen = (data->current_screen + 1) % 3; + } +} + +static void +Android_DestroyRenderer(SDL_Renderer * renderer) +{ + Android_RenderData *data = + (Android_RenderData *) renderer->driverdata; + int i; + + if (data) { + for (i = 0; i < SDL_arraysize(data->screens); ++i) { + if (data->screens[i]) { + SDL_FreeSurface(data->screens[i]); + } + } + SDL_free(data); + } + SDL_free(renderer); +} + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/android/SDL_androidrender_c.h b/src/video/android/SDL_androidrender_c.h new file mode 100644 index 000000000..18f51a25d --- /dev/null +++ b/src/video/android/SDL_androidrender_c.h @@ -0,0 +1,28 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2010 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +/* SDL surface based renderer implementation */ + +extern SDL_RenderDriver Android_RenderDriver; + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/android/SDL_androidvideo.c b/src/video/android/SDL_androidvideo.c new file mode 100644 index 000000000..565a1e1c0 --- /dev/null +++ b/src/video/android/SDL_androidvideo.c @@ -0,0 +1,152 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2010 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +/* Android SDL video driver implementation +*/ + +#include "SDL_video.h" +#include "SDL_mouse.h" +#include "../SDL_sysvideo.h" +#include "../SDL_pixels_c.h" +#include "../../events/SDL_events_c.h" + +#include "SDL_androidvideo.h" +#include "SDL_androidevents_c.h" +#include "SDL_androidrender_c.h" + +#define ANDROID_VID_DRIVER_NAME "Android" + +/* Initialization/Query functions */ +static int Android_VideoInit(_THIS); +static int Android_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode); +static void Android_VideoQuit(_THIS); + +/* GL functions (SDL_androidgl.c) */ +extern int Android_GL_LoadLibrary(_THIS, const char *path); +extern void *Android_GL_GetProcAddress(_THIS, const char *proc); +extern void Android_GL_UnloadLibrary(_THIS); +//extern int *Android_GL_GetVisual(_THIS, Display * display, int screen); +extern SDL_GLContext Android_GL_CreateContext(_THIS, SDL_Window * window); +extern int Android_GL_MakeCurrent(_THIS, SDL_Window * window, + SDL_GLContext context); +extern int Android_GL_SetSwapInterval(_THIS, int interval); +extern int Android_GL_GetSwapInterval(_THIS); +extern void Android_GL_SwapWindow(_THIS, SDL_Window * window); +extern void Android_GL_DeleteContext(_THIS, SDL_GLContext context); + +/* Android driver bootstrap functions */ + + +static int +Android_Available(void) +{ + return 1; +} + +static void +Android_DeleteDevice(SDL_VideoDevice * device) +{ + SDL_free(device); +} + +static SDL_VideoDevice * +Android_CreateDevice(int devindex) +{ + printf("Creating video device\n"); + SDL_VideoDevice *device; + + /* Initialize all variables that we clean on shutdown */ + device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice)); + if (!device) { + SDL_OutOfMemory(); + if (device) { + SDL_free(device); + } + return (0); + } + + /* Set the function pointers */ + device->VideoInit = Android_VideoInit; + device->VideoQuit = Android_VideoQuit; + device->SetDisplayMode = Android_SetDisplayMode; + device->PumpEvents = Android_PumpEvents; + + device->free = Android_DeleteDevice; + + /* GL pointers */ + device->GL_LoadLibrary = Android_GL_LoadLibrary; + device->GL_GetProcAddress = Android_GL_GetProcAddress; + device->GL_UnloadLibrary = Android_GL_UnloadLibrary; + device->GL_CreateContext = Android_GL_CreateContext; + device->GL_MakeCurrent = Android_GL_MakeCurrent; + device->GL_SetSwapInterval = Android_GL_SetSwapInterval; + device->GL_GetSwapInterval = Android_GL_GetSwapInterval; + device->GL_SwapWindow = Android_GL_SwapWindow; + device->GL_DeleteContext = Android_GL_DeleteContext; + + return device; +} + +VideoBootStrap Android_bootstrap = { + ANDROID_VID_DRIVER_NAME, "SDL Android video driver", + Android_Available, Android_CreateDevice +}; + + +int +Android_VideoInit(_THIS) +{ + SDL_DisplayMode mode; + + /* Use a fake 32-bpp desktop mode */ + mode.format = SDL_PIXELFORMAT_RGB888; + mode.w = 1024; + mode.h = 768; + mode.refresh_rate = 0; + mode.driverdata = NULL; + if (SDL_AddBasicVideoDisplay(&mode) < 0) { + return -1; + } + SDL_AddRenderDriver(&_this->displays[0], &Android_RenderDriver); + + SDL_zero(mode); + SDL_AddDisplayMode(&_this->displays[0], &mode); + + /* We're done! */ + return 0; +} + +static int +Android_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode) +{ + return 0; +} + +void +Android_VideoQuit(_THIS) +{ +} + + + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/android/SDL_androidvideo.h b/src/video/android/SDL_androidvideo.h new file mode 100644 index 000000000..703574bfe --- /dev/null +++ b/src/video/android/SDL_androidvideo.h @@ -0,0 +1,31 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2010 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +#ifndef _SDL_androidvideo_h +#define _SDL_androidvideo_h + +#include "../SDL_sysvideo.h" + +#endif /* _SDL_ndsvideo_h */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/android/egl.h b/src/video/android/egl.h new file mode 100644 index 000000000..a75cfb63f --- /dev/null +++ b/src/video/android/egl.h @@ -0,0 +1,330 @@ +/* -*- mode: c; tab-width: 8; -*- */ +/* vi: set sw=4 ts=8: */ +/* Reference version of egl.h for EGL 1.4. + * $Revision: 7244 $ on $Date: 2009-01-20 17:06:59 -0800 (Tue, 20 Jan 2009) $ + */ + +/* +** Copyright (c) 2007-2009 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +#ifndef __egl_h_ +#define __egl_h_ + +/* All platform-dependent types and macro boilerplate (such as EGLAPI + * and EGLAPIENTRY) should go in eglplatform.h. + */ +#include "eglplatform.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* EGL Types */ +/* EGLint is defined in eglplatform.h */ +typedef unsigned int EGLBoolean; +typedef unsigned int EGLenum; +typedef void *EGLConfig; +typedef void *EGLContext; +typedef void *EGLDisplay; +typedef void *EGLSurface; +typedef void *EGLClientBuffer; + +/* EGL Versioning */ +#define EGL_VERSION_1_0 1 +#define EGL_VERSION_1_1 1 +#define EGL_VERSION_1_2 1 +#define EGL_VERSION_1_3 1 +#define EGL_VERSION_1_4 1 + +/* EGL Enumerants. Bitmasks and other exceptional cases aside, most + * enums are assigned unique values starting at 0x3000. + */ + +/* EGL aliases */ +#define EGL_FALSE 0 +#define EGL_TRUE 1 + +/* Out-of-band handle values */ +#define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType)0) +#define EGL_NO_CONTEXT ((EGLContext)0) +#define EGL_NO_DISPLAY ((EGLDisplay)0) +#define EGL_NO_SURFACE ((EGLSurface)0) + +/* Out-of-band attribute value */ +#define EGL_DONT_CARE ((EGLint)-1) + +/* Errors / GetError return values */ +#define EGL_SUCCESS 0x3000 +#define EGL_NOT_INITIALIZED 0x3001 +#define EGL_BAD_ACCESS 0x3002 +#define EGL_BAD_ALLOC 0x3003 +#define EGL_BAD_ATTRIBUTE 0x3004 +#define EGL_BAD_CONFIG 0x3005 +#define EGL_BAD_CONTEXT 0x3006 +#define EGL_BAD_CURRENT_SURFACE 0x3007 +#define EGL_BAD_DISPLAY 0x3008 +#define EGL_BAD_MATCH 0x3009 +#define EGL_BAD_NATIVE_PIXMAP 0x300A +#define EGL_BAD_NATIVE_WINDOW 0x300B +#define EGL_BAD_PARAMETER 0x300C +#define EGL_BAD_SURFACE 0x300D +#define EGL_CONTEXT_LOST 0x300E /* EGL 1.1 - IMG_power_management */ + +/* Reserved 0x300F-0x301F for additional errors */ + +/* Config attributes */ +#define EGL_BUFFER_SIZE 0x3020 +#define EGL_ALPHA_SIZE 0x3021 +#define EGL_BLUE_SIZE 0x3022 +#define EGL_GREEN_SIZE 0x3023 +#define EGL_RED_SIZE 0x3024 +#define EGL_DEPTH_SIZE 0x3025 +#define EGL_STENCIL_SIZE 0x3026 +#define EGL_CONFIG_CAVEAT 0x3027 +#define EGL_CONFIG_ID 0x3028 +#define EGL_LEVEL 0x3029 +#define EGL_MAX_PBUFFER_HEIGHT 0x302A +#define EGL_MAX_PBUFFER_PIXELS 0x302B +#define EGL_MAX_PBUFFER_WIDTH 0x302C +#define EGL_NATIVE_RENDERABLE 0x302D +#define EGL_NATIVE_VISUAL_ID 0x302E +#define EGL_NATIVE_VISUAL_TYPE 0x302F +#define EGL_PRESERVED_RESOURCES 0x3030 +#define EGL_SAMPLES 0x3031 +#define EGL_SAMPLE_BUFFERS 0x3032 +#define EGL_SURFACE_TYPE 0x3033 +#define EGL_TRANSPARENT_TYPE 0x3034 +#define EGL_TRANSPARENT_BLUE_VALUE 0x3035 +#define EGL_TRANSPARENT_GREEN_VALUE 0x3036 +#define EGL_TRANSPARENT_RED_VALUE 0x3037 +#define EGL_NONE 0x3038 /* Attrib list terminator */ +#define EGL_BIND_TO_TEXTURE_RGB 0x3039 +#define EGL_BIND_TO_TEXTURE_RGBA 0x303A +#define EGL_MIN_SWAP_INTERVAL 0x303B +#define EGL_MAX_SWAP_INTERVAL 0x303C +#define EGL_LUMINANCE_SIZE 0x303D +#define EGL_ALPHA_MASK_SIZE 0x303E +#define EGL_COLOR_BUFFER_TYPE 0x303F +#define EGL_RENDERABLE_TYPE 0x3040 +#define EGL_MATCH_NATIVE_PIXMAP 0x3041 /* Pseudo-attribute (not queryable) */ +#define EGL_CONFORMANT 0x3042 + +/* Reserved 0x3041-0x304F for additional config attributes */ + +/* Config attribute values */ +#define EGL_SLOW_CONFIG 0x3050 /* EGL_CONFIG_CAVEAT value */ +#define EGL_NON_CONFORMANT_CONFIG 0x3051 /* EGL_CONFIG_CAVEAT value */ +#define EGL_TRANSPARENT_RGB 0x3052 /* EGL_TRANSPARENT_TYPE value */ +#define EGL_RGB_BUFFER 0x308E /* EGL_COLOR_BUFFER_TYPE value */ +#define EGL_LUMINANCE_BUFFER 0x308F /* EGL_COLOR_BUFFER_TYPE value */ + +/* More config attribute values, for EGL_TEXTURE_FORMAT */ +#define EGL_NO_TEXTURE 0x305C +#define EGL_TEXTURE_RGB 0x305D +#define EGL_TEXTURE_RGBA 0x305E +#define EGL_TEXTURE_2D 0x305F + +/* Config attribute mask bits */ +#define EGL_PBUFFER_BIT 0x0001 /* EGL_SURFACE_TYPE mask bits */ +#define EGL_PIXMAP_BIT 0x0002 /* EGL_SURFACE_TYPE mask bits */ +#define EGL_WINDOW_BIT 0x0004 /* EGL_SURFACE_TYPE mask bits */ +#define EGL_VG_COLORSPACE_LINEAR_BIT 0x0020 /* EGL_SURFACE_TYPE mask bits */ +#define EGL_VG_ALPHA_FORMAT_PRE_BIT 0x0040 /* EGL_SURFACE_TYPE mask bits */ +#define EGL_MULTISAMPLE_RESOLVE_BOX_BIT 0x0200 /* EGL_SURFACE_TYPE mask bits */ +#define EGL_SWAP_BEHAVIOR_PRESERVED_BIT 0x0400 /* EGL_SURFACE_TYPE mask bits */ + +#define EGL_OPENGL_ES_BIT 0x0001 /* EGL_RENDERABLE_TYPE mask bits */ +#define EGL_OPENVG_BIT 0x0002 /* EGL_RENDERABLE_TYPE mask bits */ +#define EGL_OPENGL_ES2_BIT 0x0004 /* EGL_RENDERABLE_TYPE mask bits */ +#define EGL_OPENGL_BIT 0x0008 /* EGL_RENDERABLE_TYPE mask bits */ + +/* QueryString targets */ +#define EGL_VENDOR 0x3053 +#define EGL_VERSION 0x3054 +#define EGL_EXTENSIONS 0x3055 +#define EGL_CLIENT_APIS 0x308D + +/* QuerySurface / SurfaceAttrib / CreatePbufferSurface targets */ +#define EGL_HEIGHT 0x3056 +#define EGL_WIDTH 0x3057 +#define EGL_LARGEST_PBUFFER 0x3058 +#define EGL_TEXTURE_FORMAT 0x3080 +#define EGL_TEXTURE_TARGET 0x3081 +#define EGL_MIPMAP_TEXTURE 0x3082 +#define EGL_MIPMAP_LEVEL 0x3083 +#define EGL_RENDER_BUFFER 0x3086 +#define EGL_VG_COLORSPACE 0x3087 +#define EGL_VG_ALPHA_FORMAT 0x3088 +#define EGL_HORIZONTAL_RESOLUTION 0x3090 +#define EGL_VERTICAL_RESOLUTION 0x3091 +#define EGL_PIXEL_ASPECT_RATIO 0x3092 +#define EGL_SWAP_BEHAVIOR 0x3093 +#define EGL_MULTISAMPLE_RESOLVE 0x3099 + +/* EGL_RENDER_BUFFER values / BindTexImage / ReleaseTexImage buffer targets */ +#define EGL_BACK_BUFFER 0x3084 +#define EGL_SINGLE_BUFFER 0x3085 + +/* OpenVG color spaces */ +#define EGL_VG_COLORSPACE_sRGB 0x3089 /* EGL_VG_COLORSPACE value */ +#define EGL_VG_COLORSPACE_LINEAR 0x308A /* EGL_VG_COLORSPACE value */ + +/* OpenVG alpha formats */ +#define EGL_VG_ALPHA_FORMAT_NONPRE 0x308B /* EGL_ALPHA_FORMAT value */ +#define EGL_VG_ALPHA_FORMAT_PRE 0x308C /* EGL_ALPHA_FORMAT value */ + +/* Constant scale factor by which fractional display resolutions & + * aspect ratio are scaled when queried as integer values. + */ +#define EGL_DISPLAY_SCALING 10000 + +/* Unknown display resolution/aspect ratio */ +#define EGL_UNKNOWN ((EGLint)-1) + +/* Back buffer swap behaviors */ +#define EGL_BUFFER_PRESERVED 0x3094 /* EGL_SWAP_BEHAVIOR value */ +#define EGL_BUFFER_DESTROYED 0x3095 /* EGL_SWAP_BEHAVIOR value */ + +/* CreatePbufferFromClientBuffer buffer types */ +#define EGL_OPENVG_IMAGE 0x3096 + +/* QueryContext targets */ +#define EGL_CONTEXT_CLIENT_TYPE 0x3097 + +/* CreateContext attributes */ +#define EGL_CONTEXT_CLIENT_VERSION 0x3098 + +/* Multisample resolution behaviors */ +#define EGL_MULTISAMPLE_RESOLVE_DEFAULT 0x309A /* EGL_MULTISAMPLE_RESOLVE value */ +#define EGL_MULTISAMPLE_RESOLVE_BOX 0x309B /* EGL_MULTISAMPLE_RESOLVE value */ + +/* BindAPI/QueryAPI targets */ +#define EGL_OPENGL_ES_API 0x30A0 +#define EGL_OPENVG_API 0x30A1 +#define EGL_OPENGL_API 0x30A2 + +/* GetCurrentSurface targets */ +#define EGL_DRAW 0x3059 +#define EGL_READ 0x305A + +/* WaitNative engines */ +#define EGL_CORE_NATIVE_ENGINE 0x305B + +/* EGL 1.2 tokens renamed for consistency in EGL 1.3 */ +#define EGL_COLORSPACE EGL_VG_COLORSPACE +#define EGL_ALPHA_FORMAT EGL_VG_ALPHA_FORMAT +#define EGL_COLORSPACE_sRGB EGL_VG_COLORSPACE_sRGB +#define EGL_COLORSPACE_LINEAR EGL_VG_COLORSPACE_LINEAR +#define EGL_ALPHA_FORMAT_NONPRE EGL_VG_ALPHA_FORMAT_NONPRE +#define EGL_ALPHA_FORMAT_PRE EGL_VG_ALPHA_FORMAT_PRE + +/* EGL extensions must request enum blocks from the Khronos + * API Registrar, who maintains the enumerant registry. Submit + * a bug in Khronos Bugzilla against task "Registry". + */ + + + +/* EGL Functions */ + +EGLAPI EGLint EGLAPIENTRY eglGetError(void); + +EGLAPI EGLDisplay EGLAPIENTRY eglGetDisplay(EGLNativeDisplayType display_id); +EGLAPI EGLBoolean EGLAPIENTRY eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor); +EGLAPI EGLBoolean EGLAPIENTRY eglTerminate(EGLDisplay dpy); + +EGLAPI const char * EGLAPIENTRY eglQueryString(EGLDisplay dpy, EGLint name); + +EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, + EGLint config_size, EGLint *num_config); +EGLAPI EGLBoolean EGLAPIENTRY eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, + EGLConfig *configs, EGLint config_size, + EGLint *num_config); +EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, + EGLint attribute, EGLint *value); + +EGLAPI EGLSurface EGLAPIENTRY eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, + EGLNativeWindowType win, + const EGLint *attrib_list); +EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, + const EGLint *attrib_list); +EGLAPI EGLSurface EGLAPIENTRY eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, + EGLNativePixmapType pixmap, + const EGLint *attrib_list); +EGLAPI EGLBoolean EGLAPIENTRY eglDestroySurface(EGLDisplay dpy, EGLSurface surface); +EGLAPI EGLBoolean EGLAPIENTRY eglQuerySurface(EGLDisplay dpy, EGLSurface surface, + EGLint attribute, EGLint *value); + +EGLAPI EGLBoolean EGLAPIENTRY eglBindAPI(EGLenum api); +EGLAPI EGLenum EGLAPIENTRY eglQueryAPI(void); + +EGLAPI EGLBoolean EGLAPIENTRY eglWaitClient(void); + +EGLAPI EGLBoolean EGLAPIENTRY eglReleaseThread(void); + +EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferFromClientBuffer( + EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, + EGLConfig config, const EGLint *attrib_list); + +EGLAPI EGLBoolean EGLAPIENTRY eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface, + EGLint attribute, EGLint value); +EGLAPI EGLBoolean EGLAPIENTRY eglBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer); +EGLAPI EGLBoolean EGLAPIENTRY eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer); + + +EGLAPI EGLBoolean EGLAPIENTRY eglSwapInterval(EGLDisplay dpy, EGLint interval); + + +EGLAPI EGLContext EGLAPIENTRY eglCreateContext(EGLDisplay dpy, EGLConfig config, + EGLContext share_context, + const EGLint *attrib_list); +EGLAPI EGLBoolean EGLAPIENTRY eglDestroyContext(EGLDisplay dpy, EGLContext ctx); +EGLAPI EGLBoolean EGLAPIENTRY eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, + EGLSurface read, EGLContext ctx); + +EGLAPI EGLContext EGLAPIENTRY eglGetCurrentContext(void); +EGLAPI EGLSurface EGLAPIENTRY eglGetCurrentSurface(EGLint readdraw); +EGLAPI EGLDisplay EGLAPIENTRY eglGetCurrentDisplay(void); +EGLAPI EGLBoolean EGLAPIENTRY eglQueryContext(EGLDisplay dpy, EGLContext ctx, + EGLint attribute, EGLint *value); + +EGLAPI EGLBoolean EGLAPIENTRY eglWaitGL(void); +EGLAPI EGLBoolean EGLAPIENTRY eglWaitNative(EGLint engine); +EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffers(EGLDisplay dpy, EGLSurface surface); +EGLAPI EGLBoolean EGLAPIENTRY eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, + EGLNativePixmapType target); + +/* This is a generic function pointer type, whose name indicates it must + * be cast to the proper type *and calling convention* before use. + */ +typedef void (*__eglMustCastToProperFunctionPointerType)(void); + +/* Now, define eglGetProcAddress using the generic function ptr. type */ +EGLAPI __eglMustCastToProperFunctionPointerType EGLAPIENTRY + eglGetProcAddress(const char *procname); + +#ifdef __cplusplus +} +#endif + +#endif /* __egl_h_ */ diff --git a/src/video/android/eglext.h b/src/video/android/eglext.h new file mode 100644 index 000000000..545fd0e98 --- /dev/null +++ b/src/video/android/eglext.h @@ -0,0 +1,162 @@ +#ifndef __eglext_h_ +#define __eglext_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** Copyright (c) 2007-2009 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +#include + +/*************************************************************/ + +/* Header file version number */ +/* Current version at http://www.khronos.org/registry/egl/ */ +/* $Revision: 7244 $ on $Date: 2009-01-20 17:06:59 -0800 (Tue, 20 Jan 2009) $ */ +#define EGL_EGLEXT_VERSION 3 + +#ifndef EGL_KHR_config_attribs +#define EGL_KHR_config_attribs 1 +#define EGL_CONFORMANT_KHR 0x3042 /* EGLConfig attribute */ +#define EGL_VG_COLORSPACE_LINEAR_BIT_KHR 0x0020 /* EGL_SURFACE_TYPE bitfield */ +#define EGL_VG_ALPHA_FORMAT_PRE_BIT_KHR 0x0040 /* EGL_SURFACE_TYPE bitfield */ +#endif + +#ifndef EGL_KHR_lock_surface +#define EGL_KHR_lock_surface 1 +#define EGL_READ_SURFACE_BIT_KHR 0x0001 /* EGL_LOCK_USAGE_HINT_KHR bitfield */ +#define EGL_WRITE_SURFACE_BIT_KHR 0x0002 /* EGL_LOCK_USAGE_HINT_KHR bitfield */ +#define EGL_LOCK_SURFACE_BIT_KHR 0x0080 /* EGL_SURFACE_TYPE bitfield */ +#define EGL_OPTIMAL_FORMAT_BIT_KHR 0x0100 /* EGL_SURFACE_TYPE bitfield */ +#define EGL_MATCH_FORMAT_KHR 0x3043 /* EGLConfig attribute */ +#define EGL_FORMAT_RGB_565_EXACT_KHR 0x30C0 /* EGL_MATCH_FORMAT_KHR value */ +#define EGL_FORMAT_RGB_565_KHR 0x30C1 /* EGL_MATCH_FORMAT_KHR value */ +#define EGL_FORMAT_RGBA_8888_EXACT_KHR 0x30C2 /* EGL_MATCH_FORMAT_KHR value */ +#define EGL_FORMAT_RGBA_8888_KHR 0x30C3 /* EGL_MATCH_FORMAT_KHR value */ +#define EGL_MAP_PRESERVE_PIXELS_KHR 0x30C4 /* eglLockSurfaceKHR attribute */ +#define EGL_LOCK_USAGE_HINT_KHR 0x30C5 /* eglLockSurfaceKHR attribute */ +#define EGL_BITMAP_POINTER_KHR 0x30C6 /* eglQuerySurface attribute */ +#define EGL_BITMAP_PITCH_KHR 0x30C7 /* eglQuerySurface attribute */ +#define EGL_BITMAP_ORIGIN_KHR 0x30C8 /* eglQuerySurface attribute */ +#define EGL_BITMAP_PIXEL_RED_OFFSET_KHR 0x30C9 /* eglQuerySurface attribute */ +#define EGL_BITMAP_PIXEL_GREEN_OFFSET_KHR 0x30CA /* eglQuerySurface attribute */ +#define EGL_BITMAP_PIXEL_BLUE_OFFSET_KHR 0x30CB /* eglQuerySurface attribute */ +#define EGL_BITMAP_PIXEL_ALPHA_OFFSET_KHR 0x30CC /* eglQuerySurface attribute */ +#define EGL_BITMAP_PIXEL_LUMINANCE_OFFSET_KHR 0x30CD /* eglQuerySurface attribute */ +#define EGL_LOWER_LEFT_KHR 0x30CE /* EGL_BITMAP_ORIGIN_KHR value */ +#define EGL_UPPER_LEFT_KHR 0x30CF /* EGL_BITMAP_ORIGIN_KHR value */ +#ifdef EGL_EGLEXT_PROTOTYPES +EGLAPI EGLBoolean EGLAPIENTRY eglLockSurfaceKHR (EGLDisplay display, EGLSurface surface, const EGLint *attrib_list); +EGLAPI EGLBoolean EGLAPIENTRY eglUnlockSurfaceKHR (EGLDisplay display, EGLSurface surface); +#endif /* EGL_EGLEXT_PROTOTYPES */ +typedef EGLBoolean (EGLAPIENTRYP PFNEGLLOCKSURFACEKHRPROC) (EGLDisplay display, EGLSurface surface, const EGLint *attrib_list); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLUNLOCKSURFACEKHRPROC) (EGLDisplay display, EGLSurface surface); +#endif + +#ifndef EGL_KHR_image +#define EGL_KHR_image 1 +#define EGL_NATIVE_PIXMAP_KHR 0x30B0 /* eglCreateImageKHR target */ +typedef void *EGLImageKHR; +#define EGL_NO_IMAGE_KHR ((EGLImageKHR)0) +#ifdef EGL_EGLEXT_PROTOTYPES +EGLAPI EGLImageKHR EGLAPIENTRY eglCreateImageKHR (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list); +EGLAPI EGLBoolean EGLAPIENTRY eglDestroyImageKHR (EGLDisplay dpy, EGLImageKHR image); +#endif /* EGL_EGLEXT_PROTOTYPES */ +typedef EGLImageKHR (EGLAPIENTRYP PFNEGLCREATEIMAGEKHRPROC) (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYIMAGEKHRPROC) (EGLDisplay dpy, EGLImageKHR image); +#endif + +#ifndef EGL_KHR_vg_parent_image +#define EGL_KHR_vg_parent_image 1 +#define EGL_VG_PARENT_IMAGE_KHR 0x30BA /* eglCreateImageKHR target */ +#endif + +#ifndef EGL_KHR_gl_texture_2D_image +#define EGL_KHR_gl_texture_2D_image 1 +#define EGL_GL_TEXTURE_2D_KHR 0x30B1 /* eglCreateImageKHR target */ +#define EGL_GL_TEXTURE_LEVEL_KHR 0x30BC /* eglCreateImageKHR attribute */ +#endif + +#ifndef EGL_KHR_gl_texture_cubemap_image +#define EGL_KHR_gl_texture_cubemap_image 1 +#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR 0x30B3 /* eglCreateImageKHR target */ +#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR 0x30B4 /* eglCreateImageKHR target */ +#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR 0x30B5 /* eglCreateImageKHR target */ +#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR 0x30B6 /* eglCreateImageKHR target */ +#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR 0x30B7 /* eglCreateImageKHR target */ +#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR 0x30B8 /* eglCreateImageKHR target */ +#endif + +#ifndef EGL_KHR_gl_texture_3D_image +#define EGL_KHR_gl_texture_3D_image 1 +#define EGL_GL_TEXTURE_3D_KHR 0x30B2 /* eglCreateImageKHR target */ +#define EGL_GL_TEXTURE_ZOFFSET_KHR 0x30BD /* eglCreateImageKHR attribute */ +#endif + +#ifndef EGL_KHR_gl_renderbuffer_image +#define EGL_KHR_gl_renderbuffer_image 1 +#define EGL_GL_RENDERBUFFER_KHR 0x30B9 /* eglCreateImageKHR target */ +#endif + +#ifndef EGL_KHR_image_base +#define EGL_KHR_image_base 1 +/* Most interfaces defined by EGL_KHR_image_pixmap above */ +#define EGL_IMAGE_PRESERVED_KHR 0x30D2 /* eglCreateImageKHR attribute */ +#endif + +#ifndef EGL_KHR_image_pixmap +#define EGL_KHR_image_pixmap 1 +/* Interfaces defined by EGL_KHR_image above */ +#endif + + +#ifndef EGL_ANDROID_image_native_buffer +#define EGL_ANDROID_image_native_buffer 1 +struct android_native_buffer_t; +#define EGL_NATIVE_BUFFER_ANDROID 0x3140 /* eglCreateImageKHR target */ +#endif + +#ifndef EGL_ANDROID_get_render_buffer +#define EGL_ANDROID_get_render_buffer 1 +#ifdef EGL_EGLEXT_PROTOTYPES +EGLAPI EGLClientBuffer EGLAPIENTRY eglGetRenderBufferANDROID(EGLDisplay dpy, EGLSurface draw); +#endif +typedef EGLClientBuffer (EGLAPIENTRYP PFNEGLGETRENDERBUFFERANDROIDPROC) (EGLDisplay dpy, EGLSurface draw); +#endif + +#ifndef EGL_ANDROID_swap_rectangle +#define EGL_ANDROID_swap_rectangle 1 +#ifdef EGL_EGLEXT_PROTOTYPES +EGLAPI EGLBoolean EGLAPIENTRY eglSetSwapRectangleANDROID (EGLDisplay dpy, EGLSurface draw, EGLint left, EGLint top, EGLint width, EGLint height); +#endif /* EGL_EGLEXT_PROTOTYPES */ +typedef EGLBoolean (EGLAPIENTRYP PFNEGLSETSWAPRECTANGLEANDROIDPROC) (EGLDisplay dpy, EGLSurface draw, EGLint left, EGLint top, EGLint width, EGLint height); +#endif + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/video/android/eglplatform.h b/src/video/android/eglplatform.h new file mode 100644 index 000000000..53e9e6116 --- /dev/null +++ b/src/video/android/eglplatform.h @@ -0,0 +1,118 @@ +#ifndef __eglplatform_h_ +#define __eglplatform_h_ + +/* +** Copyright (c) 2007-2009 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +/* Platform-specific types and definitions for egl.h + * $Revision: 7244 $ on $Date: 2009-01-20 17:06:59 -0800 (Tue, 20 Jan 2009) $ + * + * Adopters may modify khrplatform.h and this file to suit their platform. + * You are encouraged to submit all modifications to the Khronos group so that + * they can be included in future versions of this file. Please submit changes + * by sending them to the public Khronos Bugzilla (http://khronos.org/bugzilla) + * by filing a bug against product "EGL" component "Registry". + */ + +#include + +/* Macros used in EGL function prototype declarations. + * + * EGL functions should be prototyped as: + * + * EGLAPI return-type EGLAPIENTRY eglFunction(arguments); + * typedef return-type (EXPAPIENTRYP PFNEGLFUNCTIONPROC) (arguments); + * + * KHRONOS_APICALL and KHRONOS_APIENTRY are defined in KHR/khrplatform.h + */ + +#ifndef EGLAPI +#define EGLAPI KHRONOS_APICALL +#endif + +#define EGLAPIENTRY KHRONOS_APIENTRY +#define EGLAPIENTRYP KHRONOS_APIENTRY* + +/* The types NativeDisplayType, NativeWindowType, and NativePixmapType + * are aliases of window-system-dependent types, such as X Display * or + * Windows Device Context. They must be defined in platform-specific + * code below. The EGL-prefixed versions of Native*Type are the same + * types, renamed in EGL 1.3 so all types in the API start with "EGL". + */ + +#if defined(_WIN32) || defined(__VC32__) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) /* Win32 and WinCE */ +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN 1 +#endif +#include + +typedef HDC EGLNativeDisplayType; +typedef HBITMAP EGLNativePixmapType; +typedef HWND EGLNativeWindowType; + +#elif defined(__WINSCW__) || defined(__SYMBIAN32__) /* Symbian */ + +typedef int EGLNativeDisplayType; +typedef void *EGLNativeWindowType; +typedef void *EGLNativePixmapType; + +#elif defined(__unix__) && !defined(ANDROID) + +/* X11 (tentative) */ +#include +#include + +typedef Display *EGLNativeDisplayType; +typedef Pixmap EGLNativePixmapType; +typedef Window EGLNativeWindowType; + + +#elif defined(ANDROID) + +struct android_native_window_t; +struct egl_native_pixmap_t; + +typedef struct android_native_window_t* EGLNativeWindowType; +typedef struct egl_native_pixmap_t* EGLNativePixmapType; +typedef void* EGLNativeDisplayType; + +#else +#error "Platform not recognized" +#endif + +/* EGL 1.2 types, renamed for consistency in EGL 1.3 */ +typedef EGLNativeDisplayType NativeDisplayType; +typedef EGLNativePixmapType NativePixmapType; +typedef EGLNativeWindowType NativeWindowType; + + +/* Define EGLint. This must be a signed integral type large enough to contain + * all legal attribute names and values passed into and out of EGL, whether + * their type is boolean, bitmask, enumerant (symbolic constant), integer, + * handle, or other. While in general a 32-bit integer will suffice, if + * handles are 64 bit types, then EGLint should be defined as a signed 64-bit + * integer type. + */ +typedef khronos_int32_t EGLint; + +#endif /* __eglplatform_h */ From 62c03c084b17a8094e864af1378344ee69a22c66 Mon Sep 17 00:00:00 2001 From: Paul Hunkin Date: Thu, 10 Jun 2010 19:02:55 +1200 Subject: [PATCH 08/34] Renamed some files to fit naming conventions --- src/video/android/{SDL_androidevents_c.h => SDL_androidevents.h} | 0 src/video/android/{SDL_androidrender_c.h => SDL_androidrender.h} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/video/android/{SDL_androidevents_c.h => SDL_androidevents.h} (100%) rename src/video/android/{SDL_androidrender_c.h => SDL_androidrender.h} (100%) diff --git a/src/video/android/SDL_androidevents_c.h b/src/video/android/SDL_androidevents.h similarity index 100% rename from src/video/android/SDL_androidevents_c.h rename to src/video/android/SDL_androidevents.h diff --git a/src/video/android/SDL_androidrender_c.h b/src/video/android/SDL_androidrender.h similarity index 100% rename from src/video/android/SDL_androidrender_c.h rename to src/video/android/SDL_androidrender.h From 61533285f19ae3919cd32d693befda97c56e0429 Mon Sep 17 00:00:00 2001 From: Paul Hunkin Date: Thu, 10 Jun 2010 19:25:55 +1200 Subject: [PATCH 09/34] Fixed #includes to fix naming conventions --- src/video/android/SDL_androidgl.c | 4 ++-- src/video/android/SDL_androidvideo.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/video/android/SDL_androidgl.c b/src/video/android/SDL_androidgl.c index d0df06890..bfbdab223 100644 --- a/src/video/android/SDL_androidgl.c +++ b/src/video/android/SDL_androidgl.c @@ -31,8 +31,8 @@ #include "../../events/SDL_events_c.h" #include "SDL_androidvideo.h" -#include "SDL_androidevents_c.h" -#include "SDL_androidrender_c.h" +#include "SDL_androidevents.h" +#include "SDL_androidrender.h" /* Android header */ #include "egl.h" diff --git a/src/video/android/SDL_androidvideo.c b/src/video/android/SDL_androidvideo.c index 565a1e1c0..14c762eab 100644 --- a/src/video/android/SDL_androidvideo.c +++ b/src/video/android/SDL_androidvideo.c @@ -31,8 +31,8 @@ #include "../../events/SDL_events_c.h" #include "SDL_androidvideo.h" -#include "SDL_androidevents_c.h" -#include "SDL_androidrender_c.h" +#include "SDL_androidevents.h" +#include "SDL_androidrender.h" #define ANDROID_VID_DRIVER_NAME "Android" From 6771f38b39880f0b8b2faab7e7f778417cf0ef1e Mon Sep 17 00:00:00 2001 From: Paul Hunkin Date: Thu, 17 Jun 2010 22:19:27 +1200 Subject: [PATCH 10/34] Added minimal test project --- android/testproject/AndroidManifest.xml | 15 ++ android/testproject/build.properties | 17 ++ android/testproject/build.xml | 67 +++++++ android/testproject/default.properties | 11 ++ android/testproject/jni/Android.mk | 16 ++ android/testproject/jni/app-android.c | 79 ++++++++ android/testproject/jni/importgl.c | 168 +++++++++++++++++ android/testproject/jni/importgl.h | 172 ++++++++++++++++++ .../testproject/libs/armeabi/libsanangeles.so | Bin 0 -> 14965 bytes android/testproject/local.properties | 10 + .../testproject/res/drawable-hdpi/icon.png | Bin 0 -> 4147 bytes .../testproject/res/drawable-ldpi/icon.png | Bin 0 -> 1723 bytes .../testproject/res/drawable-mdpi/icon.png | Bin 0 -> 2574 bytes android/testproject/res/layout/main.xml | 13 ++ android/testproject/res/values/strings.xml | 4 + .../src/org/libsdl/android/TestActivity.java | 76 ++++++++ 16 files changed, 648 insertions(+) create mode 100644 android/testproject/AndroidManifest.xml create mode 100644 android/testproject/build.properties create mode 100644 android/testproject/build.xml create mode 100644 android/testproject/default.properties create mode 100644 android/testproject/jni/Android.mk create mode 100644 android/testproject/jni/app-android.c create mode 100644 android/testproject/jni/importgl.c create mode 100644 android/testproject/jni/importgl.h create mode 100755 android/testproject/libs/armeabi/libsanangeles.so create mode 100644 android/testproject/local.properties create mode 100644 android/testproject/res/drawable-hdpi/icon.png create mode 100644 android/testproject/res/drawable-ldpi/icon.png create mode 100644 android/testproject/res/drawable-mdpi/icon.png create mode 100644 android/testproject/res/layout/main.xml create mode 100644 android/testproject/res/values/strings.xml create mode 100644 android/testproject/src/org/libsdl/android/TestActivity.java diff --git a/android/testproject/AndroidManifest.xml b/android/testproject/AndroidManifest.xml new file mode 100644 index 000000000..57c344aa8 --- /dev/null +++ b/android/testproject/AndroidManifest.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/android/testproject/build.properties b/android/testproject/build.properties new file mode 100644 index 000000000..edc7f2305 --- /dev/null +++ b/android/testproject/build.properties @@ -0,0 +1,17 @@ +# This file is used to override default values used by the Ant build system. +# +# This file must be checked in Version Control Systems, as it is +# integral to the build system of your project. + +# This file is only used by the Ant script. + +# You can use this to override default values such as +# 'source.dir' for the location of your java source folder and +# 'out.dir' for the location of your output folder. + +# You can also use it define how the release builds are signed by declaring +# the following properties: +# 'key.store' for the location of your keystore and +# 'key.alias' for the name of the key to use. +# The password will be asked during the build when you use the 'release' target. + diff --git a/android/testproject/build.xml b/android/testproject/build.xml new file mode 100644 index 000000000..cd16dcbea --- /dev/null +++ b/android/testproject/build.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/testproject/default.properties b/android/testproject/default.properties new file mode 100644 index 000000000..459f2ac68 --- /dev/null +++ b/android/testproject/default.properties @@ -0,0 +1,11 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system use, +# "build.properties", and override values to adapt the script to your +# project structure. + +# Project target. +target=Google Inc.:Google APIs:7 diff --git a/android/testproject/jni/Android.mk b/android/testproject/jni/Android.mk new file mode 100644 index 000000000..77dfca416 --- /dev/null +++ b/android/testproject/jni/Android.mk @@ -0,0 +1,16 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := sanangeles + +LOCAL_CFLAGS := -DANDROID_NDK \ + -DDISABLE_IMPORTGL + +LOCAL_SRC_FILES := \ + importgl.c \ + app-android.c \ + +LOCAL_LDLIBS := -lGLESv1_CM -ldl -llog + +include $(BUILD_SHARED_LIBRARY) diff --git a/android/testproject/jni/app-android.c b/android/testproject/jni/app-android.c new file mode 100644 index 000000000..c91867ee4 --- /dev/null +++ b/android/testproject/jni/app-android.c @@ -0,0 +1,79 @@ +/******************************************************************************* + Headers +*******************************************************************************/ +#include +#include +#include +#include +#include + +/******************************************************************************* + Globals +*******************************************************************************/ +int gAppAlive = 1; + +static int sWindowWidth = 320; +static int sWindowHeight = 480; +static int sDemoStopped = 0; + +static long _getTime(void){ + struct timeval now; + gettimeofday(&now, NULL); + return (long)(now.tv_sec*1000 + now.tv_usec/1000); +} + +/******************************************************************************* + Initialize the graphics state +*******************************************************************************/ +void Java_org_libsdl_android_TestRenderer_nativeInit( JNIEnv* env ) +{ + importGLInit(); + + gAppAlive = 1; + sDemoStopped = 0; +} + +/******************************************************************************* + Resize +*******************************************************************************/ +void Java_org_libsdl_android_TestRenderer_nativeResize( JNIEnv* env, + jobject thiz, + jint w, + jint h ) +{ + sWindowWidth = w; + sWindowHeight = h; + __android_log_print(ANDROID_LOG_INFO, "SDL", "resize w=%d h=%d", w, h); +} + +/******************************************************************************* + Finalize (ie: shutdown) +*******************************************************************************/ +void Java_org_libsdl_android_TestRenderer_nativeDone( JNIEnv* env ) +{ + + //shut down the app + + importGLDeinit(); +} + +/******************************************************************************* + Pause (ie: stop as soon as possible) +*******************************************************************************/ +void Java_org_libsdl_android_TestGLSurfaceView_nativePause( JNIEnv* env ) +{ + sDemoStopped = !sDemoStopped; + if (sDemoStopped) { + //we paused + } else { + //we resumed + } +} + +/******************************************************************************* + Render the next frame +*******************************************************************************/ +void Java_org_libsdl_android_TestRenderer_nativeRender( JNIEnv* env ) +{ + //TODO: Render here +} diff --git a/android/testproject/jni/importgl.c b/android/testproject/jni/importgl.c new file mode 100644 index 000000000..f501636c7 --- /dev/null +++ b/android/testproject/jni/importgl.c @@ -0,0 +1,168 @@ +/* San Angeles Observation OpenGL ES version example + * Copyright 2004-2005 Jetro Lauha + * All rights reserved. + * Web: http://iki.fi/jetro/ + * + * This source is free software; you can redistribute it and/or + * modify it under the terms of EITHER: + * (1) The GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. The text of the GNU Lesser + * General Public License is included with this source in the + * file LICENSE-LGPL.txt. + * (2) The BSD-style license that is included with this source in + * the file LICENSE-BSD.txt. + * + * This source 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 files + * LICENSE-LGPL.txt and LICENSE-BSD.txt for more details. + * + * $Id: importgl.c,v 1.4 2005/02/08 18:42:55 tonic Exp $ + * $Revision: 1.4 $ + */ + +#undef WIN32 +#undef LINUX +#ifdef _MSC_VER +// Desktop or mobile Win32 environment: +#define WIN32 +#else +// Linux environment: +#define LINUX +#endif + +#ifndef DISABLE_IMPORTGL + +#if defined(WIN32) +#define WIN32_LEAN_AND_MEAN +#include +#include +static HMODULE sGLESDLL = NULL; +#endif // WIN32 + +#ifdef LINUX +#include +#include +static void *sGLESSO = NULL; +#endif // LINUX + +#endif /* DISABLE_IMPORTGL */ + +#define IMPORTGL_NO_FNPTR_DEFS +#define IMPORTGL_API +#define IMPORTGL_FNPTRINIT = NULL +#include "importgl.h" + + +/* Imports function pointers to selected function calls in OpenGL ES Common + * or Common Lite profile DLL or shared object. The function pointers are + * stored as global symbols with equivalent function name but prefixed with + * "funcPtr_". Standard gl/egl calls are redirected to the function pointers + * with preprocessor macros (see importgl.h). + */ +int importGLInit() +{ + int result = 1; + +#ifndef DISABLE_IMPORTGL + +#undef IMPORT_FUNC + +#ifdef WIN32 + sGLESDLL = LoadLibrary(_T("libGLES_CM.dll")); + if (sGLESDLL == NULL) + sGLESDLL = LoadLibrary(_T("libGLES_CL.dll")); + if (sGLESDLL == NULL) + return 0; // Cannot find OpenGL ES Common or Common Lite DLL. + + /* The following fetches address to each egl & gl function call + * and stores it to the related function pointer. Casting through + * void * results in warnings with VC warning level 4, which + * could be fixed by casting to the true type for each fetch. + */ +#define IMPORT_FUNC(funcName) do { \ + void *procAddress = (void *)GetProcAddress(sGLESDLL, _T(#funcName)); \ + if (procAddress == NULL) result = 0; \ + *((void **)&FNPTR(funcName)) = procAddress; } while (0) +#endif // WIN32 + +#ifdef LINUX +#ifdef ANDROID_NDK + sGLESSO = dlopen("libGLESv1_CM.so", RTLD_NOW); +#else /* !ANDROID_NDK */ + sGLESSO = dlopen("libGLES_CM.so", RTLD_NOW); + if (sGLESSO == NULL) + sGLESSO = dlopen("libGLES_CL.so", RTLD_NOW); +#endif /* !ANDROID_NDK */ + if (sGLESSO == NULL) + return 0; // Cannot find OpenGL ES Common or Common Lite SO. + +#define IMPORT_FUNC(funcName) do { \ + void *procAddress = (void *)dlsym(sGLESSO, #funcName); \ + if (procAddress == NULL) result = 0; \ + *((void **)&FNPTR(funcName)) = procAddress; } while (0) +#endif // LINUX + +#ifndef ANDROID_NDK + IMPORT_FUNC(eglChooseConfig); + IMPORT_FUNC(eglCreateContext); + IMPORT_FUNC(eglCreateWindowSurface); + IMPORT_FUNC(eglDestroyContext); + IMPORT_FUNC(eglDestroySurface); + IMPORT_FUNC(eglGetConfigAttrib); + IMPORT_FUNC(eglGetConfigs); + IMPORT_FUNC(eglGetDisplay); + IMPORT_FUNC(eglGetError); + IMPORT_FUNC(eglInitialize); + IMPORT_FUNC(eglMakeCurrent); + IMPORT_FUNC(eglSwapBuffers); + IMPORT_FUNC(eglTerminate); +#endif /* !ANDROID_NDK */ + + IMPORT_FUNC(glBlendFunc); + IMPORT_FUNC(glClear); + IMPORT_FUNC(glClearColorx); + IMPORT_FUNC(glColor4x); + IMPORT_FUNC(glColorPointer); + IMPORT_FUNC(glDisable); + IMPORT_FUNC(glDisableClientState); + IMPORT_FUNC(glDrawArrays); + IMPORT_FUNC(glEnable); + IMPORT_FUNC(glEnableClientState); + IMPORT_FUNC(glFrustumx); + IMPORT_FUNC(glGetError); + IMPORT_FUNC(glLightxv); + IMPORT_FUNC(glLoadIdentity); + IMPORT_FUNC(glMaterialx); + IMPORT_FUNC(glMaterialxv); + IMPORT_FUNC(glMatrixMode); + IMPORT_FUNC(glMultMatrixx); + IMPORT_FUNC(glNormalPointer); + IMPORT_FUNC(glPopMatrix); + IMPORT_FUNC(glPushMatrix); + IMPORT_FUNC(glRotatex); + IMPORT_FUNC(glScalex); + IMPORT_FUNC(glShadeModel); + IMPORT_FUNC(glTranslatex); + IMPORT_FUNC(glVertexPointer); + IMPORT_FUNC(glViewport); + +#endif /* DISABLE_IMPORTGL */ + + return result; +} + + +void importGLDeinit() +{ +#ifndef DISABLE_IMPORTGL +#ifdef WIN32 + FreeLibrary(sGLESDLL); +#endif + +#ifdef LINUX + dlclose(sGLESSO); +#endif +#endif /* DISABLE_IMPORTGL */ +} diff --git a/android/testproject/jni/importgl.h b/android/testproject/jni/importgl.h new file mode 100644 index 000000000..b05e0c84f --- /dev/null +++ b/android/testproject/jni/importgl.h @@ -0,0 +1,172 @@ +/* San Angeles Observation OpenGL ES version example + * Copyright 2004-2005 Jetro Lauha + * All rights reserved. + * Web: http://iki.fi/jetro/ + * + * This source is free software; you can redistribute it and/or + * modify it under the terms of EITHER: + * (1) The GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. The text of the GNU Lesser + * General Public License is included with this source in the + * file LICENSE-LGPL.txt. + * (2) The BSD-style license that is included with this source in + * the file LICENSE-BSD.txt. + * + * This source 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 files + * LICENSE-LGPL.txt and LICENSE-BSD.txt for more details. + * + * $Id: importgl.h,v 1.4 2005/02/24 20:29:33 tonic Exp $ + * $Revision: 1.4 $ + */ + +#ifndef IMPORTGL_H_INCLUDED +#define IMPORTGL_H_INCLUDED + + +#ifdef __cplusplus +extern "C" { +#endif + + +#include +#ifndef ANDROID_NDK +#include +#endif /* !ANDROID_NDK */ + +/* Use DISABLE_IMPORTGL if you want to link the OpenGL ES at + * compile/link time and not import it dynamically runtime. + */ +#ifndef DISABLE_IMPORTGL + + +/* Dynamically fetches pointers to the egl & gl functions. + * Should be called once on application initialization. + * Returns non-zero on success and 0 on failure. + */ +extern int importGLInit(); + +/* Frees the handle to egl & gl functions library. + */ +extern void importGLDeinit(); + + +#ifndef IMPORTGL_API +#define IMPORTGL_API extern +#endif +#ifndef IMPORTGL_FNPTRINIT +#define IMPORTGL_FNPTRINIT +#endif + +#define FNDEF(retType, funcName, args) IMPORTGL_API retType (*funcPtr_##funcName) args IMPORTGL_FNPTRINIT + +#ifndef ANDROID_NDK +FNDEF(EGLBoolean, eglChooseConfig, (EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config)); +FNDEF(EGLContext, eglCreateContext, (EGLDisplay dpy, EGLConfig config, EGLContext share_list, const EGLint *attrib_list)); +FNDEF(EGLSurface, eglCreateWindowSurface, (EGLDisplay dpy, EGLConfig config, NativeWindowType window, const EGLint *attrib_list)); +FNDEF(EGLBoolean, eglDestroyContext, (EGLDisplay dpy, EGLContext ctx)); +FNDEF(EGLBoolean, eglDestroySurface, (EGLDisplay dpy, EGLSurface surface)); +FNDEF(EGLBoolean, eglGetConfigAttrib, (EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value)); +FNDEF(EGLBoolean, eglGetConfigs, (EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config)); +FNDEF(EGLDisplay, eglGetDisplay, (NativeDisplayType display)); +FNDEF(EGLint, eglGetError, (void)); +FNDEF(EGLBoolean, eglInitialize, (EGLDisplay dpy, EGLint *major, EGLint *minor)); +FNDEF(EGLBoolean, eglMakeCurrent, (EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx)); +FNDEF(EGLBoolean, eglSwapBuffers, (EGLDisplay dpy, EGLSurface draw)); +FNDEF(EGLBoolean, eglTerminate, (EGLDisplay dpy)); +#endif /* !ANDROID_NDK */ + +FNDEF(void, glBlendFunc, (GLenum sfactor, GLenum dfactor)); +FNDEF(void, glClear, (GLbitfield mask)); +FNDEF(void, glClearColorx, (GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha)); +FNDEF(void, glColor4x, (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha)); +FNDEF(void, glColorPointer, (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)); +FNDEF(void, glDisable, (GLenum cap)); +FNDEF(void, glDisableClientState, (GLenum array)); +FNDEF(void, glDrawArrays, (GLenum mode, GLint first, GLsizei count)); +FNDEF(void, glEnable, (GLenum cap)); +FNDEF(void, glEnableClientState, (GLenum array)); +FNDEF(void, glFrustumx, (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar)); +FNDEF(GLenum, glGetError, (void)); +FNDEF(void, glLightxv, (GLenum light, GLenum pname, const GLfixed *params)); +FNDEF(void, glLoadIdentity, (void)); +FNDEF(void, glMaterialx, (GLenum face, GLenum pname, GLfixed param)); +FNDEF(void, glMaterialxv, (GLenum face, GLenum pname, const GLfixed *params)); +FNDEF(void, glMatrixMode, (GLenum mode)); +FNDEF(void, glMultMatrixx, (const GLfixed *m)); +FNDEF(void, glNormalPointer, (GLenum type, GLsizei stride, const GLvoid *pointer)); +FNDEF(void, glPopMatrix, (void)); +FNDEF(void, glPushMatrix, (void)); +FNDEF(void, glRotatex, (GLfixed angle, GLfixed x, GLfixed y, GLfixed z)); +FNDEF(void, glScalex, (GLfixed x, GLfixed y, GLfixed z)); +FNDEF(void, glShadeModel, (GLenum mode)); +FNDEF(void, glTranslatex, (GLfixed x, GLfixed y, GLfixed z)); +FNDEF(void, glVertexPointer, (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)); +FNDEF(void, glViewport, (GLint x, GLint y, GLsizei width, GLsizei height)); + + +#undef FN +#define FNPTR(name) funcPtr_##name + +#ifndef IMPORTGL_NO_FNPTR_DEFS + +// Redirect egl* and gl* function calls to funcPtr_egl* and funcPtr_gl*. + +#ifndef ANDROID_NDK +#define eglChooseConfig FNPTR(eglChooseConfig) +#define eglCreateContext FNPTR(eglCreateContext) +#define eglCreateWindowSurface FNPTR(eglCreateWindowSurface) +#define eglDestroyContext FNPTR(eglDestroyContext) +#define eglDestroySurface FNPTR(eglDestroySurface) +#define eglGetConfigAttrib FNPTR(eglGetConfigAttrib) +#define eglGetConfigs FNPTR(eglGetConfigs) +#define eglGetDisplay FNPTR(eglGetDisplay) +#define eglGetError FNPTR(eglGetError) +#define eglInitialize FNPTR(eglInitialize) +#define eglMakeCurrent FNPTR(eglMakeCurrent) +#define eglSwapBuffers FNPTR(eglSwapBuffers) +#define eglTerminate FNPTR(eglTerminate) +#endif /* !ANDROID_NDK */ + +#define glBlendFunc FNPTR(glBlendFunc) +#define glClear FNPTR(glClear) +#define glClearColorx FNPTR(glClearColorx) +#define glColor4x FNPTR(glColor4x) +#define glColorPointer FNPTR(glColorPointer) +#define glDisable FNPTR(glDisable) +#define glDisableClientState FNPTR(glDisableClientState) +#define glDrawArrays FNPTR(glDrawArrays) +#define glEnable FNPTR(glEnable) +#define glEnableClientState FNPTR(glEnableClientState) +#define glFrustumx FNPTR(glFrustumx) +#define glGetError FNPTR(glGetError) +#define glLightxv FNPTR(glLightxv) +#define glLoadIdentity FNPTR(glLoadIdentity) +#define glMaterialx FNPTR(glMaterialx) +#define glMaterialxv FNPTR(glMaterialxv) +#define glMatrixMode FNPTR(glMatrixMode) +#define glMultMatrixx FNPTR(glMultMatrixx) +#define glNormalPointer FNPTR(glNormalPointer) +#define glPopMatrix FNPTR(glPopMatrix) +#define glPushMatrix FNPTR(glPushMatrix) +#define glRotatex FNPTR(glRotatex) +#define glScalex FNPTR(glScalex) +#define glShadeModel FNPTR(glShadeModel) +#define glTranslatex FNPTR(glTranslatex) +#define glVertexPointer FNPTR(glVertexPointer) +#define glViewport FNPTR(glViewport) + +#endif // !IMPORTGL_NO_FNPTR_DEFS + + +#endif // !DISABLE_IMPORTGL + + +#ifdef __cplusplus +} +#endif + + +#endif // !IMPORTGL_H_INCLUDED diff --git a/android/testproject/libs/armeabi/libsanangeles.so b/android/testproject/libs/armeabi/libsanangeles.so new file mode 100755 index 0000000000000000000000000000000000000000..19f068d921b537084d27ab04b0e44ff46a39ec04 GIT binary patch literal 14965 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 literal 0 HcmV?d00001 diff --git a/android/testproject/local.properties b/android/testproject/local.properties new file mode 100644 index 000000000..27accedc4 --- /dev/null +++ b/android/testproject/local.properties @@ -0,0 +1,10 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must *NOT* be checked in Version Control Systems, +# as it contains information specific to your local configuration. + +# location of the SDK. This is only used by Ant +# For customization when using a Version Control System, please read the +# header note. +sdk.dir=/home/paul/Projects/gsoc/sdk/android-sdk-linux_86 diff --git a/android/testproject/res/drawable-hdpi/icon.png b/android/testproject/res/drawable-hdpi/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..8074c4c571b8cd19e27f4ee5545df367420686d7 GIT binary patch literal 4147 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 literal 0 HcmV?d00001 diff --git a/android/testproject/res/drawable-ldpi/icon.png b/android/testproject/res/drawable-ldpi/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..1095584ec21f71cd0afc9e0993aa2209671b590c GIT binary patch literal 1723 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 + + + + diff --git a/android/testproject/res/values/strings.xml b/android/testproject/res/values/strings.xml new file mode 100644 index 000000000..060fae8f8 --- /dev/null +++ b/android/testproject/res/values/strings.xml @@ -0,0 +1,4 @@ + + + TestActivity + diff --git a/android/testproject/src/org/libsdl/android/TestActivity.java b/android/testproject/src/org/libsdl/android/TestActivity.java new file mode 100644 index 000000000..5777d42ee --- /dev/null +++ b/android/testproject/src/org/libsdl/android/TestActivity.java @@ -0,0 +1,76 @@ +package org.libsdl.android; + +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.opengles.GL10; + +import android.app.Activity; +import android.content.Context; +import android.opengl.GLSurfaceView; +import android.os.Bundle; +import android.view.MotionEvent; + +public class TestActivity extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mGLView = new TestGLSurfaceView(this); + setContentView(mGLView); + } + + @Override + protected void onPause() { + super.onPause(); + mGLView.onPause(); + } + + @Override + protected void onResume() { + super.onResume(); + mGLView.onResume(); + } + + private GLSurfaceView mGLView; + + static { + System.loadLibrary("sanangeles"); + } +} + +class TestGLSurfaceView extends GLSurfaceView { + public TestGLSurfaceView(Context context) { + super(context); + mRenderer = new TestRenderer(); + setRenderer(mRenderer); + } + + public boolean onTouchEvent(final MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_DOWN) { + nativePause(); + } + return true; + } + + TestRenderer mRenderer; + + private static native void nativePause(); +} + +class TestRenderer implements GLSurfaceView.Renderer { + public void onSurfaceCreated(GL10 gl, EGLConfig config) { + nativeInit(); + } + + public void onSurfaceChanged(GL10 gl, int w, int h) { + //gl.glViewport(0, 0, w, h); + nativeResize(w, h); + } + + public void onDrawFrame(GL10 gl) { + nativeRender(); + } + + private static native void nativeInit(); + private static native void nativeResize(int w, int h); + private static native void nativeRender(); + private static native void nativeDone(); +} From 14131e36eb1412bc2c61680f30bfe9d619c87099 Mon Sep 17 00:00:00 2001 From: Paul Hunkin Date: Thu, 17 Jun 2010 23:04:16 +1200 Subject: [PATCH 11/34] Rotating pyramid! --- android/testproject/jni/app-android.c | 274 ++++++++++++++++++++++++++ 1 file changed, 274 insertions(+) diff --git a/android/testproject/jni/app-android.c b/android/testproject/jni/app-android.c index c91867ee4..ae39f3e36 100644 --- a/android/testproject/jni/app-android.c +++ b/android/testproject/jni/app-android.c @@ -7,6 +7,12 @@ #include #include +#include +#include +#include + +#include "importgl.h" + /******************************************************************************* Globals *******************************************************************************/ @@ -22,6 +28,106 @@ static long _getTime(void){ return (long)(now.tv_sec*1000 + now.tv_usec/1000); } +/************************************** + gluperspective implementation +**************************************/ +void gluPerspective(double fovy, double aspect, double zNear, double zFar){ + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + double xmin, xmax, ymin, ymax; + ymax = zNear * tan(fovy * M_PI / 360.0); + ymin = -ymax; + xmin = ymin * aspect; + xmax = ymax * aspect; + glFrustumf(xmin, xmax, ymin, ymax, zNear, zFar); +} + + +/************************************** + glulookat implementation +**************************************/ +void gluLookAt(GLfloat eyex, GLfloat eyey, GLfloat eyez, + GLfloat centerx, GLfloat centery, GLfloat centerz, + GLfloat upx, GLfloat upy, GLfloat upz) +{ + GLfloat m[16]; + GLfloat x[3], y[3], z[3]; + GLfloat mag; + + /* Make rotation matrix */ + + /* Z vector */ + z[0] = eyex - centerx; + z[1] = eyey - centery; + z[2] = eyez - centerz; + mag = sqrt(z[0] * z[0] + z[1] * z[1] + z[2] * z[2]); + if (mag) { /* mpichler, 19950515 */ + z[0] /= mag; + z[1] /= mag; + z[2] /= mag; + } + + /* Y vector */ + y[0] = upx; + y[1] = upy; + y[2] = upz; + + /* X vector = Y cross Z */ + x[0] = y[1] * z[2] - y[2] * z[1]; + x[1] = -y[0] * z[2] + y[2] * z[0]; + x[2] = y[0] * z[1] - y[1] * z[0]; + + /* Recompute Y = Z cross X */ + y[0] = z[1] * x[2] - z[2] * x[1]; + y[1] = -z[0] * x[2] + z[2] * x[0]; + y[2] = z[0] * x[1] - z[1] * x[0]; + + /* mpichler, 19950515 */ + /* cross product gives area of parallelogram, which is < 1.0 for + * non-perpendicular unit-length vectors; so normalize x, y here + */ + + mag = sqrt(x[0] * x[0] + x[1] * x[1] + x[2] * x[2]); + if (mag) { + x[0] /= mag; + x[1] /= mag; + x[2] /= mag; + } + + mag = sqrt(y[0] * y[0] + y[1] * y[1] + y[2] * y[2]); + if (mag) { + y[0] /= mag; + y[1] /= mag; + y[2] /= mag; + } + +#define M(row,col) m[col*4+row] + M(0, 0) = x[0]; + M(0, 1) = x[1]; + M(0, 2) = x[2]; + M(0, 3) = 0.0; + M(1, 0) = y[0]; + M(1, 1) = y[1]; + M(1, 2) = y[2]; + M(1, 3) = 0.0; + M(2, 0) = z[0]; + M(2, 1) = z[1]; + M(2, 2) = z[2]; + M(2, 3) = 0.0; + M(3, 0) = 0.0; + M(3, 1) = 0.0; + M(3, 2) = 0.0; + M(3, 3) = 1.0; +#undef M + glMultMatrixf(m); + + /* Translate Eye to Origin */ + glTranslatef(-eyex, -eyey, -eyez); + +} + + + /******************************************************************************* Initialize the graphics state *******************************************************************************/ @@ -31,6 +137,29 @@ void Java_org_libsdl_android_TestRenderer_nativeInit( JNIEnv* env ) gAppAlive = 1; sDemoStopped = 0; + + __android_log_print(ANDROID_LOG_INFO, "SDL", "Entry point"); + + + /* Enable smooth shading */ + glShadeModel( GL_SMOOTH ); + + /* Set the background black */ + glClearColor( 1.0f, 0.0f, 0.0f, 0.0f ); + + /* Depth buffer setup */ + //glClearDepth( 1.0f ); + + /* Enables Depth Testing */ + glEnable( GL_DEPTH_TEST ); + + /* The Type Of Depth Test To Do */ + glDepthFunc( GL_LEQUAL ); + + /* Really Nice Perspective Calculations */ + glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST ); + + } /******************************************************************************* @@ -44,6 +173,35 @@ void Java_org_libsdl_android_TestRenderer_nativeResize( JNIEnv* env, sWindowWidth = w; sWindowHeight = h; __android_log_print(ANDROID_LOG_INFO, "SDL", "resize w=%d h=%d", w, h); + + + + /* Height / width ration */ + GLfloat ratio; + + /* Protect against a divide by zero */ + if ( h == 0 ) + h = 1; + + ratio = ( GLfloat )w / ( GLfloat )h; + + /* Setup our viewport. */ + glViewport( 0, 0, ( GLsizei )w, ( GLsizei )h ); + + /* change to the projection matrix and set our viewing volume. */ + glMatrixMode( GL_PROJECTION ); + glLoadIdentity( ); + + /* Set our perspective */ + gluPerspective( 45.0f, ratio, 0.1f, 100.0f ); + + /* Make sure we're chaning the model view and not the projection */ + glMatrixMode( GL_MODELVIEW ); + + /* Reset The View */ + glLoadIdentity( ); + + } /******************************************************************************* @@ -55,6 +213,8 @@ void Java_org_libsdl_android_TestRenderer_nativeDone( JNIEnv* env ) //shut down the app importGLDeinit(); + + __android_log_print(ANDROID_LOG_INFO, "SDL", "Finalize"); } /******************************************************************************* @@ -65,15 +225,129 @@ void Java_org_libsdl_android_TestGLSurfaceView_nativePause( JNIEnv* env ) sDemoStopped = !sDemoStopped; if (sDemoStopped) { //we paused + __android_log_print(ANDROID_LOG_INFO, "SDL", "Pause"); } else { //we resumed + __android_log_print(ANDROID_LOG_INFO, "SDL", "Resume"); } } /******************************************************************************* Render the next frame *******************************************************************************/ + +const GLbyte vertex []= +{ + 0,1,0, + -1,0,0, + 1,0,0 +}; + +const GLubyte color []= +{ + 255,0,0, + 0,255,0, + 0,0,255 +}; + +int iRot = 0; +int Frames = 0; + + +static void prepareFrame(int width, int height) +{ + glViewport(0, 0, width, height); + + glClearColorx(0,0,0,255); + glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(45, (float)width / height, 0.5f, 150); + + glMatrixMode(GL_MODELVIEW); + + glLoadIdentity(); +} + void Java_org_libsdl_android_TestRenderer_nativeRender( JNIEnv* env ) { //TODO: Render here + + prepareFrame(sWindowWidth, sWindowHeight); + + //Camera + gluLookAt(0,0,5, 0,0,0, 0,1,0); + + //Draw a triangle + //glRotatef(iRot, 0, 1, 0); + + glRotatef( Frames % 360, 0.0f, 1.0f, 0.0f ); + + + glEnableClientState (GL_VERTEX_ARRAY); + glEnableClientState (GL_COLOR_ARRAY); + + /* Rotate The Triangle On The Y axis ( NEW ) */ + glRotatef( Frames % 360, 0.0f, 1.0f, 0.0f ); + + /* GLES variant of drawing a triangle */ + const GLfloat triVertices[][9] = { + { /* Front Triangle */ + 0.0f, 1.0f, 0.0f, /* Top Of Triangle */ + -1.0f, -1.0f, 1.0f, /* Left Of Triangle */ + 1.0f, -1.0f, 1.0f /* Right Of Triangle */ + }, { /* Right Triangle */ + 0.0f, 1.0f, 0.0f, /* Top Of Triangle */ + 1.0f, -1.0f, 1.0f, /* Left Of Triangle */ + 1.0f, -1.0f, -1.0f /* Right Of Triangle */ + }, { /* Back Triangle */ + 0.0f, 1.0f, 0.0f, /* Top Of Triangle */ + 1.0f, -1.0f, -1.0f, /* Left Of Triangle */ + -1.0f, -1.0f, -1.0f /* Right Of Triangle */ + }, { /* Left Triangle */ + 0.0f, 1.0f, 0.0f, /* Top Of Triangle */ + -1.0f, -1.0f, -1.0f, /* Left Of Triangle */ + -1.0f, -1.0f, 1.0f /* Right Of Triangle */ + } + }; + + /* unlike GL, GLES does not support RGB. We have to use RGBA instead */ + const GLfloat triColors[][12] = { + { /* Front triangle */ + 1.0f, 0.0f, 0.0f, 1.0f, /* Red */ + 0.0f, 1.0f, 0.0f, 1.0f, /* Green */ + 0.0f, 0.0f, 1.0f, 1.0f /* Blue */ + }, { /* Right triangle */ + 1.0f, 0.0f, 0.0f, 1.0f, /* Red */ + 0.0f, 0.0f, 1.0f, 1.0f, /* Blue */ + 0.0f, 1.0f, 0.0f, 1.0f /* Green */ + }, { /* Back triangle */ + 1.0f, 0.0f, 0.0f, 1.0f, /* Red */ + 0.0f, 1.0f, 0.0f, 1.0f, /* Green */ + 0.0f, 0.0f, 1.0f, 1.0f /* Blue */ + }, { /* Left triangle */ + 1.0f, 0.0f, 0.0f, 1.0f, /* Red */ + 0.0f, 0.0f, 1.0f, 1.0f, /* Blue */ + 0.0f, 1.0f, 0.0f, 1.0f /* Green */ + } + }; + + glEnableClientState(GL_COLOR_ARRAY); + + int tri=0; + + /* Loop through all Triangles */ + for(tri=0;tri Date: Fri, 18 Jun 2010 00:02:13 +1200 Subject: [PATCH 12/34] Testing out pthread support in android. Appears to work. --- android/testproject/jni/app-android.c | 271 ++---------------- .../testproject/libs/armeabi/libsanangeles.so | Bin 14965 -> 0 bytes 2 files changed, 18 insertions(+), 253 deletions(-) delete mode 100755 android/testproject/libs/armeabi/libsanangeles.so diff --git a/android/testproject/jni/app-android.c b/android/testproject/jni/app-android.c index ae39f3e36..4312242d1 100644 --- a/android/testproject/jni/app-android.c +++ b/android/testproject/jni/app-android.c @@ -11,6 +11,8 @@ #include #include +#include + #include "importgl.h" /******************************************************************************* @@ -28,106 +30,18 @@ static long _getTime(void){ return (long)(now.tv_sec*1000 + now.tv_usec/1000); } -/************************************** - gluperspective implementation -**************************************/ -void gluPerspective(double fovy, double aspect, double zNear, double zFar){ - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - double xmin, xmax, ymin, ymax; - ymax = zNear * tan(fovy * M_PI / 360.0); - ymin = -ymax; - xmin = ymin * aspect; - xmax = ymax * aspect; - glFrustumf(xmin, xmax, ymin, ymax, zNear, zFar); -} - - -/************************************** - glulookat implementation -**************************************/ -void gluLookAt(GLfloat eyex, GLfloat eyey, GLfloat eyez, - GLfloat centerx, GLfloat centery, GLfloat centerz, - GLfloat upx, GLfloat upy, GLfloat upz) -{ - GLfloat m[16]; - GLfloat x[3], y[3], z[3]; - GLfloat mag; - - /* Make rotation matrix */ - - /* Z vector */ - z[0] = eyex - centerx; - z[1] = eyey - centery; - z[2] = eyez - centerz; - mag = sqrt(z[0] * z[0] + z[1] * z[1] + z[2] * z[2]); - if (mag) { /* mpichler, 19950515 */ - z[0] /= mag; - z[1] /= mag; - z[2] /= mag; - } - - /* Y vector */ - y[0] = upx; - y[1] = upy; - y[2] = upz; - - /* X vector = Y cross Z */ - x[0] = y[1] * z[2] - y[2] * z[1]; - x[1] = -y[0] * z[2] + y[2] * z[0]; - x[2] = y[0] * z[1] - y[1] * z[0]; - - /* Recompute Y = Z cross X */ - y[0] = z[1] * x[2] - z[2] * x[1]; - y[1] = -z[0] * x[2] + z[2] * x[0]; - y[2] = z[0] * x[1] - z[1] * x[0]; - - /* mpichler, 19950515 */ - /* cross product gives area of parallelogram, which is < 1.0 for - * non-perpendicular unit-length vectors; so normalize x, y here - */ - - mag = sqrt(x[0] * x[0] + x[1] * x[1] + x[2] * x[2]); - if (mag) { - x[0] /= mag; - x[1] /= mag; - x[2] /= mag; - } - - mag = sqrt(y[0] * y[0] + y[1] * y[1] + y[2] * y[2]); - if (mag) { - y[0] /= mag; - y[1] /= mag; - y[2] /= mag; - } - -#define M(row,col) m[col*4+row] - M(0, 0) = x[0]; - M(0, 1) = x[1]; - M(0, 2) = x[2]; - M(0, 3) = 0.0; - M(1, 0) = y[0]; - M(1, 1) = y[1]; - M(1, 2) = y[2]; - M(1, 3) = 0.0; - M(2, 0) = z[0]; - M(2, 1) = z[1]; - M(2, 2) = z[2]; - M(2, 3) = 0.0; - M(3, 0) = 0.0; - M(3, 1) = 0.0; - M(3, 2) = 0.0; - M(3, 3) = 1.0; -#undef M - glMultMatrixf(m); - - /* Translate Eye to Origin */ - glTranslatef(-eyex, -eyey, -eyez); - -} +/******************************************************************************* + SDL thread +*******************************************************************************/ +pthread_t mSDLThread = 0; +void* sdlThreadProc(void* args){ + __android_log_print(ANDROID_LOG_INFO, "SDL", "Thread Entry"); + return 0; +} + /******************************************************************************* Initialize the graphics state *******************************************************************************/ @@ -140,25 +54,14 @@ void Java_org_libsdl_android_TestRenderer_nativeInit( JNIEnv* env ) __android_log_print(ANDROID_LOG_INFO, "SDL", "Entry point"); + //Spin up the SDL thread + int r = pthread_create(&mSDLThread, NULL, sdlThreadProc, NULL); - /* Enable smooth shading */ - glShadeModel( GL_SMOOTH ); - - /* Set the background black */ - glClearColor( 1.0f, 0.0f, 0.0f, 0.0f ); - - /* Depth buffer setup */ - //glClearDepth( 1.0f ); - - /* Enables Depth Testing */ - glEnable( GL_DEPTH_TEST ); - - /* The Type Of Depth Test To Do */ - glDepthFunc( GL_LEQUAL ); - - /* Really Nice Perspective Calculations */ - glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST ); - + if(r != 0){ + __android_log_print(ANDROID_LOG_INFO, "SDL", "Couldn't spawn thread: %d", r); + }else{ + __android_log_print(ANDROID_LOG_INFO, "SDL", "Started SDL thread"); + } } @@ -174,34 +77,6 @@ void Java_org_libsdl_android_TestRenderer_nativeResize( JNIEnv* env, sWindowHeight = h; __android_log_print(ANDROID_LOG_INFO, "SDL", "resize w=%d h=%d", w, h); - - - /* Height / width ration */ - GLfloat ratio; - - /* Protect against a divide by zero */ - if ( h == 0 ) - h = 1; - - ratio = ( GLfloat )w / ( GLfloat )h; - - /* Setup our viewport. */ - glViewport( 0, 0, ( GLsizei )w, ( GLsizei )h ); - - /* change to the projection matrix and set our viewing volume. */ - glMatrixMode( GL_PROJECTION ); - glLoadIdentity( ); - - /* Set our perspective */ - gluPerspective( 45.0f, ratio, 0.1f, 100.0f ); - - /* Make sure we're chaning the model view and not the projection */ - glMatrixMode( GL_MODELVIEW ); - - /* Reset The View */ - glLoadIdentity( ); - - } /******************************************************************************* @@ -236,118 +111,8 @@ void Java_org_libsdl_android_TestGLSurfaceView_nativePause( JNIEnv* env ) Render the next frame *******************************************************************************/ -const GLbyte vertex []= -{ - 0,1,0, - -1,0,0, - 1,0,0 -}; - -const GLubyte color []= -{ - 255,0,0, - 0,255,0, - 0,0,255 -}; - -int iRot = 0; -int Frames = 0; - - -static void prepareFrame(int width, int height) -{ - glViewport(0, 0, width, height); - - glClearColorx(0,0,0,255); - glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - gluPerspective(45, (float)width / height, 0.5f, 150); - - glMatrixMode(GL_MODELVIEW); - - glLoadIdentity(); -} - void Java_org_libsdl_android_TestRenderer_nativeRender( JNIEnv* env ) { //TODO: Render here - prepareFrame(sWindowWidth, sWindowHeight); - - //Camera - gluLookAt(0,0,5, 0,0,0, 0,1,0); - - //Draw a triangle - //glRotatef(iRot, 0, 1, 0); - - glRotatef( Frames % 360, 0.0f, 1.0f, 0.0f ); - - - glEnableClientState (GL_VERTEX_ARRAY); - glEnableClientState (GL_COLOR_ARRAY); - - /* Rotate The Triangle On The Y axis ( NEW ) */ - glRotatef( Frames % 360, 0.0f, 1.0f, 0.0f ); - - /* GLES variant of drawing a triangle */ - const GLfloat triVertices[][9] = { - { /* Front Triangle */ - 0.0f, 1.0f, 0.0f, /* Top Of Triangle */ - -1.0f, -1.0f, 1.0f, /* Left Of Triangle */ - 1.0f, -1.0f, 1.0f /* Right Of Triangle */ - }, { /* Right Triangle */ - 0.0f, 1.0f, 0.0f, /* Top Of Triangle */ - 1.0f, -1.0f, 1.0f, /* Left Of Triangle */ - 1.0f, -1.0f, -1.0f /* Right Of Triangle */ - }, { /* Back Triangle */ - 0.0f, 1.0f, 0.0f, /* Top Of Triangle */ - 1.0f, -1.0f, -1.0f, /* Left Of Triangle */ - -1.0f, -1.0f, -1.0f /* Right Of Triangle */ - }, { /* Left Triangle */ - 0.0f, 1.0f, 0.0f, /* Top Of Triangle */ - -1.0f, -1.0f, -1.0f, /* Left Of Triangle */ - -1.0f, -1.0f, 1.0f /* Right Of Triangle */ - } - }; - - /* unlike GL, GLES does not support RGB. We have to use RGBA instead */ - const GLfloat triColors[][12] = { - { /* Front triangle */ - 1.0f, 0.0f, 0.0f, 1.0f, /* Red */ - 0.0f, 1.0f, 0.0f, 1.0f, /* Green */ - 0.0f, 0.0f, 1.0f, 1.0f /* Blue */ - }, { /* Right triangle */ - 1.0f, 0.0f, 0.0f, 1.0f, /* Red */ - 0.0f, 0.0f, 1.0f, 1.0f, /* Blue */ - 0.0f, 1.0f, 0.0f, 1.0f /* Green */ - }, { /* Back triangle */ - 1.0f, 0.0f, 0.0f, 1.0f, /* Red */ - 0.0f, 1.0f, 0.0f, 1.0f, /* Green */ - 0.0f, 0.0f, 1.0f, 1.0f /* Blue */ - }, { /* Left triangle */ - 1.0f, 0.0f, 0.0f, 1.0f, /* Red */ - 0.0f, 0.0f, 1.0f, 1.0f, /* Blue */ - 0.0f, 1.0f, 0.0f, 1.0f /* Green */ - } - }; - - glEnableClientState(GL_COLOR_ARRAY); - - int tri=0; - - /* Loop through all Triangles */ - for(tri=0;triil!9bb!)4XA4ziVp#P0<{FS$mv@Icrofa)K5BnA8=qTU^VJR4qgLD**}K5 z0<|1{O0yiz;ASt@l@I_(Rkz6zJw{ z7Q#8WFY__3!4Mi0ddR`Q4E$wBNREFJ^k=adF8xM0IQ^eR6=$+sN`q5z?@0dw=quo~ zl#}?Hy!oGnGqyPLaQ~w1|7SqI6#IXd zqu*Anmy*_d4C8Lm(D*dy#^8S)XmkD^&`(PA<$3zvkZ1pkG0!jU*Umioa0tXv1Tj~> zTC9I7_K*6^6LZ8Gj6aR_HD~?Bw3kyB6M|6ozu$rWYmz}J0$e_y8}szN0rTba^E1d(C-I|s6|4s~7QgxEXa~O3 z!DnNBh2(Ev1baJ)N^qp6Fwlj^$2?U8V-yEWX=zP+cVBOK{!>5jFxgtta}z^Gwo_l`(& zbX$A$j&N5b(SCb06xrDmJ@2e7(XN(gceLA?V59G6MqRAyeXh{c{`n~Nb!6{|wL;bQ zuJdb`C#Pkz)|z;{rUPn<@Qt?Fwryz$Z-~O065b%;7+br(CO5n`)*0`JCZ^`sMTxH4 z)f|l{+GAaivUyh|ygl05-W6`{h(@}0#+|;zo$+Y6Gm>a-Lq}`ZPIu#?yQ0lI$x5NOV^`+MI~Cpm&B{UO97jwZqs^Wj);@x~siq7y2z2?ny+t={YurjhsGX3!Ea> z9Sv_=9}3rYL=$b@u{-jnTEn?Lr;CJQ z+(wB-L*(`u?d0~Ki~1ZEvZl>oo?Jg|)9q|eGxw-F+S-G@oJ#rX<^~*PrYL7n-X)%9 z)G6juJK+-ISZs~%N^FUC)J705r0%*%A~HjFeWa^(XQVaS0KabE(cVlldD<47m{?bX z`w zlnDB^_w=}3Q|)lr8NuVYY1_P4-(>%Tt}!u4nkaZ>j_bP zspY0Gb=aJnx;Irg`GmQP7u+A;Yj~dBXY6|Oano(brFNUtZj#!KQagmUqQy7FH=J1S zyWW4@7wW!RQQ5Y+_PUzNCiX4FI=q{(tv;H4^K@1{u0C3{v3z0Cb-U_{uI;NRZ)#{N zysmGwrlPMx99*){r)A%K;`g3W_4p(%>U>^4_FviTNp3M5MzpGAJoN26V z@?DQR%aSEc>hbS`whFXdO9X~ZAsR9w(64%hp1vr1Wg2gM89btkeSnJ4529~B-k&B) z#g+_c4~l^9RRVe$9EDVl9NcDr{=)nF<|~#|yDXnX52{_V^@Zu21ea zt4?h)NaG6(nclcCe1ZGNaNjc&>eHmB%acQ9i5N2Req8BY1wNz;=$VSZ^QJFw$h;7+ z0CFr@s;9G>$MCMUX*|7qQXYryLhX4oG(2K@#7&vi$q~OYe4)`881RT;y{s@WRu)AtkqvALhM@teXmkRXB&!MYtl zXOf3U^nmB^*dFvLXct1yg|H*+R=gDaj$Emyfzt=AHQsucdWA9z<3s+1pymD`92Mie zdV=k7hSF}`z5xH_DLtd{H=&d=zVaypzuzY^FB z-wH8CRC;wiT_|oz&xQ=Y&t|V?8{ZQuU47oQ_#85;0t4pK(11BB03F4ExklDmA2Hvs zY;z0GSx#rf{7PS7&{&1Jh&h>MfWAP#u@w6ju==Q9Lk4#Gfg<)8LK#dI=h^3N@TDwv z9MIEm0xtkByz5LT!>}XvQb}SieKR!paAEIYO6d24?=6`S&L-!o>X7k@M_79YJ3+*o zvDdnHHf+YdAkEX@I~Q$tUw-YZ%W+jZY^Ji=iK2iGo9XE)#JowIYldH*rFj@bY|4}Z zQqMVn<<*DHkGkhP2ww};7&xnz@A@E5JNR=CKo36yEAwvxf_#un;a`1ZseH*bK^l1e)U~E?d1Ac#?-?JFwmR%6XAm8`u z#lWMXz`&!}_aBUs7i0x)q91hxdt^UL@Ez#eOV;S=(ma|o`=6Y3RIEY0K50EG?C%Twro-6LX<*%&?;Q5p4GlGFW6VHUS(gdBw6XW0f?Iy#AXHTg(I!=5#d|&|dR@y~*%| zY#mDQ{5bgYbL${ddS)*87siK-1F<2a1kZtr(Gin+Z8U~pTRpvJ{vop->j`mVrbySl z#kyW*`JcYGEV=T~0>-yJD{%+Fep9!i<#?`Aw*TdGls>Dc3pB`+!Wo<#F@ua-Nj<%9 zCG1r=G+vBx1-kn{;|u8NkHIdq2hJsQzA*#mwa#yW!+RKf3q@n*m)UG_0U-DOVCj&t z5&K*e(qS|3#@SSUWuMOyHECAhez8V7Xa==@(+fU0-zL-ZDZ9VQY@f^#Xv1GvcgOk1u)=4qZGtjXBr`i(3LefN)$hyJk~I?UoTgS5c82T!4| z2zu?V?XMWG)3<44x|PADX~j zS-U3%o28HNK7(=iaha0Ty`}I|(WDed}15p#w%_t1bwkD@RY^l6z1=@Xd11(pl=KU$K3|+0XOpO>}B78MRN=90>!mB zOE$hOqsF68uEv?*{R7Vq+z-Sn_rwvi&>pPrPw|}7UnrAu;=rq(6aBCHv_8b?kn!hi z_VR-2Uf63}2C?rI73=v==!?`7`c<`84jJl+dgE@)-}l45lu)Pmc;W|N^~CqteALYr zAAz-S&%r&oA9ujU%xc(zzD3z@fb8q@^!b#f&$dhu>rx-$pP=1f+mF$nZF>3=RPL=m zaCeHnf&1HDK707=An!uhaI`u(wiR>tAU;yp&1l~ZSqC@YlUmI^Yl7T(e!^}z0|#IA ziosWvruDd|_Z!svE%=+Vs4ulg4AJMz0Os?a0XLqYPr!c<;?7%XJ@cG(RjeCWnH;MJ z?e^FZ?hAVQTC}+y*K+;aCk~W*mAfyn{2TIfEv~U0`r!lHmjV#?=S(Zl{owKO zRcaFB`^Q&{<*#K+hsQ{wbWYO%T1vLlPa`-8y|AYlS%H->wd8ms}t5IuE zH={;SZ$s@x-H-Yp>M_(GqP~EdMm;m>@JN9N>LS!?)Ed;ys1elLP9@AA@cb&ju0H)3|FQURv*YWzVBs62y7KIhzZ8aL-TsaRx+i$b1GevCXkk zXN>(R^z(c^0o{|TY9OXoGG2*Z>wbl}j`!bWp&|4k^D*j$JBSbO3qetichWYsFxf9k zl0*3Rp=TC@$7DblNt`Ll#q;-7$m*-Zb19fidy2MZ{sr-2Wbt8(-dBs~q2^0*4X$}T z_L|RW#Og{t#>EZo>}0QcW0hu&4MA!@HgJ{J59#20Gz=#MTvZ{v+gMANk^r zXvJU3{|)qi2mEyKLmaOZS_=0ok8$&2zQd`R>XJxQio@L+5!h3y&BCSfPM4otiQ{1NEj z4GK>|&^KSv20W$#+# zJ~#0b(BXTEMYq_o$uim`FyFWw{gfH^noJdF&q5CJrwvPkkWm{j$hUZDpXFcNdpPmL zNl7QX1D>WnllW$%YIuKvUYI}e3~2Bmv)1)FG_KB+&F`#t3hPn60%twwX|IKK{Q*5Q zikLxPyBzmE-tAPxvdMe!K9CiH=bC5Ki+;w667jt0K`iiTL%h$zXI@0y7%~bW6Tb79 zbMPH#K4fvfsWsHq3w(3Ok5AeipSZY1Yr}ttE#m7BBkGQR7mpVquDOKm@BrJdPh@wG zj*ceB9XRH|vkrX2f=7}TJfbA4PLuvfvJQ~ULJk~p;3Ez^>%fJt+jPquIGP8K0w=$x z3BOyI?3lFWks;S1{;h&z$@|aP^zQ&3z4+neo;lQO1tOi7k69a(wL~a#K6)&NpOC;d@@H64_!kGc@LnrQT7A?BOGJGG$ z85TGzR(=D{g7s}aftL%mO90`Yq74<_wgh}oxOqOf*Tu-|uPw|)a?3;DJ5%NF;z1~! zLZ#kf!`ii1YfCqL>c-2oRV!AlfSi9*PYn*Suzo@miiW2D!&}#hS-wK0NSW^|R~9H2 zcq^0(l}gV=9_ z?Sa&PU11&%_n!MoKVS_2AL!^1Ae&t0g-687uvdbe69IlJ1kJ&d3@*|(k4x~KqfQ~hv4nu;nfIi*_SiZ!rL3F@8Rv|x@ zR#fUhn_4+}RdzleaTd~1-#9AQXFt#7vWus3v(S~>x1DIabj*v`3Oamy$rX3qFQA8f z$*&1?O`vnfNbI(gXp^5?NVm~N0Nt^FKpVU$rd5uB?g|$Hbm<98Qc(B7g!o#OIyaTi+s431VQu;t6ceR+7{d2q_J zFmJpn4_}&x2PB;H8zr3bwMjU~2PB++#QkNzg1i?(HxEVtr;9h{jdP#vGFQNDt$nxW z&lOh!9|nKU^T12jJ2(J}jWbWkE(O+knFPKR9WFg_cbxN?x8~wEq0s^y_of^@ak~_V zC>q1Sd6ry$#O+cbZb#z?@O^;pIB~n!@-dH2#+er;<3S0(2LnyON8yYvKjJPu?ZV%d zU7Y$@-<_=vdp&-Owu_DP`?QNcfW}hbtFVzSf8y>q`PVI&!jGbPEAS3Lm!7y?Z2l)D z{7DQ9<6*l{;!j+rXI`0${}PRpz#9Qw{>1I#$e#;jHqN{=d7OE0GR{0f7pFe_?cT*{ zFMf-YaptMHxQRx~MbqUW?v8Ul^VVeiX$ij;1J41M{g1dy|37HF0h}?;)t9(kZ2g!A zC*#Zum2u_?x;XXId1$O+&woh5=VBk+JB;Evlf3{q<1`C#>ci)hU1nM5^$`i@_+t`I zx|eKX#5XWQ;WL=U3yoO#tYz`y9}AzUEMAMd{p_@Hzt!)q@3o#d=yJ}hn}^Hi9*ftq zn*D6EaYkAD8D`_WEl%m{wQdSi`g)xwjvJ4>%*#V@bLKwC0^qs)vJm4<^m-B!}fXntc0-X087OwYw z;Bp@D&w;yz`uqa8oCnOjRUzkz;=svyz?Hyd`pbX^5wA5&v-ANj=K*g4F7Myp1DErF zM}W(Dz~2Hc=K((r+$|a!zW~no$N0?kUIQ-Y0nfn^ll83vF55o+c2bmc?j%9k}d&j{ukRfS=>I6Aw8*1Dx@XA(^;$7UC1)LA`^Q z0hjZDS8yB)1)cF4;PUz023*$nGr(p2wgZ>*fIkmh&I7&&xSR+4@4)3e;GY4vPcQvT z6~6$^=Ye~kUkC2S8!HdEDj}*`M9)n~@QmGYQ+rFI%|$jw+gsZbqNgs}8EZ(y;_)a_ zJe{n^mS}UVB^pMGU28P4QdCXLzuT}SM~C!RU_H@}9eBSB$9C-Ki6)TI*%OU)H@Ah? zUAq-5ws$aLRZ7!~cZd1#9bY*yl zmC7lmbqb`wCfpR+?RO@k?(mIkYr{LbW1ZmEWxZ{N>u&y3&8BOSAi1IbhT59?@D1zN zH>}$l-da;zzmBm~*PAhp++GW{#Qn$OoR>t#tQ_Nk}rm}!%*kC4PyM*#G)3dH!iad97 zlb3VDZpN-8B($@R(F`fV?hul;b8dz{Bsk~L_av!18?!c-&2FW?+Rk>qT{`z)3``3K zQz`8;sNg1-)9>Ds6F=>YIT2>6Zz?%ma$t8jKLI-D2l;;zf%JDLvsaRCT5yp5OhC^0 zwyk>3v~ellzI%pDZD}z%tJ@JDC+8dq)#uHe&i(m9o}4*nadYZ-+7Z{zrglATn$lq> vD;ma`Zup$Ebva8~e@t;cN68Bk=l+8g{H1`MSnbLLL)0NVJC{N(CvN{A(c|ZU From b5a450c76d79da2a2d54ae4b81b9c68b0cf4de09 Mon Sep 17 00:00:00 2001 From: Paul Hunkin Date: Fri, 18 Jun 2010 00:03:09 +1200 Subject: [PATCH 13/34] Removed old video subsystem, along with (now-unncessary) egl files. --- src/video/android/SDL_androidgl.c | 95 ++------ src/video/android/SDL_androidvideo.c | 4 +- src/video/android/egl.h | 330 --------------------------- src/video/android/eglext.h | 162 ------------- src/video/android/eglplatform.h | 118 ---------- 5 files changed, 18 insertions(+), 691 deletions(-) delete mode 100644 src/video/android/egl.h delete mode 100644 src/video/android/eglext.h delete mode 100644 src/video/android/eglplatform.h diff --git a/src/video/android/SDL_androidgl.c b/src/video/android/SDL_androidgl.c index bfbdab223..9f8712e86 100644 --- a/src/video/android/SDL_androidgl.c +++ b/src/video/android/SDL_androidgl.c @@ -34,125 +34,62 @@ #include "SDL_androidevents.h" #include "SDL_androidrender.h" -/* Android header */ -#include "egl.h" - - -//EGL globals -static EGLDisplay iEglDisplay; -static EGLConfig iEglConfig; -static EGLContext iEglContext; -static EGLSurface iEglSurface; - -EGLint attribList [] = -{ - EGL_BUFFER_SIZE, 16, //16 bit color - EGL_DEPTH_SIZE, 15, - EGL_NONE -}; +#include +/* +These things are in the JNI android support +*/ + /* GL functions */ int Android_GL_LoadLibrary(_THIS, const char *path){ - printf("[STUB] GL_LoadLibrary\n"); + __android_log_print(ANDROID_LOG_INFO, "SDL", "[STUB] GL_LoadLibrary\n"); return 0; } void *Android_GL_GetProcAddress(_THIS, const char *proc){ - printf("[STUB] GL_GetProcAddress\n"); + __android_log_print(ANDROID_LOG_INFO, "SDL", "[STUB] GL_GetProcAddress\n"); return 0; } void Android_GL_UnloadLibrary(_THIS){ - printf("[STUB] GL_UnloadLibrary\n"); + __android_log_print(ANDROID_LOG_INFO, "SDL", "[STUB] GL_UnloadLibrary\n"); } /* int *Android_GL_GetVisual(_THIS, Display * display, int screen){ - printf("[STUB] GL_GetVisual\n"); + __android_log_print(ANDROID_LOG_INFO, "SDL","[STUB] GL_GetVisual\n"); return 0; } */ SDL_GLContext Android_GL_CreateContext(_THIS, SDL_Window * window){ - printf("[STUB] GL_CreateContext\n"); - - //Start up the display - iEglDisplay = eglGetDisplay (EGL_DEFAULT_DISPLAY); - if(iEglDisplay == EGL_NO_DISPLAY){ - printf("Unable to find a suitable EGLDisplay\n"); - return NULL; - } - - printf("1\n"); - - if(!eglInitialize(iEglDisplay, 0, 0)){ - printf("Couldn't init display\n"); - return NULL; - } - - printf("2\n"); - - EGLint numConfigs; - - if(!eglChooseConfig(iEglDisplay, attribList, &iEglConfig, 1, &numConfigs)){ - printf("Couldn't choose config\n"); - return NULL; - } - - printf("3\n"); - - iEglContext = eglCreateContext(iEglDisplay, iEglConfig, EGL_NO_CONTEXT, 0); - - if(iEglContext == 0){ - printf("Couldn't create context\n"); - return NULL; - } - - printf("4\n"); - - NativeWindowType iWindow = 1; //android_createDisplaySurface(); - - iEglSurface = eglCreateWindowSurface(iEglDisplay, iEglConfig, iWindow, 0); - - printf("5\n"); - - if(iEglSurface == NULL){ - printf("Couldn't create surface\n"); - return NULL; - } - - printf("6\n"); - - eglMakeCurrent(iEglDisplay, iEglSurface, iEglSurface, iEglContext); - - printf("fininshed making context\n"); - - return iEglSurface; + __android_log_print(ANDROID_LOG_INFO, "SDL", "[STUB] GL_CreateContext\n"); + return NULL; } int Android_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context){ - printf("[STUB] GL_MakeCurrent\n"); + __android_log_print(ANDROID_LOG_INFO, "SDL", "[STUB] GL_MakeCurrent\n"); return 0; } int Android_GL_SetSwapInterval(_THIS, int interval){ - printf("[STUB] GL_SetSwapInterval\n"); + __android_log_print(ANDROID_LOG_INFO, "SDL", "[STUB] GL_SetSwapInterval\n"); return 0; } int Android_GL_GetSwapInterval(_THIS){ - printf("[STUB] GL_GetSwapInterval\n"); + __android_log_print(ANDROID_LOG_INFO, "SDL", "[STUB] GL_GetSwapInterval\n"); return 0; } void Android_GL_SwapWindow(_THIS, SDL_Window * window){ - printf("[STUB] GL_SwapWindow\n"); + __android_log_print(ANDROID_LOG_INFO, "SDL", "[STUB] GL_SwapWindow\n"); } void Android_GL_DeleteContext(_THIS, SDL_GLContext context){ - printf("[STUB] GL_DeleteContext\n"); + __android_log_print(ANDROID_LOG_INFO, "SDL", "[STUB] GL_DeleteContext\n"); } diff --git a/src/video/android/SDL_androidvideo.c b/src/video/android/SDL_androidvideo.c index 14c762eab..5b43d66c6 100644 --- a/src/video/android/SDL_androidvideo.c +++ b/src/video/android/SDL_androidvideo.c @@ -120,8 +120,8 @@ Android_VideoInit(_THIS) /* Use a fake 32-bpp desktop mode */ mode.format = SDL_PIXELFORMAT_RGB888; - mode.w = 1024; - mode.h = 768; + mode.w = 320; + mode.h = 480; mode.refresh_rate = 0; mode.driverdata = NULL; if (SDL_AddBasicVideoDisplay(&mode) < 0) { diff --git a/src/video/android/egl.h b/src/video/android/egl.h deleted file mode 100644 index a75cfb63f..000000000 --- a/src/video/android/egl.h +++ /dev/null @@ -1,330 +0,0 @@ -/* -*- mode: c; tab-width: 8; -*- */ -/* vi: set sw=4 ts=8: */ -/* Reference version of egl.h for EGL 1.4. - * $Revision: 7244 $ on $Date: 2009-01-20 17:06:59 -0800 (Tue, 20 Jan 2009) $ - */ - -/* -** Copyright (c) 2007-2009 The Khronos Group Inc. -** -** Permission is hereby granted, free of charge, to any person obtaining a -** copy of this software and/or associated documentation files (the -** "Materials"), to deal in the Materials without restriction, including -** without limitation the rights to use, copy, modify, merge, publish, -** distribute, sublicense, and/or sell copies of the Materials, and to -** permit persons to whom the Materials are furnished to do so, subject to -** the following conditions: -** -** The above copyright notice and this permission notice shall be included -** in all copies or substantial portions of the Materials. -** -** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. -*/ - -#ifndef __egl_h_ -#define __egl_h_ - -/* All platform-dependent types and macro boilerplate (such as EGLAPI - * and EGLAPIENTRY) should go in eglplatform.h. - */ -#include "eglplatform.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* EGL Types */ -/* EGLint is defined in eglplatform.h */ -typedef unsigned int EGLBoolean; -typedef unsigned int EGLenum; -typedef void *EGLConfig; -typedef void *EGLContext; -typedef void *EGLDisplay; -typedef void *EGLSurface; -typedef void *EGLClientBuffer; - -/* EGL Versioning */ -#define EGL_VERSION_1_0 1 -#define EGL_VERSION_1_1 1 -#define EGL_VERSION_1_2 1 -#define EGL_VERSION_1_3 1 -#define EGL_VERSION_1_4 1 - -/* EGL Enumerants. Bitmasks and other exceptional cases aside, most - * enums are assigned unique values starting at 0x3000. - */ - -/* EGL aliases */ -#define EGL_FALSE 0 -#define EGL_TRUE 1 - -/* Out-of-band handle values */ -#define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType)0) -#define EGL_NO_CONTEXT ((EGLContext)0) -#define EGL_NO_DISPLAY ((EGLDisplay)0) -#define EGL_NO_SURFACE ((EGLSurface)0) - -/* Out-of-band attribute value */ -#define EGL_DONT_CARE ((EGLint)-1) - -/* Errors / GetError return values */ -#define EGL_SUCCESS 0x3000 -#define EGL_NOT_INITIALIZED 0x3001 -#define EGL_BAD_ACCESS 0x3002 -#define EGL_BAD_ALLOC 0x3003 -#define EGL_BAD_ATTRIBUTE 0x3004 -#define EGL_BAD_CONFIG 0x3005 -#define EGL_BAD_CONTEXT 0x3006 -#define EGL_BAD_CURRENT_SURFACE 0x3007 -#define EGL_BAD_DISPLAY 0x3008 -#define EGL_BAD_MATCH 0x3009 -#define EGL_BAD_NATIVE_PIXMAP 0x300A -#define EGL_BAD_NATIVE_WINDOW 0x300B -#define EGL_BAD_PARAMETER 0x300C -#define EGL_BAD_SURFACE 0x300D -#define EGL_CONTEXT_LOST 0x300E /* EGL 1.1 - IMG_power_management */ - -/* Reserved 0x300F-0x301F for additional errors */ - -/* Config attributes */ -#define EGL_BUFFER_SIZE 0x3020 -#define EGL_ALPHA_SIZE 0x3021 -#define EGL_BLUE_SIZE 0x3022 -#define EGL_GREEN_SIZE 0x3023 -#define EGL_RED_SIZE 0x3024 -#define EGL_DEPTH_SIZE 0x3025 -#define EGL_STENCIL_SIZE 0x3026 -#define EGL_CONFIG_CAVEAT 0x3027 -#define EGL_CONFIG_ID 0x3028 -#define EGL_LEVEL 0x3029 -#define EGL_MAX_PBUFFER_HEIGHT 0x302A -#define EGL_MAX_PBUFFER_PIXELS 0x302B -#define EGL_MAX_PBUFFER_WIDTH 0x302C -#define EGL_NATIVE_RENDERABLE 0x302D -#define EGL_NATIVE_VISUAL_ID 0x302E -#define EGL_NATIVE_VISUAL_TYPE 0x302F -#define EGL_PRESERVED_RESOURCES 0x3030 -#define EGL_SAMPLES 0x3031 -#define EGL_SAMPLE_BUFFERS 0x3032 -#define EGL_SURFACE_TYPE 0x3033 -#define EGL_TRANSPARENT_TYPE 0x3034 -#define EGL_TRANSPARENT_BLUE_VALUE 0x3035 -#define EGL_TRANSPARENT_GREEN_VALUE 0x3036 -#define EGL_TRANSPARENT_RED_VALUE 0x3037 -#define EGL_NONE 0x3038 /* Attrib list terminator */ -#define EGL_BIND_TO_TEXTURE_RGB 0x3039 -#define EGL_BIND_TO_TEXTURE_RGBA 0x303A -#define EGL_MIN_SWAP_INTERVAL 0x303B -#define EGL_MAX_SWAP_INTERVAL 0x303C -#define EGL_LUMINANCE_SIZE 0x303D -#define EGL_ALPHA_MASK_SIZE 0x303E -#define EGL_COLOR_BUFFER_TYPE 0x303F -#define EGL_RENDERABLE_TYPE 0x3040 -#define EGL_MATCH_NATIVE_PIXMAP 0x3041 /* Pseudo-attribute (not queryable) */ -#define EGL_CONFORMANT 0x3042 - -/* Reserved 0x3041-0x304F for additional config attributes */ - -/* Config attribute values */ -#define EGL_SLOW_CONFIG 0x3050 /* EGL_CONFIG_CAVEAT value */ -#define EGL_NON_CONFORMANT_CONFIG 0x3051 /* EGL_CONFIG_CAVEAT value */ -#define EGL_TRANSPARENT_RGB 0x3052 /* EGL_TRANSPARENT_TYPE value */ -#define EGL_RGB_BUFFER 0x308E /* EGL_COLOR_BUFFER_TYPE value */ -#define EGL_LUMINANCE_BUFFER 0x308F /* EGL_COLOR_BUFFER_TYPE value */ - -/* More config attribute values, for EGL_TEXTURE_FORMAT */ -#define EGL_NO_TEXTURE 0x305C -#define EGL_TEXTURE_RGB 0x305D -#define EGL_TEXTURE_RGBA 0x305E -#define EGL_TEXTURE_2D 0x305F - -/* Config attribute mask bits */ -#define EGL_PBUFFER_BIT 0x0001 /* EGL_SURFACE_TYPE mask bits */ -#define EGL_PIXMAP_BIT 0x0002 /* EGL_SURFACE_TYPE mask bits */ -#define EGL_WINDOW_BIT 0x0004 /* EGL_SURFACE_TYPE mask bits */ -#define EGL_VG_COLORSPACE_LINEAR_BIT 0x0020 /* EGL_SURFACE_TYPE mask bits */ -#define EGL_VG_ALPHA_FORMAT_PRE_BIT 0x0040 /* EGL_SURFACE_TYPE mask bits */ -#define EGL_MULTISAMPLE_RESOLVE_BOX_BIT 0x0200 /* EGL_SURFACE_TYPE mask bits */ -#define EGL_SWAP_BEHAVIOR_PRESERVED_BIT 0x0400 /* EGL_SURFACE_TYPE mask bits */ - -#define EGL_OPENGL_ES_BIT 0x0001 /* EGL_RENDERABLE_TYPE mask bits */ -#define EGL_OPENVG_BIT 0x0002 /* EGL_RENDERABLE_TYPE mask bits */ -#define EGL_OPENGL_ES2_BIT 0x0004 /* EGL_RENDERABLE_TYPE mask bits */ -#define EGL_OPENGL_BIT 0x0008 /* EGL_RENDERABLE_TYPE mask bits */ - -/* QueryString targets */ -#define EGL_VENDOR 0x3053 -#define EGL_VERSION 0x3054 -#define EGL_EXTENSIONS 0x3055 -#define EGL_CLIENT_APIS 0x308D - -/* QuerySurface / SurfaceAttrib / CreatePbufferSurface targets */ -#define EGL_HEIGHT 0x3056 -#define EGL_WIDTH 0x3057 -#define EGL_LARGEST_PBUFFER 0x3058 -#define EGL_TEXTURE_FORMAT 0x3080 -#define EGL_TEXTURE_TARGET 0x3081 -#define EGL_MIPMAP_TEXTURE 0x3082 -#define EGL_MIPMAP_LEVEL 0x3083 -#define EGL_RENDER_BUFFER 0x3086 -#define EGL_VG_COLORSPACE 0x3087 -#define EGL_VG_ALPHA_FORMAT 0x3088 -#define EGL_HORIZONTAL_RESOLUTION 0x3090 -#define EGL_VERTICAL_RESOLUTION 0x3091 -#define EGL_PIXEL_ASPECT_RATIO 0x3092 -#define EGL_SWAP_BEHAVIOR 0x3093 -#define EGL_MULTISAMPLE_RESOLVE 0x3099 - -/* EGL_RENDER_BUFFER values / BindTexImage / ReleaseTexImage buffer targets */ -#define EGL_BACK_BUFFER 0x3084 -#define EGL_SINGLE_BUFFER 0x3085 - -/* OpenVG color spaces */ -#define EGL_VG_COLORSPACE_sRGB 0x3089 /* EGL_VG_COLORSPACE value */ -#define EGL_VG_COLORSPACE_LINEAR 0x308A /* EGL_VG_COLORSPACE value */ - -/* OpenVG alpha formats */ -#define EGL_VG_ALPHA_FORMAT_NONPRE 0x308B /* EGL_ALPHA_FORMAT value */ -#define EGL_VG_ALPHA_FORMAT_PRE 0x308C /* EGL_ALPHA_FORMAT value */ - -/* Constant scale factor by which fractional display resolutions & - * aspect ratio are scaled when queried as integer values. - */ -#define EGL_DISPLAY_SCALING 10000 - -/* Unknown display resolution/aspect ratio */ -#define EGL_UNKNOWN ((EGLint)-1) - -/* Back buffer swap behaviors */ -#define EGL_BUFFER_PRESERVED 0x3094 /* EGL_SWAP_BEHAVIOR value */ -#define EGL_BUFFER_DESTROYED 0x3095 /* EGL_SWAP_BEHAVIOR value */ - -/* CreatePbufferFromClientBuffer buffer types */ -#define EGL_OPENVG_IMAGE 0x3096 - -/* QueryContext targets */ -#define EGL_CONTEXT_CLIENT_TYPE 0x3097 - -/* CreateContext attributes */ -#define EGL_CONTEXT_CLIENT_VERSION 0x3098 - -/* Multisample resolution behaviors */ -#define EGL_MULTISAMPLE_RESOLVE_DEFAULT 0x309A /* EGL_MULTISAMPLE_RESOLVE value */ -#define EGL_MULTISAMPLE_RESOLVE_BOX 0x309B /* EGL_MULTISAMPLE_RESOLVE value */ - -/* BindAPI/QueryAPI targets */ -#define EGL_OPENGL_ES_API 0x30A0 -#define EGL_OPENVG_API 0x30A1 -#define EGL_OPENGL_API 0x30A2 - -/* GetCurrentSurface targets */ -#define EGL_DRAW 0x3059 -#define EGL_READ 0x305A - -/* WaitNative engines */ -#define EGL_CORE_NATIVE_ENGINE 0x305B - -/* EGL 1.2 tokens renamed for consistency in EGL 1.3 */ -#define EGL_COLORSPACE EGL_VG_COLORSPACE -#define EGL_ALPHA_FORMAT EGL_VG_ALPHA_FORMAT -#define EGL_COLORSPACE_sRGB EGL_VG_COLORSPACE_sRGB -#define EGL_COLORSPACE_LINEAR EGL_VG_COLORSPACE_LINEAR -#define EGL_ALPHA_FORMAT_NONPRE EGL_VG_ALPHA_FORMAT_NONPRE -#define EGL_ALPHA_FORMAT_PRE EGL_VG_ALPHA_FORMAT_PRE - -/* EGL extensions must request enum blocks from the Khronos - * API Registrar, who maintains the enumerant registry. Submit - * a bug in Khronos Bugzilla against task "Registry". - */ - - - -/* EGL Functions */ - -EGLAPI EGLint EGLAPIENTRY eglGetError(void); - -EGLAPI EGLDisplay EGLAPIENTRY eglGetDisplay(EGLNativeDisplayType display_id); -EGLAPI EGLBoolean EGLAPIENTRY eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor); -EGLAPI EGLBoolean EGLAPIENTRY eglTerminate(EGLDisplay dpy); - -EGLAPI const char * EGLAPIENTRY eglQueryString(EGLDisplay dpy, EGLint name); - -EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, - EGLint config_size, EGLint *num_config); -EGLAPI EGLBoolean EGLAPIENTRY eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, - EGLConfig *configs, EGLint config_size, - EGLint *num_config); -EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, - EGLint attribute, EGLint *value); - -EGLAPI EGLSurface EGLAPIENTRY eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, - EGLNativeWindowType win, - const EGLint *attrib_list); -EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, - const EGLint *attrib_list); -EGLAPI EGLSurface EGLAPIENTRY eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, - EGLNativePixmapType pixmap, - const EGLint *attrib_list); -EGLAPI EGLBoolean EGLAPIENTRY eglDestroySurface(EGLDisplay dpy, EGLSurface surface); -EGLAPI EGLBoolean EGLAPIENTRY eglQuerySurface(EGLDisplay dpy, EGLSurface surface, - EGLint attribute, EGLint *value); - -EGLAPI EGLBoolean EGLAPIENTRY eglBindAPI(EGLenum api); -EGLAPI EGLenum EGLAPIENTRY eglQueryAPI(void); - -EGLAPI EGLBoolean EGLAPIENTRY eglWaitClient(void); - -EGLAPI EGLBoolean EGLAPIENTRY eglReleaseThread(void); - -EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferFromClientBuffer( - EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, - EGLConfig config, const EGLint *attrib_list); - -EGLAPI EGLBoolean EGLAPIENTRY eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface, - EGLint attribute, EGLint value); -EGLAPI EGLBoolean EGLAPIENTRY eglBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer); -EGLAPI EGLBoolean EGLAPIENTRY eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer); - - -EGLAPI EGLBoolean EGLAPIENTRY eglSwapInterval(EGLDisplay dpy, EGLint interval); - - -EGLAPI EGLContext EGLAPIENTRY eglCreateContext(EGLDisplay dpy, EGLConfig config, - EGLContext share_context, - const EGLint *attrib_list); -EGLAPI EGLBoolean EGLAPIENTRY eglDestroyContext(EGLDisplay dpy, EGLContext ctx); -EGLAPI EGLBoolean EGLAPIENTRY eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, - EGLSurface read, EGLContext ctx); - -EGLAPI EGLContext EGLAPIENTRY eglGetCurrentContext(void); -EGLAPI EGLSurface EGLAPIENTRY eglGetCurrentSurface(EGLint readdraw); -EGLAPI EGLDisplay EGLAPIENTRY eglGetCurrentDisplay(void); -EGLAPI EGLBoolean EGLAPIENTRY eglQueryContext(EGLDisplay dpy, EGLContext ctx, - EGLint attribute, EGLint *value); - -EGLAPI EGLBoolean EGLAPIENTRY eglWaitGL(void); -EGLAPI EGLBoolean EGLAPIENTRY eglWaitNative(EGLint engine); -EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffers(EGLDisplay dpy, EGLSurface surface); -EGLAPI EGLBoolean EGLAPIENTRY eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, - EGLNativePixmapType target); - -/* This is a generic function pointer type, whose name indicates it must - * be cast to the proper type *and calling convention* before use. - */ -typedef void (*__eglMustCastToProperFunctionPointerType)(void); - -/* Now, define eglGetProcAddress using the generic function ptr. type */ -EGLAPI __eglMustCastToProperFunctionPointerType EGLAPIENTRY - eglGetProcAddress(const char *procname); - -#ifdef __cplusplus -} -#endif - -#endif /* __egl_h_ */ diff --git a/src/video/android/eglext.h b/src/video/android/eglext.h deleted file mode 100644 index 545fd0e98..000000000 --- a/src/video/android/eglext.h +++ /dev/null @@ -1,162 +0,0 @@ -#ifndef __eglext_h_ -#define __eglext_h_ - -#ifdef __cplusplus -extern "C" { -#endif - -/* -** Copyright (c) 2007-2009 The Khronos Group Inc. -** -** Permission is hereby granted, free of charge, to any person obtaining a -** copy of this software and/or associated documentation files (the -** "Materials"), to deal in the Materials without restriction, including -** without limitation the rights to use, copy, modify, merge, publish, -** distribute, sublicense, and/or sell copies of the Materials, and to -** permit persons to whom the Materials are furnished to do so, subject to -** the following conditions: -** -** The above copyright notice and this permission notice shall be included -** in all copies or substantial portions of the Materials. -** -** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. -*/ - -#include - -/*************************************************************/ - -/* Header file version number */ -/* Current version at http://www.khronos.org/registry/egl/ */ -/* $Revision: 7244 $ on $Date: 2009-01-20 17:06:59 -0800 (Tue, 20 Jan 2009) $ */ -#define EGL_EGLEXT_VERSION 3 - -#ifndef EGL_KHR_config_attribs -#define EGL_KHR_config_attribs 1 -#define EGL_CONFORMANT_KHR 0x3042 /* EGLConfig attribute */ -#define EGL_VG_COLORSPACE_LINEAR_BIT_KHR 0x0020 /* EGL_SURFACE_TYPE bitfield */ -#define EGL_VG_ALPHA_FORMAT_PRE_BIT_KHR 0x0040 /* EGL_SURFACE_TYPE bitfield */ -#endif - -#ifndef EGL_KHR_lock_surface -#define EGL_KHR_lock_surface 1 -#define EGL_READ_SURFACE_BIT_KHR 0x0001 /* EGL_LOCK_USAGE_HINT_KHR bitfield */ -#define EGL_WRITE_SURFACE_BIT_KHR 0x0002 /* EGL_LOCK_USAGE_HINT_KHR bitfield */ -#define EGL_LOCK_SURFACE_BIT_KHR 0x0080 /* EGL_SURFACE_TYPE bitfield */ -#define EGL_OPTIMAL_FORMAT_BIT_KHR 0x0100 /* EGL_SURFACE_TYPE bitfield */ -#define EGL_MATCH_FORMAT_KHR 0x3043 /* EGLConfig attribute */ -#define EGL_FORMAT_RGB_565_EXACT_KHR 0x30C0 /* EGL_MATCH_FORMAT_KHR value */ -#define EGL_FORMAT_RGB_565_KHR 0x30C1 /* EGL_MATCH_FORMAT_KHR value */ -#define EGL_FORMAT_RGBA_8888_EXACT_KHR 0x30C2 /* EGL_MATCH_FORMAT_KHR value */ -#define EGL_FORMAT_RGBA_8888_KHR 0x30C3 /* EGL_MATCH_FORMAT_KHR value */ -#define EGL_MAP_PRESERVE_PIXELS_KHR 0x30C4 /* eglLockSurfaceKHR attribute */ -#define EGL_LOCK_USAGE_HINT_KHR 0x30C5 /* eglLockSurfaceKHR attribute */ -#define EGL_BITMAP_POINTER_KHR 0x30C6 /* eglQuerySurface attribute */ -#define EGL_BITMAP_PITCH_KHR 0x30C7 /* eglQuerySurface attribute */ -#define EGL_BITMAP_ORIGIN_KHR 0x30C8 /* eglQuerySurface attribute */ -#define EGL_BITMAP_PIXEL_RED_OFFSET_KHR 0x30C9 /* eglQuerySurface attribute */ -#define EGL_BITMAP_PIXEL_GREEN_OFFSET_KHR 0x30CA /* eglQuerySurface attribute */ -#define EGL_BITMAP_PIXEL_BLUE_OFFSET_KHR 0x30CB /* eglQuerySurface attribute */ -#define EGL_BITMAP_PIXEL_ALPHA_OFFSET_KHR 0x30CC /* eglQuerySurface attribute */ -#define EGL_BITMAP_PIXEL_LUMINANCE_OFFSET_KHR 0x30CD /* eglQuerySurface attribute */ -#define EGL_LOWER_LEFT_KHR 0x30CE /* EGL_BITMAP_ORIGIN_KHR value */ -#define EGL_UPPER_LEFT_KHR 0x30CF /* EGL_BITMAP_ORIGIN_KHR value */ -#ifdef EGL_EGLEXT_PROTOTYPES -EGLAPI EGLBoolean EGLAPIENTRY eglLockSurfaceKHR (EGLDisplay display, EGLSurface surface, const EGLint *attrib_list); -EGLAPI EGLBoolean EGLAPIENTRY eglUnlockSurfaceKHR (EGLDisplay display, EGLSurface surface); -#endif /* EGL_EGLEXT_PROTOTYPES */ -typedef EGLBoolean (EGLAPIENTRYP PFNEGLLOCKSURFACEKHRPROC) (EGLDisplay display, EGLSurface surface, const EGLint *attrib_list); -typedef EGLBoolean (EGLAPIENTRYP PFNEGLUNLOCKSURFACEKHRPROC) (EGLDisplay display, EGLSurface surface); -#endif - -#ifndef EGL_KHR_image -#define EGL_KHR_image 1 -#define EGL_NATIVE_PIXMAP_KHR 0x30B0 /* eglCreateImageKHR target */ -typedef void *EGLImageKHR; -#define EGL_NO_IMAGE_KHR ((EGLImageKHR)0) -#ifdef EGL_EGLEXT_PROTOTYPES -EGLAPI EGLImageKHR EGLAPIENTRY eglCreateImageKHR (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list); -EGLAPI EGLBoolean EGLAPIENTRY eglDestroyImageKHR (EGLDisplay dpy, EGLImageKHR image); -#endif /* EGL_EGLEXT_PROTOTYPES */ -typedef EGLImageKHR (EGLAPIENTRYP PFNEGLCREATEIMAGEKHRPROC) (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list); -typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYIMAGEKHRPROC) (EGLDisplay dpy, EGLImageKHR image); -#endif - -#ifndef EGL_KHR_vg_parent_image -#define EGL_KHR_vg_parent_image 1 -#define EGL_VG_PARENT_IMAGE_KHR 0x30BA /* eglCreateImageKHR target */ -#endif - -#ifndef EGL_KHR_gl_texture_2D_image -#define EGL_KHR_gl_texture_2D_image 1 -#define EGL_GL_TEXTURE_2D_KHR 0x30B1 /* eglCreateImageKHR target */ -#define EGL_GL_TEXTURE_LEVEL_KHR 0x30BC /* eglCreateImageKHR attribute */ -#endif - -#ifndef EGL_KHR_gl_texture_cubemap_image -#define EGL_KHR_gl_texture_cubemap_image 1 -#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR 0x30B3 /* eglCreateImageKHR target */ -#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR 0x30B4 /* eglCreateImageKHR target */ -#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR 0x30B5 /* eglCreateImageKHR target */ -#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR 0x30B6 /* eglCreateImageKHR target */ -#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR 0x30B7 /* eglCreateImageKHR target */ -#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR 0x30B8 /* eglCreateImageKHR target */ -#endif - -#ifndef EGL_KHR_gl_texture_3D_image -#define EGL_KHR_gl_texture_3D_image 1 -#define EGL_GL_TEXTURE_3D_KHR 0x30B2 /* eglCreateImageKHR target */ -#define EGL_GL_TEXTURE_ZOFFSET_KHR 0x30BD /* eglCreateImageKHR attribute */ -#endif - -#ifndef EGL_KHR_gl_renderbuffer_image -#define EGL_KHR_gl_renderbuffer_image 1 -#define EGL_GL_RENDERBUFFER_KHR 0x30B9 /* eglCreateImageKHR target */ -#endif - -#ifndef EGL_KHR_image_base -#define EGL_KHR_image_base 1 -/* Most interfaces defined by EGL_KHR_image_pixmap above */ -#define EGL_IMAGE_PRESERVED_KHR 0x30D2 /* eglCreateImageKHR attribute */ -#endif - -#ifndef EGL_KHR_image_pixmap -#define EGL_KHR_image_pixmap 1 -/* Interfaces defined by EGL_KHR_image above */ -#endif - - -#ifndef EGL_ANDROID_image_native_buffer -#define EGL_ANDROID_image_native_buffer 1 -struct android_native_buffer_t; -#define EGL_NATIVE_BUFFER_ANDROID 0x3140 /* eglCreateImageKHR target */ -#endif - -#ifndef EGL_ANDROID_get_render_buffer -#define EGL_ANDROID_get_render_buffer 1 -#ifdef EGL_EGLEXT_PROTOTYPES -EGLAPI EGLClientBuffer EGLAPIENTRY eglGetRenderBufferANDROID(EGLDisplay dpy, EGLSurface draw); -#endif -typedef EGLClientBuffer (EGLAPIENTRYP PFNEGLGETRENDERBUFFERANDROIDPROC) (EGLDisplay dpy, EGLSurface draw); -#endif - -#ifndef EGL_ANDROID_swap_rectangle -#define EGL_ANDROID_swap_rectangle 1 -#ifdef EGL_EGLEXT_PROTOTYPES -EGLAPI EGLBoolean EGLAPIENTRY eglSetSwapRectangleANDROID (EGLDisplay dpy, EGLSurface draw, EGLint left, EGLint top, EGLint width, EGLint height); -#endif /* EGL_EGLEXT_PROTOTYPES */ -typedef EGLBoolean (EGLAPIENTRYP PFNEGLSETSWAPRECTANGLEANDROIDPROC) (EGLDisplay dpy, EGLSurface draw, EGLint left, EGLint top, EGLint width, EGLint height); -#endif - - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/video/android/eglplatform.h b/src/video/android/eglplatform.h deleted file mode 100644 index 53e9e6116..000000000 --- a/src/video/android/eglplatform.h +++ /dev/null @@ -1,118 +0,0 @@ -#ifndef __eglplatform_h_ -#define __eglplatform_h_ - -/* -** Copyright (c) 2007-2009 The Khronos Group Inc. -** -** Permission is hereby granted, free of charge, to any person obtaining a -** copy of this software and/or associated documentation files (the -** "Materials"), to deal in the Materials without restriction, including -** without limitation the rights to use, copy, modify, merge, publish, -** distribute, sublicense, and/or sell copies of the Materials, and to -** permit persons to whom the Materials are furnished to do so, subject to -** the following conditions: -** -** The above copyright notice and this permission notice shall be included -** in all copies or substantial portions of the Materials. -** -** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. -*/ - -/* Platform-specific types and definitions for egl.h - * $Revision: 7244 $ on $Date: 2009-01-20 17:06:59 -0800 (Tue, 20 Jan 2009) $ - * - * Adopters may modify khrplatform.h and this file to suit their platform. - * You are encouraged to submit all modifications to the Khronos group so that - * they can be included in future versions of this file. Please submit changes - * by sending them to the public Khronos Bugzilla (http://khronos.org/bugzilla) - * by filing a bug against product "EGL" component "Registry". - */ - -#include - -/* Macros used in EGL function prototype declarations. - * - * EGL functions should be prototyped as: - * - * EGLAPI return-type EGLAPIENTRY eglFunction(arguments); - * typedef return-type (EXPAPIENTRYP PFNEGLFUNCTIONPROC) (arguments); - * - * KHRONOS_APICALL and KHRONOS_APIENTRY are defined in KHR/khrplatform.h - */ - -#ifndef EGLAPI -#define EGLAPI KHRONOS_APICALL -#endif - -#define EGLAPIENTRY KHRONOS_APIENTRY -#define EGLAPIENTRYP KHRONOS_APIENTRY* - -/* The types NativeDisplayType, NativeWindowType, and NativePixmapType - * are aliases of window-system-dependent types, such as X Display * or - * Windows Device Context. They must be defined in platform-specific - * code below. The EGL-prefixed versions of Native*Type are the same - * types, renamed in EGL 1.3 so all types in the API start with "EGL". - */ - -#if defined(_WIN32) || defined(__VC32__) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) /* Win32 and WinCE */ -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN 1 -#endif -#include - -typedef HDC EGLNativeDisplayType; -typedef HBITMAP EGLNativePixmapType; -typedef HWND EGLNativeWindowType; - -#elif defined(__WINSCW__) || defined(__SYMBIAN32__) /* Symbian */ - -typedef int EGLNativeDisplayType; -typedef void *EGLNativeWindowType; -typedef void *EGLNativePixmapType; - -#elif defined(__unix__) && !defined(ANDROID) - -/* X11 (tentative) */ -#include -#include - -typedef Display *EGLNativeDisplayType; -typedef Pixmap EGLNativePixmapType; -typedef Window EGLNativeWindowType; - - -#elif defined(ANDROID) - -struct android_native_window_t; -struct egl_native_pixmap_t; - -typedef struct android_native_window_t* EGLNativeWindowType; -typedef struct egl_native_pixmap_t* EGLNativePixmapType; -typedef void* EGLNativeDisplayType; - -#else -#error "Platform not recognized" -#endif - -/* EGL 1.2 types, renamed for consistency in EGL 1.3 */ -typedef EGLNativeDisplayType NativeDisplayType; -typedef EGLNativePixmapType NativePixmapType; -typedef EGLNativeWindowType NativeWindowType; - - -/* Define EGLint. This must be a signed integral type large enough to contain - * all legal attribute names and values passed into and out of EGL, whether - * their type is boolean, bitmask, enumerant (symbolic constant), integer, - * handle, or other. While in general a 32-bit integer will suffice, if - * handles are 64 bit types, then EGLint should be defined as a signed 64-bit - * integer type. - */ -typedef khronos_int32_t EGLint; - -#endif /* __eglplatform_h */ From 3cb853904eb1ac3bb038e3d86182dea968742fb5 Mon Sep 17 00:00:00 2001 From: Paul Hunkin Date: Fri, 18 Jun 2010 01:28:39 +1200 Subject: [PATCH 14/34] Added egl headers so we can use eglMakeCurrent() --- android/testproject/jni/Android.mk | 8 +- android/testproject/jni/app-android.c | 42 ++- android/testproject/jni/egl.h | 269 +++++++++++++++ android/testproject/jni/eglnatives.h | 277 +++++++++++++++ android/testproject/jni/egltypes.h | 48 +++ android/testproject/jni/lesson05.c | 469 ++++++++++++++++++++++++++ 6 files changed, 1109 insertions(+), 4 deletions(-) create mode 100644 android/testproject/jni/egl.h create mode 100644 android/testproject/jni/eglnatives.h create mode 100644 android/testproject/jni/egltypes.h create mode 100644 android/testproject/jni/lesson05.c diff --git a/android/testproject/jni/Android.mk b/android/testproject/jni/Android.mk index 77dfca416..3f3f20250 100644 --- a/android/testproject/jni/Android.mk +++ b/android/testproject/jni/Android.mk @@ -4,13 +4,17 @@ include $(CLEAR_VARS) LOCAL_MODULE := sanangeles +SDL := /home/paul/Projects/gsoc/SDL-gsoc2010_android/ + LOCAL_CFLAGS := -DANDROID_NDK \ - -DDISABLE_IMPORTGL + -DDISABLE_IMPORTGL \ + -I$(SDL)/include LOCAL_SRC_FILES := \ importgl.c \ app-android.c \ + lesson05.c \ -LOCAL_LDLIBS := -lGLESv1_CM -ldl -llog +LOCAL_LDLIBS := -lGLESv1_CM -ldl -llog -lSDL -lEGL -lgcc -L$(SDL) -L$(SDL)/build-scripts/android_libs/ include $(BUILD_SHARED_LIBRARY) diff --git a/android/testproject/jni/app-android.c b/android/testproject/jni/app-android.c index 4312242d1..e91329a81 100644 --- a/android/testproject/jni/app-android.c +++ b/android/testproject/jni/app-android.c @@ -14,6 +14,7 @@ #include #include "importgl.h" +#include "egl.h" /******************************************************************************* Globals @@ -31,7 +32,17 @@ static long _getTime(void){ } - +/******************************************************************************* + Things used by libsdl +*******************************************************************************/ +pthread_mutex_t mSDLRenderMutex; +pthread_cond_t mSDLRenderCondition; + +EGLContext mContext; +EGLDisplay mDisplay; +EGLSurface mRead; +EGLSurface mDraw; + /******************************************************************************* SDL thread *******************************************************************************/ @@ -39,7 +50,13 @@ pthread_t mSDLThread = 0; void* sdlThreadProc(void* args){ __android_log_print(ANDROID_LOG_INFO, "SDL", "Thread Entry"); - return 0; + + if(!eglMakeCurrent(mDisplay, mDraw, mRead, mContext)){ + __android_log_print(ANDROID_LOG_INFO, "SDL", "Couldn't make current: 0x%x", eglGetError()); + return NULL; + } + + return (void *)SDL_main(); } /******************************************************************************* @@ -54,6 +71,21 @@ void Java_org_libsdl_android_TestRenderer_nativeInit( JNIEnv* env ) __android_log_print(ANDROID_LOG_INFO, "SDL", "Entry point"); + pthread_mutex_init(&mSDLRenderMutex, NULL); + pthread_cond_init (&mSDLRenderCondition, NULL); + + //Get some egl stuff we need + mContext = eglGetCurrentContext(); + mDisplay = eglGetCurrentDisplay(); + mRead = eglGetCurrentSurface(EGL_READ); + mDraw = eglGetCurrentSurface(EGL_DRAW); + + //We need to abandon our context so SDL can have it + if(!eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)){ + __android_log_print(ANDROID_LOG_INFO, "SDL", "Couldn't abandon context: 0x%x", eglGetError()); + return NULL; + } + //Spin up the SDL thread int r = pthread_create(&mSDLThread, NULL, sdlThreadProc, NULL); @@ -115,4 +147,10 @@ void Java_org_libsdl_android_TestRenderer_nativeRender( JNIEnv* env ) { //TODO: Render here + pthread_mutex_lock(&mSDLRenderMutex); + pthread_cond_signal(&mSDLRenderCondition); //wake up the SDL thread + pthread_mutex_unlock(&mSDLRenderMutex); + + //__android_log_print(ANDROID_LOG_INFO, "SDL", "Unlocked"); + } diff --git a/android/testproject/jni/egl.h b/android/testproject/jni/egl.h new file mode 100644 index 000000000..3efa93cb7 --- /dev/null +++ b/android/testproject/jni/egl.h @@ -0,0 +1,269 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * 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 + * + * http://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. + */ + +#ifndef ANDROID_EGL_H +#define ANDROID_EGL_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define EGL_VERSION_1_0 1 +#define EGL_VERSION_1_1 1 +#define EGL_VERSION_1_2 1 + +#define EGL_FALSE 0 +#define EGL_TRUE 1 + +/* Errors */ +#define EGL_SUCCESS 0x3000 +#define EGL_NOT_INITIALIZED 0x3001 +#define EGL_BAD_ACCESS 0x3002 +#define EGL_BAD_ALLOC 0x3003 +#define EGL_BAD_ATTRIBUTE 0x3004 +#define EGL_BAD_CONFIG 0x3005 +#define EGL_BAD_CONTEXT 0x3006 +#define EGL_BAD_CURRENT_SURFACE 0x3007 +#define EGL_BAD_DISPLAY 0x3008 +#define EGL_BAD_MATCH 0x3009 +#define EGL_BAD_NATIVE_PIXMAP 0x300A +#define EGL_BAD_NATIVE_WINDOW 0x300B +#define EGL_BAD_PARAMETER 0x300C +#define EGL_BAD_SURFACE 0x300D +#define EGL_CONTEXT_LOST 0x300E + +/* Config attributes */ +#define EGL_BUFFER_SIZE 0x3020 +#define EGL_ALPHA_SIZE 0x3021 +#define EGL_BLUE_SIZE 0x3022 +#define EGL_GREEN_SIZE 0x3023 +#define EGL_RED_SIZE 0x3024 +#define EGL_DEPTH_SIZE 0x3025 +#define EGL_STENCIL_SIZE 0x3026 +#define EGL_CONFIG_CAVEAT 0x3027 +#define EGL_CONFIG_ID 0x3028 +#define EGL_LEVEL 0x3029 +#define EGL_MAX_PBUFFER_HEIGHT 0x302A +#define EGL_MAX_PBUFFER_PIXELS 0x302B +#define EGL_MAX_PBUFFER_WIDTH 0x302C +#define EGL_NATIVE_RENDERABLE 0x302D +#define EGL_NATIVE_VISUAL_ID 0x302E +#define EGL_NATIVE_VISUAL_TYPE 0x302F +#define EGL_SAMPLES 0x3031 +#define EGL_SAMPLE_BUFFERS 0x3032 +#define EGL_SURFACE_TYPE 0x3033 +#define EGL_TRANSPARENT_TYPE 0x3034 +#define EGL_TRANSPARENT_BLUE_VALUE 0x3035 +#define EGL_TRANSPARENT_GREEN_VALUE 0x3036 +#define EGL_TRANSPARENT_RED_VALUE 0x3037 +#define EGL_NONE 0x3038 +#define EGL_BIND_TO_TEXTURE_RGB 0x3039 +#define EGL_BIND_TO_TEXTURE_RGBA 0x303A +#define EGL_MIN_SWAP_INTERVAL 0x303B +#define EGL_MAX_SWAP_INTERVAL 0x303C +#define EGL_LUMINANCE_SIZE 0x303D +#define EGL_ALPHA_MASK_SIZE 0x303E +#define EGL_COLOR_BUFFER_TYPE 0x303F +#define EGL_RENDERABLE_TYPE 0x3040 + +/* Config values */ +#define EGL_DONT_CARE ((EGLint)-1) + +#define EGL_SLOW_CONFIG 0x3050 +#define EGL_NON_CONFORMANT_CONFIG 0x3051 +#define EGL_TRANSPARENT_RGB 0x3052 +#define EGL_NO_TEXTURE 0x305C +#define EGL_TEXTURE_RGB 0x305D +#define EGL_TEXTURE_RGBA 0x305E +#define EGL_TEXTURE_2D 0x305F +#define EGL_RGB_BUFFER 0x308E +#define EGL_LUMINANCE_BUFFER 0x308F + +/* Config attribute mask bits */ +#define EGL_PBUFFER_BIT 0x01 +#define EGL_PIXMAP_BIT 0x02 +#define EGL_WINDOW_BIT 0x04 +#define EGL_OPENGL_ES_BIT 0x01 +#define EGL_OPENVG_BIT 0x02 + +/* String names */ +#define EGL_VENDOR 0x3053 +#define EGL_VERSION 0x3054 +#define EGL_EXTENSIONS 0x3055 +#define EGL_CLIENT_APIS 0x308D + +/* Surface attributes */ +#define EGL_HEIGHT 0x3056 +#define EGL_WIDTH 0x3057 +#define EGL_LARGEST_PBUFFER 0x3058 +#define EGL_TEXTURE_FORMAT 0x3080 +#define EGL_TEXTURE_TARGET 0x3081 +#define EGL_MIPMAP_TEXTURE 0x3082 +#define EGL_MIPMAP_LEVEL 0x3083 +#define EGL_RENDER_BUFFER 0x3086 +#define EGL_COLORSPACE 0x3087 +#define EGL_ALPHA_FORMAT 0x3088 +#define EGL_HORIZONTAL_RESOLUTION 0x3090 +#define EGL_VERTICAL_RESOLUTION 0x3091 +#define EGL_PIXEL_ASPECT_RATIO 0x3092 +#define EGL_SWAP_BEHAVIOR 0x3093 + +#define EGL_BACK_BUFFER 0x3084 +#define EGL_SINGLE_BUFFER 0x3085 + +#define EGL_DISPLAY_SCALING 10000 + +#define EGL_UNKNOWN ((EGLint)-1) + +/* Back buffer swap behaviors */ +#define EGL_BUFFER_PRESERVED 0x3094 +#define EGL_BUFFER_DESTROYED 0x3095 + +/* CreatePbufferFromClientBuffer buffer types */ +#define EGL_OPENVG_IMAGE 0x3096 + +/* QueryContext targets */ +#define EGL_CONTEXT_CLIENT_TYPE 0x3097 + +/* BindAPI/QueryAPI targets */ +#define EGL_OPENGL_ES_API 0x30A0 +#define EGL_OPENVG_API 0x30A1 + +/* WaitNative engines */ +#define EGL_CORE_NATIVE_ENGINE 0x305B + +/* Current surfaces */ +#define EGL_DRAW 0x3059 +#define EGL_READ 0x305A + + +EGLDisplay eglGetDisplay(NativeDisplayType display); +EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor); +EGLBoolean eglTerminate(EGLDisplay dpy); + +EGLBoolean eglGetConfigs( EGLDisplay dpy, + EGLConfig *configs, + EGLint config_size, EGLint *num_config); + +EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list, + EGLConfig *configs, EGLint config_size, + EGLint *num_config); + +EGLBoolean eglGetConfigAttrib( EGLDisplay dpy, EGLConfig config, + EGLint attribute, EGLint *value); + +EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, + NativeWindowType window, + const EGLint *attrib_list); + +EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config, + NativePixmapType pixmap, + const EGLint *attrib_list); + +EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config, + const EGLint *attrib_list); + +EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface); + +EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface, + EGLint attribute, EGLint *value); + +EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, + EGLContext share_list, const EGLint *attrib_list); + +EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx); + +EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw, + EGLSurface read, EGLContext ctx); + +EGLContext eglGetCurrentContext(void); +EGLSurface eglGetCurrentSurface(EGLint readdraw); +EGLDisplay eglGetCurrentDisplay(void); +EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx, + EGLint attribute, EGLint *value); + +EGLBoolean eglWaitGL(void); +EGLBoolean eglWaitNative(EGLint engine); +EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw); +EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface, + NativePixmapType target); + +EGLint eglGetError(void); +const char* eglQueryString(EGLDisplay dpy, EGLint name); +void (*eglGetProcAddress (const char *procname))(); + +/* ---------------------------------------------------------------------------- + * EGL 1.1 + * ---------------------------------------------------------------------------- + */ + +EGLBoolean eglSurfaceAttrib( + EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value); +EGLBoolean eglBindTexImage( + EGLDisplay dpy, EGLSurface surface, EGLint buffer); +EGLBoolean eglReleaseTexImage( + EGLDisplay dpy, EGLSurface surface, EGLint buffer); + +EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval); + +/* ---------------------------------------------------------------------------- + * EGL 1.2 + * ---------------------------------------------------------------------------- + */ + +EGLBoolean eglBindAPI(EGLenum api); +EGLenum eglQueryAPI(void); +EGLBoolean eglWaitClient(void); +EGLBoolean eglReleaseThread(void); +EGLSurface eglCreatePbufferFromClientBuffer( + EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, + EGLConfig config, const EGLint *attrib_list); + +/* ---------------------------------------------------------------------------- + * Android extentions + * ---------------------------------------------------------------------------- + */ + +EGLBoolean eglSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw, + EGLint l, EGLint t, EGLint w, EGLint h); + +EGLBoolean eglCopyFrontToBackANDROID(EGLDisplay dpy, + EGLSurface surface, + EGLint l, EGLint t, EGLint w, EGLint h); + +const char* eglQueryStringConfigANDROID( + EGLDisplay dpy, EGLConfig config, EGLint name); + +void* eglGetRenderBufferAddressANDROID(EGLDisplay dpy, EGLSurface surface); + +EGLBoolean eglCopyBitsANDROID(EGLDisplay dpy, + NativeWindowType draw, EGLint x, EGLint y, + NativeWindowType read, + EGLint crop_x, EGLint crop_y, EGLint crop_w, EGLint crop_h, + EGLint flags); + + +#ifdef __cplusplus +} +#endif + + +#endif /*ANDROID_EGL_H*/ + diff --git a/android/testproject/jni/eglnatives.h b/android/testproject/jni/eglnatives.h new file mode 100644 index 000000000..9d72be84e --- /dev/null +++ b/android/testproject/jni/eglnatives.h @@ -0,0 +1,277 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * 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 + * + * http://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. + */ + +#ifndef ANDROID_EGLNATIVES_H +#define ANDROID_EGLNATIVES_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif +/*****************************************************************************/ + +struct egl_native_window_t; +struct egl_native_pixmap_t; + + +typedef struct egl_native_window_t* NativeWindowType; +typedef struct egl_native_pixmap_t* NativePixmapType; +typedef void* NativeDisplayType; + +/* + * This a conveniance function to create a NativeWindowType surface + * that maps to the whole screen + * This function is actually implemented in libui.so + */ + +NativeWindowType android_createDisplaySurface(); + +/* flags returned from swapBuffer */ +#define EGL_NATIVES_FLAG_SIZE_CHANGED 0x00000001 + +/* surface flags */ +#define EGL_NATIVES_FLAG_DESTROY_BACKBUFFER 0x00000001 + +enum native_pixel_format_t +{ + NATIVE_PIXEL_FORMAT_RGBA_8888 = 1, + NATIVE_PIXEL_FORMAT_RGB_565 = 4, + NATIVE_PIXEL_FORMAT_RGBA_5551 = 6, + NATIVE_PIXEL_FORMAT_RGBA_4444 = 7, + NATIVE_PIXEL_FORMAT_YCbCr_422_SP= 0x10, + NATIVE_PIXEL_FORMAT_YCbCr_420_SP= 0x11, +}; + +enum native_memory_type_t +{ + NATIVE_MEMORY_TYPE_PMEM = 0, + NATIVE_MEMORY_TYPE_GPU = 1, + NATIVE_MEMORY_TYPE_FB = 2, + NATIVE_MEMORY_TYPE_HEAP = 128 +}; + + +struct egl_native_window_t +{ + /* + * magic must be set to 0x600913 + */ + uint32_t magic; + + /* + * must be sizeof(egl_native_window_t) + */ + uint32_t version; + + /* + * ident is reserved for the Android platform + */ + uint32_t ident; + + /* + * width, height and stride of the window in pixels + * Any of these value can be nul in which case GL commands are + * accepted and processed as usual, but not rendering occurs. + */ + int width; // w=h=0 is legal + int height; + int stride; + + /* + * format of the native window (see ui/PixelFormat.h) + */ + int format; + + /* + * Offset of the bits in the VRAM + */ + intptr_t offset; + + /* + * flags describing some attributes of this surface + * EGL_NATIVES_FLAG_DESTROY_BACKBUFFER: backbuffer not preserved after + * eglSwapBuffers + */ + uint32_t flags; + + /* + * horizontal and vertical resolution in DPI + */ + float xdpi; + float ydpi; + + /* + * refresh rate in frames per second (Hz) + */ + float fps; + + + /* + * Base memory virtual address of the surface in the CPU side + */ + intptr_t base; + + /* + * Heap the offset above is based from + */ + int fd; + + /* + * Memory type the surface resides into + */ + uint8_t memory_type; + + /* + * Reserved for future use. MUST BE ZERO. + */ + uint8_t reserved_pad[3]; + int reserved[8]; + + /* + * Vertical stride (only relevant with planar formats) + */ + + int vstride; + + /* + * Hook called by EGL to hold a reference on this structure + */ + void (*incRef)(NativeWindowType window); + + /* + * Hook called by EGL to release a reference on this structure + */ + void (*decRef)(NativeWindowType window); + + /* + * Hook called by EGL to perform a page flip. This function + * may update the size attributes above, in which case it returns + * the EGL_NATIVES_FLAG_SIZE_CHANGED bit set. + */ + uint32_t (*swapBuffers)(NativeWindowType window); + + /* + * Hook called by EGL to set the swap rectangle. this hook can be + * null (operation not supported) + */ + void (*setSwapRectangle)(NativeWindowType window, int l, int t, int w, int h); + + /* + * Reserved for future use. MUST BE ZERO. + */ + void (*reserved_proc_0)(void); + + + /* + * Hook called by EGL to retrieve the next buffer to render into. + * This call updates this structure. + */ + uint32_t (*nextBuffer)(NativeWindowType window); + + /* + * Hook called by EGL when the native surface is associated to EGL + * (eglCreateWindowSurface). Can be NULL. + */ + void (*connect)(NativeWindowType window); + + /* + * Hook called by EGL when eglDestroySurface is called. Can be NULL. + */ + void (*disconnect)(NativeWindowType window); + + /* + * Reserved for future use. MUST BE ZERO. + */ + void (*reserved_proc[11])(void); + + /* + * Some storage reserved for the oem driver. + */ + intptr_t oem[4]; +}; + + +struct egl_native_pixmap_t +{ + int32_t version; /* must be 32 */ + int32_t width; + int32_t height; + int32_t stride; + uint8_t* data; + uint8_t format; + uint8_t rfu[3]; + union { + uint32_t compressedFormat; + int32_t vstride; + }; + int32_t reserved; +}; + +/*****************************************************************************/ + +/* + * OEM's egl's library (libhgl.so) must imlement these hooks to allocate + * the GPU memory they need + */ + + +typedef struct +{ + // for internal use + void* user; + // virtual address of this area + void* base; + // size of this area in bytes + size_t size; + // physical address of this area + void* phys; + // offset in this area available to the GPU + size_t offset; + // fd of this area + int fd; +} gpu_area_t; + +typedef struct +{ + // area where GPU registers are mapped + gpu_area_t regs; + // number of extra areas (currently limited to 2) + int32_t count; + // extra GPU areas (currently limited to 2) + gpu_area_t gpu[2]; +} request_gpu_t; + + +typedef request_gpu_t* (*OEM_EGL_acquire_gpu_t)(void* user); +typedef int (*OEM_EGL_release_gpu_t)(void* user, request_gpu_t* handle); +typedef void (*register_gpu_t) + (void* user, OEM_EGL_acquire_gpu_t, OEM_EGL_release_gpu_t); + +void oem_register_gpu( + void* user, + OEM_EGL_acquire_gpu_t acquire, + OEM_EGL_release_gpu_t release); + + +/*****************************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* ANDROID_EGLNATIVES_H */ + diff --git a/android/testproject/jni/egltypes.h b/android/testproject/jni/egltypes.h new file mode 100644 index 000000000..fd68fa351 --- /dev/null +++ b/android/testproject/jni/egltypes.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * 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 + * + * http://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. + */ + +#ifndef ANDROID_EGL_TYPES_H +#define ANDROID_EGL_TYPES_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned int EGLBoolean; +typedef int32_t EGLint; +typedef int EGLenum; +typedef void *EGLDisplay; +typedef void *EGLConfig; +typedef void *EGLSurface; +typedef void *EGLContext; +typedef void *EGLClientBuffer; + +#define EGL_DEFAULT_DISPLAY ((NativeDisplayType)0) + +#define EGL_NO_CONTEXT ((EGLContext)0) +#define EGL_NO_DISPLAY ((EGLDisplay)0) +#define EGL_NO_SURFACE ((EGLSurface)0) + + +#ifdef __cplusplus +} +#endif + + +#endif /* ANDROID_EGL_TYPES_H */ + diff --git a/android/testproject/jni/lesson05.c b/android/testproject/jni/lesson05.c new file mode 100644 index 000000000..329507704 --- /dev/null +++ b/android/testproject/jni/lesson05.c @@ -0,0 +1,469 @@ +/* + * This code was created by Jeff Molofee '99 + * (ported to Linux/SDL by Ti Leggett '01) + * + * If you've found this code useful, please let me know. + * + * Visit Jeff at http://nehe.gamedev.net/ + * + * or for port-specific comments, questions, bugreports etc. + * email to leggett@eecs.tulane.edu + */ + +#include +#include +#include + +#include + + +#ifdef ANDROID +#include +#else +#include +#include +#endif +#include "SDL.h" + +/* screen width, height, and bit depth */ +#define SCREEN_WIDTH 320 +#define SCREEN_HEIGHT 480 +#define SCREEN_BPP 16 + +/* Define our booleans */ +#define TRUE 1 +#define FALSE 0 + +/* This is our SDL surface */ +SDL_Surface *surface; + + +/************************************** + gluperspective implementation +**************************************/ +void gluPerspective(double fovy, double aspect, double zNear, double zFar){ + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + double xmin, xmax, ymin, ymax; + ymax = zNear * tan(fovy * M_PI / 360.0); + ymin = -ymax; + xmin = ymin * aspect; + xmax = ymax * aspect; + glFrustumf(xmin, xmax, ymin, ymax, zNear, zFar); +} + + +/************************************** + glulookat implementation +**************************************/ +void gluLookAt(GLfloat eyex, GLfloat eyey, GLfloat eyez, + GLfloat centerx, GLfloat centery, GLfloat centerz, + GLfloat upx, GLfloat upy, GLfloat upz) +{ + GLfloat m[16]; + GLfloat x[3], y[3], z[3]; + GLfloat mag; + + /* Make rotation matrix */ + + /* Z vector */ + z[0] = eyex - centerx; + z[1] = eyey - centery; + z[2] = eyez - centerz; + mag = sqrt(z[0] * z[0] + z[1] * z[1] + z[2] * z[2]); + if (mag) { /* mpichler, 19950515 */ + z[0] /= mag; + z[1] /= mag; + z[2] /= mag; + } + + /* Y vector */ + y[0] = upx; + y[1] = upy; + y[2] = upz; + + /* X vector = Y cross Z */ + x[0] = y[1] * z[2] - y[2] * z[1]; + x[1] = -y[0] * z[2] + y[2] * z[0]; + x[2] = y[0] * z[1] - y[1] * z[0]; + + /* Recompute Y = Z cross X */ + y[0] = z[1] * x[2] - z[2] * x[1]; + y[1] = -z[0] * x[2] + z[2] * x[0]; + y[2] = z[0] * x[1] - z[1] * x[0]; + + /* mpichler, 19950515 */ + /* cross product gives area of parallelogram, which is < 1.0 for + * non-perpendicular unit-length vectors; so normalize x, y here + */ + + mag = sqrt(x[0] * x[0] + x[1] * x[1] + x[2] * x[2]); + if (mag) { + x[0] /= mag; + x[1] /= mag; + x[2] /= mag; + } + + mag = sqrt(y[0] * y[0] + y[1] * y[1] + y[2] * y[2]); + if (mag) { + y[0] /= mag; + y[1] /= mag; + y[2] /= mag; + } + +#define M(row,col) m[col*4+row] + M(0, 0) = x[0]; + M(0, 1) = x[1]; + M(0, 2) = x[2]; + M(0, 3) = 0.0; + M(1, 0) = y[0]; + M(1, 1) = y[1]; + M(1, 2) = y[2]; + M(1, 3) = 0.0; + M(2, 0) = z[0]; + M(2, 1) = z[1]; + M(2, 2) = z[2]; + M(2, 3) = 0.0; + M(3, 0) = 0.0; + M(3, 1) = 0.0; + M(3, 2) = 0.0; + M(3, 3) = 1.0; +#undef M + glMultMatrixf(m); + + /* Translate Eye to Origin */ + glTranslatef(-eyex, -eyey, -eyez); + +} + + + + + +/* function to release/destroy our resources and restoring the old desktop */ +void Quit( int returnCode ) +{ + /* clean up the window */ + SDL_Quit( ); + + /* and exit appropriately */ + exit( returnCode ); +} + +/* function to reset our viewport after a window resize */ +int resizeWindow( int width, int height ) +{ + /* Height / width ration */ + GLfloat ratio; + + /* Protect against a divide by zero */ + if ( height == 0 ) + height = 1; + + ratio = ( GLfloat )width / ( GLfloat )height; + + /* Setup our viewport. */ + glViewport( 0, 0, ( GLsizei )width, ( GLsizei )height ); + + /* change to the projection matrix and set our viewing volume. */ + glMatrixMode( GL_PROJECTION ); + glLoadIdentity( ); + + /* Set our perspective */ + gluPerspective( 45.0f, ratio, 0.1f, 100.0f ); + + /* Make sure we're chaning the model view and not the projection */ + glMatrixMode( GL_MODELVIEW ); + + /* Reset The View */ + glLoadIdentity( ); + + return( TRUE ); +} + +/* function to handle key press events */ +void handleKeyPress( SDL_keysym *keysym ) +{ + switch ( keysym->sym ) + { + case SDLK_ESCAPE: + /* ESC key was pressed */ + Quit( 0 ); + break; + case SDLK_F1: + /* F1 key was pressed + * this toggles fullscreen mode + */ + SDL_WM_ToggleFullScreen( surface ); + break; + default: + break; + } + + return; +} + +/* general OpenGL initialization function */ +int initGL( GLvoid ) +{ + + /* Enable smooth shading */ + glShadeModel( GL_SMOOTH ); + + /* Set the background black */ + glClearColor( 0.0f, 0.0f, 0.0f, 0.0f ); + + /* Depth buffer setup */ + //glClearDepth( 1.0f ); + + /* Enables Depth Testing */ + glEnable( GL_DEPTH_TEST ); + + /* The Type Of Depth Test To Do */ + glDepthFunc( GL_LEQUAL ); + + /* Really Nice Perspective Calculations */ + glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST ); + + return( TRUE ); +} + +/* Here goes our drawing code */ +int drawGLScene( GLvoid ) +{ + static int Frames = 0; + static int T0 = 0; + + glViewport(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); + + glClearColorx(0,0,Frames,255); + glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(45, (float)SCREEN_WIDTH / SCREEN_HEIGHT, 0.5f, 150); + + glMatrixMode(GL_MODELVIEW); + + glLoadIdentity(); + + //Camera + gluLookAt(0,0,5, 0,0,0, 0,1,0); + + //Draw a triangle + //glRotatef(iRot, 0, 1, 0); + + glRotatef( Frames % 360, 0.0f, 1.0f, 0.0f ); + + + glEnableClientState (GL_VERTEX_ARRAY); + glEnableClientState (GL_COLOR_ARRAY); + + /* Rotate The Triangle On The Y axis ( NEW ) */ + glRotatef( Frames % 360, 0.0f, 1.0f, 0.0f ); + + /* GLES variant of drawing a triangle */ + const GLfloat triVertices[][9] = { + { /* Front Triangle */ + 0.0f, 1.0f, 0.0f, /* Top Of Triangle */ + -1.0f, -1.0f, 1.0f, /* Left Of Triangle */ + 1.0f, -1.0f, 1.0f /* Right Of Triangle */ + }, { /* Right Triangle */ + 0.0f, 1.0f, 0.0f, /* Top Of Triangle */ + 1.0f, -1.0f, 1.0f, /* Left Of Triangle */ + 1.0f, -1.0f, -1.0f /* Right Of Triangle */ + }, { /* Back Triangle */ + 0.0f, 1.0f, 0.0f, /* Top Of Triangle */ + 1.0f, -1.0f, -1.0f, /* Left Of Triangle */ + -1.0f, -1.0f, -1.0f /* Right Of Triangle */ + }, { /* Left Triangle */ + 0.0f, 1.0f, 0.0f, /* Top Of Triangle */ + -1.0f, -1.0f, -1.0f, /* Left Of Triangle */ + -1.0f, -1.0f, 1.0f /* Right Of Triangle */ + } + }; + + /* unlike GL, GLES does not support RGB. We have to use RGBA instead */ + const GLfloat triColors[][12] = { + { /* Front triangle */ + 1.0f, 0.0f, 0.0f, 1.0f, /* Red */ + 0.0f, 1.0f, 0.0f, 1.0f, /* Green */ + 0.0f, 0.0f, 1.0f, 1.0f /* Blue */ + }, { /* Right triangle */ + 1.0f, 0.0f, 0.0f, 1.0f, /* Red */ + 0.0f, 0.0f, 1.0f, 1.0f, /* Blue */ + 0.0f, 1.0f, 0.0f, 1.0f /* Green */ + }, { /* Back triangle */ + 1.0f, 0.0f, 0.0f, 1.0f, /* Red */ + 0.0f, 1.0f, 0.0f, 1.0f, /* Green */ + 0.0f, 0.0f, 1.0f, 1.0f /* Blue */ + }, { /* Left triangle */ + 1.0f, 0.0f, 0.0f, 1.0f, /* Red */ + 0.0f, 0.0f, 1.0f, 1.0f, /* Blue */ + 0.0f, 1.0f, 0.0f, 1.0f /* Green */ + } + }; + + glEnableClientState(GL_COLOR_ARRAY); + + int tri=0; + + /* Loop through all Triangles */ + for(tri=0;tri= 5000) { + GLfloat seconds = (t - T0) / 1000.0; + GLfloat fps = Frames / seconds; + __android_log_print(ANDROID_LOG_INFO, "SDL","%d frames in %g seconds = %g FPS\n", Frames, seconds, fps); + T0 = t; + Frames = 0; + } + } + + return( TRUE ); +} + +int SDL_main( int argc, char **argv ) +{ + + __android_log_print(ANDROID_LOG_INFO, "SDL","entry\n"); + + /* Flags to pass to SDL_SetVideoMode */ + int videoFlags; + /* main loop variable */ + int done = FALSE; + /* used to collect events */ + SDL_Event event; + /* this holds some info about our display */ + const SDL_VideoInfo *videoInfo; + /* whether or not the window is active */ + int isActive = TRUE; + + /* initialize SDL */ + if ( SDL_Init( SDL_INIT_VIDEO ) < 0 ) + { + __android_log_print(ANDROID_LOG_INFO, "SDL", "Video initialization failed: %s\n", + SDL_GetError( ) ); + Quit( 1 ); + } + + /* Fetch the video info */ + videoInfo = SDL_GetVideoInfo( ); + + if ( !videoInfo ) + { + __android_log_print(ANDROID_LOG_INFO, "SDL", "Video query failed: %s\n", + SDL_GetError( ) ); + Quit( 1 ); + } + + /* the flags to pass to SDL_SetVideoMode */ + videoFlags = SDL_OPENGL; /* Enable OpenGL in SDL */ + videoFlags |= SDL_GL_DOUBLEBUFFER; /* Enable double buffering */ + videoFlags |= SDL_HWPALETTE; /* Store the palette in hardware */ + videoFlags |= SDL_RESIZABLE; /* Enable window resizing */ + + /* This checks to see if surfaces can be stored in memory */ + if ( videoInfo->hw_available ) + videoFlags |= SDL_HWSURFACE; + else + videoFlags |= SDL_SWSURFACE; + + /* This checks if hardware blits can be done */ + if ( videoInfo->blit_hw ) + videoFlags |= SDL_HWACCEL; + + /* Sets up OpenGL double buffering */ + SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); + + /* get a SDL surface */ + surface = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, + videoFlags ); + + /* Verify there is a surface */ + if ( !surface ) + { + __android_log_print(ANDROID_LOG_INFO, "SDL", "Video mode set failed: %s\n", SDL_GetError( ) ); + Quit( 1 ); + } + + __android_log_print(ANDROID_LOG_INFO, "SDL","Made a video mode!\n"); + + /* initialize OpenGL */ + initGL( ); + + /* resize the initial window */ + resizeWindow( SCREEN_WIDTH, SCREEN_HEIGHT ); + + /* wait for events */ + while ( !done ) + { + /* handle the events in the queue */ + + while ( SDL_PollEvent( &event ) ) + { + switch( event.type ) + { + case SDL_ACTIVEEVENT: + /* Something's happend with our focus + * If we lost focus or we are iconified, we + * shouldn't draw the screen + */ + if ( event.active.gain == 0 ) + isActive = FALSE; + else + isActive = TRUE; + break; + case SDL_VIDEORESIZE: + /* handle resize event */ + surface = SDL_SetVideoMode( event.resize.w, + event.resize.h, + 16, videoFlags ); + if ( !surface ) + { + __android_log_print(ANDROID_LOG_INFO, "SDL","Could not get a surface after resize: %s\n", SDL_GetError( ) ); + Quit( 1 ); + } + resizeWindow( event.resize.w, event.resize.h ); + break; + case SDL_KEYDOWN: + /* handle key presses */ + handleKeyPress( &event.key.keysym ); + break; + case SDL_QUIT: + /* handle quit requests */ + done = TRUE; + break; + default: + break; + } + } + + /* draw the scene */ + if ( isActive ) + drawGLScene( ); + } + + /* clean ourselves up and exit */ + Quit( 0 ); + + /* Should never get here */ + return( 0 ); +} + + From 5c404353ee7d8cd5a5ffb29b3b086ad890f46c91 Mon Sep 17 00:00:00 2001 From: Paul Hunkin Date: Fri, 18 Jun 2010 01:29:14 +1200 Subject: [PATCH 15/34] Tweaks to the libsdl side --- src/video/android/SDL_androidgl.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/video/android/SDL_androidgl.c b/src/video/android/SDL_androidgl.c index 9f8712e86..b10f57615 100644 --- a/src/video/android/SDL_androidgl.c +++ b/src/video/android/SDL_androidgl.c @@ -36,12 +36,13 @@ #include +#include /* These things are in the JNI android support */ - - +extern pthread_mutex_t mSDLRenderMutex; +extern pthread_cond_t mSDLRenderCondition; /* GL functions */ int Android_GL_LoadLibrary(_THIS, const char *path){ @@ -67,7 +68,7 @@ int *Android_GL_GetVisual(_THIS, Display * display, int screen){ SDL_GLContext Android_GL_CreateContext(_THIS, SDL_Window * window){ __android_log_print(ANDROID_LOG_INFO, "SDL", "[STUB] GL_CreateContext\n"); - return NULL; + return 1; } int Android_GL_MakeCurrent(_THIS, SDL_Window * window, @@ -87,7 +88,14 @@ int Android_GL_GetSwapInterval(_THIS){ } void Android_GL_SwapWindow(_THIS, SDL_Window * window){ - __android_log_print(ANDROID_LOG_INFO, "SDL", "[STUB] GL_SwapWindow\n"); + + pthread_mutex_lock(&mSDLRenderMutex); + pthread_cond_wait(&mSDLRenderCondition, &mSDLRenderMutex); + pthread_mutex_unlock(&mSDLRenderMutex); + + + //__android_log_print(ANDROID_LOG_INFO, "SDL", "[STUB] GL_SwapWindow\n"); + } void Android_GL_DeleteContext(_THIS, SDL_GLContext context){ From 19486584277f976a88e35fa8a2aff7837477541a Mon Sep 17 00:00:00 2001 From: Paul Hunkin Date: Mon, 28 Jun 2010 21:35:28 +1200 Subject: [PATCH 16/34] Last test version with GLSurface --- android/testproject/jni/app-android.c | 37 ++++++++++++++++--- android/testproject/jni/lesson05.c | 4 +- .../src/org/libsdl/android/TestActivity.java | 2 + src/video/android/SDL_androidgl.c | 5 ++- 4 files changed, 41 insertions(+), 7 deletions(-) diff --git a/android/testproject/jni/app-android.c b/android/testproject/jni/app-android.c index e91329a81..6d458a99e 100644 --- a/android/testproject/jni/app-android.c +++ b/android/testproject/jni/app-android.c @@ -55,6 +55,7 @@ void* sdlThreadProc(void* args){ __android_log_print(ANDROID_LOG_INFO, "SDL", "Couldn't make current: 0x%x", eglGetError()); return NULL; } + return (void *)SDL_main(); } @@ -143,14 +144,40 @@ void Java_org_libsdl_android_TestGLSurfaceView_nativePause( JNIEnv* env ) Render the next frame *******************************************************************************/ +volatile int frames = 0; +volatile int startSDL = 0; + +//eglSwapBuffers(mDisplay, mDraw); + void Java_org_libsdl_android_TestRenderer_nativeRender( JNIEnv* env ) { - //TODO: Render here + __android_log_print(ANDROID_LOG_INFO, "SDL", "JNI: BeginRender"); + + //Let the SDL thread do an entire run + int lastFrames = frames; + startSDL = 1; + + //wait for it to finish + while(lastFrames == frames){ + ; + } - pthread_mutex_lock(&mSDLRenderMutex); - pthread_cond_signal(&mSDLRenderCondition); //wake up the SDL thread - pthread_mutex_unlock(&mSDLRenderMutex); + __android_log_print(ANDROID_LOG_INFO, "SDL", "JNI: EndRender"); +} + +void sdl_render(){ + + //When we get here, we've accumulated a full frame - //__android_log_print(ANDROID_LOG_INFO, "SDL", "Unlocked"); + __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: BeginRender"); + + frames++; + while(startSDL == 0){ + ; + } + startSDL = 0; + + __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: EndRender"); } + diff --git a/android/testproject/jni/lesson05.c b/android/testproject/jni/lesson05.c index 329507704..40fa4afae 100644 --- a/android/testproject/jni/lesson05.c +++ b/android/testproject/jni/lesson05.c @@ -236,7 +236,7 @@ int drawGLScene( GLvoid ) glViewport(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); - glClearColorx(0,0,Frames,255); + glClearColorx(0,0,0,255); glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); glMatrixMode(GL_PROJECTION); @@ -335,6 +335,8 @@ int drawGLScene( GLvoid ) } } + + return( TRUE ); } diff --git a/android/testproject/src/org/libsdl/android/TestActivity.java b/android/testproject/src/org/libsdl/android/TestActivity.java index 5777d42ee..9581f9ea2 100644 --- a/android/testproject/src/org/libsdl/android/TestActivity.java +++ b/android/testproject/src/org/libsdl/android/TestActivity.java @@ -41,6 +41,8 @@ public TestGLSurfaceView(Context context) { super(context); mRenderer = new TestRenderer(); setRenderer(mRenderer); + + //setRenderMode(RENDERMODE_WHEN_DIRTY); } public boolean onTouchEvent(final MotionEvent event) { diff --git a/src/video/android/SDL_androidgl.c b/src/video/android/SDL_androidgl.c index b10f57615..a6b9b0bad 100644 --- a/src/video/android/SDL_androidgl.c +++ b/src/video/android/SDL_androidgl.c @@ -43,6 +43,7 @@ These things are in the JNI android support */ extern pthread_mutex_t mSDLRenderMutex; extern pthread_cond_t mSDLRenderCondition; +extern void sdl_render(); /* GL functions */ int Android_GL_LoadLibrary(_THIS, const char *path){ @@ -89,12 +90,14 @@ int Android_GL_GetSwapInterval(_THIS){ void Android_GL_SwapWindow(_THIS, SDL_Window * window){ +/* pthread_mutex_lock(&mSDLRenderMutex); pthread_cond_wait(&mSDLRenderCondition, &mSDLRenderMutex); pthread_mutex_unlock(&mSDLRenderMutex); - +*/ //__android_log_print(ANDROID_LOG_INFO, "SDL", "[STUB] GL_SwapWindow\n"); + sdl_render(); } From 877d51d2452bf70933ea6f5b52b4075aad1ec6c7 Mon Sep 17 00:00:00 2001 From: Paul Hunkin Date: Tue, 29 Jun 2010 00:40:12 +1200 Subject: [PATCH 17/34] - Restructured threads and application structure. - Moved to SurfaceView instead of GLSurfaceView - Moved to C++ for the android library --- android/testproject/jni/Android.mk | 4 +- android/testproject/jni/app-android.c | 183 ------------------ android/testproject/jni/app-android.cpp | 101 ++++++++++ .../jni/{importgl.c => importgl.cpp} | 0 .../src/org/libsdl/android/TestActivity.java | 173 +++++++++++++++-- src/video/android/SDL_androidgl.c | 14 +- 6 files changed, 258 insertions(+), 217 deletions(-) delete mode 100644 android/testproject/jni/app-android.c create mode 100644 android/testproject/jni/app-android.cpp rename android/testproject/jni/{importgl.c => importgl.cpp} (100%) diff --git a/android/testproject/jni/Android.mk b/android/testproject/jni/Android.mk index 3f3f20250..7d3e649da 100644 --- a/android/testproject/jni/Android.mk +++ b/android/testproject/jni/Android.mk @@ -11,8 +11,8 @@ LOCAL_CFLAGS := -DANDROID_NDK \ -I$(SDL)/include LOCAL_SRC_FILES := \ - importgl.c \ - app-android.c \ + importgl.cpp \ + app-android.cpp \ lesson05.c \ LOCAL_LDLIBS := -lGLESv1_CM -ldl -llog -lSDL -lEGL -lgcc -L$(SDL) -L$(SDL)/build-scripts/android_libs/ diff --git a/android/testproject/jni/app-android.c b/android/testproject/jni/app-android.c deleted file mode 100644 index 6d458a99e..000000000 --- a/android/testproject/jni/app-android.c +++ /dev/null @@ -1,183 +0,0 @@ -/******************************************************************************* - Headers -*******************************************************************************/ -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include "importgl.h" -#include "egl.h" - -/******************************************************************************* - Globals -*******************************************************************************/ -int gAppAlive = 1; - -static int sWindowWidth = 320; -static int sWindowHeight = 480; -static int sDemoStopped = 0; - -static long _getTime(void){ - struct timeval now; - gettimeofday(&now, NULL); - return (long)(now.tv_sec*1000 + now.tv_usec/1000); -} - - -/******************************************************************************* - Things used by libsdl -*******************************************************************************/ -pthread_mutex_t mSDLRenderMutex; -pthread_cond_t mSDLRenderCondition; - -EGLContext mContext; -EGLDisplay mDisplay; -EGLSurface mRead; -EGLSurface mDraw; - -/******************************************************************************* - SDL thread -*******************************************************************************/ -pthread_t mSDLThread = 0; - -void* sdlThreadProc(void* args){ - __android_log_print(ANDROID_LOG_INFO, "SDL", "Thread Entry"); - - if(!eglMakeCurrent(mDisplay, mDraw, mRead, mContext)){ - __android_log_print(ANDROID_LOG_INFO, "SDL", "Couldn't make current: 0x%x", eglGetError()); - return NULL; - } - - - return (void *)SDL_main(); -} - -/******************************************************************************* - Initialize the graphics state -*******************************************************************************/ -void Java_org_libsdl_android_TestRenderer_nativeInit( JNIEnv* env ) -{ - importGLInit(); - - gAppAlive = 1; - sDemoStopped = 0; - - __android_log_print(ANDROID_LOG_INFO, "SDL", "Entry point"); - - pthread_mutex_init(&mSDLRenderMutex, NULL); - pthread_cond_init (&mSDLRenderCondition, NULL); - - //Get some egl stuff we need - mContext = eglGetCurrentContext(); - mDisplay = eglGetCurrentDisplay(); - mRead = eglGetCurrentSurface(EGL_READ); - mDraw = eglGetCurrentSurface(EGL_DRAW); - - //We need to abandon our context so SDL can have it - if(!eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)){ - __android_log_print(ANDROID_LOG_INFO, "SDL", "Couldn't abandon context: 0x%x", eglGetError()); - return NULL; - } - - //Spin up the SDL thread - int r = pthread_create(&mSDLThread, NULL, sdlThreadProc, NULL); - - if(r != 0){ - __android_log_print(ANDROID_LOG_INFO, "SDL", "Couldn't spawn thread: %d", r); - }else{ - __android_log_print(ANDROID_LOG_INFO, "SDL", "Started SDL thread"); - } - -} - -/******************************************************************************* - Resize -*******************************************************************************/ -void Java_org_libsdl_android_TestRenderer_nativeResize( JNIEnv* env, - jobject thiz, - jint w, - jint h ) -{ - sWindowWidth = w; - sWindowHeight = h; - __android_log_print(ANDROID_LOG_INFO, "SDL", "resize w=%d h=%d", w, h); - -} - -/******************************************************************************* - Finalize (ie: shutdown) -*******************************************************************************/ -void Java_org_libsdl_android_TestRenderer_nativeDone( JNIEnv* env ) -{ - - //shut down the app - - importGLDeinit(); - - __android_log_print(ANDROID_LOG_INFO, "SDL", "Finalize"); -} - -/******************************************************************************* - Pause (ie: stop as soon as possible) -*******************************************************************************/ -void Java_org_libsdl_android_TestGLSurfaceView_nativePause( JNIEnv* env ) -{ - sDemoStopped = !sDemoStopped; - if (sDemoStopped) { - //we paused - __android_log_print(ANDROID_LOG_INFO, "SDL", "Pause"); - } else { - //we resumed - __android_log_print(ANDROID_LOG_INFO, "SDL", "Resume"); - } -} - -/******************************************************************************* - Render the next frame -*******************************************************************************/ - -volatile int frames = 0; -volatile int startSDL = 0; - -//eglSwapBuffers(mDisplay, mDraw); - -void Java_org_libsdl_android_TestRenderer_nativeRender( JNIEnv* env ) -{ - __android_log_print(ANDROID_LOG_INFO, "SDL", "JNI: BeginRender"); - - //Let the SDL thread do an entire run - int lastFrames = frames; - startSDL = 1; - - //wait for it to finish - while(lastFrames == frames){ - ; - } - - __android_log_print(ANDROID_LOG_INFO, "SDL", "JNI: EndRender"); -} - -void sdl_render(){ - - //When we get here, we've accumulated a full frame - - __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: BeginRender"); - - frames++; - - while(startSDL == 0){ - ; - } - startSDL = 0; - - __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: EndRender"); -} - diff --git a/android/testproject/jni/app-android.cpp b/android/testproject/jni/app-android.cpp new file mode 100644 index 000000000..bcd1fcf88 --- /dev/null +++ b/android/testproject/jni/app-android.cpp @@ -0,0 +1,101 @@ +/******************************************************************************* + Headers +*******************************************************************************/ +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "importgl.h" +#include "egl.h" + +/******************************************************************************* + Globals +*******************************************************************************/ +static long _getTime(void){ + struct timeval now; + gettimeofday(&now, NULL); + return (long)(now.tv_sec*1000 + now.tv_usec/1000); +} + +JNIEnv* mEnv = NULL; +JavaVM* mVM = NULL; + +//Main activity +jclass mActivityInstance; + +//method signatures +jmethodID midCreateGLContext; +jmethodID midFlipBuffers; + +extern "C" int SDL_main(); + +/******************************************************************************* + Functions called by JNI +*******************************************************************************/ + +extern "C" void Java_org_libsdl_android_TestActivity_nativeInit( JNIEnv* env, jobject obj ) +{ + __android_log_print(ANDROID_LOG_INFO, "SDL", "JNI: NativeInit"); + + mEnv = env; + + SDL_main(); +} + +extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved) +{ + JNIEnv* env = NULL; + jint result = -1; + + if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { + return result; + } + + mEnv = env; + + __android_log_print(ANDROID_LOG_INFO, "SDL", "JNI: OnLoad"); + + jclass cls = mEnv->FindClass ("org/libsdl/android/TestActivity"); + mActivityInstance = cls; + midCreateGLContext = mEnv->GetStaticMethodID(cls,"createGLContext","()V"); + midFlipBuffers = mEnv->GetStaticMethodID(cls,"flipBuffers","()V"); + + if(!midCreateGLContext || !midFlipBuffers){ + __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: Bad mids\n"); + }else{ + __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: Good mids\n"); + } + + return JNI_VERSION_1_4; +} + + + +/******************************************************************************* + Functions called by SDL +*******************************************************************************/ +extern "C" void sdl_create_context(){ + __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: sdl_create_context()\n"); + + mEnv->CallStaticVoidMethod(mActivityInstance, midCreateGLContext ); + __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: sdl_create_context() return\n"); + + // exit(1); +} + +extern "C" void sdl_render(){ + + //When we get here, we've accumulated a full frame + //__android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: sdl_render()"); + + mEnv->CallStaticVoidMethod(mActivityInstance, midFlipBuffers ); +} + diff --git a/android/testproject/jni/importgl.c b/android/testproject/jni/importgl.cpp similarity index 100% rename from android/testproject/jni/importgl.c rename to android/testproject/jni/importgl.cpp diff --git a/android/testproject/src/org/libsdl/android/TestActivity.java b/android/testproject/src/org/libsdl/android/TestActivity.java index 9581f9ea2..f022662e4 100644 --- a/android/testproject/src/org/libsdl/android/TestActivity.java +++ b/android/testproject/src/org/libsdl/android/TestActivity.java @@ -2,66 +2,197 @@ import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; +import javax.microedition.khronos.egl.*; import android.app.Activity; import android.content.Context; -import android.opengl.GLSurfaceView; +import android.view.SurfaceHolder; +import android.view.SurfaceView; import android.os.Bundle; import android.view.MotionEvent; +import android.util.Log; +import android.graphics.*; + +import java.lang.*; + + +//http://www.mail-archive.com/android-beginners@googlegroups.com/msg01830.html + +/* +In TestActivity::onResume() call SDL_Init +SDL_GL_CreateContext call SDLSurface::createSDLGLContext() +SDL_GL_FlipBuffers calls SDLSurface::flip() + +*/ + + public class TestActivity extends Activity { - @Override + protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - mGLView = new TestGLSurfaceView(this); - setContentView(mGLView); + mSurface = new SDLSurface(getApplication()); + setContentView(mSurface); + SurfaceHolder holder = mSurface.getHolder(); + holder.setType(SurfaceHolder.SURFACE_TYPE_GPU); } - @Override protected void onPause() { super.onPause(); - mGLView.onPause(); } - @Override protected void onResume() { super.onResume(); - mGLView.onResume(); + + //All set up. Start up SDL + + } - private GLSurfaceView mGLView; + private static SDLSurface mSurface; static { System.loadLibrary("sanangeles"); } + + //C functions we call + public static native void nativeInit(); + + + //Java functions called from C + private static void createGLContext(){ + mSurface.initEGL(); + } + + public static void flipBuffers(){ + mSurface.flipBuffers(); + } } -class TestGLSurfaceView extends GLSurfaceView { - public TestGLSurfaceView(Context context) { - super(context); - mRenderer = new TestRenderer(); - setRenderer(mRenderer); +class SDLThread implements Runnable{ + public void run(){ + TestActivity.nativeInit(); + } +} + +class SDLSurface extends SurfaceView implements SurfaceHolder.Callback{ + + private EGLContext mEGLContext; + private EGLSurface mEGLSurface; + private EGLDisplay mEGLDisplay; + + public void surfaceCreated(SurfaceHolder holder) { + Log.v("SDL","Surface created"); - //setRenderMode(RENDERMODE_WHEN_DIRTY); + Thread runner = new Thread(new SDLThread(), "SDLThread"); // (1) Create a new thread. + runner.start(); // (2) Start the thread + } - public boolean onTouchEvent(final MotionEvent event) { - if (event.getAction() == MotionEvent.ACTION_DOWN) { - nativePause(); + public void surfaceDestroyed(SurfaceHolder holder) { + Log.v("SDL","Surface destroyed"); + } + + public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { + + } + + + boolean initEGL(){ + Log.v("SDL","Starting up"); + + try{ + + // Get an EGL instance + EGL10 egl = (EGL10)EGLContext.getEGL(); + + // Get to the default display. + EGLDisplay dpy = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); + + // We can now initialize EGL for that display + int[] version = new int[2]; + egl.eglInitialize(dpy, version); + + // Specify a configuration for our opengl session + // and grab the first configuration that matches is + int[] configSpec = { + //EGL10.EGL_DEPTH_SIZE, 16, + EGL10.EGL_NONE + }; + EGLConfig[] configs = new EGLConfig[1]; + int[] num_config = new int[1]; + egl.eglChooseConfig(dpy, configSpec, configs, 1, num_config); + EGLConfig config = configs[0]; + + // Create an OpenGL ES context. This must be done only once + EGLContext ctx = egl.eglCreateContext(dpy, config, EGL10.EGL_NO_CONTEXT, null); + + // Create an EGL surface we can render into. + EGLSurface surface = egl.eglCreateWindowSurface(dpy, config, this, null); + + // Before we can issue GL commands, we need to make sure + // the context is current and bound to a surface. + egl.eglMakeCurrent(dpy, surface, surface, ctx); + + mEGLContext = ctx; + mEGLDisplay = dpy; + mEGLSurface = surface; + }catch(Exception e){ + Log.v("SDL", e + ""); } + + Log.v("SDL","Done making!"); + return true; } - TestRenderer mRenderer; + public SDLSurface(Context context) { + super(context); + + getHolder().addCallback(this); + + } + + public void onDraw(Canvas canvas) { + + + } + + + public void flipBuffers(){ + //Log.v("test","Draw!"); + + try{ + + EGL10 egl = (EGL10)EGLContext.getEGL(); + GL10 gl = (GL10)mEGLContext.getGL(); + + egl.eglWaitNative(EGL10.EGL_NATIVE_RENDERABLE, null); + + //drawing here + + egl.eglWaitGL(); + + egl.eglSwapBuffers(mEGLDisplay, mEGLSurface); + + + }catch(Exception e){ + Log.v("SDL", e + ""); + } + + } - private static native void nativePause(); } + +/* class TestRenderer implements GLSurfaceView.Renderer { public void onSurfaceCreated(GL10 gl, EGLConfig config) { nativeInit(); } + + public void onSurfaceChanged(GL10 gl, int w, int h) { //gl.glViewport(0, 0, w, h); nativeResize(w, h); @@ -75,4 +206,6 @@ public void onDrawFrame(GL10 gl) { private static native void nativeResize(int w, int h); private static native void nativeRender(); private static native void nativeDone(); + } +*/ diff --git a/src/video/android/SDL_androidgl.c b/src/video/android/SDL_androidgl.c index a6b9b0bad..d01682a4c 100644 --- a/src/video/android/SDL_androidgl.c +++ b/src/video/android/SDL_androidgl.c @@ -41,8 +41,7 @@ /* These things are in the JNI android support */ -extern pthread_mutex_t mSDLRenderMutex; -extern pthread_cond_t mSDLRenderCondition; +extern void sdl_create_context(); extern void sdl_render(); /* GL functions */ @@ -68,7 +67,7 @@ int *Android_GL_GetVisual(_THIS, Display * display, int screen){ */ SDL_GLContext Android_GL_CreateContext(_THIS, SDL_Window * window){ - __android_log_print(ANDROID_LOG_INFO, "SDL", "[STUB] GL_CreateContext\n"); + sdl_create_context(); return 1; } @@ -89,16 +88,7 @@ int Android_GL_GetSwapInterval(_THIS){ } void Android_GL_SwapWindow(_THIS, SDL_Window * window){ - -/* - pthread_mutex_lock(&mSDLRenderMutex); - pthread_cond_wait(&mSDLRenderCondition, &mSDLRenderMutex); - pthread_mutex_unlock(&mSDLRenderMutex); -*/ - - //__android_log_print(ANDROID_LOG_INFO, "SDL", "[STUB] GL_SwapWindow\n"); sdl_render(); - } void Android_GL_DeleteContext(_THIS, SDL_GLContext context){ From 6f2641d19ef3f427a40b7758578f694a9557d0c0 Mon Sep 17 00:00:00 2001 From: Paul Hunkin Date: Tue, 29 Jun 2010 01:30:11 +1200 Subject: [PATCH 18/34] Code cleanup --- android/testproject/AndroidManifest.xml | 2 +- android/testproject/jni/Android.mk | 2 +- android/testproject/jni/app-android.cpp | 4 +- .../{TestActivity.java => SDLActivity.java} | 161 +++++++++--------- 4 files changed, 87 insertions(+), 82 deletions(-) rename android/testproject/src/org/libsdl/android/{TestActivity.java => SDLActivity.java} (62%) diff --git a/android/testproject/AndroidManifest.xml b/android/testproject/AndroidManifest.xml index 57c344aa8..bb98659f2 100644 --- a/android/testproject/AndroidManifest.xml +++ b/android/testproject/AndroidManifest.xml @@ -4,7 +4,7 @@ android:versionCode="1" android:versionName="1.0"> - diff --git a/android/testproject/jni/Android.mk b/android/testproject/jni/Android.mk index 7d3e649da..bf1e39e9f 100644 --- a/android/testproject/jni/Android.mk +++ b/android/testproject/jni/Android.mk @@ -2,7 +2,7 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) -LOCAL_MODULE := sanangeles +LOCAL_MODULE := sdltest SDL := /home/paul/Projects/gsoc/SDL-gsoc2010_android/ diff --git a/android/testproject/jni/app-android.cpp b/android/testproject/jni/app-android.cpp index bcd1fcf88..54d541dd8 100644 --- a/android/testproject/jni/app-android.cpp +++ b/android/testproject/jni/app-android.cpp @@ -41,7 +41,7 @@ extern "C" int SDL_main(); Functions called by JNI *******************************************************************************/ -extern "C" void Java_org_libsdl_android_TestActivity_nativeInit( JNIEnv* env, jobject obj ) +extern "C" void Java_org_libsdl_android_SDLActivity_nativeInit( JNIEnv* env, jobject obj ) { __android_log_print(ANDROID_LOG_INFO, "SDL", "JNI: NativeInit"); @@ -63,7 +63,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved) __android_log_print(ANDROID_LOG_INFO, "SDL", "JNI: OnLoad"); - jclass cls = mEnv->FindClass ("org/libsdl/android/TestActivity"); + jclass cls = mEnv->FindClass ("org/libsdl/android/SDLActivity"); mActivityInstance = cls; midCreateGLContext = mEnv->GetStaticMethodID(cls,"createGLContext","()V"); midFlipBuffers = mEnv->GetStaticMethodID(cls,"flipBuffers","()V"); diff --git a/android/testproject/src/org/libsdl/android/TestActivity.java b/android/testproject/src/org/libsdl/android/SDLActivity.java similarity index 62% rename from android/testproject/src/org/libsdl/android/TestActivity.java rename to android/testproject/src/org/libsdl/android/SDLActivity.java index f022662e4..edce904c6 100644 --- a/android/testproject/src/org/libsdl/android/TestActivity.java +++ b/android/testproject/src/org/libsdl/android/SDLActivity.java @@ -16,105 +16,146 @@ import java.lang.*; -//http://www.mail-archive.com/android-beginners@googlegroups.com/msg01830.html - -/* -In TestActivity::onResume() call SDL_Init -SDL_GL_CreateContext call SDLSurface::createSDLGLContext() -SDL_GL_FlipBuffers calls SDLSurface::flip() - +/** + SDL Activity */ +public class SDLActivity extends Activity { + //Main components + private static SDLActivity mSingleton; + private static SDLSurface mSurface; + //Load the .so + static { + System.loadLibrary("sdltest"); + } -public class TestActivity extends Activity { - + //Setup protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + + //So we can call stuff from static callbacks + mSingleton = this; + + //Set up the surface mSurface = new SDLSurface(getApplication()); setContentView(mSurface); SurfaceHolder holder = mSurface.getHolder(); holder.setType(SurfaceHolder.SURFACE_TYPE_GPU); + + } + //Events protected void onPause() { super.onPause(); } protected void onResume() { super.onResume(); - - //All set up. Start up SDL - - } - private static SDLSurface mSurface; - static { - System.loadLibrary("sanangeles"); - } + + + //C functions we call public static native void nativeInit(); + + + + //Java functions called from C private static void createGLContext(){ mSurface.initEGL(); } public static void flipBuffers(){ - mSurface.flipBuffers(); + mSurface.flipEGL(); } + + + + + + + + //EGL context creation + } -class SDLThread implements Runnable{ +/** + Simple nativeInit() runnable +*/ +class SDLRunner implements Runnable{ public void run(){ - TestActivity.nativeInit(); + //Runs SDL_main() + SDLActivity.nativeInit(); } } + +/** + SDLSurface. This is what we draw on, so we need to know when it's created + in order to do anything useful. + + Because of this, that's where we set up the SDL thread +*/ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback{ + //This is what SDL runs in. It invokes SDL_main(), eventually + private Thread mSDLThread; + + //EGL private objects private EGLContext mEGLContext; private EGLSurface mEGLSurface; private EGLDisplay mEGLDisplay; + //Startup + public SDLSurface(Context context) { + super(context); + getHolder().addCallback(this); + } + + //Called when we have a valid drawing surface public void surfaceCreated(SurfaceHolder holder) { Log.v("SDL","Surface created"); - Thread runner = new Thread(new SDLThread(), "SDLThread"); // (1) Create a new thread. - runner.start(); // (2) Start the thread - + mSDLThread = new Thread(new SDLRunner(), "SDLThread"); + mSDLThread.start(); } + //Called when we lose the surface public void surfaceDestroyed(SurfaceHolder holder) { Log.v("SDL","Surface destroyed"); } - public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { - + //Called when the surface is resized + public void surfaceChanged(SurfaceHolder holder, int format, + int width, int height) { + Log.v("SDL","Surface resized"); } + //unused + public void onDraw(Canvas canvas) {} - boolean initEGL(){ + + //EGL functions + public boolean initEGL(){ Log.v("SDL","Starting up"); try{ - // Get an EGL instance EGL10 egl = (EGL10)EGLContext.getEGL(); - // Get to the default display. EGLDisplay dpy = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); - // We can now initialize EGL for that display int[] version = new int[2]; egl.eglInitialize(dpy, version); - // Specify a configuration for our opengl session - // and grab the first configuration that matches is int[] configSpec = { //EGL10.EGL_DEPTH_SIZE, 16, EGL10.EGL_NONE @@ -124,21 +165,21 @@ boolean initEGL(){ egl.eglChooseConfig(dpy, configSpec, configs, 1, num_config); EGLConfig config = configs[0]; - // Create an OpenGL ES context. This must be done only once EGLContext ctx = egl.eglCreateContext(dpy, config, EGL10.EGL_NO_CONTEXT, null); - // Create an EGL surface we can render into. EGLSurface surface = egl.eglCreateWindowSurface(dpy, config, this, null); - // Before we can issue GL commands, we need to make sure - // the context is current and bound to a surface. egl.eglMakeCurrent(dpy, surface, surface, ctx); mEGLContext = ctx; mEGLDisplay = dpy; mEGLSurface = surface; + }catch(Exception e){ Log.v("SDL", e + ""); + for(StackTraceElement s : e.getStackTrace()){ + Log.v("SDL", s.toString()); + } } Log.v("SDL","Done making!"); @@ -146,22 +187,8 @@ boolean initEGL(){ return true; } - public SDLSurface(Context context) { - super(context); - - getHolder().addCallback(this); - - } - - public void onDraw(Canvas canvas) { - - - } - - - public void flipBuffers(){ - //Log.v("test","Draw!"); - + //EGL buffer flip + public void flipEGL(){ try{ EGL10 egl = (EGL10)EGLContext.getEGL(); @@ -177,35 +204,13 @@ public void flipBuffers(){ }catch(Exception e){ - Log.v("SDL", e + ""); - } + Log.v("SDL", "flipEGL(): " + e); + for(StackTraceElement s : e.getStackTrace()){ + Log.v("SDL", s.toString()); + } + } } - } -/* -class TestRenderer implements GLSurfaceView.Renderer { - public void onSurfaceCreated(GL10 gl, EGLConfig config) { - nativeInit(); - } - - - - public void onSurfaceChanged(GL10 gl, int w, int h) { - //gl.glViewport(0, 0, w, h); - nativeResize(w, h); - } - - public void onDrawFrame(GL10 gl) { - nativeRender(); - } - - private static native void nativeInit(); - private static native void nativeResize(int w, int h); - private static native void nativeRender(); - private static native void nativeDone(); - -} -*/ From b839e9722877b950f6124d359a2f10942daf9d1b Mon Sep 17 00:00:00 2001 From: Paul Hunkin Date: Wed, 7 Jul 2010 00:43:23 +1200 Subject: [PATCH 19/34] Added preliminary keyboard event support --- android/testproject/jni/app-android.cpp | 16 ++++++ android/testproject/jni/lesson05.c | 17 ++++++- .../src/org/libsdl/android/SDLActivity.java | 51 ++++++++++++++----- src/events/SDL_keyboard.c | 16 ++++-- src/video/android/SDL_androidevents.c | 28 ++++++++++ src/video/android/SDL_androidevents.h | 1 + src/video/android/SDL_androidvideo.c | 2 + 7 files changed, 112 insertions(+), 19 deletions(-) diff --git a/android/testproject/jni/app-android.cpp b/android/testproject/jni/app-android.cpp index 54d541dd8..85e869156 100644 --- a/android/testproject/jni/app-android.cpp +++ b/android/testproject/jni/app-android.cpp @@ -36,6 +36,8 @@ jmethodID midCreateGLContext; jmethodID midFlipBuffers; extern "C" int SDL_main(); +extern "C" int Android_OnKeyDown(int keycode); +extern "C" int Android_OnKeyUp(int keycode); /******************************************************************************* Functions called by JNI @@ -77,6 +79,20 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved) return JNI_VERSION_1_4; } +extern "C" void Java_org_libsdl_android_SDLActivity_onNativeKeyDown(JNIEnv* env, + jobject obj, jint keycode){ + + int r = Android_OnKeyDown(keycode); + __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: native key down %d, %d\n", keycode, r); +} + +extern "C" void Java_org_libsdl_android_SDLActivity_onNativeKeyUp(JNIEnv* env, + jobject obj, jint keycode){ + + int r = Android_OnKeyUp(keycode); + __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: native key up %d, %d\n", keycode, r); +} + /******************************************************************************* diff --git a/android/testproject/jni/lesson05.c b/android/testproject/jni/lesson05.c index 40fa4afae..a1b27e00d 100644 --- a/android/testproject/jni/lesson05.c +++ b/android/testproject/jni/lesson05.c @@ -37,6 +37,8 @@ /* This is our SDL surface */ SDL_Surface *surface; +int rotation = 0; + /************************************** gluperspective implementation @@ -196,10 +198,20 @@ void handleKeyPress( SDL_keysym *keysym ) */ SDL_WM_ToggleFullScreen( surface ); break; + case SDLK_LEFT: + rotation -= 30; + break; + + case SDLK_RIGHT: + rotation += 30; + break; + default: break; } + __android_log_print(ANDROID_LOG_INFO, "SDL","Keycode: %d, %d, %d\n", keysym->sym, SDLK_LEFT, SDLK_RIGHT); + return; } @@ -231,6 +243,7 @@ int initGL( GLvoid ) /* Here goes our drawing code */ int drawGLScene( GLvoid ) { + static int Frames = 0; static int T0 = 0; @@ -253,14 +266,14 @@ int drawGLScene( GLvoid ) //Draw a triangle //glRotatef(iRot, 0, 1, 0); - glRotatef( Frames % 360, 0.0f, 1.0f, 0.0f ); + glRotatef( rotation, 0.0f, 1.0f, 0.0f ); glEnableClientState (GL_VERTEX_ARRAY); glEnableClientState (GL_COLOR_ARRAY); /* Rotate The Triangle On The Y axis ( NEW ) */ - glRotatef( Frames % 360, 0.0f, 1.0f, 0.0f ); + //glRotatef( Frames % 360, 0.0f, 1.0f, 0.0f ); /* GLES variant of drawing a triangle */ const GLfloat triVertices[][9] = { diff --git a/android/testproject/src/org/libsdl/android/SDLActivity.java b/android/testproject/src/org/libsdl/android/SDLActivity.java index edce904c6..c1a1ec5b0 100644 --- a/android/testproject/src/org/libsdl/android/SDLActivity.java +++ b/android/testproject/src/org/libsdl/android/SDLActivity.java @@ -4,14 +4,14 @@ import javax.microedition.khronos.opengles.GL10; import javax.microedition.khronos.egl.*; -import android.app.Activity; -import android.content.Context; -import android.view.SurfaceHolder; -import android.view.SurfaceView; -import android.os.Bundle; -import android.view.MotionEvent; +import android.app.*; +import android.content.*; +import android.view.*; +import android.os.*; import android.util.Log; import android.graphics.*; +import android.text.method.*; +import android.text.*; import java.lang.*; @@ -55,13 +55,14 @@ protected void onResume() { super.onResume(); } - - + //C functions we call public static native void nativeInit(); + public static native void onNativeKeyDown(int keycode); + public static native void onNativeKeyUp(int keycode); @@ -82,8 +83,7 @@ public static void flipBuffers(){ - - //EGL context creation + } @@ -104,7 +104,7 @@ public void run(){ Because of this, that's where we set up the SDL thread */ -class SDLSurface extends SurfaceView implements SurfaceHolder.Callback{ +class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, View.OnKeyListener { //This is what SDL runs in. It invokes SDL_main(), eventually private Thread mSDLThread; @@ -117,7 +117,12 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback{ //Startup public SDLSurface(Context context) { super(context); - getHolder().addCallback(this); + getHolder().addCallback(this); + + setFocusable(true); + setFocusableInTouchMode(true); + requestFocus(); + setOnKeyListener(this); } //Called when we have a valid drawing surface @@ -175,13 +180,13 @@ public boolean initEGL(){ mEGLDisplay = dpy; mEGLSurface = surface; + }catch(Exception e){ Log.v("SDL", e + ""); for(StackTraceElement s : e.getStackTrace()){ Log.v("SDL", s.toString()); } } - Log.v("SDL","Done making!"); return true; @@ -211,6 +216,26 @@ public void flipEGL(){ } } } + + + + + public boolean onKey(View v, int keyCode, KeyEvent event){ + + if(event.getAction() == KeyEvent.ACTION_DOWN){ + SDLActivity.onNativeKeyDown(keyCode); + return true; + } + + else if(event.getAction() == KeyEvent.ACTION_UP){ + SDLActivity.onNativeKeyUp(keyCode); + return true; + } + + return false; + } + + } diff --git a/src/events/SDL_keyboard.c b/src/events/SDL_keyboard.c index e6a9ca0ef..43a3346cc 100644 --- a/src/events/SDL_keyboard.c +++ b/src/events/SDL_keyboard.c @@ -694,8 +694,16 @@ SDL_SendKeyboardKey(int index, Uint8 state, SDL_scancode scancode) Uint16 modstate; Uint32 type; + if(!keyboard){ + return 7; + } + + if(!scancode){ + return 8; + } + if (!keyboard || !scancode) { - return 0; + return 1; } #if 0 printf("The '%s' key has been %s\n", SDL_GetScancodeName(scancode), @@ -788,7 +796,7 @@ SDL_SendKeyboardKey(int index, Uint8 state, SDL_scancode scancode) break; default: /* Invalid state -- bail */ - return 0; + return 2; } /* Drop events that don't change state */ @@ -796,14 +804,14 @@ SDL_SendKeyboardKey(int index, Uint8 state, SDL_scancode scancode) #if 0 printf("Keyboard event didn't change state - dropped!\n"); #endif - return 0; + return 3; } /* Update internal keyboard state */ keyboard->keystate[scancode] = state; /* Post the event, if desired */ - posted = 0; + posted = 4; if (SDL_GetEventState(type) == SDL_ENABLE) { SDL_Event event; event.key.type = type; diff --git a/src/video/android/SDL_androidevents.c b/src/video/android/SDL_androidevents.c index 2ca26e1eb..d29f585cc 100644 --- a/src/video/android/SDL_androidevents.c +++ b/src/video/android/SDL_androidevents.c @@ -30,6 +30,24 @@ #include "../../events/SDL_sysevents.h" #include "../../events/SDL_events_c.h" +#include "SDL_androidevents.h" + +void Android_InitEvents(){ + + SDL_Keyboard keyboard; + + SDL_zero(keyboard); + SDL_AddKeyboard(&keyboard, -1); + + SDLKey keymap[SDL_NUM_SCANCODES]; + + /* Add default scancode to key mapping */ + SDL_GetDefaultKeymap(keymap); + SDL_SetKeymap(0, 0, keymap, SDL_NUM_SCANCODES); + + +} + void Android_PumpEvents(_THIS) { @@ -49,4 +67,14 @@ Android_PumpEvents(_THIS) */ } +int +Android_OnKeyDown(int keycode){ + return SDL_SendKeyboardKey(0, SDL_PRESSED, (SDL_scancode)keycode); +} + +int +Android_OnKeyUp(int keycode){ + return SDL_SendKeyboardKey(0, SDL_RELEASED, (SDL_scancode)keycode); +} + /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/android/SDL_androidevents.h b/src/video/android/SDL_androidevents.h index b53b74ebe..4a7ba5299 100644 --- a/src/video/android/SDL_androidevents.h +++ b/src/video/android/SDL_androidevents.h @@ -24,5 +24,6 @@ #include "SDL_androidvideo.h" extern void Android_PumpEvents(_THIS); +extern void Android_InitEvents(); /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/android/SDL_androidvideo.c b/src/video/android/SDL_androidvideo.c index 5b43d66c6..0c39e3bec 100644 --- a/src/video/android/SDL_androidvideo.c +++ b/src/video/android/SDL_androidvideo.c @@ -132,6 +132,8 @@ Android_VideoInit(_THIS) SDL_zero(mode); SDL_AddDisplayMode(&_this->displays[0], &mode); + Android_InitEvents(); + /* We're done! */ return 0; } From 0c36b9bb164e688bd89dbd3aa06a98986b11502b Mon Sep 17 00:00:00 2001 From: Paul Hunkin Date: Tue, 27 Jul 2010 09:58:17 +0200 Subject: [PATCH 20/34] - Modified build system - Initial support for touch and key events --- Makefile.android | 3 ++- {build-scripts => android/scripts}/acc.sh | 0 {build-scripts => android/scripts}/ald.sh | 0 android/testproject/jni/app-android.cpp | 13 ++++++++-- .../src/org/libsdl/android/SDLActivity.java | 24 +++++++++++++++---- 5 files changed, 33 insertions(+), 7 deletions(-) rename {build-scripts => android/scripts}/acc.sh (100%) rename {build-scripts => android/scripts}/ald.sh (100%) diff --git a/Makefile.android b/Makefile.android index bf6b2838e..7959f76de 100755 --- a/Makefile.android +++ b/Makefile.android @@ -1,6 +1,7 @@ # Makefile to build the SDL library -ANDROID_NDK=/home/paul/Projects/gsoc/sdk/android-ndk-r4 +include ./android/config.cfg #get ANDROID_NDK + TOOLS_PATH=$(ANDROID_NDK)/build/prebuilt/linux-x86/arm-eabi-4.2.1/bin ANDROID_INCLUDES = -I$(ANDROID_NDK)/build/platforms/android-4/common/include \ -I$(ANDROID_NDK)/build/platforms/android-4/arch-arm/usr/include diff --git a/build-scripts/acc.sh b/android/scripts/acc.sh similarity index 100% rename from build-scripts/acc.sh rename to android/scripts/acc.sh diff --git a/build-scripts/ald.sh b/android/scripts/ald.sh similarity index 100% rename from build-scripts/ald.sh rename to android/scripts/ald.sh diff --git a/android/testproject/jni/app-android.cpp b/android/testproject/jni/app-android.cpp index 85e869156..2b7451aa0 100644 --- a/android/testproject/jni/app-android.cpp +++ b/android/testproject/jni/app-android.cpp @@ -83,14 +83,23 @@ extern "C" void Java_org_libsdl_android_SDLActivity_onNativeKeyDown(JNIEnv* env jobject obj, jint keycode){ int r = Android_OnKeyDown(keycode); - __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: native key down %d, %d\n", keycode, r); + __android_log_print(ANDROID_LOG_INFO, "SDL", + "SDL: native key down %d, %d\n", keycode, r); } extern "C" void Java_org_libsdl_android_SDLActivity_onNativeKeyUp(JNIEnv* env, jobject obj, jint keycode){ int r = Android_OnKeyUp(keycode); - __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: native key up %d, %d\n", keycode, r); + __android_log_print(ANDROID_LOG_INFO, "SDL", + "SDL: native key up %d, %d\n", keycode, r); +} + +extern "C" void Java_org_libsdl_android_SDLActivity_onNativeTouch(JNIEnv* env, + jobject obj, jint action, jfloat x, jfloat y, jfloat p){ + __android_log_print(ANDROID_LOG_INFO, "SDL", + "SDL: native touch event %d @ %f/%f, pressure %f\n", + action, x, y, p); } diff --git a/android/testproject/src/org/libsdl/android/SDLActivity.java b/android/testproject/src/org/libsdl/android/SDLActivity.java index c1a1ec5b0..d94e9bd9e 100644 --- a/android/testproject/src/org/libsdl/android/SDLActivity.java +++ b/android/testproject/src/org/libsdl/android/SDLActivity.java @@ -63,7 +63,8 @@ protected void onResume() { public static native void nativeInit(); public static native void onNativeKeyDown(int keycode); public static native void onNativeKeyUp(int keycode); - + public static native void onNativeTouch(int action, float x, + float y, float p); @@ -104,7 +105,8 @@ public void run(){ Because of this, that's where we set up the SDL thread */ -class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, View.OnKeyListener { +class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, + View.OnKeyListener, View.OnTouchListener { //This is what SDL runs in. It invokes SDL_main(), eventually private Thread mSDLThread; @@ -122,7 +124,8 @@ public SDLSurface(Context context) { setFocusable(true); setFocusableInTouchMode(true); requestFocus(); - setOnKeyListener(this); + setOnKeyListener(this); + setOnTouchListener(this); } //Called when we have a valid drawing surface @@ -219,7 +222,7 @@ public void flipEGL(){ - + //Key events public boolean onKey(View v, int keyCode, KeyEvent event){ if(event.getAction() == KeyEvent.ACTION_DOWN){ @@ -235,6 +238,19 @@ else if(event.getAction() == KeyEvent.ACTION_UP){ return false; } + //Touch events + public boolean onTouch(View v, MotionEvent event){ + + int action = event.getAction(); + float x = event.getX(); + float y = event.getY(); + float p = event.getPressure(); + + //TODO: Anything else we need to pass? + SDLActivity.onNativeTouch(action, x, y, p); + return true; + } + } From e61a95e7a0e299857d62adac6ff614ca87ce5dd0 Mon Sep 17 00:00:00 2001 From: Paul Hunkin Date: Tue, 27 Jul 2010 10:20:22 +0200 Subject: [PATCH 21/34] Shut down the C application properly on quit instead of crashing in the most horrible way possible --- android/testproject/jni/app-android.cpp | 46 ++++++++++++++----- android/testproject/jni/lesson05.c | 3 +- .../src/org/libsdl/android/SDLActivity.java | 4 +- 3 files changed, 40 insertions(+), 13 deletions(-) diff --git a/android/testproject/jni/app-android.cpp b/android/testproject/jni/app-android.cpp index 2b7451aa0..762062c38 100644 --- a/android/testproject/jni/app-android.cpp +++ b/android/testproject/jni/app-android.cpp @@ -38,22 +38,29 @@ jmethodID midFlipBuffers; extern "C" int SDL_main(); extern "C" int Android_OnKeyDown(int keycode); extern "C" int Android_OnKeyUp(int keycode); +extern "C" int SDL_SendQuit(); + +//If we're not the active app, don't try to render +bool bRenderingEnabled = false; /******************************************************************************* Functions called by JNI *******************************************************************************/ -extern "C" void Java_org_libsdl_android_SDLActivity_nativeInit( JNIEnv* env, jobject obj ) -{ - __android_log_print(ANDROID_LOG_INFO, "SDL", "JNI: NativeInit"); +extern "C" void Java_org_libsdl_android_SDLActivity_nativeInit( JNIEnv* env, + jobject obj ){ + + __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: Native Init"); mEnv = env; + bRenderingEnabled = true; + SDL_main(); } -extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved) -{ +extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved){ + JNIEnv* env = NULL; jint result = -1; @@ -85,6 +92,7 @@ extern "C" void Java_org_libsdl_android_SDLActivity_onNativeKeyDown(JNIEnv* env int r = Android_OnKeyDown(keycode); __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: native key down %d, %d\n", keycode, r); + } extern "C" void Java_org_libsdl_android_SDLActivity_onNativeKeyUp(JNIEnv* env, @@ -93,13 +101,28 @@ extern "C" void Java_org_libsdl_android_SDLActivity_onNativeKeyUp(JNIEnv* env, int r = Android_OnKeyUp(keycode); __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: native key up %d, %d\n", keycode, r); + } extern "C" void Java_org_libsdl_android_SDLActivity_onNativeTouch(JNIEnv* env, jobject obj, jint action, jfloat x, jfloat y, jfloat p){ + __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: native touch event %d @ %f/%f, pressure %f\n", action, x, y, p); + +} + +extern "C" void Java_org_libsdl_android_SDLActivity_nativeQuit( JNIEnv* env, + jobject obj ){ + + //Stop rendering as we're no longer in the foreground + bRenderingEnabled = false; + + //Inject a SDL_QUIT event + int r = SDL_SendQuit(); + + __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: Native quit %d", r); } @@ -110,17 +133,18 @@ extern "C" void Java_org_libsdl_android_SDLActivity_onNativeTouch(JNIEnv* env, extern "C" void sdl_create_context(){ __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: sdl_create_context()\n"); - mEnv->CallStaticVoidMethod(mActivityInstance, midCreateGLContext ); - __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: sdl_create_context() return\n"); + bRenderingEnabled = true; - // exit(1); + mEnv->CallStaticVoidMethod(mActivityInstance, midCreateGLContext ); } extern "C" void sdl_render(){ - //When we get here, we've accumulated a full frame - //__android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: sdl_render()"); - + if(!bRenderingEnabled){ + return; + } + + //When we get here, we've accumulated a full frame mEnv->CallStaticVoidMethod(mActivityInstance, midFlipBuffers ); } diff --git a/android/testproject/jni/lesson05.c b/android/testproject/jni/lesson05.c index a1b27e00d..553354737 100644 --- a/android/testproject/jni/lesson05.c +++ b/android/testproject/jni/lesson05.c @@ -348,7 +348,7 @@ int drawGLScene( GLvoid ) } } - + rotation++; return( TRUE ); } @@ -463,6 +463,7 @@ int SDL_main( int argc, char **argv ) case SDL_QUIT: /* handle quit requests */ done = TRUE; + __android_log_print(ANDROID_LOG_INFO, "SDL","App is shutting down\n"); break; default: break; diff --git a/android/testproject/src/org/libsdl/android/SDLActivity.java b/android/testproject/src/org/libsdl/android/SDLActivity.java index d94e9bd9e..2dc67ef97 100644 --- a/android/testproject/src/org/libsdl/android/SDLActivity.java +++ b/android/testproject/src/org/libsdl/android/SDLActivity.java @@ -61,6 +61,7 @@ protected void onResume() { //C functions we call public static native void nativeInit(); + public static native void nativeQuit(); public static native void onNativeKeyDown(int keycode); public static native void onNativeKeyUp(int keycode); public static native void onNativeTouch(int action, float x, @@ -69,7 +70,6 @@ public static native void onNativeTouch(int action, float x, - //Java functions called from C private static void createGLContext(){ mSurface.initEGL(); @@ -139,6 +139,8 @@ public void surfaceCreated(SurfaceHolder holder) { //Called when we lose the surface public void surfaceDestroyed(SurfaceHolder holder) { Log.v("SDL","Surface destroyed"); + + SDLActivity.nativeQuit(); } //Called when the surface is resized From b788f098b518ceeadc107351c5525ffd0646197b Mon Sep 17 00:00:00 2001 From: Paul Hunkin Date: Tue, 27 Jul 2010 10:49:11 +0200 Subject: [PATCH 22/34] Added resize hander stub and initial screen size setter --- android/testproject/jni/app-android.cpp | 57 ++++++++++++++----- android/testproject/jni/lesson05.c | 2 +- .../src/org/libsdl/android/SDLActivity.java | 14 +++++ src/video/android/SDL_androidevents.c | 5 ++ src/video/android/SDL_androidvideo.c | 16 +++++- 5 files changed, 76 insertions(+), 18 deletions(-) diff --git a/android/testproject/jni/app-android.cpp b/android/testproject/jni/app-android.cpp index 762062c38..5a43bec4b 100644 --- a/android/testproject/jni/app-android.cpp +++ b/android/testproject/jni/app-android.cpp @@ -38,6 +38,8 @@ jmethodID midFlipBuffers; extern "C" int SDL_main(); extern "C" int Android_OnKeyDown(int keycode); extern "C" int Android_OnKeyUp(int keycode); +extern "C" void Android_SetScreenResolution(int width, int height); +extern "C" void Android_OnResize(int width, int height, int format); extern "C" int SDL_SendQuit(); //If we're not the active app, don't try to render @@ -47,18 +49,7 @@ bool bRenderingEnabled = false; Functions called by JNI *******************************************************************************/ -extern "C" void Java_org_libsdl_android_SDLActivity_nativeInit( JNIEnv* env, - jobject obj ){ - - __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: Native Init"); - - mEnv = env; - - bRenderingEnabled = true; - - SDL_main(); -} - +//Library init extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved){ JNIEnv* env = NULL; @@ -86,7 +77,21 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved){ return JNI_VERSION_1_4; } -extern "C" void Java_org_libsdl_android_SDLActivity_onNativeKeyDown(JNIEnv* env, +//Start up the SDL app +extern "C" void Java_org_libsdl_android_SDLActivity_nativeInit( JNIEnv* env, + jobject obj ){ + + __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: Native Init"); + + mEnv = env; + + bRenderingEnabled = true; + + SDL_main(); +} + +//Keydown +extern "C" void Java_org_libsdl_android_SDLActivity_onNativeKeyDown(JNIEnv* env, jobject obj, jint keycode){ int r = Android_OnKeyDown(keycode); @@ -95,7 +100,8 @@ extern "C" void Java_org_libsdl_android_SDLActivity_onNativeKeyDown(JNIEnv* env } -extern "C" void Java_org_libsdl_android_SDLActivity_onNativeKeyUp(JNIEnv* env, +//Keyup +extern "C" void Java_org_libsdl_android_SDLActivity_onNativeKeyUp(JNIEnv* env, jobject obj, jint keycode){ int r = Android_OnKeyUp(keycode); @@ -104,15 +110,19 @@ extern "C" void Java_org_libsdl_android_SDLActivity_onNativeKeyUp(JNIEnv* env, } -extern "C" void Java_org_libsdl_android_SDLActivity_onNativeTouch(JNIEnv* env, +//Touch +extern "C" void Java_org_libsdl_android_SDLActivity_onNativeTouch(JNIEnv* env, jobject obj, jint action, jfloat x, jfloat y, jfloat p){ __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: native touch event %d @ %f/%f, pressure %f\n", action, x, y, p); + + //TODO: Pass this off to the SDL multitouch stuff } +//Quit extern "C" void Java_org_libsdl_android_SDLActivity_nativeQuit( JNIEnv* env, jobject obj ){ @@ -125,6 +135,23 @@ extern "C" void Java_org_libsdl_android_SDLActivity_nativeQuit( JNIEnv* env, __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: Native quit %d", r); } +//Screen size +extern "C" void Java_org_libsdl_android_SDLActivity_nativeSetScreenSize( + JNIEnv* env, jobject obj, jint width, jint height){ + + __android_log_print(ANDROID_LOG_INFO, "SDL", + "SDL: Set screen size on init: %d/%d\n", width, height); + Android_SetScreenResolution(width, height); + +} + +//Resize +extern "C" void Java_org_libsdl_android_SDLActivity_onNativeResize( + JNIEnv* env, jobject obj, jint width, + jint height, jint format){ + Android_OnResize(width, height, format); +} + /******************************************************************************* diff --git a/android/testproject/jni/lesson05.c b/android/testproject/jni/lesson05.c index 553354737..d5f2b28fb 100644 --- a/android/testproject/jni/lesson05.c +++ b/android/testproject/jni/lesson05.c @@ -27,7 +27,7 @@ /* screen width, height, and bit depth */ #define SCREEN_WIDTH 320 -#define SCREEN_HEIGHT 480 +#define SCREEN_HEIGHT 430 #define SCREEN_BPP 16 /* Define our booleans */ diff --git a/android/testproject/src/org/libsdl/android/SDLActivity.java b/android/testproject/src/org/libsdl/android/SDLActivity.java index 2dc67ef97..da91a6d29 100644 --- a/android/testproject/src/org/libsdl/android/SDLActivity.java +++ b/android/testproject/src/org/libsdl/android/SDLActivity.java @@ -62,10 +62,12 @@ protected void onResume() { //C functions we call public static native void nativeInit(); public static native void nativeQuit(); + public static native void nativeSetScreenSize(int width, int height); public static native void onNativeKeyDown(int keycode); public static native void onNativeKeyUp(int keycode); public static native void onNativeTouch(int action, float x, float y, float p); + public static native void onNativeResize(int x, int y, int format); @@ -95,6 +97,8 @@ class SDLRunner implements Runnable{ public void run(){ //Runs SDL_main() SDLActivity.nativeInit(); + + Log.v("SDL","SDL thread terminated"); } } @@ -132,6 +136,14 @@ public SDLSurface(Context context) { public void surfaceCreated(SurfaceHolder holder) { Log.v("SDL","Surface created"); + int width = getWidth(); + int height = getHeight(); + + //Set the width and height variables in C before we start SDL so we have + //it available on init + SDLActivity.nativeSetScreenSize(width, height); + + //Now start up the C app thread mSDLThread = new Thread(new SDLRunner(), "SDLThread"); mSDLThread.start(); } @@ -147,6 +159,8 @@ public void surfaceDestroyed(SurfaceHolder holder) { public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { Log.v("SDL","Surface resized"); + + SDLActivity.onNativeResize(width, height, format); } //unused diff --git a/src/video/android/SDL_androidevents.c b/src/video/android/SDL_androidevents.c index d29f585cc..0a2bf1051 100644 --- a/src/video/android/SDL_androidevents.c +++ b/src/video/android/SDL_androidevents.c @@ -67,6 +67,11 @@ Android_PumpEvents(_THIS) */ } + +void Android_OnResize(int width, int height, int format){ + +} + int Android_OnKeyDown(int keycode){ return SDL_SendKeyboardKey(0, SDL_PRESSED, (SDL_scancode)keycode); diff --git a/src/video/android/SDL_androidvideo.c b/src/video/android/SDL_androidvideo.c index 0c39e3bec..cdb7cea34 100644 --- a/src/video/android/SDL_androidvideo.c +++ b/src/video/android/SDL_androidvideo.c @@ -57,6 +57,12 @@ extern void Android_GL_DeleteContext(_THIS, SDL_GLContext context); /* Android driver bootstrap functions */ +//These are filled in with real values in Android_SetScreenResolution on +//init (before SDL_Main()) +static int iScreenWidth = 320; +static int iScreenHeight = 240; + + static int Android_Available(void) { @@ -120,8 +126,8 @@ Android_VideoInit(_THIS) /* Use a fake 32-bpp desktop mode */ mode.format = SDL_PIXELFORMAT_RGB888; - mode.w = 320; - mode.h = 480; + mode.w = iScreenWidth; + mode.h = iScreenHeight; mode.refresh_rate = 0; mode.driverdata = NULL; if (SDL_AddBasicVideoDisplay(&mode) < 0) { @@ -150,5 +156,11 @@ Android_VideoQuit(_THIS) } +void Android_SetScreenResolution(int width, int height){ + iScreenWidth = width; + iScreenHeight = height; +} + + /* vi: set ts=4 sw=4 expandtab: */ From 2fabc2d7bc6ef651b3fc57b78569c7bdce815186 Mon Sep 17 00:00:00 2001 From: Paul Hunkin Date: Tue, 27 Jul 2010 11:02:07 +0200 Subject: [PATCH 23/34] OK, /actually/ fixed the nativeQuit() crash this time --- .../testproject/src/org/libsdl/android/SDLActivity.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/android/testproject/src/org/libsdl/android/SDLActivity.java b/android/testproject/src/org/libsdl/android/SDLActivity.java index da91a6d29..e54fac128 100644 --- a/android/testproject/src/org/libsdl/android/SDLActivity.java +++ b/android/testproject/src/org/libsdl/android/SDLActivity.java @@ -153,6 +153,13 @@ public void surfaceDestroyed(SurfaceHolder holder) { Log.v("SDL","Surface destroyed"); SDLActivity.nativeQuit(); + + //Now wait for the SDL thread to quit + try{ + mSDLThread.wait(); + }catch(Exception e){ + Log.v("SDL","Problem stopping thread: " + e); + } } //Called when the surface is resized From 4766b872ff8d2456a03baf222ec21e5212f0b7fb Mon Sep 17 00:00:00 2001 From: Paul Hunkin Date: Tue, 27 Jul 2010 11:34:43 +0200 Subject: [PATCH 24/34] Added stub android sound system --- Makefile.android | 2 +- src/audio/SDL_audio.c | 4 + src/audio/android/SDL_androidaudio.c | 106 +++++++++++++++++++++++++++ src/audio/android/SDL_androidaudio.h | 42 +++++++++++ src/audio/android/SDL_androidaudio.o | Bin 0 -> 8744 bytes 5 files changed, 153 insertions(+), 1 deletion(-) create mode 100644 src/audio/android/SDL_androidaudio.c create mode 100644 src/audio/android/SDL_androidaudio.h create mode 100644 src/audio/android/SDL_androidaudio.o diff --git a/Makefile.android b/Makefile.android index 7959f76de..5a7da8748 100755 --- a/Makefile.android +++ b/Makefile.android @@ -28,7 +28,7 @@ SOURCES = \ src/timer/*.c \ src/video/*.c \ src/power/*.c \ - src/audio/dummy/*.c \ + src/audio/android/*.c \ src/video/android/*.c \ src/joystick/dummy/*.c \ src/haptic/dummy/*.c \ diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c index fe2f3ff86..572cdb4a7 100644 --- a/src/audio/SDL_audio.c +++ b/src/audio/SDL_audio.c @@ -69,6 +69,7 @@ extern AudioBootStrap MMEAUDIO_bootstrap; extern AudioBootStrap DART_bootstrap; extern AudioBootStrap NDSAUD_bootstrap; extern AudioBootStrap FUSIONSOUND_bootstrap; +extern AudioBootStrap ANDROIDAUD_bootstrap; /* Available audio drivers */ @@ -136,6 +137,9 @@ static const AudioBootStrap *const bootstrap[] = { #endif #if SDL_AUDIO_DRIVER_FUSIONSOUND &FUSIONSOUND_bootstrap, +#endif +#if SDL_AUDIO_DRIVER_ANDROID + &ANDROIDAUD_bootstrap, #endif NULL }; diff --git a/src/audio/android/SDL_androidaudio.c b/src/audio/android/SDL_androidaudio.c new file mode 100644 index 000000000..1b26d5170 --- /dev/null +++ b/src/audio/android/SDL_androidaudio.c @@ -0,0 +1,106 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2010 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org + + This file written by Ryan C. Gordon (icculus@icculus.org) +*/ +#include "SDL_config.h" + +/* Output audio to Android */ + +#include "SDL_audio.h" +#include "../SDL_audio_c.h" +#include "SDL_androidaudio.h" + +#include + +static int +AndroidAUD_OpenDevice(_THIS, const char *devname, int iscapture) +{ + //TODO: Sample rates etc + __android_log_print(ANDROID_LOG_INFO, "SDL", "AndroidAudio Open\n"); + + return 1; +} + +static void +AndroidAUD_PlayDevice(_THIS) +{ + __android_log_print(ANDROID_LOG_INFO, "SDL", "AndroidAudio Play\n"); + + + + //playGenericSound(this->hidden->mixbuf, this->hidden->mixlen); + +#if 0 +// sound->data = this->hidden->mixbuf;/* pointer to raw audio data */ +// sound->len = this->hidden->mixlen; /* size of raw data pointed to above */ +// sound->rate = 22050; /* sample rate = 22050Hz */ +// sound->vol = 127; /* volume [0..127] for [min..max] */ +// sound->pan = 64; /* balance [0..127] for [left..right] */ +// sound->format = 0; /* 0 for 16-bit, 1 for 8-bit */ +// playSound(sound); +#endif +} + + +static Uint8 * +AndroidAUD_GetDeviceBuf(_THIS) +{ + return this->hidden->mixbuf; /* is this right? */ +} + +static void +AndroidAUD_WaitDevice(_THIS) +{ + /* stub */ +} + +static void +AndroidAUD_CloseDevice(_THIS) +{ + /* stub */ +} + +static int +AndroidAUD_Init(SDL_AudioDriverImpl * impl) +{ + /* Set the function pointers */ + impl->OpenDevice = AndroidAUD_OpenDevice; + impl->PlayDevice = AndroidAUD_PlayDevice; + impl->WaitDevice = AndroidAUD_WaitDevice; + impl->GetDeviceBuf = AndroidAUD_GetDeviceBuf; + impl->CloseDevice = AndroidAUD_CloseDevice; + + /* and the capabilities */ + impl->HasCaptureSupport = 0; //TODO + impl->OnlyHasDefaultOutputDevice = 1; + impl->OnlyHasDefaultInputDevice = 1; + + __android_log_print(ANDROID_LOG_INFO, "SDL","Audio init\n"); + + return 1; /* this audio target is available. */ +} + +AudioBootStrap ANDROIDAUD_bootstrap = { + "android", "SDL Android audio driver", AndroidAUD_Init, 0 /*1? */ +}; + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/audio/android/SDL_androidaudio.h b/src/audio/android/SDL_androidaudio.h new file mode 100644 index 000000000..7bf55e33b --- /dev/null +++ b/src/audio/android/SDL_androidaudio.h @@ -0,0 +1,42 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2010 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +#ifndef _SDL_androidaudio_h +#define _SDL_androidaudio_h + +#include "../SDL_sysaudio.h" + +/* Hidden "this" pointer for the audio functions */ +#define _THIS SDL_AudioDevice *this + +struct SDL_PrivateAudioData +{ + /* The file descriptor for the audio device */ + Uint8 *mixbuf; + Uint32 mixlen; + Uint32 write_delay; + Uint32 initial_calls; +}; + +#endif /* _SDL_androidaudio_h */ +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/audio/android/SDL_androidaudio.o b/src/audio/android/SDL_androidaudio.o new file mode 100644 index 0000000000000000000000000000000000000000..2068b1a726b866209ac8f3ea3bc98740919ed2c1 GIT binary patch literal 8744 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 Tr0Da)mxRYODXzVTts?&)>|2NI literal 0 HcmV?d00001 From dcc7155c344459249627c089b7cc41b6e025cb34 Mon Sep 17 00:00:00 2001 From: Paul Hunkin Date: Tue, 27 Jul 2010 11:35:06 +0200 Subject: [PATCH 25/34] Updated test app to init the sound system --- android/testproject/jni/lesson05.c | 9 +++++++++ include/SDL_config_android.h | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/android/testproject/jni/lesson05.c b/android/testproject/jni/lesson05.c index d5f2b28fb..3188e015b 100644 --- a/android/testproject/jni/lesson05.c +++ b/android/testproject/jni/lesson05.c @@ -425,6 +425,15 @@ int SDL_main( int argc, char **argv ) /* resize the initial window */ resizeWindow( SCREEN_WIDTH, SCREEN_HEIGHT ); + /* Load the SDL library */ + if (SDL_Init(SDL_INIT_AUDIO) < 0) { + __android_log_print(ANDROID_LOG_INFO, "SDL","Couldn't initialize SDL Audio: %s\n", SDL_GetError()); + return (1); + }else{ + __android_log_print(ANDROID_LOG_INFO, "SDL","Init audio ok\n"); + } + + /* wait for events */ while ( !done ) { diff --git a/include/SDL_config_android.h b/include/SDL_config_android.h index 9f8666e3c..348f9341e 100755 --- a/include/SDL_config_android.h +++ b/include/SDL_config_android.h @@ -47,7 +47,7 @@ typedef unsigned int uint32_t; typedef unsigned int size_t; //typedef unsigned long uintptr_t; -#define SDL_AUDIO_DRIVER_DUMMY 1 +#define SDL_AUDIO_DRIVER_ANDROID 1 #define SDL_CDROM_DISABLED 1 From 94059431901bd4465345a03de9f92540ef895d29 Mon Sep 17 00:00:00 2001 From: Paul Hunkin Date: Tue, 27 Jul 2010 15:23:09 +0200 Subject: [PATCH 26/34] Oops, I wasn't using pthreads. Fixed so we can have mutexes and stuff --- Makefile.android | 4 +- include/SDL_config_android.h | 77 ++++++++++++++++++++++++++++++++++-- 2 files changed, 75 insertions(+), 6 deletions(-) diff --git a/Makefile.android b/Makefile.android index 5a7da8748..2ba3c8347 100755 --- a/Makefile.android +++ b/Makefile.android @@ -33,8 +33,8 @@ SOURCES = \ src/joystick/dummy/*.c \ src/haptic/dummy/*.c \ src/atomic/dummy/*.c \ - src/thread/generic/*.c \ - src/timer/dummy/*.c \ + src/thread/pthread/*.c \ + src/timer/unix/*.c \ src/loadso/dummy/*.c \ OBJECTS = $(shell echo $(SOURCES) | sed -e 's,\.c,\.o,g') diff --git a/include/SDL_config_android.h b/include/SDL_config_android.h index 348f9341e..a38270943 100755 --- a/include/SDL_config_android.h +++ b/include/SDL_config_android.h @@ -42,6 +42,74 @@ typedef signed int int32_t; typedef unsigned int uint32_t; */ + +#define HAVE_ALLOCA_H 1 +#define HAVE_SYS_TYPES_H 1 +#define HAVE_STDIO_H 1 +#define STDC_HEADERS 1 +#define HAVE_STRING_H 1 +#define HAVE_INTTYPES_H 1 +#define HAVE_STDINT_H 1 +#define HAVE_CTYPE_H 1 +#define HAVE_MATH_H 1 +#define HAVE_SIGNAL_H 1 + +/* C library functions */ +#define HAVE_MALLOC 1 +#define HAVE_CALLOC 1 +#define HAVE_REALLOC 1 +#define HAVE_FREE 1 +#define HAVE_ALLOCA 1 +#define HAVE_GETENV 1 +#define HAVE_SETENV 1 +#define HAVE_PUTENV 1 +#define HAVE_SETENV 1 +#define HAVE_UNSETENV 1 +#define HAVE_QSORT 1 +#define HAVE_ABS 1 +#define HAVE_BCOPY 1 +#define HAVE_MEMSET 1 +#define HAVE_MEMCPY 1 +#define HAVE_MEMMOVE 1 +#define HAVE_MEMCMP 1 +#define HAVE_STRLEN 1 +#define HAVE_STRLCPY 1 +#define HAVE_STRLCAT 1 +#define HAVE_STRDUP 1 +#define HAVE_STRCHR 1 +#define HAVE_STRRCHR 1 +#define HAVE_STRSTR 1 +#define HAVE_STRTOL 1 +#define HAVE_STRTOUL 1 +#define HAVE_STRTOLL 1 +#define HAVE_STRTOULL 1 +#define HAVE_STRTOD 1 +#define HAVE_ATOI 1 +#define HAVE_ATOF 1 +#define HAVE_STRCMP 1 +#define HAVE_STRNCMP 1 +#define HAVE_STRCASECMP 1 +#define HAVE_STRNCASECMP 1 +#define HAVE_SSCANF 1 +#define HAVE_SNPRINTF 1 +#define HAVE_VSNPRINTF 1 +#define HAVE_CEIL 1 +#define HAVE_COPYSIGN 1 +#define HAVE_COS 1 +#define HAVE_COSF 1 +#define HAVE_FABS 1 +#define HAVE_FLOOR 1 +#define HAVE_LOG 1 +#define HAVE_POW 1 +#define HAVE_SCALBN 1 +#define HAVE_SIN 1 +#define HAVE_SINF 1 +#define HAVE_SQRT 1 +#define HAVE_SIGACTION 1 +#define HAVE_SETJMP 1 +#define HAVE_NANOSLEEP 1 +#define HAVE_SYSCONF 1 + #define SIZEOF_VOIDP 4 typedef unsigned int size_t; @@ -57,11 +125,12 @@ typedef unsigned int size_t; #define SDL_LOADSO_DISABLED 1 -#define SDL_THREADS_DISABLED 1 - -#define SDL_TIMERS_DISABLED 1 +/* Enable various threading systems */ +#define SDL_THREAD_PTHREAD 1 +#define SDL_THREAD_PTHREAD_RECURSIVE_MUTEX 1 -#define SDL_TIMER_UNIX 1 +/* Enable various timer systems */ +#define SDL_TIMER_UNIX 1 #define SDL_VIDEO_DRIVER_ANDROID 1 From 7cec8fc84284af73e5cc936346f6e1d59ff402f6 Mon Sep 17 00:00:00 2001 From: Paul Hunkin Date: Tue, 27 Jul 2010 21:20:17 +0200 Subject: [PATCH 27/34] Added accelerometer 'joystick' --- src/joystick/android/SDL_sysjoystick.c | 106 +++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 src/joystick/android/SDL_sysjoystick.c diff --git a/src/joystick/android/SDL_sysjoystick.c b/src/joystick/android/SDL_sysjoystick.c new file mode 100644 index 000000000..9088cc4bf --- /dev/null +++ b/src/joystick/android/SDL_sysjoystick.c @@ -0,0 +1,106 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2010 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ + +#include "SDL_config.h" + +#ifdef SDL_JOYSTICK_ANDROID + +/* This is the system specific header for the SDL joystick API */ +#include /* For the definition of NULL */ + +#include "SDL_error.h" +#include "SDL_events.h" +#include "SDL_joystick.h" +#include "../SDL_sysjoystick.h" +#include "../SDL_joystick_c.h" + +extern float fLastAccelerometer[3]; + +const char *accelerometerName = "Android accelerometer"; + +/* Function to scan the system for joysticks. + * This function should set SDL_numjoysticks to the number of available + * joysticks. Joystick 0 should be the system default joystick. + * It should return 0, or -1 on an unrecoverable fatal error. + */ +int +SDL_SYS_JoystickInit(void) +{ + SDL_numjoysticks = 1; + +return (1); +} + +/* Function to get the device-dependent name of a joystick */ +const char * +SDL_SYS_JoystickName(int index) +{ + if (!index) + return accelerometerName; + SDL_SetError("No joystick available with that index"); + return (NULL); +} + +/* Function to open a joystick for use. + The joystick to open is specified by the index field of the joystick. + This should fill the nbuttons and naxes fields of the joystick structure. + It returns 0, or -1 if there is an error. + */ +int +SDL_SYS_JoystickOpen(SDL_Joystick * joystick) +{ + joystick->nbuttons = 0; + joystick->nhats = 0; + joystick->nballs = 0; + joystick->naxes = 3; + joystick->name = accelerometerName; + return 0; +} + + +/* Function to update the state of a joystick - called as a device poll. + * This function shouldn't update the joystick structure directly, + * but instead should call SDL_PrivateJoystick*() to deliver events + * and update joystick device state. + */ + void +SDL_SYS_JoystickUpdate(SDL_Joystick * joystick) +{ + int i=0; + for(i=0;i<3;i++){ + SDL_PrivateJoystickAxis(joystick, i, fLastAccelerometer[i]); + } +} + +/* Function to close a joystick after use */ +void +SDL_SYS_JoystickClose(SDL_Joystick * joystick) +{ +} + +/* Function to perform any system-specific joystick related cleanup */ +void +SDL_SYS_JoystickQuit(void) +{ +} + +#endif /* SDL_JOYSTICK_NDS */ From d2697435f07be89e25417e6c66412bdcadc82260 Mon Sep 17 00:00:00 2001 From: Paul Hunkin Date: Tue, 27 Jul 2010 21:21:24 +0200 Subject: [PATCH 28/34] - Cleaned up a bunch of code - Added 'feature' enable/disable so we're not running accel/sound/whatever in Java when we don't need to be - More work on the sound system. But it still crashes pretty horribly, not sure why yet. --- Makefile.android | 2 +- android/testproject/jni/app-android.cpp | 35 ++++++- android/testproject/jni/lesson05.c | 94 ++++++++++++++++-- .../src/org/libsdl/android/SDLActivity.java | 51 +++++++++- include/SDL_config_android.h | 2 +- src/audio/SDL_audio.c | 2 + src/audio/android/SDL_androidaudio.o | Bin 8744 -> 8760 bytes src/video/android/SDL_androidgl.c | 8 +- 8 files changed, 174 insertions(+), 20 deletions(-) diff --git a/Makefile.android b/Makefile.android index 2ba3c8347..9cf9f2855 100755 --- a/Makefile.android +++ b/Makefile.android @@ -30,7 +30,7 @@ SOURCES = \ src/power/*.c \ src/audio/android/*.c \ src/video/android/*.c \ - src/joystick/dummy/*.c \ + src/joystick/android/*.c \ src/haptic/dummy/*.c \ src/atomic/dummy/*.c \ src/thread/pthread/*.c \ diff --git a/android/testproject/jni/app-android.cpp b/android/testproject/jni/app-android.cpp index 5a43bec4b..d8811caa6 100644 --- a/android/testproject/jni/app-android.cpp +++ b/android/testproject/jni/app-android.cpp @@ -34,6 +34,7 @@ jclass mActivityInstance; //method signatures jmethodID midCreateGLContext; jmethodID midFlipBuffers; +jmethodID midEnableFeature; extern "C" int SDL_main(); extern "C" int Android_OnKeyDown(int keycode); @@ -41,10 +42,18 @@ extern "C" int Android_OnKeyUp(int keycode); extern "C" void Android_SetScreenResolution(int width, int height); extern "C" void Android_OnResize(int width, int height, int format); extern "C" int SDL_SendQuit(); +extern "C" void Android_EnableFeature(int featureid, bool enabled); //If we're not the active app, don't try to render bool bRenderingEnabled = false; +//Feature IDs +static const int FEATURE_SOUND = 1; +static const int FEATURE_ACCEL = 2; + +//Accelerometer data storage +float fLastAccelerometer[3]; + /******************************************************************************* Functions called by JNI *******************************************************************************/ @@ -67,8 +76,9 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved){ mActivityInstance = cls; midCreateGLContext = mEnv->GetStaticMethodID(cls,"createGLContext","()V"); midFlipBuffers = mEnv->GetStaticMethodID(cls,"flipBuffers","()V"); + midEnableFeature = mEnv->GetStaticMethodID(cls,"enableFeature","(I, I)V"); - if(!midCreateGLContext || !midFlipBuffers){ + if(!midCreateGLContext || !midFlipBuffers || !midEnableFeature){ __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: Bad mids\n"); }else{ __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: Good mids\n"); @@ -84,9 +94,10 @@ extern "C" void Java_org_libsdl_android_SDLActivity_nativeInit( JNIEnv* env, __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: Native Init"); mEnv = env; - bRenderingEnabled = true; + Android_EnableFeature(FEATURE_ACCEL, true); + SDL_main(); } @@ -152,12 +163,20 @@ extern "C" void Java_org_libsdl_android_SDLActivity_onNativeResize( Android_OnResize(width, height, format); } +extern "C" void Java_org_libsdl_android_SDLActivity_onNativeAccel( + JNIEnv* env, jobject obj, + jfloat x, jfloat y, jfloat z){ + fLastAccelerometer[0] = x; + fLastAccelerometer[1] = y; + fLastAccelerometer[2] = z; +} + /******************************************************************************* - Functions called by SDL + Functions called by SDL into Java *******************************************************************************/ -extern "C" void sdl_create_context(){ +extern "C" void Android_CreateContext(){ __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: sdl_create_context()\n"); bRenderingEnabled = true; @@ -165,7 +184,7 @@ extern "C" void sdl_create_context(){ mEnv->CallStaticVoidMethod(mActivityInstance, midCreateGLContext ); } -extern "C" void sdl_render(){ +extern "C" void Android_Render(){ if(!bRenderingEnabled){ return; @@ -175,3 +194,9 @@ extern "C" void sdl_render(){ mEnv->CallStaticVoidMethod(mActivityInstance, midFlipBuffers ); } +extern "C" void Android_EnableFeature(int featureid, bool enabled){ + + mEnv->CallStaticVoidMethod(mActivityInstance, midFlipBuffers, + featureid, (int)enabled); +} + diff --git a/android/testproject/jni/lesson05.c b/android/testproject/jni/lesson05.c index 3188e015b..c53aab4c1 100644 --- a/android/testproject/jni/lesson05.c +++ b/android/testproject/jni/lesson05.c @@ -14,6 +14,8 @@ #include #include +#include + #include @@ -353,6 +355,89 @@ int drawGLScene( GLvoid ) return( TRUE ); } + +struct +{ + SDL_AudioSpec spec; + Uint8 *sound; /* Pointer to wave data */ + Uint32 soundlen; /* Length of wave data */ + int soundpos; /* Current play position */ +} wave; + +void SDLCALL +fillerup(void *unused, Uint8 * stream, int len) +{ + __android_log_print(ANDROID_LOG_INFO, "SDL","FILLERUP\n"); + + Uint8 *waveptr; + int waveleft; + + /* Set up the pointers */ + waveptr = wave.sound + wave.soundpos; + waveleft = wave.soundlen - wave.soundpos; + + /* Go! */ + while (waveleft <= len) { + SDL_memcpy(stream, waveptr, waveleft); + stream += waveleft; + len -= waveleft; + waveptr = wave.sound; + waveleft = wave.soundlen; + wave.soundpos = 0; + } + SDL_memcpy(stream, waveptr, len); + wave.soundpos += len; +} + +void testAudio(){ + + const char *file = "/sdcard/sample.wav"; + + /* Load the SDL library */ + if (SDL_Init(SDL_INIT_AUDIO) < 0) { + __android_log_print(ANDROID_LOG_INFO, "SDL","Couldn't initialize SDL Audio: %s\n", SDL_GetError()); + return; + }else{ + __android_log_print(ANDROID_LOG_INFO, "SDL","Init audio ok\n"); + } + + /* Load the wave file into memory */ + if (SDL_LoadWAV(file, &wave.spec, &wave.sound, &wave.soundlen) == NULL) { + __android_log_print(ANDROID_LOG_INFO, "SDL", "Couldn't load %s: %s\n", file, SDL_GetError()); + return; + } + + wave.spec.callback = fillerup; + + __android_log_print(ANDROID_LOG_INFO, "SDL","Loaded: %d\n", wave.soundlen); + + + /* Initialize fillerup() variables */ + if (SDL_OpenAudio(&wave.spec, NULL) < 0) { + __android_log_print(ANDROID_LOG_INFO, "SDL", "Couldn't open audio: %s\n", SDL_GetError()); + SDL_FreeWAV(wave.sound); + return; + } + + __android_log_print(ANDROID_LOG_INFO, "SDL","Using audio driver: %s\n", SDL_GetCurrentAudioDriver()); + + /* Let the audio run */ + SDL_PauseAudio(0); + + __android_log_print(ANDROID_LOG_INFO, "SDL","Playing\n"); + + while (SDL_GetAudioStatus() == SDL_AUDIO_PLAYING){ + //__android_log_print(ANDROID_LOG_INFO, "SDL","Still playing\n"); + //SDL_Delay(100); + } + + __android_log_print(ANDROID_LOG_INFO, "SDL","Closing down\n"); + + /* Clean up on signal */ + SDL_CloseAudio(); + SDL_FreeWAV(wave.sound); +} + int SDL_main( int argc, char **argv ) { @@ -425,13 +510,8 @@ int SDL_main( int argc, char **argv ) /* resize the initial window */ resizeWindow( SCREEN_WIDTH, SCREEN_HEIGHT ); - /* Load the SDL library */ - if (SDL_Init(SDL_INIT_AUDIO) < 0) { - __android_log_print(ANDROID_LOG_INFO, "SDL","Couldn't initialize SDL Audio: %s\n", SDL_GetError()); - return (1); - }else{ - __android_log_print(ANDROID_LOG_INFO, "SDL","Init audio ok\n"); - } + + testAudio(); /* wait for events */ diff --git a/android/testproject/src/org/libsdl/android/SDLActivity.java b/android/testproject/src/org/libsdl/android/SDLActivity.java index e54fac128..d821f9ffe 100644 --- a/android/testproject/src/org/libsdl/android/SDLActivity.java +++ b/android/testproject/src/org/libsdl/android/SDLActivity.java @@ -12,6 +12,7 @@ import android.graphics.*; import android.text.method.*; import android.text.*; +import android.media.*; import java.lang.*; @@ -24,6 +25,12 @@ public class SDLActivity extends Activity { //Main components private static SDLActivity mSingleton; private static SDLSurface mSurface; + + private static AudioTrack mAudioTrack; + + //feature IDs. Must match up on the C side as well. + private static int FEATURE_SOUND = 1; + private static int FEATURE_ACCEL = 2; //Load the .so static { @@ -41,11 +48,23 @@ protected void onCreate(Bundle savedInstanceState) { mSurface = new SDLSurface(getApplication()); setContentView(mSurface); SurfaceHolder holder = mSurface.getHolder(); - holder.setType(SurfaceHolder.SURFACE_TYPE_GPU); - + holder.setType(SurfaceHolder.SURFACE_TYPE_GPU); } + public static boolean initAudio(){ + + //blah. Hardcoded things are bad. FIXME when we have more sound stuff + //working properly. + mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, + 11025, + AudioFormat.CHANNEL_CONFIGURATION_MONO, + AudioFormat.ENCODING_PCM_8BIT, + 2048, + AudioTrack.MODE_STREAM); + return true; + } + //Events protected void onPause() { super.onPause(); @@ -81,6 +100,32 @@ public static void flipBuffers(){ mSurface.flipEGL(); } + public static void updateAudio(byte [] buf){ + + if(mAudioTrack == null){ + return; + } + + mAudioTrack.write(buf, 0, buf.length); + mAudioTrack.play(); + + Log.v("SDL","Played some audio"); + } + + public static void enableFeature(int featureid, int enabled){ + Log.v("SDL","Feature " + featureid + " = " + enabled); + + //Yuck. This is all horribly inelegent. If it gets to more than a few + //'features' I'll rip this out and make something nicer, I promise :) + if(featureid == FEATURE_SOUND){ + if(enabled == 1){ + initAudio(); + }else{ + //We don't have one of these yet... + //closeAudio(); + } + } + } @@ -95,6 +140,8 @@ Simple nativeInit() runnable */ class SDLRunner implements Runnable{ public void run(){ + //SDLActivity.initAudio(); + //Runs SDL_main() SDLActivity.nativeInit(); diff --git a/include/SDL_config_android.h b/include/SDL_config_android.h index a38270943..4651d9572 100755 --- a/include/SDL_config_android.h +++ b/include/SDL_config_android.h @@ -121,7 +121,7 @@ typedef unsigned int size_t; #define SDL_HAPTIC_DISABLED 1 -#define SDL_JOYSTICK_DISABLED 1 +#define SDL_JOYSTICK_ANDROID 1 #define SDL_LOADSO_DISABLED 1 diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c index 572cdb4a7..66a0fb926 100644 --- a/src/audio/SDL_audio.c +++ b/src/audio/SDL_audio.c @@ -320,6 +320,8 @@ SDL_StreamDeinit(SDL_AudioStreamer * stream) } +#include + /* The general mixing thread function */ int SDLCALL SDL_RunAudio(void *devicep) diff --git a/src/audio/android/SDL_androidaudio.o b/src/audio/android/SDL_androidaudio.o index 2068b1a726b866209ac8f3ea3bc98740919ed2c1..2f8c45e8614f5d61cf60e417990692d7d44db5bd 100644 GIT binary patch delta 3157 zcmX|D3vg9e6+P$Xym#+=c_(@Ky}Upg(%vL5YWN7{m$BH^ly>+OFi_)%PcT7LgtVki z`LtJ=jxdte(95(PERx!c#t|VHv8mDzS_%b<47S*6>F5+3)Di5+`0H3)>)suid1vjl z_Bwl?bMCn}47H86_1EjZLpSz1!Sk+Cj^aO~PhixSij-O#E9zpDfWf$Jkc&*>i|c!p zqmzd<{Bz-Qrr!aNqrF#1oWvd$N+RpbT)~9nHX0~@Vm!N%qnG$y1a2uRI)QN?gTXP0 z6bd9v(zq!08>Ea%pyP~In9bX4KC7K!6T{YSgsyoJqqhr##;pW~Ufx(~mGY?IFajIfv0KMkV(X7a0DN z;rBlVhih)fnARN_i~Eo(u4mMONM+tfn0J5lF2JsZ;2xmv_{yG#f$UJsT)T?Be$2Lx@7WHVl{*r%w4F!xlgm*qV}F7DxraZB*^ZyJ&q8&7$|X5| zr7~QL`z)7fDw#R*Zwlsm07&aBniNL^*91KWA+s5Ahx@bV5!-b*CHI$O>)*u2FVoBA z@8uGY#Vl!$kiGJ9)YvOoeg7Ke9_OK8Q6=lT*DLo#T&2>!1W(|;8q>UegX=#Tvs(Ke zrnsl#GWB+l4Nr3=j^AvDn0qaDE>@*iKwm>D`zQ*g@Z_03!!4L<4BmuyF=iMJc@qv| zBetA!2OkX1U)eJVyw9?P-cS{} z2eiFT_r}Xnc2KJfsJhwnpM%SuqqX5xjNHs;=xn?gF=M|))|AFPUZ1_(XrVS@89NCZ z4!q`=X6?O@y${8#($3})eRyhQ&D-sq_>nkQYqzjyOU&x+BC?4wYp_0@lVa9vzr#&U zZjGw6l+9;{sXP#)Cpi9;vWHCoWm>G%QTZM%H^;&a6sEA=^jN5+@I#iI5ewrXsB%rh z?Z@w(Yj`T<`Z=gPhDaSt{VGaDv(c&81RUucGrWm?yXMcZr8Rd^Y%oB{0?IX?9?xV< zy$NxJcFimxreI|=dBG~P-aK9zy9%N=KfeCTZl_@ZoAb39$DIWWW9r#Em=u;#Wj~)Yr=rz#GPoiRe7Bja+4~v7(G`eH-4B%IR-yAseJFr6C&Rx%eq-yf?PSgX4NAc6k zyXcCVwy@q3h-!QTQw>qY(eQezxb?vQT|QlWXY==Q{XQSTcS-r-(LPW8Fn+3bGCQyN zEr?TydaDUY-y(+v^wMd^0r{}ilqv4^PpSWDB)YPE97i6k8E-m|W8=;^rOpWc zTJRmg=sy|AUlY!6CjAKk~K!jnzBZ4Od-xU0# z;59)9Z%K3%f^~u|f~|sg3Em^vC3t^?_-KDageL@t1aHGVWrL-Hs|9-m9};{-a8Phq z@CCusg1;5KD)>GzK!X%sIyR~nY!qx4Tp{=+!5+b{3T_qLCb&cJQNi7Udjy{r+z$*K zJlA0gz@JOv7_nNZQ^LOqqH(qe zA18v(72`a?WumVnVq&-O9?AC#J|Ow8OMa*De&KtB?-Tw5w=^zzP=q7l(>HGa9~irT A6#xJL delta 3133 zcmX|D4Qy5A8UDU=ztivB_I~98?d`p^wk4<7IzSo4p(HC)OWdHeYF%WyO9KM2QGOh# z8z?83Zft~U%^^ySn-#|>38EB1Br>-FT7Q8px`oXNnNG}NHa0htxh;F1bKb7WeV_Mv z-sgM2pYz?*d!%!ubFf(t9GJSniw;|*JjFkwk0I*!GfFK_74<<EP!ip8qf#eNJiaQbx}<87O~Xe)TlQz(1XU&7z|h8M_?@&-fWM z@J)rWXm$oA^DpR`FU^D5yvxb2>Sfx@blys&*1U`uJVG_Y0ULKR9Yi1V;L}Wpe1vWL znLY%A-|<(ZS*F@dzz!;A=?IWzuFX~|?VDk-<^;zqL??UQDW(^h?ztQeYvv$U>V=3^ z+fl2U#B2sKmHP+MqJ8EafGb0=`>A`Oa;G8LXN!nlXj}!^bDSjd!V32r(gUPkXx*)x zYn0P^Vc>4UDcFN4t8|@Y&!0_dIrkFwXAgx*)4baU)gI=Oys$)kwUiazDJ(y-ucx%ZCF^@5ZPV<2%n9FQYcFhb zPokZDD|Oz0J7hXAcEUNRufUOi2z|54aQXIa?!-()2%3J6m}5E;G>u?CE=PF@pAR3( zm{ySrZet5CEV{XvGFX~Uvd(>ttna&+#|t;OQDCr~wM;mm-QQTeJ*D5*ZV`G1D^j{$ zyVqa~R;F}NyFQM+gC~*+cWC!9t9K4U%!E55?Y468nnx4bk-O=kbJ}|eGj4$F(hSD&7VSX0ptUw(IoHNhXiHcW=G~o; zgUixljcaG|3)2&8(QW3y>1nOOtz**}DQk9}WHVFN;-=7fdCJ<{PHyUo_N2>Qx zY#xZwO>VG9v=n||A@;UP@YFQP4X zov7obv82S&|6wT!G>+HLV3*eX5w%LqH75=zS>%&6pA}DFT&+hwSzGf(Kf)H!Mg?}5+ILj&XQx5FzL=S5|M9G?eBIZ`3 zc|LvY?iU!J4W)PFrefvUmh=^1-1{s}OIhHSV{Gdu1bYm>(S zA-VLrd>jpn(QKBk;qy%XO1lFvTv4}Xov%V&uEIaP z)U#MT^&VEFZ%+0|&oDld@tF%}@jVc_) z`*QoWe-yp;#C_HG#^bv=lZ>?OmB0e_Z$$&}Uy0z;MF3b1&@o4Qly(Ipm zwnvY}UoLFYN8=X@p?|JHsj>KcA=EvwU)QQf;+aYOI--dmKzuIVjW`g$RoCiwRpWaR zpQ)Q1=Zblqk1r{<`u9O=PPA`AE5@s#JqGQ!@lY|;YvW_!TX>|2=il&biCwAHe;nF{ zMC&T$^^Uj~S=j;@WDH8$z~cuQkzG%DJwg1-`cPw->G&jfuu8TObgI8|_#;C#Vu z!Ls08f|~@lr5LFp5%vlm5KEUngns# zBM}A#pAwvh8_LFu1#c7V7ramKdxAd_+$;EkAYVc3^J~Eif}av26g*sd8uEgTf?a~Q z2;MH(FSu6l9>Gn5TLiZX{!lO$d|YrhFyb$yy%d1YOW|k4I^0v?Z%F-=;91cx2>wO% zzYG3X^c=pr$)h2nf4yK65&hdNew@%STZF5K;Pb_JonW` Date: Tue, 27 Jul 2010 21:58:18 +0200 Subject: [PATCH 29/34] More joystick stuff --- android/testproject/jni/app-android.cpp | 6 +- android/testproject/jni/lesson05.c | 2 +- .../src/org/libsdl/android/SDLActivity.java | 75 +++++++++++++++++-- 3 files changed, 72 insertions(+), 11 deletions(-) diff --git a/android/testproject/jni/app-android.cpp b/android/testproject/jni/app-android.cpp index d8811caa6..2df3706a1 100644 --- a/android/testproject/jni/app-android.cpp +++ b/android/testproject/jni/app-android.cpp @@ -48,7 +48,7 @@ extern "C" void Android_EnableFeature(int featureid, bool enabled); bool bRenderingEnabled = false; //Feature IDs -static const int FEATURE_SOUND = 1; +static const int FEATURE_AUDIO = 1; static const int FEATURE_ACCEL = 2; //Accelerometer data storage @@ -76,7 +76,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved){ mActivityInstance = cls; midCreateGLContext = mEnv->GetStaticMethodID(cls,"createGLContext","()V"); midFlipBuffers = mEnv->GetStaticMethodID(cls,"flipBuffers","()V"); - midEnableFeature = mEnv->GetStaticMethodID(cls,"enableFeature","(I, I)V"); + midEnableFeature = mEnv->GetStaticMethodID(cls,"enableFeature","(II)V"); if(!midCreateGLContext || !midFlipBuffers || !midEnableFeature){ __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: Bad mids\n"); @@ -196,7 +196,7 @@ extern "C" void Android_Render(){ extern "C" void Android_EnableFeature(int featureid, bool enabled){ - mEnv->CallStaticVoidMethod(mActivityInstance, midFlipBuffers, + mEnv->CallStaticVoidMethod(mActivityInstance, midEnableFeature, featureid, (int)enabled); } diff --git a/android/testproject/jni/lesson05.c b/android/testproject/jni/lesson05.c index c53aab4c1..60ceb596b 100644 --- a/android/testproject/jni/lesson05.c +++ b/android/testproject/jni/lesson05.c @@ -511,7 +511,7 @@ int SDL_main( int argc, char **argv ) resizeWindow( SCREEN_WIDTH, SCREEN_HEIGHT ); - testAudio(); + //testAudio(); /* wait for events */ diff --git a/android/testproject/src/org/libsdl/android/SDLActivity.java b/android/testproject/src/org/libsdl/android/SDLActivity.java index d821f9ffe..de2a1850b 100644 --- a/android/testproject/src/org/libsdl/android/SDLActivity.java +++ b/android/testproject/src/org/libsdl/android/SDLActivity.java @@ -13,6 +13,8 @@ import android.text.method.*; import android.text.*; import android.media.*; +import android.hardware.*; +import android.content.*; import java.lang.*; @@ -25,11 +27,16 @@ public class SDLActivity extends Activity { //Main components private static SDLActivity mSingleton; private static SDLSurface mSurface; - + + //Audio private static AudioTrack mAudioTrack; + private static boolean bAudioIsEnabled; + + //Sensors + private static boolean bAccelIsEnabled; //feature IDs. Must match up on the C side as well. - private static int FEATURE_SOUND = 1; + private static int FEATURE_AUDIO = 1; private static int FEATURE_ACCEL = 2; //Load the .so @@ -52,6 +59,7 @@ protected void onCreate(Bundle savedInstanceState) { } + //Audio public static boolean initAudio(){ //blah. Hardcoded things are bad. FIXME when we have more sound stuff @@ -61,9 +69,24 @@ public static boolean initAudio(){ AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_8BIT, 2048, - AudioTrack.MODE_STREAM); + AudioTrack.MODE_STREAM); + bAudioIsEnabled = true; + return true; + } + + //Accel + public static boolean initAccel(){ + mSurface.enableSensor(Sensor.TYPE_ACCELEROMETER, true); + bAccelIsEnabled = true; return true; } + + public static boolean closeAccel(){ + mSurface.enableSensor(Sensor.TYPE_ACCELEROMETER, false); + bAccelIsEnabled = false; + return true; + } + //Events protected void onPause() { @@ -87,7 +110,7 @@ protected void onResume() { public static native void onNativeTouch(int action, float x, float y, float p); public static native void onNativeResize(int x, int y, int format); - + public static native void onNativeAccel(float x, float y, float z); @@ -117,7 +140,7 @@ public static void enableFeature(int featureid, int enabled){ //Yuck. This is all horribly inelegent. If it gets to more than a few //'features' I'll rip this out and make something nicer, I promise :) - if(featureid == FEATURE_SOUND){ + if(featureid == FEATURE_AUDIO){ if(enabled == 1){ initAudio(); }else{ @@ -125,6 +148,14 @@ public static void enableFeature(int featureid, int enabled){ //closeAudio(); } } + + else if(featureid == FEATURE_ACCEL){ + if(enabled == 1){ + initAccel(); + }else{ + closeAccel(); + } + } } @@ -157,7 +188,7 @@ public void run(){ Because of this, that's where we set up the SDL thread */ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, - View.OnKeyListener, View.OnTouchListener { + View.OnKeyListener, View.OnTouchListener, SensorEventListener { //This is what SDL runs in. It invokes SDL_main(), eventually private Thread mSDLThread; @@ -167,6 +198,9 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, private EGLSurface mEGLSurface; private EGLDisplay mEGLDisplay; + //Sensors + private static SensorManager mSensorManager; + //Startup public SDLSurface(Context context) { super(context); @@ -176,7 +210,9 @@ public SDLSurface(Context context) { setFocusableInTouchMode(true); requestFocus(); setOnKeyListener(this); - setOnTouchListener(this); + setOnTouchListener(this); + + mSensorManager = (SensorManager)context.getSystemService("sensor"); } //Called when we have a valid drawing surface @@ -321,6 +357,31 @@ public boolean onTouch(View v, MotionEvent event){ return true; } + //Sensor events + public void enableSensor(int sensortype, boolean enabled){ + //TODO: This uses getDefaultSensor - what if we have >1 accels? + if(enabled){ + mSensorManager.registerListener(this, + mSensorManager.getDefaultSensor(sensortype), + SensorManager.SENSOR_DELAY_GAME, null); + }else{ + mSensorManager.unregisterListener(this, + mSensorManager.getDefaultSensor(sensortype)); + } + } + + public void onAccuracyChanged(Sensor sensor, int accuracy){ + //TODO + } + + public void onSensorChanged(SensorEvent event){ + if(event.sensor.getType() == Sensor.TYPE_ACCELEROMETER){ + SDLActivity.onNativeAccel( event.values[0], + event.values[1], + event.values[2] ); + } + } + } From 655c8937460eef3806998b358f909760f717787e Mon Sep 17 00:00:00 2001 From: Paul Hunkin Date: Sat, 14 Aug 2010 12:35:21 +1200 Subject: [PATCH 30/34] Working on the sound system --- android/config.cfg | 1 + android/testproject/jni/app-android.cpp | 36 ++++++++++++++++++++- android/testproject/jni/lesson05.c | 4 +-- src/audio/android/SDL_androidaudio.c | 40 ++++++++++++++++++++++-- src/audio/android/SDL_androidaudio.o | Bin 8760 -> 0 bytes 5 files changed, 75 insertions(+), 6 deletions(-) create mode 100644 android/config.cfg delete mode 100644 src/audio/android/SDL_androidaudio.o diff --git a/android/config.cfg b/android/config.cfg new file mode 100644 index 000000000..8164a5eb4 --- /dev/null +++ b/android/config.cfg @@ -0,0 +1 @@ +ANDROID_NDK=/home/paul/Projects/gsoc/sdk/android-ndk-r4 diff --git a/android/testproject/jni/app-android.cpp b/android/testproject/jni/app-android.cpp index 2df3706a1..ed8981e70 100644 --- a/android/testproject/jni/app-android.cpp +++ b/android/testproject/jni/app-android.cpp @@ -26,6 +26,7 @@ static long _getTime(void){ } JNIEnv* mEnv = NULL; +JNIEnv* mAudioThreadEnv = NULL; //See the note below for why this is necessary JavaVM* mVM = NULL; //Main activity @@ -35,6 +36,7 @@ jclass mActivityInstance; jmethodID midCreateGLContext; jmethodID midFlipBuffers; jmethodID midEnableFeature; +jmethodID midUpdateAudio; extern "C" int SDL_main(); extern "C" int Android_OnKeyDown(int keycode); @@ -54,6 +56,7 @@ static const int FEATURE_ACCEL = 2; //Accelerometer data storage float fLastAccelerometer[3]; + /******************************************************************************* Functions called by JNI *******************************************************************************/ @@ -77,8 +80,10 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved){ midCreateGLContext = mEnv->GetStaticMethodID(cls,"createGLContext","()V"); midFlipBuffers = mEnv->GetStaticMethodID(cls,"flipBuffers","()V"); midEnableFeature = mEnv->GetStaticMethodID(cls,"enableFeature","(II)V"); + midUpdateAudio = mEnv->GetStaticMethodID(cls,"updateAudio","([B)V"); - if(!midCreateGLContext || !midFlipBuffers || !midEnableFeature){ + if(!midCreateGLContext || !midFlipBuffers || !midEnableFeature || + !midUpdateAudio){ __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: Bad mids\n"); }else{ __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: Good mids\n"); @@ -200,3 +205,32 @@ extern "C" void Android_EnableFeature(int featureid, bool enabled){ featureid, (int)enabled); } +extern "C" void Android_UpdateAudioBuffer(unsigned char *buf, int len){ + + //Annoyingly we can't just call into Java from any thread. Because the audio + //callback is dispatched from the SDL audio thread (that wasn't made from + //java, we have to do some magic here to let the JVM know about the thread. + //Because everything it touches on the Java side is static anyway, it's + //not a big deal, just annoying. + if(!mAudioThreadEnv){ + __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: Need to set up audio thread env\n"); + + mJVM->AttachCurrentThread(&mAudioThreadEnv, NULL); + + __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: ok\n"); + } + + jbyteArray arr = mAudioThreadEnv->NewByteArray(len); + + //blah. We probably should rework this so we avoid the copy. + mAudioThreadEnv->SetByteArrayRegion(arr, 0, len, (jbyte *)buf); + + __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: copied\n"); + + mAudioThreadEnv->CallStaticVoidMethod( mActivityInstance, + midUpdateAudio, arr ); + + __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: invoked\n"); + +} + diff --git a/android/testproject/jni/lesson05.c b/android/testproject/jni/lesson05.c index 60ceb596b..92bb07153 100644 --- a/android/testproject/jni/lesson05.c +++ b/android/testproject/jni/lesson05.c @@ -428,7 +428,7 @@ void testAudio(){ while (SDL_GetAudioStatus() == SDL_AUDIO_PLAYING){ //__android_log_print(ANDROID_LOG_INFO, "SDL","Still playing\n"); - //SDL_Delay(100); + SDL_Delay(100); } __android_log_print(ANDROID_LOG_INFO, "SDL","Closing down\n"); @@ -511,7 +511,7 @@ int SDL_main( int argc, char **argv ) resizeWindow( SCREEN_WIDTH, SCREEN_HEIGHT ); - //testAudio(); + testAudio(); /* wait for events */ diff --git a/src/audio/android/SDL_androidaudio.c b/src/audio/android/SDL_androidaudio.c index 1b26d5170..cf22e4001 100644 --- a/src/audio/android/SDL_androidaudio.c +++ b/src/audio/android/SDL_androidaudio.c @@ -29,13 +29,38 @@ #include "../SDL_audio_c.h" #include "SDL_androidaudio.h" +extern void Android_UpdateAudioBuffer(unsigned char *buf, int len); + #include static int AndroidAUD_OpenDevice(_THIS, const char *devname, int iscapture) { + SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format); + int valid_datatype = 0; + //TODO: Sample rates etc __android_log_print(ANDROID_LOG_INFO, "SDL", "AndroidAudio Open\n"); + + this->hidden = SDL_malloc(sizeof(*(this->hidden))); + if (!this->hidden) { + SDL_OutOfMemory(); + return 0; + } + SDL_memset(this->hidden, 0, (sizeof *this->hidden)); + + while ((!valid_datatype) && (test_format)) { + this->spec.format = test_format; + switch (test_format) { + case AUDIO_S8: + /*case AUDIO_S16LSB: */ + valid_datatype = 1; + break; + default: + test_format = SDL_NextAudioFormat(); + break; + } + } return 1; } @@ -45,13 +70,11 @@ AndroidAUD_PlayDevice(_THIS) { __android_log_print(ANDROID_LOG_INFO, "SDL", "AndroidAudio Play\n"); - //playGenericSound(this->hidden->mixbuf, this->hidden->mixlen); #if 0 -// sound->data = this->hidden->mixbuf;/* pointer to raw audio data */ -// sound->len = this->hidden->mixlen; /* size of raw data pointed to above */ + // sound->rate = 22050; /* sample rate = 22050Hz */ // sound->vol = 127; /* volume [0..127] for [min..max] */ // sound->pan = 64; /* balance [0..127] for [left..right] */ @@ -64,6 +87,15 @@ AndroidAUD_PlayDevice(_THIS) static Uint8 * AndroidAUD_GetDeviceBuf(_THIS) { + //__android_log_print(ANDROID_LOG_INFO, "SDL", "****** get device buf\n"); + + + // sound->data = this->hidden->mixbuf;/* pointer to raw audio data */ +// sound->len = this->hidden->mixlen; /* size of raw data pointed to above */ + + + Android_UpdateAudioBuffer(this->hidden->mixbuf, this->hidden->mixlen); + return this->hidden->mixbuf; /* is this right? */ } @@ -71,12 +103,14 @@ static void AndroidAUD_WaitDevice(_THIS) { /* stub */ + __android_log_print(ANDROID_LOG_INFO, "SDL", "****** wait device buf\n"); } static void AndroidAUD_CloseDevice(_THIS) { /* stub */ + __android_log_print(ANDROID_LOG_INFO, "SDL", "****** close device buf\n"); } static int diff --git a/src/audio/android/SDL_androidaudio.o b/src/audio/android/SDL_androidaudio.o deleted file mode 100644 index 2f8c45e8614f5d61cf60e417990692d7d44db5bd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8760 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 From bbc81c7354d632bf2ba657e9eabf3587ef5116b1 Mon Sep 17 00:00:00 2001 From: Paul Hunkin Date: Sat, 14 Aug 2010 16:17:17 +1200 Subject: [PATCH 31/34] Added initial README.android --- README.android | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 README.android diff --git a/README.android b/README.android new file mode 100644 index 000000000..5fe9d23f8 --- /dev/null +++ b/README.android @@ -0,0 +1,16 @@ +============================================================================== +Building the Simple DirectMedia Layer for Android +============================================================================== + +Requirements: Android NDK r4 or later + +Instructions: +1. Edit android/config.cfg to point to the location of the NDK +2. Run 'make -f Makefile.android'. If all goes well, libsdl.a should be created +3. Place your application source files in android/testproject/jni +4. Run 'ndk-build' (a script provided by the NDK). This compiles the C source +4. Run 'ant' in android/testproject. This compiles the .java and eventually +creates a .apk with the C source embedded +6. 'ant install' will push the apk to the device + + From 19fd0a0bded05798b26d4a94519d7d18d7b5ce92 Mon Sep 17 00:00:00 2001 From: Paul Hunkin Date: Tue, 17 Aug 2010 15:35:56 +1200 Subject: [PATCH 32/34] Cleanups. - Moved to 'project' instead of 'testproject' - Removed extraneous .c files - Removed the android_libs folder (that was against the NDK agreement anyway) --- README.android | 4 +- android/project/AndroidManifest.xml | 15 + android/project/build.properties | 17 + android/project/build.xml | 67 ++ android/project/default.properties | 11 + android/project/jni/Android.mk | 18 + android/project/jni/android-support.cpp | 242 ++++++++ android/project/jni/lesson05.c | 574 ++++++++++++++++++ android/project/local.properties | 10 + android/project/res/drawable-hdpi/icon.png | Bin 0 -> 4147 bytes android/project/res/drawable-ldpi/icon.png | Bin 0 -> 1723 bytes android/project/res/drawable-mdpi/icon.png | Bin 0 -> 2574 bytes android/project/res/layout/main.xml | 13 + android/project/res/values/strings.xml | 4 + .../src/org/libsdl/app/SDLActivity.java | 388 ++++++++++++ android/testproject/jni/app-android.cpp | 4 +- build-scripts/android_libs/libEGL.so | Bin 36100 -> 0 bytes build-scripts/android_libs/libcutils.so | Bin 55252 -> 0 bytes build-scripts/android_libs/libutils.so | Bin 172344 -> 0 bytes 19 files changed, 1363 insertions(+), 4 deletions(-) create mode 100644 android/project/AndroidManifest.xml create mode 100644 android/project/build.properties create mode 100644 android/project/build.xml create mode 100644 android/project/default.properties create mode 100644 android/project/jni/Android.mk create mode 100644 android/project/jni/android-support.cpp create mode 100644 android/project/jni/lesson05.c create mode 100644 android/project/local.properties create mode 100644 android/project/res/drawable-hdpi/icon.png create mode 100644 android/project/res/drawable-ldpi/icon.png create mode 100644 android/project/res/drawable-mdpi/icon.png create mode 100644 android/project/res/layout/main.xml create mode 100644 android/project/res/values/strings.xml create mode 100644 android/project/src/org/libsdl/app/SDLActivity.java delete mode 100644 build-scripts/android_libs/libEGL.so delete mode 100644 build-scripts/android_libs/libcutils.so delete mode 100644 build-scripts/android_libs/libutils.so diff --git a/README.android b/README.android index 5fe9d23f8..10d2061b0 100644 --- a/README.android +++ b/README.android @@ -1,5 +1,5 @@ ============================================================================== -Building the Simple DirectMedia Layer for Android +Simple DirectMedia Layer for Android ============================================================================== Requirements: Android NDK r4 or later @@ -11,6 +11,6 @@ Instructions: 4. Run 'ndk-build' (a script provided by the NDK). This compiles the C source 4. Run 'ant' in android/testproject. This compiles the .java and eventually creates a .apk with the C source embedded -6. 'ant install' will push the apk to the device +6. 'ant install' will push the apk to the device or emulator (if connected) diff --git a/android/project/AndroidManifest.xml b/android/project/AndroidManifest.xml new file mode 100644 index 000000000..182232582 --- /dev/null +++ b/android/project/AndroidManifest.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/android/project/build.properties b/android/project/build.properties new file mode 100644 index 000000000..edc7f2305 --- /dev/null +++ b/android/project/build.properties @@ -0,0 +1,17 @@ +# This file is used to override default values used by the Ant build system. +# +# This file must be checked in Version Control Systems, as it is +# integral to the build system of your project. + +# This file is only used by the Ant script. + +# You can use this to override default values such as +# 'source.dir' for the location of your java source folder and +# 'out.dir' for the location of your output folder. + +# You can also use it define how the release builds are signed by declaring +# the following properties: +# 'key.store' for the location of your keystore and +# 'key.alias' for the name of the key to use. +# The password will be asked during the build when you use the 'release' target. + diff --git a/android/project/build.xml b/android/project/build.xml new file mode 100644 index 000000000..37b376807 --- /dev/null +++ b/android/project/build.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/project/default.properties b/android/project/default.properties new file mode 100644 index 000000000..9d135cb85 --- /dev/null +++ b/android/project/default.properties @@ -0,0 +1,11 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system use, +# "build.properties", and override values to adapt the script to your +# project structure. + +# Project target. +target=android-7 diff --git a/android/project/jni/Android.mk b/android/project/jni/Android.mk new file mode 100644 index 000000000..585f5f34f --- /dev/null +++ b/android/project/jni/Android.mk @@ -0,0 +1,18 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := sdlapp +SDL := ../../../ + +LOCAL_CFLAGS := -DANDROID_NDK \ + -DDISABLE_IMPORTGL \ + -I$(SDL)/include + +LOCAL_SRC_FILES := \ + android-support.cpp \ + lesson05.c \ + +LOCAL_LDLIBS := -lGLESv1_CM -ldl -llog -lSDL -lgcc -L$(SDL) + +include $(BUILD_SHARED_LIBRARY) diff --git a/android/project/jni/android-support.cpp b/android/project/jni/android-support.cpp new file mode 100644 index 000000000..a0b6c5c65 --- /dev/null +++ b/android/project/jni/android-support.cpp @@ -0,0 +1,242 @@ +/******************************************************************************* + This file links the Java side of Android with libsdl +*******************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEBUG + + +/******************************************************************************* + Globals +*******************************************************************************/ +static long _getTime(void){ + struct timeval now; + gettimeofday(&now, NULL); + return (long)(now.tv_sec*1000 + now.tv_usec/1000); +} + +JNIEnv* mEnv = NULL; +JNIEnv* mAudioThreadEnv = NULL; //See the note below for why this is necessary +JavaVM* mVM = NULL; + +//Main activity +jclass mActivityInstance; + +//method signatures +jmethodID midCreateGLContext; +jmethodID midFlipBuffers; +jmethodID midEnableFeature; +jmethodID midUpdateAudio; + +extern "C" int SDL_main(); +extern "C" int Android_OnKeyDown(int keycode); +extern "C" int Android_OnKeyUp(int keycode); +extern "C" void Android_SetScreenResolution(int width, int height); +extern "C" void Android_OnResize(int width, int height, int format); +extern "C" int SDL_SendQuit(); +extern "C" void Android_EnableFeature(int featureid, bool enabled); + +//If we're not the active app, don't try to render +bool bRenderingEnabled = false; + +//Feature IDs +static const int FEATURE_AUDIO = 1; +static const int FEATURE_ACCEL = 2; + +//Accelerometer data storage +float fLastAccelerometer[3]; + + +/******************************************************************************* + Functions called by JNI +*******************************************************************************/ + +//Library init +extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved){ + + JNIEnv* env = NULL; + jint result = -1; + + if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { + return result; + } + + mEnv = env; + + __android_log_print(ANDROID_LOG_INFO, "SDL", "JNI: OnLoad"); + + jclass cls = mEnv->FindClass ("org/libsdl/app/SDLActivity"); + mActivityInstance = cls; + midCreateGLContext = mEnv->GetStaticMethodID(cls,"createGLContext","()V"); + midFlipBuffers = mEnv->GetStaticMethodID(cls,"flipBuffers","()V"); + midEnableFeature = mEnv->GetStaticMethodID(cls,"enableFeature","(II)V"); + midUpdateAudio = mEnv->GetStaticMethodID(cls,"updateAudio","([B)V"); + + if(!midCreateGLContext || !midFlipBuffers || !midEnableFeature || + !midUpdateAudio){ + __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: Bad mids\n"); + }else{ +#ifdef DEBUG + __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: Good mids\n"); +#endif + } + + return JNI_VERSION_1_4; +} + +//Start up the SDL app +extern "C" void Java_org_libsdl_app_SDLActivity_nativeInit( JNIEnv* env, + jobject obj ){ + + __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: Native Init"); + + mEnv = env; + bRenderingEnabled = true; + + Android_EnableFeature(FEATURE_ACCEL, true); + + SDL_main(); +} + +//Keydown +extern "C" void Java_org_libsdl_app_SDLActivity_onNativeKeyDown(JNIEnv* env, + jobject obj, jint keycode){ + + int r = Android_OnKeyDown(keycode); +#ifdef DEBUG + __android_log_print(ANDROID_LOG_INFO, "SDL", + "SDL: native key down %d, %d\n", keycode, r); +#endif + +} + +//Keyup +extern "C" void Java_org_libsdl_app_SDLActivity_onNativeKeyUp(JNIEnv* env, + jobject obj, jint keycode){ + + int r = Android_OnKeyUp(keycode); +#ifdef DEBUG + __android_log_print(ANDROID_LOG_INFO, "SDL", + "SDL: native key up %d, %d\n", keycode, r); +#endif + +} + +//Touch +extern "C" void Java_org_libsdl_app_SDLActivity_onNativeTouch(JNIEnv* env, + jobject obj, jint action, jfloat x, jfloat y, jfloat p){ + +#ifdef DEBUG + __android_log_print(ANDROID_LOG_INFO, "SDL", + "SDL: native touch event %d @ %f/%f, pressure %f\n", + action, x, y, p); +#endif + + //TODO: Pass this off to the SDL multitouch stuff + +} + +//Quit +extern "C" void Java_org_libsdl_app_SDLActivity_nativeQuit( JNIEnv* env, + jobject obj ){ + + //Stop rendering as we're no longer in the foreground + bRenderingEnabled = false; + + //Inject a SDL_QUIT event + int r = SDL_SendQuit(); + + __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: Native quit %d", r); +} + +//Screen size +extern "C" void Java_org_libsdl_app_SDLActivity_nativeSetScreenSize( + JNIEnv* env, jobject obj, jint width, jint height){ + + __android_log_print(ANDROID_LOG_INFO, "SDL", + "SDL: Set screen size on init: %d/%d\n", width, height); + Android_SetScreenResolution(width, height); + +} + +//Resize +extern "C" void Java_org_libsdl_app_SDLActivity_onNativeResize( + JNIEnv* env, jobject obj, jint width, + jint height, jint format){ + Android_OnResize(width, height, format); +} + +extern "C" void Java_org_libsdl_app_SDLActivity_onNativeAccel( + JNIEnv* env, jobject obj, + jfloat x, jfloat y, jfloat z){ + fLastAccelerometer[0] = x; + fLastAccelerometer[1] = y; + fLastAccelerometer[2] = z; +} + + + +/******************************************************************************* + Functions called by SDL into Java +*******************************************************************************/ +extern "C" void Android_CreateContext(){ + __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: sdl_create_context()\n"); + + bRenderingEnabled = true; + + mEnv->CallStaticVoidMethod(mActivityInstance, midCreateGLContext ); +} + +extern "C" void Android_Render(){ + + if(!bRenderingEnabled){ + return; + } + + //When we get here, we've accumulated a full frame + mEnv->CallStaticVoidMethod(mActivityInstance, midFlipBuffers ); +} + +extern "C" void Android_EnableFeature(int featureid, bool enabled){ + + mEnv->CallStaticVoidMethod(mActivityInstance, midEnableFeature, + featureid, (int)enabled); +} + +extern "C" void Android_UpdateAudioBuffer(unsigned char *buf, int len){ + + //Annoyingly we can't just call into Java from any thread. Because the audio + //callback is dispatched from the SDL audio thread (that wasn't made from + //java, we have to do some magic here to let the JVM know about the thread. + //Because everything it touches on the Java side is static anyway, it's + //not a big deal, just annoying. + if(!mAudioThreadEnv){ + __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: Need to set up audio thread env\n"); + + mVM->AttachCurrentThread(&mAudioThreadEnv, NULL); + + __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: ok\n"); + } + + jbyteArray arr = mAudioThreadEnv->NewByteArray(len); + + //blah. We probably should rework this so we avoid the copy. + mAudioThreadEnv->SetByteArrayRegion(arr, 0, len, (jbyte *)buf); + + __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: copied\n"); + + mAudioThreadEnv->CallStaticVoidMethod( mActivityInstance, + midUpdateAudio, arr ); + + __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: invoked\n"); + +} + diff --git a/android/project/jni/lesson05.c b/android/project/jni/lesson05.c new file mode 100644 index 000000000..01560dfdf --- /dev/null +++ b/android/project/jni/lesson05.c @@ -0,0 +1,574 @@ +/* + * This code was created by Jeff Molofee '99 + * (ported to Linux/SDL by Ti Leggett '01) + * + * If you've found this code useful, please let me know. + * + * Visit Jeff at http://nehe.gamedev.net/ + * + * or for port-specific comments, questions, bugreports etc. + * email to leggett@eecs.tulane.edu + */ + +#include +#include +#include + +#include + +#include + + +#ifdef ANDROID +#include +#else +#include +#include +#endif +#include "SDL.h" + +/* screen width, height, and bit depth */ +#define SCREEN_WIDTH 320 +#define SCREEN_HEIGHT 430 +#define SCREEN_BPP 16 + +/* Define our booleans */ +#define TRUE 1 +#define FALSE 0 + +/* This is our SDL surface */ +SDL_Surface *surface; + +int rotation = 0; + + +/************************************** + gluperspective implementation +**************************************/ +void gluPerspective(double fovy, double aspect, double zNear, double zFar){ + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + double xmin, xmax, ymin, ymax; + ymax = zNear * tan(fovy * M_PI / 360.0); + ymin = -ymax; + xmin = ymin * aspect; + xmax = ymax * aspect; + glFrustumf(xmin, xmax, ymin, ymax, zNear, zFar); +} + + +/************************************** + glulookat implementation +**************************************/ +void gluLookAt(GLfloat eyex, GLfloat eyey, GLfloat eyez, + GLfloat centerx, GLfloat centery, GLfloat centerz, + GLfloat upx, GLfloat upy, GLfloat upz) +{ + GLfloat m[16]; + GLfloat x[3], y[3], z[3]; + GLfloat mag; + + /* Make rotation matrix */ + + /* Z vector */ + z[0] = eyex - centerx; + z[1] = eyey - centery; + z[2] = eyez - centerz; + mag = sqrt(z[0] * z[0] + z[1] * z[1] + z[2] * z[2]); + if (mag) { /* mpichler, 19950515 */ + z[0] /= mag; + z[1] /= mag; + z[2] /= mag; + } + + /* Y vector */ + y[0] = upx; + y[1] = upy; + y[2] = upz; + + /* X vector = Y cross Z */ + x[0] = y[1] * z[2] - y[2] * z[1]; + x[1] = -y[0] * z[2] + y[2] * z[0]; + x[2] = y[0] * z[1] - y[1] * z[0]; + + /* Recompute Y = Z cross X */ + y[0] = z[1] * x[2] - z[2] * x[1]; + y[1] = -z[0] * x[2] + z[2] * x[0]; + y[2] = z[0] * x[1] - z[1] * x[0]; + + /* mpichler, 19950515 */ + /* cross product gives area of parallelogram, which is < 1.0 for + * non-perpendicular unit-length vectors; so normalize x, y here + */ + + mag = sqrt(x[0] * x[0] + x[1] * x[1] + x[2] * x[2]); + if (mag) { + x[0] /= mag; + x[1] /= mag; + x[2] /= mag; + } + + mag = sqrt(y[0] * y[0] + y[1] * y[1] + y[2] * y[2]); + if (mag) { + y[0] /= mag; + y[1] /= mag; + y[2] /= mag; + } + +#define M(row,col) m[col*4+row] + M(0, 0) = x[0]; + M(0, 1) = x[1]; + M(0, 2) = x[2]; + M(0, 3) = 0.0; + M(1, 0) = y[0]; + M(1, 1) = y[1]; + M(1, 2) = y[2]; + M(1, 3) = 0.0; + M(2, 0) = z[0]; + M(2, 1) = z[1]; + M(2, 2) = z[2]; + M(2, 3) = 0.0; + M(3, 0) = 0.0; + M(3, 1) = 0.0; + M(3, 2) = 0.0; + M(3, 3) = 1.0; +#undef M + glMultMatrixf(m); + + /* Translate Eye to Origin */ + glTranslatef(-eyex, -eyey, -eyez); + +} + + + + + +/* function to release/destroy our resources and restoring the old desktop */ +void Quit( int returnCode ) +{ + /* clean up the window */ + SDL_Quit( ); + + /* and exit appropriately */ + exit( returnCode ); +} + +/* function to reset our viewport after a window resize */ +int resizeWindow( int width, int height ) +{ + /* Height / width ration */ + GLfloat ratio; + + /* Protect against a divide by zero */ + if ( height == 0 ) + height = 1; + + ratio = ( GLfloat )width / ( GLfloat )height; + + /* Setup our viewport. */ + glViewport( 0, 0, ( GLsizei )width, ( GLsizei )height ); + + /* change to the projection matrix and set our viewing volume. */ + glMatrixMode( GL_PROJECTION ); + glLoadIdentity( ); + + /* Set our perspective */ + gluPerspective( 45.0f, ratio, 0.1f, 100.0f ); + + /* Make sure we're chaning the model view and not the projection */ + glMatrixMode( GL_MODELVIEW ); + + /* Reset The View */ + glLoadIdentity( ); + + return( TRUE ); +} + +/* function to handle key press events */ +void handleKeyPress( SDL_keysym *keysym ) +{ + switch ( keysym->sym ) + { + case SDLK_ESCAPE: + /* ESC key was pressed */ + Quit( 0 ); + break; + case SDLK_F1: + /* F1 key was pressed + * this toggles fullscreen mode + */ + SDL_WM_ToggleFullScreen( surface ); + break; + case SDLK_LEFT: + rotation -= 30; + break; + + case SDLK_RIGHT: + rotation += 30; + break; + + default: + break; + } + + __android_log_print(ANDROID_LOG_INFO, "SDL","Keycode: %d, %d, %d\n", keysym->sym, SDLK_LEFT, SDLK_RIGHT); + + return; +} + +/* general OpenGL initialization function */ +int initGL( GLvoid ) +{ + + /* Enable smooth shading */ + glShadeModel( GL_SMOOTH ); + + /* Set the background black */ + glClearColor( 0.0f, 0.0f, 0.0f, 0.0f ); + + /* Depth buffer setup */ + //glClearDepth( 1.0f ); + + /* Enables Depth Testing */ + glEnable( GL_DEPTH_TEST ); + + /* The Type Of Depth Test To Do */ + glDepthFunc( GL_LEQUAL ); + + /* Really Nice Perspective Calculations */ + glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST ); + + return( TRUE ); +} + +/* Here goes our drawing code */ +int drawGLScene( GLvoid ) +{ + + static int Frames = 0; + static int T0 = 0; + + glViewport(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); + + glClearColorx(0,0,0,255); + glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(45, (float)SCREEN_WIDTH / SCREEN_HEIGHT, 0.5f, 150); + + glMatrixMode(GL_MODELVIEW); + + glLoadIdentity(); + + //Camera + gluLookAt(0,0,5, 0,0,0, 0,1,0); + + //Draw a triangle + //glRotatef(iRot, 0, 1, 0); + + glRotatef( rotation, 0.0f, 1.0f, 0.0f ); + + + glEnableClientState (GL_VERTEX_ARRAY); + glEnableClientState (GL_COLOR_ARRAY); + + /* Rotate The Triangle On The Y axis ( NEW ) */ + //glRotatef( Frames % 360, 0.0f, 1.0f, 0.0f ); + + /* GLES variant of drawing a triangle */ + const GLfloat triVertices[][9] = { + { /* Front Triangle */ + 0.0f, 1.0f, 0.0f, /* Top Of Triangle */ + -1.0f, -1.0f, 1.0f, /* Left Of Triangle */ + 1.0f, -1.0f, 1.0f /* Right Of Triangle */ + }, { /* Right Triangle */ + 0.0f, 1.0f, 0.0f, /* Top Of Triangle */ + 1.0f, -1.0f, 1.0f, /* Left Of Triangle */ + 1.0f, -1.0f, -1.0f /* Right Of Triangle */ + }, { /* Back Triangle */ + 0.0f, 1.0f, 0.0f, /* Top Of Triangle */ + 1.0f, -1.0f, -1.0f, /* Left Of Triangle */ + -1.0f, -1.0f, -1.0f /* Right Of Triangle */ + }, { /* Left Triangle */ + 0.0f, 1.0f, 0.0f, /* Top Of Triangle */ + -1.0f, -1.0f, -1.0f, /* Left Of Triangle */ + -1.0f, -1.0f, 1.0f /* Right Of Triangle */ + } + }; + + /* unlike GL, GLES does not support RGB. We have to use RGBA instead */ + const GLfloat triColors[][12] = { + { /* Front triangle */ + 1.0f, 0.0f, 0.0f, 1.0f, /* Red */ + 0.0f, 1.0f, 0.0f, 1.0f, /* Green */ + 0.0f, 0.0f, 1.0f, 1.0f /* Blue */ + }, { /* Right triangle */ + 1.0f, 0.0f, 0.0f, 1.0f, /* Red */ + 0.0f, 0.0f, 1.0f, 1.0f, /* Blue */ + 0.0f, 1.0f, 0.0f, 1.0f /* Green */ + }, { /* Back triangle */ + 1.0f, 0.0f, 0.0f, 1.0f, /* Red */ + 0.0f, 1.0f, 0.0f, 1.0f, /* Green */ + 0.0f, 0.0f, 1.0f, 1.0f /* Blue */ + }, { /* Left triangle */ + 1.0f, 0.0f, 0.0f, 1.0f, /* Red */ + 0.0f, 0.0f, 1.0f, 1.0f, /* Blue */ + 0.0f, 1.0f, 0.0f, 1.0f /* Green */ + } + }; + + glEnableClientState(GL_COLOR_ARRAY); + + int tri=0; + + /* Loop through all Triangles */ + for(tri=0;tri= 5000) { + GLfloat seconds = (t - T0) / 1000.0; + GLfloat fps = Frames / seconds; + __android_log_print(ANDROID_LOG_INFO, "SDL","%d frames in %g seconds = %g FPS\n", Frames, seconds, fps); + T0 = t; + Frames = 0; + } + } + + rotation++; + + return( TRUE ); +} + + +struct +{ + SDL_AudioSpec spec; + Uint8 *sound; /* Pointer to wave data */ + Uint32 soundlen; /* Length of wave data */ + int soundpos; /* Current play position */ +} wave; + +void SDLCALL +fillerup(void *unused, Uint8 * stream, int len) +{ + __android_log_print(ANDROID_LOG_INFO, "SDL","FILLERUP\n"); + + Uint8 *waveptr; + int waveleft; + + /* Set up the pointers */ + waveptr = wave.sound + wave.soundpos; + waveleft = wave.soundlen - wave.soundpos; + + /* Go! */ + while (waveleft <= len) { + SDL_memcpy(stream, waveptr, waveleft); + stream += waveleft; + len -= waveleft; + waveptr = wave.sound; + waveleft = wave.soundlen; + wave.soundpos = 0; + } + SDL_memcpy(stream, waveptr, len); + wave.soundpos += len; +} + +void testAudio(){ + + const char *file = "/sdcard/sample.wav"; + + /* Load the SDL library */ + if (SDL_Init(SDL_INIT_AUDIO) < 0) { + __android_log_print(ANDROID_LOG_INFO, "SDL","Couldn't initialize SDL Audio: %s\n", SDL_GetError()); + return; + }else{ + __android_log_print(ANDROID_LOG_INFO, "SDL","Init audio ok\n"); + } + + /* Load the wave file into memory */ + if (SDL_LoadWAV(file, &wave.spec, &wave.sound, &wave.soundlen) == NULL) { + __android_log_print(ANDROID_LOG_INFO, "SDL", "Couldn't load %s: %s\n", file, SDL_GetError()); + return; + } + + wave.spec.callback = fillerup; + + __android_log_print(ANDROID_LOG_INFO, "SDL","Loaded: %d\n", wave.soundlen); + + + /* Initialize fillerup() variables */ + if (SDL_OpenAudio(&wave.spec, NULL) < 0) { + __android_log_print(ANDROID_LOG_INFO, "SDL", "Couldn't open audio: %s\n", SDL_GetError()); + SDL_FreeWAV(wave.sound); + return; + } + + __android_log_print(ANDROID_LOG_INFO, "SDL","Using audio driver: %s\n", SDL_GetCurrentAudioDriver()); + + /* Let the audio run */ + SDL_PauseAudio(0); + + __android_log_print(ANDROID_LOG_INFO, "SDL","Playing\n"); + + while (SDL_GetAudioStatus() == SDL_AUDIO_PLAYING){ + //__android_log_print(ANDROID_LOG_INFO, "SDL","Still playing\n"); + SDL_Delay(100); + } + + __android_log_print(ANDROID_LOG_INFO, "SDL","Closing down\n"); + + /* Clean up on signal */ + SDL_CloseAudio(); + SDL_FreeWAV(wave.sound); +} + +int SDL_main( int argc, char **argv ) +{ + + __android_log_print(ANDROID_LOG_INFO, "SDL","entry\n"); + + /* Flags to pass to SDL_SetVideoMode */ + int videoFlags; + /* main loop variable */ + int done = FALSE; + /* used to collect events */ + SDL_Event event; + /* this holds some info about our display */ + const SDL_VideoInfo *videoInfo; + /* whether or not the window is active */ + int isActive = TRUE; + + /* initialize SDL */ + if ( SDL_Init( SDL_INIT_VIDEO ) < 0 ) + { + __android_log_print(ANDROID_LOG_INFO, "SDL", "Video initialization failed: %s\n", + SDL_GetError( ) ); + Quit( 1 ); + } + + /* Fetch the video info */ + videoInfo = SDL_GetVideoInfo( ); + + if ( !videoInfo ) + { + __android_log_print(ANDROID_LOG_INFO, "SDL", "Video query failed: %s\n", + SDL_GetError( ) ); + Quit( 1 ); + } + + /* the flags to pass to SDL_SetVideoMode */ + videoFlags = SDL_OPENGL; /* Enable OpenGL in SDL */ + videoFlags |= SDL_GL_DOUBLEBUFFER; /* Enable double buffering */ + videoFlags |= SDL_HWPALETTE; /* Store the palette in hardware */ + videoFlags |= SDL_RESIZABLE; /* Enable window resizing */ + + /* This checks to see if surfaces can be stored in memory */ + if ( videoInfo->hw_available ) + videoFlags |= SDL_HWSURFACE; + else + videoFlags |= SDL_SWSURFACE; + + /* This checks if hardware blits can be done */ + if ( videoInfo->blit_hw ) + videoFlags |= SDL_HWACCEL; + + /* Sets up OpenGL double buffering */ + SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); + + /* get a SDL surface */ + surface = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, + videoFlags ); + + /* Verify there is a surface */ + if ( !surface ) + { + __android_log_print(ANDROID_LOG_INFO, "SDL", "Video mode set failed: %s\n", SDL_GetError( ) ); + Quit( 1 ); + } + + __android_log_print(ANDROID_LOG_INFO, "SDL","Made a video mode!\n"); + + /* initialize OpenGL */ + initGL( ); + + /* resize the initial window */ + resizeWindow( SCREEN_WIDTH, SCREEN_HEIGHT ); + + + //testAudio(); + + + /* wait for events */ + while ( !done ) + { + /* handle the events in the queue */ + + while ( SDL_PollEvent( &event ) ) + { + switch( event.type ) + { + case SDL_ACTIVEEVENT: + /* Something's happend with our focus + * If we lost focus or we are iconified, we + * shouldn't draw the screen + */ + if ( event.active.gain == 0 ) + isActive = FALSE; + else + isActive = TRUE; + break; + case SDL_VIDEORESIZE: + /* handle resize event */ + surface = SDL_SetVideoMode( event.resize.w, + event.resize.h, + 16, videoFlags ); + if ( !surface ) + { + __android_log_print(ANDROID_LOG_INFO, "SDL","Could not get a surface after resize: %s\n", SDL_GetError( ) ); + Quit( 1 ); + } + resizeWindow( event.resize.w, event.resize.h ); + break; + case SDL_KEYDOWN: + /* handle key presses */ + handleKeyPress( &event.key.keysym ); + break; + case SDL_QUIT: + /* handle quit requests */ + done = TRUE; + __android_log_print(ANDROID_LOG_INFO, "SDL","App is shutting down\n"); + break; + default: + break; + } + } + + /* draw the scene */ + if ( isActive ) + drawGLScene( ); + } + + /* clean ourselves up and exit */ + Quit( 0 ); + + /* Should never get here */ + return( 0 ); +} + + diff --git a/android/project/local.properties b/android/project/local.properties new file mode 100644 index 000000000..27accedc4 --- /dev/null +++ b/android/project/local.properties @@ -0,0 +1,10 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must *NOT* be checked in Version Control Systems, +# as it contains information specific to your local configuration. + +# location of the SDK. This is only used by Ant +# For customization when using a Version Control System, please read the +# header note. +sdk.dir=/home/paul/Projects/gsoc/sdk/android-sdk-linux_86 diff --git a/android/project/res/drawable-hdpi/icon.png b/android/project/res/drawable-hdpi/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..8074c4c571b8cd19e27f4ee5545df367420686d7 GIT binary patch literal 4147 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 literal 0 HcmV?d00001 diff --git a/android/project/res/drawable-ldpi/icon.png b/android/project/res/drawable-ldpi/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..1095584ec21f71cd0afc9e0993aa2209671b590c GIT binary patch literal 1723 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 + + + + diff --git a/android/project/res/values/strings.xml b/android/project/res/values/strings.xml new file mode 100644 index 000000000..17e33264c --- /dev/null +++ b/android/project/res/values/strings.xml @@ -0,0 +1,4 @@ + + + SDLActivity + diff --git a/android/project/src/org/libsdl/app/SDLActivity.java b/android/project/src/org/libsdl/app/SDLActivity.java new file mode 100644 index 000000000..07d750e88 --- /dev/null +++ b/android/project/src/org/libsdl/app/SDLActivity.java @@ -0,0 +1,388 @@ +package org.libsdl.app; + +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.opengles.GL10; +import javax.microedition.khronos.egl.*; + +import android.app.*; +import android.content.*; +import android.view.*; +import android.os.*; +import android.util.Log; +import android.graphics.*; +import android.text.method.*; +import android.text.*; +import android.media.*; +import android.hardware.*; +import android.content.*; + +import java.lang.*; + + +/** + SDL Activity +*/ +public class SDLActivity extends Activity { + + //Main components + private static SDLActivity mSingleton; + private static SDLSurface mSurface; + + //Audio + private static AudioTrack mAudioTrack; + private static boolean bAudioIsEnabled; + + //Sensors + private static boolean bAccelIsEnabled; + + //feature IDs. Must match up on the C side as well. + private static int FEATURE_AUDIO = 1; + private static int FEATURE_ACCEL = 2; + + //Load the .so + static { + System.loadLibrary("sdlapp"); + } + + //Setup + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + //So we can call stuff from static callbacks + mSingleton = this; + + //Set up the surface + mSurface = new SDLSurface(getApplication()); + setContentView(mSurface); + SurfaceHolder holder = mSurface.getHolder(); + holder.setType(SurfaceHolder.SURFACE_TYPE_GPU); + + } + + //Audio + public static boolean initAudio(){ + + //blah. Hardcoded things are bad. FIXME when we have more sound stuff + //working properly. + mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, + 11025, + AudioFormat.CHANNEL_CONFIGURATION_MONO, + AudioFormat.ENCODING_PCM_8BIT, + 2048, + AudioTrack.MODE_STREAM); + bAudioIsEnabled = true; + return true; + } + + //Accel + public static boolean initAccel(){ + mSurface.enableSensor(Sensor.TYPE_ACCELEROMETER, true); + bAccelIsEnabled = true; + return true; + } + + public static boolean closeAccel(){ + mSurface.enableSensor(Sensor.TYPE_ACCELEROMETER, false); + bAccelIsEnabled = false; + return true; + } + + + //Events + protected void onPause() { + super.onPause(); + } + + protected void onResume() { + super.onResume(); + } + + + + + + //C functions we call + public static native void nativeInit(); + public static native void nativeQuit(); + public static native void nativeSetScreenSize(int width, int height); + public static native void onNativeKeyDown(int keycode); + public static native void onNativeKeyUp(int keycode); + public static native void onNativeTouch(int action, float x, + float y, float p); + public static native void onNativeResize(int x, int y, int format); + public static native void onNativeAccel(float x, float y, float z); + + + + //Java functions called from C + private static void createGLContext(){ + mSurface.initEGL(); + } + + public static void flipBuffers(){ + mSurface.flipEGL(); + } + + public static void updateAudio(byte [] buf){ + + if(mAudioTrack == null){ + return; + } + + mAudioTrack.write(buf, 0, buf.length); + mAudioTrack.play(); + + Log.v("SDL","Played some audio"); + } + + public static void enableFeature(int featureid, int enabled){ + Log.v("SDL","Feature " + featureid + " = " + enabled); + + //Yuck. This is all horribly inelegent. If it gets to more than a few + //'features' I'll rip this out and make something nicer, I promise :) + if(featureid == FEATURE_AUDIO){ + if(enabled == 1){ + initAudio(); + }else{ + //We don't have one of these yet... + //closeAudio(); + } + } + + else if(featureid == FEATURE_ACCEL){ + if(enabled == 1){ + initAccel(); + }else{ + closeAccel(); + } + } + } + + + + + + + +} + +/** + Simple nativeInit() runnable +*/ +class SDLRunner implements Runnable{ + public void run(){ + //SDLActivity.initAudio(); + + //Runs SDL_main() + SDLActivity.nativeInit(); + + Log.v("SDL","SDL thread terminated"); + } +} + + +/** + SDLSurface. This is what we draw on, so we need to know when it's created + in order to do anything useful. + + Because of this, that's where we set up the SDL thread +*/ +class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, + View.OnKeyListener, View.OnTouchListener, SensorEventListener { + + //This is what SDL runs in. It invokes SDL_main(), eventually + private Thread mSDLThread; + + //EGL private objects + private EGLContext mEGLContext; + private EGLSurface mEGLSurface; + private EGLDisplay mEGLDisplay; + + //Sensors + private static SensorManager mSensorManager; + + //Startup + public SDLSurface(Context context) { + super(context); + getHolder().addCallback(this); + + setFocusable(true); + setFocusableInTouchMode(true); + requestFocus(); + setOnKeyListener(this); + setOnTouchListener(this); + + mSensorManager = (SensorManager)context.getSystemService("sensor"); + } + + //Called when we have a valid drawing surface + public void surfaceCreated(SurfaceHolder holder) { + Log.v("SDL","Surface created"); + + int width = getWidth(); + int height = getHeight(); + + //Set the width and height variables in C before we start SDL so we have + //it available on init + SDLActivity.nativeSetScreenSize(width, height); + + //Now start up the C app thread + mSDLThread = new Thread(new SDLRunner(), "SDLThread"); + mSDLThread.start(); + } + + //Called when we lose the surface + public void surfaceDestroyed(SurfaceHolder holder) { + Log.v("SDL","Surface destroyed"); + + SDLActivity.nativeQuit(); + + //Now wait for the SDL thread to quit + try{ + mSDLThread.wait(); + }catch(Exception e){ + Log.v("SDL","Problem stopping thread: " + e); + } + } + + //Called when the surface is resized + public void surfaceChanged(SurfaceHolder holder, int format, + int width, int height) { + Log.v("SDL","Surface resized"); + + SDLActivity.onNativeResize(width, height, format); + } + + //unused + public void onDraw(Canvas canvas) {} + + + //EGL functions + public boolean initEGL(){ + Log.v("SDL","Starting up"); + + try{ + + EGL10 egl = (EGL10)EGLContext.getEGL(); + + EGLDisplay dpy = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); + + int[] version = new int[2]; + egl.eglInitialize(dpy, version); + + int[] configSpec = { + //EGL10.EGL_DEPTH_SIZE, 16, + EGL10.EGL_NONE + }; + EGLConfig[] configs = new EGLConfig[1]; + int[] num_config = new int[1]; + egl.eglChooseConfig(dpy, configSpec, configs, 1, num_config); + EGLConfig config = configs[0]; + + EGLContext ctx = egl.eglCreateContext(dpy, config, EGL10.EGL_NO_CONTEXT, null); + + EGLSurface surface = egl.eglCreateWindowSurface(dpy, config, this, null); + + egl.eglMakeCurrent(dpy, surface, surface, ctx); + + mEGLContext = ctx; + mEGLDisplay = dpy; + mEGLSurface = surface; + + + }catch(Exception e){ + Log.v("SDL", e + ""); + for(StackTraceElement s : e.getStackTrace()){ + Log.v("SDL", s.toString()); + } + } + Log.v("SDL","Done making!"); + + return true; + } + + //EGL buffer flip + public void flipEGL(){ + try{ + + EGL10 egl = (EGL10)EGLContext.getEGL(); + GL10 gl = (GL10)mEGLContext.getGL(); + + egl.eglWaitNative(EGL10.EGL_NATIVE_RENDERABLE, null); + + //drawing here + + egl.eglWaitGL(); + + egl.eglSwapBuffers(mEGLDisplay, mEGLSurface); + + + }catch(Exception e){ + Log.v("SDL", "flipEGL(): " + e); + + for(StackTraceElement s : e.getStackTrace()){ + Log.v("SDL", s.toString()); + } + } + } + + + + //Key events + public boolean onKey(View v, int keyCode, KeyEvent event){ + + if(event.getAction() == KeyEvent.ACTION_DOWN){ + SDLActivity.onNativeKeyDown(keyCode); + return true; + } + + else if(event.getAction() == KeyEvent.ACTION_UP){ + SDLActivity.onNativeKeyUp(keyCode); + return true; + } + + return false; + } + + //Touch events + public boolean onTouch(View v, MotionEvent event){ + + int action = event.getAction(); + float x = event.getX(); + float y = event.getY(); + float p = event.getPressure(); + + //TODO: Anything else we need to pass? + SDLActivity.onNativeTouch(action, x, y, p); + return true; + } + + //Sensor events + public void enableSensor(int sensortype, boolean enabled){ + //TODO: This uses getDefaultSensor - what if we have >1 accels? + if(enabled){ + mSensorManager.registerListener(this, + mSensorManager.getDefaultSensor(sensortype), + SensorManager.SENSOR_DELAY_GAME, null); + }else{ + mSensorManager.unregisterListener(this, + mSensorManager.getDefaultSensor(sensortype)); + } + } + + public void onAccuracyChanged(Sensor sensor, int accuracy){ + //TODO + } + + public void onSensorChanged(SensorEvent event){ + if(event.sensor.getType() == Sensor.TYPE_ACCELEROMETER){ + SDLActivity.onNativeAccel( event.values[0], + event.values[1], + event.values[2] ); + } + } + + +} + + diff --git a/android/testproject/jni/app-android.cpp b/android/testproject/jni/app-android.cpp index ed8981e70..e3dc8f773 100644 --- a/android/testproject/jni/app-android.cpp +++ b/android/testproject/jni/app-android.cpp @@ -13,8 +13,8 @@ #include -#include "importgl.h" -#include "egl.h" +//#include "importgl.h" +//#include "egl.h" /******************************************************************************* Globals diff --git a/build-scripts/android_libs/libEGL.so b/build-scripts/android_libs/libEGL.so deleted file mode 100644 index 03a18b39fd95da0102567ed3a7102d72961f2b9c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 36100 zcmeIbd3;pW`9FScX30VVVG$;9!AZh0EQXK-2#A*KGn0i#q6TZ58IlQiAj_D9O;O{% zw`|%hXw{-03eiSOT5F*nTK)E`t*tZFwpeXDTB|Gpv9%pUlKH-$bI+Z*8PL|(@2}tM z<$dwyInP<2^PK0b_vXy4B^9NTBr)wVFdHN8>^#QuK#lh^7RQ(=k6D=!VH4Q|3isW+ zg)t2;7#JfMDLxR*4Gf-@+fFIaj`CRQJy9G3PoQwh-woUj z&;v2pTJB;@25lGaZ-N#9Qw8r5l*mmwH#xTg*8w*Y^EuBt_+JWq9cTqgfm+})zye$Y zpbA`PYd|*x^xO)N+?NxBryBSga1}9l@_`xL1*L*c25u013up~6A6O*(3P9_Hd!?Wn zxeX4enm=>#eUL@PC(%SKzJyZUH&~2hawr2EGBL0~-J@unB-ku-~=xA z&=^9GfvHxI(8XEs$*fq{kfgi2sgsC@_`NaVZE;$ts_S1-g~UVgUzHfU3!Q{yoq+Ow z0^S6^OYq%D{~J_xx8Mh3$~y#q?VA0z)2G4joc;Y-MV zF~Df~EsD|aZ;-!){5AO}#>o43l)L7#X#buXlmGvqzOTaAUla1Z852Gxro5NI>+P!< z>9vRSkrmUwu8c`P8TGjule(slIp9x$ClllL6Qkb(==1lmFRlGgAV0mnm&df{9Wm+u z8Y9p3(3kemy!b5AueeWLAB|_@*b6cG^TwqAHROG&FlxWgBR_XOV~-;*lK%k8e+UD< zR-Z#L`t&1SI@*J>rTB$0<)tCNt1;Piitrm_^m{e<7TD){5xyiQ|HCouU$tY zf3hx|+RuReZzy8yPWY32IWgh?jFIs{oxCP!WGQGN$e z{=*K&l0|vTL0^Ubweidhd48@N9|n+L{(Wi#CNz zTN~Tkyp4;pukkc=wzWH2e9en;o4l>w4yAq*_bS;mD&mrww)Rd>V>Ehk4v*2;T)l~j z-0D$4ho>_)hXhdzsBdmt2N}GrouhJFyw2X%wxOe{t*EWF)3c?sg!wv^c8|NUex0YY z!{=%6HhCMEXI*odr?Y5dd%LH#Q^XXWCGG8P?Z~oq^ZH0q6s=FX+SBZDcX(=fzL7{R z8&O_;qo<>@y=`lZZ*yD21`@M8qMi$Cy%c)&Y+2P*Qe7Ucw!5>f#oJKtZEc9jaAPaa zQmfkr&(`_|)UwkpC<}RZp?E!`JNII@+^lV|$akf#*=f%dK9!v8l<^UfSN)q844qc`X&sxS+GM-Mf~& zuG;8n-&zB%bzP*1MO_;`4WkIJo7&pz8&vhzHwZ&UZ$KoTgU(`$ReR$Cii!v?U8G9) z29Gdy%0ooZ+E6FQq6@U0>uzk+RIRqOz9`j4SJEhB&gm9@B=(G^%zyN5SWt*5=k+bTMOqt)B#bvJu& z^spN`Fv>7rdz;VG-no@j&0ug|FS=T6`1-0a{o3LX8*Yl&oJLsW)n}#S6j3Af^s7 z7)_&IZLR2s_4SP%ZS@Mq#%3_OVK{ePS;e*OZXc>$?%7&0Doj5_FN3rgBJ|_%qL_jD zKSWnY?Tb$U7s);M%jKT;<)SbCa?zK3x#&y3T=e{y=ofUdoW+{-Fihu;Li= z(fpBS)EZ3ZUtK@!z7?X_n>7=KzI{aVpf930 zquN4rDfC4Ydg~&Jz5bmJ_i*S}f6ngI_TE^HOq7KF$C+fsm8&Mnx z>>~=j_Y=h#!2r>#7&}O`7VlPw;_&tmQMAJmqSrF^GEubOD@4&=uMzzw_NYYB&TkT3 z%h*w(jf}lRw284GQH8PhiLS@H6{2YWA)?K&PogcbOQNvbvqXKcL!upwF|_~WPP9MK zZD@a@x1#-tcA@==-iCNzJzr_yD-C?5fv+_1l?J}jz*idhN&{bM;42M$rGc+B@c&5z z#^7atHwM4^_p!lm2NTZx?C*IlWcSN&zi0l{gYV^?IrMkUy+G%lsdLLZ_avP=S?4wi zw+VTk536~S`xBjeNaucE=YB`$epBauP3L}D=RTx!AJn<~b?&`7_a2>lx6b{b&V8rO zy-nxt)VZ5=?na&adY!vg=dRGXi*@c5I(MGVy+G%lsdLLZ_avP=S?4zD+~-Gh`q#OK zbnf?c?ss(VH+AmUbncgR?n65FL7lr_=iaMx@6ow;>)a3O+;{5S+jQWapIfF3U~DV{Ms7FL8FUUd#BpdoA~rPISt_ ziO#8j1(*y>0ww^dz*ry|NCFZ7GhhVb00#6~EV8eR`NQFV+~ zT2h~7OX?QLKP;5q^2%|+9~K&aw|>Ts!jJweS&Iv;vhT2=+-PSRHx*B_Om+Fnj+Bmt zTy}grKyE@@FjbK*mwwLXp9>H_QAtvE72a3STi91nH`P~`I@re&6{)3nc!fNaq`z zQaPpk=HiobCvECu=DU1t*Lq820Wop+)P!6>t*&6JjJf-rc;%}tc zlyGRqDWhzbnJp!dYz>F1PajD)%2MXNlGWAZ`ku?Cq(g6=(5~jX;!63PJ}kzAHoN8pvzBL6_$<^ zu!JL}FCvYq!?6`(%eNK(jqAeb59Ur&@KLkByDZVU*OD%uUt~w^P5xh5i`d`l)R1uK zwXlSixF2~?JyQpbkoym?kkrGz!PE+~oC;gGePEWwCg){`L;h1XIX_$azVt{qwCxm| z#cYPRv!{ncFPxHQnH-H4E01*}EW?JHA1TeJb5ndH;~Qj|Mma?`xY%5iKLKUT)ZI7v@26FZXYL4mZjX(z+{JFseoj+LnlSDAz+nB zGan44I`?t^yi?&&2Ku)Vy?3lX8zm18CpnUwaofF?{m{Fyk9~(~bLY@(m#I5`;LPFv zI#r(}H?_rP-WKD^Zz`5-2LD+5SckT9ewz@30|aT90?XzJiZUWUm(!TwqLG>ma_ zc49CU<)osVcz?1z&5{7W^XU$jjImKIEzxhbCpjr(I8)Asx>2UW%X|%I*Horf9+hS0 zCU1|OCPtT#K0KmSjS!- zmI9j%hn9vDgK6?Ri;@&JPx5asiwo|9wRM+KT^mKYf52EkWxoYV<@yGvR*aQl`?e&% z#h&I!b5d#cY|3w3*d%8JCp(|CywS|&C;7+A{zYS8y(WLPvPkYOBTHj`X;um>Ia5BL zTL(){^8dnGz#3r5CckSvk7Z*4Hj6Cp1kUfN?mt4=RBw{QH#n)ng!03ogTrdgXNa1Q zvybC7uS3np#?(B)ndEp1)?b&M$ZP)Mh#}aYD=Rkn@iO1x^`e}ArwV=A2yUucS%+Q`o$x7H$rtJIY_7fxlg`uQr{=#lUko# ze=;1Z8`k&9lb>CzPri6U>ys9gO=FzCPyXlfw~Q+PofBI5^H9EJRQU%kTKv%Y?CVbWj`t^(KZ?;o%6+uZ5MbWK;7V_N&}@%)#FO1mC#!!f zOk-aX@?Hado`+svLc1paSGr9aRkzki-42}yhxVV>>-LI^)-5?ww?j1-t6K)_SHfJG zZns+aZ0%yU_`nS3#~6Lcp5$!Vd08-Fti>hSOmA5n4Sc-%XL@>Yid|Y6*DblGDXGeJ z((RTB-W`Rew^PgimHs|Yml`~nKE_#I^rXda`8n*>;GZN{!FYQpJ(K4X?{x5y z>?Vw4Dk6*l*fl++os19+)gomsy74fN7_3r(q}CMdgJP6Cvz!R)$LiIBhSYuVjl1vw*6Oao_a#xpE{3g_WX4`BX$9M}is z|2`b1b|f434UVfEhZP3R>6wa@J3f#i=JGwq_4Q=OZ@ z4lQz1DQm zdw97l?Kbocl*I=VR*iv#r_-|e=(YGWBT5X1)`jCC-> zr)o_WT02tu9^UnnT*W%MRGrD%s%%CdQbRm~JBG*)Ci?<|JP3b~g&kMO^ zp{+?=TgKeC+t~bAxkz7QoIjem(2|cF-sL0gY9ZO3Lb4;J2l0&r>Fa5%oisbsWYTms zB_dNAtX^%w>mydL2$?jiS6lF65+wu^p{XRUsq49>l7u`fBJx;;JP+&S`7YdN2Jb@q z8TLuLG)=wssX_F`s9iNjT5x)_1-aEvFG|LT;JkysqHsewBK!?YSumxE9^;5nO8F_8ZD*z9>vyO0jOATLQ4Y2)$1I^*^>f3j{d`i6u>fVe zb!BUPjLJp-7o{cyCfX;VR2r93F)Cj7=_R7%hegR_N0pq3lIx_o=>6@j?<(6xxf_So zG3XXiZmq7|Xgj2d8YhT$NDN$JKace%l|2dlGaQ=s=@e1=HKO#?QKef^y3|)FeIMm7 zm)})B*+4ZXz2`;r9w%hbY*QPr%^0CS!^$fT(B->Y3vQ~QH0JV)H#95cr{YSCSFFg z{uWXH?z5^LCIlwgFL7MLb)Sve?>Vd0K52sc1i2h&k9d zm|JoCKnmZD8L>)%e&&t|qz1F>3mpsjzHBA8`l7Q&xiXj_kA%+h{kZh7)W_y024*^+ zz>afe_AJM2XE>CNSWAO*y=?Aye`fjLEPrXHd1R`5CMOj$XFOb=U~Z{HzmjG{{{c4J zi?|c83!KS!bKk%UZH)hSncrY**UO2-vgyJ#>MoLe}R7P9wPm;+x7a1&haCmfw0rZqMUIi+&F+Dtc41=uK!Fs*Ayol{0FByz&3*BWnN3feciS%r9u)qeHRn zJDbb@d|6cfGlRPZjB>(`o2$~~@%s{YUWyj13@7xY?i&d$3y<5E*mFzqNGLBXEr5O( z#s~fy?6h|}HaeGBva$L|4@%Z$Nb#dEbdUCWIrw^TnfD5L%#ItqNjpDNXlEJ!D7$Pz zAo06wp)ruqE%A5*!L{WchsXJeSi_8jGNGZTFf*}PNjt~v>@Q8|#-F>}#`&qe6ZRbN zrh9t|&Hk%b{R=Dahh{6;AG7hngx-LX*o`zIULxXUczY4Ayz+*$1i8wgWLG&~|1h!p z7fNM0yUgG}V;S-u@S211d(K$m``-5&cK3NryS^^HWT{j3HaC>=(bMJ*#P^Iv{a+m! z(~|-^IFi(p4Eo&26^<*MY@zI*zy6r_21_5Kbj!=1wc$z`c7rv3*GQ=IWYS~t zz4`JVT;b3Y=f-0MnZWzo@}aT8tn!8S8!VS9&s&z%T~6ntkBo$_KRM!JIM;jN+*q{m zp^3uH%^!;WaJ^L4SWYzIvg{X#pVrSn=k zzt!dsTGx(*W{+HG^IKr^%SSYuher4bQmoBKXOQPNT-@d#86lf5Kd0LKl_jdI^tW!> znC=^tGFW;t&aNd_p=%7zuWuiiZpo7KmSjV=2T$5$>H9c`+&vOHbdr1uPpWwxELPX> zX9m|)JTMTC@hwF*?lfU^EAl6xt$#h7fWDU$SZ)6`_AImmNY1Wyj)dL{o8_!vzC0Is zT|R;<4QzA#(n9PTW=cUv`TLewjE7@EVsMW?5IwmJ?9tx6iwS63&cALQkGIY|pi?FJ-gS zEh(}!r($v3Bj%m)JCcI)E3+I~&L-?*FoI={gdTuwr9pEaOYgaAp~4nU^3Rj^=1hTW zoIk!dwdV|*2zxd5vK=PGd7;ew-50LHSmc-H#C^xOnTvqBf5q{(u=D9O%Cnh`09 z&L~uEEZC4E8~SiY5GiYFq^y>a|8afrrOTS|xn&LEJYsZN?;qFdwe)k#YO8o?z_?>u zv0=AqXZ$XlkOwC8u(=a)Qef!y+P#ici#6MeH+W5zhQ}1=uQPpV*6beaJVrv7oHxra z1}E%c>C&8Z7tY~lZ7X!y-40{$e!PuYAjd6E$epU(UKk3n1=qeExA+-mL+{*sjPz~} z7<#X=U(0j9#`(t&=gG#Nk+169{HD>~}KIQ=47wuZywoEql z#`o>xt&rj$gZd@?*@XX%enX$Jce?qKq7>Hz%z;Li@jJ%uk0-M>j& zC@;t}KT@&OxR}jO+`Swp=K21_KAU3fVY{}ir<@@V&Q9d*XX~+0&L+ zrkWm!-#%f_n4SsUvy~2u!6nT$_a0noT`c98cgD>-6i5;McT$1cf9KNQ7ob1Tnu+>` z4Jd=30hHEIx52HRxy`S-XW$k(!w<}@$iwc)jyd65$1tY(rA))FqTnn$tqExzkOUxX~$fwxUK&86lvb{fJ-^)#VNmSEL?`|CtA0c zjfCDkYv_@-n`m6K8hb96heOYQ^tdt-@*iUvap_WKhWkm^yDq~nY3aem*1Wide+ZZ= z*sP^#H#d%i+~*AZUCwO$-2ll?W7Kh+?NA+Q-g9FOd}i>5RS#g5bZfC`hk2)DO9-@9 z-i&n!)u{Ry)~)X(2iMy-I5s%HhW+x&>|X>S3r3vhf|Fc72(Bw%XIC7uqByUt%apfT zUbN7xKOAy>^noi&u2`}Fv%sM|!!F~)@sDIHQo6J7AFdoXvt0?B!5fQ!v0G}zpJPoH8ky{utjAoL$|?u(iaSH8gll`*K6j>4 z!ToG&GnBY)r(=8BG55Hj^-=>)lQ1Kmjq6+KC~>k~(sq*0WHs~+hbDYv=smcE?7*<| zU|!t3=K_l=uW&HyO=;8RZD^Sp)8n=qwi|cF@16%c&GHW^Y{C4uX=QJFJ6l<>9;>&E z!~f+(%*`jlafI);zsb+{i!Yva2_8*6JCZH-fdcGu1$AA?UoZR(l0w>{Y-&Ir}z(enYEjbI_AJ~$MQ8hfwhfo#X3a+l>ji??(*WIwIo|J09YKAly*z{%1-sGBcW z?HQHnD9;QX{QJ~odWw1Vx_8z2q|5Qr3WL4|vMcB(dnPJ-3MKz==-8<= zv|2KBXM^78yp`H+1wh{pyfa?ypL@|hF9QMK*cis%0R1Q68%!uqz-myo)aF?+BHVjA z94f$!M(&lT)pmJ$xps~_mA`}gJ9e&9{1)s>=^Fu)|7fm-pXaj7DZvSN<2VuT6W2iA zH2*I%*Rbk3W}D*|9jyf8R1o&R(3ZWJ8OO&=(ps3I`MN`U^h^Fsl#s+a&U)zdPe~`w zK{8IRX)U=eI|;Ua8A`(H(~7q${FK1#*p^LSI$%$6j&vo9ygJbKn*qx2?BJypmsT3n zw-tLZU*<2x$|z$v)IK!LAy>)H2Fnv^PuC^n9%#tHn#uUJ;n1N|u)*}0SMCj1|wppWgX>AMZC(2TkSl{l-nj zYb?F^ieNa@$oJqf@}V)O`ww_Yl_|N3TzByAf%NXUc?o_aAmOcRxpifsDJZ$(f(0%X zybb$BU)h<#yA{0eo;fC1q-=UTSH zfK4{{b>pOs*;c?k95SDJX@)Uh+BIyOc=VXX&@&vmAK#v&1m?;TcEA`@hNSLg@`~EH z?%_}^&%?^oofvu<>CV}v9JQrUDj!mf_h(>VMX44HvGiqE=gSllHx!2)hC_KgwG@c& zJy^#cHT7M871l`)8~3p8S#|8P0|B#RbDiU{%azCY=<%zQS8IwN*D zCj+Lw-gxux$J^VL4c_#+eC%MRg-t!>@Jn`X@aD@;)IG0+L*v7V1Nqo>ZCk?Fk3Ler zvHBV4?|?+$9l#1*(zMHgFQk;>kLp$^M%ND&oatEil#UH{DATxg z#dGU226`034t$*xXbei($$74l({I!VFLxNaFR$2OF~erMGOm*5r?Ks3ZUF-)vSq$5 z#@mgRVX8->KN%YQ)k))b*=&59<|=jF?fP2K(7m8ybjsZ#rG%83VVqgm=JS-#o{YyX zD#IyZFVL0lkf`q%x(`^)y=*&K&z2KZUR)-9!xJBNxeUFQ@~(8Y^Q6TgsWLT*oQ=r& z-y@HsN3oe!Ik6&sRo0re;wzL~xzLSti?DHhF_9A$vHq`b6?#=}MOMj{uEbzCnsN zNlxbR(j)N_77d54M9kzoihCwN; zUga_e%Xp@E8SMV%;x@;CN`mY)18_bp;$SKcp z8mvkE-?yBA@14i9?MdHR=Su#;Tt1(iK2Gm&heNHr9%GN^1lO0Y$cfv@b{e})J!AK$ z9DubSH`t~HHk8V_hFvM$hMuu~iT!q0T#r?b#~Ab)a-gxUg17PMW9FcxVngW_x#8S- zY1jen>`FIwJJ@oRk#U^aUJsD=e}%W*+48p^`$3&H=2aixG3y!j47b-q!}!J({rm15 z)lPC@pAQ@jhs!}}-su3n3HW?{oIQ4-K5jXFF@2mrHd-G|LLVO-Cpqsvb}@YvexW{! zg+5+BPCcjT3-r;8{gtnRdFqBWtWRe2!&Z zWz0)n@Ndjy)K^jmlV$B|#pCG3!+8HsU#-TbyD=u6Z*WY-m~ttDzQjyZ#uugp5*<@r z9=rpiS!nffvoqfQge9Yn=GnUAzQYXbpEFkcT{u8%4qAKAI^%8hl6SCgJqiSY_km-; z5O4!T;H>wvy)pv;dj2P~jjSXv1FE2t6U4f&! zn2PgXa5YsVJ}#%?Zd{+E-uTlI<<%RKw2On_f3foEk|4S?=nJo@QuEYbOC_%Cx!B!O zs_dV0yA-ASFRqv3dBk2YMQOkIhACCfBHblZltzEc6!D|3nbLUOElshPMp2rWTcfyq z`g@~vaiR)GI#sWcOQCqWQ5Q5JPV`bHRes&QOgui9H|8oODlg_PB_3CIjS^$Ho1?yJ zRc*ba%2DemsBm0YQq28ot}ZGnsj1=a!h+)Zf*7`8h5g&b75Rc@kuUJ)6%dV~}uUd6&mAI*d;nK5C+^S}+ zt*BXUo#nH3w&8!)fJ?H-xe6E2lvP+uYOK(pG3)Cz5tPr{2GPDU39$b3dN~Ydw zW~J7OaP@259iA93AHN@rdy322#C>SE&-BgnmRYT+j*_iS)*s|#&uaJBum+h3&JmquHf>qX!P7-Ys7;t z7Q$^pP)b`XRRANgdo4txK6BwUb{89sVtOso#f}N^`hpAe&J`b7Kc0UOYg}u?Y8IQZ+f%>KtXL4RxF@ zO|b_T+BIpxDi<3ZNzH?|=z?oHJ*^G6s*iG~TP|Y_3ckMTW_PPcEkR?n90afCuQ4K! z+AWVKV@99 z#aiCF1ZX5ayQK{3TnikoP%9oyI@TJ&EvA#79hE^d0Fjk$X@ZW85YrQ@`0k&FkEr9^`xsu?wQ zVOpROn_{Xi)sm^#={$?uF;KSC!mYin`KqE-mC^Xu;2KNM7ImO2Xm7{;tjMa}y_vgt zHNcdpW3a}el1)Nb1QNGt6zd($jSlP>71%L4P^+Yx?G_P;>5m(3t-Bp_vA!v4FkIuF zQ#H%c(L_t+h@Mc=D)gi}MypBnyO@^Lkc%m)q_t6JQmRFj;zG?11sYTx++exAmNsux z{oB^jpim03Nu|`tU`55rr3Hw}>&8-j%_&*b()A&#GIW6vO^i+x@&3F7T93wEyse$0 z&z81t?C9Ls!Yd)1T5=x1tD^>pDwTO!qa7KHt``#*tpizCjE|Z%Jaw8Dofn?^N{hs! zydtSZO+_49?|3S`KHMOymZ@_V3AzQN9J=NxZ*}k&jgQ!)CZSP$MA%3a(!M@QqzO7l z*|vJ)qZkJee^g*c)Sow%cN4c@L@V`f@iYoyRd+;!(&jdIrxp}#QdL2;e7m5wx`w}K ztVq^$<@7q-D63Yj!n;oCaHs@;-@P) z;-@QL=NFMej2EMa1L3I^Ay_SU{bVDSg2MRqAzEU+AJ4%~H`%Xic66x240o!tSR;2w zCnZORt`n+Z(XOl3z|kQriU;fM-~taVf!dfn7z!3!Gu~4x+ZsL1G;`=Us#%n!@k__4 zS?WAuVvDBa5hD3=#c;1kZekczJtKK&4PW7H^<3+1?4)@+;#Sj&fJpk*4N-Mew7DA{ zjTqXzowQ~m7DEb_uw0S|$1{p@qDt@(%U-(Zo-5`WuV=HGffi?-w_z1cQI*=&?`nWH za8WrCH`PjGsK|(WbQ*50kuae@@DSTUKN}$IEs_ZSBphY9vAI)?$jgmzys#)IQo_TF z)-P&nYj5P+AW9zf(Gux=)Pz+uPBiCI5yDAPHK#sKbd$8Iy;EtU6skjw#NCuub*P@z zn82E8$>{MSgy#_Hvy?%M59xHY7iAdZBXXuuIFc9Fa!fp-YwlY^7s-p9$jv=H?YgYU zH&Pg9w7}-A>)KjZH8tU2QX|y3>D;FXKhHqRdxVbmp!hL9 zA{`Enc)m5{;L*543-xy3`hH4`4Q7LW(iQW)m{)ON6&)sdWqB8+g#6G*onIqtWG)j2 z3S!fz<8+5A!dGktb=-w$@=8Y`0(HB9{LkW%1b{^m(ol4Xu$_wEl z9-?MZJ~o1=Wh6pWo~YLaX`+=Ib@&0vG(IA1ySufcS=e>0#_&QTjH)*=;V+^pMch=f z#!yuvZe2i*E=3NX=tQg>U5XsO3=jc)D2=#vS>@_d9pb(v+$;kYhPD8+gy50g-8oKwsv%S zS{CB>2^Jz2(ODh!v-l4wlvUtu3H`TeQGHRR>dLtw1yW@-G;s|Q#Y-?0irsVL0_(;O zdV|>LX>w!rM{fn`6}tG@EjDYTmHu_G`=6I?8yGkck5{_P_k8%)fq{Xp)E}x;=5&A8 zO2JnPS|O-C#=nm9`?_3$DuVh1-7e@0ME6Tw>>!o1uge-k?VR7=)i3D#B0PCejh`o| zPtZ=H$nOQt@9**pdW`4+bC>H!YPv&$%0E{52RYr}Wqg77{ap&D`?_8sdLXWA#ZQQu zyABGv;6*iE9;f@ewh%@58R7rnPgVXb(fy{bibE>@GEvlX!C|8NyL?0;??KM*>v~P_ zbw5+%pCO9yZU0MrTvzfDm39j{^XJ4HyAE<1*ERDOYW&?q;h+2xDCw2xKB>zk_)ek- z9}>LfW$-BHJW<5A{U4R@Ckp;3(E}5@jIXHv_X>K1=z*lJ6~7{y&~;SM{9mj59zoe_ z#3y$h`wdZZSO0H`CUp(?L7|6ZL=RZH?7vg_W={8Y;X4){?s`L|2RYr>br$qM!gF2S zZ<7DM2tCO8fvy(>JtXLxoF3>pEBH?YJtOFlpvOQDd@ZT#=J$7!_|{|R!?)Uw zs^!=Ptq`Zv*ArbzG;Ag(2=CgoP^d~`Ug})2*KHqo2ebfp06T!kfM*Zz*E2>;19qVAZ4wue+G~PIDj>P0(1Zm z0gnRD0xtn?1OEgJ4Zi*~AO|P_Rs-Jz)&pCB`+)BN`+y$2lyf22R;O(CSU(F zU=EN2tOUw|H9!;43EU0z0RzBGz+1qFz*!)99rOe&0!o4F00p=ecm#MF_zCbT@DA`P z@Zl!dgW~JA0t4cm&uBJO}&?_$}}k;4~n4kp}o0-~zS*eZU~_67Uvq3OEm> zt@rgW11f-Zz*gWMU>EQN@B`p5@LS-oz!^Z=;OoBxm`xHp8ZXnLr*;23!lQ1zLe^z(YVP#`+9k31A1l4r~HqXSJ&qpicsy z&c_%A6u>P3i-2?>HhwHW{=bMrX-J-jm#H#Ipd{A~MXGE&u2ki7=c_XQW@)tCpVvU1 zTF7%X#suISC2L z{olpdG>`G_u%*TK&|+15-9%kluZFv zSX6g2mHAlp}n=peAl*WYy)#-k@ydkOASX+jsq zIk@EqeEqoVlRpJEXp#T2Ig@6>**1aVP(Qg!@Dz{w1cCa3_GspOIXn^pibu9j zAloONK>1N0Xa%%*)K>^rM4&j--?Vt`a8usor`dfm2__zjN7x2v@y^aezXVp262wDs z=!pj?9+i_{r=r*jMm$@HW@&(cfmcwftzTBCI42@ld%0 z^3vkv-v_+_T3Hm8;?Uy-$e+qxi8zG*OTmaoi?;?m;`lUwiZ@qdKs6D@sqrEqUc~E( PaM5_ks=s=5iS_>hkCIXr diff --git a/build-scripts/android_libs/libcutils.so b/build-scripts/android_libs/libcutils.so deleted file mode 100644 index 825852b607d70437a8da5cfa236be119b8de1d16..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 55252 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 diff --git a/build-scripts/android_libs/libutils.so b/build-scripts/android_libs/libutils.so deleted file mode 100644 index c09e96fdc29d719abdc45278c80e2b62a55cdeab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 172344 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