Mercurial > sdl-ios-xcode
changeset 4726:9076cdb027af
Cleanups.
- Moved to 'project' instead of 'testproject'
- Removed extraneous .c files
- Removed the android_libs folder (that was against the NDK agreement anyway)
author | Paul Hunkin <paul@bieh.net> |
---|---|
date | Tue, 17 Aug 2010 15:35:56 +1200 |
parents | 4eb9d3c7fdd2 |
children | 8087bb208acf |
files | README.android android/project/AndroidManifest.xml android/project/build.properties android/project/build.xml android/project/default.properties android/project/jni/Android.mk android/project/jni/android-support.cpp android/project/jni/lesson05.c android/project/local.properties android/project/res/drawable-hdpi/icon.png android/project/res/drawable-ldpi/icon.png android/project/res/drawable-mdpi/icon.png android/project/res/layout/main.xml android/project/res/values/strings.xml android/project/src/org/libsdl/app/SDLActivity.java android/testproject/jni/app-android.cpp build-scripts/android_libs/libEGL.so build-scripts/android_libs/libcutils.so build-scripts/android_libs/libutils.so |
diffstat | 19 files changed, 1363 insertions(+), 4 deletions(-) [+] |
line wrap: on
line diff
--- a/README.android Sat Aug 14 16:17:17 2010 +1200 +++ b/README.android Tue Aug 17 15:35:56 2010 +1200 @@ -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 @@ 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)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/android/project/AndroidManifest.xml Tue Aug 17 15:35:56 2010 +1200 @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="org.libsdl.app" + android:versionCode="1" + android:versionName="1.0"> + <application android:label="@string/app_name" android:icon="@drawable/icon"> + <activity android:name="SDLActivity" + android:label="@string/app_name"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> +</manifest>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/android/project/build.properties Tue Aug 17 15:35:56 2010 +1200 @@ -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. +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/android/project/build.xml Tue Aug 17 15:35:56 2010 +1200 @@ -0,0 +1,67 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project name="SDLApp" default="help"> + + <!-- The local.properties file is created and updated by the 'android' tool. + It contains the path to the SDK. It should *NOT* be checked in in Version + Control Systems. --> + <property file="local.properties" /> + + <!-- The build.properties file can be created by you and is never touched + by the 'android' tool. This is the place to change some of the default property values + used by the Ant rules. + Here are some properties you may want to change/update: + + application.package + the name of your application package as defined in the manifest. Used by the + 'uninstall' rule. + source.dir + the name of the source directory. Default is 'src'. + out.dir + the name of the output directory. Default is 'bin'. + + Properties related to the SDK location or the project target should be updated + using the 'android' tool with the 'update' action. + + This file is an integral part of the build system for your application and + should be checked in in Version Control Systems. + + --> + <property file="build.properties" /> + + <!-- The default.properties file is created and updated by the 'android' tool, as well + as ADT. + This file is an integral part of the build system for your application and + should be checked in in Version Control Systems. --> + <property file="default.properties" /> + + <!-- Custom Android task to deal with the project target, and import the proper rules. + This requires ant 1.6.0 or above. --> + <path id="android.antlibs"> + <pathelement path="${sdk.dir}/tools/lib/anttasks.jar" /> + <pathelement path="${sdk.dir}/tools/lib/sdklib.jar" /> + <pathelement path="${sdk.dir}/tools/lib/androidprefs.jar" /> + <pathelement path="${sdk.dir}/tools/lib/apkbuilder.jar" /> + <pathelement path="${sdk.dir}/tools/lib/jarutils.jar" /> + </path> + + <taskdef name="setup" + classname="com.android.ant.SetupTask" + classpathref="android.antlibs" /> + + <!-- Execute the Android Setup task that will setup some properties specific to the target, + and import the build rules files. + + The rules file is imported from + <SDK>/platforms/<target_platform>/templates/android_rules.xml + + To customize some build steps for your project: + - copy the content of the main node <project> from android_rules.xml + - paste it in this build.xml below the <setup /> task. + - disable the import by changing the setup task below to <setup import="false" /> + + This will ensure that the properties are setup correctly but that your customized + build steps are used. + --> + <setup /> + +</project>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/android/project/default.properties Tue Aug 17 15:35:56 2010 +1200 @@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/android/project/jni/Android.mk Tue Aug 17 15:35:56 2010 +1200 @@ -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)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/android/project/jni/android-support.cpp Tue Aug 17 15:35:56 2010 +1200 @@ -0,0 +1,242 @@ +/******************************************************************************* + This file links the Java side of Android with libsdl +*******************************************************************************/ +#include <jni.h> +#include <sys/time.h> +#include <time.h> +#include <android/log.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <math.h> +#include <pthread.h> + +#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"); + +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/android/project/jni/lesson05.c Tue Aug 17 15:35:56 2010 +1200 @@ -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 <stdio.h> +#include <stdlib.h> +#include <math.h> + +#include <signal.h> + +#include <android/log.h> + + +#ifdef ANDROID +#include <GLES/gl.h> +#else +#include <GL/gl.h> +#include <GL/glu.h> +#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<sizeof(triVertices)/(9*sizeof(GLfloat));tri++) + { + glVertexPointer(3, GL_FLOAT, 0, triVertices[tri]); + glColorPointer(4, GL_FLOAT, 0, triColors[tri]); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 3); + } + + //__android_log_print(ANDROID_LOG_INFO, "SDL", "render %d", Frames++); + + /* Draw it to the screen */ + SDL_GL_SwapBuffers( ); + + /* Gather our frames per second */ + Frames++; + { + GLint t = SDL_GetTicks(); + if (t - T0 >= 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 ); +} + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/android/project/local.properties Tue Aug 17 15:35:56 2010 +1200 @@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/android/project/res/layout/main.xml Tue Aug 17 15:35:56 2010 +1200 @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + > +<TextView + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:text="Hello World, SDLActivity" + /> +</LinearLayout> +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/android/project/res/values/strings.xml Tue Aug 17 15:35:56 2010 +1200 @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <string name="app_name">SDLActivity</string> +</resources>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/android/project/src/org/libsdl/app/SDLActivity.java Tue Aug 17 15:35:56 2010 +1200 @@ -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] ); + } + } + + +} + +
--- a/android/testproject/jni/app-android.cpp Sat Aug 14 16:17:17 2010 +1200 +++ b/android/testproject/jni/app-android.cpp Tue Aug 17 15:35:56 2010 +1200 @@ -13,8 +13,8 @@ #include <pthread.h> -#include "importgl.h" -#include "egl.h" +//#include "importgl.h" +//#include "egl.h" /******************************************************************************* Globals