aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--LibOVR/Include/OVRVersion.h4
-rw-r--r--LibOVR/Projects/Win32/LibOVR_Msvc2010.vcxproj8
-rw-r--r--LibOVR/Projects/Win32/LibOVR_Msvc2010.vcxproj.filters6
-rw-r--r--LibOVR/Src/Kernel/OVR_List.h2
-rw-r--r--LibOVR/Src/Kernel/OVR_Math.h2
-rw-r--r--LibOVR/Src/Kernel/OVR_Types.h2
-rw-r--r--LibOVR/Src/OVR_DeviceImpl.h2
-rw-r--r--LibOVR/Src/OVR_Linux_HIDDevice.cpp2
-rw-r--r--LibOVR/Src/OVR_Linux_HMDDevice.cpp2
-rw-r--r--LibOVR/Src/OVR_Profile.cpp43
-rw-r--r--LibOVR/Src/OVR_Profile.h3
-rw-r--r--LibOVR/Src/OVR_SensorFusion.cpp334
-rw-r--r--LibOVR/Src/OVR_SensorFusion.h213
-rw-r--r--LibOVR/Src/Util/Util_MagCalibration.cpp57
-rw-r--r--LibOVR/Src/Util/Util_MagCalibration.h19
-rw-r--r--LibOVR/Src/Util/Util_Render_Stereo.cpp4
-rw-r--r--Oculus Configuration Utility.lnkbin0 -> 2351 bytes
-rw-r--r--Oculus World Demo.lnkbin0 -> 2349 bytes
-rw-r--r--Samples/CommonSrc/Platform/Linux_Gamepad.cpp415
-rw-r--r--Samples/CommonSrc/Platform/Linux_Gamepad.h48
-rw-r--r--Samples/OculusRoomTiny/OculusRoomTiny_Msvc2010.vcxproj2
-rw-r--r--Samples/OculusRoomTiny/OculusRoomTiny_Msvc2010.vcxproj.filters2
-rw-r--r--Samples/OculusWorldDemo/OculusWorldDemo.cpp42
-rw-r--r--Samples/OculusWorldDemo/OculusWorldDemo_Msvc2010.vcxproj2
-rw-r--r--Samples/OculusWorldDemo/OculusWorldDemo_Msvc2010.vcxproj.filters2
-rw-r--r--Samples/OculusWorldDemo/Player.cpp6
-rw-r--r--Samples/OculusWorldDemo/Player.h4
-rw-r--r--Samples/SensorBox/SensorBoxTest_Msvc2010.vcxproj2
-rw-r--r--Samples/SensorBox/SensorBoxTest_Msvc2010.vcxproj.filters2
29 files changed, 1020 insertions, 210 deletions
diff --git a/LibOVR/Include/OVRVersion.h b/LibOVR/Include/OVRVersion.h
index 520a925..453db75 100644
--- a/LibOVR/Include/OVRVersion.h
+++ b/LibOVR/Include/OVRVersion.h
@@ -16,7 +16,7 @@ otherwise accompanies this software in either electronic or hard copy form.
#define OVR_MAJOR_VERSION 0
#define OVR_MINOR_VERSION 2
-#define OVR_BUILD_VERSION 3
-#define OVR_VERSION_STRING "0.2.3"
+#define OVR_BUILD_VERSION 4
+#define OVR_VERSION_STRING "0.2.4"
#endif
diff --git a/LibOVR/Projects/Win32/LibOVR_Msvc2010.vcxproj b/LibOVR/Projects/Win32/LibOVR_Msvc2010.vcxproj
index 1cc44e8..2e7fc31 100644
--- a/LibOVR/Projects/Win32/LibOVR_Msvc2010.vcxproj
+++ b/LibOVR/Projects/Win32/LibOVR_Msvc2010.vcxproj
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
@@ -50,7 +50,9 @@
<ClInclude Include="..\..\Src\OVR_HIDDevice.h" />
<ClInclude Include="..\..\Src\OVR_HIDDeviceBase.h" />
<ClInclude Include="..\..\Src\OVR_HIDDeviceImpl.h" />
+ <ClInclude Include="..\..\Src\OVR_JSON.h" />
<ClInclude Include="..\..\Src\OVR_LatencyTestImpl.h" />
+ <ClInclude Include="..\..\Src\OVR_Profile.h" />
<ClInclude Include="..\..\Src\OVR_SensorFilter.h" />
<ClInclude Include="..\..\Src\Util\Util_LatencyTest.h" />
<ClInclude Include="..\..\Src\OVR_SensorFusion.h" />
@@ -84,7 +86,9 @@
<ClCompile Include="..\..\Src\Kernel\OVR_UTF8Util.cpp" />
<ClCompile Include="..\..\Src\OVR_DeviceHandle.cpp" />
<ClCompile Include="..\..\Src\OVR_DeviceImpl.cpp" />
+ <ClCompile Include="..\..\Src\OVR_JSON.cpp" />
<ClCompile Include="..\..\Src\OVR_LatencyTestImpl.cpp" />
+ <ClCompile Include="..\..\Src\OVR_Profile.cpp" />
<ClCompile Include="..\..\Src\OVR_SensorFilter.cpp" />
<ClCompile Include="..\..\Src\OVR_SensorFusion.cpp" />
<ClCompile Include="..\..\Src\OVR_SensorImpl.cpp" />
@@ -234,6 +238,7 @@
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<OmitDefaultLibName>true</OmitDefaultLibName>
<DebugInformationFormat>OldStyle</DebugInformationFormat>
+ <WholeProgramOptimization>false</WholeProgramOptimization>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
@@ -258,6 +263,7 @@
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<OmitDefaultLibName>true</OmitDefaultLibName>
<DebugInformationFormat>OldStyle</DebugInformationFormat>
+ <WholeProgramOptimization>false</WholeProgramOptimization>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
diff --git a/LibOVR/Projects/Win32/LibOVR_Msvc2010.vcxproj.filters b/LibOVR/Projects/Win32/LibOVR_Msvc2010.vcxproj.filters
index 7e00c30..016a15d 100644
--- a/LibOVR/Projects/Win32/LibOVR_Msvc2010.vcxproj.filters
+++ b/LibOVR/Projects/Win32/LibOVR_Msvc2010.vcxproj.filters
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="..\..\Src\OVR_SensorFusion.cpp" />
@@ -73,6 +73,8 @@
<Filter>Util</Filter>
</ClCompile>
<ClCompile Include="..\..\Src\OVR_SensorFilter.cpp" />
+ <ClCompile Include="..\..\Src\OVR_JSON.cpp" />
+ <ClCompile Include="..\..\Src\OVR_Profile.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\Src\OVR_DeviceImpl.h" />
@@ -171,6 +173,8 @@
<Filter>Util</Filter>
</ClInclude>
<ClInclude Include="..\..\Src\OVR_SensorFilter.h" />
+ <ClInclude Include="..\..\Src\OVR_JSON.h" />
+ <ClInclude Include="..\..\Src\OVR_Profile.h" />
</ItemGroup>
<ItemGroup>
<Filter Include="Kernel">
diff --git a/LibOVR/Src/Kernel/OVR_List.h b/LibOVR/Src/Kernel/OVR_List.h
index 4b32f49..6ad471d 100644
--- a/LibOVR/Src/Kernel/OVR_List.h
+++ b/LibOVR/Src/Kernel/OVR_List.h
@@ -115,7 +115,7 @@ struct ListNode
// }
//
-// List<> represents a doubly-linked list if T, where each T must derive
+// List<> represents a doubly-linked list of T, where each T must derive
// from ListNode<B>. B specifies the base class that was directly
// derived from ListNode, and is only necessary if there is an intermediate
// inheritance chain.
diff --git a/LibOVR/Src/Kernel/OVR_Math.h b/LibOVR/Src/Kernel/OVR_Math.h
index 2b255c7..567ea9c 100644
--- a/LibOVR/Src/Kernel/OVR_Math.h
+++ b/LibOVR/Src/Kernel/OVR_Math.h
@@ -879,7 +879,7 @@ public:
}
// Sets this quaternion to the one rotates in the opposite direction.
- void Invert() const
+ void Invert()
{
*this = Quat(-x, -y, -z, w);
}
diff --git a/LibOVR/Src/Kernel/OVR_Types.h b/LibOVR/Src/Kernel/OVR_Types.h
index 75493aa..db024f1 100644
--- a/LibOVR/Src/Kernel/OVR_Types.h
+++ b/LibOVR/Src/Kernel/OVR_Types.h
@@ -291,7 +291,7 @@ namespace BaseTypes
#if defined(OVR_CC_MSVC)
# define OVR_FORCE_INLINE __forceinline
#elif defined(OVR_CC_GNU)
-# define OVR_FORCE_INLINE __attribute__((always_inline))
+# define OVR_FORCE_INLINE __attribute__((always_inline)) inline
#else
# define OVR_FORCE_INLINE inline
#endif // OVR_CC_MSVC
diff --git a/LibOVR/Src/OVR_DeviceImpl.h b/LibOVR/Src/OVR_DeviceImpl.h
index 2273d3d..e61e37b 100644
--- a/LibOVR/Src/OVR_DeviceImpl.h
+++ b/LibOVR/Src/OVR_DeviceImpl.h
@@ -350,7 +350,7 @@ public:
virtual void Shutdown();
- // Every DeviceManager has an associated profile manager, which us used to store
+ // Every DeviceManager has an associated profile manager, which is used to store
// user settings that may affect device behavior.
virtual ProfileManager* GetProfileManager() const { return pProfileManager.GetPtr(); }
diff --git a/LibOVR/Src/OVR_Linux_HIDDevice.cpp b/LibOVR/Src/OVR_Linux_HIDDevice.cpp
index 6656e9a..062d566 100644
--- a/LibOVR/Src/OVR_Linux_HIDDevice.cpp
+++ b/LibOVR/Src/OVR_Linux_HIDDevice.cpp
@@ -258,7 +258,7 @@ bool HIDDeviceManager::Enumerate(HIDEnumerateVisitor* enumVisitor)
udev_device_unref(hid);
entry = udev_list_entry_get_next(entry);
}
- }
+ }
// Free the enumerator and udev objects
udev_enumerate_unref(devices);
diff --git a/LibOVR/Src/OVR_Linux_HMDDevice.cpp b/LibOVR/Src/OVR_Linux_HMDDevice.cpp
index 7b26479..dc94851 100644
--- a/LibOVR/Src/OVR_Linux_HMDDevice.cpp
+++ b/LibOVR/Src/OVR_Linux_HMDDevice.cpp
@@ -176,7 +176,7 @@ void HMDDeviceFactory::EnumerateDevices(EnumerateVisitor& visitor)
bool foundHMD = false;
Display* display = XOpenDisplay(NULL);
- if (display)
+ if (display && XineramaIsActive(display))
{
int numberOfScreens;
XineramaScreenInfo* screens = XineramaQueryScreens(display, &numberOfScreens);
diff --git a/LibOVR/Src/OVR_Profile.cpp b/LibOVR/Src/OVR_Profile.cpp
index 7554a28..83eade3 100644
--- a/LibOVR/Src/OVR_Profile.cpp
+++ b/LibOVR/Src/OVR_Profile.cpp
@@ -46,16 +46,15 @@ namespace OVR {
//-----------------------------------------------------------------------------
// Returns the pathname of the JSON file containing the stored profiles
-String GetProfilePath(bool create_dir)
+String GetBaseOVRPath(bool create_dir)
{
String path;
#if defined(OVR_OS_WIN32)
-
- PWSTR data_path = NULL;
- SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, NULL, &data_path);
+
+ TCHAR data_path[MAX_PATH];
+ SHGetFolderPath(0, CSIDL_LOCAL_APPDATA, NULL, 0, data_path);
path = String(data_path);
- CoTaskMemFree(data_path);
path += "/Oculus";
@@ -113,10 +112,15 @@ String GetProfilePath(bool create_dir)
#endif
- path += "/Profiles.json";
return path;
}
+String GetProfilePath(bool create_dir)
+{
+ String path = GetBaseOVRPath(create_dir);
+ path += "/Profiles.json";
+ return path;
+}
//-----------------------------------------------------------------------------
// ***** ProfileManager
@@ -232,22 +236,25 @@ void ProfileManager::LoadCache(ProfileType device)
Ptr<Profile> profile = *CreateProfileObject(profileName, device, &deviceName);
// Read the base profile fields.
- while (item = profileItem->GetNextItem(item), item)
+ if (profile)
{
- if (item->Type != JSON_Object)
+ while (item = profileItem->GetNextItem(item), item)
{
- profile->ParseProperty(item->Name, item->Value);
- }
- else
- { // Search for the matching device to get device specific fields
- if (!deviceFound && OVR_strcmp(item->Name, deviceName) == 0)
+ if (item->Type != JSON_Object)
{
- deviceFound = true;
-
- for (JSON* deviceItem = item->GetFirstItem(); deviceItem;
- deviceItem = item->GetNextItem(deviceItem))
+ profile->ParseProperty(item->Name, item->Value);
+ }
+ else
+ { // Search for the matching device to get device specific fields
+ if (!deviceFound && OVR_strcmp(item->Name, deviceName) == 0)
{
- profile->ParseProperty(deviceItem->Name, deviceItem->Value);
+ deviceFound = true;
+
+ for (JSON* deviceItem = item->GetFirstItem(); deviceItem;
+ deviceItem = item->GetNextItem(deviceItem))
+ {
+ profile->ParseProperty(deviceItem->Name, deviceItem->Value);
+ }
}
}
}
diff --git a/LibOVR/Src/OVR_Profile.h b/LibOVR/Src/OVR_Profile.h
index bfd8ea9..7184aae 100644
--- a/LibOVR/Src/OVR_Profile.h
+++ b/LibOVR/Src/OVR_Profile.h
@@ -181,6 +181,9 @@ protected:
friend class ProfileManager;
};
+
+String GetBaseOVRPath(bool create_dir);
+
}
#endif // OVR_Profile_h \ No newline at end of file
diff --git a/LibOVR/Src/OVR_SensorFusion.cpp b/LibOVR/Src/OVR_SensorFusion.cpp
index a4c5809..ba913c1 100644
--- a/LibOVR/Src/OVR_SensorFusion.cpp
+++ b/LibOVR/Src/OVR_SensorFusion.cpp
@@ -16,6 +16,8 @@ otherwise accompanies this software in either electronic or hard copy form.
#include "OVR_SensorFusion.h"
#include "Kernel/OVR_Log.h"
#include "Kernel/OVR_System.h"
+#include "OVR_JSON.h"
+#include "OVR_Profile.h"
namespace OVR {
@@ -32,7 +34,8 @@ SensorFusion::SensorFusion(SensorDevice* sensor)
MagCondCount(0), MagCalibrated(false), MagRefQ(0, 0, 0, 1),
MagRefM(0), MagRefYaw(0), YawErrorAngle(0), MagRefDistance(0.5f),
YawErrorCount(0), YawCorrectionActivated(false), YawCorrectionInProgress(false),
- EnableYawCorrection(false), MagNumReferences(0), MagHasNearbyReference(false)
+ EnableYawCorrection(false), MagNumReferences(0), MagHasNearbyReference(false),
+ MotionTrackingEnabled(true)
{
if (sensor)
AttachToSensor(sensor);
@@ -47,6 +50,7 @@ SensorFusion::~SensorFusion()
bool SensorFusion::AttachToSensor(SensorDevice* sensor)
{
+ pSensor = sensor;
if (sensor != NULL)
{
MessageHandler* pCurrentHandler = sensor->GetMessageHandler();
@@ -63,6 +67,9 @@ bool SensorFusion::AttachToSensor(SensorDevice* sensor)
("SensorFusion::AttachToSensor failed - sensor %p already has handler", sensor));
return false;
}
+
+ // Automatically load the default mag calibration for this sensor
+ LoadMagCalibration();
}
if (Handler.IsHandlerInstalled())
@@ -95,7 +102,7 @@ void SensorFusion::Reset()
void SensorFusion::handleMessage(const MessageBodyFrame& msg)
{
- if (msg.Type != Message_BodyFrame)
+ if (msg.Type != Message_BodyFrame || !IsMotionTrackingEnabled())
return;
// Put the sensor readings into convenient local variables
@@ -251,7 +258,7 @@ void SensorFusion::handleMessage(const MessageBodyFrame& msg)
{
if (MagNumReferences == 0)
{
- SetMagReference(); // Use the current direction
+ setMagReference(); // Use the current direction
}
else if (Q.Distance(MagRefQ) > MagRefDistance)
{
@@ -278,7 +285,7 @@ void SensorFusion::handleMessage(const MessageBodyFrame& msg)
//LogText("Using reference %d\n",bestNdx);
}
else if (MagNumReferences < MagMaxReferences)
- SetMagReference();
+ setMagReference();
}
}
@@ -322,9 +329,7 @@ void SensorFusion::handleMessage(const MessageBodyFrame& msg)
}
-// Simple predictive filters based on extrapolating the smoothed, current angular velocity
-// or using smooth time derivative information. The argument is the amount of time into
-// the future to predict.
+// A predictive filter based on extrapolating the smoothed, current angular velocity
Quatf SensorFusion::GetPredictedOrientation(float pdt)
{
Lock::Locker lockScope(Handler.GetHandlerLock());
@@ -332,45 +337,32 @@ Quatf SensorFusion::GetPredictedOrientation(float pdt)
if (EnablePrediction)
{
-#if 1
// This method assumes a constant angular velocity
Vector3f angVelF = FAngV.SavitzkyGolaySmooth8();
float angVelFL = angVelF.Length();
-
+
+ // Force back to raw measurement
+ angVelF = AngV;
+ angVelFL = AngV.Length();
+
+ // Dynamic prediction interval: Based on angular velocity to reduce vibration
+ const float minPdt = 0.001f;
+ const float slopePdt = 0.1f;
+ float newpdt = pdt;
+ float tpdt = minPdt + slopePdt * angVelFL;
+ if (tpdt < pdt)
+ newpdt = tpdt;
+ //LogText("PredictonDTs: %d\n",(int)(newpdt / PredictionTimeIncrement + 0.5f));
+
if (angVelFL > 0.001f)
{
Vector3f rotAxisP = angVelF / angVelFL;
- float halfRotAngleP = angVelFL * pdt * 0.5f;
+ float halfRotAngleP = angVelFL * newpdt * 0.5f;
float sinaHRAP = sin(halfRotAngleP);
Quatf deltaQP(rotAxisP.x*sinaHRAP, rotAxisP.y*sinaHRAP,
rotAxisP.z*sinaHRAP, cos(halfRotAngleP));
qP = QUncorrected * deltaQP;
- }
-#else
- // This method estimates angular acceleration, conservatively
- OVR_ASSERT(pdt >= 0);
- int predictionStages = (int)(pdt / PredictionTimeIncrement + 0.5f);
- Quatd qpd = Quatd(Q.x,Q.y,Q.z,Q.w);
- Vector3f aa = FAngV.SavitzkyGolayDerivative12();
- Vector3d aad = Vector3d(aa.x,aa.y,aa.z);
- Vector3f angVelF = FAngV.SavitzkyGolaySmooth8();
- Vector3d avkd = Vector3d(angVelF.x,angVelF.y,angVelF.z);
- Vector3d rotAxisd = Vector3d(0,1,0);
- for (int i = 0; i < predictionStages; i++)
- {
- double angVelLengthd = avkd.Length();
- if (angVelLengthd > 0)
- rotAxisd = avkd / angVelLengthd;
- double halfRotAngled = angVelLengthd * PredictionTimeIncrement * 0.5;
- double sinHRAd = sin(halfRotAngled);
- Quatd deltaQd = Quatd(rotAxisd.x*sinHRAd, rotAxisd.y*sinHRAd, rotAxisd.z*sinHRAd,
- cos(halfRotAngled));
- qpd = qpd * deltaQd;
- // Update angular velocity by using the angular acceleration estimate
- avkd += aad;
- }
- qP = Quatf((float)qpd.x,(float)qpd.y,(float)qpd.z,(float)qpd.w);
-#endif
+ }
}
return qP;
}
@@ -387,7 +379,7 @@ Vector3f SensorFusion::GetCalibratedMagValue(const Vector3f& rawMag) const
}
-void SensorFusion::SetMagReference(const Quatf& q, const Vector3f& rawMag)
+void SensorFusion::setMagReference(const Quatf& q, const Vector3f& rawMag)
{
if (MagNumReferences < MagMaxReferences)
{
@@ -430,6 +422,274 @@ bool SensorFusion::BodyFrameHandler::SupportsMessageType(MessageType type) const
return (type == Message_BodyFrame);
}
+// Writes the current calibration for a particular device to a device profile file
+// sensor - the sensor that was calibrated
+// cal_name - an optional name for the calibration or default if cal_name == NULL
+bool SensorFusion::SaveMagCalibration(const char* calibrationName) const
+{
+ if (pSensor == NULL || !HasMagCalibration())
+ return false;
+
+ // A named calibration may be specified for calibration in different
+ // environments, otherwise the default calibration is used
+ if (calibrationName == NULL)
+ calibrationName = "default";
+
+ SensorInfo sinfo;
+ pSensor->GetDeviceInfo(&sinfo);
+
+ // Generate a mag calibration event
+ JSON* calibration = JSON::CreateObject();
+ // (hardcoded for now) the measurement and representation method
+ calibration->AddStringItem("Version", "1.0");
+ calibration->AddStringItem("Name", "default");
+
+ // time stamp the calibration
+ char time_str[64];
+
+#ifdef OVR_OS_WIN32
+ struct tm caltime;
+ localtime_s(&caltime, &MagCalibrationTime);
+ strftime(time_str, 64, "%Y-%m-%d %H:%M:%S", &caltime);
+#else
+ struct tm* caltime;
+ caltime = localtime(&MagCalibrationTime);
+ strftime(time_str, 64, "%Y-%m-%d %H:%M:%S", caltime);
+#endif
+
+ calibration->AddStringItem("Time", time_str);
+
+ // write the full calibration matrix
+ Matrix4f calmat = GetMagCalibration();
+ char matrix[128];
+ int pos = 0;
+ for (int r=0; r<4; r++)
+ {
+ for (int c=0; c<4; c++)
+ {
+ pos += (int)OVR_sprintf(matrix+pos, 128, "%g ", calmat.M[r][c]);
+ }
+ }
+ calibration->AddStringItem("Calibration", matrix);
+
+
+ String path = GetBaseOVRPath(true);
+ path += "/Devices.json";
+
+ // Look for a prexisting device file to edit
+ Ptr<JSON> root = *JSON::Load(path);
+ if (root)
+ { // Quick sanity check of the file type and format before we parse it
+ JSON* version = root->GetFirstItem();
+ if (version && version->Name == "Oculus Device Profile Version")
+ { // In the future I may need to check versioning to determine parse method
+ }
+ else
+ {
+ root->Release();
+ root = NULL;
+ }
+ }
+
+ JSON* device = NULL;
+ if (root)
+ {
+ device = root->GetFirstItem(); // skip the header
+ device = root->GetNextItem(device);
+ while (device)
+ { // Search for a previous calibration with the same name for this device
+ // and remove it before adding the new one
+ if (device->Name == "Device")
+ {
+ JSON* item = device->GetItemByName("Serial");
+ if (item && item->Value == sinfo.SerialNumber)
+ { // found an entry for this device
+ item = device->GetNextItem(item);
+ while (item)
+ {
+ if (item->Name == "MagCalibration")
+ {
+ JSON* name = item->GetItemByName("Name");
+ if (name && name->Value == calibrationName)
+ { // found a calibration of the same name
+ item->RemoveNode();
+ item->Release();
+ break;
+ }
+ }
+ item = device->GetNextItem(item);
+ }
+
+ // update the auto-mag flag
+ item = device->GetItemByName("EnableYawCorrection");
+ if (item)
+ item->dValue = (double)EnableYawCorrection;
+ else
+ device->AddBoolItem("EnableYawCorrection", EnableYawCorrection);
+
+ break;
+ }
+ }
+
+ device = root->GetNextItem(device);
+ }
+ }
+ else
+ { // Create a new device root
+ root = *JSON::CreateObject();
+ root->AddStringItem("Oculus Device Profile Version", "1.0");
+ }
+
+ if (device == NULL)
+ {
+ device = JSON::CreateObject();
+ device->AddStringItem("Product", sinfo.ProductName);
+ device->AddNumberItem("ProductID", sinfo.ProductId);
+ device->AddStringItem("Serial", sinfo.SerialNumber);
+ device->AddBoolItem("EnableYawCorrection", EnableYawCorrection);
+
+ root->AddItem("Device", device);
+ }
+
+ // Create and the add the new calibration event to the device
+ device->AddItem("MagCalibration", calibration);
+
+ return root->Save(path);
+}
+
+// Loads a saved calibration for the specified device from the device profile file
+// sensor - the sensor that the calibration was saved for
+// cal_name - an optional name for the calibration or the default if cal_name == NULL
+bool SensorFusion::LoadMagCalibration(const char* calibrationName)
+{
+ if (pSensor == NULL)
+ return false;
+
+ // A named calibration may be specified for calibration in different
+ // environments, otherwise the default calibration is used
+ if (calibrationName == NULL)
+ calibrationName = "default";
+
+ SensorInfo sinfo;
+ pSensor->GetDeviceInfo(&sinfo);
+
+ String path = GetBaseOVRPath(true);
+ path += "/Devices.json";
+
+ // Load the device profiles
+ Ptr<JSON> root = *JSON::Load(path);
+ if (root == NULL)
+ return false;
+
+ // Quick sanity check of the file type and format before we parse it
+ JSON* version = root->GetFirstItem();
+ if (version && version->Name == "Oculus Device Profile Version")
+ { // In the future I may need to check versioning to determine parse method
+ }
+ else
+ {
+ return false;
+ }
+
+ bool autoEnableCorrection = false;
+
+ JSON* device = root->GetNextItem(version);
+ while (device)
+ { // Search for a previous calibration with the same name for this device
+ // and remove it before adding the new one
+ if (device->Name == "Device")
+ {
+ JSON* item = device->GetItemByName("Serial");
+ if (item && item->Value == sinfo.SerialNumber)
+ { // found an entry for this device
+
+ JSON* autoyaw = device->GetItemByName("EnableYawCorrection");
+ if (autoyaw)
+ autoEnableCorrection = (autoyaw->dValue != 0);
+
+ item = device->GetNextItem(item);
+ while (item)
+ {
+ if (item->Name == "MagCalibration")
+ {
+ JSON* calibration = item;
+ JSON* name = calibration->GetItemByName("Name");
+ if (name && name->Value == calibrationName)
+ { // found a calibration with this name
+
+ time_t now;
+ time(&now);
+
+ // parse the calibration time
+ time_t calibration_time = now;
+ JSON* caltime = calibration->GetItemByName("Time");
+ if (caltime)
+ {
+ const char* caltime_str = caltime->Value.ToCStr();
+
+ tm ct;
+ memset(&ct, 0, sizeof(tm));
+
+#ifdef OVR_OS_WIN32
+ struct tm nowtime;
+ localtime_s(&nowtime, &now);
+ ct.tm_isdst = nowtime.tm_isdst;
+ sscanf_s(caltime_str, "%d-%d-%d %d:%d:%d",
+ &ct.tm_year, &ct.tm_mon, &ct.tm_mday,
+ &ct.tm_hour, &ct.tm_min, &ct.tm_sec);
+#else
+ struct tm* nowtime = localtime(&now);
+ ct.tm_isdst = nowtime->tm_isdst;
+ sscanf(caltime_str, "%d-%d-%d %d:%d:%d",
+ &ct.tm_year, &ct.tm_mon, &ct.tm_mday,
+ &ct.tm_hour, &ct.tm_min, &ct.tm_sec);
+#endif
+ ct.tm_year -= 1900;
+ ct.tm_mon--;
+ calibration_time = mktime(&ct);
+ }
+
+ // parse the calibration matrix
+ JSON* cal = calibration->GetItemByName("Calibration");
+ if (cal)
+ {
+ const char* data_str = cal->Value.ToCStr();
+ Matrix4f calmat;
+ for (int r=0; r<4; r++)
+ {
+ for (int c=0; c<4; c++)
+ {
+ calmat.M[r][c] = (float)atof(data_str);
+ while (data_str && *data_str != ' ')
+ data_str++;
+
+ if (data_str)
+ data_str++;
+ }
+ }
+
+ SetMagCalibration(calmat);
+ MagCalibrationTime = calibration_time;
+ EnableYawCorrection = autoEnableCorrection;
+
+ return true;
+ }
+ }
+ }
+ item = device->GetNextItem(item);
+ }
+
+ break;
+ }
+ }
+
+ device = root->GetNextItem(device);
+ }
+
+ return false;
+}
+
+
} // namespace OVR
diff --git a/LibOVR/Src/OVR_SensorFusion.h b/LibOVR/Src/OVR_SensorFusion.h
index adfe780..c660a86 100644
--- a/LibOVR/Src/OVR_SensorFusion.h
+++ b/LibOVR/Src/OVR_SensorFusion.h
@@ -19,6 +19,7 @@ otherwise accompanies this software in either electronic or hard copy form.
#include "OVR_Device.h"
#include "OVR_SensorFilter.h"
+#include <time.h>
namespace OVR {
@@ -27,6 +28,8 @@ namespace OVR {
// SensorFusion class accumulates Sensor notification messages to keep track of
// orientation, which involves integrating the gyro and doing correction with gravity.
+// Magnetometer based yaw drift correction is also supported; it is usually enabled
+// automatically based on loaded magnetometer configuration.
// Orientation is reported as a quaternion, from which users can obtain either the
// rotation matrix or Euler angles.
//
@@ -35,16 +38,20 @@ namespace OVR {
// - By attaching SensorFusion to a SensorDevice, in which case it will
// automatically handle notifications from that device.
+
class SensorFusion : public NewOverrideBase
{
enum
{
MagMaxReferences = 80
- };
+ };
public:
SensorFusion(SensorDevice* sensor = 0);
~SensorFusion();
+
+
+ // *** Setup
// Attaches this SensorFusion to a sensor device, from which it will receive
// notification messages. If a sensor is attached, manual message notification
@@ -52,15 +59,85 @@ public:
bool AttachToSensor(SensorDevice* sensor);
// Returns true if this Sensor fusion object is attached to a sensor.
- bool IsAttachedToSensor() const { return Handler.IsHandlerInstalled(); }
+ bool IsAttachedToSensor() const { return Handler.IsHandlerInstalled(); }
+
+
+
+ // *** State Query
+
+ // Obtain the current accumulated orientation. Many apps will want to use GetPredictedOrientation
+ // instead to reduce latency.
+ Quatf GetOrientation() const { return lockedGet(&Q); }
+
+ // Get predicted orientaion in the near future; predictDt is lookahead amount in seconds.
+ Quatf GetPredictedOrientation(float predictDt);
+ Quatf GetPredictedOrientation() { return GetPredictedOrientation(PredictionDT); }
+
+ // Obtain the last absolute acceleration reading, in m/s^2.
+ Vector3f GetAcceleration() const { return lockedGet(&A); }
+ // Obtain the last angular velocity reading, in rad/s.
+ Vector3f GetAngularVelocity() const { return lockedGet(&AngV); }
+
+ // Obtain the last raw magnetometer reading, in Gauss
+ Vector3f GetMagnetometer() const { return lockedGet(&RawMag); }
+ // Obtain the calibrated magnetometer reading (direction and field strength)
+ Vector3f GetCalibratedMagnetometer() const { OVR_ASSERT(MagCalibrated); return lockedGet(&CalMag); }
+
+
+ // Resets the current orientation.
+ void Reset();
+
+
+
+ // *** Configuration
+
+ void EnableMotionTracking(bool enable = true) { MotionTrackingEnabled = enable; }
+ bool IsMotionTrackingEnabled() const { return MotionTrackingEnabled; }
+
+ // Multiplier for yaw rotation (turning); setting this higher than 1 (the default) can allow the game
+ // to be played without auxillary rotation controls, possibly making it more immersive.
+ // Whether this is more or less likely to cause motion sickness is unknown.
+ float GetYawMultiplier() const { return YawMult; }
+ void SetYawMultiplier(float y) { YawMult = y; }
+
- void SetGravityEnabled(bool enableGravity) { EnableGravity = enableGravity; }
-
- bool IsGravityEnabled() const { return EnableGravity;}
+ // *** Prediction Control
- void SetYawCorrectionEnabled(bool enableYawCorrection) { EnableYawCorrection = enableYawCorrection; }
-
- // Yaw correction is set up to work
+ // Prediction functions.
+ // Prediction delta specifes how much prediction should be applied in seconds; it should in
+ // general be under the average rendering latency. Call GetPredictedOrientation() to get
+ // predicted orientation.
+ float GetPredictionDelta() const { return PredictionDT; }
+ void SetPrediction(float dt, bool enable = true) { PredictionDT = dt; EnablePrediction = enable; }
+ void SetPredictionEnabled(bool enable = true) { EnablePrediction = enable; }
+ bool IsPredictionEnabled() { return EnablePrediction; }
+
+
+ // *** Accelerometer/Gravity Correction Control
+
+ // Enables/disables gravity correction (on by default).
+ void SetGravityEnabled(bool enableGravity) { EnableGravity = enableGravity; }
+ bool IsGravityEnabled() const { return EnableGravity;}
+
+ // Gain used to correct gyro with accel. Default value is appropriate for typical use.
+ float GetAccelGain() const { return Gain; }
+ void SetAccelGain(float ag) { Gain = ag; }
+
+
+
+ // *** Magnetometer and Yaw Drift Correction Control
+
+ // Methods to load and save a mag calibration. Calibrations can optionally
+ // be specified by name to differentiate multiple calibrations under different conditions
+ // If LoadMagCalibration succeeds, it will override YawCorrectionEnabled based on
+ // saved calibration setting.
+ bool SaveMagCalibration(const char* calibrationName = NULL) const;
+ bool LoadMagCalibration(const char* calibrationName = NULL);
+
+ // Enables/disables magnetometer based yaw drift correction. Must also have mag calibration
+ // data for this correction to work.
+ void SetYawCorrectionEnabled(bool enable) { EnableYawCorrection = enable; }
+ // Determines if yaw correction is enabled.
bool IsYawCorrectionEnabled() const { return EnableYawCorrection;}
// Yaw correction is currently working (forcing a corrective yaw rotation)
@@ -70,12 +147,17 @@ public:
void SetMagCalibration(const Matrix4f& m)
{
MagCalibrationMatrix = m;
+ time(&MagCalibrationTime); // time stamp the calibration
MagCalibrated = true;
}
+ // Retrieves the magnetometer calibration matrix
+ Matrix4f GetMagCalibration() const { return MagCalibrationMatrix; }
+ // Retrieve the time of the calibration
+ time_t GetMagCalibrationTime() const { return MagCalibrationTime; }
+
// True only if the mag has calibration values stored
- bool HasMagCalibration() const { return MagCalibrated;}
-
+ bool HasMagCalibration() const { return MagCalibrated;}
// Force the mag into the uncalibrated state
void ClearMagCalibration() { MagCalibrated = false; }
@@ -83,110 +165,49 @@ public:
void ClearMagReferences() { MagNumReferences = 0; }
void SetMagRefDistance(const float d) { MagRefDistance = d; }
- // Notifies SensorFusion object about a new BodyFrame message from a sensor.
- // Should be called by user if not attaching to a sensor.
- void OnMessage(const MessageBodyFrame& msg)
- {
- OVR_ASSERT(!IsAttachedToSensor());
- handleMessage(msg);
- }
-
- // Obtain the current accumulated orientation.
- Quatf GetOrientation() const
- {
- Lock::Locker lockScope(Handler.GetHandlerLock());
- return Q;
- }
-
- // Use a predictive filter to estimate the future orientation
- Quatf GetPredictedOrientation(float pdt); // Specify lookahead time in ms
- Quatf GetPredictedOrientation() { return GetPredictedOrientation(PredictionDT); }
-
- // Obtain the last absolute acceleration reading, in m/s^2.
- Vector3f GetAcceleration() const
- {
- Lock::Locker lockScope(Handler.GetHandlerLock());
- return A;
- }
-
- // Obtain the last angular velocity reading, in rad/s.
- Vector3f GetAngularVelocity() const
- {
- Lock::Locker lockScope(Handler.GetHandlerLock());
- return AngV;
- }
- // Obtain the last magnetometer reading, in Gauss
- Vector3f GetMagnetometer() const
- {
- Lock::Locker lockScope(Handler.GetHandlerLock());
- return RawMag;
- }
- // Obtain the filtered magnetometer reading, in Gauss
- Vector3f GetFilteredMagnetometer() const
- {
- Lock::Locker lockScope(Handler.GetHandlerLock());
- return FRawMag.Mean();
- }
- // Obtain the calibrated magnetometer reading (direction and field strength)
- Vector3f GetCalibratedMagnetometer() const
- {
- OVR_ASSERT(MagCalibrated);
- Lock::Locker lockScope(Handler.GetHandlerLock());
- return CalMag;
- }
Vector3f GetCalibratedMagValue(const Vector3f& rawMag) const;
- float GetMagRefYaw() const
- {
- return MagRefYaw;
- }
+ float GetMagRefYaw() const { return MagRefYaw; }
+ float GetYawErrorAngle() const { return YawErrorAngle; }
- float GetYawErrorAngle() const
- {
- return YawErrorAngle;
- }
- // For later
- //Vector3f GetGravity() const;
- // Resets the current orientation
- void Reset();
- // Configuration
+ // *** Message Handler Logic
- // Gain used to correct gyro with accel. Default value is appropriate for typical use.
- float GetAccelGain() const { return Gain; }
- void SetAccelGain(float ag) { Gain = ag; }
-
- // Multiplier for yaw rotation (turning); setting this higher than 1 (the default) can allow the game
- // to be played without auxillary rotation controls, possibly making it more immersive. Whether this is more
- // or less likely to cause motion sickness is unknown.
- float GetYawMultiplier() const { return YawMult; }
- void SetYawMultiplier(float y) { YawMult = y; }
+ // Notifies SensorFusion object about a new BodyFrame message from a sensor.
+ // Should be called by user if not attaching to a sensor.
+ void OnMessage(const MessageBodyFrame& msg)
+ {
+ OVR_ASSERT(!IsAttachedToSensor());
+ handleMessage(msg);
+ }
void SetDelegateMessageHandler(MessageHandler* handler)
{ pDelegate = handler; }
- // Prediction functions.
- // Prediction delta specifes how much prediction should be applied in seconds; it should in
- // general be under the average rendering latency. Call GetPredictedOrientation() to get
- // predicted orientation.
- float GetPredictionDelta() const { return PredictionDT; }
- void SetPrediction(float dt, bool enable = true) { PredictionDT = dt; EnablePrediction = enable; }
- void SetPredictionEnabled(bool enable = true) { EnablePrediction = enable; }
- bool IsPredictionEnabled() { return EnablePrediction; }
+
private:
+
SensorFusion* getThis() { return this; }
+ // Helper used to read and return value within a Lock.
+ template<class C>
+ C lockedGet(const C* p) const
+ {
+ Lock::Locker lockScope(Handler.GetHandlerLock());
+ return *p;
+ }
+
// Internal handler for messages; bypasses error checking.
- void handleMessage(const MessageBodyFrame& msg);
+ void handleMessage(const MessageBodyFrame& msg);
// Set the magnetometer's reference orientation for use in yaw correction
// The supplied mag is an uncalibrated value
- void SetMagReference(const Quatf& q, const Vector3f& rawMag);
+ void setMagReference(const Quatf& q, const Vector3f& rawMag);
// Default to current HMD orientation
- void SetMagReference() { SetMagReference(Q, RawMag); }
+ void setMagReference() { setMagReference(Q, RawMag); }
class BodyFrameHandler : public MessageHandler
{
@@ -199,6 +220,8 @@ private:
virtual bool SupportsMessageType(MessageType type) const;
};
+ Ptr<SensorDevice> pSensor;
+
Quatf Q;
Quatf QUncorrected;
Vector3f A;
@@ -228,6 +251,7 @@ private:
bool EnableYawCorrection;
Matrix4f MagCalibrationMatrix;
+ time_t MagCalibrationTime;
bool MagCalibrated;
int MagCondCount;
float MagRefDistance;
@@ -244,6 +268,7 @@ private:
bool YawCorrectionInProgress;
bool YawCorrectionActivated;
+ bool MotionTrackingEnabled;
};
diff --git a/LibOVR/Src/Util/Util_MagCalibration.cpp b/LibOVR/Src/Util/Util_MagCalibration.cpp
index c537154..58b8c45 100644
--- a/LibOVR/Src/Util/Util_MagCalibration.cpp
+++ b/LibOVR/Src/Util/Util_MagCalibration.cpp
@@ -23,6 +23,12 @@ void MagCalibration::BeginAutoCalibration(SensorFusion& sf)
// This is a "hard" reset of the mag, so need to clear stored values
sf.ClearMagCalibration();
SampleCount = 0;
+
+ // reset the statistics
+ MinMagValues = Vector3f(10000.0f,10000.0f,10000.0f);
+ MaxMagValues = Vector3f(-10000.0f,-10000.0f,-10000.0f);
+ MinQuatValues = Quatf(1.0f,1.0f,1.0f,1.0f);
+ MaxQuatValues = Quatf(0.0f,0.0f,0.0f,0.0f);
}
unsigned MagCalibration::UpdateAutoCalibration(SensorFusion& sf)
@@ -36,7 +42,11 @@ unsigned MagCalibration::UpdateAutoCalibration(SensorFusion& sf)
InsertIfAcceptable(q, m);
if ((SampleCount == 4) && (Stat == Mag_AutoCalibrating))
+ {
+ //LogText("Magnetometer Output Spread: %f %f %f\n",MagSpread.x,MagSpread.y,MagSpread.z);
+ //LogText("Quaternion Spread: %f %f %f %f\n",QuatSpread.x,QuatSpread.y,QuatSpread.z,QuatSpread.w);
SetCalibration(sf);
+ }
return Stat;
@@ -83,7 +93,39 @@ bool MagCalibration::IsAcceptableSample(const Quatf& q, const Vector3f& m)
bool MagCalibration::InsertIfAcceptable(const Quatf& q, const Vector3f& m)
{
- if (IsAcceptableSample(q, m))
+ // Update some statistics
+ if (m.x < MinMagValues.x)
+ MinMagValues.x = m.x;
+ if (m.y < MinMagValues.y)
+ MinMagValues.y = m.y;
+ if (m.z < MinMagValues.z)
+ MinMagValues.z = m.z;
+ if (m.x > MaxMagValues.x)
+ MaxMagValues.x = m.x;
+ if (m.y > MaxMagValues.y)
+ MaxMagValues.y = m.y;
+ if (m.z > MaxMagValues.z)
+ MaxMagValues.z = m.z;
+ if (q.x < MinQuatValues.x)
+ MinQuatValues.x = q.x;
+ if (q.y < MinQuatValues.y)
+ MinQuatValues.y = q.y;
+ if (q.z < MinQuatValues.z)
+ MinQuatValues.z = q.z;
+ if (q.w < MinQuatValues.w)
+ MinQuatValues.w = q.w;
+ if (q.x > MaxQuatValues.x)
+ MaxQuatValues.x = q.x;
+ if (q.y > MaxQuatValues.y)
+ MaxQuatValues.y = q.y;
+ if (q.z > MaxQuatValues.z)
+ MaxQuatValues.z = q.z;
+ if (q.w > MaxQuatValues.w)
+ MaxQuatValues.w = q.w;
+ MagSpread = MaxMagValues - MinMagValues;
+ QuatSpread = MaxQuatValues - MinQuatValues;
+
+ if (IsAcceptableSample(q, m))
{
MagSamples[SampleCount] = m;
QuatSamples[SampleCount] = q;
@@ -94,6 +136,14 @@ bool MagCalibration::InsertIfAcceptable(const Quatf& q, const Vector3f& m)
return false;
}
+Matrix4f MagCalibration::GetMagCalibration() const
+{
+ Matrix4f calMat = Matrix4f();
+ calMat.M[0][3] = -MagCenter.x;
+ calMat.M[1][3] = -MagCenter.y;
+ calMat.M[2][3] = -MagCenter.z;
+ return calMat;
+}
bool MagCalibration::SetCalibration(SensorFusion& sf)
{
@@ -101,10 +151,7 @@ bool MagCalibration::SetCalibration(SensorFusion& sf)
return false;
MagCenter = CalculateSphereCenter(MagSamples[0],MagSamples[1],MagSamples[2],MagSamples[3]);
- Matrix4f calMat = Matrix4f();
- calMat.M[0][3] = -MagCenter.x;
- calMat.M[1][3] = -MagCenter.y;
- calMat.M[2][3] = -MagCenter.z;
+ Matrix4f calMat = GetMagCalibration();
sf.SetMagCalibration(calMat);
Stat = Mag_Calibrated;
//LogText("MagCenter: %f %f %f\n",MagCenter.x,MagCenter.y,MagCenter.z);
diff --git a/LibOVR/Src/Util/Util_MagCalibration.h b/LibOVR/Src/Util/Util_MagCalibration.h
index fd26d22..1f8e8cb 100644
--- a/LibOVR/Src/Util/Util_MagCalibration.h
+++ b/LibOVR/Src/Util/Util_MagCalibration.h
@@ -41,7 +41,11 @@ public:
{
MinMagDistanceSq = MinMagDistance * MinMagDistance;
MinQuatDistanceSq = MinQuatDistance * MinQuatDistance;
- }
+ MinMagValues = Vector3f(10000.0f,10000.0f,10000.0f);
+ MaxMagValues = Vector3f(-10000.0f,-10000.0f,-10000.0f);
+ MinQuatValues = Quatf(1.0f,1.0f,1.0f,1.0f);
+ MaxQuatValues = Quatf(0.0f,0.0f,0.0f,0.0f);
+ }
// Methods that are useful for either auto or manual calibration
bool IsUnitialized() const { return Stat == Mag_Uninitialized; }
@@ -93,6 +97,12 @@ public:
// A result of the calibration, which is the center of a sphere that
// roughly approximates the magnetometer data.
Vector3f GetMagCenter() const { return MagCenter; }
+ // Retrieves the full magnetometer calibration matrix
+ Matrix4f GetMagCalibration() const;
+ // Retrieves the range of each quaternion term during calibration
+ Quatf GetCalibrationQuatSpread() const { return QuatSpread; }
+ // Retrieves the range of each magnetometer term during calibration
+ Vector3f GetCalibrationMagSpread() const { return MagSpread; }
private:
// Determine the unique sphere through 4 non-coplanar points
@@ -109,6 +119,13 @@ private:
float MinQuatDistance;
float MinMagDistanceSq;
float MinQuatDistanceSq;
+ // For gathering statistics during calibration
+ Vector3f MinMagValues;
+ Vector3f MaxMagValues;
+ Vector3f MagSpread;
+ Quatf MinQuatValues;
+ Quatf MaxQuatValues;
+ Quatf QuatSpread;
unsigned SampleCount;
Vector3f MagSamples[4];
diff --git a/LibOVR/Src/Util/Util_Render_Stereo.cpp b/LibOVR/Src/Util/Util_Render_Stereo.cpp
index b16cfb5..e2600a9 100644
--- a/LibOVR/Src/Util/Util_Render_Stereo.cpp
+++ b/LibOVR/Src/Util/Util_Render_Stereo.cpp
@@ -247,7 +247,7 @@ void StereoConfig::update2D()
// eye, where hmd screen projection surface is at 0.05m distance.
// This introduces an extra off-center pixel projection shift based on eye distance.
// This offCenterShift is the pixel offset of the other camera's center
- // in your reference camera based on surface distance.
+ // in your reference camera based on surface distance.
float metersToPixels = (HMD.HResolution / HMD.HScreenSize);
float lensDistanceScreenPixels= metersToPixels * HMD.LensSeparationDistance;
float eyeDistanceScreenPixels = metersToPixels * InterpupillaryDistance;
@@ -278,7 +278,7 @@ void StereoConfig::update2D()
void StereoConfig::updateEyeParams()
{
// Projection matrix for the center eye, which the left/right matrices are based on.
- Matrix4f projCenter = Matrix4f::PerspectiveRH(YFov, Aspect, 0.01f, 1000.0f);
+ Matrix4f projCenter = Matrix4f::PerspectiveRH(YFov, Aspect, 0.01f, 2000.0f);
switch(Mode)
{
diff --git a/Oculus Configuration Utility.lnk b/Oculus Configuration Utility.lnk
new file mode 100644
index 0000000..ca2804c
--- /dev/null
+++ b/Oculus Configuration Utility.lnk
Binary files differ
diff --git a/Oculus World Demo.lnk b/Oculus World Demo.lnk
new file mode 100644
index 0000000..d846ead
--- /dev/null
+++ b/Oculus World Demo.lnk
Binary files differ
diff --git a/Samples/CommonSrc/Platform/Linux_Gamepad.cpp b/Samples/CommonSrc/Platform/Linux_Gamepad.cpp
index 9370120..7bca5c5 100644
--- a/Samples/CommonSrc/Platform/Linux_Gamepad.cpp
+++ b/Samples/CommonSrc/Platform/Linux_Gamepad.cpp
@@ -3,7 +3,7 @@
Filename : Linux_Gamepad.cpp
Content : Linux implementation of Platform app infrastructure
Created : May 6, 2013
-Authors : Lee Cooper
+Authors : Lee Cooper, Simon Hallam
Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
@@ -21,18 +21,34 @@ limitations under the License.
************************************************************************************/
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <glob.h>
+#include <linux/joystick.h>
#include "Linux_Gamepad.h"
+
namespace OVR { namespace Platform { namespace Linux {
-GamepadManager::GamepadManager()
-{
+const char* pNameXbox360Wireless = "Xbox 360";
+const char* pNameXbox360Wired = "Microsoft X-Box 360";
+
+GamepadManager::GamepadManager() :
+ pDevice(NULL)
+{
}
GamepadManager::~GamepadManager()
{
-
+ // if we have an open device, close it
+ if (pDevice)
+ {
+ pDevice->Close();
+ pDevice = NULL;
+ }
}
UInt32 GamepadManager::GetGamepadCount()
@@ -40,9 +56,398 @@ UInt32 GamepadManager::GetGamepadCount()
return 1;
}
-bool GamepadManager::GetGamepadState(UInt32 index, GamepadState* pState)
+bool GamepadManager::GetGamepadState(UInt32 index, GamepadState *pState)
+{
+ if (!pDevice)
+ {
+ // get a list of paths to all the connected joystick devices
+ glob_t joystickGlobBuffer;
+ glob("/dev/input/js*", 0, NULL, &joystickGlobBuffer);
+
+ // open each joystick device, until we find one that will work for our needs
+ for (UInt32 i = 0; i < joystickGlobBuffer.gl_pathc; i++)
+ {
+ pDevice = new Gamepad();
+ if (pDevice->Open(joystickGlobBuffer.gl_pathv[i]))
+ {
+
+ if (pDevice->IsSupportedType())
+ {
+ break;
+ }
+ }
+
+ // we don't know why the device was not useable, make sure it gets closed cleanly
+ pDevice->Close();
+ pDevice = NULL;
+ }
+
+ }
+
+ if (pDevice)
+ {
+ // we have a device, so update it
+ pDevice->UpdateState();
+
+ // copy the device state into the struct param
+ memcpy(pState, pDevice->GetState(), sizeof(GamepadState));
+
+ // TODO: is the device still active/connected? if not, we should close it
+ // and clear pDevice, so that another device can take over
+
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+Gamepad::Gamepad() :
+ IsInitialized(false),
+ Name(String("Undefined")),
+ Type(UNDEFINED)
+{
+}
+
+Gamepad::~Gamepad()
+{
+ this->Close();
+}
+
+bool Gamepad::Open(const String& devicePathName)
{
+ Name = "Undefined";
+ Type = UNDEFINED;
+
+ FileDescriptor = ::open(devicePathName.ToCStr(), O_RDONLY | O_NONBLOCK);
+ if (FileDescriptor == -1)
+ {
+ return false;
+ }
+
+ // get the device name
+ char name[128];
+ if (ioctl(FileDescriptor, JSIOCGNAME(sizeof(name)), name) < 0)
+ {
+ return false;
+ }
+
+ Name = name;
+
+ // see if device name matches one of our supported devices
+ static const UInt32 Wireless360Len = String(pNameXbox360Wireless).GetLength();
+ static const UInt32 Wired360Len = String(pNameXbox360Wired).GetLength();
+ if (Name.Substring(0, Wireless360Len) == pNameXbox360Wireless)
+ {
+ Type = XBOX360GAMEPADWIRELESS;
+ return true;
+ }
+ else if(Name.Substring(0, Wired360Len) == pNameXbox360Wired)
+ {
+ Type = XBOX360GAMEPADWIRED;
+ return true;
+ }
+
return false;
}
+bool Gamepad::Close()
+{
+ IsInitialized = false;
+ Name = "Undefined";
+ Type = UNDEFINED;
+ return !::close(FileDescriptor);
+}
+
+void Gamepad::UpdateState()
+{
+ GamepadState *pState = &State;
+ js_event gamepadEvent;
+
+ // read the latest batch of events
+ while (read(FileDescriptor, &gamepadEvent, sizeof(struct js_event)) != -1)
+ {
+ switch (gamepadEvent.type)
+ {
+ case JS_EVENT_BUTTON:
+ IsInitialized = true;
+ SetStateButton(pState, gamepadEvent.number, gamepadEvent.value);
+ break;
+
+ case JS_EVENT_AXIS:
+ IsInitialized = true;
+ SetStateAxis(pState, gamepadEvent.number, gamepadEvent.value);
+ break;
+
+ case JS_EVENT_BUTTON | JS_EVENT_INIT:
+ if (IsInitialized) // skip the fake values during device event initialization
+ {
+ SetStateButton(pState, gamepadEvent.number, gamepadEvent.value);
+ }
+ break;
+
+ case JS_EVENT_AXIS | JS_EVENT_INIT:
+ if (IsInitialized) // skip the fake values during device event initialization
+ {
+ SetStateAxis(pState, gamepadEvent.number, gamepadEvent.value);
+ }
+ break;
+
+ default:
+ LogText("OVR::Linux::UpdateState unknown event type\n");
+ }
+ }
+}
+
+const GamepadState* Gamepad::GetState()
+{
+ return &State;
+}
+
+
+bool Gamepad::IsSupportedType()
+{
+ return Type != UNDEFINED;
+}
+
+const String& Gamepad::GetIdentifier()
+{
+ return Name;
+}
+
+static inline float NormalizeGamepadStickXbox360(SInt32 in)
+{
+ float v;
+ if (abs(in) < 9000) return 0;
+ else if (in > 9000) v = (float)in - 9000;
+ else v = (float)in + 9000;
+ return v / (32767 - 9000);
+}
+
+static inline float NormalizeGamepadTriggerXbox360(SInt32 in,
+ SInt32 offset,
+ SInt32 deadBand,
+ float divisor)
+{
+ in += offset;
+
+ if (in < deadBand)
+ {
+ return 0;
+ }
+ else
+ {
+ return float(in - deadBand) / divisor;
+ }
+}
+
+static inline void UpdateButtonMaskAndBitfield(GamepadState *pState,
+ SInt32 value,
+ UInt32 buttonBitfield)
+{
+ if (value)
+ {
+ pState->Buttons |= buttonBitfield;
+ }
+ else
+ {
+ pState->Buttons = pState->Buttons & (0xFFFFFFFF ^ buttonBitfield);
+ }
+}
+
+void Gamepad::SetStateAxis(GamepadState *pState, UInt32 axis, SInt32 value)
+{
+ // some pads/sticks have lots in common with one another,
+ // handle those shared cases first
+ switch (Type)
+ {
+ case XBOX360GAMEPADWIRELESS:
+ case XBOX360GAMEPADWIRED:
+ switch (axis)
+ {
+ case 0:
+ pState->LX = NormalizeGamepadStickXbox360(value);
+ break;
+
+ case 1:
+ pState->LY = -NormalizeGamepadStickXbox360(value);
+ break;
+
+ case 3:
+ pState->RX = NormalizeGamepadStickXbox360(value);
+ break;
+
+ case 4:
+ pState->RY = -NormalizeGamepadStickXbox360(value);
+ break;
+ }
+ break;
+
+ case UNDEFINED:
+ default:
+ break;
+ }
+
+ // handle the special cases, or pads/sticks which are unique
+ switch (Type)
+ {
+ case XBOX360GAMEPADWIRELESS:
+ switch (axis)
+ {
+ case 2:
+ pState->LT = NormalizeGamepadTriggerXbox360(value, 0, 500, 32267);
+ break;
+
+ case 5:
+ pState->RT = NormalizeGamepadTriggerXbox360(value, 0, 500, 32267);
+ break;
+ }
+ break;
+
+ case XBOX360GAMEPADWIRED:
+ switch (axis)
+ {
+ case 2:
+ pState->LT = NormalizeGamepadTriggerXbox360(value, 32767, 1000, 64535);
+ break;
+
+ case 5:
+ pState->RT = NormalizeGamepadTriggerXbox360(value, 32767, 1000, 64535);
+ break;
+
+ case 6:
+ if (value == 0)
+ {
+ UpdateButtonMaskAndBitfield(pState, 0, Gamepad_Left);
+ UpdateButtonMaskAndBitfield(pState, 0, Gamepad_Right);
+ }
+ else if (value < 0)
+ {
+ UpdateButtonMaskAndBitfield(pState, 1, Gamepad_Left);
+ }
+ else if (value > 0)
+ {
+ UpdateButtonMaskAndBitfield(pState, 1, Gamepad_Right);
+ }
+ break;
+
+ case 7:
+ if (value == 0)
+ {
+ UpdateButtonMaskAndBitfield(pState, 0, Gamepad_Up);
+ UpdateButtonMaskAndBitfield(pState, 0, Gamepad_Down);
+ }
+ else if (value < 0)
+ {
+ UpdateButtonMaskAndBitfield(pState, 1, Gamepad_Up);
+ }
+ else if (value > 0)
+ {
+ UpdateButtonMaskAndBitfield(pState, 1, Gamepad_Down);
+ }
+ break;
+ }
+ break;
+
+ case UNDEFINED:
+ default:
+ break;
+ }
+}
+
+void Gamepad::SetStateButton(GamepadState *pState, UInt32 button, SInt32 value)
+{
+ // some pads/sticks have lots in common with one another,
+ // handle those shared cases first
+ switch (Type)
+ {
+ case XBOX360GAMEPADWIRELESS:
+ case XBOX360GAMEPADWIRED:
+ switch (button)
+ {
+ case 0:
+ UpdateButtonMaskAndBitfield(pState, value, Gamepad_A);
+ break;
+
+ case 1:
+ UpdateButtonMaskAndBitfield(pState, value, Gamepad_B);
+ break;
+
+ case 2:
+ UpdateButtonMaskAndBitfield(pState, value, Gamepad_X);
+ break;
+
+ case 3:
+ UpdateButtonMaskAndBitfield(pState, value, Gamepad_Y);
+ break;
+
+ case 4:
+ UpdateButtonMaskAndBitfield(pState, value, Gamepad_L1);
+ break;
+
+ case 5:
+ UpdateButtonMaskAndBitfield(pState, value, Gamepad_R1);
+ break;
+
+ case 6:
+ UpdateButtonMaskAndBitfield(pState, value, Gamepad_Back);
+ break;
+
+ case 7:
+ UpdateButtonMaskAndBitfield(pState, value, Gamepad_Start);
+ break;
+
+ case 8:
+ // we have no value defined for the Xbox/power button
+ break;
+
+ case 9:
+ UpdateButtonMaskAndBitfield(pState, value, Gamepad_LStick);
+ break;
+
+ case 10:
+ UpdateButtonMaskAndBitfield(pState, value, Gamepad_RStick);
+ break;
+ }
+ break;
+
+ case UNDEFINED:
+ default:
+ break;
+ }
+
+ // handle the special cases, or pads/sticks which are unique
+ switch (Type)
+ {
+ case XBOX360GAMEPADWIRELESS:
+ switch (button)
+ {
+ case 11:
+ UpdateButtonMaskAndBitfield(pState, value, Gamepad_Left);
+ break;
+
+ case 12:
+ UpdateButtonMaskAndBitfield(pState, value, Gamepad_Right);
+ break;
+
+ case 13:
+ UpdateButtonMaskAndBitfield(pState, value, Gamepad_Up);
+ break;
+
+ case 14:
+ UpdateButtonMaskAndBitfield(pState, value, Gamepad_Down);
+ break;
+ }
+
+ case XBOX360GAMEPADWIRED:
+ break;
+
+ case UNDEFINED:
+ default:
+ break;
+ }
+}
+
}}} // OVR::Platform::Linux
+
diff --git a/Samples/CommonSrc/Platform/Linux_Gamepad.h b/Samples/CommonSrc/Platform/Linux_Gamepad.h
index 9e6413d..ba66e70 100644
--- a/Samples/CommonSrc/Platform/Linux_Gamepad.h
+++ b/Samples/CommonSrc/Platform/Linux_Gamepad.h
@@ -3,7 +3,7 @@
Filename : Linux_Gamepad.h
Content : Linux implementation of Gamepad functionality.
Created : May 6, 2013
-Authors : Lee Cooper
+Authors : Lee Cooper, Simon Hallam
Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
@@ -28,22 +28,54 @@ limitations under the License.
namespace OVR { namespace Platform { namespace Linux {
+class Gamepad; // forward declaration for readability
+
class GamepadManager : public Platform::GamepadManager
{
public:
+
GamepadManager();
~GamepadManager();
- virtual UInt32 GetGamepadCount();
- virtual bool GetGamepadState(UInt32 index, GamepadState* pState);
+ virtual UInt32 GetGamepadCount();
+ virtual bool GetGamepadState(UInt32 index, GamepadState *pState);
private:
- // Dynamically ink to XInput to simplify projects.
- //HMODULE hXInputModule;
- //typedef DWORD (WINAPI *PFn_XInputGetState)(DWORD dwUserIndex, XINPUT_STATE* pState);
- //PFn_XInputGetState pXInputGetState;
- //UInt32 LastPadPacketNo;
+ Gamepad *pDevice;
+};
+
+class Gamepad
+{
+public:
+
+ Gamepad();
+ virtual ~Gamepad();
+
+ bool Open(const String& devicePathName);
+ bool Close();
+ bool IsSupportedType();
+ const String& GetIdentifier();
+ void UpdateState();
+ const GamepadState* GetState();
+
+private:
+
+ void SetStateAxis(GamepadState *pState, UInt32 axis, SInt32 value);
+ void SetStateButton(GamepadState *pState, UInt32 button, SInt32 value);
+
+ enum GamepadType
+ {
+ UNDEFINED,
+ XBOX360GAMEPADWIRELESS,
+ XBOX360GAMEPADWIRED
+ };
+
+ UInt32 FileDescriptor;
+ bool IsInitialized;
+ String Name;
+ GamepadType Type;
+ GamepadState State;
};
}}}
diff --git a/Samples/OculusRoomTiny/OculusRoomTiny_Msvc2010.vcxproj b/Samples/OculusRoomTiny/OculusRoomTiny_Msvc2010.vcxproj
index 4bc37a8..5ed8886 100644
--- a/Samples/OculusRoomTiny/OculusRoomTiny_Msvc2010.vcxproj
+++ b/Samples/OculusRoomTiny/OculusRoomTiny_Msvc2010.vcxproj
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
diff --git a/Samples/OculusRoomTiny/OculusRoomTiny_Msvc2010.vcxproj.filters b/Samples/OculusRoomTiny/OculusRoomTiny_Msvc2010.vcxproj.filters
index 3c09bd5..5643d9f 100644
--- a/Samples/OculusRoomTiny/OculusRoomTiny_Msvc2010.vcxproj.filters
+++ b/Samples/OculusRoomTiny/OculusRoomTiny_Msvc2010.vcxproj.filters
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="OculusRoomModel.cpp" />
diff --git a/Samples/OculusWorldDemo/OculusWorldDemo.cpp b/Samples/OculusWorldDemo/OculusWorldDemo.cpp
index be2e6b2..613cdac 100644
--- a/Samples/OculusWorldDemo/OculusWorldDemo.cpp
+++ b/Samples/OculusWorldDemo/OculusWorldDemo.cpp
@@ -342,8 +342,8 @@ int OculusWorldDemoApp::OnStartup(int argc, const char** argv)
pUserProfile = pHMD->GetProfile();
if (pUserProfile)
{
- ThePlayer.EyeHeight = pUserProfile->GetEyeHeight();
- ThePlayer.EyePos.y = ThePlayer.EyeHeight;
+ ThePlayer.UserEyeHeight = pUserProfile->GetEyeHeight();
+ ThePlayer.EyePos.y = ThePlayer.UserEyeHeight;
}
}
else
@@ -915,7 +915,7 @@ void OculusWorldDemoApp::OnKey(OVR::KeyCode key, int chr, bool down, int modifie
// Reset the camera position in case we get stuck
case Key_T:
- ThePlayer.EyePos = Vector3f(10.0f, 1.6f, 10.0f);
+ ThePlayer.EyePos = Vector3f(10.0f, ThePlayer.UserEyeHeight, 10.0f);
break;
case Key_F5:
@@ -1094,6 +1094,7 @@ void OculusWorldDemoApp::OnIdle()
{
pSensor = *desc.Handle.CreateDeviceTyped<SensorDevice>();
SFusion.AttachToSensor(pSensor);
+
SetAdjustMessage("---------------------------\n"
"SENSOR connected\n"
"---------------------------");
@@ -1199,16 +1200,6 @@ void OculusWorldDemoApp::OnIdle()
(this->*pAdjustFunc)(dt * AdjustDirection * (ShiftDown ? 5.0f : 1.0f));
}
- // Process latency tester results.
- const char* results = LatencyUtil.GetResultsString();
- if (results != NULL)
- {
- LogText("LATENCY TESTER: %s\n", results);
- }
-
- // Have to place this as close as possible to where the HMD orientation is read.
- LatencyUtil.ProcessInputs();
-
// Magnetometer calibration procedure
if (MagCal.IsManuallyCalibrating())
UpdateManualMagCalibration();
@@ -1229,6 +1220,17 @@ void OculusWorldDemoApp::OnIdle()
}
}
+
+ // Process latency tester results.
+ const char* results = LatencyUtil.GetResultsString();
+ if (results != NULL)
+ {
+ LogText("LATENCY TESTER: %s\n", results);
+ }
+
+ // >>> THIS MUST BE PLACED AS CLOSE AS POSSIBLE TO WHERE THE HMD ORIENTATION IS READ <<<
+ LatencyUtil.ProcessInputs();
+
// Handle Sensor motion.
// We extract Yaw, Pitch, Roll instead of directly using the orientation
// to allow "additional" yaw manipulation with mouse/controller.
@@ -1459,9 +1461,9 @@ void OculusWorldDemoApp::UpdateManualMagCalibration()
static const char* HelpText =
"F1 \t100 NoStereo \t420 Z \t520 Manual Mag Calib\n"
"F2 \t100 Stereo \t420 X \t520 Auto Mag Calib\n"
- "F3 \t100 StereoHMD \t420 ; \t520 Mag Set Ref Point\n"
- "F4 \t100 MSAA \t420 F6 \t520 Mag Info\n"
- "F9 \t100 FullScreen \t420 R \t520 Reset SensorFusion\n"
+ "F3 \t100 StereoHMD \t420 F6 \t520 Yaw Drift Info\n"
+ "F4 \t100 MSAA \t420 R \t520 Reset SensorFusion\n"
+ "F9 \t100 FullScreen \t420\n"
"F11 \t100 Fast FullScreen \t500 - + \t660 Adj EyeHeight\n"
"C \t100 Chromatic Ab \t500 [ ] \t660 Adj FOV\n"
"P \t100 Motion Pred \t500 Shift \t660 Adj Faster\n"
@@ -1553,7 +1555,7 @@ void OculusWorldDemoApp::Render(const StereoEyeParams& stereo)
{
LoadingScene.Render(pRender, Matrix4f());
String loadMessage = String("Loading ") + MainFilePath;
- DrawTextBox(pRender, 0.0f, 0.25f, textHeight, loadMessage.ToCStr(), DrawText_HCenter);
+ DrawTextBox(pRender, 0.0f, 0.0f, textHeight, loadMessage.ToCStr(), DrawText_HCenter);
LoadingState = LoadingState_DoLoad;
}
@@ -1572,7 +1574,7 @@ void OculusWorldDemoApp::Render(const StereoEyeParams& stereo)
" FPS: %d Frame: %d \n Pos: %3.2f, %3.2f, %3.2f \n"
" EyeHeight: %3.2f",
RadToDegree(ThePlayer.EyeYaw), RadToDegree(ThePlayer.EyePitch), RadToDegree(ThePlayer.EyeRoll),
- FPS, FrameCounter, ThePlayer.EyePos.x, ThePlayer.EyePos.y, ThePlayer.EyePos.z, ThePlayer.EyePos.y);
+ FPS, FrameCounter, ThePlayer.EyePos.x, ThePlayer.EyePos.y, ThePlayer.EyePos.z, ThePlayer.UserEyeHeight);
size_t texMemInMB = pRender->GetTotalTextureMemoryUsage() / 1058576;
if (texMemInMB)
{
@@ -1680,10 +1682,10 @@ void OculusWorldDemoApp::AdjustEyeHeight(float dt)
{
float dist = 0.5f * dt;
- ThePlayer.EyeHeight += dist;
+ ThePlayer.UserEyeHeight += dist;
ThePlayer.EyePos.y += dist;
- SetAdjustMessage("EyeHeight: %4.2f", ThePlayer.EyeHeight);
+ SetAdjustMessage("UserEyeHeight: %4.2f", ThePlayer.UserEyeHeight);
}
void OculusWorldDemoApp::AdjustMotionPrediction(float dt)
diff --git a/Samples/OculusWorldDemo/OculusWorldDemo_Msvc2010.vcxproj b/Samples/OculusWorldDemo/OculusWorldDemo_Msvc2010.vcxproj
index a881ab8..fb72d47 100644
--- a/Samples/OculusWorldDemo/OculusWorldDemo_Msvc2010.vcxproj
+++ b/Samples/OculusWorldDemo/OculusWorldDemo_Msvc2010.vcxproj
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
diff --git a/Samples/OculusWorldDemo/OculusWorldDemo_Msvc2010.vcxproj.filters b/Samples/OculusWorldDemo/OculusWorldDemo_Msvc2010.vcxproj.filters
index e96dc9e..8199eb7 100644
--- a/Samples/OculusWorldDemo/OculusWorldDemo_Msvc2010.vcxproj.filters
+++ b/Samples/OculusWorldDemo/OculusWorldDemo_Msvc2010.vcxproj.filters
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="CommonSrc">
diff --git a/Samples/OculusWorldDemo/Player.cpp b/Samples/OculusWorldDemo/Player.cpp
index 5577b82..6422920 100644
--- a/Samples/OculusWorldDemo/Player.cpp
+++ b/Samples/OculusWorldDemo/Player.cpp
@@ -24,7 +24,7 @@ limitations under the License.
#include <Kernel/OVR_Alg.h>
Player::Player(void)
- : EyeHeight(1.8f),
+ : UserEyeHeight(1.8f),
EyePos(7.7f, 1.8f, -1.0f),
EyeYaw(YawInitial), EyePitch(0), EyeRoll(0),
LastSensorYaw(0)
@@ -158,9 +158,9 @@ void Player::HandleCollision(double dt, Array<Ptr<CollisionModel> >* collisionMo
}
// Maintain the minimum camera height
- if (EyeHeight - finalDistanceDown < 1.0f)
+ if (UserEyeHeight - finalDistanceDown < 1.0f)
{
- EyePos.y += EyeHeight - finalDistanceDown;
+ EyePos.y += UserEyeHeight - finalDistanceDown;
}
}
}
diff --git a/Samples/OculusWorldDemo/Player.h b/Samples/OculusWorldDemo/Player.h
index e1c0437..e57e67c 100644
--- a/Samples/OculusWorldDemo/Player.h
+++ b/Samples/OculusWorldDemo/Player.h
@@ -55,9 +55,11 @@ const float RailHeight = 0.8f;
class Player
{
public:
+
+ float UserEyeHeight;
+
// Position and look. The following apply:
Vector3f EyePos;
- float EyeHeight;
float EyeYaw; // Rotation around Y, CCW positive when looking at RHS (X,Z) plane.
float EyePitch; // Pitch. If sensor is plugged in, only read from sensor.
float EyeRoll; // Roll, only accessible from Sensor.
diff --git a/Samples/SensorBox/SensorBoxTest_Msvc2010.vcxproj b/Samples/SensorBox/SensorBoxTest_Msvc2010.vcxproj
index a0c06af..6f9e57c 100644
--- a/Samples/SensorBox/SensorBoxTest_Msvc2010.vcxproj
+++ b/Samples/SensorBox/SensorBoxTest_Msvc2010.vcxproj
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
diff --git a/Samples/SensorBox/SensorBoxTest_Msvc2010.vcxproj.filters b/Samples/SensorBox/SensorBoxTest_Msvc2010.vcxproj.filters
index 5c2ee68..07a8312 100644
--- a/Samples/SensorBox/SensorBoxTest_Msvc2010.vcxproj.filters
+++ b/Samples/SensorBox/SensorBoxTest_Msvc2010.vcxproj.filters
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="CommonSrc">