diff --git a/project/java/Accelerometer.java b/project/java/Accelerometer.java index 7a026d124..9bceeca65 100644 --- a/project/java/Accelerometer.java +++ b/project/java/Accelerometer.java @@ -36,6 +36,7 @@ import android.hardware.SensorEvent; import android.util.Log; import android.widget.TextView; import android.os.Build; +import java.util.Arrays; class AccelerometerReader implements SensorEventListener @@ -105,33 +106,162 @@ class AccelerometerReader implements SensorEventListener static class GyroscopeListener implements SensorEventListener { - public float x1 = 0.0f, x2 = 0.0f, xc = 0.0f, y1 = 0.0f, y2 = 0.0f, yc = 0.0f, z1 = 0.0f, z2 = 0.0f, zc = 0.0f; public boolean invertedOrientation = false; + + final float noiseMin[] = new float[] { -1.0f, -1.0f, -1.0f }; // Large initial values, they will only decrease + final float noiseMax[] = new float[] { 1.0f, 1.0f, 1.0f }; + + float noiseData[][] = new float[200][3]; + int noiseDataIdx = noiseData.length * 3 / 4; // Speed up first measurement, to converge to sane values faster + int noiseMovementDetected = 0; + float noiseMeasuredRange[] = null; + + static int noiseCounter = 0; + public GyroscopeListener() { } - public void onSensorChanged(SensorEvent event) + + void collectNoiseData(final float[] data) { - if( event.values[0] < x1 || event.values[0] > x2 || - event.values[1] < y1 || event.values[1] > y2 || - event.values[2] < z1 || event.values[2] > z2 ) + for( int i = 0; i < 3; i++ ) { - if( Globals.HorizontalOrientation ) + if( data[i] < noiseMin[i] || data[i] > noiseMax[i] ) { - if( invertedOrientation ) - nativeGyroscope(-(event.values[0] - xc), -(event.values[1] - yc), event.values[2] - zc); - else - nativeGyroscope(event.values[0] - xc, event.values[1] - yc, event.values[2] - zc); + // Movement detected, this can converge our min/max too early, so we're discarding last few values + if( noiseMovementDetected < 0 ) + { + int discard = 10; + if( -noiseMovementDetected < discard ) + discard = -noiseMovementDetected; + noiseDataIdx -= discard; + if( noiseDataIdx < 0 ) + noiseDataIdx = 0; + } + noiseMovementDetected = 10; + return; } - else + noiseData[noiseDataIdx][i] = data[i]; + } + noiseMovementDetected--; + if( noiseMovementDetected >= 0 ) + return; // Also discard several values after the movement stopped + noiseDataIdx++; + + if( noiseDataIdx < noiseData.length ) + return; + + noiseCounter++; + Log.i( "SDL", "GYRO_NOISE: Measuring in progress... " + noiseCounter ); // DEBUG + if( noiseCounter > 15 ) + { + Log.i( "SDL", "GYRO_NOISE: Measuring done! Max iteration reached " + noiseCounter ); // DEBUG + noiseData = null; + noiseMeasuredRange = null; + } + + noiseDataIdx = 0; + boolean changed = false; + for( int i = 0; i < 3; i++ ) + { + float min = 1.0f; + float max = -1.0f; + for( int ii = 0; ii < noiseData.length; ii++ ) { - if( invertedOrientation ) - nativeGyroscope(-(event.values[1] - yc), event.values[0] - xc, event.values[2] - zc); - else - nativeGyroscope(event.values[1] - yc, -(event.values[0] - xc), event.values[2] - zc); + if( min > noiseData[ii][i] ) + min = noiseData[ii][i]; + if( max < noiseData[ii][i] ) + max = noiseData[ii][i]; + } + // Increase the range a bit, for conservative noise filtering + float middle = (min + max) / 2.0f; + min += (min - middle) * 0.2f; + max += (max - middle) * 0.2f; + // Check if range between min/max is less then the current range, as a safety measure, + // and min/max range is not jumping outside of previously measured range + if( max - min < noiseMax[i] - noiseMin[i] && min >= noiseMin[i] && max <= noiseMax[i] ) + { + noiseMax[i] = (noiseMax[i] + max * 4.0f) / 5.0f; + noiseMin[i] = (noiseMin[i] + min * 4.0f) / 5.0f; + changed = true; } } + + Log.i( "SDL", "GYRO_NOISE: MIN MAX: " + Arrays.toString(noiseMin) + " " + Arrays.toString(noiseMax) ); // DEBUG + + if( !changed ) + return; + + // Determine when to stop measuring - check that the previous min/max range is close to the current one + + float range[] = new float[3]; + for( int i = 0; i < 3; i++ ) + range[i] = noiseMax[i] - noiseMin[i]; + + Log.i( "SDL", "GYRO_NOISE: RANGE: " + Arrays.toString(range) + " " + Arrays.toString(noiseMeasuredRange) ); // DEBUG + + if( noiseMeasuredRange == null ) + { + noiseMeasuredRange = range; + return; + } + + for( int i = 0; i < 3; i++ ) + { + if( noiseMeasuredRange[i] / range[i] > 1.2f ) + { + noiseMeasuredRange = range; + return; + } + } + + // We converged to the final min/max, stop measuring + noiseData = null; + noiseMeasuredRange = null; + Log.i( "SDL", "GYRO_NOISE: Measuring done! Range converged on iteration " + noiseCounter ); // DEBUG } + + public void onSensorChanged(final SensorEvent event) + { + boolean filtered = true; + final float[] data = event.values; + + if( noiseData != null ) + collectNoiseData(data); + + for( int i = 0; i < 3; i++ ) + { + if( data[i] < noiseMin[i] ) + { + filtered = false; + data[i] -= noiseMin[i]; + } + else if( data[i] > noiseMax[i] ) + { + filtered = false; + data[i] -= noiseMax[i]; + } + } + + if( filtered ) + return; + + if( Globals.HorizontalOrientation ) + { + if( invertedOrientation ) + nativeGyroscope(-data[0], -data[1], data[2]); + else + nativeGyroscope(data[0], data[1], data[2]); + } + else + { + if( invertedOrientation ) + nativeGyroscope(-data[1], data[0], data[2]); + else + nativeGyroscope(data[1], -data[0], data[2]); + } + } + public void onAccuracyChanged(Sensor s, int a) { } diff --git a/project/java/Settings.java b/project/java/Settings.java index 8863745b7..84dd59d3a 100644 --- a/project/java/Settings.java +++ b/project/java/Settings.java @@ -163,15 +163,16 @@ class Settings out.writeBoolean(false); // Unused out.writeInt(Globals.TouchscreenKeyboardDrawSize); out.writeInt(p.getApplicationVersion()); - out.writeFloat(AccelerometerReader.gyro.x1); - out.writeFloat(AccelerometerReader.gyro.x2); - out.writeFloat(AccelerometerReader.gyro.xc); - out.writeFloat(AccelerometerReader.gyro.y1); - out.writeFloat(AccelerometerReader.gyro.y2); - out.writeFloat(AccelerometerReader.gyro.yc); - out.writeFloat(AccelerometerReader.gyro.z1); - out.writeFloat(AccelerometerReader.gyro.z2); - out.writeFloat(AccelerometerReader.gyro.zc); + // Gyroscope calibration data, now unused + out.writeFloat(0.0f); + out.writeFloat(0.0f); + out.writeFloat(0.0f); + out.writeFloat(0.0f); + out.writeFloat(0.0f); + out.writeFloat(0.0f); + out.writeFloat(0.0f); + out.writeFloat(0.0f); + out.writeFloat(0.0f); out.writeBoolean(Globals.OuyaEmulation); out.writeBoolean(Globals.HoverJitterFilter); @@ -356,15 +357,16 @@ class Settings settingsFile.readBoolean(); // Unused Globals.TouchscreenKeyboardDrawSize = settingsFile.readInt(); int cfgVersion = settingsFile.readInt(); - AccelerometerReader.gyro.x1 = settingsFile.readFloat(); - AccelerometerReader.gyro.x2 = settingsFile.readFloat(); - AccelerometerReader.gyro.xc = settingsFile.readFloat(); - AccelerometerReader.gyro.y1 = settingsFile.readFloat(); - AccelerometerReader.gyro.y2 = settingsFile.readFloat(); - AccelerometerReader.gyro.yc = settingsFile.readFloat(); - AccelerometerReader.gyro.z1 = settingsFile.readFloat(); - AccelerometerReader.gyro.z2 = settingsFile.readFloat(); - AccelerometerReader.gyro.zc = settingsFile.readFloat(); + // Gyroscope calibration data, now unused + settingsFile.readFloat(); + settingsFile.readFloat(); + settingsFile.readFloat(); + settingsFile.readFloat(); + settingsFile.readFloat(); + settingsFile.readFloat(); + settingsFile.readFloat(); + settingsFile.readFloat(); + settingsFile.readFloat(); Globals.OuyaEmulation = settingsFile.readBoolean(); Globals.HoverJitterFilter = settingsFile.readBoolean(); diff --git a/project/java/SettingsMenu.java b/project/java/SettingsMenu.java index 12ee38812..c0a8705f0 100644 --- a/project/java/SettingsMenu.java +++ b/project/java/SettingsMenu.java @@ -243,7 +243,6 @@ class SettingsMenu new SettingsMenuMisc.OptionalDownloadConfig(false), new SettingsMenuKeyboard.KeyboardConfigMainMenu(), new SettingsMenuMouse.MouseConfigMainMenu(), - new SettingsMenuMisc.GyroscopeCalibration(), new SettingsMenuMisc.AudioConfig(), new SettingsMenuKeyboard.RemapHwKeysConfig(), new SettingsMenuKeyboard.ScreenGesturesConfig(), diff --git a/project/java/SettingsMenuMisc.java b/project/java/SettingsMenuMisc.java index ed02bf0ca..c1637866b 100644 --- a/project/java/SettingsMenuMisc.java +++ b/project/java/SettingsMenuMisc.java @@ -589,157 +589,19 @@ class SettingsMenuMisc extends SettingsMenu } } - static class GyroscopeCalibration extends Menu implements SensorEventListener + static class GyroscopeCalibration extends Menu { String title(final MainActivity p) { - return p.getResources().getString(R.string.calibrate_gyroscope); + return ""; } boolean enabled() { - return Globals.AppUsesGyroscope || Globals.MoveMouseWithGyroscope; + return false; } void run (final MainActivity p) { - if( !(Globals.AppUsesGyroscope || Globals.MoveMouseWithGyroscope) || !AccelerometerReader.gyro.available(p) ) - { - if( Globals.AppUsesGyroscope || Globals.MoveMouseWithGyroscope ) - { - Toast toast = Toast.makeText(p, p.getResources().getString(R.string.calibrate_gyroscope_not_supported), Toast.LENGTH_LONG); - toast.show(); - } - goBack(p); - return; - } - AlertDialog.Builder builder = new AlertDialog.Builder(p); - builder.setTitle(p.getResources().getString(R.string.calibrate_gyroscope)); - builder.setMessage(p.getResources().getString(R.string.calibrate_gyroscope_text)); - builder.setPositiveButton(p.getResources().getString(R.string.ok), new DialogInterface.OnClickListener() - { - public void onClick(DialogInterface dialog, int item) - { - dialog.dismiss(); - startCalibration(p); - } - }); - builder.setOnCancelListener(new DialogInterface.OnCancelListener() - { - public void onCancel(DialogInterface dialog) - { - goBack(p); - } - }); - AlertDialog alert = builder.create(); - alert.setOwnerActivity(p); - alert.show(); - } - - ImageView img; - Bitmap bmp; - int numEvents; - MainActivity p; - - void startCalibration(final MainActivity _p) - { - p = _p; - img = new ImageView(p); - img.setLayoutParams(new ViewGroup.LayoutParams( ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT)); - img.setScaleType(ImageView.ScaleType.MATRIX); - bmp = BitmapFactory.decodeResource( p.getResources(), R.drawable.calibrate ); - img.setImageBitmap(bmp); - Matrix m = new Matrix(); - RectF src = new RectF(0, 0, bmp.getWidth(), bmp.getHeight()); - RectF dst = new RectF( p.getVideoLayout().getWidth()/2 - 50, p.getVideoLayout().getHeight()/2 - 50, - p.getVideoLayout().getWidth()/2 + 50, p.getVideoLayout().getHeight()/2 + 50); - m.setRectToRect(src, dst, Matrix.ScaleToFit.FILL); - img.setImageMatrix(m); - p.getVideoLayout().addView(img); - numEvents = -10; - AccelerometerReader.gyro.x1 = 100; - AccelerometerReader.gyro.x2 = -100; - AccelerometerReader.gyro.xc = 0; - AccelerometerReader.gyro.y1 = 100; - AccelerometerReader.gyro.y2 = -100; - AccelerometerReader.gyro.yc = 0; - AccelerometerReader.gyro.z1 = 100; - AccelerometerReader.gyro.z2 = -100; - AccelerometerReader.gyro.zc = 0; - AccelerometerReader.gyro.registerListener(p, this); - (new Thread(new Runnable() - { - public void run() - { - for(int count = 1; count < 10; count++) - { - p.setText("" + count * 10 + "% ..."); - try { - Thread.sleep(300); - } catch( Exception e ) {} - } - finishCalibration(p); - } - } - )).start(); - } - - public void onSensorChanged(SensorEvent event) - { - gyroscopeEvent(event.values[0], event.values[1], event.values[2]); - } - public void onAccuracyChanged(Sensor s, int a) - { - } - void gyroscopeEvent(float x, float y, float z) - { - numEvents++; - if (numEvents <= 0) - return; // Skip few initial measurements, they may be incorrect - AccelerometerReader.gyro.xc += x; - AccelerometerReader.gyro.yc += y; - AccelerometerReader.gyro.zc += z; - AccelerometerReader.gyro.x1 = Math.min(AccelerometerReader.gyro.x1, x * 1.02f); // Small safety bound coefficient - AccelerometerReader.gyro.x2 = Math.max(AccelerometerReader.gyro.x2, x * 1.02f); - AccelerometerReader.gyro.y1 = Math.min(AccelerometerReader.gyro.y1, y * 1.02f); - AccelerometerReader.gyro.y2 = Math.max(AccelerometerReader.gyro.y2, y * 1.02f); - AccelerometerReader.gyro.z1 = Math.min(AccelerometerReader.gyro.z1, z * 1.02f); - AccelerometerReader.gyro.z2 = Math.max(AccelerometerReader.gyro.z2, z * 1.02f); - final Matrix m = new Matrix(); - RectF src = new RectF(0, 0, bmp.getWidth(), bmp.getHeight()); - RectF dst = new RectF( x * 5000 + p.getVideoLayout().getWidth()/2 - 50, y * 5000 + p.getVideoLayout().getHeight()/2 - 50, - x * 5000 + p.getVideoLayout().getWidth()/2 + 50, y * 5000 + p.getVideoLayout().getHeight()/2 + 50); - m.setRectToRect(src, dst, Matrix.ScaleToFit.FILL); - p.runOnUiThread(new Runnable() - { - public void run() - { - img.setImageMatrix(m); - } - }); - } - void finishCalibration(final MainActivity p) - { - AccelerometerReader.gyro.unregisterListener(p, this); - try { - Thread.sleep(200); // Just in case we have pending events - } catch( Exception e ) {} - if( numEvents > 10 ) - { - AccelerometerReader.gyro.xc /= (float)numEvents; - AccelerometerReader.gyro.yc /= (float)numEvents; - AccelerometerReader.gyro.zc /= (float)numEvents; - Log.i("SDL", "libSDL: gyroscope calibration: " + - AccelerometerReader.gyro.x1 + " < " + AccelerometerReader.gyro.xc + " > " + AccelerometerReader.gyro.x2 + " : " + - AccelerometerReader.gyro.y1 + " < " + AccelerometerReader.gyro.yc + " > " + AccelerometerReader.gyro.y2 + " : " + - AccelerometerReader.gyro.z1 + " < " + AccelerometerReader.gyro.zc + " > " + AccelerometerReader.gyro.z2); - } - p.runOnUiThread(new Runnable() - { - public void run() - { - p.getVideoLayout().removeView(img); - goBack(p); - } - }); + goBack(p); } } diff --git a/project/jni/application/test-gyro/AndroidAppSettings.cfg b/project/jni/application/test-gyro/AndroidAppSettings.cfg new file mode 100644 index 000000000..8e7f7664f --- /dev/null +++ b/project/jni/application/test-gyro/AndroidAppSettings.cfg @@ -0,0 +1,279 @@ +# The application settings for Android libSDL port + +# Specify application name (e.x. My Application) +AppName="! Gyro test" + +# Specify reversed site name of application (e.x. com.mysite.myapp) +AppFullName=gyro.test + +# Application version code (integer) +AppVersionCode=101 + +# Application user-visible version name (string) +AppVersionName="1.01" + +# Specify path to download application data in zip archive in the form 'Description|URL|MirrorURL^Description2|URL2|MirrorURL2^...' +# If you'll start Description with '!' symbol it will be enabled by default, other downloads should be selected by user from startup config menu +# If the URL in in the form ':dir/file.dat:http://URL/' it will be downloaded as binary BLOB to the application dir and not unzipped +# If the URL does not contain 'http://' it is treated as file from 'project/jni/application/src/AndroidData' dir - +# these files are put inside .apk package by build system +# You can specify Google Play expansion files in the form 'obb:main.12345' or 'obb:patch.12345' where 12345 is the app version, first associated with the file +AppDataDownloadUrl="!!Game data is 1 Mb|ballfield3.zip" + +# Reset SDL config when updating application to the new version (y) / (n) +ResetSdlConfigForThisVersion=n + +# Delete application data files when upgrading (specify file/dir paths separated by spaces) +DeleteFilesOnUpgrade="%" + +# Here you may type readme text, which will be shown during startup. Format is: +# Text in English, use \\\\n to separate lines (that's four backslashes)^de:Text in Deutsch^ru:Text in Russian^button:Button that will open some URL:http://url-to-open/ +ReadmeText='^Readme text' + +# libSDL version to use (1.2/1.3/2.0) +LibSdlVersion=1.2 + +# Specify screen orientation: (v)ertical/(p)ortrait or (h)orizontal/(l)andscape +ScreenOrientation=h + +# Video color depth - 16 BPP is the fastest and supported for all modes, 24 bpp is supported only +# with SwVideoMode=y, SDL_OPENGL mode supports everything. (16)/(24)/(32) +VideoDepthBpp=16 + +# Enable OpenGL depth buffer (needed only for 3-d applications, small speed decrease) (y) or (n) +NeedDepthBuffer=n + +# Enable OpenGL stencil buffer (needed only for 3-d applications, small speed decrease) (y) or (n) +NeedStencilBuffer=n + +# Try to use GLES 2.x context - will revert to GLES 1.X if unsupported by device +# you need this option only if you're developing 3-d app (y) or (n) +NeedGles2=n + +# Application uses software video buffer - you're calling SDL_SetVideoMode() without SDL_HWSURFACE and without SDL_OPENGL, +# this will allow small speed optimization. Enable this even when you're using SDL_HWSURFACE. (y) or (n) +SwVideoMode=y + +# Application video output will be resized to fit into native device screen (y)/(n) +SdlVideoResize=y + +# Application resizing will keep 4:3 aspect ratio, with black bars at sides (y)/(n) +SdlVideoResizeKeepAspect=n + +# Do not allow device to sleep when the application is in foreground, set this for video players or apps which use accelerometer +InhibitSuspend=n + +# Create Android service, so the app is less likely to be killed while in background +CreateService= + +# Application does not call SDL_Flip() or SDL_UpdateRects() appropriately, or draws from non-main thread - +# enabling the compatibility mode will force screen update every 100 milliseconds, which is laggy and inefficient (y) or (n) +CompatibilityHacksForceScreenUpdate=n + +# Application does not call SDL_Flip() or SDL_UpdateRects() after mouse click (ScummVM and all Amiga emulators do that) - +# force screen update by moving mouse cursor a little after each click (y) or (n) +CompatibilityHacksForceScreenUpdateMouseClick=n + +# Application initializes SDL audio/video inside static constructors (which is bad, you won't be able to run ndk-gdb) (y)/(n) +CompatibilityHacksStaticInit=n + +# On-screen Android soft text input emulates hardware keyboard, this will only work with Hackers Keyboard app (y)/(n) +CompatibilityHacksTextInputEmulatesHwKeyboard=n + +# Built-in text input keyboards with custom layouts for emulators, requires CompatibilityHacksTextInputEmulatesHwKeyboard=y +# 0 - standard Android keyboard +# 1 - Simple QWERTY keyboard, no function keys, no arrow keys +# 2 - Commodore 64 keyboard +# 3 - Amiga keyboard +TextInputKeyboard=1 + +# Hack for broken devices: prevent audio chopping, by sleeping a bit after pushing each audio chunk (y)/(n) +CompatibilityHacksPreventAudioChopping=n + +# Hack for broken apps: application ignores audio buffer size returned by SDL (y)/(n) +CompatibilityHacksAppIgnoresAudioBufferSize=n + +# Hack for VCMI: preload additional shared libraries before aplication start +CompatibilityHacksAdditionalPreloadedSharedLibraries="" + +# Hack for Free Heroes 2, which redraws the screen inside SDL_PumpEvents(): slow and compatible SDL event queue - +# do not use it with accelerometer/gyroscope, or your app may freeze at random (y)/(n) +CompatibilityHacksSlowCompatibleEventQueue=n + +# Save and restore OpenGL state when drawing on-screen keyboard for apps that use SDL_OPENGL +CompatibilityHacksTouchscreenKeyboardSaveRestoreOpenGLState= + +# Application uses SDL_UpdateRects() properly, and does not draw in any region outside those rects. +# This improves drawing speed, but I know only one application that does that, and it's written by me (y)/(n) +CompatibilityHacksProperUsageOfSDL_UpdateRects=n + +# Application uses mouse (y) or (n), this will show mouse emulation dialog to the user +AppUsesMouse=y + +# Application needs two-button mouse, will also enable advanced point-and-click features (y) or (n) +AppNeedsTwoButtonMouse=y + +# Right mouse button can do long-press/drag&drop action, necessary for some games (y) or (n) +# If you disable it, swiping with two fingers will send mouse wheel events +RightMouseButtonLongPress=n + +# Show SDL mouse cursor, for applications that do not draw cursor at all (y) or (n) +ShowMouseCursor=n + +# Screen follows mouse cursor, when it's covered by soft keyboard, this works only in software video mode (y) or (n) +ScreenFollowsMouse= + +# Generate more touch events, by default SDL generates one event per one video frame, this is useful for drawing apps (y) or (n) +GenerateSubframeTouchEvents=n + +# Force relative (laptop) mouse movement mode, useful when both on-screen keyboard and mouse are needed (y) or (n) +ForceRelativeMouseMode=n + +# Show on-screen dpad/joystick, that will act as arrow keys (y) or (n) +AppNeedsArrowKeys=n + +# On-screen dpad/joystick will appear under finger when it touches the screen (y) or (n) +# Joystick always follows finger, so moving mouse requires touching the screen with other finger +FloatingScreenJoystick=n + +# Application needs text input (y) or (n), enables button for text input on screen +AppNeedsTextInput=n + +# Application uses joystick (y) or (n), the on-screen DPAD will be used as joystick 0 axes 0-1 +# This will disable AppNeedsArrowKeys option +AppUsesJoystick=n + +# Application uses second on-screen joystick, as SDL joystick 0 axes 2-3 (y)/(n) +AppUsesSecondJoystick=n + +# Application uses third on-screen joystick, as SDL joystick 0 axes 20-21 (y)/(n) +AppUsesThirdJoystick=n + +# Application uses accelerometer (y) or (n), the accelerometer will be used as joystick 1 axes 0-1 and 5-7 +AppUsesAccelerometer=y + +# Application uses gyroscope (y) or (n), the gyroscope will be used as joystick 1 axes 2-4 +AppUsesGyroscope=y + +# Application uses orientation sensor (y) or (n), reported as joystick 1 axes 8-10 +AppUsesOrientationSensor= + +# Use gyroscope to move mouse cursor (y) or (n), it eats battery, and can be disabled in settings, do not use with AppUsesGyroscope setting +MoveMouseWithGyroscope=n + +# Application uses multitouch (y) or (n), multitouch events are passed as SDL_JOYBALLMOTION events for the joystick 0 +AppUsesMultitouch=n + +# Application records audio (it will use any available source, such a s microphone) +# API is defined in file SDL_android.h: int SDL_ANDROID_OpenAudioRecording(SDL_AudioSpec *spec); void SDL_ANDROID_CloseAudioRecording(void); +# This option will add additional permission to Android manifest (y)/(n) +AppRecordsAudio=n + +# Application needs to access SD card. If your data files are bigger than 5 Mb, enable it. (y) / (n) +AccessSdCard=y + +# Application needs Internet access. If you disable it, you'll have to bundle all your data files inside .apk (y) / (n) +AccessInternet= + +# Immersive mode - Android will hide on-screen Home/Back keys. Looks bad if you invoke Android keyboard. (y) / (n) +ImmersiveMode=y + +# Application implements Android-specific routines to put to background, and will not draw anything to screen +# between SDL_ACTIVEEVENT lost / gained notifications - you should check for them +# rigth after SDL_Flip(), if (n) then SDL_Flip() will block till app in background (y) or (n) +# This option is reported to be buggy, sometimes failing to restore video state +NonBlockingSwapBuffers=n + +# Redefine common hardware keys to SDL keysyms +# BACK hardware key is available on all devices, MENU is available on pre-ICS devices, other keys may be absent +# SEARCH and CALL by default return same keycode as DPAD_CENTER - one of those keys is available on most devices +# Use word NO_REMAP if you want to preserve native functionality for certain key (volume keys are 3-rd and 4-th) +# Keys: TOUCHSCREEN (works only when AppUsesMouse=n), DPAD_CENTER/SEARCH, VOLUMEUP, VOLUMEDOWN, MENU, BACK, CAMERA +RedefinedKeys="SPACE RETURN NO_REMAP NO_REMAP SPACE ESCAPE" + +# Number of virtual keyboard keys (currently 6 is maximum) +AppTouchscreenKeyboardKeysAmount=0 + +# Redefine on-screen keyboard keys to SDL keysyms - 6 keyboard keys + 4 multitouch gestures (zoom in/out and rotate left/right) +RedefinedKeysScreenKb="0 1 2 3 4 5 6 7 8 9" + +# Names for on-screen keyboard keys, such as Fire, Jump, Run etc, separated by spaces, they are used in SDL config menu +RedefinedKeysScreenKbNames="0 1 2 3 4 5 6 7 8 9" + +# On-screen keys theme +# 0 = Ultimate Droid by Sean Stieber (green, with cross joystick) +# 1 = Simple Theme by Beholder (white, with cross joystick) +# 2 = Sun by Sirea (yellow, with round joystick) +# 3 = Keen by Gerstrong (multicolor, with round joystick) +# 4 = Retro by Santiago Radeff (red/white, with cross joystick) +TouchscreenKeysTheme=4 + +# Redefine gamepad keys to SDL keysyms, button order is: +# A B X Y L1 R1 L2 R2 LThumb RThumb +RedefinedKeysGamepad="0 1 2 3 4 5 6 7 8 9" + +# How long to show startup menu button, in msec, 0 to disable startup menu +StartupMenuButtonTimeout=0 + +# Menu items to hide from startup menu, available menu items: +# SettingsMenu.OkButton SettingsMenu.DummyMenu SettingsMenu.MainMenu SettingsMenuMisc.DownloadConfig SettingsMenuMisc.OptionalDownloadConfig SettingsMenuMisc.AudioConfig SettingsMenuMisc.VideoSettingsConfig SettingsMenuMisc.ShowReadme SettingsMenuMisc.GyroscopeCalibration SettingsMenuMisc.ResetToDefaultsConfig SettingsMenuMouse.MouseConfigMainMenu SettingsMenuMouse.DisplaySizeConfig SettingsMenuMouse.LeftClickConfig SettingsMenuMouse.RightClickConfig SettingsMenuMouse.AdditionalMouseConfig SettingsMenuMouse.JoystickMouseConfig SettingsMenuMouse.TouchPressureMeasurementTool SettingsMenuMouse.CalibrateTouchscreenMenu SettingsMenuKeyboard.KeyboardConfigMainMenu SettingsMenuKeyboard.ScreenKeyboardSizeConfig SettingsMenuKeyboard.ScreenKeyboardDrawSizeConfig SettingsMenuKeyboard.ScreenKeyboardThemeConfig SettingsMenuKeyboard.ScreenKeyboardTransparencyConfig SettingsMenuKeyboard.RemapHwKeysConfig SettingsMenuKeyboard.RemapScreenKbConfig SettingsMenuKeyboard.ScreenGesturesConfig SettingsMenuKeyboard.CustomizeScreenKbLayout SettingsMenuKeyboard.ScreenKeyboardAdvanced +HiddenMenuOptions='' + +# Menu items to show at startup - this is Java code snippet, leave empty for default +# new SettingsMenuMisc.ShowReadme(), (AppUsesMouse \&\& \! ForceRelativeMouseMode \? new SettingsMenuMouse.DisplaySizeConfig(true) : new SettingsMenu.DummyMenu()), new SettingsMenuMisc.OptionalDownloadConfig(true), new SettingsMenuMisc.GyroscopeCalibration() +# Available menu items: +# SettingsMenu.OkButton SettingsMenu.DummyMenu SettingsMenu.MainMenu SettingsMenuMisc.DownloadConfig SettingsMenuMisc.OptionalDownloadConfig SettingsMenuMisc.AudioConfig SettingsMenuMisc.VideoSettingsConfig SettingsMenuMisc.ShowReadme SettingsMenuMisc.GyroscopeCalibration SettingsMenuMisc.ResetToDefaultsConfig SettingsMenuMouse.MouseConfigMainMenu SettingsMenuMouse.DisplaySizeConfig SettingsMenuMouse.LeftClickConfig SettingsMenuMouse.RightClickConfig SettingsMenuMouse.AdditionalMouseConfig SettingsMenuMouse.JoystickMouseConfig SettingsMenuMouse.TouchPressureMeasurementTool SettingsMenuMouse.CalibrateTouchscreenMenu SettingsMenuKeyboard.KeyboardConfigMainMenu SettingsMenuKeyboard.ScreenKeyboardSizeConfig SettingsMenuKeyboard.ScreenKeyboardDrawSizeConfig SettingsMenuKeyboard.ScreenKeyboardThemeConfig SettingsMenuKeyboard.ScreenKeyboardTransparencyConfig SettingsMenuKeyboard.RemapHwKeysConfig SettingsMenuKeyboard.RemapScreenKbConfig SettingsMenuKeyboard.ScreenGesturesConfig SettingsMenuKeyboard.CustomizeScreenKbLayout SettingsMenuKeyboard.ScreenKeyboardAdvanced +FirstStartMenuOptions='SettingsMenu.DummyMenu' + +# Minimum amount of RAM application requires, in Mb, SDL will print warning to user if it's lower +AppMinimumRAM=0 + +# GCC version, 4.6 (default) or 4.8, CLANG is not supported yet +NDK_TOOLCHAIN_VERSION= + +# Specify architectures to compile, 'all' or 'y' to compile for all architectures. +# Available architectures: armeabi armeabi-v7a armeabi-v7a-hard x86 mips +MultiABI='armeabi-v7a' + +# Optional shared libraries to compile - removing some of them will save space +# MP3 support by libMAD is encumbered by patents and libMAD is GPL-ed +# Available libraries: mad (GPL-ed!) sdl_mixer sdl_image sdl_ttf sdl_net sdl_blitpool sdl_gfx sdl_sound intl xml2 lua jpeg png ogg flac tremor vorbis freetype xerces curl theora fluidsynth lzma lzo2 mikmod openal timidity zzip bzip2 yaml-cpp python boost_date_time boost_filesystem boost_iostreams boost_program_options boost_regex boost_signals boost_system boost_thread glu avcodec avdevice avfilter avformat avresample avutil swscale swresample bzip2 +CompiledLibraries="sdl_image" + +# Application uses custom build script AndroidBuild.sh instead of Android.mk (y) or (n) +CustomBuildScript=n + +# Aditional CFLAGS for application +AppCflags='-O2 -finline-functions' + +# Additional LDFLAGS for application +AppLdflags='-fuse-ld=bfd' + +# If application has headers with the same name as system headers, this option tries to fix compiler flags to make it compilable +AppOverlapsSystemHeaders= + +# Build only following subdirs (empty will build all dirs, ignored with custom script) +AppSubdirsBuild='' + +# Exclude these files from build +AppBuildExclude='' + +# Application command line parameters, including app name as 0-th param +AppCmdline='' + +# Screen size is used by Google Play to prevent an app to be installed on devices with smaller screens +# Minimum screen size that application supports: (s)mall / (m)edium / (l)arge +MinimumScreenSize=s + +# Your AdMob Publisher ID, (n) if you don't want advertisements +AdmobPublisherId=n + +# Your AdMob test device ID, to receive a test ad +AdmobTestDeviceId= + +# Your AdMob banner size (BANNER/FULL_BANNER/LEADERBOARD/MEDIUM_RECTANGLE/SMART_BANNER/WIDE_SKYSCRAPER/FULL_WIDTH:Height/Width:AUTO_HEIGHT/Width:Height) +AdmobBannerSize= + +# Google Play Game Services application ID, required for cloud saves to work +GooglePlayGameServicesId= + diff --git a/project/jni/application/test-gyro/AndroidData/ballfield3.zip b/project/jni/application/test-gyro/AndroidData/ballfield3.zip new file mode 100644 index 000000000..617dcc938 Binary files /dev/null and b/project/jni/application/test-gyro/AndroidData/ballfield3.zip differ diff --git a/project/jni/application/test-gyro/icon.png b/project/jni/application/test-gyro/icon.png new file mode 100644 index 000000000..b3614e149 Binary files /dev/null and b/project/jni/application/test-gyro/icon.png differ diff --git a/project/jni/application/test-gyro/test-gyro.cpp b/project/jni/application/test-gyro/test-gyro.cpp new file mode 100644 index 000000000..c93c59e4a --- /dev/null +++ b/project/jni/application/test-gyro/test-gyro.cpp @@ -0,0 +1,434 @@ +/* + * "Ballfield" + * + * (C) David Olofson , 2002, 2003 + * + * This software is released under the terms of the GPL. + * + * Contact author for permission if you want to use this + * software, or work derived from it, under other terms. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#define fprintf(X, ...) __android_log_print(ANDROID_LOG_INFO, "Ballfield", __VA_ARGS__) +#define printf(...) __android_log_print(ANDROID_LOG_INFO, "Ballfield", __VA_ARGS__) + +/*---------------------------------------------------------- + Definitions... +----------------------------------------------------------*/ + +#define SCREEN_W 1280 +#define SCREEN_H 800 + + + +/*---------------------------------------------------------- + General tool functions +----------------------------------------------------------*/ + +/* + * Bump areas of low and high alpha to 0% or 100% + * respectively, just in case the graphics contains + * "alpha noise". + */ +SDL_Surface *clean_alpha(SDL_Surface *s) +{ + SDL_Surface *work; + SDL_Rect r; + Uint32 *pixels; + int pp; + int x, y; + + work = SDL_CreateRGBSurface(SDL_SWSURFACE, s->w, s->h, + 32, 0xff000000, 0x00ff0000, 0x0000ff00, + 0x000000ff); + if(!work) + return NULL; + + r.x = r.y = 0; + r.w = s->w; + r.h = s->h; + if(SDL_BlitSurface(s, &r, work, NULL) < 0) + { + SDL_FreeSurface(work); + return NULL; + } + + SDL_LockSurface(work); + pixels = (Uint32 *)work->pixels; + pp = work->pitch / sizeof(Uint32); + for(y = 0; y < work->h; ++y) + for(x = 0; x < work->w; ++x) + { + Uint32 pix = pixels[y*pp + x]; + switch((pix & 0xff) >> 4) + { + case 0: + pix = 0x00000000; + break; + default: + break; + case 15: + pix |= 0xff; + break; + } + pixels[y*pp + x] = pix; + } + SDL_UnlockSurface(work); + + return work; +} + + +/* + * Load and convert an antialiazed, zoomed set of sprites. + */ +SDL_Surface *load_zoomed(char *name, int alpha) +{ + SDL_Surface *sprites; + SDL_Surface *temp = IMG_Load(name); + if(!temp) + return NULL; + + /* + sprites = temp; + SDL_SetAlpha(sprites, 0, 255); + temp = clean_alpha(sprites); + SDL_FreeSurface(sprites); + */ + if(!temp) + { + fprintf(stderr, "Could not clean alpha!\n"); + return NULL; + } + + if(alpha) + { + SDL_SetAlpha(temp, 0, SDL_ALPHA_OPAQUE); + sprites = SDL_DisplayFormatAlpha(temp); + } + else + { + SDL_SetColorKey(temp, SDL_SRCCOLORKEY, + SDL_MapRGB(temp->format, 0, 0, 0)); + sprites = SDL_DisplayFormat(temp); + } + SDL_FreeSurface(temp); + + return sprites; +} + + +void print_num(SDL_Surface *dst, SDL_Surface *font, int x, int y, float value) +{ + char buf[16]; + int val = (int)(value * 10.0); + int pos, p = 0; + SDL_Rect from; + + /* Sign */ + if(val < 0) + { + buf[p++] = 10; + val = -val; + } + + /* Integer part */ + pos = 10000000; + while(pos > 1) + { + int num = val / pos; + val -= num * pos; + pos /= 10; + if(p || num) + buf[p++] = num; + } + + /* Decimals */ + if(val / pos) + { + buf[p++] = 11; + while(pos > 0) + { + int num = val / pos; + val -= num * pos; + pos /= 10; + buf[p++] = num; + } + } + + /* Render! */ + from.y = 0; + from.w = 7; + from.h = 10; + for(pos = 0; pos < p; ++pos) + { + SDL_Rect to; + to.x = x + pos * 7; + to.y = y; + from.x = buf[pos] * 7; + SDL_BlitSurface(font, &from, dst, &to); + } +} + +/* + * Draw tiled background image with offset. + */ +void tiled_back(SDL_Surface *back, SDL_Surface *screen, int xo, int yo) +{ + SDL_Rect r; + xo %= back->w/8; + yo %= back->h/8; + r.x = xo - back->w/2 + screen->w/2; + r.y = yo - back->h/2 + screen->h/2; + r.w = back->w; + r.h = back->h; + SDL_BlitSurface(back, NULL, screen, &r); +} + +void print_num_hex(SDL_Surface *dst, SDL_Surface *font, int x, int y, unsigned val) +{ + char buf[8]; + int pos, p = 0; + SDL_Rect from; + + //val = htonl(val); // Big-endian + + /* Render! */ + from.y = 0; + from.w = 7; + from.h = 10; + for(pos = 0; pos < 8; ++pos) + { + SDL_Rect to; + to.x = 8 * 7 - (x + pos * 7); // Little-endian number wrapped backwards + to.y = y; + from.x = ( ( val >> (pos * 4) ) & 0xf ) * 7; + SDL_BlitSurface(font, &from, dst, &to); + } +} + + +/*---------------------------------------------------------- + main() +----------------------------------------------------------*/ + +int main(int argc, char* argv[]) +{ + SDL_Surface *screen; + SDL_Surface *temp_image; + SDL_Surface *back, *logo, *font, *font_hex; + SDL_Event event; + int bpp = 16, + flags = SDL_HWSURFACE, + alpha = 1; + int x_offs = 0, y_offs = 0; + long tick, + last_tick, + last_avg_tick; + double t = 0; + float dt; + int i; + float fps = 0.0; + int fps_count = 0; + int fps_start = 0; + float x_speed, y_speed, z_speed; + enum { MAX_POINTERS = 16 }; + // some random colors + int colors[MAX_POINTERS] = { 0xaaaaaa, 0xffffff, 0x888888, 0xcccccc, 0x666666, 0x999999, 0xdddddd, 0xeeeeee, 0xaaaaaa, 0xffffff, 0x888888, 0xcccccc, 0x666666, 0x999999, 0xdddddd, 0xeeeeee }; + struct TouchPointer_t { int x; int y; int pressure; int pressed; } touchPointers[MAX_POINTERS]; + int accel[5], screenjoy[4], gamepads[4][8]; + SDL_Surface *mouse[4]; + int screenKeyboardShown = 0; + + + SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK); + SDL_EnableUNICODE(1); + SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); + SDL_Joystick * joysticks[6]; + for( i = 0; i < 6; i++ ) + joysticks[i] = SDL_JoystickOpen(i); + + atexit(SDL_Quit); + + screen = SDL_SetVideoMode(SCREEN_W, SCREEN_H, bpp, flags); + if(!screen) + { + fprintf(stderr, "Failed to open screen!\n"); + exit(-1); + } + + SDL_WM_SetCaption("Ballfield", "Ballfield"); + if(flags & SDL_FULLSCREEN) + SDL_ShowCursor(0); + + /* + * Load background image + */ + temp_image = IMG_Load("maxresdefault.jpg"); + if(!temp_image) + { + fprintf(stderr, "Could not load background!\n"); + exit(-1); + } + back = SDL_DisplayFormat(temp_image); + SDL_FreeSurface(temp_image); + + /* + * Load logo + */ + temp_image = SDL_LoadBMP("logo.bmp"); + if(!temp_image) + { + fprintf(stderr, "Could not load logo!\n"); + exit(-1); + } + SDL_SetColorKey(temp_image, SDL_SRCCOLORKEY, + SDL_MapRGB(temp_image->format, 255, 0, 255)); + logo = SDL_DisplayFormat(temp_image); + SDL_FreeSurface(temp_image); + + /* + * Load font + */ + temp_image = SDL_LoadBMP("font7x10.bmp"); + if(!temp_image) + { + fprintf(stderr, "Could not load font!\n"); + exit(-1); + } + SDL_SetColorKey(temp_image, SDL_SRCCOLORKEY, + SDL_MapRGB(temp_image->format, 255, 0, 255)); + font = SDL_DisplayFormat(temp_image); + SDL_FreeSurface(temp_image); + + temp_image = SDL_LoadBMP("font7x10-hex.bmp"); + if(!temp_image) + { + fprintf(stderr, "Could not load hex font!\n"); + exit(-1); + } + SDL_SetColorKey(temp_image, SDL_SRCCOLORKEY, + SDL_MapRGB(temp_image->format, 255, 0, 255)); + font_hex = SDL_DisplayFormat(temp_image); + SDL_FreeSurface(temp_image); + + for(i = 0; i < 4; i++) + { + char name[32]; + sprintf(name, "mouse%d.png", i); + temp_image = IMG_Load(name); + if(!temp_image) + { + fprintf(stderr, "Could not load %s!\n", name); + exit(-1); + } + //mouse[i] = SDL_DisplayFormat(temp_image); + //SDL_FreeSurface(temp_image); + mouse[i] = temp_image; // Keep alpha + } + + last_avg_tick = last_tick = SDL_GetTicks(); + + float gyroX = SCREEN_W/2, gyroY = SCREEN_H/2; + + while(1) + { + SDL_Rect r; + + /* Timing */ + tick = SDL_GetTicks(); + dt = (tick - last_tick) * 0.001f; + last_tick = tick; + + if( bpp == 32 ) + SDL_FillRect(screen, NULL, 0); // Clear alpha channel + + /* Background image */ + tiled_back(back, screen, x_offs>>11, y_offs>>11); + + /* FPS counter */ + if(tick > fps_start + 1000) + { + fps = (float)fps_count * 1000.0 / (tick - fps_start); + fps_count = 0; + fps_start = tick; + } + + print_num(screen, font, screen->w-37, screen->h-12, fps); + ++fps_count; + + + r.x = gyroX; + r.y = gyroY; + r.w = mouse[0]->w; + r.h = mouse[0]->h; + r.x -= r.w/2; + r.y -= r.h/2; + SDL_BlitSurface(mouse[0], NULL, screen, &r); + + SDL_Flip(SDL_GetVideoSurface()); + + SDL_Event evt; + while( SDL_PollEvent(&evt) ) + { + if(evt.type == SDL_KEYUP || evt.type == SDL_KEYDOWN) + { + __android_log_print(ANDROID_LOG_INFO, "Ballfield", "SDL key event: evt %s state %s key %4d %12s scancode %4d mod %2d unicode %d", evt.type == SDL_KEYUP ? "UP " : "DOWN" , evt.key.state == SDL_PRESSED ? "PRESSED " : "RELEASED", (int)evt.key.keysym.sym, SDL_GetKeyName(evt.key.keysym.sym), (int)evt.key.keysym.scancode, (int)evt.key.keysym.mod, (int)evt.key.keysym.unicode); + if(evt.key.keysym.sym == SDLK_ESCAPE) + return 0; + } + if(evt.type == SDL_MOUSEBUTTONUP || evt.type == SDL_MOUSEBUTTONDOWN) + { + __android_log_print(ANDROID_LOG_INFO, "Ballfield", "SDL mouse button event: evt %s state %s button %d coords %d:%d", evt.type == SDL_MOUSEBUTTONUP ? "UP " : "DOWN" , evt.button.state == SDL_PRESSED ? "PRESSED " : "RELEASED", (int)evt.button.button, (int)evt.button.x, (int)evt.button.y); + gyroX = SCREEN_W/2; + gyroY = SCREEN_H/2; + } + if(evt.type == SDL_VIDEORESIZE) + __android_log_print(ANDROID_LOG_INFO, "Ballfield", "SDL resize event: %d x %d", evt.resize.w, evt.resize.h); + if(evt.type == SDL_ACTIVEEVENT) + __android_log_print(ANDROID_LOG_INFO, "Ballfield", "======= SDL active event: gain %d state %d", evt.active.gain, evt.active.state); + // Android-specific events - accelerometer, multitoush, and on-screen joystick + if( evt.type == SDL_JOYAXISMOTION ) + { + if(evt.jaxis.which == 1 && evt.jaxis.axis == 2) + gyroX += evt.jaxis.value / 50.0f; + if(evt.jaxis.which == 1 && evt.jaxis.axis == 3) + gyroY -= evt.jaxis.value / 50.0f; + if(gyroX < 0) + gyroX = 0; + if(gyroX > SCREEN_W) + gyroX = SCREEN_W; + if(gyroY < 0) + gyroY = 0; + if(gyroY > SCREEN_H) + gyroY = SCREEN_H; + } + } + + /* Animate */ + /* + x_speed = 500.0 * sin(t * 0.37); + y_speed = 500.0 * sin(t * 0.53); + z_speed = 400.0 * sin(t * 0.21); + x_offs -= x_speed; + y_offs -= y_speed; + */ + + t += dt; + } + + SDL_FreeSurface(back); + SDL_FreeSurface(logo); + SDL_FreeSurface(font); + return 0; +}