From dece536bfc96c3a4bd65aa9de35b7a667f18b2d6 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 df6f09b78dc068d33939cd087026b6054bf669cb 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 26026fcdaa1a10ff3f8edfd51b441b2a105c0dc5 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 3634d8ffac191aca4cdafd26c7b81ce64594faa1 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 e3367d6ac7e2fa92d567efead558eb647273ac5d 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 6251bfb6a18fc147293c854c5a89e6cf6c82bc68 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 dc9ee5ef88b32f97f98caf64578a180639a685dc 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 zcmeIbdw5jU)iA!!+;WFN5GHWINkU-4B@9V`fT)n`%;Z8OL4&nsCYh6*A(NTS%p`!K zrfR*n4Hs=LXw{-`3cGEzq_r*drPZ%rwYJWPwpwjFS}$Az#<#Wyk>q^OI_J#H$$-A~ z`Tg~K9{0m!t+n^sd#%0p+PAY0``l4kTg5O8M1vO0fYkXV03`sRdjLQKpf3Rv=)eqF zFcZ_seLDf7zvr|d{dC9=Amvww4ZA`5=`k`>N$&-S{x+lljF|xpO1cKw?v4LW0!Tkh z$MT&3aHk?*Cjhi6I12!N1-}^p$^l@mLOT?Q;Z_xnVHW`02mrSv#H&LG09*+GUjqOy z08{}$696m+03!fg4*+J6ZMGEvb|{(e0J&aQDRct>Tnhl#DRe0SEKqO)0J8yLyFzyX zKqCMw1%Q=G+(rOsQSc24jD~Ljz;1;o0DvF>tcxZBz%s?;(ZB;hEdbmO009870e}wx zHUq%d0U!qeIsw2906hS(1ORRVfNB7^0RV1`7W4%nNl8oo0v-%$mr0+dic6PW2U1jV zUlgtYfJFeHRWU6DfW;~rL!LsTU(Er4c>qwX#N`7(mV&E8hME9?`2a9ei7Ntt)d}gT z3cVHpRwbmV!*qqH0f1}(Fe!8;092?LH>vP41+NEyYgF+VW&uE((qFLeZBfz-0U#Fu z+5un<0Mr416#&*N=`#SJ830x&v2c%zQ0KT~rBwc4h68xM2(65w-7^M3( z0Do8muwQDcBp6MQcQjhK(w3VN%Evw)4JhxsT7W&*0E{W+)h6is7yyht3Gj&?Ux>pPE*Q?|8IjHJTnE&so0As^)0a*SPEx@j; z<#xsT|3+0l@|Q-PQYrrm9l*aT01hhk@g&se8XW*r1yZ|XdFK++qrMs~FO31<3T3}V z{*M@d*NZ{w(@5880G?V6(wK+zP=bCTwAcOd`aGd(546vxDjMtafXpfdq;X7-2BaTJ zmFFuAXrJgjfdSLadVpQ^^7w}OR3_NxFA4e`(gHklEx<#Hz03*zbYFsfbQ*y7i{VmIV85(E)U+#*@_vpd**hz{Uk8$h}uZ=D9<#Z~d~%%BDMwQ77ANd+j4 zjjz+epPJtkwc>>*N0LSJlD_?IT2uCGi71nP3lSX>oGSR(DIccZb{S zYH1^+h4?Md#dUT0dN_n_WEZsDSii>Ub@_d6*GkLvTwBoRw{;QE%Hnpn*B#(ndZehz zo+*s08-4yD=Zdpe6iFN|PeTtVrL}Z%T>&mwT!f0q0$M!2juzr~dxKL-Th(Fp`8osj zzH*;8$n6YP0txbd&gp9D;DQ0dwYl5fZNPPSs<~i!x8Kisg9@h-S?Txt{LpfvcgMC^ z*1*)Pn>i2X3~)_SxiO}$?jX0b#l;1Je&4QySdXu*6V!=Dbp!8h1E}%^T$WJx)(F zwcZ(Y_r!RsYoiA7dE4C`fhZ-Lr@|c|9_Oy9k&WH{c4wPZLb)Wjp|!ico%2`ueOf+j_H0ULUTJ7i1=OjDH?YNoqx;Vcq zaASSN=1sN=OljnTSoh6bThQt4@NlZ6Et2_^O4L|4BYUl{Eg>e_&fHF0m$O5vY?<5Z zQqxKi@tT$U$SzqE$&9Fgij?cE*iO}3ii^1p4|-^e8zr^0`}{3!viV!u6i068iCIqN zu@$nvNeU_zQKD2#b2gI)Ew{8uhP`J6qbFZqJm6j&7&lrEaIy z^5{|-Yl)2wHpI~_6ttQPHu!yQ8(l6x7YINg=x^&H$WzV5x{|8pFSU4iQRTL6v3fg$ z+)j5e*3sob#_d%_`Mhl$w6wSaz82o;b$Pfc#TR!}*WTcF62kdwxLuV~($qurT0a-y z{5|S%cxA#s{lBowqxR(|fXkF#{N+k7`Eu;5z8w4NFUP*-%dwXxuwOEy6|IU|KXEQh zY=bY6HL*RuMApQ%`4U+Z+v!VWO>DC-ku|aXzC_lDi3 z?DWncINREA2yl6Pg!6*S!%0hvfLB_zw8y&mlr`1L&+DPeswmdK*2vRmY5B^^%{7gd z7InU8T1A5UMB~dpKfa-6>h!DX^zy*eE>%W7f~iO;$5Vo{%JKe6GID-3wF^coLa5!`Z zozVmi3213)4FsZ5alEBPN#VRM30I&rEue;#)wL)L8twtmBms;ounFN}fKL?IjL-sb zUV%3uEC#r!KnFrxSKli`7t(0}I;7J8c%-idNJjcv01wiY0O?3q0tAtE0PIA#4q!LJ ztpL3UI|1%SSO;()!W#h|LO2JY58?FyruzY|m<3=)xClUZA4vP)WQ00^bcA|JScK^SCWILP3lUBOFeA(aScWhQz=CiNKncRR0Hp}$0jx(jA7BH*D*-AH zngFZ_7Xs8GTnx~F&fVUC014Iz=0Pi8(25=H#C%_m&55PFWE`U!E`T))&Bmfr?;z7av0JDPtI)u9c zk`dkkkdCkyAQK@TMtl{%3SWhzpm#OfDDx6i}vs8Gx3fC#P{-uZBy(r3MBL0aA zA5-D)sqnW|_-iWsWflH{3O}mCkEn2}!VjwO11fyK3V%q2->t%TtMH%-_o#4}3cpE( zH>vPi6<(pj*Q@Xn6~0V`FI3^I3ZJFI(^a@mgL~+dtQLH>6iZ`4P#r6}T*mFV@zkNa!A3Gt6^n@t>=7cD|aY7VNpAf|h zCqyyrHBr>^$^2bq%&UxviS(ECZro5ts>x_Zq{;Zf^i|ninLmQn&CA%Ilre9*Sxw|8 zWx7|lE!b1`(O(%;MVW~u$Fwy%E9BlN!8uG%s?o7Y)>|v) z8k3819VS*3&Yi`-nID24I;K#mv!^8XcQ5h3_vC-^FvtJ^LJTAFm23{A4t} zHoZQ>y1U}3t#^*(7}M-#RunFtO|40@rP&woPUDltVpeN{hecuRtY+k24sxvGYXA!w zfQ+X_5#PfbpDv17uZiN^*HC^^O_KfAivH$uRv!|DyU&7|32opZ0w$FE?;8O&FaVjO zqHs#YdZpB)DE!GGQSh7vvo3TzcMqfG83z+No;So8+00|VRq~P1IdyYtZmT$B{EG*c zXu`)$y^JRETyZvkU-isdZMKeurA+vE?tW&Pt;=|E70-iN6F#0l%rKFqzW(atx%-&@ zGEL|}8H9E0anoJQfig{46n-h{SZvovZj{>*eT|G})MV7%TJiO4GcO7Y&gxhL3+9Y) zx=9oo&K=Luu}t25jLFgN_`bu;=dhv>Jcng0QPuIUVp8p0{O$^7X>wR^GuR>TE(hAw zU=oFjvzf;}*b0EQvq-i}sY$85wSvty@#SnvNEF^112bB2-B}Y4IigT;4sH00tx+3J ztDRP}yW$^`Ep(ws@jM=uLa4tw#eUG3!(LozR3_u(^>QiGMZUyU^A_|EAAZ0H=5ZJiztN7n%Pnd^8@A)QP_PJ^1-Zq%Q9aSo;%Cr z>uoNhN#eTYtY*Z_l4HlKO7Xd=27ru0o{r66wGJrIhmu)Q2#H{ZP`(2#biC@)^y5>~ z$4BSZ&8@w6%lruDO&c}644T2dmJ_WtHf zdtX^nDBYTEOlDcj#T*-?+fx;3DItS3)s86>d8}nCpiEwp`SK02OdN+$9?CLEa^}?T zt`LQllVE1TjA>!yPB*he|K?0T814Z ztPxWp+3edZQ+Zgzg!-yAk>TQbe1A38)uqV&lU}atn|fI;8J$}@jon?rm{UVWYql-h zj?%0aEN{A~XLBR7?N1s{cwlL2Xa*Zvna0CXeW-z7$@W*Hr$LCx&#)gf=CK!xn|Uy& zhJIt(2yM;C<=7^1nIR1M=y|8Fm+Sshy=-G?EFPUzt7oz1M<(Q&FHmYe-8x;Wd9x)w zGA*Iz$@Wy+Q${n}Y)O%7{)!-S?jk6>h-=RpFuSlAv zNa8K&k&FaMN%mC9#=Iiwo0D;?;(vTV|9MxD^S&Zyd~|N@T_b4Il(5md(CF|$!SoQA zAfMTPplWVpmi>jC`vF@n%MN)#izwVUX^a>hS48sItICsq&8%ZqF(t4>6DoEeDEs6s z#-cInL(EVWlVpH}k7a-SVO!OF2V>HXj30Ysi(E(41AXa#?~~7+QTIvqOtepKJ0l9s z6Y4&B=Cjnx^vPeGj`m68mP`BO|1N*$6!~wTj>=zhMih)w{ zE}~!d^62+uG(+*PyDx%yMkuxB(K20#DSos}8wPhuWP>{?Vz4IJlF;wxqt`zs;@Fqk z1hCZta4{r`&*S;te`MR#DRuM4>UQ+BC>*+|w(ZrIty_AmZbut0SGU|+^eRm_$7(W4 zv$X@vN#O1Q1C_)Pvr=1${G z_ntESTbVWg%6ZRdVp&UO*yuLG3^@Gt2mW-od9IcmPf`uVi8WI(E1^Ibx{Cc6llrXE|({@FdOz$E)t% zEVs*I14uH-=shE|+4(HwY7gu8>h@~)!akHI3hknn1rsct6H2eu_iG1r15cMFg&_|L z;ICSDztQYqOeql?Q(=69-wO`@y5&%*+6$54Ip@A~(+ssu1WtrjR$h4Y)vgA-{@jzKh z*bqstfk=AIabtQUt>&{2(`r8bFs!OJ5h(1n6r`JudHLy6R=kZMOjBtiBmmfH#t|y#Ivj5O%W^tCUKP3uR zeOBebe)C2{ybicl$*jlG{poBAd*=wQRc<+Do-Ya;PBCUC1o?)DMP9i)EDD7unS8w! zXCLHScuHQaJk%hsRd5XiJeYC)c|yeXr-{c^t0>%lQeGF`IbvX$;dyoGtSIdLj2XJE z0+t%W@|?EZXl8lKl@SYzE5LtzhBFN;oEw2$rjQBGv>!6IxksdxnIV+#b~D!-3I7h? zU!5FDwx-+C?aPcNmX~~R(}a#?hDG6LqGkkFNwXVdUwqvluNQDm`@2D&-^NGp9Wk)_ zVeP&Jb?NLJRurl}(@T2k!*i|kZ1YgB`3n`T`W3CNj6fc0bw$k?W2>7M&E}ynJ(TNC zf3$(gHd^_2_>2Sa@H&>+uN@kxPKqRNO0%Wg&t+Sr(QDObI#xd{3LRq7h>0CPcKarP z-C8<%~;81=PyKUmTjGDn=9GOWHBk)*%a;ODK^WJZ1(tNY?cy9vA(qM z9av(_WYg>>$!e!B$W~(&s~xX;w_et(LZz2Hf88auBkF_}`=Ls!Y(=Y*m{yY)N~((FH7xWZVMW6LCeN2iz53BU~ z9_}+ozd2%HwZqK5sHI;1RIBvGxLHtaexw#wYYr3m&g}pjNii-73AlE$Jn<-)yD*zVT_)+q0}$ zwpn(wQ53%W>1?I_Uj0<|tLYJ@P!rCmIg7JxevZ4{ZD)RHe23@xBi?oFGI9O)=@p9PhZV`wrby0nx4WB}0;84p zd*9*v6uI3K@)&fxBDYB;H{K4}N{y41c1Q_dVZE4hKj4@+%WkrW!n{xCDAKQ2q-Rc% zZgRJ~nV~Y~2SzKuj(vy!q!Vk7b}xz9U8CrLdnOzMqvN$9BnqEh1hXb&;wOb+X%Cw@ zdglo4Jehqsj*G&>=cRqbex@JH8KFtx$0C?hLa;0;#PCp{3*Y6|6%WF}W{AK-9DBpk zD1y%=B5T|Geyn$>CYnD{NOtwzpVB;lTN5?Ng@IewxzikGnsZ zQu`xa(c1sFD0`j8F1I`WzYpBY$@NdE1%7u0nA1W!%cStTvy9mg*4y-Ug9)E4ObWBl z;`(&2P2SIzy^hZ^ifiv2$&hwqx-jH1`=B5#oEa&!uCT3;_GKF+uP;BZW9uTx?4)pB z+K)32GefX6CA`r7gfW@jV9B>FvWtS{ypCNHDR4u1kaRjxbU;nqx(j5Z1SGl>a*Dy!zp{OWG96>F?k?! zcv4s^P9IJgxV>UhC=r=unlP+L3jaM4v<7Y6_SHrU%Ug0HjA<=9Dg0D~h1gy%L|%!k zbzjYsDvwxzjVJ3w z-J7}0my##`#`uY8!&{~Nxp29|3>2Wjh<#_IB8(o@TBnKWZFQ+@T4$0nL3a@JSjXgdA03oJFH+sOSheLZ#NDB z=37_utTDAOwSOKDeOgn}zDXf?CiStT!BX~54pDgG!i;_}&y@Pxy0K}I!kQJ+v6NY3 z>BFL6kW!Kdw>gpe*#+c2B9-#XiRr_l@S_Wv!=iBb!i-^2cy=O7nvW(0+eA_ytbkC# zhn5dpt7SjBN++)mzozUf{W^dYW!#89qs8a7`203Hf8e@yQdl&3sn74UObY8Jqdq?= z1f?fPkl^$28RXf{%lrHzlj!p`7i6Emrc%}w|F2tgOedpEF65-w=vc;4=18;NT5;#d zd}AS7vf9E<3J;wzv&;`lEzJH&;piERDLW&Vb)-UG!;g<{t$lDLiQQe1!Rq$v_d!8< zD0z5N`29rk5G+j%Z?^tE=S9FBK)R*DJ}JB@8rZ@}DO$WOblw-_bO+~e;heChbX$ zEUhcF724agEo{04@+O4`MFU$EF$_V@z;!ElSTQTKggsa^hldr@LrH^~1LKfoZ02=? zutz@xInPxazW3a9xL;uwYrd;nePmT~VI-`13<{@*wT~Xpd60RuEIBmOI>)9Rlq{*F{nDQMe%v=5 z22)a>p-N`@p0>9F;ViEmb60B}ofnlJFUYY>j1|MXYw{ zammYMS#x8ux+ee2@xhmtHS=?2jcrSm_1>vyz1DoLEMM)nMs$02S7`U^_a^OQ%-ZnG z0Vv1{8zS04x7BUSG@2}KyCKqEr+tjK|2~gon=Au>K6k}M1N)1}%ma|aEY5N0h9G}; znZxR|=^_u5L3kOfS(RKom%p=22*a`)-qNi4A(+`o;owQMyCJL{yv}-qRQmPyKYzG{ z)eTGveJ7a`ZGU6kL0Freyr(jIiTlVR!`^g$25Vv`g_)}jp z{Qwl`LfRqS;C#as|D>b zl(K&v4@*izDMMynHvs!~Z^M!wuLg5rNZ$|UE5dn^(>%}T@yt5NnG}wF3TE9~$pg&l z2YopwM3$*e)fzM^IZ{YK&YAt|PnJd1b zm7jl&k1nmhcjR__h954dEy>2`_mjf6Pcr6=5R<3fS02f?;+hcG5f*7=$^A^*R~pH+ z=GpUESX^v;##p;b`(52W{hk6I3QVDQd1lG{u!BG2?ym;(w6KHM_MP_jRZj}?%OuB)q*a_j;j~?eIh0saJ)#NaFxy~mY?>Mykm^DXMnMyP({uI{NLjIcU+gy`^ z^MY17%UN`-yhg?`>XdTcg7cp9bx|B2-M;C;5gmI+g?^7=FJn#)d+Tn?#=Z5V&~OsW zNpGh|wplxEo%U;urR)aFZzB3ZSOVc^BC{Mnj&#&?Sa}=E^Y&|+^VnU+Ul?)LpAZ}$ zec&i$YgaF0A@693cAxIyq(>|~lVdOYA4icB%-4jpL$FjI*7Y-9Fx^+J8*FfB2ae<> z^>_02a?QSP7&D9RG^VfoiCfc;7MUGlOeYC^V<_9g9K!o!ln&=?QPmcE56d-Gcse%Ut2f!vhC=&zsLw zrmXB5m$pwcaAcKfHM3H)M^o_Iuy%-9ni`gD9LjPSz6UEZLWak5`Kuf$k>pz3M_rX| zl=dZ)g77Is7*m=wmN#D$Z{u$&Z5&&o*G2IM-xtNd<9!&?v&i(? zbldI;b zxXR6!vM@e8;dLyxKV>}Ufx>lRi*03%!}zYzT{R(C&+%0gLgq&}pXS#rvqR1Y%}d$Z z;t?ay6>_C4lMCY?UO4Fj^MX); z9+^1jGDK$8&)uXoJ(2xx_Jr`>*^C;-B-hc+LxCpzhNpZ%|3>|$cel?aBO(iCFLb&goC~OqqBo88>Q#DkT)kX z)BdC}i@jL9m4|}t&~Nj$LPIl{XN6KC8TJetNj-+4WI zW#kG)x8%@k((^=J$dYj8X<{#0Hu6xA5_%!0MmoJ$cw#4>$E*ImRvybgP~@Xs$>%U@%*$%dd+*reAcomhqtg3!Xx;G29Cm!=kV3no>3?cS7)w&9kxfti8?nME29o$;F4;ir7+C zckP65^lT{$ITHdsJKI{s<`_$Hb~roBHfz%r);1&LUg@~eG3fYaJa#t2hUd9Xk9OaI?r1yc;xMoRmNVg<8 z#4OQ-YD^o-^by9PiEMO0%YhWnnXG80xP^e0|u=P6&px&o9uGGW#aXS#O*)Y6m8S2gdMS zmjadH~4chcbcTDwQjCbPPn*{puwgusujs)fbqpKW1nKl;kaGq`e`9-a`` zGw9=mR+F*Nw!#j5_>@dLgsphznc7H!eW~^PM%}(#V>YXmX3d^6`k}uhEq#5Ft&~Nt z`O6vJi6dlQjlrZFc-M$CtLu!(Ud+xae!LlS4EwZulKL_trL1mXLU`c}KE>MR*7f&Q zYX=NN%?-Mh+C51F+QIvpb$wty6V?w6CK+CzVfFK!?wsaQRutxm`hl7x!|UnxPIoE$ zMDw$}D9jL3MoQW7W4l)a{PZLF9jjk`B#N(oB#J2?iQ?NIiK2-CD3RtPTb+TmS$|kz ztJCkZ)!bIWSA5jGp4T~k!oxx^9jKZX3GnkI?@E%qOBWvCwR@mIA9h6;OL~c;^4y7* z$W=CN|5de}M#H|8ANS^7$1Kf;K7-@|Bd0B_v@XsQg$*LsBPEn>nh;((qx&8#(y>X7 zD#tyJYa`nJWwldt?pJa$d7_XfCiQ`Nsg(0aXOaeVY_6Sg=!SZ8Yz+1tZU14TVG#Pz zdv=~id733=;_m`_J=F5|Gf5*C@#zd2(FU-i5VBg`QxH^;5AXq9T&xA_{+p+%!%*YO$e(` z;s1nj>>{JcH;YY|_;O-=$tx#>Yfh)H zN-sg)@i30#=STHyIy;-qlz11jW=HZGEOjl5U!5>8qIauuPEj#I&SH2Aj;LuR_hpX=Z%^3(Ni$CX!w8sZh3*Z?0sy@zJ$)Yi*GG z!-}a5!b_*L z=6T`HDz;d=FQZ>OFl{J>S{<4J6PvVeLU{R^I{^DAMr{!6El>=yPrkNvngI_5Q;+LQl7_@U&lM<+xP*G=~n$$nBi zE{YGnA&NEQ@^}y!7sXr0ac}c^_Bem?QhVHf>T>qDcyg*e+7)|za0>Oj=j7$=QTB!Q zs8HfY<@;rMmWVb z*TEUh(u!sCDT6)9`h+pJ8RyyNQ{)(4_&II@7&FOh4qSWSI^!)d^Vr+3isBouieltd zQGD-JQ9SvoD2}}isn3D6UFPXwT>RYCeo^s7p zlvdr+lz3?r@+90ECB>=ljZ*Q%4IZ;=>{2L+Z^{KtT!-pXCOKVoFO$SC>6>ts66Q;| zODP%`y^#!{vbwgVep6G6t=`sT+gNM6v9dynYur*^UfI|v;bj{uS~ez-wY8hd4tjcrV?o6fp!_-vUxXzSMOhKP1pFo?_<3V&2;k?zgrpiXs#s-^dhdaodygrk1 z)0j!=tR}O^*U`bbOn9@DiEw_Ce1l#A3m^R8+@|o%? zn>H@5tgZzmLejp*x>>%}%!I8Kqgq;>fy5{x-47=5DVMb=_n~>E`|4Wc&O0SNu)|4O z{Lw4krX=BYYJTZzxM)U*)gSy^dz-J@8#K8CCa-UY$zpPQO@8@eKXU=(yVjZ1j%&^* z1tz>7jC0A=Rv6-*d(lQ5JTx)knA=lw4Y(zR3bhh!0 zywk<`p~F+gb-29^oWH%!=XD2t{*84N7>if2Nf!;)`r0H5DUr&Bgfd5!-`T~Zmwlyf$SX&g&}od3;jANK|g`j_IMMmE7v6MvgfBczIoiTuwA=G+vcO zF_@Gc@hD3)t2$1}Cf&$bfp;Nwcx0lnyH%mfd9JNfWtGODGuRz~j?YPuODy+rPOPQ` zqjioG*oG=fm8XIuLB2hjEK`ZevD{L!I(K7`^R~G?Qg*!MGSQ*RJ#NzAae6sfLX?OK zP-waQD4`@`yOl`UB&@p?g-EExE@LX*I%l9W%F^I-<29QS*+twQF6OD_zAl2d0dlds zBa6^gFO4p)h?cF&(AeE7O|O^ciKfJ}kzLW-DHU!hBFcBUxL98K8c)Bk!|&`u>@ zg>H|h3UB=E@F>f!2B(J$2Dv(C(C=1EQo(t+AQ!#w64w++S8?7pE>M4cJR;ut(8Cli zRitbLIbPMl19A^n;$xc1w7Or$OPvy{E;d#%Ik(b(<%}fAE4@o{J*AB$e6!QrA-R=` ziWWFgl}%}hBBdu(dU0lh4h5NNCOPqPR+3XLXQWE6 zOXX6sM^#DJ6GMlBNDeFcYn7)vAjSJSa8N+dBSUQDDqn|Eam1ntO667ltad`o7WZ^@ zifnvUV$2d#^TeV*FGI9PSNVP3pwefn{M~_Icb8NN1&wBx5~S)VsGLyEdE*_qn)9l9 zF;ek5pm!z2#7aWb7G)|>uH%(9 z5c1@(#p`bO`EgvU=7RD%f^*4ZfUE*W`rYa^Lp2vH^Z7iS(~B*Olr(=fII-$M&hMTY zEf4-mioeJ$uS{lTZm-k7D_$>oibHK{eH~Lcqt2)9IG425=Oo6;m;HZA@p4py zpKEgm+&*uW&)?+?%97=zMqjsIS_M>dN=#H0x#}`+6SuR{+Y@a83~nVF_(nLCnZ}z)d}Uac-NI{U<<^TN49|44b7-07w5rIOhuvJ#z`E%RFqt#Dk6bfF|))FD>q(btTc5&@iOAs zz1$6MR}kmt+9)pPRT5(Py`6D$)cTw*n~U=X-9cP4At^6mB~48tvY9C8e>?cdL;b#LB ze~V@EyLX~;SYWpYhfKd)s$ZOvgvHXL;<`OScN4d>+~@PVq;1gDm}sUrkCL$-#|cj{ zR!u>XHHyk=$&{igba*!TgS-!O$cW4&;h0xOt!#$(W? zQ=_oJgczk{9ED>!B`YUJsTdpaB6+1G#3fcvvARTHY)qI$M6-K#b@;rS+S>yh_VNZb zEoV?M#4-`N)~*D4;={+$Ul`Ony=02k;;`2i49|7 zsqR2PdY;nAdAK(9q^nHm%Dmdh$!i~JY^xBdT1n@FGj}ZGUb7SvguP%s)s5{ ztg;zYQJ3;aynl|GYy0S8R#<6%L8cLZ!W&1~G(|Ek% zzsjr{<5Eqra+0$5Q-~?K;$>HJv1xb8V}>XZ-FY-|@kv#wO{|ke>lBMnY8Iyz?PC#2 zE#q{o7V)S{^2BQ}<>5yY7o%g!`kmf@NAc?zAqkD9C=!(ke9>|Y8F{nb&O<)sS$~##Cx2~r=s25 z4uW3_>G0gZ;hsfFLYJHR4G*qE_3$65DPJDJ-CX=*I*I3Du~cQF8aqat`X!WD^yhpx zMLEoj9>>KG@l-L1M}hKVy-UvmRWa&QKjq-{avw@cIDMVM89kx9%-JJ;oJjuQ5MuEU z5vk8GvEoy|qf^Z(A7+Y{sO&Z_JtV|)3;94gZrsE()x>jG%l_cpHLH@Xl`gC&Y zrMPOGT$aSsoxLa3n9Ug@FftGyfLkiWkm5tJ$o|P@-buw0TNe(=C zYHOE{#u1vlzM!ey*X?yJGj#{>1kuH{JG(v7sURMqE1%th{B9He3%~=!o!AM$4}*aM-|BaOr{@_;GtgK zb4VZRGKE=>3eIB%Jd5e zM}~Ws9h2n{gol{kBN9E_`?5ke|4Jzj;UT7X_kSa;=}kW_!+r%W{58_L-Xjv!^e+63 z%)cMuVO?+f^Rhe>!eOS@q0m8uhjqPU3T=Er&UX>v$Z)Uu|Hw2&I5OP(2ExNLdv(8) zKo;yuWp|9Lb=-W3FI(9RmpWRI8j21!{wGdj|LTF_Rp*OY= z+SNknT`h#}X(9Bn7D9j2Lg=qs2z|4K&`(+j1qY$C9E2`)5L)UW)aoGA=^*qr2ch3| z5W3ev=;IDTpK%cS-wr}U4nqItAoL>#p_7=`NobCf(3MU?uW=Gu?SyC$4ThJPC}n@5_;50=%1W~jynm>XeD$(E1^ZLgxXpO-P%eh-%4npmC$ds68dN> zp+9OR^!Zjo-)bfFpRI&y+X&5WBebZE(2Z?`Zf+y=<~BmNwGq0rjnMns2>oswp~G#2 z{;ZAAU$+tZr#3=AZX-0^MQFB*P_v8B)hg%;=Lo%-Beb0(w2LFOnt z*iPvAc0$uT2wl)Y=*kX4t2zk1v4c>)gU~xV2z{i3(5E{H{dotWFLn_6b_b!Kb`bhu z51})7LQOoO%XmVs;t8$h3GLzueS|0UAW!HsJfXkh3H>8a=-+rk&+&vZZbD6NLa%ib z>Tnaf+fC?@o6u1=q0hSsebY_oSvR2<-GpXuBXsRHLTk4X+Odt$UE2t~cN?Mmwh{Wo zHbQ^AjnHG;2>s(WLjS&v(D7}AGM$88(Mf1QC!tq&657;BsJoNUot=c<+ezpXorI2d z68d5%p`lJf-|8gv!%jl~*-5C@L+ES|p}8JHi#>!^dkEd^A@pVsp&k#Rw|WS@-$Ur2 zhtMB*2>qpp&=)*}{?S9|pFM>B!$as<51|)4gc`aC&FUgFuZz%?U4(AvBDB7X(3`pl z?dl?QPZyy>U4$O$BJ`(Sgg)Oz=qp`>{;iA9GhKv!hWWjOn!JP-dI??cCA7{^Ik$<@e=xmm(cgTg#M40P@Rv^IX*%Qe1u-(BlJ2S zp&dR#13p6U_YwMtkI<)mg#Oe==>PQ*`j(H-4}FAQ@DZ9s2+byhE+T|pLkMjmgmw`^ zcMw9qK?waeA@qBM&}Rstza@meLI{0>5c(b=^c*2HV>_X9w-dT}JE5z$6I!{Q(8leA zy0;U$V>_YW+D_=ec0zx+ozP!yC-e{73H|eSLf_p^=-75bh3$kgenO}D3C;Esy4X)> ziJ#CiKcSoagnr#m=r%v0JN<-y(@*HbenOw}6Z%s>p}+ML`e#3(ANmQs;3qUKKL&EYZbEU!=;|i))^0-Y?!J%o<*5c-QALVwpo=%0HC{h)`? z|LGx=*+FR54ni01Ahcu$q18JGy&&&{%q>TumMLU%1A^wXt;PAnyK<1#{-WrVI=Mrh8mOZgMSjQ@ZK1M2heT3IJ% zt*qDfa#^=M*U0)gOJyDZuqH0|*NucSO@yx8Lg*D+2>m+ZO@!*V5PGaB&i8o%KNDV; z3KG0Qfi49S1@2PdHx&5oRDfv!@M$VY-zLY9jemLp=7Ic;bo^}J5dgr?Z1d>=1^}?? z0PwTk+BASPtTW;Oa2~(c2LL7wz%0P;jRVX9fb~Wh_sqd>ii7kG_AI6R3!>=5Z?^xZ zA@kli=aI$m)lX%E@Fqfgze(uWld``=hGm%COXz#Ugt8A3Dk@>4833d&n**}|+jmt{ zB^Y!m%uL-Z<_czx*2rWtb2STeP$+#vve567VSo<={Xu6d6mHyHSIF&@P}eT6v&-EE zg}gJs1Csb{&_X}wL0m3EqWnHNHRzY~JEeC|x`SK*3R?pKIScUwp|HajghKp|c~p?w zwG#^Q`@bzt>8-E-JS(?p% zj(pfB@P~aN8lvue6#%4wEC+obe<6j&yjWf`0C-h=*jMm}eF%B5zeV}{Aop*Ki?(}( z>U;Lchrit_zVk~!`fWfXC;@pe-~%kw73GvR%fAYflBkr00mpxw@>M8ukuMo}@FzWWlLOig!$QSQ$cN(t z{!S`wgaOM#-W{s)aIC@~-jyE>$cI0S!XK7bdcXXO%EA!U&#jb;d>ihUfAq>|X>q=- ja#y*>zp38BiTnlHPe-$92-izM^jE+G9iIUDNIgsYk*0pf0PRQX=@+pcTNwkvvVwk@o)q@UKY!H2q2Y7kDcIsc5bSFb{wl zDcb}f3Bb=NF91G>l+$!R1|N#xzm6&U6u?*{{~G`w0{A$lo~Ek+d>4R;0j5Rj`T+b9 z!1HwM2=7GzGGf}U0gwyeD1g5M7zNN3t!IE;08Rt=4uD<&cL6X1_#D6wqjUgX2Jjky ztpG*<{2)?y7=Q)9%1Hh%2k+OjZ{5F7_0K5y}Cy}ymN~ZvP37|Am z`8NPf0B!|P8`t1*0N;<4B}U}b5y`&^;3WXh0hj|I0l*0W|A^Gnt@j>)ivWHF;EK4u z?**_rrtEhBiX-`M0RN2OM`CDbdKAF9NLc~{+!Db#2KXs}P$W-NK?I+ODeI5m1i&i* zssa3Oq|6h6*8#`@@OuCY0BnzG-wZ$ja6G2$|7J@3zuDP;Nyh(DPLnCF&J~xR9+!`% z%qRjNI|ir89+&^7wCbA*zadfE98DVmTp!HU%Da;CDyhWdJq+=!_CYk~ad|q6Gi~0Bn)` zoiXJ!9RP4!q--aE3INwe^6MgyCPxG>1aL5dF9T2$!DG`kF&Q_2?*T{$@Z(7N&tvKz ziNVVNI02ML${vcTI~2ix0pQ69ejk7vV`ymF7Rf&tS3W;MExV z9RS`2@FIX`0Q3O3AHZ1ve~qD|>9+tb0H}+UzY~F4yaC_^0DA%K0pO3+or%CS080TF zBR2G#5{-pu;xum`iCeUMB7PFnj_$ubCSbQW9D7WM0do_9wVT7ff#y$ez^;h#OM?Na zQRf6`?W>c3=XYyil13kuWwicHJ#cGTct6qpZcYJqz5vZ;()|4~MvC&I*8@jO!uFQd z*T)zUTHi~ZLnP7svP9tIW@tJ=={HB6XoSC4S>W-j!*LF+e;{Vl)Ao!Jxb=pxzR~(4 zI^g}{uzu5gtlm+2TWUBqq$v%bs8_^|C+GohX*f2d?P<&uO*A%&5x>@7F$27^JRB!d z`qkH!MyE4WBP<~|wcy}d`6X9<%u6~FI?p+u5 z4Ya>M#R!D9-)96~y9t^tr1gaID^Ae|Ss>%;u&<`|rFvj(X*h16c|#J=|2(w4O!J*Q z;4civzcha<4TK|!j&~|feqAX*a`zPfG-i$_O8-X#@b0zYwWIx&rve2uIEm=P)p7Fa zO9B?{fo3l#{bbyDPaA-YjZ^%7s2wW8iH`Si9KXLv0zSDLnxCQleV79L`={X;nC59b z|9tM$dK;2~Tki|ob6S7D5m@ zfk(@r#cnkJM;&lQNjR>i`5he49SMGDevb|~T0FIWGg8Cnu&BIfJpYLcT5Le+zncv7 zKNXIpX#S^0;AF*=ytl>4_q%a!JL z`9<3P@i=}8b->P|@L7=7uQmYX>%(z2%?ok#wMO8J8^h-oT7Q}c%GXVe_ih4k?=4gI z{X=@7h$K3nU&ra&3fg|{l)ca=0@rMw%CF{u8`n%o z|HHWTnw0`P{ruE=RhWQT!j!$ajt6{er|e@%5^#+lxPcGbzvmKw&hLcJ&$Ry&arR_c z-29Hl)n88!#4+>VY64yq!siXzUjq;53d32dP=gAo|1n9}bBas5{_z-!B=;+wI!^*$Y=KQta_ zGyn-3!gn2%U%?2xedAQT^luK3W9-jwW7^aC?=%9v-=1p!j2_4=3*Z0H{_J{yDGkTS zG=CQlWEM{Ge+|97iX__KKRMv#nDMME@Wm=C(fU*iSvKY#__i;F5Wt91O{&k z-zm}l4n%|ANW8W>uKzpZ*8gHM(E9vTy!mbtU~8V*Uxjh{_H7!U-U;+Y_UG0({eQ;< zOn9gEYxM3Y%Fq1x{vxu9*7FH~?&k0rh|Y(emHf-5;?13jz~wRa;6oNz`>iQ|_i&v4 z9OHnEG4k(C0Umz?$cym*$7EpXb5s8JQ9bZQ>6HKY*aYY{Ppy|(2lTF+vY(xC;|(MO z?>-0Z3_|(uh^xOXPCxdWfRDY&?nUZHqT>CRdz_Mv-y}pwS zkY6#HTb+hf97qKI=9`Kas*{0}om275{}_Phubr~Tujql|vZ?r>fCb90f_DE%`P-of z{H0UvpQQHl>Z$SXh+E&PIDI=3mwzQrzi-q5x?*T&Y&zbz6M@}T;X5Cif1U?g3#a7& z81PGy}|+MG5X?+)9;$N{k2dB{A}HnzmDEhMfG_F zwI4C@^nX}j`?se2;p#a3*b=k8)Sl5hyc=_&-KWs`|1`$l()x!O;Lpo}_t>!izKsV? zuAS1KpPGO#V)kQ;4tO^veta`-J|7r>zg-)?E1=^=?-`==IiCb9-8)quz5k5XFN(7_ zgahthJr$4C(@WRLEf+mcjU)g+yLBp_5p=-)#Z&ujSzLctr2wHAdo?FUUew+$N(DAX zE&$Vzf}=d}=fbJ=Pvn7_G5$XgcU~Sb0*f|H>HGCY;MyCf{4=8i9$hzO|369u`nQJf z52(C;6Stm^#qEdLarNhPfWKtwyx^qq(rr`mwJXlwO)~-8Z=14DqXyvUbyNPWCCw>w;TQS=ku$R&A@S61P=u-R^CurVYM6r=@ZIXsy4}c#GFx6GyZoN);=O zYTu4Z?+&lO#=E)32X9rCudxxa1dYDnM#@`ZeM7A`_?4g|D;4z^Z$tE&tB zH9=p)b=zw+hN~I_b*K#1*VNzPYp4u*H&=c${q?~Hf8AEvWuxz_T}DJ!=eq+n^;@;c zRW@v|s|@-Y;}{H67BuSB4ng;8)*WkO2^$k<2Tp#e&#S%9L8+;87^$n%3JrfqWUR4i1glgM+~EpvZ~rZ zQkVkVMDQYSqZq|0BavcHeO=J&uWKyz?Ti)`);Fy6R$U_Y zY;S1r)dfA?fVavYyhP=x-(DB=)YsJb8~ycljnT%%b-~z?itB=Fzq{RAbE!VUeq{7= zUu``VK_t6z`z5}#DSg#YR{I)*4fU58xG`)bBTdVw6}@D}Gy@TxVOS(z?aN>1pHjf@ zZud6&BMYV(<`v5?DL`ypWHJ9+HC=yNSLY4-clatrZ(VhbFT5Ax%Bp=ezF>S|RhZAs znvL1m;0t&ge1-K5H))O}TpEjC=kr#7jX0+8CaO;1W|}O+Xhax|^;O$^!AgIfx4OEa z(p$H)veDPD!`Be0K%*~6N$LYZ)c6~NzPf0OTJJVrC9TpLZogEnncT{%8o#eDSXotH zSLdq=M%%>JeYGq+Xys;qT{X7X)%feSeN+8ZS$$x$=C`zAzE=E|DOA?^f_Kz6Y>V)O z%BtYbfUgo&^>thPTPwHFAtQKWupx?WuCK3&;&t`az9?Q(@4ZA$acciARW|y9*y;;b zRt2_G9{k>#%DU~fn|%$~LQNaBXH{YYwruqU8?i;RjkK(;##gs=MX)|k%Txt+PGzdM z2QFo5e06!j`lTzhZUQ@F@z|>B?SXJrgRiQ-p_)$0=dG=zeAW4yf^o%~H~lIl^%j&m z;;-to4eS=Rch;HI-zMawi5-p-C8}L>6xA?2R+KzS|C8A3ZC8Bd{tP*|I zm4W&if7MQeGqfLCy1mBNpb6v~XlOT=XuOflP*hw{uy%cPz{=XjfVaw587@U6 zx23*57>>{)1-0I$N^cE~HLAZ}Nk#O3B%qaF>+%k7%{EQLDg)lFzQ*WCTCwP((Lk89 z?Ts`XtZbwXAR;9?-JpN#_WJFO5&lsdXs8cTYZ7S{Z1C5jac3jlywS2+I)gwkDuJ*i z{bm7Zq*XKk4mRSegm?IZV&!IUqc2+iHDj)Hs=>F_UtjlM+g;+**Ra)B zS-<&qUsdpuT(rG-X*FtU>Z_tTe_gdN;H#?++te`U-&hxJ^%d_|TVEX|t@YJDIkZN3`=m&T@!mku4}#lLI{ zucm=jw4!>M|4sz&3|kp`dI{{r*2?X{DjFMI3g9b)ccOM1jo>Nft==3p>;Af}bQg;C zjls=3BMTCV;^U|y8>n&%okCr8ZR1vI_;yfu=gzJ5L7x^H*Vp+P#rh!Xymj@BH9lV; zw(<@y4Hm)+PE91$*yxh`>#0GERBo>e`0JuIk+QFsM2u=MO4t}|sG-vj_+u*Bq?+p4HFO`LJHU7;t^;;J=)>Eu10vm(XRoU5*Of7|#mA)o_braoG4b&Zk zbJUtwR#tn1-e`r7W>8tVxv?=?G=*1IMrwR@)fygw+EG;-e|ykh(@4id-f>{o93Y>< zE})3Q0icY+AwZIV*&Og5g$AIH!UW(9g-L)+VG8gOg{i;*h0}oZ6wUy~D4Y#^PN5mN zNa5wcIED1XmJl#I1K=rK2pB1J0!b8R0cjNG05d7f1w&8&yaC9k@Ft*u!drnN3I(8y!fIe6g+Aa03bz3j6n+=D zg~A3vps*3BrZ5PI6y5>UPKWuvn83hAVG@Jo6h=R^{r{18dC|wb{M5%O@?)}b?3W*#>1F8e z9y@FL!y{+SpTG5S6i~6jGj}~iF2yz^QvlwpsE*plS@;`EOJ*tLOSbAJ7X$oMwj{b6?tSS$s($f zKf)6@`BSQL`v@cQnV(8la`EV~!j?k-?Qg7iNg0*ou7YH889^o!$|?6*a*CbAYgUy# zqi`;hGK)C7&FmzqGG`RdENMZBlRRx!mEb6x4k^9VN&3yIQZouCk!*s45+GgKvgpa zR5g1*RjJM-z2WLjDM~F%Eomx9Cd{V2j+COu3zEds*jB**Q7qtvW*hVJyRZ_ptBP?X zlh}#Dsw%arsw^8hR=D{f5M+SQzf@J8r~Qrf&MZqMGmCc>%q;a)=*fNd8AS&RP9R78 zrXJ<blb9{;cQX85u0t4>oCu%(sQZ*nX2(C{r8>Ml{{WR_3DKKVgBhnv^nrVpf{;Jscd&a zj-^UOc0$Nh#M+!@RXIMwI^cxFII0A`xYjI+Y@Wwmu_kczSmF8uVg00fd9M&y7wF|l zzR1bi_~>LhUfJ7guQVj2w`9qT>W^Xz(K>$Amo7Z^yOBBAYaa@&4RT%DfSc2oOH zB72oSo9#PT=Cb_u7P{)`BVEND+0fl!w%Sx>&&V${3Y@%8?!@Dzw-;W$OfffA=-Yl{ zS@NT&3foFV|LbP7TqX~SEv0z`t)H5kZ4RO;{~Ug_%s{sJms#{3%{Eo}aCo~sC_Yqz zR;T}UGt-hs!gR-nm&-`MISX8BBm~mjCzTGe1Q`%hosoBs*cX7jcW*=Jo ze#8C^FR`ryVzZ5Fp_=*n@J#uR(jAxRZaa^bL6K51txi9;ui3`7)cErVzfV;T4BuX6 zAo`A_mK=FoalmY75yh>=s#0(sEyH3SVcN6&+`bJjv2Ao5CY^7koHq{}h_`5|S>K^5 zCBv+By1dPQTS>DG?H5D`dELCEn|V@I>V~f`GmzBor507m8)mFXzh?m*|b>}+7zZ)iu3A+)W~U-(w;)k}>BlG>A7uauX( zXzWmxKMfl@=xD#UP&q9)|FS>z#cM2djgJlMpE_^Jl$qRiH+$UDWXk+^$gtl^KC*Pq zF|{UjCbX-{tHY-KR$}N>72|nRM{;MnnQGKC!wH@GE>qJ-W>XduVwNVfCUhCv2mCMk z4P9Q8psGg)RQ1$=sR9iiJzOi_rfWBd zI&yDW;*$yDt^z}=sWnYZXqhJ>6QNIK;}cgkG4@9a+4gJQj})+-cahD7iS4E~Cetn< zQzx;R*GXI^q~FVX@758qVK4@X{U+p+_|qX+-A4T<_09>e~n1nmi{Ol@Z^>;YztKY$umPwJccgaRnNNbIe%gt%+-v`nVY`Uy3DvQp#|xQud?m>Rzurt*+tk+{eDB2 zs<>1*7l!Vdcff5rW$b{{DkXI0I1&TK{ZwC=RmL`E`CIOPo;E&(CDWyZL$_L80pkH? zMZy!z)y93WCdjEJY2}A2ycTwUw@X!S8A_5FYvTSa!E}&2bcK*`fPd<0!PuqiOcWTI z#xTh}V@H!ZfyJMx>fZ)bm3}{YR@0N;i}OelNfkK%Lp|>DQh~QUEvyrF7n~FJiViPF zX6EYKnFpCxE_3zC%BIey)ocQv>fxR=?B+VnuG3BW7N%pR=aIs#g%&-Zm+CRJAWJ8u zk(C5vE&ma`kT-ib`;nC#$}YKzxJXLp5wog@gIl~Qo$JUkPonu>mX!9CE`7J*Mdm8L zU3Y|kN%w@R9GZkP;ne&x>-x-1-Ing9s$v>uGDP=cnQ^9ubX`Aob0?XrY&J_kFWVN* z5AYpKuCATQ<6B@iv>CdXY(q%jMRzV2Vsc^Cw;Ngv`;n!WOr=R11}X+ERC31#bsexV z0o{IB|LJ{v?(<&iwT~6b^gn+NhUKIiRMpHuRSonelV6EE$rL#MHbKApRlzMTAhT8s z3C&`i*XgC6^MxVXgWSr*IgD$CdDQ!o7uLYhK(CIZ5XPEhQ9=nf@xynt%SI) zw(8lGge<=A%IwvB$XO}PmUm>YlDPEh>}e98?$1t?;M^u1kN`m|>MuTbZeI?25CG;&;`ULJ`Bv(&kfwi)W2NLy>91yN^5 zBF(+(tO)(x>Wm2ePIY?GNOV4i1 zmFGveIX}SJ;rv`85k5Z};O%gpmn;z;&kX47aDF7sj?C=60lgj0Gt!Jm`#%jB>~Ov( zrA6BRcEDI_w8Qx)so#u@WPvX^TtW3YuN`=2P*wjjsHzWgzz2h>dTLNr`v+BZcu-Y8 zrn)gm&jxf~Tt*5+lWY^IF6`I%t`eDSKE%q;iOBghlr6&glskXT#iL`ri_25V;^N%} zdLmXVD&xfG3tVJx`%H4JzfDw?zp8LDA*3&o*_WE_Xm=6r#Wv7LE9FZ)fs+j}3xe)> zGCg~+`zMvRF3_`w?$o4`b0K{8Fw1OLhud)cvZBj2*ojlK5tGWR7r2)WxmitHKOIOZ zv67c7_8xSI2i+-BqCBajTu9u&ib=%-n~?4|ce^H)eHT7HH>uQJxPQS<(5uC@1#Mw} zetsfsQ@$8fRr3(FDZdusU{5Y?RtPasJT@n=F0GgHua_Wt#YyG2qgwPakal#e_x>KV=?TQ;<*9@xy9=1*_9oY= zY5K&JgzSqa;cx`F7ftp_<@_kq!gU;W>!qyX>=J)Px0%}6Zx1jXc>=TC(PYZjOV;dv zO9|PEl$`AfeSXebW-oSb>UOzgT0e()S54EWrdXCJCoN>n%2a(`ipBZK$@#>!I#07s z!zU}V2PIQB8$w1#AW^nvb5cS!BPC}ihA1D*a$A!r^UKh30ajhl*wJ0W@pFdtrsD2R z-L8ZZzZqRe%uG7vRB(@;J61TeHN0(KUC~q*Q z5w?xVelmw@x?;qkJx9POKC}V@8jA}%dC6~}v&y42E&xoIa>j;@wX=f%lvqH=Y z=E^kLnw=sgWG6|<*(Pab*=5DE);l-(%||TVE<8C~h8;3v*L5&1U5l=Z?fky`e@^^E zg!Pa+Nivotmn3X(ZhFy-_HNgZC6`Ppb)(eE8Z^ITZVAtSUu53D7*f^04XNs^VJZVl zxuuk@_X9o6V!vp#51S_yX+#!bW9+(?x$+C*U!hobm|fykqH*bcg;i_QLMcTl#i=FE z3cvY?dAG>4cf0U-P-OQ_D$7Qx-Q{IwnXYTUTRshIn1}SofS=Wc^?1c_SpFA#Ik8Zj zU(S<5mfZ!66}H*(oF**-wx-GSbbT3dtzNBPoszJG>0_4aWNQ{LC1kNuauy_5ncN?{ z|9PTcV65+AQW+RIEWkNKq8dG2g)>1)C^8kBB3x4Ge>B3&wDx|w=OxBb;l6nExgUgO zQx)Nf?gIl!voY35<=BX;Oh>quT?KI7B;^s%bF} z%55V~fpJX>O)8V;Y2P26pH?!n_}Pl?-03A~p>56NDl(}wkLYFgfRoe+s&cC~Q|g7L zPhv59nvVMFC^ERmxemHFjFI`>IjpK(kvYCOtf~yI`^P+WNr*8Y?zfrm?PrnpkJrGTbTBB`B*+LAN**Zx}+bt_hSmv z@)r%ldbl5G`#5!#{10A!>@1Vke0KGi=j^{#brpj(XVdbJ4*Yl8{21DMze3B2SE;72)Uq+@`sojuYRe1x){? zx#S=2kItFLVU3=ppI5uuKIUtfO#~*(jQXz`A@funr=SuriJ#Zk&e0?14VDbQbk<66D$Ba`LEq__V3? zpgXnCD!vFB5g5s&A`dh2q|$L7PELAWu!f^JTai0(R8`g0f!;!qC&}bBcjDhv;Tg@^bc>ukB4W{42v!>VPPKpa|E2v~VQXdmdV3v7B}^L@B+J?2>v*q1FI&Z@ zMP~n->!^qSNJP%RLd=S7;vx6w2|DH)u?QY>hmqb*yLt;mIAAl$tauPdDmeMLh%8oO zmLlulAtv`(_opX}#C4SFQ=$m**c|PaY#p_aJV_<0a-HfG9U|AltYq?kfJ2s9k$H1n zXrsPO&@9ui_#@Fta)n8y?!4e<@&vC=UQCi!Tp?o7KSNlk>&YYZ>@?Q9M&!w6e>p_+ zUgO@L{chVyC*f_A%J>kqxN{`f>*uA)?f6Yaf_zeBS}Vl7{Cn|Tvr+655(TCU*`I}& zWmTe8-0vPfF{!LLzd-N_VOdizpGtJ?e4DELYm#fBoJaYloLEC?)=8yqh@LMD0=NHu z;cdY!xCA(Lp-ClgC@Gy6kU?brU>?zRcCWiq)R8v@!Oyq^FZC#g)fD-k+N!T2To;~D zmHtWUV_p$iZMJ_pXXtT8<{6eB*QP43O|oC(WRAv(a|lkIWDwY=)(PDHw}m|#FMMcH z`E-!-qLZh_-mJo!c4>508~vF{x>LEXZt*1{%z<={dV}!ZLPmo85{^}H^6$h+<(XlZ zcC*P`L1lN){mF?*rDNDi(p-~D{xIEDZNq`1X}vT*HWc0$6we!u?gKqBTd5{aDt{W} ziH^WIU+Mv8n^fKyVjPgagT3zYlV-x(s)R{p=8#pOCr8?I^)TfHR;G)}G0g?r4~2gS zlgjL2E+Vgsy{1yrdPdKay9(Y(*@G_2L9>%gD*qW;AZ`^Y_QH^htkmxR_k0g{groP$ z_xG3%PAi+Xo@>q2)7Ox9Ql7JX4=-3;1Z_X3-`dpYyIZ7M$$go)MePhlRAG zf!^O}zM<2de3IJf9fNS{LzBu629j)yKyR6J^2gMp*q;%md<0L@tjT0HnN*$|pnDPy zUU*yhp5Xb4%`Y6HI^@=LlHQllJ^aW3J>MiraJ(&e1iChR2B^Mqn!e=>Aw7D3;wX2N zKGd_jV6=kThGio6Dr|-}7fG{ED%TBKdCtVA5D#lx+8k_Vtt$!alggc1?{iNxHr~p% zqJ^=sb}M0DnpEB!u#%-(+g}gBX*kU+F@>y}{Ys(tB&R5+X9t;uyWD#1ENIZqf{Zk& z1PAEtQOoMcK0#n0=m}J*SsVUr+B44sSZt!@SCg zMly|D-oA`%E2MUidUPjQO0a)IX}SO>bBf8Rb?et(zTZin-jt}l4NWNjxiGIMaP;#% z;W=OI)ss{*i%cVo74`|`9qo*raC#|OMY4&iysbthm_Nv*SG(zJU!Zqx`D`+`WOo5i zx+|XP(H)_jEG4#f{v}npMTPUS)6BP+#ay3QINLR;EFa))Xl3n;jagtN+)LaOlnX1- zy~yvMPzJ)BrdPZ5#a42Ah3()B@t~WLCX^R0*n4P9QuAMUZP0j4(|A>tH&kuy7e&`T zjcTv9_8$#IIj6pE?s}fgExNnlfu7uoRFY=DT!c;cIP(f!wV4Apepac`l$64ISbJ7; zP4hM(tbY^ADs435=}eMFKnTTCbyN5l7~%fG_kLp}4#nYMW)y9-juixr8Yp?yO6 zxi)WyME7W#-9;vpJr|x4SMrIb)Rg(2WzBaqTm5H6M&!FEl>0^xi%cigqvte^ji>3p zoKResq%}`l3;hNw8Qo+!m>XH?9*vte`Yo6ChI~~ie-|s>Re&5;LWZu9k!LnB%T}yE zxM{I?rDb>162rgVTbyH&7U%GN$VrtPIV8l(cje5GcIR9cnjz0>!Xi$(ftVKQLafXR zu$IWYaORwyd~%KzSgS{71Vz1E>7( zWQ}&y_nJy$3r>QcYeIISB#5x7%6saMMIAvlBbf!r0ijp068crcJe76w66dr?jFW_> z%T_|EXQ+&GRw&%^r|L^$w4Eq)3p&z&&MU&2>D9|rr!nTd$jFR+qdRca)q8)BjvzBt zswsp6t&T>qkoGq`$vAZ(u`rXU%8M$TpGi9HyA0|VjRZD~y?&7)G)DYTjr#9o66WR4 zlZ=y-c&8x*t3ex4RUS~`ydY^`kQ}9coO(f3S+2rq3OThI+@d~viEBYPEKq4to3g5W zRoUJi`r_?qLUwg1uPCqBY4)2Z6nTV3&}E@Y*-DsBy?sJCJOXD?$Vyh(CX@zkm#mTK zeV;Y!OUX_kGs|W)S+flivUO5IHYb_1+qcg`RO76~YMao$cYtIFSV@9yLfJS;k6r@ z6{qQK%!KmldHN=je%eLX!akwAaGq^}lZ2WG9a%@17C0}HTqKjMA`=Qb!jm`MsoJ=v z(c24+);+gyU0F9$E#W$o1Sd(9ks1bLnJe)!kXlN!A6KaWN~AITo5Fv&8)1VK;M9B08DLyW7c} zY$1?05@uzKn?J$kB6B3w62=jNwB(6iOuoWYUR3u@i>6*5m| z$Vm^*Dq@%3=T13kwJuD|cjtM`fx`)|{N?$T#OcZLR0MVfenHaY3bJ*cuI26}2`8DS z4ks+n&-3JX%z;}1x-KS{kqL#XkoDJ)p+_j36QDMNjv0QJqIYwu@{sx)V(MdD6N)rU z*Gng55_;nOu?l%A&idE}I~>Or&RdY6Pm?pqHTlhp*buYI^uAI4IPHpj6B)|q((U<7 zE|*1L?D;0fg`A;~IdWd&#kr*{u{9mD-c?}C-`mqn@8p-y6c)_GR+dDVjRa7u3nHV&lGJ<$V`@!web@|&CJq#X1USBP^paf_AssfLVhWip(mFSo}jhXJy%ADs=TI7D`|1F zeb#1n`E)t8_*wFxJEc-fC=UJPm~LHH>L?>zHWs@9p6(f243WIk47z zf)P_wO!`$Gb>V6@HGeg$VSH--YSStYzif|r-&*|%Wbu+T=PW(#W^V}fi-*O9{(If} zP?i5FcXDV#X&9R8SS{Z(2TNFq?$?T;XT*@j<~=Le{9FB2@yCJKWY2E5%h}f}Uxeo?`N>6!#UX_UWuCe>zLQNO+`hrKsAc^QQdiCU2q1 z!!P@}xyAiej`X1kW!X@ogUR3o(ap%&LijF++WKa3LYW+<*6lyqxj4|PC&`4dnr#!x zfuXeme+5tU0*$d&4Xw2t7G%Nd^?Ac*5w?^oxvQX~f}Y);y8}3^#UG2y7He;HLPb{( zCtBLEs7Rvie=w{kbkEHm$|MFdp}ahpQS!r$sf+nDaG*Wann`#$^%^){w9wrAa%%NH zAM{zWMPx6OnB26`++tG1zPj0LH7_L?+k7#%X=yeaV(eK0D`VjjVWvE*oV5v-3FWq7 z>T#1!Czt-Sg4(=|!%K;qP%iR@=)XaWk*z&Jrt$uSa=Uh(XZEA3V;yq^9fiI$ zkA?K>ZTp|!6#lwwLOC_)(Dv%!9204+>=A{W`)gU7#W>Vj4Bh7X=CX|*z zI7dz+y_vot*l%!C4nH5FJ-c=Q0qu-rDN81n;#~!LB2+xn!-=+bES{@HIy1|C7Rt-Z zL-U=}`)J!2hQ8xW?qlpr3ER!IO(?$|Fm=-eowo7upd61q; zr0wCk({BZ7tPqw!%@F6>u%WCKJgn=0x2qUbB9l%VBl%QI%Z)gjx8*Zzpx?=|O<3FX5<`mbwfC1JJIm^}!m`4pAKw}&Q_ z?+tJwmpwz8P@1)#whW}Lr>`EgC!IB$Oen8^Nuwf8rY-0@zkb8Vn{GUi9nrkw12<{< zkQ9;0z2{Z+iSw%Z%z0I%->>{d)4lm+^UL@4>?)wUfu1>$op6d2!Dcm2(C-MeF9YGo z7G@V$RUq3UVF?qORSbDnvDZxBnuGLQDNQJg2UwBInl4Q!Sp&St<|IoKO8S6a47d|y zrX4mcL5Q=t2yBf!ezcO@j0xps?JgqW43)A}Rv zIVfkKyl3p_bB$r$vW`$5Gs`kdvdVWAq>!g8d=>-A7LDTfdlFix{4z>mlg$%KdW`($ z7iCmn(QJu%C68nht6f#Tufl0Ny`%|C*btL(g)mDtYhMsdC_f*7GcDv2X3BYFT>0$< zIFnCn@9y?xf=T9_Z0HL5&MS{A!3*{UdV#*%>C3lnN;q(pw)W%7dlwS5wWohPo1Wcb zW$fzR+f!R;xB`ys08dyO)zSwC4vU$DvD23HggUMiYH#_UNt_nDyLx%T5$2DZ#ru1h z7Pf7Z$XGpY<`sufB|IxQ3D>GBC)93nLb*5~iWADe2AGZs<Mr{dx6@WPo;F3-dK$* z{~4`wTrQ{Be|j61aMHN)>F939Ecvqskv&Vg*^vCcQ$#1Te_RP@=i|gvA zRHE`aGrHBm2~0+f+o0WLQl6MLdb=$3Z_p^In6T%#gD??g; zl%t=I@*BZi~4IF9JK<^L;BhcEFIh~r6&<4O20JpD;K z=};-HkKw848+dxCCw%gnPpl%1ZpM}AqlOlG6FIK9M#F1l=zz0a8dsd7jM$i26taoz zD_B791-qL^o2x{|e&pVlgwcDQ+A5DL`4_YvPK_&Rkt7#qjipSnSCk6 zcI$2Q-e6oAAKC4gE1!B0S#u=bF~>b!(zjbh#-@Lnw;NuTBU9>MZ>0af;q^Kozyqfu?Zfw@Oxs>RJ@c=YKC~5Kv6)+#CodBXj+w-` zoa8ehI9Sxx`-!o5_S^G41Qs|Gy`PpnAePv)|E3vwM=JA@tQHEFinWx&ED;{ts zoCt_>%?I4N<1hISxLL_78Z!SLqPQWnS)^@$?s=NFI&gU1Ped&KZ7BS{luACd>B#*( zMc~>NoBum6Gh_?ltgQWB&kQ#kf&+F|wiDyB#Q9tYTCC*FbyXr~`@ZL+2saI4R}42* zq9OZ3jT?Q4>lhSaM++RZRhSq0!h=kMWL#M!?lo}lbB+!VpQlCT>(Y9SrN)xG3J#dP zVyWAlf1j8>$42e#d3wJ?PitvMzf~KS^~GLuskwx{xOACs74>ABo8)g5kvZ>g%r!gB zwdTw7pA`?fEq$4Dt%S3WYyT5s`st^|N8Ngl-bB_4yH!hq*_03>Q%4a2`WA5C<{P)aX&Pgm`7S8v) z>>U>R&07WM!VSVt%**}fy_^=u4R~oZ;F;I4X6)#5HDP&As_H#yy{fWPrSH`<%4U@A zD)@)_W)WGJhb$t!f8yB^yP9Lr;t= za`TyXCWHk#*|;E=Fo(M48WzmU-)q@d$h0KLtX1#kLdyte-Q#&>4rhPD(`8`}{n%|h zQ6w%ix4Ze{zi_kCZK7fEVCW%nb0IR1hmzJO75#9N&D?z@jW5m)n@aNtx4+*!uACV* z7Uz*H;x&&e9}I`zN2S}t-vhZuRJCM8RjWtn8<(m)uF`MhmX+(t-X7x$gJXArfiSJ} zqPE8V#N6EcN%L}ITs~lj?K;rd&2@fZ@rPCqzAK!vpWC?5do7s#A6Pxuyiv9lfw7(4 zXx~`ko?qPOsDORr?dBQc8LMOSwSEtHtI;EG%q5FfVfVO4o>a%oYfxm3J)UWNOw7OstLG2~;hL0VL7CC%x#n{$a5 z<4Vntp?f9a#{PGb#=t91qec62$^q+2&Hns)h$k*Gt}HuWMHWibO7oq%{i@QghQA#6 z&_U&WGhVC6t$4@WZxMv2g$LaU64%A=q0BOWH>`{pHXNH5E&;=6Mx z1$Va4f86p$p?57pkISl&dvgAgg?&E||12uvTZNCTh4g9vi=uZeq|yFYsZTki6Pffk z@}KwUgootxg{#eP6>?9hc&mVWa?4s)dclq3C;NSCS?PHC$5&_oN!>_jmn2ieSI$=brkZ8^@3KPY6E}=E@uV^zLS6My;8bm-w+HA(ST1yyE4; zYsfu*EcthcmN8P=6K(_dYR z{z8$-cs~DCPoc0x=KYk%2l}t{KjvmaS9l?B_hOMl;{BB4yZV#-uX>TAll1;K+&JFY zpW}VrTjod3^hn9={Wad_y@~QIBDZj1KDR_4+9Onm-JV&V3ZYy`mpk1!QPF>^$fReu z5xTygU9dPG(y!zP{J(G~h29qL^Pi~@rDIX9^ml*BmA}OIEO&^%a3_R<0&=E@PW#u2O!|TR z=RIqM|A(#&txVSNeGbcq#!*rnam^;l1ajqpfL0dL+*g+3a&0aIiQ;( zi3w;x6vP8Oewq*<7bFNCTxvW}SH(r$bzSwhI|J@6B;a=N0J#FfZchTF|DWm!tnPn5 zzyDu9VY;iUU%h($>eZ{NSKl(rVbVb!j=U>pN!>gOWcWZ{?t_eRBhue5zvLS)!9?H%cLLBvK@DCSU1!`6c%l_kF_Cb4!G;jma6~ zj!`%z=X;pXQX)!y*)<7|+rw1ICp+Aaiyr-d(tIypW9Qov#LPc7Na zqvOdboV;j)I@6dkGs@<|IJfvim(KbFGbJj!IMemE>w9Km6lEFj8fEEA>P$M|T9ou% z<#ALl_<$|lsDlCW~oS9p6Iz#q*J%Ms}kd}K~Beai3i;)5?|uckqjJ<$4W5q zYTynD(tiq261};Fha)@XMa+lZ%Gq$VQ|=XaNF6`Z)6H_Lrl-%zbT`q{r{$l7Z2~9X zBa!u%ke((=kUnliPsiagQ}XfMnw}EFZDrsygy8Olb?NbtEQnkO+#lK9qZfYyHA3V`zc57^6m4* zWP~59W@vM|`yOE-TOgtoox4Oxk!f3=I~60_LScs6=PeVW<~=Dw=2-u~jC!0h`7%h1 zUVPWZOIbV}xZSN6qA@N1k4RcV#L=gPv%*#(AXIoC7kD3o^*u)Cr9;=0xdWFDMn-Jx zDdmawrug40N=|9vxnn=q-M5MEnu+edSv=15w(Ar#I*PI+YP#Ex z_>^l5MyZor55aeg1sCOZz>`e92+)lV#>R8aqQ+~(-zpfS1sX(Py*Fnnum5&@woR z1CV}O0Hx;OU9P*qBd+1|-DcudnP?K0|Y2`+udhu#Fd#G`99<0al9*PTYnW^?Jbf9SPosbet7TVc#`>AJplwX*qa zQBEs-#@35bGSS<&-BpPPcyz>y(A*=ne__lV1`}N(ru6KDjlF)x$ctuFp ztS#+N#$%?^t$NMgCTn_3Z=<_Wm%fE+reqr)GZo`X2^@m~iv$kJZ^N-u|9Kj1({*k4 z(ydgxzLU_rATRdL(CjbjhOBA+Z=|9r@4_EhUF##_+uq9A;eoXR*&X|hd*32%??lUAsKb8^byN%kUr$$$j373df7KYf=sU>g)U9o7YdmenMS#PC0sP#H7_}H>@lM0S0RJd zi*LBncsh{gMuG|J@+@nlnmeE1jk z>yZiS3}ecas8rXql6PJ7wi)b{sJFdUUR~-W*DEglmfVsb*eOv|N~(+A{;un7?{MTO z+sq{W_L)gl-kC|iW3P|T#6P&QU5~(1EZFY$CHMk9uZV0>_<2{+q^Z0i@FM8h8Sb?4 zUSX-w>`RefhK=kaVsaYci;@eCY>F>23qS9oQ}XbO-j(7K?}zRKe7ygw7~P~7VJfR@ zePto>cM4$!9ypC8UE3x;{^+iG+k8ia%|fIM(i`HFe8ka5dE-&Aej&Um{7q;Uw)z-s zbW-v)MYwQt|HQv-b~H9lHl#e!Vboa0L3#2|I*k@=*S&-QJJoHU5A*7Q9AQj z*Xu5{HM{gIJ2r|kr@QFQtuE9t%KBQ;!9==Cjog>?cXoKZ8UN&pcRd0-Sg;iPB7Ohs z<3*I}z^}QAa>wyufo}Lco8#sM%Xpt)l8JXRUre5e0$`=&6-L(faFQACbJ4c3_(Sg^ zak2MZ_bYsy|7?sdXEXe5K{rD@k`~)7@El z2CHr646JL;B-(GKWTWZ%q}yG(u9fUq96R{{882ZIHfHOZQM)lUY{%PP8)l|H>!Dih zw;NKIc=cPSx(uyU08Gz%^|H~Lg$+B_B~5jG=+$?lE}wUG;$)0c_083ukA-aa6Fy1M zcUP6!O&3^6=w|bzB(l@H^k)uHw&e<_OTXhG0GoGS zSo?RWtKj3gbLQ!~PMM0~v$=E^)on28rcTGyr(OKeu`N6quf3QU$Ciu8V#VX#-R^SX zF5!D))QApUgp^4yvSH$WS1wNna^19G!L+ z@o7yda_I#1cB5@t*~F;ZU3*>6vooV~sZ(9Qb?KWY73#a5^}g-#dBdZq)KM;dyKdVX zu2HG0k}f9cy8jgU&!iR1!1z==?8EP5SfMP#oc=dqQ&&ztpFVWgAO3_B`UzVO{gEQa)VIZWaG#)3vRG zH2m$twCtsPI1}gkg6ZJl*cthlRRqg|4jzu5lGhZs^KiUZCb7G#Zh%RT$yMErW%!;6 zEwg4}2z(_I58+Sp6FeOKOxAVsN%mYq=dj$ra30e?uh;ev$O|6j;duYt-4fjbj?%z4 zCYdV-H=LSl^?g5&?*7iSsJH-Zb1yI0Y_s4-Fjb`FnwZd>&olf`;GTk9W;>r0NW-z% zm~F7wr-7LzGd<=z5))l_6u-(K(}qNaiE|(F4GEG^Qur!k=S1NFX0mj{C&?CUoW4M$ zO|LVX+{S4ZhQT)yjZTBfemj_r8lBOJ5w1>VUt*g4jfw6q02335Q7g!uA~-VqjHqu~ zB!1`>Jap3&{MEohneNuNZRC@WzRr(7vcwx;7Ye(j??r0LdhvcV3koPl?Hp*`l+ju3ADVK}U z0*60h%7jFmhIO5)vf+B-NQ~Tt8>d8Fdov$>WT$jj;`f4^L8fT;Zr^=^u7ge)8!S8Asp2_f4(@d|8CXBEX5m)%5M#n5z%iV8Ui?5jCcei%5NPM= zz*g65?o>f1r%1c`6-S>DjtfViTPE}41Z@J+SNM@F54XDtp@2v34wn(fx@Pf4*Q^N< zk+GIUSHM*eZnV&@7lQ9zOOh(tIt~iFl_ZW%i?sq-KP}pUh=K91H&Tu$I+Y|Z} z^96J;P2ywXNvMoc!H5cWQlYy z6Qbo);#NND$WG~wq*KBi_7xvWF}v3Yv}L?|wqSJ9Bib^2gG51-@2YQ!>Kui2o52z0 zCv#~}$Y4e-^yaZLXtB1c0xFHy$j?9oiJLXWT2V8-HB5dUBBvV6t!_x6ThSJMXP-g$ zwXOp!U^S#LvTlb%jBrrLVog*tEl1`WQg*wk7OHzPe%Ku?$B7YX=vb@?$&uMFxK}VJ zSC{h^e_c#|LFr*=3nOf&>&F~Wh4 z#abviGPl~h-%VS`yQ>8?@jC|P=(2Ur?@!aIQ{77h)M@A;5qCiLAGDD9%f%|)1BZab zRc?kBdLL~earOEh2+6W33LDetV{uqjs)skoF==otHl=cch1dIIwLL$(`Rhk9b`cbY zqz>M2RNp}~e@JN>AUl{uIW{#SojyJeM@}(VUvt}V)YRXy`ZiUWF-#&h7x?w0zrOvN z^3xeeOZQh!@bTA}NSAT?f+Wnw*x@+FqDY%6k~X;?OGGV#h%A(eaT(pudQm&wWONGx zYBMnfBI7O)BvJ6PF654LOTw$nQZWz5yO#-8Tr1LCF3!gr+_AZk(!s|ZN0#X>%CS~^lih+)EkgN`}J)mJgj8juw$c>%!r5L?a6w< z3YEk=hv6tZ7DHO37B_cI$vCrz*B=>DMh!$+XaQ0pwZUnXwlJxA%(MEs_E9Nx!l<=4-e#Xsv^ zU_>V561+x!vVX3KOh!K2AIn8#(Z{FZNT5I7~i$!y@`kE7IF7iAlrNZuLeCU2DqFZfOg zI(bMj4v;=_&voPEcx?t>nOX5`~{c{rYf>2^CFQhF|Om~J0dHec6|?DdL0 z2x)YHXw+>tkWAL$hzw&&No3Q*9!MMKr`LcZK0u4fCd9F>O)i8N#I1)73*vaAKdd0E zD2>_2(A+g;`yhvV=8(AP$I1De7gV)bi(?5B$?iL{Rv-;MZk`7gjGBzO0%OB;6VbV&pad(t7;a1 zpHc}wE_j-UlV|6msnFTYw`(%mRUY~dhcBq=3l~Vd+Mms%@I08!5Nw+vW%R&ToEv_) zlU#qK;j3kr(W{^8A?P-Qa%N#x5pef2Z!*`ECxR4yoJi4R%t816p4D$&pOadk+e~k< z71>I%nYWnV+ng-b9M-Z93{6N|^ZlbrR(8`>f~G_?)yR=-YK2$O&79l+72Y zb{#foPuB)RvGxblN}LcFQl?xWF&|-pxB{v@htYA@lx4vqr-zjE3m^_Du@|CBX-u`( zv%paW1~uSTm?I%JfW56(aKBzMR{|z@_zGQ%5xqB`+a_0qXj#s zhdb^*29^%^E3*{hS?Bau9OWmFQ`cz4&fCK${&XB1bNayU_4k`cqkG&Dg03+?V`cz3 z!G7B<3R8}OWe1#N?gIzwoIc%=`5zQg`@nAXWAuIEe&}Q(H5%hJ8i{^gqZvE%!_&tc z1M^nc$J_5!?$G1z%q zcm^DAk&8-h^0c3EPT$SL$){xGq#DO+^}2i<9Q7yG%cYJx1C$v#BLuLo@!x!Z&?C`1hMcB2_296u@5Lry4WUf1}moUO&|suSxS)BkwMU-Hda(-cj}+ z?|M%@BY@qbz3bB6opI~kX}@?k%;EgSyNpb}R_ZZiju38^mV7MsKk7N|7w>>$R9~?` zY@e<%D?=BE%|=dDQHOPMzvUhj;R~&Vuh7O0bIUgN#NbCfsA&w=w}ADxhUfs<(=w!d za~@eq^v36=X_&Ouznw4TOJ`X`Js6J^uQlmkwnnIX>V&Q+PHrfGOcdG>q^rrV2Q0kZ+-GH9CK zG^A9VbK_vbqcMH#U)c9!I~l6OpYUkR^UQm(^B|dNOf;B=l)Cef2EB&tCF1Ht_^Tm% zDcsHO6m=bk09jsT9`_pM$bv7%Pi6MN;e{J`x)IrLp*aKU~<9P8M+c0cr`(Yk4Lyi)|#AIyDdzqis_cEUu0EaGcxMUog zEkau4iQkpAvuMUw(9ZrDn%ObzVzE$sj!!!IPRb9^&VB`PEK1d7)7vPS?m|=OZKOwz zN=^~WL^K^udYLx{qQvJ!V;;G_;72l8=$3tjYnjtr}35JwCXGuHNvjk_#C|6_1LcP@!X!#``dT;Be z$nVK%{o({wsZsS!!UR=Ws%|c>O47IA>oz8u6Mx5KV95G=A6Rx7q63_!e_aIqljxt7 z)5_R(u9z>LWoU1M2qwO!n?Kw;89!3y#EtGDrRQv8@dHIe${lBil#+AV*no$W-<(Aq zVO>=FV@y5MSf*=laNm*mcUEP>FeTR&pcyk6$QtUS<@*cKlywZqb;aF$@C26cov@vU zll?Mn!30CY5-o@L`PEH+%p9HvLrR&(4{Gm#XBeht3Pa2H6+?%gK}{A6nSFiZWz-I7 zKc_J1CI!nvO(QZi3RHUsRN_qxRkNFi-k0Qe5;3Obq5|lMXQ&q1WOAYApHmtAA5A^AsNpDQ})F<`>Q?hI^P;1g4oxnvarE z&c71Ved*E`_;z6zuk@lR7X?VotVos*d&&PHczk*0f&zeNCjz{o2O#b3O+%>d5nHzY zwPAJLJOo>Us``cjpe(4WU=7zi^-Bjaro|_E+~su3SZtQodC0o#E~$k#_7N{J!!L+> z=aZ1Lu!T=ONwttCRBv8+AB*H^Wt}Y5LUod~%DyF{e(HNbEo|ZMJ3;M9#{_rHukPXR z4(yWX_GMBtPxUrWSEnPnIakef`-)|s2x&U4EYye0jBG7F#egMDenCXJV{)G1Q6E_1 z<#8fp{xc9GZ(>}rPmX^FrYwAmN4*Gx%;Tr|D}8M73(OZxd}9X$n1q7oU^hE~K`q&$ z89Ok&M^$=nppKZr`Am`+Tj;3B5mDFDiZu&HmAAtcc7hmP{x9}r_PM!<;@{X8*#i}% z2O#5sGai8T3x!MTU+#{1HUZ%8qX9N005l?irUZaZ4uIgnD3Qe9C1A+V^>H|kjD*hU zWZ6xw_MJKGp5y*5DMQE=KVfnRZb2X7I(S_lC6ix*-9uu5-YVYOW55r2P)jt1^hp1Z z^7xOh7vIK&;Wi$QPr$&%H-)w4%c$|Tw3q;zI*shB0jzqwf|26n2ikCL0f)fV!tKbmMdf<8h4$`@eqCcm2Ke*)k<++W zRVuX9+q|s7Z&oaz1NbNePek&vncz zE-WcV9ks+la{-2GWhUvG3d#-5v*kP-y)V8~*QP3c*G6}uraY``GwxHBudkub$9UsO zPM|uF1-SS+)b11J)){1C9V`OX5mzS&h?`rtR0Io^vs8Hhme;ZC%!t(=@j5!rXjZ?i z6O5BSW+G}F#Z;TFeZHG={+gkhp5fudE*VYLwJa5_1snK-Cp*dfw*PmsD2|rLmkcoZ z?3l(EAcjpYc^~#MacqnTS-QZO@&Fqt-pkW6%6*JK+XpFNiId|B2beWXLgR1Y3pT#I z8J02uHbR7S+MkZW^0?QlZEKO2;_cR8QntYpJ z4)a^cDVLbfS>4n>vEd?Un8qHS%*s{H{<<%|(_WZf0=C+@3wT|&eO~R{(H*wpL)@MG z`MIgZa}YAsV=Cpxd1vPy5Ta$2azI!n#J7zv2lFic$9cM`=d?e1vwm{}J}1x`W;4qD zHFHilE3UVF03AGgY;5_MlCbtOYz`h&PF>v3CbD2ls3Up9{V@f5S-N8s3=C#*lCTo<9s^=9>$KwEQi@|$Ae1MzexYL(g4BQhTgbur^<%Tbo|&Ck9~UcZ?p)eL?OJ}(3V#h z(LSggxCr)%fjvcg%l8&6^~5*sEvogfI&yV;<10m?$I!UcGcoL?f@n8O#W&vWCMnVG zT?MReSFz}s8Me$5l*-KCO8^sMk0n!}qST8(XKc#?Tg3A;GS z{;vPoa%8!WH?|EbQ3Eg$dVhCnOA(lQm_emi+y4Q*@0?1*U>;O9Tp)FL{nS$Lq#Wbs zIBaOkC*SjeUXzc8n$WxR6ikE@J5CMtgC%+o^++=1ek8%2M{Rh7b;nSjYS*mW*gVGe z$Gahm^jrjY+08Rl^#0_B?|FEd8&Ta4$GMGE@59sF1}edAXvL<5zk;-pyp~_{(XZ#N zTeFU#jBc9x?Yek3Lk+Dnx`B#yFY|K3IHxtKZzZ zS~POiFXY(axc(G4-~@GQy=@(Qz{ANK{g4j5L;c%qD!k9b$$$2f(Z)~xIcacmpx@Zt zJrZB^W540n^|$?5IAdmbtD*ZaeCRcHf9Poi!SkWF!n2XN2aYgzKzQ2+%tB@p5551} zUnz1J%;7CBdYSzm8EpT!8?rL{z?3N;_Uaa?YT3+CtnbyG0JZ^DU3))3_JFFI&Z}y{ z{Q$EERQ1qKfDd;9{B9?}M>_#N-U)DcC%~sW0Y2FY@cB-FOFIF!>;zabpsL7J$R{_3 zQz$3Ty-1TyxAyNp8pA1FZj5`QPv;EpexHB0PY}VZZ;FurP|h^I!2E@sRu|sBiHE-X z`%x~+c}3K>g|}|t2l~tyxGWjS_qGwA6WP}BY~xHS#=TJcm!NRxxnroe3nNTC!jPq?&)8&`oKuan4CP}wD?;dPUiK8}0go2YtiellF7{duk$_Xp$p4 zARPkF%F+9o#t1w3H_GVth4+!u2{y>Dh{IXyPJsEIyXKXO-pS4t9}#3xB!q_996H%Tf=>DEApYyw6!Ut+Zo&6RhwoV(iS1tZ^Hb1(Ewg@7xH}7CynB zJ9**sw(;+R>vNPlW1h9_73M?lR6MG2iO10Tw)bTb<)G}hJ%+9&-U?xA-BPiIr+X_z zYuTIpwW^)sXxEa#|$cU=fEBpm{wq2;AjMg zAuzQZnVq z56orOo;|4Kp9QOn_*Rp3S!V*NMZ1|c5joog+Kx_wty?gabH%6FRWbdq|7sCQP(N9$@d~_!uD)viz*sa z;H*)WS+H&N>15!bT~#h$)8m`CdMVQYwhpN3dIa#54uHu5_$n8mjoBNC>prjh^yc3i<<8HYpOTSnn1Ae^+svwB9weU4@B7Cc;PBYJx0%Phsw#|@ z_I`iD9usEFsuHW+zu7NIrah)+X0NKeqM;=1?KgFH6?HLPJoN7F-(F~!&WpchkQv$G z1ekX)?L{9j(1PW<2|YZV+}ux_z!J?z2kf}YG^iXVD2in6#AN-C!iU` zi$}M=$UugClIfU?kp-p039xjrj~Bmdo(qEvG*Qh-GFaX;5M3ek+HTS_IdLHjDoq+a zs*TLPJjS5ONi}H7|M1XT*8g21bfB$U_=zB0)1cp-ewJPK6XGi*CVF4)dToJ3Q;ON`9?@g%gP$&gCQ zN$fv*dd&U_z6E6`gnjHj9!|#fkJ)jL54KL9NF4(kv_{Lb)5A|dJG4#Ddz6QhsDFA2 z7N8l)U}6QZpj4Fm03tTTvUB%$V*RR<;q`xU@|^tisg`j}SabNR9(mLhfaL~& zWg~MtWIjh#)pf*PW{Z}k?R=&`CplJ3ZV&6^8CIk_=O%JZU^29&<6$L21^WcQC{;>r zd}1I?vPkXxxWHNQTd{*59oQr87Tfqy0ZFVB+xdtcmqj$WV+z#83xsrK?;1QdlONm+IiVY)(0Ld*} zOY$BP0io*{R{k(d&>2ub-w`kBcQ}OPk-g0X1q4~Vr|S-m!%;XFgISMNC3e^%fcu(q=7~jMg65?j{pLa$I_d5X_-KKn+`P00 z9%Y|_bIdoaQ*7d=k!a&)T?^Gsx4jRKEie~#!DZ%o7+~LH!bHo`F5cvyP{@hni`FqS z#B4^__9WvJBNENRJ^cJxmI{44sUwL=h#RRP6UY`hF<-PT9mTwrxQ4%bmPN2tP~E5# zO{H49`9JkR7n%awpaZo(&A-v7Vab=grFw$d(n>bu+AJ*j%jFsL8VCB&40yDcTdAXMIIpNBz7De!Bz|^`4=fs zmpGnX#8{$?BfCi1Cx}~JCb{xhFNeW z5H1tEH^SQw1Eic|1LR~La{mp96R-xAKMzb6G{hHey#H!EK$R1qeLz)r4yfu&WRB$E zoYFbP|I_oZ=llYKVqz8z2f!4$nZvQ>pmO!%tOCB6GMUy3>njB(HfgDEUI4qHH>e!Z zPRzUFC#PEcMt*2hqd2WFIRaC+xeYqAjt;wRl!1a#5;Hm~X%uXsnr<5vwg+tqDq#a* zZ9!%3z{GOh0UDoWIZd8j7YKb)&k(v|P}y~X$m@zfY&(a8%CrHKhV~LvxDk18zF-h_ zSp$CEftzmf!Ribu{tM*9qQl<0tdNfv|Ej7I%*%bhklo_a#U(p>9`;bpX$w(H*nvnf`Zc;q zw;4>>%;BV#AlbXFp-cvqvWxc?Ft6)6)0rp}`L?MSrs3$;pz_tlI&C)YW#L-^(xd#N z_b{fh`@lw}az3BWEj%WSZXVk@U)Uyu9awLn+f29@1(n_lp_;~OGWyBCTK1NK&E{L; zJHS${`YkhM)D~d^TbSs?LFHxbd_i(GbisgWtdq&f2%L$nL%E5Kkgfz~U?+~=7F3?R z7=1tx^j*kISzZ>xUOOdR5lE@oTB%(lrzHlJug?>Wz3eCRouoD|Uqs!ysi+k)CiPKm z$VoL(9lFjA{)0YUYV?7{Lfq?NuOU-(>t$hsnNT}|f=bQE*Lv+diHKkVmrpMd&0=1n zPm7F-WjNu?>9{U6#YW|XIY+6MSoc&{qArgb=Q6q{MR4xW$x>m3H4BnPcGL!ytLMjS z-)&N6=)2{d3!PJT>7c3DRQ^QILmreuuv8$mil<)v2b&;6<|scd2F@-l6YMw*2bJ&6 z6C{_QQlZuHs(%_rCbI4yxQ?di@aW<$o;m>;`riK2kU?pfw6Pi@Bw1rom8-)fwl}CD zQW7dN&J!*Er#}>#v?&AN(15B!_5Y4Pt>H^=?19%aO7esZ4dbbD0dl@CJOPQ~sL4MX zgMzK#OIYJu>OGRU)w@REm=Gt=UMK!K)l1s;L^-*@%ruI+!+GMH5LD976Fj9M@gY%F zUL)AuCqEd8=b3?Hr`)t9Zxj6e-k@^n94%fw4fdY`#DctYAyo74&XF(jPd{*Bh1Cnz zN+D#VpyD}y$Qz1FJMRd|m(=C=17u%2RS4#wviV%>A>D%jTI^pl+DsKL^#+wE&yn~) z4pc5uGoVS7!?MU`g5^|^bhJ>mk#1mT=a(!meB$OPArHN$*GI(mY|Za zVNl{e$QtFR59HzXHV&_Wpz^EpIf=c?Vj!>Ex>aj6^9i% zam@nvEv-3rZZ_G6ogS)_pUkN|2(#!1b*}%!tdBjYE7lb~ww>ahz1 zQ5B~HoEcEHn3^g+rlpeDoOYLCw7I81axfmni{Hz(Hk!CeH+aEH|WxL!2*!!5&n0orjbt z`K8L2g(U)Xa@ZmeOjS`dVKW|5UI~V9(CZGyme3|Jul4A0kgWLI!~52oA`yiX-DKuB zs4PAY_Nd;Vvhys6LFLJ_`XUvn*mOR7rh8p2gHkXFhO9sKjz z{1P$>cjNFtP_s#tNMeMO#W(CCSzk{sw-oiWCRtT(4BItC z`otox^aZAZW#x@N)c&zATSN7`?FK;+i0~(t+r@8LR=h{-6v=p&tZRh@qRYk>-K3m% zBfcoU_(@-#(9i5-oW9F~Q&g1-H6KsPL0oKIhDi4;@m)I9Wec z!<;D${{`QFxz0&L%7j6}{o-@6hdxjJH}7=^pI8<;>2A9!O9TV|GYL#T_}tRRzP34# zsSl)9kQsy)6}U+4l(*;9Q&KD^SCAO^ii#oSks#uTpYJRqah{KO3}R*}LH!IWzxt7A zW&V$jB51mweUq7vbzD%{bUjSA7u?TI$0VvRsI0$k!IN^68zC#q&lQ?WNW@_d8&pcJ zzqE`KX$>8wOtsfoM1+mmPXlt!pJ!hjYllGAVtTJA4l1?7ghO5>ahS-DY{~Tm`**Vn z_Mrf&`3pgL898+=s@RM#GlNRfu)J(gnWSEn=(ZlMb@!enp5NRNxxi&rWiG2~>Sa|O zf1KC?vU(g;E}n@mp~bZxox>Q2D;!lsvzka2Qv*vQ#$zf}ohV4ZmL{9MWk@Ze=~Mq6xYY41DZE z6|*X0O&?dJI0uz)hLKD!J?TJ+#)( zkdrDoQ!=JD2bGjFqe_q#hZ-J;E{-nJbEJQCh_EfF_=h58iZcp-5vcAm!BFX*IVI}xI!`2S=IMZ<)C`QX%#*>qmkD1= zB0}2vIeuM^EB#*qQKa_{Dp}Ww)y@w%))cwa*eJbKKq zR5wBB6D1Q?m2x$_hv4ceO5#8riStkW*Xc*h0HONm@FXW!N;eX$?opT^b&fBbP-GFw zS!$&H&KL@zgKxi)ChuN`I9Wg~AR7FFrHjx>Ar%(d7OgQf+?uCMisDny--72%IA@-ZYjK*B zQil_RWRCicYoWdZM#_5aCsqASD{E@e#-3%~H6Cg+iS3WgMI17LnQl>(O9RL`DxfHj zX!WYNII)Dr6AP)fSq#Mz%C8TW%A5&tigM{9XVPPGb^hW=jLF2&nn#>}hKz2eoZ-r; z4ytoP!DKOx>1FktMTD(E<+;HO8JTFDj;T+mPqQ)llP*V>D++ZY`lL{d6U-QW(J1&t z>eIO*Bhc-UqQh4tjw;UgQEeYHl5e$-^peHbLpz)n4wF+}ROPN=lIp!qw77=@82TyX z=MX(M^%MCL={~s(y^dP+I0_$LmWKzG>qBIwD-YL+gUa8A$T_BA0Xz1IyTorrRVf{& zv|etB*6t!SX~rHLSFFQE@gdKK9%PU3lR0_H9^t3$v4Kd<4t$|9q2J*#+V5zUjC53G z(v2wDSZFMQCgMX7X#^GHU`W>%U#EIv53NiN=|tQWVk06-)_N3W(*SZt1r##M5EZ54 zg1#`Uh`!a=oC#{!|0C~ZYwzhWNUHJ=m6W;bS_t$0F)2(MU8>Xik%v8l%6Hd^9UfK4 zVTnulov-?Hwg| z6u0!O^_*G|hL?HAiqU((6i3dq@I~xHTyAcxO%iH-baO<@Tw$MZMtDmitN4tlC}9I& zpU|r)-U|db(-4?d&KK&rQ!JT7S{+<2E6TJBdNFe162GEM(qzC~$Sb08Ucn0tS!)a` zGlImEo>Vra_yzV96D!wBky-e-Ln8RGtQea%E^wcSCWiSl3NlAx@`FlButP-YwBJ^o zUewQAJ^c?6wLU08R!o4F&1I=YFR*7%rbVMylSx6+dMB$U`ORghy-B>TT-MG) z7!?>-JiefxF*DOe(mFUTpGgh1$%n2b6eJWL@|l@hVF{D&8xZWGsw57Pw)yQ~Sn1-0 zaoY*%A@VCq&V_hw3@%Iv^?7rygyj31E2_HjimJYFMOELqqN-nBQPpEtRCV}@ddok( zbkJ5}E4LS|^_*t)__3Z{+Rgz*Ij*h{&xx55a%B4{N1PuV+1e?+$}re-{NoGqF!4(i zcFit@VpuDEYmt_ZDLBy!5yK5^$9 z^6o=}w6s;b_7mFQ0B6sM2{ zQk199-+pTxqA2<2iPm%H^9pI4SL9=?^0b1yQrm)Rb{bZchzn#yVhr3Ij}WeZIET#X z_dCnA@d!)CBZ~6=`LuH6j0`BsXpLU*Tv`#?Z$ZW*iZVe>Ek4cW;ZqFRi>4?uR40x# zDaudh$*4n7g69Yi-<+FJMq^Sd;J!OezTlL>&^U%I1+Ib}Bdbb#kc?wcU~Ey8j4bp@ zXn)j)I zm~P+2>bVKBB<>L>7wJ2Vudf!~6X^C`jE*z5D9WzkRhkw(GAN3~wq^#2{6e~sUQD;^ zxl@d>Q&FB9j*<6>RQq+MT*H%#3fQrwR8_>m3Rch2?TYg7FhSRUMS@v5qh`e$eicyk`$<{0qOK}Tsab`(F+ z^RS0*Le0c?p*CM!peW0=aecU-YDaAmcu*0B$e9+#0Ko-Sl-{#9&)LeAjhv!fC$Z() zGt_qRv_XjIpe?*Gt_ZbL-LEn`eW=akvj|IsYTuypcdZxyThNK=b~1aPca8K{Q9cj$h}V_r!=YH%HEd{pW!2w^uGq?K#ZUA+;-Q*ojdQeFS)eGf z8s|noY8zCNhsf+$c!0x-a?g21dE^$~88Y3DI!GI6JB!-J715?W0_uE+v15}^DOi1r zeS^w|L2?rKqrqvI(m4HYh;T~M9u8JZ9NshMxW?&*A(GY*d{4Zt{BYyunH`6j5U&%D zt7=wN^#fVUYnNoL@JTgr>#p8cCDs1>w)%nUnw1SuaHo6G9fc(@>rR+6zZB-*SqyGZ z=`5IAP+m40=9kU~aIIC_DRdDt0LfTUww^Kvm~Ee zUcGo_?E}^IHwlurs(dSboZVW*RjgiFO)8cTTzCf5uc{&Ma4V}DRyIUHdcFkd`42$7 zucoSY#mLXC`~0e#DGx$ry{|4m9n$j~xKQT&D(>fZYd|B(Ro1SkTVB1gIsz){rRv2{ zS6^FM-OvCleM?}aSYPcUG#?zfTq&)nhUK+2OTgi9a3$q)^0^1=rIpoOov(hSRXg&mzQXnd<`o# zx+CS*)>jiM4cto6SHo2|)>T)otga$eA?nqT&#kJtl^80??rgL=a~jh)sYWZmX4Q&{ z>iYi|19iUohUzNLsxjG+@o&;ZYY5@0RdvgyO5aMYd`)kp>IPD9zO{k#)sR>7LrUI| zAF7H*@|Hq{nDbREujW?PaYv}&R}%xFDY&&NWEdK1E0nWBsMv}ni)w0X7D+WL ztLuH0E2RgjL90cUwJIxAHmvY9at*5+R#vYVk?rlAHQTv-RRsJZmHc<>iB!X_YN#H` z|BELp8tRCotPRjmy}Y_|WoH>Z;6tr&ib3*VYql zgB8Bz%WEs`X`!S{sFUidZ{BGc?)ELKCSQywXB7}$?EgXaPEl&$8pPUF%d5DWYGPMK zUtOK1tPKE=3;=lKcfx=Cl4t)dZTx@ayP4;|KSeRbBF+L~&uQ4q~vS-s-FJi3)9Q>tqG z|CO)Gw-WBU(+&Smd*>e;$5F-ccgM!Pw5Bn^v`%Hvwu(gx$znv1tPqL(u!F0(*u+M4 zg;Bh@+t^2aKiFNTb}-ya>QVzKq{YwxDT+`e&bJ_Mf}sH!NTsy+j})2K2p5$$fPo+d zDMA%$P{pF}yjlAaS}A`afim*wGw;otA3O8*&G@9VGkI@IlSfU>n|rBq_xAhAPZzf| z4R2{0w&EW;I66@99on?1=s51C2kopcPHlUGIVUGyi_$6gX)4Nzus1jCJ0rI5yL+?w ztRHWe^#=8xJ zINh>`$q8i9F4u9?@iOcW6i_JI2vZjAaQ5Rc5Z}eC(WNRpbAMqtpRvqt$5(D%$lvE? zeS}pwzZ$$LV`j2W#)2E?3u^9H>8YdO`M4Bd?zj~A1v6)RzT;Zd#-fiF@|$Fls;hlB>!^M(Wpmgw?W%Rv z+fj52Bco>8b!@fRvh!+JmKR6w1tx?bsdh`6AwD)`%zVL*H@+&uU|l7=SlT;_cGkVh zL+{a7ld2Ul_q&B0j&sDY^iaWDek0VR+B$cU>!c6lyn+941-<<$9>|&Yip4dJwYpJ*Ru;y?giE^O5$R?keT}jJ48X zmDgfv^f_!IVp!Te?F^0!oG*Sszdr?6FC={p&|`{Ggi zvU$Y*m9wKG>-kRJaZL#mYH^2@?kY1oopy>>2aN4Xi8!rQpL2yi`Q{S~fiCXM->Hy_!WZNb$ zw>>EGAZVQC%_E}kR}3}FT!b7L+&2o=aPL9k`GeBF_cK!8GKTgccYrj`XO&#$CC$`l zWgg9nQ{1O{RO`fM4c4cl>tZ<*Eul20uG8m+|WnB872P^O7#)oD6_J<+g$!E0u zD&(Ms2R|?E=n)}UjpF|UlzUb73rr=vBH}bL*51kcW~WN@GkBL!wQdU zz64h8k`$Q3?!9M75Jb5BbB+>f6$;=R3l>lVAxnK*kYPcoK48@Ysy#Clo7u9t;d_{GqV@M>5}j zFi7#%r$p}2EIuXkt~(?8LCtx^DL(RJ(J%Z2?Q6JkR^(PNNb$*^%Q%Z?rJwqzA=mSU zXQI;5m8jHp9&(cVo|AUt&qbxhD^cm9mN)zo^>^{*UrBxK^HJ&Cm8g_?Au7#XiArZ* zkp5>Ez*@fiYp{_gez$DMJ{t0 zawWm7zm<9PDweq)gkNd>Yf4UX<4e--HqBPeb}&ftNiBa*b3w7f^}mz;E`ni&J6;x! zy)5fD2YKpNZhb}c{wtz?UCCu`xFGswFsR|9iYe~>y^MQNv*Qm^-||P%kAUR_FM?s2 zQ%k~n#R?CB!CGGWlh_~ovvBS&U@bTQ6*PEB6X*Jk^#7gy{!BQH3*V(%iNJqo{!82%XbsUVkckKv!*laQNg|q064evY z+lc6PBAUEg%KqI%Yl+AtqPG)KiirLhMTML6Sl5$``4y|<8|g;=FRTI5)`f5yY<&8Z zB9i(hlTM#}e>jce#-9q6!Hx7kldyMhHd)g&sbwLYM&AA&BC;KOUzQShk5_%Lr;Tci zRAO~vtx=zNN8kOeRT`0*dNUiTmdwd|6-8bwz9$EW5Pnr~me6j`#K3Tpq;>QEwqs;3~ zn{=#097Ehg?n_BrLqa@6{s2krgB{`_@`XBygNTK&L0tTpj*YNG{6t3FjFb8WoQOU| zM5{^0L7YU!`l1~&`a`_TSJ@%1A|u|y2C+G|b4g-6ba9O6K&4J7B9B$sU2G6K`Fyi@RP|Wk=7F$~`M)%XWvwt_b!#D|zlF83!ruuT}S_K6pUv zpI@n~wp*{CU#&fC=84YgwU6zve)yUNo+Cc5aAqBeH$jh!v7w6Xx}GPMU%kc-DXZ5A x{k1Mg?)jUlQYn6p`(?~xTm#$p#)2LT39g}@Rj0xN(W9|YWk(cFckO92{|&Ayxk~^5 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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�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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 84cd073e6fa69ee8c8d942bcecb00a4a734805b9 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 --HG-- rename : src/video/android/SDL_androidevents_c.h => src/video/android/SDL_androidevents.h rename : src/video/android/SDL_androidrender_c.h => src/video/android/SDL_androidrender.h --- 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 a633daa196f006b91c1372d2fffd2d2ef0f7d32d 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 db5022f8c4be82445e6a7a183a0acf33d66ed5c4 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/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 5a619d67b2c0f206fac7bde33a60166ca6140ae8 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 | 275 ++---------------- .../testproject/libs/armeabi/libsanangeles.so | Bin 14965 -> 0 bytes 2 files changed, 20 insertions(+), 255 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); + + +/******************************************************************************* + SDL thread +*******************************************************************************/ +pthread_t mSDLThread = 0; + +void* sdlThreadProc(void* args){ + __android_log_print(ANDROID_LOG_INFO, "SDL", "Thread Entry"); + return 0; } - - -/************************************** - 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 *******************************************************************************/ @@ -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 */ - 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 C 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 d4cfca1cdbe8995b416df57938e8b5eb6bb41af7 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 | 40 ++- 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, 1108 insertions(+), 3 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 904e7b4511c71945961bf2f5bfd4b767857b4675 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 3ad2c1bdbf7da548131b600ceea62b38b5247eb0 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"); - pthread_mutex_lock(&mSDLRenderMutex); - pthread_cond_signal(&mSDLRenderCondition); //wake up the SDL thread - pthread_mutex_unlock(&mSDLRenderMutex); + //Let the SDL thread do an entire run + int lastFrames = frames; + startSDL = 1; - //__android_log_print(ANDROID_LOG_INFO, "SDL", "Unlocked"); + //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/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 @@ class TestGLSurfaceView extends GLSurfaceView { 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 482a87c499155961f7d045b67f5c401c4d68e6ea 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 | 175 +++++++++++++++-- src/video/android/SDL_androidgl.c | 14 +- 6 files changed, 259 insertions(+), 218 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 @@ package org.libsdl.android; 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"); } -} -class TestGLSurfaceView extends GLSurfaceView { - public TestGLSurfaceView(Context context) { - super(context); - mRenderer = new TestRenderer(); - setRenderer(mRenderer); + //C functions we call + public static native void nativeInit(); - //setRenderMode(RENDERMODE_WHEN_DIRTY); + + //Java functions called from C + private static void createGLContext(){ + mSurface.initEGL(); } - public boolean onTouchEvent(final MotionEvent event) { - if (event.getAction() == MotionEvent.ACTION_DOWN) { - nativePause(); + public static void flipBuffers(){ + mSurface.flipBuffers(); + } +} + +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"); + + Thread runner = new Thread(new SDLThread(), "SDLThread"); // (1) Create a new thread. + runner.start(); // (2) Start the thread + + } + + 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 @@ class TestRenderer implements GLSurfaceView.Renderer { 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 26a7c004338a018ffba781c84e7f7b9b8d14409d 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 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() - +/** + 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 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback{ 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 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback{ 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 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback{ }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 d8e077adbbf96a5fea32245e68260d6a676d95c6 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.egl.EGLConfig; 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 @@ public class SDLActivity extends Activity { 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 class SDLActivity extends Activity { - - //EGL context creation + } @@ -104,7 +104,7 @@ class SDLRunner implements Runnable{ 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 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback{ 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 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback{ } } } + + + + + 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 d42b7d3970f2638ec15d09ab185601ee8fed87a0 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 --HG-- rename : build-scripts/acc.sh => android/scripts/acc.sh rename : build-scripts/ald.sh => android/scripts/ald.sh --- 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 @@ public class SDLActivity extends Activity { 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 @@ class SDLRunner implements Runnable{ 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 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, View.OnK setFocusable(true); setFocusableInTouchMode(true); requestFocus(); - setOnKeyListener(this); + setOnKeyListener(this); + setOnTouchListener(this); } //Called when we have a valid drawing surface @@ -219,7 +222,7 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, View.OnK - + //Key events public boolean onKey(View v, int keyCode, KeyEvent event){ if(event.getAction() == KeyEvent.ACTION_DOWN){ @@ -235,6 +238,19 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, View.OnK 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 27d80262c26ce63bb2ec753f7081b58c1e2a8c1e 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 @@ public class SDLActivity extends Activity { //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 class SDLActivity extends Activity { - //Java functions called from C private static void createGLContext(){ mSurface.initEGL(); @@ -139,6 +139,8 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, //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 088b7581253b51b60452510534a0e53cf8574029 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 @@ public class SDLActivity extends Activity { //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 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, 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 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, 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 e0c98826af32e34c8364416ec4a4bc9e7f8bd8d6 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 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, 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 56e126ff144ebe3204eb6b74cb78e9b11f4d4c75 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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 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 9aea3f99a72a29e562b7058d52bf8bed315cc8ef 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 +/* Enable various threading systems */ +#define SDL_THREAD_PTHREAD 1 +#define SDL_THREAD_PTHREAD_RECURSIVE_MUTEX 1 -#define SDL_TIMERS_DISABLED 1 - -#define SDL_TIMER_UNIX 1 +/* Enable various timer systems */ +#define SDL_TIMER_UNIX 1 #define SDL_VIDEO_DRIVER_ANDROID 1 From 9ac4bd2a179de9d38ecd3149ab592f28cb41d6a4 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 ef474722804cd6b94d32735c514d2f23e08127cf 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.util.Log; 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 @@ public class SDLActivity extends Activity { 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 class SDLActivity extends Activity { 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 @@ public class SDLActivity extends Activity { */ 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|@dvH}(6~@24?>_gOBzGq_uX}GUX-IpL+^FFplvl>0t&w(k6fjWZqd+i0RD`so zPI@FKUT2-X_dUZMV;zHyYT(d~{kr&!4`}db)JXv9aspTzTX4xa0B!t^1duS^=hyc` ztK<;{n0Xq|Gd@PY3SOkp-X11ODnQR#L5KF64PgGn@tkH}1MhbZenkS%MdN?da00JH z1D;75U#s9Z3BbSu5;NPG@C{BryOYBf4%>SH_~tnP!7i80ba>2Sjhg9c0Sclt~g)H{=x(NBOhe%!?b;h6aJJX>97Wd zwfIl5OjAS8(SOrmt`}YTX$_RQ3u}UJG8#y2RzR2kvu8A5*Chb|m*e$s;>0g7mgVnd ziN|A=v`494d?7BleD!^6;GbYqbeJw**SjA6$v8`meV+aIUy5bUzRLPf#j4)E&H7Hq zX&UViCp^PSbl7T#>3cbjT!M=rCt*F+i{)&faGiQ>`4}>I(bqmd|cU5rruENqW3F% zozWYwIPZ``iVN)KAbi>Y_B=zIUg9x+PJ*@A2v8u6i*rNAObD=rAoi~0U_SM@hOxhN!M!T45QmmS6$jHgDYPH|tLrrOS zS=uTWaE57Yh*1-DIJNR2Qv`zPv892Q?=j@&*l+_4Q<-l@Y^bN~z#-5|vvM@qUS0z(Z=!>rJWrMS1wz7Z*O-`bgukDz`@GC4I87;ihbUibsM_-4}T)v z=|u->XRB4w<=VySTr?xIMIDO{WkT;tJ#a31Jrk~dLx@wOQOGK3#u`y%@x#^=$2eTwMMzi(yoFRCr4Gn(&XpcZ8Z- zjja$i2-}41!aIa_344V1ITnGhiQ!SQs8a;92_WuDGyMGk` delta 3133 zcmX|@e{5FO8OOip+;iW1+rFo~K>Pk`ZA)(Pt)nQTIFw{%YKa?^R;`OnR~itAjq<~R zx`A?o>BdHw)?6~FaT9S!Nf=5IL?Uw=p!FxRMYpgyA)6Dkn2pWNWNypyJ@@I}Kknyz zpXa&HdCt%G9_)uspTkkIn&T6LfljXZ*o68=zHY zzXHscG@!3sK)(uqMxp(Ondmc`<}T$^2h9dBzi0dE>3oL%+YUjM2k6)Y+YLMLJq`FK zV*;(hGag|6WdQFB^O*2mc79bKn=Ne4TL~aAF98T2q1EFH8+WoftO4`jQ*4g-fZ29{ z&4)a|@BAx(DmImwq=3vU6)T{MZDqF7(y`fPKFN0$Y9P4oG@BRM+_nx)PjW>>GKs%TI9Kpec5%0}zzdp%9lVt>RA-(YGTwb>_F z`HSsr;_8i##A)k;?7LzRG>M zGL^&14)EPOI3r%PL)nk$y>r;7+!-sol`pUPfzyvGYnXa%;G%aa`w64hpLgCLD`dIP z=7iCh0qh$LZT$t$PXyb`$m#DnW$X~urJgH4v^x|KR_dL~+BVKYn^SR=vv;z-%Ti~Z z?V$5>GhArVZsv4@3e4yI7%*Ida4z>#T`pY6 z9b#|gcowCb9`=3)bhC3F_M;rg;#7r}_t}KX!aU6vd%Ad#%?Iuv{*xEUY7fYz%Wi+p zD=L!Qv7M%Ys@C)hF!p^qr>82k%XtnimFoe4dE5uG+kEEw<`o&hwsDrf#fjjKIYqTG zRmQ$XwP`_yzHssf+y?ij)8DM4ET*{GjOS;78a@!1t6kYlY}iToz=u9izgq*Ux_2Z4 zsOuS}Zb0cRR@9^D=T)fsYl4ZG#S+t?eL&sp z#>kjm0Hy+%8vw-zS$`h~-5Imj(i8^IR17-m681C9b=uB^H!`ZBm9AEol2QCKT>)V4 z|6?P@@*lG}$WcUGiQSaEZB)d`=Z%TR%UHmwMH%2wPxVsm0XVcjdqDZe0$^`4P%4I8(q}C?Kixqzhr_{y#yO>j35?iYHkJSMeoUOZ* zQ#+FWQpMlV0Gv#oEES&GRWe^Y#cf&!-1kBm_^s$a2`>si6>47VWgrxmgss9w!dnv6 zbbaYvQRjtK{1+$#^~tiPW;K{>X{y9yVtYmSOW}LMkA$BJeSXrEfvLi2!db%k!X9D2 z@Gjvd;kJ}9M#QjBcvyHs$PXoU$d5MiW8r7QDxSGAP!LWRb_lN#_6qxjYaC-B7Q?Xc zN#Q)+>}6oF@HXL~@IK*pgg+GS6Fx8G6~sKh5?&B~LdIo4^FAsAIboBqTX>7`cHy9K zt?(Y=%T85&PeT{}p?d zAKqLVQUeXbX0iaZ1&Ce1Y%yF#mVx;ac%86E>`TZ3uvGM*_*V<>7XL=^4~hPs=tT5R S(Yu35X~I!498L~S+xkDkvV9H! diff --git a/src/video/android/SDL_androidgl.c b/src/video/android/SDL_androidgl.c index d01682a4c..bcd37dbcf 100644 --- a/src/video/android/SDL_androidgl.c +++ b/src/video/android/SDL_androidgl.c @@ -41,8 +41,8 @@ /* These things are in the JNI android support */ -extern void sdl_create_context(); -extern void sdl_render(); +extern void Android_CreateContext(); +extern void Android_Render(); /* GL functions */ int Android_GL_LoadLibrary(_THIS, const char *path){ @@ -67,7 +67,7 @@ int *Android_GL_GetVisual(_THIS, Display * display, int screen){ */ SDL_GLContext Android_GL_CreateContext(_THIS, SDL_Window * window){ - sdl_create_context(); + Android_CreateContext(); return 1; } @@ -88,7 +88,7 @@ int Android_GL_GetSwapInterval(_THIS){ } void Android_GL_SwapWindow(_THIS, SDL_Window * window){ - sdl_render(); + Android_Render(); } void Android_GL_DeleteContext(_THIS, SDL_GLContext context){ From 9c7acc66238f54fba66356433c76e7ac49a89452 Mon Sep 17 00:00:00 2001 From: Paul Hunkin 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.graphics.*; 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 @@ public class SDLActivity extends Activity { } + //Audio public static boolean initAudio(){ //blah. Hardcoded things are bad. FIXME when we have more sound stuff @@ -61,10 +69,25 @@ public class SDLActivity extends Activity { 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() { super.onPause(); @@ -87,7 +110,7 @@ public class SDLActivity extends Activity { 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 class SDLActivity extends Activity { //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 class SDLActivity extends Activity { //closeAudio(); } } + + else if(featureid == FEATURE_ACCEL){ + if(enabled == 1){ + initAccel(); + }else{ + closeAccel(); + } + } } @@ -157,7 +188,7 @@ class SDLRunner implements Runnable{ 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 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, 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 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, 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 b2104a9057b185e06c76e865c5d466dc9a6d1ae3 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 zcmcIqeQ;dWb^pDO)vmRAvTVt+kcC-Te~4o5u8lFqp@3{zwy-QYmSt!gSe|yDtc_Q@ z%kEoa^N|=z8m0l_B&10RRHkuTI-x+@&_D|*G$ABFsD~ygZIcYaY=?z!il`?>!3u8|?bFc6S|el$7Y?iEU6Z&A>XUaZ9F%*h7u zxyI_b^iP6+_UjuPnar7neP-VqcIF#rGnr=_nZ%jK{*Kv3EOE!#OyXH3A56?PIx@eh z$k0?P~r(w0n}trci@V8wJBWS1Joa3|F|&c|?P zIu0yr>c`_wye&?(@&)kJs6=C z`#Jixgw=2UBGrG#1nfJ$%+J{fVE^``{JhTsB3HZzU#+++yAo}N;Yjv(B_f<|# zGuh_+O$3NOu}RtNaK6U&{(>Hv$u8J*CHggbX?Icb^nbCyo>R_um_S_pp+|_?-6qg> zvjJQi{mW-ez$scl^c#Wq$Jy>T1MeTChtF%S#d(_Cx4xCHGz(M zIhe5NcJvkYz+PzrvGdNdGyHrwcHUza;4EkHwHy@=#VZC7`wdz!lReI_+Cc1jZM@=) zk;~rA#7g?klMx^`NtuyA9`i%uG+SCk@AA-Dw8GO5SHU zzo7KU7ntA4FB;B0tXq0eu@4wdD=n8-DCJXzGe_mxTS|J`KpS&wODy@64LGk-b~TKH zdKYO~pK}XsZqQu986&q*b8DO=HB*}FcYcq3N^e(IHZ0rA7B({+wsD@B%q+W;j$f<` zRDoXdg?&0V4k`dIK4THLA&R+-5RmK$W)c|GBxHe<5fcnSc6ph^SL-zt%+ z9RcF%4;2IXYfN1Gr#5FZ`=B%swL2m-$&q73g3=2jK&KJ4w{c0~fW$6kZgq9Uu4cM8 zH?Vtqb>hSMBo#*3Hm7?pJGM`AF^7w1z_r1CgcU~_uBiQQYBJge&{ng64xI$f3tXg< zf$jAsuw;#11Z<~4*;>uToEc7ub+SMpYJWKbw4IF5)UmBCfRkd-k24HRpO?tptU22` zL++LlZoSFavY#<2ZdKvq0Jcf+hgyI*{~&5#rJSZ+n{C8ydpiQGc-RDt*0ED9K=-W? z0NvMe!R`J!v$XrL4Orb5Gm71N4It9}yalv$cXG;ipJr^Z@^u?9cBnB>>nhjh>t1XD zdbUwAz_Cw_AW-rL~({#(tdhJvuaMP|l^$xNdng(Ag(Ct76nW zsIrARrvP*UxFQPl+(q}t+2jfDy4&w-0dfg2}(eyX_7PeZ-`h zS~Zt;>-j=C?UwS@av_iOba}>0SKN9ry}w%isF(9=>BF^hE?vtX36wUL@<%pSx1=ZQ zgp!q*Q)74DOarLz4VNmn=X{RUt$wT1&!f-Jxixj zzr>b=1HpN=L;o2H4RH^D?XQ+=1RfZGj-oP)@1$Z zs^{jLytX>8T{~V2N+KW7`ZQZFmJg?nrupxZf;AkwymMoxwe)K1M#DNfmD!Lfn5{63@xc)cFm)1zQo(PV;7 z@*42!ULg~g#L3As&S1N}r#*JBn)oD6#-5NKryOTcphuk;XC(G3eNkl<1J@A}ToZAd zO{6swx3PjEw(2jeO%<+IA%kr5X>E|84l}sTCUW+N4N~>x_t)kL$jsw~c zV7)R#dM>ILlY!B}17pL30~3SU$#U7R`Bk@~6#C{>)qbTYINXz%m}+bX)hG?mREo{A zp+eF3s`JA=F_`6G4|+!nIZtUFR5^^Bss-Q6R?0PulygT!zT5Nl*Qh(=VXErg2xe5l zEoO6Wu~@^-V!7st@{D^d%X4DLer>v3^%J~yNawO6W4p8C!y~&!529Z4s(IIUQS?gL z+)*F9M<)_H6I)W7Q=3q(cqK27V!3oUq5jZFHd`;0{EIhdeasY&dDU#OoI8T)LO$=6 zM7U{d)<qUR8?pNy4%>`~=GjL!u9Jg!S zLZFuSj+Pja`N;1)bP!5jF6mOeG7Jwwhj+MC@G+%^B3mfsyo+S7i3{#brRdfE_a%CKaAYGlqRp92nP7p%M4{ww+KPP5&q`Nh zdC88H5AUxQ%GH8@997r%vV~Hvih3y=l3>Z27|e!qEbq;@rF^zrDjsjTxzjBcC*9l; z)#SEN&di%+Oy*PP1LxTS)rwoMdHFz56x3#cK~JVk;bw19>J67ZIP-QLI52jASzJ|KtDJuSrpfVLw43S13kzKz8aOyG zB2#feH~r~Cjk7RY^Q)da<5f|kkMmr`&F2fH!qg)>yw0I$HZ>>6pZcokwRr3 z=OkATJp>Ed(z#!24%&FoX4veZT?clIjqk#s=X*JsY_)JMEXY`|#Zu%U_3y`y8- zjOwj-N4e~et0kNh;o{BMb$B_F9$+4oYrM<+Jce9r6Cz=3@!*Y~T1$-3{= z^bYv{p!3u&41K!d)mt|3fP(FGm3n_@(hYq8w_bgy(B~K)Aubeq`s@z$82YjjP+*Tw zWlMrW0B8ENE!tyU>d{_WFtFDjeo&USNc1}_qTWoXAov_wr1yDKpDqFl^mZ)r@2x)I zjIDi)hWtCU$ljq=;E=p7k^*}?)P(!{@UlM{!U7r&En7_ZNNtY=R}V->ml2u zm;;6UhVIt?gj>!C&V`Y+IV#rQ1?+54*4%ZPz5wF5s6ZqOp5O}?!Lwn@jk zfaOw$6v*_Ev`L@h@i;_*-fKE<^=TAPdgpwA9(@gRnRL1f;1fnbfjwdu#jCs7JXvanG|9peb*msT z=S&#tzS1N^&GR51Dd)pca33NcCJS*jCxZJC1t#5=~nE!+;gONsHqX+~_n};1<**OU-~LSt=`aO57e3o-tfT|32U-6x#e392(ZRVNvKX9I6mLafXW3p<+!wTok(NgcL*PgKTg_ z%NEOrvz2P-F0}BX$6IONYCX~t1i-ng zp~jg!*9sypr?kuQCI7l0i9FY4BG*aN(R-!I$42tKdi^1Cl!$7on!vf_P2hZD6zCWE zR>2Pm?h)jJGwUA|bOombxvNutv*7K5Dh|EU?_S_{rJPrG^2`O|3xcl*{+-~D1=WvO zy#U|uiCh$j5&oFa3v>u}3$7R3Eck1Jo?uPzcEL{z^0A)wz9RUPAfJ9&{(ZqW1>X_m z&m5E|1vd#^DY#GYCc#e#eopWq!N&w&5&Q?iHwFJy@IApc{*c!T^a}P1UMe^wI3bu9 zcD 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 ab688d00e389feda74b35e21b3a3b5ad0ab8fceb 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 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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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�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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 0d3fdb86c934015ac63c8e12e655a17decfcc5c0 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] ); - } - } - - -} - -