Browse Source

Razer Hydra integration

DavidWyand-GG 12 years ago
parent
commit
0b4c3f1e42

+ 35 - 0
Engine/source/platform/input/razerHydra/razerHydraConstants.h

@@ -0,0 +1,35 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2012 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#ifndef _RAZERHYDRACONSTANTS_H_
+#define _RAZERHYDRACONSTANTS_H_
+
+namespace RazerHydraConstants
+{
+   enum Constants {
+      DefaultHydraBase     = 0,
+      HydraActiveCheckFreq = 1000,
+      MaxControllers       = 2,
+   };
+}
+
+#endif   // _RAZERHYDRACONSTANTS_H_

+ 192 - 0
Engine/source/platform/input/razerHydra/razerHydraData.cpp

@@ -0,0 +1,192 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2012 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#include "platform/input/razerHydra/razerHydraData.h"
+#include "platform/input/razerHydra/razerHydraUtil.h"
+
+RazerHyrdaControllerData::RazerHyrdaControllerData()
+{
+   reset();
+}
+
+void RazerHyrdaControllerData::reset()
+{
+   mDataSet = false;
+
+   mShoulder = false;
+   mThumb = false;
+   mStart = false;
+   mButton1 = false;
+   mButton2 = false;
+   mButton3 = false;
+   mButton4 = false;
+
+   mIsDocked = false;
+}
+
+void RazerHyrdaControllerData::setData(const sixenseControllerData& data, const F32& maxAxisRadius)
+{
+   // Controller position
+   RazerHydraUtil::convertPosition(data.pos, mRawPos[0], mRawPos[1], mRawPos[2]);
+   mPos[0] = (S32)mFloor(mRawPos[0]);
+   mPos[1] = (S32)mFloor(mRawPos[1]);
+   mPos[2] = (S32)mFloor(mRawPos[2]);
+
+   mPosPoint.set(mPos[0], mPos[1], mPos[2]);
+
+   // Controller rotation
+   RazerHydraUtil::convertRotation(data.rot_mat, mRot);
+   mRotQuat.set(mRot);
+
+   // Controller rotation as axis, but only if not docked
+   if(!data.is_docked)
+   {
+      RazerHydraUtil::calculateAxisRotation(mRot, maxAxisRadius, mRotAxis);
+   }
+   else
+   {
+      mRotAxis.x = 0.0f;
+      mRotAxis.y = 0.0f;
+   }
+
+   // Thumb stick
+   mThumbStick[0] = data.joystick_x;
+   mThumbStick[1] = data.joystick_y;
+
+   // Trigger
+   mTrigger = data.trigger;
+
+   //Buttons
+   mShoulder = data.buttons & SIXENSE_BUTTON_BUMPER;
+   mThumb = data.buttons & SIXENSE_BUTTON_JOYSTICK;
+   mStart = data.buttons & SIXENSE_BUTTON_START;
+   mButton1 = data.buttons & SIXENSE_BUTTON_1;
+   mButton2 = data.buttons & SIXENSE_BUTTON_2;
+   mButton3 = data.buttons & SIXENSE_BUTTON_3;
+   mButton4 = data.buttons & SIXENSE_BUTTON_4;
+
+   // Other data
+   mIsDocked = data.is_docked;
+
+   // Store the current sequence number
+   mSequenceNum = data.sequence_number;
+
+   mDataSet = true;
+}
+
+U32 RazerHyrdaControllerData::compare(RazerHyrdaControllerData* other)
+{
+   S32 result = DIFF_NONE;
+
+   // Check position
+   if(mDataSet)
+   {
+      if(mPos[0] != other->mPos[0])
+         result |= DIFF_POSX;
+
+      if(mPos[1] != other->mPos[1])
+         result |= DIFF_POSY;
+
+      if(mPos[2] != other->mPos[2])
+         result |= DIFF_POSZ;
+   }
+   else
+   {
+      result |= DIFF_POS;
+   }
+
+   // Check rotation
+   if(mRotQuat != other->mRotQuat || !mDataSet)
+   {
+      result |= DIFF_ROT;
+   }
+
+   // Check rotation as axis
+   if(mRotAxis.x != other->mRotAxis.x || !mDataSet)
+   {
+      result |= DIFF_ROTAXISX;
+   }
+   if(mRotAxis.y != other->mRotAxis.y || !mDataSet)
+   {
+      result |= DIFF_ROTAXISY;
+   }
+
+   // Check thumb stick
+   if(mThumbStick[0] != other->mThumbStick[0] || !mDataSet)
+   {
+      result |= DIFF_AXISX;
+   }
+   if(mThumbStick[1] != other->mThumbStick[1] || !mDataSet)
+   {
+      result |= DIFF_AXISY;
+   }
+
+   // Check trigger
+   if(mTrigger != other->mTrigger || !mDataSet)
+   {
+      result |= DIFF_TRIGGER;
+   }
+
+   // Check buttons
+   if(mShoulder != other->mShoulder)
+   {
+      result |= DIFF_BUTTON_SHOULDER;
+   }
+   if(mThumb != other->mThumb)
+   {
+      result |= DIFF_BUTTON_THUMB;
+   }
+   if(mStart != other->mStart)
+   {
+      result |= DIFF_BUTTON_START;
+   }
+   if(mButton1 != other->mButton1)
+   {
+      result |= DIFF_BUTTON1;
+   }
+   if(mButton2 != other->mButton2)
+   {
+      result |= DIFF_BUTTON2;
+   }
+   if(mButton3 != other->mButton3)
+   {
+      result |= DIFF_BUTTON3;
+   }
+   if(mButton4 != other->mButton4)
+   {
+      result |= DIFF_BUTTON4;
+   }
+
+   return result;
+}
+
+U32 RazerHyrdaControllerData::compareMeta(RazerHyrdaControllerData* other)
+{
+   S32 result = DIFF_NONE;
+
+   if(mIsDocked != other->mIsDocked || !mDataSet)
+   {
+      result |= METADIFF_DOCKED;
+   }
+
+   return result;
+}

+ 111 - 0
Engine/source/platform/input/razerHydra/razerHydraData.h

@@ -0,0 +1,111 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2012 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#ifndef _RAZERHYDRADATA_H_
+#define _RAZERHYDRADATA_H_
+
+#include "console/consoleTypes.h"
+#include "math/mMathFn.h"
+#include "math/mMatrix.h"
+#include "math/mQuat.h"
+#include "sixense.h"
+
+struct RazerHyrdaControllerData
+{
+   enum DataDifferences {
+      DIFF_NONE            = 0,
+      DIFF_POSX            = (1<<0),
+      DIFF_POSY            = (1<<1),
+      DIFF_POSZ            = (1<<2),
+      DIFF_ROT             = (1<<3),
+      DIFF_ROTAXISX        = (1<<4),
+      DIFF_ROTAXISY        = (1<<5),
+      DIFF_AXISX           = (1<<6),
+      DIFF_AXISY           = (1<<7),
+      DIFF_TRIGGER         = (1<<8),
+      DIFF_BUTTON1         = (1<<9),
+      DIFF_BUTTON2         = (1<<10),
+      DIFF_BUTTON3         = (1<<11),
+      DIFF_BUTTON4         = (1<<12),
+      DIFF_BUTTON_START    = (1<<13),
+      DIFF_BUTTON_SHOULDER = (1<<14),
+      DIFF_BUTTON_THUMB    = (1<<15),
+
+      DIFF_POS = (DIFF_POSX | DIFF_POSY | DIFF_POSZ),
+      DIFF_AXIS = (DIFF_AXISX | DIFF_AXISY),
+      DIFF_ROTAXIS = (DIFF_ROTAXISX | DIFF_ROTAXISY),
+   };
+
+   enum MetaDataDifferences {
+      METADIFF_NONE        = 0,
+      METADIFF_DOCKED      = (1<<0),
+   };
+
+   bool mDataSet;
+
+   // Position
+   F32 mRawPos[3];
+   S32 mPos[3];
+   Point3F mPosPoint;
+
+   // Rotation
+   MatrixF mRot;
+   QuatF   mRotQuat;
+
+   // Controller rotation as axis x, y
+   Point2F mRotAxis;
+
+   // Thumb stick x, y and trigger
+   F32 mThumbStick[2];
+   F32 mTrigger;
+
+   // Buttons
+   bool mShoulder;
+   bool mThumb;
+   bool mStart;
+   bool mButton1;
+   bool mButton2;
+   bool mButton3;
+   bool mButton4;
+
+   // Other data
+   bool mIsDocked;
+
+   // Sequence number from sixense
+   U32 mSequenceNum;
+
+   RazerHyrdaControllerData();
+
+   /// Reset controller data
+   void reset();
+
+   /// Set position based on sixense controller data
+   void setData(const sixenseControllerData& data, const F32& maxAxisRadius);
+
+   /// Compare this data and given and return differences
+   U32 compare(RazerHyrdaControllerData* other);
+
+   /// Compare meta data between this and given and return differences
+   U32 compareMeta(RazerHyrdaControllerData* other);
+};
+
+#endif   // _RAZERHYDRADATA_H_

+ 701 - 0
Engine/source/platform/input/razerHydra/razerHydraDevice.cpp

@@ -0,0 +1,701 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2012 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#include "platform/input/razerHydra/razerHydraDevice.h"
+#include "platform/input/razerHydra/razerHydraData.h"
+#include "platform/input/razerHydra/razerHydraConstants.h"
+#include "platform/input/razerHydra/razerHydraFrameStore.h"
+#include "platform/platformInput.h"
+#include "core/module.h"
+#include "console/engineAPI.h"
+#include "math/mAngAxis.h"
+#include "math/mTransform.h"
+
+MODULE_BEGIN( RazerHydraDevice )
+
+   MODULE_INIT_AFTER( InputEventManager )
+   MODULE_SHUTDOWN_BEFORE( InputEventManager )
+
+   MODULE_INIT
+   {
+      RazerHydraDevice::staticInit();
+      ManagedSingleton< RazerHydraDevice >::createSingleton();
+      if(RazerHydraDevice::smEnableDevice)
+      {
+         RAZERHYDRADEV->enable();
+      }
+
+      // Register the device with the Input Event Manager
+      INPUTMGR->registerDevice(RAZERHYDRADEV);
+   }
+   
+   MODULE_SHUTDOWN
+   {
+      INPUTMGR->unregisterDevice(RAZERHYDRADEV);
+      ManagedSingleton< RazerHydraDevice >::deleteSingleton();
+   }
+
+MODULE_END;
+
+bool RazerHydraDevice::smEnableDevice = true;
+
+bool RazerHydraDevice::smProcessWhenDocked = false;
+
+bool RazerHydraDevice::smSeparatePositionEvents = true;
+bool RazerHydraDevice::smCombinedPositionEvents = false;
+bool RazerHydraDevice::smRotationAsAxisEvents = false;
+
+F32 RazerHydraDevice::smMaximumAxisAngle = 25.0;
+
+bool RazerHydraDevice::smGenerateWholeFrameEvents = false;
+
+U32 RazerHydraDevice::RH_DOCKED[RazerHydraConstants::MaxControllers] = {0};
+U32 RazerHydraDevice::RH_POSX[RazerHydraConstants::MaxControllers] = {0};
+U32 RazerHydraDevice::RH_POSY[RazerHydraConstants::MaxControllers] = {0};
+U32 RazerHydraDevice::RH_POSZ[RazerHydraConstants::MaxControllers] = {0};
+U32 RazerHydraDevice::RH_POS[RazerHydraConstants::MaxControllers] = {0};
+U32 RazerHydraDevice::RH_ROT[RazerHydraConstants::MaxControllers] = {0};
+U32 RazerHydraDevice::RH_ROTAXISX[RazerHydraConstants::MaxControllers] = {0};
+U32 RazerHydraDevice::RH_ROTAXISY[RazerHydraConstants::MaxControllers] = {0};
+U32 RazerHydraDevice::RH_THUMBX[RazerHydraConstants::MaxControllers] = {0};
+U32 RazerHydraDevice::RH_THUMBY[RazerHydraConstants::MaxControllers] = {0};
+U32 RazerHydraDevice::RH_TRIGGER[RazerHydraConstants::MaxControllers] = {0};
+U32 RazerHydraDevice::RH_SHOULDER[RazerHydraConstants::MaxControllers] = {0};
+U32 RazerHydraDevice::RH_THUMB[RazerHydraConstants::MaxControllers] = {0};
+U32 RazerHydraDevice::RH_START[RazerHydraConstants::MaxControllers] = {0};
+U32 RazerHydraDevice::RH_1[RazerHydraConstants::MaxControllers] = {0};
+U32 RazerHydraDevice::RH_2[RazerHydraConstants::MaxControllers] = {0};
+U32 RazerHydraDevice::RH_3[RazerHydraConstants::MaxControllers] = {0};
+U32 RazerHydraDevice::RH_4[RazerHydraConstants::MaxControllers] = {0};
+U32 RazerHydraDevice::RH_FRAME = 0;
+
+RazerHydraDevice::RazerHydraDevice()
+{
+   // From IInputDevice
+   dStrcpy(mName, "razerhydra");
+   mDeviceType = INPUTMGR->getNextDeviceType();
+
+   //
+   mRazerHydraLib = NULL;
+   mEnabled = false;
+   mActive = false;
+   mNumberActiveControllers = 0;
+   mLastActiveCheck = 0;
+
+   for(U32 i=0; i<RazerHydraConstants::MaxControllers; ++i)
+   {
+      for(U32 j=0; j<2; ++j)
+      {
+         mDataBuffer[i][j] = new RazerHyrdaControllerData();
+      }
+
+      mPrevData[i] = mDataBuffer[i][0];
+   }
+
+   buildCodeTable();
+}
+
+RazerHydraDevice::~RazerHydraDevice()
+{
+   mRazerHydraLib = NULL;
+
+   // Delete the controller data buffers
+   for(U32 i=0; i<RazerHydraConstants::MaxControllers; ++i)
+   {
+      for(U32 j=0; j<2; ++j)
+      {
+         delete mDataBuffer[i][j];
+         mDataBuffer[i][j] = NULL;
+         mPrevData[i] = NULL;
+      }
+   }
+}
+
+void RazerHydraDevice::staticInit()
+{
+   Con::addVariable("pref::RazerHydra::EnableDevice", TypeBool, &smEnableDevice, 
+      "@brief If true, the Razer Hydra device will be enabled, if present.\n\n"
+	   "@ingroup Game");
+
+   Con::addVariable("RazerHydra::ProcessWhenDocked", TypeBool, &smProcessWhenDocked, 
+      "@brief If true, events will still be sent when a controller is docked.\n\n"
+	   "@ingroup Game");
+
+   Con::addVariable("RazerHydra::SeparatePositionEvents", TypeBool, &smSeparatePositionEvents, 
+      "@brief If true, separate position events will be sent for each component.\n\n"
+	   "@ingroup Game");
+   Con::addVariable("RazerHydra::CombinedPositionEvents", TypeBool, &smCombinedPositionEvents, 
+      "@brief If true, one position event will be sent that includes one component per argument.\n\n"
+	   "@ingroup Game");
+
+   Con::addVariable("RazerHydra::RotationAsAxisEvents", TypeBool, &smRotationAsAxisEvents, 
+      "@brief If true, broadcast controller rotation as axis events.\n\n"
+	   "@ingroup Game");
+   Con::addVariable("RazerHydra::MaximumAxisAngle", TypeF32, &smMaximumAxisAngle, 
+      "@brief The maximum controller angle when used as an axis event as measured from a vector pointing straight up (in degrees).\n\n"
+      "Shoud range from 0 to 90 degrees.\n\n"
+	   "@ingroup Game");
+
+   Con::addVariable("RazerHydra::GenerateWholeFrameEvents", TypeBool, &smGenerateWholeFrameEvents, 
+      "@brief Indicates that a whole frame event should be generated and frames should be buffered.\n\n"
+	   "@ingroup Game");
+}
+
+void RazerHydraDevice::buildCodeTable()
+{
+   // Obtain all of the device codes
+   for(U32 i=0; i<RazerHydraConstants::MaxControllers; ++i)
+   {
+      RH_DOCKED[i] = INPUTMGR->getNextDeviceCode();
+
+      RH_POSX[i] = INPUTMGR->getNextDeviceCode();
+      RH_POSY[i] = INPUTMGR->getNextDeviceCode();
+      RH_POSZ[i] = INPUTMGR->getNextDeviceCode();
+
+      RH_POS[i] = INPUTMGR->getNextDeviceCode();
+
+      RH_ROT[i] = INPUTMGR->getNextDeviceCode();
+
+      RH_ROTAXISX[i] = INPUTMGR->getNextDeviceCode();
+      RH_ROTAXISY[i] = INPUTMGR->getNextDeviceCode();
+
+      RH_THUMBX[i] = INPUTMGR->getNextDeviceCode();
+      RH_THUMBY[i] = INPUTMGR->getNextDeviceCode();
+
+      RH_TRIGGER[i] = INPUTMGR->getNextDeviceCode();
+
+      RH_SHOULDER[i] = INPUTMGR->getNextDeviceCode();
+      RH_THUMB[i] = INPUTMGR->getNextDeviceCode();
+      RH_START[i] = INPUTMGR->getNextDeviceCode();
+      RH_1[i] = INPUTMGR->getNextDeviceCode();
+      RH_2[i] = INPUTMGR->getNextDeviceCode();
+      RH_3[i] = INPUTMGR->getNextDeviceCode();
+      RH_4[i] = INPUTMGR->getNextDeviceCode();
+   }
+
+   RH_FRAME = INPUTMGR->getNextDeviceCode();
+
+   // Build out the virtual map
+   char buffer[64];
+   for(U32 i=0; i<RazerHydraConstants::MaxControllers; ++i)
+   {
+      dSprintf(buffer, 64, "rh_docked%d", i);
+      INPUTMGR->addVirtualMap( buffer, SI_BUTTON, RH_DOCKED[i] );
+
+      dSprintf(buffer, 64, "rh_posx%d", i);
+      INPUTMGR->addVirtualMap( buffer, SI_FLOAT, RH_POSX[i] );
+      dSprintf(buffer, 64, "rh_posy%d", i);
+      INPUTMGR->addVirtualMap( buffer, SI_FLOAT, RH_POSY[i] );
+      dSprintf(buffer, 64, "rh_posz%d", i);
+      INPUTMGR->addVirtualMap( buffer, SI_FLOAT, RH_POSZ[i] );
+
+      dSprintf(buffer, 64, "rh_pos%d", i);
+      INPUTMGR->addVirtualMap( buffer, SI_POS, RH_POS[i] );
+
+      dSprintf(buffer, 64, "rh_rot%d", i);
+      INPUTMGR->addVirtualMap( buffer, SI_ROT, RH_ROT[i] );
+
+      dSprintf(buffer, 64, "rh_rotaxisx%d", i);
+      INPUTMGR->addVirtualMap( buffer, SI_AXIS, RH_ROTAXISX[i] );
+      dSprintf(buffer, 64, "rh_rotaxisy%d", i);
+      INPUTMGR->addVirtualMap( buffer, SI_AXIS, RH_ROTAXISY[i] );
+
+      dSprintf(buffer, 64, "rh_thumbx%d", i);
+      INPUTMGR->addVirtualMap( buffer, SI_AXIS, RH_THUMBX[i] );
+      dSprintf(buffer, 64, "rh_thumby%d", i);
+      INPUTMGR->addVirtualMap( buffer, SI_AXIS, RH_THUMBY[i] );
+
+      dSprintf(buffer, 64, "rh_trigger%d", i);
+      INPUTMGR->addVirtualMap( buffer, SI_AXIS, RH_TRIGGER[i] );
+
+      dSprintf(buffer, 64, "rh_shoulder%d", i);
+      INPUTMGR->addVirtualMap( buffer, SI_BUTTON, RH_SHOULDER[i] );
+
+      dSprintf(buffer, 64, "rh_thumb%d", i);
+      INPUTMGR->addVirtualMap( buffer, SI_BUTTON, RH_THUMB[i] );
+
+      dSprintf(buffer, 64, "rh_start%d", i);
+      INPUTMGR->addVirtualMap( buffer, SI_BUTTON, RH_START[i] );
+
+      dSprintf(buffer, 64, "rh_1button%d", i);
+      INPUTMGR->addVirtualMap( buffer, SI_BUTTON, RH_1[i] );
+      dSprintf(buffer, 64, "rh_2button%d", i);
+      INPUTMGR->addVirtualMap( buffer, SI_BUTTON, RH_2[i] );
+      dSprintf(buffer, 64, "rh_3button%d", i);
+      INPUTMGR->addVirtualMap( buffer, SI_BUTTON, RH_3[i] );
+      dSprintf(buffer, 64, "rh_4button%d", i);
+      INPUTMGR->addVirtualMap( buffer, SI_BUTTON, RH_4[i] );
+   }
+
+   AddInputVirtualMap(  rh_frame,      SI_INT,     RH_FRAME );
+}
+
+bool RazerHydraDevice::enable()
+{
+   // Start off with disabling the device if it is already enabled
+   disable();
+
+   // Dynamically load the Razer Hydra library and set up function pointers
+#ifdef LOG_INPUT
+   Input::log( "Enabling Razer Hydra...\n" );
+#endif
+
+   const char* dllName;
+#ifdef TORQUE_OS_WIN32
+   #ifdef TORQUE_DEBUG
+      dllName = "sixensed.dll";
+   #else
+      dllName = "sixense.dll";
+   #endif
+#else
+   #ifdef LOG_INPUT
+      Input::log( "...platform not supported for Razer Hydra\n" );
+   #endif
+      return;
+#endif
+
+   mRazerHydraLib = OsLoadLibrary( dllName );
+   if(mRazerHydraLib)
+   {
+#ifdef LOG_INPUT
+      Input::log( "Razer Hydra library loaded.\n" );
+#endif
+      Con::printf("Razer Hydra Init:");
+
+      // Obtain library function pointers
+      mfnSixenseInit = (FN_SixenseInit) mRazerHydraLib->bind( "sixenseInit" );
+      mfnSixenseExit = (FN_SixenseExit) mRazerHydraLib->bind( "sixenseExit" );
+
+      mfnSixenseGetMaxBases = (FN_SixenseGetMaxBases) mRazerHydraLib->bind( "sixenseGetMaxBases" );
+      mfnSixenseSetActiveBase = (FN_SixenseSetActiveBase) mRazerHydraLib->bind( "sixenseSetActiveBase" );
+      mfnSixenseIsBaseConnected = (FN_SixenseIsBaseConnected) mRazerHydraLib->bind( "sixenseIsBaseConnected" );
+
+      mfnSixenseGetMaxControllers = (FN_SixenseGetMaxControllers) mRazerHydraLib->bind( "sixenseGetMaxControllers" );
+      mfnSixenseIsControllerEnabled = (FN_SixenseIsControllerEnabled) mRazerHydraLib->bind( "sixenseIsControllerEnabled" );
+      mfnSixenseGetNumActiveControllers = (FN_SixenseGetNumActiveControllers) mRazerHydraLib->bind( "sixenseGetNumActiveControllers" );
+
+      mfnSixenseGetHistorySize = (FN_SixenseGetHistorySize) mRazerHydraLib->bind( "sixenseGetHistorySize" );
+
+      mfnSixenseGetData = (FN_SixenseGetData) mRazerHydraLib->bind( "sixenseGetData" );
+      mfnSixenseGetAllData = (FN_SixenseGetAllData) mRazerHydraLib->bind( "sixenseGetAllData" );
+      mfnSixenseGetNewestData = (FN_SixenseGetNewestData) mRazerHydraLib->bind( "sixenseGetNewestData" );
+      mfnSixenseGetAllNewestData = (FN_SixenseGetAllNewestData) mRazerHydraLib->bind( "sixenseGetAllNewestData" );
+
+      mfnSixenseSetHemisphereTrackingMode = (FN_SixenseSetHemisphereTrackingMode) mRazerHydraLib->bind( "sixenseSetHemisphereTrackingMode" );
+      mfnSixenseGetHemisphereTrackingMode = (FN_SixenseGetHemisphereTrackingMode) mRazerHydraLib->bind( "sixenseGetHemisphereTrackingMode" );
+
+      mfnSixenseAutoEnableHemisphereTracking = (FN_SixenseAutoEnableHemisphereTracking) mRazerHydraLib->bind( "sixenseAutoEnableHemisphereTracking" );
+
+      mfnSixenseSetHighPriorityBindingEnabled = (FN_SixenseSetHighPriorityBindingEnabled) mRazerHydraLib->bind( "sixenseSetHighPriorityBindingEnabled" );
+      mfnSixenseGetHighPriorityBindingEnabled = (FN_SixenseGetHighPriorityBindingEnabled) mRazerHydraLib->bind( "sixenseGetHighPriorityBindingEnabled" );
+
+      mfnSixenseTriggerVibration = (FN_SixenseTriggerVibration) mRazerHydraLib->bind( "sixenseTriggerVibration" );
+
+      mfnSixenseSetFilterEnabled = (FN_SixenseSetFilterEnabled) mRazerHydraLib->bind( "sixenseSetFilterEnabled" );
+      mfnSixenseGetFilterEnabled = (FN_SixenseGetFilterEnabled) mRazerHydraLib->bind( "sixenseGetFilterEnabled" );
+
+      mfnSixenseSetFilterParams = (FN_SixenseSetFilterParams) mRazerHydraLib->bind( "sixenseSetFilterParams" );
+      mfnSixenseGetFilterParams = (FN_SixenseGetFilterParams) mRazerHydraLib->bind( "sixenseGetFilterParams" );
+
+      mfnSixenseSetBaseColor = (FN_SixenseSetBaseColor) mRazerHydraLib->bind( "sixenseSetBaseColor" );
+      mfnSixenseGetBaseColor = (FN_SixenseGetBaseColor) mRazerHydraLib->bind( "sixenseGetBaseColor" );
+
+      // Init the sixense library
+      S32 result = mfnSixenseInit();
+      if(result == SIXENSE_FAILURE)
+      {
+         // Problem with starting the library
+         Con::printf("   Sixense library startup failure");
+         mRazerHydraLib = NULL;
+
+         mEnabled = false;
+         mActive = false;
+
+         return false;
+      }
+
+      // Retrieve some information about the Hydra
+      mMaximumBases = mfnSixenseGetMaxBases();
+      Con::printf("   Max bases: %d", mMaximumBases);
+      mMaximumControllers = mfnSixenseGetMaxControllers();
+      Con::printf("   Max controllers: %d", mMaximumControllers);
+
+      mEnabled = true;
+
+      if(checkControllers())
+      {
+         Con::printf("   Active controllers: %d", mNumberActiveControllers);
+         mActive = true;
+      }
+      else
+      {
+         Con::printf("   Controllers not yet found.  Starting to poll.");
+         mLastActiveCheck = Platform::getRealMilliseconds();
+         mActive = false;
+      }
+
+      Con::printf("");
+
+      return true;
+   }
+   else
+   {
+#ifdef LOG_INPUT
+      Input::log( "Razer Hydra library was not found.\n" );
+#endif
+      Con::errorf("Razer Hydra library was not found.");
+
+      mEnabled = false;
+      mActive = false;
+   }
+
+   return false;
+}
+
+void RazerHydraDevice::disable()
+{
+   if(mRazerHydraLib)
+   {
+      // Shutdown the sixense library
+      mfnSixenseExit();
+
+      mRazerHydraLib = NULL;
+   }
+
+   mEnabled = false;
+}
+
+bool RazerHydraDevice::process()
+{
+   if(!mEnabled)
+      return false;
+
+   //Con::printf("RazerHydraDevice::process()");
+
+   if(!mActive)
+   {
+      // Only perform a check on a periodic basis
+      S32 time = Platform::getRealMilliseconds();
+      if((time - mLastActiveCheck) < RazerHydraConstants::HydraActiveCheckFreq)
+         return false;
+
+      mLastActiveCheck = time;
+
+      if(checkControllers())
+      {
+         Con::printf("Razer Hydra now has %d active controllers", mNumberActiveControllers);
+         mActive = true;
+      }
+      else
+      {
+         return false;
+      }
+   }
+   else if(!checkControllers())
+   {
+      // We no longer have active controllers
+      Con::printf("Razer Hydra now has NO active controllers");
+      mLastActiveCheck = Platform::getRealMilliseconds();
+      mActive = false;
+      return false;
+   }
+
+   //Build the maximum axis angle to be passed into the RazerHyrdaControllerData::setData()
+   F32 maxAxisRadius = mSin(mDegToRad(smMaximumAxisAngle));
+
+   // Get the controller data
+   mfnSixenseSetActiveBase(RazerHydraConstants::DefaultHydraBase);
+   sixenseAllControllerData acd;
+   mfnSixenseGetAllNewestData(&acd);
+
+   // Store the current data from each controller and compare with previous data
+   U32 diff[RazerHydraConstants::MaxControllers];
+   U32 metaDiff[RazerHydraConstants::MaxControllers];
+   RazerHyrdaControllerData* currentBuffer[RazerHydraConstants::MaxControllers];
+   for(U32 i=0; i<RazerHydraConstants::MaxControllers; ++i)
+   {
+      currentBuffer[i] = (mPrevData[i] == mDataBuffer[i][0]) ? mDataBuffer[i][1] : mDataBuffer[i][0];
+      currentBuffer[i]->setData(acd.controllers[i], maxAxisRadius);
+      diff[i] = mPrevData[i]->compare(currentBuffer[i]);
+      metaDiff[i] = mPrevData[i]->compareMeta(currentBuffer[i]);
+   }
+
+   // Update the previous data pointers.  We do this here in case someone calls our
+   // console functions during one of the input events below.
+   mPrevData[0] = currentBuffer[0];
+   mPrevData[1] = currentBuffer[1];
+
+   // Process each controller's meta data.
+   for(U32 i=0; i<RazerHydraConstants::MaxControllers; ++i)
+   {
+      // Docked
+      if(metaDiff[i] != RazerHyrdaControllerData::METADIFF_NONE)
+      {
+         INPUTMGR->buildInputEvent(mDeviceType, RazerHydraConstants::DefaultHydraBase, SI_BUTTON, RH_DOCKED[i], currentBuffer[i]->mIsDocked ? SI_MAKE : SI_BREAK, currentBuffer[i]->mIsDocked ? 1.0f : 0.0f);
+      }
+
+      // Position, rotation and buttons
+      if(diff[i] != RazerHyrdaControllerData::DIFF_NONE && (!currentBuffer[i]->mIsDocked || smProcessWhenDocked && currentBuffer[i]->mIsDocked))
+      {
+         // Position
+         if(smSeparatePositionEvents)
+         {
+            if(diff[i] & RazerHyrdaControllerData::DIFF_POSX)
+               INPUTMGR->buildInputEvent(mDeviceType, RazerHydraConstants::DefaultHydraBase, SI_FLOAT, RH_POSX[i], SI_MOVE, currentBuffer[i]->mPos[0]);
+            if(diff[i] & RazerHyrdaControllerData::DIFF_POSY)
+               INPUTMGR->buildInputEvent(mDeviceType, RazerHydraConstants::DefaultHydraBase, SI_FLOAT, RH_POSY[i], SI_MOVE, currentBuffer[i]->mPos[1]);
+            if(diff[i] & RazerHyrdaControllerData::DIFF_POSZ)
+               INPUTMGR->buildInputEvent(mDeviceType, RazerHydraConstants::DefaultHydraBase, SI_FLOAT, RH_POSZ[i], SI_MOVE, currentBuffer[i]->mPos[2]);
+         }
+         if(smCombinedPositionEvents)
+         {
+            if(diff[i] & RazerHyrdaControllerData::DIFF_POSX || diff[i] & RazerHyrdaControllerData::DIFF_POSY || diff[i] & RazerHyrdaControllerData::DIFF_POSZ)
+            {
+               INPUTMGR->buildInputEvent(mDeviceType, RazerHydraConstants::DefaultHydraBase, SI_POS, RH_POS[i], SI_MOVE, currentBuffer[i]->mPosPoint);
+            }
+         }
+
+         // Rotation
+         if(diff[i] & RazerHyrdaControllerData::DIFF_ROT)
+            INPUTMGR->buildInputEvent(mDeviceType, RazerHydraConstants::DefaultHydraBase, SI_ROT, RH_ROT[i], SI_MOVE, currentBuffer[i]->mRotQuat);
+
+         // Thumb stick
+         if(diff[i] & RazerHyrdaControllerData::DIFF_AXISX)
+            INPUTMGR->buildInputEvent(mDeviceType, RazerHydraConstants::DefaultHydraBase, SI_AXIS, RH_THUMBX[i], SI_MOVE, currentBuffer[i]->mThumbStick[0]);
+         if(diff[i] & RazerHyrdaControllerData::DIFF_AXISY)
+            INPUTMGR->buildInputEvent(mDeviceType, RazerHydraConstants::DefaultHydraBase, SI_AXIS, RH_THUMBY[i], SI_MOVE, currentBuffer[i]->mThumbStick[1]);
+
+         // Trigger
+         if(diff[i] & RazerHyrdaControllerData::DIFF_TRIGGER)
+            INPUTMGR->buildInputEvent(mDeviceType, RazerHydraConstants::DefaultHydraBase, SI_AXIS, RH_TRIGGER[i], SI_MOVE, currentBuffer[i]->mTrigger);
+
+         // Shoulder button
+         if(diff[i] & RazerHyrdaControllerData::DIFF_BUTTON_SHOULDER)
+            INPUTMGR->buildInputEvent(mDeviceType, RazerHydraConstants::DefaultHydraBase, SI_BUTTON, RH_SHOULDER[i], currentBuffer[i]->mShoulder ? SI_MAKE : SI_BREAK, currentBuffer[i]->mShoulder ? 1.0f : 0.0f);
+
+         // Thumb button
+         if(diff[i] & RazerHyrdaControllerData::DIFF_BUTTON_THUMB)
+            INPUTMGR->buildInputEvent(mDeviceType, RazerHydraConstants::DefaultHydraBase, SI_BUTTON, RH_THUMB[i], currentBuffer[i]->mThumb ? SI_MAKE : SI_BREAK, currentBuffer[i]->mThumb ? 1.0f : 0.0f);
+
+         // Start button
+         if(diff[i] & RazerHyrdaControllerData::DIFF_BUTTON_START)
+            INPUTMGR->buildInputEvent(mDeviceType, RazerHydraConstants::DefaultHydraBase, SI_BUTTON, RH_START[i], currentBuffer[i]->mStart ? SI_MAKE : SI_BREAK, currentBuffer[i]->mStart ? 1.0f : 0.0f);
+
+         // Button 1
+         if(diff[i] & RazerHyrdaControllerData::DIFF_BUTTON1)
+            INPUTMGR->buildInputEvent(mDeviceType, RazerHydraConstants::DefaultHydraBase, SI_BUTTON, RH_1[i], currentBuffer[i]->mButton1 ? SI_MAKE : SI_BREAK, currentBuffer[i]->mButton1 ? 1.0f : 0.0f);
+
+         // Button 2
+         if(diff[i] & RazerHyrdaControllerData::DIFF_BUTTON2)
+            INPUTMGR->buildInputEvent(mDeviceType, RazerHydraConstants::DefaultHydraBase, SI_BUTTON, RH_2[i], currentBuffer[i]->mButton2 ? SI_MAKE : SI_BREAK, currentBuffer[i]->mButton2 ? 1.0f : 0.0f);
+
+         // Button 3
+         if(diff[i] & RazerHyrdaControllerData::DIFF_BUTTON3)
+            INPUTMGR->buildInputEvent(mDeviceType, RazerHydraConstants::DefaultHydraBase, SI_BUTTON, RH_3[i], currentBuffer[i]->mButton3 ? SI_MAKE : SI_BREAK, currentBuffer[i]->mButton3 ? 1.0f : 0.0f);
+
+         // Button 4
+         if(diff[i] & RazerHyrdaControllerData::DIFF_BUTTON4)
+            INPUTMGR->buildInputEvent(mDeviceType, RazerHydraConstants::DefaultHydraBase, SI_BUTTON, RH_4[i], currentBuffer[i]->mButton4 ? SI_MAKE : SI_BREAK, currentBuffer[i]->mButton4 ? 1.0f : 0.0f);
+      }
+
+      // Left rotation as axis.  Done here as we still need to send events even when docked.
+      if(smRotationAsAxisEvents && diff[i] & RazerHyrdaControllerData::DIFF_ROTAXIS)
+      {
+         if(diff[i] & RazerHyrdaControllerData::DIFF_ROTAXISX)
+            INPUTMGR->buildInputEvent(mDeviceType, RazerHydraConstants::DefaultHydraBase, SI_AXIS, RH_ROTAXISX[i], SI_MOVE, currentBuffer[i]->mRotAxis.x);
+         if(diff[i] & RazerHyrdaControllerData::DIFF_ROTAXISY)
+            INPUTMGR->buildInputEvent(mDeviceType, RazerHydraConstants::DefaultHydraBase, SI_AXIS, RH_ROTAXISY[i], SI_MOVE, currentBuffer[i]->mRotAxis.y);
+      }
+   }
+
+   // Send out whole frame event, but only if the special frame group is defined
+   if(smGenerateWholeFrameEvents && RazerHydraFrameStore::isFrameGroupDefined())
+   {
+      S32 id = RAZERHYDRAFS->generateNewFrame(acd, maxAxisRadius);
+      if(id != 0)
+      {
+         INPUTMGR->buildInputEvent(mDeviceType, RazerHydraConstants::DefaultHydraBase, SI_INT, RH_FRAME, SI_VALUE, id);
+      }
+   }
+
+   return true;
+}
+
+bool RazerHydraDevice::checkControllers()
+{
+   if(!mEnabled)
+      return false;
+
+   bool hasBase = (mfnSixenseIsBaseConnected(RazerHydraConstants::DefaultHydraBase) == 1);
+   if(!hasBase)
+   {
+      mNumberActiveControllers = 0;
+      return false;
+   }
+
+   mfnSixenseSetActiveBase(RazerHydraConstants::DefaultHydraBase);
+   mNumberActiveControllers = mfnSixenseGetNumActiveControllers();
+   if(mNumberActiveControllers < 1)
+      return false;
+
+   return true;
+}
+
+bool RazerHydraDevice::isControllerDocked(U32 controller)
+{
+   if(!mEnabled || !mActive)
+      return true;
+
+   if(controller >= RazerHydraConstants::MaxControllers)
+      return true;
+
+   // Results are based on the last retrieved data from the device
+   return mPrevData[controller]->mIsDocked || !mPrevData[controller]->mDataSet;
+}
+
+const Point3F& RazerHydraDevice::getControllerPosition(U32 controller)
+{
+   if(!mEnabled || !mActive)
+      return Point3F::Zero;
+
+   if(controller >= RazerHydraConstants::MaxControllers)
+      return Point3F::Zero;
+
+   // Results are based on the last retrieved data from the device
+   return mPrevData[controller]->mPosPoint;
+}
+
+const QuatF& RazerHydraDevice::getControllerRotation(U32 controller)
+{
+   if(!mEnabled || !mActive)
+      return QuatF::Identity;
+
+   if(controller >= RazerHydraConstants::MaxControllers)
+      return QuatF::Identity;
+
+   // Results are based on the last retrieved data from the device
+   return mPrevData[controller]->mRotQuat;
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineFunction(isRazerHydraActive, bool, (),,
+   "@brief Used to determine if the Razer Hydra input device active\n\n"
+
+   "The Razer Hydra input device is considered active when the support library has been "
+   "loaded and the controller has been found.\n\n"
+
+   "@return True if the Razer Hydra input device is active.\n"
+
+   "@ingroup Game")
+{
+   if(!ManagedSingleton<RazerHydraDevice>::instanceOrNull())
+   {
+      return false;
+   }
+
+   return RAZERHYDRADEV->isActive();
+}
+
+DefineEngineFunction(isRazerHydraControllerDocked, bool, (S32 controller),,
+   "@brief Used to determine if the given Razer Hydra controller is docked\n\n"
+
+   "@param controller Controller number to check.\n"
+
+   "@return True if the given Razer Hydra controller is docked.  Also returns true if "
+   "the input device is not found or active.\n"
+
+   "@ingroup Game")
+{
+   if(!ManagedSingleton<RazerHydraDevice>::instanceOrNull())
+   {
+      return true;
+   }
+
+   return RAZERHYDRADEV->isControllerDocked(controller);
+}
+
+DefineEngineFunction(getRazerHydraControllerPos, Point3F, (S32 controller),,
+   "@brief Get the given Razer Hydra controller's last position\n\n"
+
+   "@param controller Controller number to check.\n"
+
+   "@return A Point3F containing the last known position.\n"
+
+   "@ingroup Game")
+{
+   if(!ManagedSingleton<RazerHydraDevice>::instanceOrNull())
+   {
+      return Point3F::Zero;
+   }
+
+   return RAZERHYDRADEV->getControllerPosition(controller);
+}
+
+DefineEngineFunction(getRazerHydraControllerRot, AngAxisF, (S32 controller),,
+   "@brief Get the given Razer Hydra controller's last rotation\n\n"
+
+   "@param controller Controller number to check.\n"
+
+   "@return A AngAxisF containing the last known rotation.\n"
+
+   "@ingroup Game")
+{
+   AngAxisF aa(Point3F(0, 0, 1), 0);
+
+   if(!ManagedSingleton<RazerHydraDevice>::instanceOrNull())
+   {
+      return aa;
+   }
+
+   const QuatF& qa = RAZERHYDRADEV->getControllerRotation(controller);
+   aa.set(qa);
+   aa.axis.normalize();
+
+   return aa;
+}
+
+DefineEngineFunction(getRazerHydraControllerTransform, TransformF, (S32 controller),,
+   "@brief Get the given Razer Hydra controller's last transform\n\n"
+
+   "@param controller Controller number to check.\n"
+
+   "@return A TransformF containing the last known transform.\n"
+
+   "@ingroup Game")
+{
+   TransformF trans;
+
+   if(!ManagedSingleton<RazerHydraDevice>::instanceOrNull())
+   {
+      return trans;
+   }
+
+   const Point3F& pos = RAZERHYDRADEV->getControllerPosition(controller);
+   const QuatF& qa = RAZERHYDRADEV->getControllerRotation(controller);
+
+   AngAxisF aa(qa);
+   aa.axis.normalize();
+   trans.set(pos, aa);
+
+   return trans;
+}

+ 225 - 0
Engine/source/platform/input/razerHydra/razerHydraDevice.h

@@ -0,0 +1,225 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2012 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#ifndef _RAZERHYDRADEVICE_H_
+#define _RAZERHYDRADEVICE_H_
+
+#include "platform/input/razerHydra/razerHydraConstants.h"
+#include "platform/platformDlibrary.h"
+#include "platform/input/IInputDevice.h"
+#include "platform/input/event.h"
+#include "core/util/tSingleton.h"
+#include "math/mQuat.h"
+#include "sixense.h"
+
+#define HYDRA_ACTIVE_CHECK_FREQ 1000
+
+#define FN_HYDRA __cdecl
+
+// Library function typedefs
+typedef int (FN_HYDRA* FN_SixenseInit)();
+typedef int (FN_HYDRA* FN_SixenseExit)();
+
+typedef int (FN_HYDRA* FN_SixenseGetMaxBases)();
+typedef int (FN_HYDRA* FN_SixenseSetActiveBase)(int base_num);
+typedef int (FN_HYDRA* FN_SixenseIsBaseConnected)(int base_num);
+
+typedef int (FN_HYDRA* FN_SixenseGetMaxControllers)();
+typedef int (FN_HYDRA* FN_SixenseIsControllerEnabled)(int which);
+typedef int (FN_HYDRA* FN_SixenseGetNumActiveControllers)();
+
+typedef int (FN_HYDRA* FN_SixenseGetHistorySize)();
+
+typedef int (FN_HYDRA* FN_SixenseGetData)(int which, int index_back, sixenseControllerData *);
+typedef int (FN_HYDRA* FN_SixenseGetAllData)(int index_back, sixenseAllControllerData *);
+typedef int (FN_HYDRA* FN_SixenseGetNewestData)(int which, sixenseControllerData *);
+typedef int (FN_HYDRA* FN_SixenseGetAllNewestData)(sixenseAllControllerData *);
+
+typedef int (FN_HYDRA* FN_SixenseSetHemisphereTrackingMode)(int which_controller, int state);
+typedef int (FN_HYDRA* FN_SixenseGetHemisphereTrackingMode)(int which_controller, int *state);
+
+typedef int (FN_HYDRA* FN_SixenseAutoEnableHemisphereTracking)(int which_controller);
+
+typedef int (FN_HYDRA* FN_SixenseSetHighPriorityBindingEnabled)(int on_or_off);
+typedef int (FN_HYDRA* FN_SixenseGetHighPriorityBindingEnabled)(int *on_or_off);
+
+typedef int (FN_HYDRA* FN_SixenseTriggerVibration)(int controller_id, int duration_100ms, int pattern_id);
+
+typedef int (FN_HYDRA* FN_SixenseSetFilterEnabled)(int on_or_off);
+typedef int (FN_HYDRA* FN_SixenseGetFilterEnabled)(int *on_or_off);
+
+typedef int (FN_HYDRA* FN_SixenseSetFilterParams)(float near_range, float near_val, float far_range, float far_val);
+typedef int (FN_HYDRA* FN_SixenseGetFilterParams)(float *near_range, float *near_val, float *far_range, float *far_val);
+
+typedef int (FN_HYDRA* FN_SixenseSetBaseColor)(unsigned char red, unsigned char green, unsigned char blue);
+typedef int (FN_HYDRA* FN_SixenseGetBaseColor)(unsigned char *red, unsigned char *green, unsigned char *blue);
+
+struct RazerHyrdaControllerData;
+
+class RazerHydraDevice : public IInputDevice
+{
+public:
+   static bool smEnableDevice;
+
+   // Should events be sent when a controller is docked
+   static bool smProcessWhenDocked;
+
+   // The type of position events to broadcast
+   static bool smSeparatePositionEvents;
+   static bool smCombinedPositionEvents;
+
+   // Broadcast controller rotation as axis
+   static bool smRotationAsAxisEvents;
+
+   // The maximum controller angle when used as an axis event
+   // as measured from a vector pointing straight up (in degrees)
+   static F32 smMaximumAxisAngle;
+
+   // Indicates that a whole frame event should be generated and frames
+   // should be buffered.
+   static bool smGenerateWholeFrameEvents;
+
+   // Controller Action Codes
+   static U32 RH_DOCKED[RazerHydraConstants::MaxControllers];     // SI_BUTTON
+
+   static U32 RH_POSX[RazerHydraConstants::MaxControllers];       // SI_FLOAT
+   static U32 RH_POSY[RazerHydraConstants::MaxControllers];
+   static U32 RH_POSZ[RazerHydraConstants::MaxControllers];
+
+   static U32 RH_POS[RazerHydraConstants::MaxControllers];        // SI_POS
+
+   static U32 RH_ROT[RazerHydraConstants::MaxControllers];        // SI_ROT
+
+   static U32 RH_ROTAXISX[RazerHydraConstants::MaxControllers];   // SI_AXIS
+   static U32 RH_ROTAXISY[RazerHydraConstants::MaxControllers];
+
+   static U32 RH_THUMBX[RazerHydraConstants::MaxControllers];     // SI_AXIS
+   static U32 RH_THUMBY[RazerHydraConstants::MaxControllers];
+
+   static U32 RH_TRIGGER[RazerHydraConstants::MaxControllers];    // SI_AXIS
+
+   static U32 RH_SHOULDER[RazerHydraConstants::MaxControllers];   // SI_BUTTON
+   static U32 RH_THUMB[RazerHydraConstants::MaxControllers];      // SI_BUTTON
+   static U32 RH_START[RazerHydraConstants::MaxControllers];      // SI_BUTTON
+   static U32 RH_1[RazerHydraConstants::MaxControllers];          // SI_BUTTON
+   static U32 RH_2[RazerHydraConstants::MaxControllers];          // SI_BUTTON
+   static U32 RH_3[RazerHydraConstants::MaxControllers];          // SI_BUTTON
+   static U32 RH_4[RazerHydraConstants::MaxControllers];          // SI_BUTTON
+
+   // Whole frame
+   static U32 RH_FRAME;       // SI_INT
+
+public:
+   RazerHydraDevice();
+   ~RazerHydraDevice();
+
+   static void staticInit();
+
+   bool enable();
+
+   void disable();
+
+   bool process();
+
+   bool isActive() { return mActive; }
+
+   bool isControllerDocked(U32 controller);
+
+   const Point3F& getControllerPosition(U32 controller);
+
+   const QuatF& getControllerRotation(U32 controller);
+
+protected:
+   DLibraryRef mRazerHydraLib;
+
+   FN_SixenseInit                      mfnSixenseInit;
+   FN_SixenseExit                      mfnSixenseExit;
+
+   FN_SixenseGetMaxBases               mfnSixenseGetMaxBases;
+   FN_SixenseSetActiveBase             mfnSixenseSetActiveBase;
+   FN_SixenseIsBaseConnected           mfnSixenseIsBaseConnected;
+
+   FN_SixenseGetMaxControllers         mfnSixenseGetMaxControllers;
+   FN_SixenseIsControllerEnabled       mfnSixenseIsControllerEnabled;
+   FN_SixenseGetNumActiveControllers   mfnSixenseGetNumActiveControllers;
+
+   FN_SixenseGetHistorySize            mfnSixenseGetHistorySize;
+
+   FN_SixenseGetData                   mfnSixenseGetData;
+   FN_SixenseGetAllData                mfnSixenseGetAllData;
+   FN_SixenseGetNewestData             mfnSixenseGetNewestData;
+   FN_SixenseGetAllNewestData          mfnSixenseGetAllNewestData;
+
+   FN_SixenseSetHemisphereTrackingMode mfnSixenseSetHemisphereTrackingMode;
+   FN_SixenseGetHemisphereTrackingMode mfnSixenseGetHemisphereTrackingMode;
+
+   FN_SixenseAutoEnableHemisphereTracking mfnSixenseAutoEnableHemisphereTracking;
+
+   FN_SixenseSetHighPriorityBindingEnabled   mfnSixenseSetHighPriorityBindingEnabled;
+   FN_SixenseGetHighPriorityBindingEnabled   mfnSixenseGetHighPriorityBindingEnabled;
+
+   FN_SixenseTriggerVibration          mfnSixenseTriggerVibration;
+
+   FN_SixenseSetFilterEnabled          mfnSixenseSetFilterEnabled;
+   FN_SixenseGetFilterEnabled          mfnSixenseGetFilterEnabled;
+
+   FN_SixenseSetFilterParams           mfnSixenseSetFilterParams;
+   FN_SixenseGetFilterParams           mfnSixenseGetFilterParams;
+
+   FN_SixenseSetBaseColor              mfnSixenseSetBaseColor;
+   FN_SixenseGetBaseColor              mfnSixenseGetBaseColor;
+
+   S32 mMaximumBases;
+   S32 mMaximumControllers;
+
+   S32 mNumberActiveControllers;
+
+   /// Is the Razer Hydra active (enabled means the library is loaded)
+   bool mActive;
+
+   /// When was the last check for an active Hydra
+   S32 mLastActiveCheck;
+
+   /// Buffers to store data for the controllers
+   RazerHyrdaControllerData*  mDataBuffer[RazerHydraConstants::MaxControllers][2];
+
+   /// Points to the buffers that holds the previously collected data
+   /// for each controller
+   RazerHyrdaControllerData*  mPrevData[RazerHydraConstants::MaxControllers];
+
+protected:
+   /// Build out the codes used for controller actions with the
+   /// Input Event Manager
+   void buildCodeTable();
+
+   /// Checks if there are active controllers
+   bool checkControllers();
+
+public:
+   // For ManagedSingleton.
+   static const char* getSingletonName() { return "RazerHydraDevice"; }   
+};
+
+/// Returns the RazerHydraDevice singleton.
+#define RAZERHYDRADEV ManagedSingleton<RazerHydraDevice>::instance()
+
+#endif   // _RAZERHYDRADEVICE_H_

+ 337 - 0
Engine/source/platform/input/razerHydra/razerHydraFrame.cpp

@@ -0,0 +1,337 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2012 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#include "platform/input/razerHydra/razerHydraFrame.h"
+#include "platform/input/razerHydra/razerHydraUtil.h"
+#include "console/engineAPI.h"
+#include "math/mAngAxis.h"
+#include "math/mTransform.h"
+
+U32 RazerHydraFrame::smNextInternalFrameId = 0;
+
+IMPLEMENT_CONOBJECT(RazerHydraFrame);
+
+RazerHydraFrame::RazerHydraFrame()
+{
+   clear();
+}
+
+RazerHydraFrame::~RazerHydraFrame()
+{
+   clear();
+
+   for(U32 i=0; i<RazerHydraConstants::MaxControllers; ++i)
+   {
+      mControllerData[i].mEnabled = false;
+   }
+}
+
+
+void RazerHydraFrame::initPersistFields()
+{
+   Parent::initPersistFields();
+}
+
+bool RazerHydraFrame::onAdd()
+{
+   if (!Parent::onAdd())
+      return false;
+
+   return true;
+}
+
+void RazerHydraFrame::onRemove()
+{
+   Parent::onRemove();
+}
+
+void RazerHydraFrame::clear()
+{
+   mFrameValid = false;
+}
+
+void RazerHydraFrame::copyFromFrame(const sixenseAllControllerData& frame, const F32& maxAxisRadius)
+{
+   clear();
+
+   // Calling this method automatically makes this a valid frame
+   mFrameValid = true;
+
+   mFrameInternalId = smNextInternalFrameId;
+   ++smNextInternalFrameId;
+   mFrameSimTime = Sim::getCurrentTime();
+   mFrameRealTime = Platform::getRealMilliseconds();
+
+   // Process the controllers
+   for(U32 i=0; i<RazerHydraConstants::MaxControllers; ++i)
+   {
+      const sixenseControllerData& controller = frame.controllers[i];
+      ControllerData& data = mControllerData[i];
+
+      // General controller data
+      data.mEnabled = controller.enabled;
+      data.mIsDocked = controller.is_docked;
+      data.mSequenceNum = controller.sequence_number;
+
+      // Controller position
+      RazerHydraUtil::convertPosition(controller.pos, data.mRawPos);
+      data.mPos.x = (S32)mFloor(data.mRawPos.x);
+      data.mPos.y = (S32)mFloor(data.mRawPos.y);
+      data.mPos.z = (S32)mFloor(data.mRawPos.z);
+
+      // Controller rotation
+      RazerHydraUtil::convertRotation(controller.rot_mat, data.mRot);
+      data.mRotQuat.set(data.mRot);
+
+      // Controller as axis rotation
+      RazerHydraUtil::calculateAxisRotation(data.mRot, maxAxisRadius, data.mRotAxis);
+
+      // Controller thumb stick
+      data.mThumbStick.x = controller.joystick_x;
+      data.mThumbStick.y = controller.joystick_y;
+
+      // Trigger
+      data.mTrigger = controller.trigger;
+
+      // Controller buttons
+      data.mShoulder = controller.buttons & SIXENSE_BUTTON_BUMPER;
+      data.mThumb = controller.buttons & SIXENSE_BUTTON_JOYSTICK;
+      data.mStart = controller.buttons & SIXENSE_BUTTON_START;
+      data.mButton1 = controller.buttons & SIXENSE_BUTTON_1;
+      data.mButton2 = controller.buttons & SIXENSE_BUTTON_2;
+      data.mButton3 = controller.buttons & SIXENSE_BUTTON_3;
+      data.mButton4 = controller.buttons & SIXENSE_BUTTON_4;
+   }
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod( RazerHydraFrame, isFrameValid, bool, ( ),,
+   "@brief Checks if this frame is valid.\n\n"
+   "@return True if the frame is valid.\n\n")
+{
+   return object->isFrameValid();
+}
+
+DefineEngineMethod( RazerHydraFrame, getFrameInternalId, S32, ( ),,
+   "@brief Provides the internal ID for this frame.\n\n"
+   "@return Internal ID of this frame.\n\n")
+{
+   return object->getFrameInternalId();
+}
+
+DefineEngineMethod( RazerHydraFrame, getFrameSimTime, S32, ( ),,
+   "@brief Get the sim time that this frame was generated.\n\n"
+   "@return Sim time of this frame in milliseconds.\n\n")
+{
+   return object->getFrameSimTime();
+}
+
+DefineEngineMethod( RazerHydraFrame, getFrameRealTime, S32, ( ),,
+   "@brief Get the real time that this frame was generated.\n\n"
+   "@return Real time of this frame in milliseconds.\n\n")
+{
+   return object->getFrameRealTime();
+}
+
+DefineEngineMethod( RazerHydraFrame, getControllerCount, S32, ( ),,
+   "@brief Get the number of controllers defined in this frame.\n\n"
+   "@return The number of defined controllers.\n\n")
+{
+   return RazerHydraConstants::MaxControllers;
+}
+
+DefineEngineMethod( RazerHydraFrame, getControllerEnabled, bool, ( S32 index ),,
+   "@brief Get the enabled state of the controller.\n\n"
+   "@param index The controller index to check.\n"
+   "@return True if the requested controller is enabled.\n\n")
+{
+   return object->getEnabled(index);
+}
+
+DefineEngineMethod( RazerHydraFrame, getControllerDocked, bool, ( S32 index ),,
+   "@brief Get the docked state of the controller.\n\n"
+   "@param index The controller index to check.\n"
+   "@return True if the requested controller is docked.\n\n")
+{
+   return object->getDocked(index);
+}
+
+DefineEngineMethod( RazerHydraFrame, getControllerSequenceNum, S32, ( S32 index ),,
+   "@brief Get the controller sequence number.\n\n"
+   "@param index The controller index to check.\n"
+   "@return The sequence number of the requested controller.\n\n")
+{
+   return object->getSequenceNum(index);
+}
+
+DefineEngineMethod( RazerHydraFrame, getControllerRawPos, Point3F, ( S32 index ),,
+   "@brief Get the raw position of the requested controller.\n\n"
+   "The raw position is the controller's floating point position converted to "
+   "Torque 3D coordinates (in millimeters).\n"
+   "@param index The controller index to check.\n"
+   "@return Raw position of the requested controller (in millimeters).\n\n")
+{
+   return object->getRawPos(index);
+}
+
+DefineEngineMethod( RazerHydraFrame, getControllerPos, Point3I, ( S32 index ),,
+   "@brief Get the position of the requested controller.\n\n"
+   "The position is the controller's integer position converted to "
+   "Torque 3D coordinates (in millimeters).\n"
+   "@param index The controller index to check.\n"
+   "@return Integer position of the requested controller (in millimeters).\n\n")
+{
+   return object->getPos(index);
+}
+
+DefineEngineMethod( RazerHydraFrame, getControllerRot, AngAxisF, ( S32 index ),,
+   "@brief Get the rotation of the requested controller.\n\n"
+   "The Razer Hydra controller rotation as converted into the Torque 3D"
+   "coordinate system.\n"
+   "@param index The controller index to check.\n"
+   "@return Rotation of the requested controller.\n\n")
+{
+   AngAxisF aa(object->getRot(index));
+   return aa;
+}
+
+DefineEngineMethod( RazerHydraFrame, getControllerRawTransform, TransformF, ( S32 index ),,
+   "@brief Get the raw transform of the requested controller.\n\n"
+   "@param index The controller index to check.\n"
+   "@return The raw position and rotation of the requested controller (in Torque 3D coordinates).\n\n")
+{
+   const Point3F& pos = object->getRawPos(index);
+   const QuatF& qa = object->getRotQuat(index);
+
+   AngAxisF aa(qa);
+   aa.axis.normalize();
+
+   TransformF trans(pos, aa);
+   return trans;
+}
+
+DefineEngineMethod( RazerHydraFrame, getControllerTransform, TransformF, ( S32 index ),,
+   "@brief Get the transform of the requested controller.\n\n"
+   "@param index The controller index to check.\n"
+   "@return The position and rotation of the requested controller (in Torque 3D coordinates).\n\n")
+{
+   const Point3I& pos = object->getPos(index);
+   const QuatF& qa = object->getRotQuat(index);
+
+   AngAxisF aa(qa);
+   aa.axis.normalize();
+
+   TransformF trans;
+   trans.mPosition = Point3F(pos.x, pos.y, pos.z);
+   trans.mOrientation = aa;
+
+   return trans;
+}
+
+DefineEngineMethod( RazerHydraFrame, getControllerRotAxis, Point2F, ( S32 index ),,
+   "@brief Get the axis rotation of the requested controller.\n\n"
+   "This is the axis rotation of the controller as if the controller were a gamepad thumb stick.  "
+   "Imagine a stick coming out the top of the controller and tilting the controller front, back, "
+   "left and right controls that stick.  The values returned along the x and y stick "
+   "axis are normalized from -1.0 to 1.0 with the maximum controller tilt angle for these "
+   "values as defined by $RazerHydra::MaximumAxisAngle.\n"
+   "@param index The controller index to check.\n"
+   "@return Axis rotation of the requested controller.\n\n"
+   "@see RazerHydra::MaximumAxisAngle\n")
+{
+   return object->getRotAxis(index);
+}
+
+DefineEngineMethod( RazerHydraFrame, getControllerThumbStick, Point2F, ( S32 index ),,
+   "@brief Get the thumb stick values of the requested controller.\n\n"
+   "The thumb stick values are in the range of -1.0..1.0\n"
+   "@param index The controller index to check.\n"
+   "@return Thumb stick values of the requested controller.\n\n")
+{
+   return object->getThumbStick(index);
+}
+
+DefineEngineMethod( RazerHydraFrame, getControllerTrigger, F32, ( S32 index ),,
+   "@brief Get the trigger value for the requested controller.\n\n"
+   "The trigger value is in the range of -1.0..1.0\n"
+   "@param index The controller index to check.\n"
+   "@return Trigger value of the requested controller.\n\n")
+{
+   return object->getTrigger(index);
+}
+
+DefineEngineMethod( RazerHydraFrame, getControllerShoulderButton, bool, ( S32 index ),,
+   "@brief Get the shoulder button state for the requested controller.\n\n"
+   "@param index The controller index to check.\n"
+   "@return Shoulder button state requested controller as true or false.\n\n")
+{
+   return object->getShoulder(index);
+}
+
+DefineEngineMethod( RazerHydraFrame, getControllerThumbButton, bool, ( S32 index ),,
+   "@brief Get the thumb button state for the requested controller.\n\n"
+   "@param index The controller index to check.\n"
+   "@return Thumb button state requested controller as true or false.\n\n")
+{
+   return object->getThumb(index);
+}
+
+DefineEngineMethod( RazerHydraFrame, getControllerStartButton, bool, ( S32 index ),,
+   "@brief Get the start button state for the requested controller.\n\n"
+   "@param index The controller index to check.\n"
+   "@return Start button state requested controller as true or false.\n\n")
+{
+   return object->getStart(index);
+}
+
+DefineEngineMethod( RazerHydraFrame, getControllerButton1, bool, ( S32 index ),,
+   "@brief Get the button 1 state for the requested controller.\n\n"
+   "@param index The controller index to check.\n"
+   "@return Button 1 state requested controller as true or false.\n\n")
+{
+   return object->getButton1(index);
+}
+
+DefineEngineMethod( RazerHydraFrame, getControllerButton2, bool, ( S32 index ),,
+   "@brief Get the button 2 state for the requested controller.\n\n"
+   "@param index The controller index to check.\n"
+   "@return Button 2 state requested controller as true or false.\n\n")
+{
+   return object->getButton2(index);
+}
+
+DefineEngineMethod( RazerHydraFrame, getControllerButton3, bool, ( S32 index ),,
+   "@brief Get the button 3 state for the requested controller.\n\n"
+   "@param index The controller index to check.\n"
+   "@return Button 3 state requested controller as true or false.\n\n")
+{
+   return object->getButton3(index);
+}
+
+DefineEngineMethod( RazerHydraFrame, getControllerButton4, bool, ( S32 index ),,
+   "@brief Get the button 4 state for the requested controller.\n\n"
+   "@param index The controller index to check.\n"
+   "@return Button 4 state requested controller as true or false.\n\n")
+{
+   return object->getButton4(index);
+}

+ 218 - 0
Engine/source/platform/input/razerHydra/razerHydraFrame.h

@@ -0,0 +1,218 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2012 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#ifndef _RAZERHYDRAFRAME_H_
+#define _RAZERHYDRAFRAME_H_
+
+#include "platform/input/razerHydra/razerHydraConstants.h"
+#include "console/simObject.h"
+#include "math/mPoint3.h"
+#include "math/mMatrix.h"
+#include "math/mQuat.h"
+#include "sixense.h"
+
+class RazerHydraFrame : public SimObject
+{
+   typedef SimObject Parent;
+
+protected:
+   struct ControllerData
+   {
+      // Position
+      Point3F mRawPos;
+      Point3I mPos;
+
+      // Rotation
+      MatrixF mRot;
+      QuatF   mRotQuat;
+
+      // Controller rotation as axis x, y
+      Point2F mRotAxis;
+
+      // Thumb stick x, y and trigger
+      Point2F mThumbStick;
+      F32 mTrigger;
+
+      // Buttons
+      bool mShoulder;
+      bool mThumb;
+      bool mStart;
+      bool mButton1;
+      bool mButton2;
+      bool mButton3;
+      bool mButton4;
+
+      // Other data
+      U8 mSequenceNum;
+      bool mEnabled;
+      bool mIsDocked;
+   };
+
+   static U32 smNextInternalFrameId;
+
+   // Sixense Frame
+   bool  mFrameValid;
+
+   // Torque 3D frame information
+   U32   mFrameInternalId;
+   S32   mFrameSimTime;
+   S32   mFrameRealTime;
+
+   // Controller data for the frame
+   ControllerData mControllerData[RazerHydraConstants::MaxControllers];
+
+public:
+   RazerHydraFrame();
+   virtual ~RazerHydraFrame();
+
+   static void initPersistFields();
+
+   virtual bool onAdd();
+   virtual void onRemove();
+
+   void clear();
+
+   /// Copy a Leap Frame into our data structures
+   void copyFromFrame(const sixenseAllControllerData& frame, const F32& maxAxisRadius);
+
+   // Frame
+   bool isFrameValid() const { return mFrameValid; }
+   U32 getFrameInternalId() const { return mFrameInternalId; }
+   S32 getFrameSimTime() const { return mFrameSimTime; }
+   S32 getFrameRealTime() const { return mFrameRealTime; }
+
+   // Controller
+   const Point3F& getRawPos(U32 index) const;
+   const Point3I& getPos(U32 index) const;
+   const MatrixF& getRot(U32 index) const;
+   const QuatF& getRotQuat(U32 index) const;
+   const Point2F& getRotAxis(U32 index) const;
+
+   // Controller variable controls
+   const Point2F& getThumbStick(U32 Index) const;
+   F32 getTrigger(U32 index) const;
+
+   // Controller buttons
+   bool getShoulder(U32 index) const;
+   bool getThumb(U32 index) const;
+   bool getStart(U32 index) const;
+   bool getButton1(U32 index) const;
+   bool getButton2(U32 index) const;
+   bool getButton3(U32 index) const;
+   bool getButton4(U32 index) const;
+
+   // Controller other
+   bool getEnabled(U32 index) const;
+   bool getDocked(U32 index) const;
+   S32 getSequenceNum(U32 index) const;
+
+   DECLARE_CONOBJECT(RazerHydraFrame);
+};
+
+//-----------------------------------------------------------------------------
+
+inline const Point3F& RazerHydraFrame::getRawPos(U32 index) const
+{
+   return (index >= RazerHydraConstants::MaxControllers) ? Point3F::Zero : mControllerData[index].mRawPos;
+}
+
+inline const Point3I& RazerHydraFrame::getPos(U32 index) const
+{
+   return (index >= RazerHydraConstants::MaxControllers) ? Point3I::Zero : mControllerData[index].mPos;
+}
+
+inline const MatrixF& RazerHydraFrame::getRot(U32 index) const
+{
+   return (index >= RazerHydraConstants::MaxControllers) ? MatrixF::Identity : mControllerData[index].mRot;
+}
+
+inline const QuatF& RazerHydraFrame::getRotQuat(U32 index) const
+{
+   return (index >= RazerHydraConstants::MaxControllers) ? QuatF::Identity : mControllerData[index].mRotQuat;
+}
+
+inline const Point2F& RazerHydraFrame::getRotAxis(U32 index) const
+{
+   return (index >= RazerHydraConstants::MaxControllers) ? Point2F::Zero : mControllerData[index].mRotAxis;
+}
+
+inline const Point2F& RazerHydraFrame::getThumbStick(U32 index) const
+{
+   return (index >= RazerHydraConstants::MaxControllers) ? Point2F::Zero : mControllerData[index].mThumbStick;
+}
+
+inline F32 RazerHydraFrame::getTrigger(U32 index) const
+{
+   return (index >= RazerHydraConstants::MaxControllers) ? 0.0f : mControllerData[index].mTrigger;
+}
+
+inline bool RazerHydraFrame::getShoulder(U32 index) const
+{
+   return (index >= RazerHydraConstants::MaxControllers) ? false : mControllerData[index].mShoulder;
+}
+
+inline bool RazerHydraFrame::getThumb(U32 index) const
+{
+   return (index >= RazerHydraConstants::MaxControllers) ? false : mControllerData[index].mThumb;
+}
+
+inline bool RazerHydraFrame::getStart(U32 index) const
+{
+   return (index >= RazerHydraConstants::MaxControllers) ? false : mControllerData[index].mStart;
+}
+
+inline bool RazerHydraFrame::getButton1(U32 index) const
+{
+   return (index >= RazerHydraConstants::MaxControllers) ? false : mControllerData[index].mButton1;
+}
+
+inline bool RazerHydraFrame::getButton2(U32 index) const
+{
+   return (index >= RazerHydraConstants::MaxControllers) ? false : mControllerData[index].mButton2;
+}
+
+inline bool RazerHydraFrame::getButton3(U32 index) const
+{
+   return (index >= RazerHydraConstants::MaxControllers) ? false : mControllerData[index].mButton3;
+}
+
+inline bool RazerHydraFrame::getButton4(U32 index) const
+{
+   return (index >= RazerHydraConstants::MaxControllers) ? false : mControllerData[index].mButton4;
+}
+
+inline bool RazerHydraFrame::getEnabled(U32 index) const
+{
+   return (index >= RazerHydraConstants::MaxControllers) ? false : mControllerData[index].mEnabled;
+}
+
+inline bool RazerHydraFrame::getDocked(U32 index) const
+{
+   return (index >= RazerHydraConstants::MaxControllers) ? false : mControllerData[index].mIsDocked;
+}
+
+inline S32 RazerHydraFrame::getSequenceNum(U32 index) const
+{
+   return (index >= RazerHydraConstants::MaxControllers) ? -1 : mControllerData[index].mSequenceNum;
+}
+
+#endif   // _RAZERHYDRAFRAME_H_

+ 104 - 0
Engine/source/platform/input/razerHydra/razerHydraFrameStore.cpp

@@ -0,0 +1,104 @@
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#include "platform/input/razerHydra/razerHydraFrameStore.h"
+#include "platform/input/razerHydra/razerHydraFrame.h"
+#include "core/module.h"
+#include "console/simSet.h"
+#include "console/consoleTypes.h"
+
+MODULE_BEGIN( RazerHydraFrameStore )
+
+   MODULE_INIT_AFTER( RazerHydraDevice )
+   MODULE_INIT_AFTER( Sim )
+   MODULE_SHUTDOWN_BEFORE( Sim )
+   MODULE_SHUTDOWN_BEFORE( RazerHydraDevice )
+
+   MODULE_INIT
+   {
+      RazerHydraFrameStore::staticInit();
+      ManagedSingleton< RazerHydraFrameStore >::createSingleton();
+   }
+   
+   MODULE_SHUTDOWN
+   {
+      ManagedSingleton< RazerHydraFrameStore >::deleteSingleton();
+   }
+
+MODULE_END;
+
+S32 RazerHydraFrameStore::smMaximumFramesStored = 30;
+
+SimGroup* RazerHydraFrameStore::smFrameGroup = NULL;
+
+RazerHydraFrameStore::RazerHydraFrameStore()
+{
+   // Set up the SimGroup to store our frames
+   smFrameGroup = new SimGroup();
+   smFrameGroup->registerObject("RazerHydraFrameGroup");
+   smFrameGroup->setNameChangeAllowed(false);
+   Sim::getRootGroup()->addObject(smFrameGroup);
+}
+
+RazerHydraFrameStore::~RazerHydraFrameStore()
+{
+   if(smFrameGroup)
+   {
+      smFrameGroup->deleteObject();
+      smFrameGroup = NULL;
+   }
+}
+
+void RazerHydraFrameStore::staticInit()
+{
+   Con::addVariable("RazerHydra::MaximumFramesStored", TypeS32, &smMaximumFramesStored, 
+      "@brief The maximum number of frames to keep when $RazerHydra::GenerateWholeFrameEvents is true.\n\n"
+	   "@ingroup Game");
+}
+
+S32 RazerHydraFrameStore::generateNewFrame(const sixenseAllControllerData& frame, const F32& maxAxisRadius)
+{
+   // Make sure our group has been created
+   if(!smFrameGroup)
+      return 0;
+
+   // Either create a new frame object or pull one off the end
+   S32 frameID = 0;
+   if(smFrameGroup->size() >= smMaximumFramesStored)
+   {
+      // Make the last frame the first and update
+      RazerHydraFrame* frameObj = static_cast<RazerHydraFrame*>(smFrameGroup->last());
+      smFrameGroup->bringObjectToFront(frameObj);
+      frameObj->copyFromFrame(frame, maxAxisRadius);
+      frameID = frameObj->getId();
+   }
+   else
+   {
+      // Create a new frame and add it to the front of the list
+      RazerHydraFrame* frameObj = new RazerHydraFrame();
+      frameObj->registerObject();
+      smFrameGroup->addObject(frameObj);
+      smFrameGroup->bringObjectToFront(frameObj);
+      frameObj->copyFromFrame(frame, maxAxisRadius);
+      frameID = frameObj->getId();
+   }
+
+   return frameID;
+}

+ 58 - 0
Engine/source/platform/input/razerHydra/razerHydraFrameStore.h

@@ -0,0 +1,58 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2012 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#ifndef _RAZERHYDRAFRAMESTORE_H_
+#define _RAZERHYDRAFRAMESTORE_H_
+
+#include "platform/types.h"
+#include "sixense.h"
+
+class SimGroup;
+
+class RazerHydraFrameStore
+{
+public:
+   // The maximum number of frames to keep
+   static S32 smMaximumFramesStored;
+
+   static SimGroup* smFrameGroup;
+
+public:
+   RazerHydraFrameStore();
+   virtual ~RazerHydraFrameStore();
+
+   static void staticInit();
+
+   static bool isFrameGroupDefined() { return smFrameGroup != NULL; }
+   static SimGroup* getFrameGroup() { return smFrameGroup; }
+
+   S32 generateNewFrame(const sixenseAllControllerData& frame, const F32& maxAxisRadius);
+
+public:
+   // For ManagedSingleton.
+   static const char* getSingletonName() { return "RazerHydraFrameStore"; }   
+};
+
+/// Returns the LeapMotionFrameStore singleton.
+#define RAZERHYDRAFS ManagedSingleton<RazerHydraFrameStore>::instance()
+
+#endif   // _RAZERHYDRAFRAMESTORE_H_

+ 95 - 0
Engine/source/platform/input/razerHydra/razerHydraUtil.cpp

@@ -0,0 +1,95 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2012 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#include "platform/input/razerHydra/razerHydraUtil.h"
+
+namespace RazerHydraUtil
+{
+
+enum Components
+{
+   X = 0,
+   Y = 1,
+   Z = 2,
+};
+
+void convertPosition(const F32 inPosition[3], F32& x, F32& y, F32& z)
+{
+   // Convert to Torque coordinates.  The conversion is:
+   //
+   // Motion       Torque
+   // x y z   -->  x -z y
+   x = inPosition[X];    // x = x
+   y = -inPosition[Z];   // y = -z
+   z = inPosition[Y];    // z = y;
+}
+
+void convertPosition(const F32 inPosition[3], Point3F& outPosition)
+{
+   // Convert to Torque coordinates.  The conversion is:
+   //
+   // Motion       Torque
+   // x y z   -->  x -z y
+   outPosition.x = inPosition[X];    // x = x
+   outPosition.y = -inPosition[Z];   // y = -z
+   outPosition.z = inPosition[Y];    // z = y;
+}
+
+void convertRotation(const F32 inRotMat[3][3], MatrixF& outRotation)
+{
+   // Set rotation.  We need to convert from sixense coordinates to
+   // Torque coordinates.  The conversion is:
+   //
+   // Sixense                      Torque
+   // a b c         a  b  c        a -c  b
+   // d e f   -->  -g -h -i  -->  -g  i -h
+   // g h i         d  e  f        d -f  e
+   outRotation.setColumn(0, Point4F( inRotMat[0][0], -inRotMat[0][2],  inRotMat[0][1], 0.0f));
+   outRotation.setColumn(1, Point4F(-inRotMat[2][0],  inRotMat[2][2], -inRotMat[2][1], 0.0f));
+   outRotation.setColumn(2, Point4F( inRotMat[1][0], -inRotMat[1][2],  inRotMat[1][1], 0.0f));
+   outRotation.setPosition(Point3F::Zero);
+}
+
+void calculateAxisRotation(const MatrixF& inRotation, const F32& maxAxisRadius, Point2F& outRotation)
+{
+   const VectorF& controllerUp = inRotation.getUpVector();
+   Point2F axis(0,0);
+   axis.x = controllerUp.x;
+   axis.y = controllerUp.y;
+
+   // Limit the axis angle to that given to us
+   if(axis.len() > maxAxisRadius)
+   {
+      axis.normalize(maxAxisRadius);
+   }
+
+   // Renormalize to the range of 0..1
+   if(maxAxisRadius != 0.0f)
+   {
+      axis /= maxAxisRadius;
+   }
+
+   outRotation.x = axis.x;
+   outRotation.y = axis.y;
+}
+
+}

+ 44 - 0
Engine/source/platform/input/razerHydra/razerHydraUtil.h

@@ -0,0 +1,44 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2012 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#ifndef _RAZERHYDRAUTIL_H_
+#define _RAZERHYDRAUTIL_H_
+
+#include "math/mPoint3.h"
+#include "math/mMatrix.h"
+
+namespace RazerHydraUtil
+{
+   /// Convert from a Razer Hydra controller position to a Torque 3D position
+   void convertPosition(const F32 inPosition[3], F32& x, F32& y, F32& z);
+
+   /// Convert from a Razer Hydra controller position to a Torque 3D Point3F
+   void convertPosition(const F32 inPosition[3], Point3F& outPosition);
+
+   /// Convert a Razer Hydra controller's rotation to a Torque 3D matrix
+   void convertRotation(const F32 inRotMat[3][3], MatrixF& outRotation);
+
+   /// Calcualte a controller's rotation as if it were a thumb stick axis
+   void calculateAxisRotation(const MatrixF& inRotation, const F32& maxAxisRadius, Point2F& outRotation);
+}
+
+#endif   // _RAZERHYDRAUTIL_H_

+ 75 - 0
Tools/projectGenerator/modules/razerHydra.inc

@@ -0,0 +1,75 @@
+<?php
+//-----------------------------------------------------------------------------
+// Copyright (c) 2012 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+beginModule( 'razerHydra' );
+
+   // Look for the optional global from the project.conf.
+   global $RAZERHYDRA_SDK_PATH;
+   if (!$RAZERHYDRA_SDK_PATH)
+   {
+      // First look for an environment var.
+      $RAZERHYDRA_SDK_PATH = getenv( "TORQUE_RAZERHYDRA_PATH" );
+
+      if (strlen($RAZERHYDRA_SDK_PATH) == 0 || !file_exists($RAZERHYDRA_SDK_PATH))
+      {
+         // Sometimes users get confused and use this var.
+         $RAZERHYDRA_SDK_PATH = getenv( "RAZERHYDRA_SDK_PATH" );
+      }
+
+      // We need forward slashes for paths.
+      $RAZERHYDRA_SDK_PATH = str_replace( "\\", "/", $RAZERHYDRA_SDK_PATH);
+
+      // Remove trailing slashes.
+      $RAZERHYDRA_SDK_PATH = rtrim($RAZERHYDRA_SDK_PATH, " /");
+   }
+
+   // If we still don't have the SDK path then let the user know.
+   if (!file_exists($RAZERHYDRA_SDK_PATH))
+   {
+      trigger_error( 
+            "\n*******************************************************************".
+            "\n".
+            "\n  We were not able to find a valid path to the Razer Hydra SDK!".
+            "\n".
+            "\n  You must install the latest Sixense SDK and set the path via a".
+            "\n  \$RAZERHYDRA_SDK_PATH variable in your buildFiles/project.conf file".
+            "\n  or by setting the TORQUE_RAZERHYDRA_PATH system environment variable".
+            "\n  (may require a reboot).".
+            "\n".
+            "\n*******************************************************************".
+            "\n", E_USER_ERROR );
+   }
+
+   // Only Windows is supported at this time
+   if ( Generator::$platform == "win32" )
+   {
+      // Source
+      addEngineSrcDir( "platform/input/razerHydra" );
+
+      // Includes
+      addIncludePath( $RAZERHYDRA_SDK_PATH . "/include" );
+   }
+
+endModule();
+
+?>