Explorar o código

Adds raw sensor API for distinguishing acceleration from rotation rate. Part 3 of #835.

Ken Whatmough %!s(int64=12) %!d(string=hai) anos
pai
achega
652edff393

+ 14 - 0
gameplay/src/Game.h

@@ -527,6 +527,20 @@ public:
      */
     inline void getAccelerometerValues(float* pitch, float* roll);
 
+    /**
+     * Gets raw sensor values, if equipped, allowing a distinction between device acceleration
+     * and rotation rate. Returns zeros on platforms with no corresponding support. See also
+     * hasAccelerometer() and getAccelerometerValues().
+     *
+     * @param accelX The x-coordinate of the raw accelerometer data.
+     * @param accelY The y-coordinate of the raw accelerometer data.
+     * @param accelZ The z-coordinate of the raw accelerometer data.
+     * @param gyroX The x-coordinate of the raw gyroscope data.
+     * @param gyroY The y-coordinate of the raw gyroscope data.
+     * @param gyroZ The z-coordinate of the raw gyroscope data.
+     */
+    inline void getRawSensorValues(float* accelX, float* accelY, float* accelZ, float* gyroX, float* gyroY, float* gyroZ);
+
     /**
      * Gets the command line arguments.
      * 

+ 5 - 0
gameplay/src/Game.inl

@@ -131,6 +131,11 @@ inline void Game::getAccelerometerValues(float* pitch, float* roll)
     Platform::getAccelerometerValues(pitch, roll);
 }
 
+inline void Game::getRawSensorValues(float* accelX, float* accelY, float* accelZ, float* gyroX, float* gyroY, float* gyroZ)
+{
+    return Platform::getRawSensorValues(accelX, accelY, accelZ, gyroX, gyroY, gyroZ);
+}
+
 inline unsigned int Game::getGamepadCount() const
 {
     return Gamepad::getGamepadCount();

+ 14 - 0
gameplay/src/Platform.h

@@ -217,6 +217,20 @@ private:
      */
     static void getAccelerometerValues(float* pitch, float* roll);
 
+    /**
+     * Gets raw sensor values, if equipped, allowing a distinction between device acceleration
+     * and rotation rate. Returns zeros on platforms with no corresponding support. See also
+     * hasAccelerometer() and getAccelerometerValues().
+     *
+     * @param accelX The x-coordinate of the raw accelerometer data.
+     * @param accelY The y-coordinate of the raw accelerometer data.
+     * @param accelZ The z-coordinate of the raw accelerometer data.
+     * @param gyroX The x-coordinate of the raw gyroscope data.
+     * @param gyroY The y-coordinate of the raw gyroscope data.
+     * @param gyroZ The z-coordinate of the raw gyroscope data.
+     */
+    static void getRawSensorValues(float* accelX, float* accelY, float* accelZ, float* gyroX, float* gyroY, float* gyroZ);
+
     /**
      * Gets the command line arguments.
      * 

+ 77 - 12
gameplay/src/PlatformAndroid.cpp

@@ -31,6 +31,13 @@ static ASensorManager* __sensorManager;
 static ASensorEventQueue* __sensorEventQueue;
 static ASensorEvent __sensorEvent;
 static const ASensor* __accelerometerSensor;
+static const ASensor* __gyroscopeSensor;
+static float __accelRawX;
+static float __accelRawY;
+static float __accelRawZ;
+static float __gyroRawX;
+static float __gyroRawY;
+static float __gyroRawZ;
 static int __orientationAngle = 90;
 static bool __multiSampling = false;
 static bool __multiTouch = false;
@@ -905,13 +912,19 @@ static void engine_handle_cmd(struct android_app* app, int32_t cmd)
             __initialized = false;
             break;
         case APP_CMD_GAINED_FOCUS:
-            // When our app gains focus, we start monitoring the accelerometer.
+            // When our app gains focus, we start monitoring the sensors.
             if (__accelerometerSensor != NULL) 
             {
                 ASensorEventQueue_enableSensor(__sensorEventQueue, __accelerometerSensor);
                 // We'd like to get 60 events per second (in microseconds).
                 ASensorEventQueue_setEventRate(__sensorEventQueue, __accelerometerSensor, (1000L/60)*1000);
             }
+            if (__gyroscopeSensor != NULL)
+            {
+                ASensorEventQueue_enableSensor(__sensorEventQueue, __gyroscopeSensor);
+                // We'd like to get 60 events per second (in microseconds).
+                ASensorEventQueue_setEventRate(__sensorEventQueue, __gyroscopeSensor, (1000L/60)*1000);
+            }
 
             if (Game::getInstance()->getState() == Game::UNINITIALIZED)
             {
@@ -934,12 +947,16 @@ static void engine_handle_cmd(struct android_app* app, int32_t cmd)
             __suspended = true;
             break;
         case APP_CMD_LOST_FOCUS:
-            // When our app loses focus, we stop monitoring the accelerometer.
+            // When our app loses focus, we stop monitoring the sensors.
             // This is to avoid consuming battery while not being used.
             if (__accelerometerSensor != NULL) 
             {
                 ASensorEventQueue_disableSensor(__sensorEventQueue, __accelerometerSensor);
             }
+            if (__gyroscopeSensor != NULL) 
+            {
+                ASensorEventQueue_disableSensor(__sensorEventQueue, __gyroscopeSensor);
+            }
             break;
     }
 }
@@ -1018,6 +1035,7 @@ int Platform::enterMessagePump()
     // Prepare to monitor accelerometer.
     __sensorManager = ASensorManager_getInstance();
     __accelerometerSensor = ASensorManager_getDefaultSensor(__sensorManager, ASENSOR_TYPE_ACCELEROMETER);
+    __gyroscopeSensor = ASensorManager_getDefaultSensor(__sensorManager, ASENSOR_TYPE_GYROSCOPE);
     __sensorEventQueue = ASensorManager_createEventQueue(__sensorManager, __state->looper, LOOPER_ID_USER, NULL, NULL);
     
     // Get the initial time.
@@ -1040,8 +1058,22 @@ int Platform::enterMessagePump()
             
             // If a sensor has data, process it now.
             if (ident == LOOPER_ID_USER && __accelerometerSensor != NULL)
+            {
                 ASensorEventQueue_getEvents(__sensorEventQueue, &__sensorEvent, 1);
-            
+                if (__sensorEvent.type == ASENSOR_TYPE_ACCELEROMETER)
+                {
+                    __accelRawX = __sensorEvent.acceleration.x;
+                    __accelRawY = __sensorEvent.acceleration.y;
+                    __accelRawZ = __sensorEvent.acceleration.z;
+                }
+                else if (__sensorEvent.type == ASENSOR_TYPE_GYROSCOPE)
+                {
+                    __gyroRawX = __sensorEvent.vector.x;
+                    __gyroRawY = __sensorEvent.vector.y;
+                    __gyroRawZ = __sensorEvent.vector.z;
+                }
+            }
+
             if (__state->destroyRequested != 0)
             {
                 return 0;
@@ -1192,23 +1224,23 @@ void Platform::getAccelerometerValues(float* pitch, float* roll)
     switch (__orientationAngle)
     {
     case 90:
-        tx = -__sensorEvent.acceleration.y;
-        ty = __sensorEvent.acceleration.x;
+        tx = -__accelRawY;
+        ty = __accelRawX;
         break;
     case 180:
-        tx = -__sensorEvent.acceleration.x;
-        ty = -__sensorEvent.acceleration.y;
+        tx = -__accelRawX;
+        ty = -__accelRawY;
         break;
     case 270:
-        tx = __sensorEvent.acceleration.y;
-        ty = -__sensorEvent.acceleration.x;
+        tx = __accelRawY;
+        ty = -__accelRawX;
         break;
     default:
-        tx = __sensorEvent.acceleration.x;
-        ty = __sensorEvent.acceleration.y;
+        tx = __accelRawX;
+        ty = __accelRawY;
         break;
     }
-    tz = __sensorEvent.acceleration.z;
+    tz = __accelRawZ;
 
     if (pitch != NULL)
     {
@@ -1222,6 +1254,39 @@ void Platform::getAccelerometerValues(float* pitch, float* roll)
     }
 }
 
+void Platform::getRawSensorValues(float* accelX, float* accelY, float* accelZ, float* gyroX, float* gyroY, float* gyroZ)
+{
+    if (accelX)
+    {
+        *accelX = __accelRawX;
+    }
+
+    if (accelY)
+    {
+        *accelY = __accelRawY;
+    }
+
+    if (accelZ)
+    {
+        *accelZ = __accelRawZ;
+    }
+
+    if (gyroX)
+    {
+        *gyroX = __gyroRawX;
+    }
+
+    if (gyroY)
+    {
+        *gyroY = __gyroRawY;
+    }
+
+    if (gyroZ)
+    {
+        *gyroZ = __gyroRawZ;
+    }
+}
+
 void Platform::getArguments(int* argc, char*** argv)
 {
     if (argc)

+ 54 - 1
gameplay/src/PlatformBlackBerry.cpp

@@ -46,6 +46,12 @@ static bool __multiTouch = false;
 static bool __multiSampling = false;
 static float __pitch;
 static float __roll;
+static float __accelRawX;
+static float __accelRawY;
+static float __accelRawZ;
+static float __gyroRawX;
+static float __gyroRawY;
+static float __gyroRawZ;
 static const char* __glExtensions;
 static struct gestures_set * __gestureSet;
 static bitset<3> __gestureEventsProcessed;
@@ -704,10 +710,16 @@ Platform* Platform::create(Game* game, void* attachToWindow)
     bps_initialize();
 
     // Initialize navigator and orientation
-    static const int SENSOR_RATE = 25000;
+    static const int SENSOR_RATE = 25000; // (25000 microseconds = 40 Hz)
     sensor_set_rate(SENSOR_TYPE_AZIMUTH_PITCH_ROLL, SENSOR_RATE);
+    sensor_set_rate(SENSOR_TYPE_ACCELEROMETER, SENSOR_RATE);
+    sensor_set_rate(SENSOR_TYPE_GYROSCOPE, SENSOR_RATE);
     sensor_set_skip_duplicates(SENSOR_TYPE_AZIMUTH_PITCH_ROLL, true);
+    sensor_set_skip_duplicates(SENSOR_TYPE_ACCELEROMETER, true);
+    sensor_set_skip_duplicates(SENSOR_TYPE_GYROSCOPE, true);
     sensor_request_events(SENSOR_TYPE_AZIMUTH_PITCH_ROLL);
+    sensor_request_events(SENSOR_TYPE_ACCELEROMETER);
+    sensor_request_events(SENSOR_TYPE_GYROSCOPE);
     navigator_request_events(0);
     navigator_rotation_lock(true);
     __orientationAngle = atoi(getenv("ORIENTATION"));
@@ -1311,6 +1323,14 @@ int Platform::enterMessagePump()
                     float azimuth;
                     sensor_event_get_apr(event, &azimuth, &__pitch, &__roll);
                 }
+                else if (bps_event_get_code(event) == SENSOR_ACCELEROMETER_READING)
+                {
+                    sensor_event_get_xyz(event, &__accelRawX, &__accelRawY, &__accelRawZ);
+                }
+                else if (bps_event_get_code(event) == SENSOR_GYROSCOPE_READING)
+                {
+                    sensor_event_get_xyz(event, &__gyroRawX, &__gyroRawY, &__gyroRawZ);
+                }
             }
         }
 
@@ -1481,6 +1501,39 @@ void Platform::getAccelerometerValues(float* pitch, float* roll)
     }
 }
 
+void Platform::getRawSensorValues(float* accelX, float* accelY, float* accelZ, float* gyroX, float* gyroY, float* gyroZ)
+{
+	if (accelX)
+	{
+		*accelX = __accelRawX;
+	}
+
+	if (accelY)
+	{
+		*accelY = __accelRawY;
+	}
+
+	if (accelZ)
+	{
+		*accelZ = __accelRawZ;
+	}
+
+	if (gyroX)
+	{
+		*gyroX = __gyroRawX;
+	}
+
+	if (gyroY)
+	{
+		*gyroY = __gyroRawY;
+	}
+
+	if (gyroZ)
+	{
+		*gyroZ = __gyroRawZ;
+	}
+}
+
 void Platform::getArguments(int* argc, char*** argv)
 {
     if (argc)

+ 33 - 0
gameplay/src/PlatformLinux.cpp

@@ -1422,6 +1422,39 @@ namespace gameplay
         *roll = 0;
     }
 
+    void Platform::getRawSensorValues(float* accelX, float* accelY, float* accelZ, float* gyroX, float* gyroY, float* gyroZ)
+    {
+        if (accelX)
+        {
+            *accelX = 0;
+        }
+
+        if (accelY)
+        {
+            *accelY = 0;
+        }
+
+        if (accelZ)
+        {
+            *accelZ = 0;
+        }
+
+        if (gyroX)
+        {
+            *gyroX = 0;
+        }
+
+        if (gyroY)
+        {
+            *gyroY = 0;
+        }
+
+        if (gyroZ)
+        {
+            *gyroZ = 0;
+        }
+    }
+
     void Platform::getArguments(int* argc, char*** argv)
     {
         if (argc)

+ 28 - 0
gameplay/src/PlatformMacOSX.mm

@@ -1813,6 +1813,34 @@ void Platform::getAccelerometerValues(float* pitch, float* roll)
     *roll = 0;
 }
 
+void Platform::getRawSensorValues(float* accelX, float* accelY, float* accelZ, float* gyroX, float* gyroY, float* gyroZ)
+{
+    if (accelX)
+    {
+        *accelX = 0;
+    }
+    if (accelY)
+    {
+        *accelY = 0;
+    }
+    if (accelZ)
+    {
+        *accelZ = 0;
+    }
+    if (gyroX)
+    {
+        *gyroX = 0;
+    }
+    if (gyroY)
+    {
+        *gyroY = 0;
+    }
+    if (gyroZ)
+    {
+        *gyroZ = 0;
+    }
+}
+
 void Platform::getArguments(int* argc, char*** argv)
 {
     if (argc)

+ 33 - 0
gameplay/src/PlatformWindows.cpp

@@ -1115,6 +1115,39 @@ void Platform::getAccelerometerValues(float* pitch, float* roll)
     *roll = 0;
 }
 
+void Platform::getRawSensorValues(float* accelX, float* accelY, float* accelZ, float* gyroX, float* gyroY, float* gyroZ)
+{
+    if (accelX)
+    {
+        *accelX = 0;
+    }
+
+    if (accelY)
+    {
+        *accelY = 0;
+    }
+
+    if (accelZ)
+    {
+        *accelZ = 0;
+    }
+
+    if (gyroX)
+    {
+        *gyroX = 0;
+    }
+
+    if (gyroY)
+    {
+        *gyroY = 0;
+    }
+
+    if (gyroZ)
+    {
+        *gyroZ = 0;
+    }
+}
+
 void Platform::getArguments(int* argc, char*** argv)
 {
     if (argc)

+ 61 - 2
gameplay/src/PlatformiOS.mm

@@ -850,7 +850,12 @@ int getUnicode(int key);
         motionManager.accelerometerUpdateInterval = 1 / 40.0;    // 40Hz
         [motionManager startAccelerometerUpdates];
     }
-        
+    if([motionManager isGyroAvailable] == YES)
+    {
+        motionManager.gyroUpdateInterval = 1 / 40.0;    // 40Hz
+        [motionManager startGyroUpdates];
+    }
+    
     window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
     viewController = [[ViewController alloc] init];
     [window setRootViewController:viewController];
@@ -901,6 +906,28 @@ int getUnicode(int key);
         *roll = r;
 }
 
+- (void)getRawAccelX:(float*)x Y:(float*)y Z:(float*)z
+{
+    CMAccelerometerData* accelerometerData = motionManager.accelerometerData;
+    if(accelerometerData != nil)
+    {
+        *x = -9.81f * accelerometerData.acceleration.x;
+        *y = -9.81f * accelerometerData.acceleration.y;
+        *z = -9.81f * accelerometerData.acceleration.z;
+    }
+}
+
+- (void)getRawGyroX:(float*)x Y:(float*)y Z:(float*)z
+{
+    CMGyroData* gyroData = motionManager.gyroData;
+    if(gyroData != nil)
+    {
+        *x = gyroData.rotationRate.x;
+        *y = gyroData.rotationRate.y;
+        *z = gyroData.rotationRate.z;
+    }
+}
+
 - (void)applicationWillResignActive:(UIApplication*)application
 {    
     [viewController stopUpdating];
@@ -1389,7 +1416,39 @@ void Platform::getAccelerometerValues(float* pitch, float* roll)
 {
     [__appDelegate getAccelerometerPitch:pitch roll:roll];
 }
-    
+
+void Platform::getRawSensorValues(float* accelX, float* accelY, float* accelZ, float* gyroX, float* gyroY, float* gyroZ)
+{
+    float x, y, z;
+    [__appDelegate getRawAccelX:&x Y:&y Z:&z];
+    if (accelX)
+    {
+        *accelX = x;
+    }
+    if (accelY)
+    {
+        *accelY = y;
+    }
+    if (accelZ)
+    {
+        *accelZ = z;
+    }
+
+    [__appDelegate getRawGyroX:&x Y:&y Z:&z];
+    if (gyroX)
+    {
+        *gyroX = x;
+    }
+    if (gyroY)
+    {
+        *gyroY = y;
+    }
+    if (gyroZ)
+    {
+        *gyroZ = z;
+    }
+}
+
 void Platform::getArguments(int* argc, char*** argv)
 {
     if (argc)

+ 60 - 1
samples/browser/src/InputSample.cpp

@@ -11,7 +11,8 @@
 static const char* keyString(int key);
 
 InputSample::InputSample()
-    :  _mouseString("No Mouse"), _font(NULL), _inputSampleControls(NULL), _mouseWheel(0), _crosshair(NULL)
+    :  _mouseString("No Mouse"), _font(NULL), _inputSampleControls(NULL), _mouseWheel(0), _crosshair(NULL),
+       _scene(NULL), _formNode(NULL), _formNodeParent(NULL)
 {
 }
 
@@ -44,6 +45,32 @@ void InputSample::initialize()
     _inputSampleControls->getControl("restoreMouseLabel")->setVisible(false);
 
     _mousePoint.set(-100, -100);
+
+    // Create a 3D form that responds to raw sensor inputs.
+    // For this, we will need a scene with a camera node.
+    Camera* camera = Camera::createPerspective(45.0f, (float)getWidth() / (float)getHeight(), 0.25f, 100.0f);
+    _scene = Scene::create();
+    Node* cameraNode = _scene->addNode("Camera");
+    cameraNode->setCamera(camera);
+    _scene->setActiveCamera(camera);
+    SAFE_RELEASE(camera);
+    _formNodeParent = _scene->addNode("FormParent");
+    _formNode = Node::create("Form");
+    _formNodeParent->addChild(_formNode);
+    Theme* theme = _inputSampleControls->getTheme();
+    Form* form = Form::create("testForm", theme->getStyle("basicContainer"));
+    form->setSize(225, 100);
+    Label* label = Label::create("sensorLabel", theme->getStyle("iconNoBorder"));
+    label->setPosition(25, 15);
+    label->setSize(175, 50);
+    label->setText("Raw sensor response (accel/gyro)");
+    form->addControl(label);
+    label->release();
+    _formNode->setScale(0.0015f, 0.0015f, 1.0f);
+    _formNodeRestPosition.set(0, 0, -1.5f);
+    _formNodeParent->setTranslation(_formNodeRestPosition);
+    _formNode->setTranslation(-0.2f, -0.2f, 0);
+    _formNode->setForm(form);
 }
 
 void InputSample::finalize()
@@ -54,6 +81,8 @@ void InputSample::finalize()
         displayKeyboard(false);
     }
 
+    SAFE_RELEASE(_scene);
+    SAFE_RELEASE(_formNode);
     SAFE_RELEASE(_inputSampleControls);
     SAFE_DELETE(_crosshair);
     SAFE_RELEASE(_font);
@@ -61,6 +90,34 @@ void InputSample::finalize()
 
 void InputSample::update(float elapsedTime)
 {
+    if (hasAccelerometer())
+    {
+        Vector3 accelRaw, gyroRaw;
+        getRawSensorValues(&accelRaw.x, &accelRaw.y, &accelRaw.z, &gyroRaw.x, &gyroRaw.y, &gyroRaw.z);
+
+        // Adjust for landscape mode
+        float temp = accelRaw.x;
+        accelRaw.x = -accelRaw.y;
+        accelRaw.y = temp;
+        temp = gyroRaw.x;
+        gyroRaw.x = -gyroRaw.y;
+        gyroRaw.y = temp;
+
+        // Respond to raw accelerometer inputs
+        Vector3 position;
+        _formNodeParent->getTranslation(&position);
+        position.smooth(_formNodeRestPosition - accelRaw*0.04f, elapsedTime, 100);
+        _formNodeParent->setTranslation(position);
+
+        // Respond to raw gyroscope inputs
+        Vector3 rotation;
+        float angle = _formNodeParent->getRotation(&rotation);
+        rotation *= angle;
+        rotation.smooth(gyroRaw*(-0.18f), elapsedTime, 220);
+        angle = rotation.length();
+        rotation.normalize();
+        _formNodeParent->setRotation(rotation, angle);
+    }
 }
 
 void InputSample::render(float elapsedTime)
@@ -157,6 +214,8 @@ void InputSample::render(float elapsedTime)
     }
     if (hasAccelerometer() && !_keyboardState)
     {
+        _formNode->getForm()->draw();
+
         sprintf(buffer, "Pitch: %f   Roll: %f", pitch, roll);
         _font->measureText(buffer, _font->getSize(), &width, &height);
         _font->drawText(buffer, getWidth() - width, getHeight() - height, fontColor, _font->getSize());

+ 4 - 0
samples/browser/src/InputSample.h

@@ -65,6 +65,10 @@ private:
     Rectangle _crosshairSrcRect;
     Vector2 _crosshairLowerLimit;
     Vector2 _crosshairUpperLimit;
+    Scene* _scene;
+    Node* _formNode;
+    Node* _formNodeParent;
+    Vector3 _formNodeRestPosition;
 };
 
 #endif

+ 5 - 0
samples/browser/src/Sample.cpp

@@ -185,6 +185,11 @@ void Sample::getAccelerometerValues(float* pitch, float* roll)
     Game::getInstance()->getAccelerometerValues(pitch, roll);
 }
 
+void Sample::getRawSensorValues(float* accelX, float* accelY, float* accelZ, float* gyroX, float* gyroY, float* gyroZ)
+{
+    Game::getInstance()->getRawSensorValues(accelX, accelY, accelZ, gyroX, gyroY, gyroZ);
+}
+
 void Sample::schedule(long timeOffset, TimeListener* timeListener, void* cookie)
 {
     Game::getInstance()->schedule(timeOffset, timeListener, cookie);

+ 1 - 0
samples/browser/src/Sample.h

@@ -61,6 +61,7 @@ public:
     bool isMultiTouch() const;
     bool hasAccelerometer() const;
     void getAccelerometerValues(float* pitch, float* roll);
+    void getRawSensorValues(float* accelX, float* accelY, float* accelZ, float* gyroX, float* gyroY, float* gyroZ);
     void schedule(long timeOffset, TimeListener* timeListener, void* cookie = 0);
 	void enableScriptCamera(bool enable);
     void setScriptCameraSpeed(float normal, float fast);